- Задание -
При использовании действия "Войти под другим пользователем" новый пользователь должен быть перенаправлен на главную странцу (рис. 1), а не на ту, с которой было выполнено действие.
- Анализ -
Кнопка, которую мы анализируем находится в пользовательском контроле Welcome.ascx, который в свою очередь находится в папке CONTROLTEMPLATES. Рассмотрим его код разметки (часть кода была опущена):
<SharePoint:PersonalActions AccessKey="<%$Resources:wss,personalactions_menu_ak%>" ToolTip="<%$Resources:wss,open_menu%>" runat="server" ID="ExplicitLogout" Visible="false"> <CustomTemplate> <SharePoint:FeatureMenuTemplate runat="server" FeatureScope="Site" Location="Microsoft.SharePoint.StandardMenu" GroupId="PersonalActions" ID="ID_PersonalActionMenu" UseShortId="true"> <%-- Тут пункты меню --%> <SharePoint:MenuItemTemplate runat="server" id="ID_LoginAsDifferentUser" Text="<%$Resources:wss,personalactions_loginasdifferentuser%>" Description="<%$Resources:wss,personalactions_loginasdifferentuserdescription%>" MenuGroupId="200" Sequence="100" UseShortId="true" /> <%-- И тут пункты меню --%> </SharePoint:FeatureMenuTemplate> </CustomTemplate> </SharePoint:PersonalActions>
Итак, мы нашли необходимый нам пункт меню с уникальным идентификатором ID_LoginAsDifferentUser, но почему-то отсутствует инициализация свойства ClientOnClickScript. Сразу промелькнула мысль, что инициализация осуществляется в code behind. Смотрим туда, но интересного ничего не находим. Смотрим методы дочерних элементов и что мы видим (ILSpy 1.0.0.1000):
public sealed class PersonalActions : ToolBarMenuButton, IPreRenderOverride { [SharePointPermission(SecurityAction.Demand, ObjectModel = true)] protected override void CreateChildControls() { /* Тут ничего интересного. */ this.SetLoginAsDifferentUserMenuItemGoToPageUrl(); this.SetSignOutMenuItemGoToPageUrl(); this.HandleRequestForAccessMenuItem(); } private void SetLoginAsDifferentUserMenuItemGoToPageUrl() { MenuItemTemplate menuItem = base.GetMenuItem("ID_LoginAsDifferentUser"); if (menuItem != null) { if (SPSecurity.AuthenticationMode == AuthenticationMode.None) { menuItem.Visible = false; return; } string serverRelativeUrlFromUrl = this.Web.GetServerRelativeUrlFromUrl("_layouts/closeConnection.aspx?loginasanotheruser=true"); menuItem.ClientOnClickScript = "javascript:LoginAsAnother('" + SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl) + "', 0)"; } } }
Вуаля, то что нам нужно! Однако зоркий глаз программиста увидит, что унаследоваться от данного класса нельзя, соответственно необходимо искать другие подходы для переопределения данной функциональности. Можно, конечно, поправить JS-функцию LoginAsAnother() в init.js, но я бы не советовал трогать встроенную функциональность, лучше пойти в обход и "склонировать" (об этом далее).
- Действия -
Мне было легче, потому что у меня был доступ к исходникам решения, в котором была мастер-страница с готовой разметкой, в которой красовалось:
<wssuc:Welcome id="IdWelcome" runat="server" EnableViewState="false" />
Далее создаём свой пользовательский контрол в mapped-папке CONTROLTEMPLATES, например, с названием Welcome.ascx (рис. 2).
Разметку копируем с Welcome.ascx. Далее заходим в Welcome.ascx.cs и добавляем следущее:
/* Тут атрибуты, если необходимо */ public partial class WelcomeControl : Welcome { private const string LoginAsAnotherUserId = "W_ID_LoginAsDifferentUser"; ////// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering. /// protected override void CreateChildControls() { base.CreateChildControls(); this.SetLoginAsDifferentUserMenuItemGoToPageUrl(); } ////// Builds functionality for the control that performs "Sign in as different user" action. /// protected virtual void SetLoginAsDifferentUserMenuItemGoToPageUrl() { MenuItemTemplate menuItem = this.ExplicitLogout.GetMenuItem(LoginAsAnotherUserId); if (menuItem != null) { if (SPSecurity.AuthenticationMode == AuthenticationMode.None) { menuItem.Visible = false; return; } SPWeb contextWeb = this.ExplicitLogout.Web; string serverRelativeUrlFromUrl = SPUrlUtility.CombineUrl( contextWeb.Url, "/_layouts/closeConnection.aspx?loginasanotheruser=true"); menuItem.ClientOnClickScript = string.Format( "javascript:WLoginAsAnother('{0}', '{1}', 0);", SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl), contextWeb.Site.Url); } } } }
Значение поля LoginAsAnotherUserId - новый идентификатор действия, которое уже мы будем переопределять. Старый идентификатор просто заменяем на новый (в разметке). В методе PersonalActions.SetLoginAsDifferentUserMenuItemGoToPageUrl() стоит проверка на null если старого пункта меню не найдено, соответственно исключений нам не грозит. Далее, необходимо создать аналог JS-функции LoginAsAnother(), я назвал её WLoginAsAnother и принимает она уже не 2 параметра, а 3 (об этом далее). Создаём JS-файл (рис. 3), которые в дальнейшем будет зарегистрирован на мастер-странице через SctipLink (или можно зарегистрировать его в ascx-файле, не имеет значения).
Вот его код:
function ULSWInit() { var o = new Object; o.ULSTeamName = "Project name"; //// Укажите своё имя проекта. o.ULSFileName = "mkb.init.js"; return o; } function WLoginAsAnother(url, sourceUrl, bUseSource) { ULSWInit: ; document.cookie = "loginAsDifferentAttemptCount=0"; if (bUseSource == "1") { GoToPage(url); } else { var ch = url.indexOf("?") >= 0 ? "&" : "?"; url += ch + "Source=" + escapeProperly(sourceUrl); STSNavigate(url); } }
Как мы видим, с какой бы страницы пользователь не вышел, он всегда будет перенаправлен на страницу, которую мы указали (contextWeb.Site.Url). Теперь топаем на мастер-страницу, регистрируем вместо стандартного Welcome.ascx только что созданный, регистрируем JS-файл и радуемся. В данном случае мы в выигрыше по двум причинам:
- не затронули стандартной функциональности и при необходимости можем безболезненно вернуть всё обратно.
- имеем доступ ко всем встроенным пунктам меню и можем добавлять новые прямо в разметку (без CustomAction).
Если будут вопросы - пишите в комментариях. Возможно, статья получилась немного сумбурная...
Комментариев нет:
Отправить комментарий