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:
The designers came up with some clean, semantic markup married with some jquery, for me to start from:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<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.
- Part 1 – Overview, Profile Picture, and User Name
- Part 2 – Edit Profile and My Site links
- 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):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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:
1 2 3 4 5 6 7 8 9 10 11 |
<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:
1 2 3 4 5 6 7 |
// 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<%@ 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
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.
very well done, i would have like to seen the css that goes along with this.
Nice work. However I want to know how you make the div to be a dropdown. Thanks.