Creating a Custom Welcome Menu for SharePoint Server 2010 – Part 3

Part 3 – Sign Out/Sign in as a Different User

A project I am working on called for a custom implementation of the SharePoint Welcome menu control. The replacement control needed to provide the following:

  • Implement the look and behaviors that the designers created.
  • Exclude some default SharePoint menu items (such as My Regional Settings).
  • Reuse some existing SharePoint menu items (such as Sign Out/Sign in as a Different User).
  • Allow for the addition of other custom menu items in the future.
  • Display thumbnail of the user’s profile picture.

I had to create a control that looked and behaved like the following:

CropperCapture2_thumb1_thumb

The designers came up with some clean, semantic markup married with some jquery, for me to start from:

<div class="header">
    <img class="header-logo" src="/images/header_logo.png" alt="" width="169" height="78" />
    <div class="header-bar">
        <div class="profile_menu">
            <a href="#" class="profile_btn">
                <span class="image"><img src="" style="width:20px;height:20px" /></span>
                <span class="name">John Doe</span>
                <span class="arrow"></span>
            </a>
            <div class="profile_dropdown">
                <div class="dropdown_bkgrd">
                    <ul>
                        <li>Edit Profile</li> 
                        <li>My Site</li>
                        <li>Log Out</li>                        
                        <li>Sign in as a Different User</li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>

This is part 3 of a three part series.

  1. Part 1 – Overview, Profile Picture, and User Name
  2. Part 2 – Edit Profile and My Site links
  3. Part 3 – Sign Out/Sign in as a Different User

Building the Sign Out Links

The Sign Out and Sign in as a Different User menu items are rendered by the PersonalActions control, in two methods (from Reflector):

private void SetLoginAsDifferentUserMenuItemGoToPageUrl()
{
    MenuItemTemplate menuItem = base.GetMenuItem("ID_LoginAsDifferentUser");
    if (menuItem != null)
    {
        if (SPSecurity.AuthenticationMode == AuthenticationMode.None)
        {
            menuItem.Visible = false;
        }
        else
        {
            string serverRelativeUrlFromUrl = this.Web.GetServerRelativeUrlFromUrl("_layouts/closeConnection.aspx?loginasanotheruser=true");
            menuItem.ClientOnClickScript = "javascript:LoginAsAnother('" + SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl) + "', 0)";
        }
    }
}
 
private void SetSignOutMenuItemGoToPageUrl()
{
    MenuItemTemplate menuItem = base.GetMenuItem("ID_Logout");
    if (menuItem != null)
    {
        if (SPSecurity.AuthenticationMode == AuthenticationMode.None)
        {
            menuItem.Visible = false;
        }
        else
        {
            menuItem.ClientOnClickNavigateUrl = this.Web.GetServerRelativeUrlFromUrl("_layouts/SignOut.aspx");
        }
    }
}

The “Sign Out” link points to “_layouts/SignOut.aspx”, and “Sign in as a Different User” points to “_layouts/closeConnection.aspx”.

To leverage this, I again adjusted the ASCX markup to include some PlaceHolder and LinkButton controls:

<div class="profile_dropdown">
<asp:PlaceHolder ID="placeHolderUserID" runat="server"></asp:PlaceHolder>
    <div class="dropdown_bkgrd">
        <ul>
            <asp:PlaceHolder ID="placeHolderEditProfile" runat="server"><li><asp:LinkButton ID="linkButtonEditProfile" runat="server" EnableViewState="false" Text="Edit Profile"></asp:LinkButton></li></asp:PlaceHolder> 
            <asp:PlaceHolder ID="placeHolderMySite" runat="server"><li><asp:LinkButton ID="linkButtonMySite" runat="server" EnableViewState="false" Text="My Site"></asp:LinkButton></li></asp:PlaceHolder>
            <li><asp:LinkButton ID="linkButtonLogOut" runat="server" EnableViewState="false" Text="Sign Out"></asp:LinkButton></li>                        
            <li><asp:LinkButton ID="linkButtonLoginAsDifferentUser" runat="server" EnableViewState="false" Text="Sign in as a Different User"></asp:LinkButton></li>
        </ul>
    </div>
</div>

And then here is some code-behind that re-creates the output from the PersonalActions control:

// Login as another user
string loginAsAnotherUserUrl = this.ResolveClientUrl("~/_layouts/closeConnection.aspx?loginasanotheruser=true");
linkButtonLoginAsDifferentUser.OnClientClick = string.Format("LoginAsAnother('{0}', 0);return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(loginAsAnotherUserUrl));   
 
// Sign out
string signOutUrl = this.ResolveClientUrl("~/_layouts/SignOut.aspx");
linkButtonLogOut.OnClientClick = "GoToPage('" + SPHttpUtility.EcmaScriptStringLiteralEncode(signOutUrl) + "');return false;";

Summary

In this post, we deconstructed the PersonalActions control further to re-create the Sign Out and Sign in as a Different User menu items.

Our Final ASCX markup is:

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %> 
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CustomWelcomeMenuControl.ascx.cs" Inherits="CustomWelcomeMenu.ControlTemplates.CustomWelcomeMenu.CustomWelcomeMenuControl" %>
<div class="header">
    <img class="header-logo" src="/images/header_logo.png" alt="" width="169" height="78" />
    <div class="header-bar">
        <div class="profile_menu">
        <a href="#" class="profile_btn">
            <span class="image"><asp:Image ID="imageProfilePicture" runat="server" Width="20px" Height="20px" /></span>
            <span class="name"><asp:PlaceHolder ID="placeHolderWelcomeName" runat="server"></asp:PlaceHolder></span>
            <span class="arrow"></span>
        </a>
            <div class="profile_dropdown">
                <asp:PlaceHolder ID="placeHolderUserID" runat="server"></asp:PlaceHolder>
                <div class="dropdown_bkgrd">
                    <ul>
                        <asp:PlaceHolder ID="placeHolderEditProfile" runat="server"><li><asp:LinkButton ID="linkButtonEditProfile" runat="server" EnableViewState="false" Text="Edit Profile"></asp:LinkButton></li></asp:PlaceHolder> 
                        <asp:PlaceHolder ID="placeHolderMySite" runat="server"><li><asp:LinkButton ID="linkButtonMySite" runat="server" EnableViewState="false" Text="My Site"></asp:LinkButton></li></asp:PlaceHolder>
                        <li><asp:LinkButton ID="linkButtonLogOut" runat="server" EnableViewState="false" Text="Sign Out"></asp:LinkButton></li>                        
                        <li><asp:LinkButton ID="linkButtonLoginAsDifferentUser" runat="server" EnableViewState="false" Text="Sign in as a Different User"></asp:LinkButton></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>

Our Final ASCX code-behind is:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;
 
namespace CustomWelcomeMenu.ControlTemplates.CustomWelcomeMenu
{
    public partial class CustomWelcomeMenuControl : UserControl
    {
        protected void Page_PreRender(object sender, EventArgs e)
        {    
    
            // Username
            PostCacheSubstitutionText welcomeText = new PostCacheSubstitutionText();
            welcomeText.TextType = PostCacheSubstitutionTextType.UserName;
            placeHolderWelcomeName.Controls.Add(welcomeText);
 
            // Profile picture
            SPList userInfoList = SPContext.Current.Web.GetCatalog(SPListTemplateType.UserInformation);
            SPListItem userProfileItem = userInfoList.GetItemById(SPContext.Current.Web.CurrentUser.ID);
            if (userProfileItem["Picture"] == null || string.IsNullOrEmpty(userProfileItem["Picture"].ToString()))
            {
                // Use default picture (or replace with another)
                imageProfilePicture.ImageUrl = "/_layouts/images/PERSON.GIF";
            }
            else
            {
                SPFieldUrlValue value = new SPFieldUrlValue(userProfileItem["Picture"].ToString());
                imageProfilePicture.ImageUrl = value.Url;
            }
 
                string myProfileUrl = Context.Items["SocialData$ProfileURL"] as string;
            string mySiteHostUrl = Context.Items["SocialData$MySiteHostURL"] as string;
    
            if (!Page.IsPostBack)
            {
                myProfileUrl = Context.Items["SocialData$ProfileURL"] as string;
                ViewState[Constants.VIEWSTATE_PROFILE_URL] = myProfileUrl;
                mySiteHostUrl = Context.Items["SocialData$MySiteHostURL"] as string;
                ViewState[Constants.VIEWSTATE_MYSITE_URL] = mySiteHostUrl;
            }
            else
            {
                myProfileUrl = ViewState[Constants.VIEWSTATE_PROFILE_URL] as string;
                mySiteHostUrl = ViewState[Constants.VIEWSTATE_MYSITE_URL] as string;
            }
    
    
            if (string.IsNullOrEmpty(mySiteHostUrl))
            {
                // No MySite host, or user does not have rights to view profile page...
            placeHolderMySite.Visible = false;
 
            }
            else
            {
                // User has a MySite, show the link to it...
            placeHolderMySite.Visible = true;
            linkButtonMySite.OnClientClick = string.Format("STSNavigate2(event, '{0}');return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(mySiteHostUrl));
            }
    
            if (string.IsNullOrEmpty(myProfileUrl))
            {
            // Use the SharePoint foundation profile page, since the MySite host is not available
            PostCacheSubstitutionText pt = new PostCacheSubstitutionText();
            pt.TextType = PostCacheSubstitutionTextType.UserId;
            pt.PrefixHtml = "<script type="text/javascript">n//<![CDATA[nvar _spUserId=";
            pt.SuffixHtml = ";n//]]>n</script>";
            placeHolderUserID.Controls.Add(pt);
                string serverRelativeUrlFromUrl = this.ResolveClientUrl("~/_layouts/userdisp.aspx?Force=True&ID=");
            linkButtonEditProfile.OnClientClick = "GoToPage('" + SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl) + "' + _spUserId);return false;";
            }
            else
            {
                // Use the MySite profile page...
            linkButtonEditProfile.OnClientClick = string.Format("STSNavigate2(event, '{0}');return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(myProfileUrl));
            }
 
            // Login as another user
            string loginAsAnotherUserUrl = this.ResolveClientUrl("~/_layouts/closeConnection.aspx?loginasanotheruser=true");
            linkButtonLoginAsDifferentUser.OnClientClick = string.Format("LoginAsAnother('{0}', 0);return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(loginAsAnotherUserUrl));
 
            // Sign out
            string signOutUrl = this.ResolveClientUrl("~/_layouts/SignOut.aspx");
            linkButtonLogOut.OnClientClick = "GoToPage('" + SPHttpUtility.EcmaScriptStringLiteralEncode(signOutUrl) + "');return false;";
 
        }
 
    }
}

Hopefully you find this useful, and can take it further if need be. Leave comments if you have any questions.

2 comments on “Creating a Custom Welcome Menu for SharePoint Server 2010 – Part 3

Comments are closed.