czwartek, 17 września 2009

Witryna MySite i główna nawigacja

Implementując MOSS'a w mojej organizacji zdecydowano, że nie będziemy udostępniać użytkownikom możliwości tworzenia własnych witryn MySite (nie pytajcie dlaczego - tak uznano).

Za to zdecydowano się na skorzystanie z możliwości importu profili z Active Directory i wykorzystania wyszukiwania kontaktów jako książki telefonicznej. I tylko do tego miały służyć informacje z SSP - żadnych publikacji dokumentów, żadnych blogów itp.

Po instalacji okazało się, że zwykły użytkownik przeglądając szczegóły kontaktu nie widzi górnego paska łączy. Przeglądając własny profil widzi tylko guzik "mój profil" i nic więcej. Oczywiście witryna została podłączona (Ustawienia witryny > Połączenie witryny portalu) z głównym portalem i za pomocą paska "chlebowego" (zawsze śmieszy mnie to tłumaczenie, ale ja nie znam lepszego) można wrócić do strony głównej. Ale użytkownicy zwykle są wygodni (inaczej mówiąc niespostrzegawczy lub niegrzeszący intelignecjią) i chcą na witrynie MySite takie samo menu jak na stronie głównej.

Na początek wypróbowałem (ten sposób opisuje źródło1)  "Łącza do witryn personalizacji" dostępne w SSP "Profile użytkowników i Moje witryny". Dodałem kilka testowych łączy, ustawiłem właścicieli na "wszyscy" (authenticated users"), ale efekt był marny.

Łącza pokazywały się tylko przy przeglądaniu własnego profilu.

Nie zrażając się pomyślałem "Nic prostszego!", przygotowując się do edycji strony wzorcowej witryny MySite za pomocą nieśmiertelnego SharePoint Designer'a.

Ale nie było wcale łatwo.

Przeszukałem internet (źródło2, źródło3) i okazało się, że:
  • w stronie wzorcowej umieszczona jest placeholder "PlaceHolderHorizontalNav" z kontrolką "TopNavigationMenu" generującą menu za pomocą dostawcy "SPNavigationProvider",
  • doprowadzenie do tego, żeby kontrolka wyświetlała menu głównego portalu jest możliwe poprzez zmianę tego dostawcy.

Okazało się, że rozwiązanie to działa i menu jest generowane na podstawie witryny głównej, ALE zwykli użytkownicy NADAL GO NIE WIDZĄ. Zacząłem podejrzewać, że kontrolki lub całe placeholdery są w jakiś sposób ukrywane, ale nigdzie nie mogłem znaleźć atrybutów, które coś takiego by sugerowały.

COFAMY NASZE ZMIANY (posługując się na przykład historią wersji strony wzorcowej) bo póxniej okaże się, że nie są konieczne.

Szperając dalej (źródło4, źródło5, źródło6) okazało się, że:
  • "TopNavigationMenu" jest ukrywane, ale nie przez parametr, ale POPRZEZ SPECJALNY KOD.
  • można to obejść kompilując własny kod (instrukcje w źródłach),
  • kombinując z nowymi placeholderami,
  • wykorzystując mój sposób!

protected override void OnPreRender(EventArgs e)
{
if (base.IsProfileError || !base.Profile.IsSelf)
{
Control master = base.Master;
if (master != null)
{
master = master.FindControl("PlaceHolderTopNavBar");
}
if (master != null)
{
master = master.FindControl("PlaceHolderHorizontalNav");
}
if (master != null)
{
master = master.FindControl("TopNavigationMenu");
}
if (master != null)
{
master.Visible = false;
}
}
base.OnPreRender(e);
}

Jak widać funkcja szuka na stronie konkretnego obiektu "TopNavigationMenu" i na koniec ustawia wartość atrybutu visible na false!

Jak sobie z tym poradzić? Źródła sugerują podmianę kodu i definicji witryny, ale przecież musi być jakiś prostszy sposób. Może trzeba jakoś "zmylić" tę funkcję i "przerwać" jej działanie?

Wracamy do kodu naszej strony wzorcowej.

Zmieniamy następujące linie:
<asp:ContentPlaceHolder id="PlaceHolderHorizontalNav" runat="server">
na
<asp:ContentPlaceHolder id="PlaceHolderHorizontalNav1" runat="server">
Co zrobiliśmy? Sprawiliśmy, że funkcja przeszukująca stronę NIE ZNAJDZIE naszego placeholdera, a co za tym idzie nie znajdzie obiektu "TopNavigationMenu" i go nie ukryje! Po prostu przełamaliśmy łańcuch przeszukiwania na samym początku.
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource">
na
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource1">
To jest troszeczkę bardziej zawiłe.
W tej definicji możemy zmieniać dostawcę dla menu i kombinować z początkowym węzłem (jak podają źródła, które przytoczyłem) aby wygenerować nasze menu, ale metodą prób i błędów okazało się, że wystarczy tylko zmienić ID tej kontrolki.

I TO WYSTARCZY.

Zapisujemy stronę wzorcową, i podglądamy wyniki. Wszystkim użytkownikom pokazuje się menu witryny głównej.