Tuesday, August 17, 2010

Microsoft Active Accessibility in MOSS

Today while navigating across the tabs in browser which had some of my MOSS websites open, a new menu link came into my notice, see the screen shot below.

image

To be frank initially I thought it might be a menu from my browser, but out of curiosity I did a search on internet and this is what I found,

“On an MOSS 2007 technologies-based site, most user interface (UI) elements, such as links, form controls, and buttons, are designed to use Microsoft Active Accessibility (MSAA). MSAA enables people with disabilities to interact with content by using assistive technologies such as screen readers, which are devices that provide a synthesized speech or Braille description of what a blind or low-vision user is unable to see on a computer screen or Web site. Proper MSAA names are given on all editable controls, links, and buttons.” – Quoted from Andrew Woodward

Thanks to Andrew Woodward (MVP, Moderator) of social.msdn.microsoft.com, and the link is http://social.msdn.microsoft.com/Forums/en-US/sharepointaccessibility/thread/b4f541e0-ece1-4cbc-9e61-bdc74553180c
and his detail link in which he has explained in detail what is this all about.. http://www.21apps.co.uk/sharepoint/sharepoint-accessibility-is-moss-2007-accessible/

Basically it allows the user with disabilities to access the web content, in MOSS it changes the way the Drop down menus in list behaves, instead of the html dropdown it pops up another window with the options and some of the enhanced controls such as rich text boxes with normal text boxes.

Normal Behavior –> image                          

With accessibility mode on –> ScreenClip000006

To enable this Turn On more accessible link, just refresh page and press on tab key (repeat the tab press if the menu doesn't shows up)

I have been working with Sharepoint for a pretty long time but still the product is surprising and giving me fresh feel everyday. It was a fresh thing for me to learn like some of you just did .. :-)

LiveJournal Tags: ,,

Wednesday, August 4, 2010

Checking permission of SPUser who is member of an Active Directory Group which is added to an SPGroup

Consider the following scenario, an AD group is added to an SPGroup. We need to check the permission of a user which is a member of that ADgroup when he logs in to the sharepoint application. Basically the SPUser.Roles or SPGroup.Roles is accessible only if the logged in user is having permission to access the roles information. In this the user wont be an administrator so the Roles information cannot be accessed and it will throw an AccessDenied Exception. So one way to check current user's permission inside elevated code block is to Open the SPWeb, get all the SPGroups of web then check for the group member is an domain group or not, if domain group then recursively loop to find the user based on current user's login name and if found then check for group's role information. But the above code will definitely keep processor busy and too much coding is required and chances of unwanted recursive loop execution is also there. On thinking how to solve this in an effecient way, the SPGroup.ContainsCurrentUser property came into help. For this, firstly out side the elevation block gets the SPGroups of CurrentWeb and check whether current user is a member of each group, if member then add those group information into a temporary collection, I am using List<KeyValuePair>(int, string) to store the collection of SPGroup's ID and Title. And then inside the elevated code block, loop through the elevated SPWeb's groups and check whether the iterated group belongs in the collection of KeyValue which we loaded earlier. If the group is in temporary collection then check that SPGroup's Roles, since it is in elevated code block the Roles information can be fetched without any exception. The code block can be found below,

private bool CheckWhetherCurrentUserHaveFullControl()
{   
    bool hasFullControlPermission = false;
    ////Gets all the groups to which user is having access
    List<KeyValuePair<int, string>> groupsToWhichUserHasAccess = new List<KeyValuePair<int, string>>();
    foreach (SPGroup spGroup in SPContext.Current.Web.Groups)
    {
        if (spGroup.ContainsCurrentUser)
        {
            groupsToWhichUserHasAccess.Add(new KeyValuePair<int, string>(spGroup.ID, spGroup.Name));
        }
    }
    Guid spWebGuid = SPContext.Current.Web.ID;
    Guid spSiteGuid = SPContext.Current.Site.ID;
    int id = SPContext.Current.Web.CurrentUser.ID;
    SPSecurity.RunWithElevatedPrivileges(() =>
    {
        using (SPSite spSite = new SPSite(spSiteGuid))
        {
            using (SPWeb spWeb = spSite.OpenWeb(spWebGuid))
            {
                SPGroupCollection spGroupCollection = spWeb.Groups;

                foreach (SPGroup spGroup in spGroupCollection)
                {
                    var checkPermission = from groupToWhichUserHasAccess in groupsToWhichUserHasAccess
                                          where groupToWhichUserHasAccess.Key == spGroup.ID
                                          select groupToWhichUserHasAccess;

                    if (checkPermission.Any())
                    {
                        foreach (SPRole spRole in spGroup.Roles)
                        {
                            if (spRole.Name.ToUpper().Equals("FULL CONTROL"))
                            {
                                hasFullControlPermission = true;

                                break;
                            }
                        }
                    }
                }
            }
        }
    });
    return hasFullControlPermission;
}

By the above method we can meet the objective and without writing much lines of code and unwanted recursive call against Active Directory objects.

Cheers !!!

Friday, July 2, 2010

Displaying Flash Content in SPGridView

Hi all, while playing around with SPGridView, the power creating a new class by inheriting the SPBoundField to render any Html element gave me the thought of displaying Adobe flash content on Sharepoint SPGridView. The .swf files are stored in an Sharepoint document library, the SPGridView added to an webpart or a custom aspx renders the information from that document library. The document library is used as the flash content store. Even though I am not that familiar with Flash rendering and tags, I managed to get that the <object> tag is the used to show flash content. The object tag has some specified properties and parameters which in turn renders the flash object in the browser. Basically the SPBoundField can be inherited and by overriding ChildControlDataBinding and the custom html element can be rendered. One of the parameters of ChildControlDataBinding provides the dataItem which has the current SPListItem of the row. So the SPListItem properties can be accessed and from that the swf file’s serverRelativeUrl is fetched.

The SPFlashField class is given below,

public class SPFlashField : SPBoundField
{
    protected override void ChildControlDataBinding(System.Web.UI.Control childControl, object dataItem, System.ComponentModel.MemberDescriptor dataFieldPropertyDescriptor)
    {
        PlaceHolder placeHolder = (PlaceHolder)childControl;
        SPDataSourceViewResultItem spDataSourceViewResultItem = dataItem as SPDataSourceViewResultItem;
        Microsoft.SharePoint.SPListItem spListItem = spDataSourceViewResultItem.ResultItem as Microsoft.SharePoint.SPListItem;
        string fileUrl = spListItem.File.ServerRelativeUrl;
        LiteralControl literalControl = new LiteralControl();
        literalControl.Text = "&nbsp;";
        //Only if the file is a flash file
        if (fileUrl.ToLower().Contains(".swf"))
        {
            literalControl.Text = this.GetFlashObjectHtml(fileUrl, spListItem.Name, "250", "538");
        }
        placeHolder.Controls.Add(literalControl);    
    }

    protected override System.Web.UI.Control GetChildControlInstance()
    {
       return new PlaceHolder();
    }

    private string GetFlashObjectHtml(string swfFileUrl, string swfName, string height, string width)
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append("&lt;object height='" + height + "' width='" + width + "' name='" + swfName + "' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0' classid='clsid:" + new Guid().ToString() + "&gt;");
        stringBuilder.Append("&lt;param value='" + swfFileUrl + "' name='movie'&gt;");
        stringBuilder.Append("&lt;param value='high' name='quality'&gt;");
        stringBuilder.Append("&lt;param value='transparent' name='wmode'&gt;");
        stringBuilder.Append("&lt;param value='always' name='allowscriptaccess'&gt;");
        stringBuilder.Append("&lt;embed height='" + height + "' width='" + width + "' allowscriptaccess='always' type='application/x-shockwave-flash' flashvars='strm=stream3' bgcolor='#ffffff' quality='high' src='" + swfFileUrl + "' name='" + swfName + "' wmode='transparent' id='" + swfName + "'&gt;");
        stringBuilder.Append("&lt;/object&gt;");
        return stringBuilder.ToString();
    }
}

Note: Replace &gt; with > and &lt; with <, my live editor didn’t allowed me to copy paste that code snippet ;-)

The final output is like shown below,

ScreenClip000001

The function GetFlashObjectHtml can be also used to render flash in a webpart, or even in a custom SPField.

Thursday, July 1, 2010

AssetUploader aspx page in SharePoint

Just wanted to share one of the usage of AssetUploader.aspx in SharePoint. The scenario is pretty simple, we have a picture library, and the list items are displayed in a SPGridView with thumbnail as one of the column.

<Columns>
    <asp:TemplateField HeaderText="Type" ItemStyle-Width="30px">
        <ItemTemplate>
            <%# Eval("ContentType").ToString() == "Folder" ? "<img src='/_layouts/images/folder.gif' alt='' />" : "<img src='/_layouts/images/" + Microsoft.SharePoint.Utilities.SPUtility.MapToIcon(Microsoft.SharePoint.SPContext.Current.Web, Eval("DocIcon").ToString(), "")+ "' alt='' />" %>
        </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField HeaderText="Thumbnail" ItemStyle-Width="100px">
        <ItemTemplate>
            <%# Eval("ContentType").ToString() == "Folder" ? "<span>&nbsp;</span>" : "<img src='/_layouts/AssetUploader.aspx?Size=Small&ImageUrl=" + HttpUtility.HtmlEncode(Eval("FileRef").ToString()) + "' alt='' style='cursor: pointer;'  />"%>
        </ItemTemplate>
    </asp:TemplateField>
    <sp:SPBoundField DataField="LinkFilenameNoMenu" HeaderText="Name" />
</Columns>

The above will render the grid like below,

ScreenClip000000

Here the file type image is rendered based on the Field property DocIcon and SPUtility.MapToIcon function.

The thumbnail is generated using AssetUpload.aspx

And the name column just bound to the LinkFileNameNoMenu

 

 

 

 Usage of AssetUploader.aspx in detail

This can be used anywhere with <img> tag to display thumbnail of size normal or small.

<img src=”/_layouts/AssetUploader.aspx?Size=Small&ImageUrl=/IMAGES/fileName.fileextension&Size=Small” alt=”” />

  • IMAGES –> Is the Images library name
  • fileName –> the name of the image (myPhoto in myPhoto.jpg)
  • fileextension –> the file extension of the image (jpg in myPhoto.jpg)
  • Size –> If not provided then medium size thumbnail will be generated, pass Small for smaller thumbnail.

So the effort to generate crisper and smaller thumbnail is made easier with the AssetUploader.aspx

Issue

Recently I ran across an issue in Sharepoint with AssetUploader.aspx (The page can be used to generate thumbnail images for images which are located in a Sharepoint library, the usage I have mentioned at the bottom of the post). The issue which we faced was that the AssetUploader.aspx failed to generate thumbnail when the request was secured that is when the request was made across https://. So I tried to investigate using refactoring the dll using .Net reflector, but unfortunately the code was obfuscated. But as a savior I found Mr.Bob Moore’s Blog while googling on the issue. The post is located at http://blogs.pointbridge.com/Blogs/moore_bob/Pages/Post.aspx?_ID=14 the title of post is Pain in the AssetUploader.aspx . Thanks a lot Bob :)

Sunday, June 20, 2010

Adding a custom menu item into "Site Actions" Menu

There may be some scenario when we need to add custom menu item to Site Actions drop down, for doing this we need to add a feature which add the menu. The procedures for this is mentioned below.

1. Create a folder named 'MyCustomSiteActionMenu'
2. Create feature.xml in that folder and add the following code to the feature.xml and save
<?xml version="1.0" encoding="utf-8" ?>
<Feature Id="{NEWGUID}" Hidden="TRUE"
Title="Custom Menu Site Action demo feature"
Description="The feature will add a custom menu item into the Site Actions drop down"
Version="12.0.0.0"
Scope="Web"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="elements.xml" />
</ElementManifests>
</Feature>

Replace {NEWGUID} with a newly created GUID - Use Visual Studio 'Create GUID' tool for this. (Go to Tools -> Create Guid in IDE)
'Id' Any new GUID
'Hidden' denotes whether the feature should be listed under Site Features.
'Title' denotes the feature title, this will be displayed as the title in feature listing page
'Description' denotes the feature description, which will be displayed in the feature listing page
'Version' denotes the version
'Scope' denotes the feature activation scope. Possible values are Site, Web and Farm
And finally mention the element Manifests of the feature, in this case 'elements.xml'
3. Create the elements.xml in the same folder and add the below code and save
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="customAction.Menu.JsAlert"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="999"
Title="Show Javascript Alert"
Description="Click to see Javascript alert" RequireSiteAdministrator="True" >
<UrlAction Url="javascript:alert('Hi.. From Site Actions')"/>
</CustomAction>
<CustomAction
Id="customAction.Menu.RedirectToPage"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="Redirect to Bing.com"
Description="Click to redirect to a url www.bing.com" RequireSiteAdministrator="True" >
<UrlAction Url="http://www.bing.com"/>
</CustomAction>
</Elements>
Refer the MSDN url for more information on the Attributes http://msdn.microsoft.com/en-us/library/ms460194.aspx
'GroupId' Value is important if you want to add as Sub menu of another Menu Item
'Location' is important as well, because it denotes where the custome menu should be added.
Refer the MSDN url for more information on the Location values http://msdn.microsoft.com/en-us/library/bb802730.aspx
In this post, we are going to add a custom menu to the SiteActions menu so location is 'Microsoft.SharePoint.StandardMenu' 'Sequence' as the name indicates the ordering of the menu item.
'Title' is what we see in the menu item
'Description' is also seen just below the menu item title
'RequireSiteAdministrator' value indicating whether the menu item will be visible only to Site Administrators
<UrlAction> denotes the action to be performed.
Now we are good enough to deploy the feature.
4. Copy the folder 'MyCustomSiteActionMenu' to 12\TEMPLATE\FEATURES
5. Using Stsadm command install the feature.
Using Command Prompt, go to the folder 12\bin and then execute the following command
STSADM -o installfeature -name 'MyCustomSiteActionMenu'
Wait for message "Operation Completed Successfully."
6. Using Stsadm command activate the feature (The feature is Hidden so it wont be seen in the features listing).
STSADM -o activatefeature -name "MyCustomSiteActionMenu" -url "http://localhost"
Wait for message "Operation Completed Successfully."
7. Done - Go back to the page, refresh to find the newly added custom menu.
8. Cheers !!!