SharePoint Server 2007 uses this control to display the navigation path and whilst this appears to be acceptable, under the bonnet it renders non-semantic markup that doesn't fully represent a visitor's current position in the site and is also more difficult to brand. SharePoint 2010 ships with a new control called the ListSiteMapPath that uses semantic markup to display the navigation path and although this is a landmark development, if you need much greater control over the rendered content or you want to manipulate the behaviour of your navigation path (or you're simply using SharePoint 2007) then read on.
To begin with we're going to use the good old SiteMapPath control which works in both SharePoint 2007 and SharePoint 2010 but as previously described renders non-semantic markup:
<span><a href="...>Home</a></span><span> > </span><span><a href="...>Company</a></span><span> > </span><span><a href="...>Press</a></span><span> > </span><span><a href="...>A Lovely Day</a></span>
To a screen reader or a search engine this has no underlying context and will just appear as a chain of words so we need fix this up by transforming it into a nest of unordered lists:
<div class="AspNet-siteMap">
<ul>
<li>
<a href="/" class="AspNet-SiteMap-Link">Home</a>
<ul>
<li>
<a href="… class="AspNet-SiteMap-Link">Company</a>
<ul>
<li>
<a href="… class="AspNet-SiteMap-Link">Press</a>
<ul>
<li>
<a href="… class="AspNet-SiteMap-Link">A Lovely Day</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
This can then be styled using CSS for our finished breadcrumb:
.AspNet-siteMap
{
font-family: Arial, Sans-Serif;
font-size: 80%;
font-weight: normal;
color: #ffffff;
margin: 0 0 20px 0;
}
.AspNet-siteMap ul {display: inline; margin: 0; padding: 0;}
.AspNet-siteMap ul li {display: inline; margin: 0;}
.AspNet-siteMap ul a
{
color: #9ACD34;
margin-right: 3px;
text-decoration: none;
display: inline-block; /* IE needs this for proper background image position if lines break */
font-weight: bold;
}
.AspNet-siteMap ul ul a
{
color: #FFF;
background: url(../images/BcBullet.gif) no-repeat 0 6px;
padding: 0 0 0 12px; /* list indent */
font-weight: normal;
}
.AspNet-siteMap ul a:hover {text-decoration: underline;}
To get this up and running create a custom control that derives from the ASP.NET SiteMapPath control (signing the assembly and deploying it to the GAC):
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Text.RegularExpressions
Namespace Custom.Web.UI.WebControls
<DefaultProperty("Text"), ToolboxData("<{0}:CustomSiteMapPath runat=server></{0}:CustomSiteMapPath>")> _
Public Class CustomSiteMapPath
Inherits SiteMapPath
<Bindable(True), Category("Appearance"), DefaultValue(""), Localizable(True)> Property Text() As String
Get
Dim s As String = CStr(ViewState("Text"))
If s Is Nothing Then
Return "[" + Me.ID + "]"
Else
Return s
End If
End Get
Set(ByVal Value As String)
ViewState("Text") = Value
End Set
End Property
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
If IsPublishingPage() Then
MyBase.SiteMapProvider = "CurrentNavSiteMapProviderNoEncode"
End If
MyBase.OnInit(e)
End Sub
Public Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter)
writer.WriteLine()
writer.WriteBeginTag("div")
writer.WriteAttribute("class", "AspNet-siteMap")
writer.Write(HtmlTextWriter.TagRightChar)
End Sub
Public Overrides Sub RenderEndTag(ByVal writer As System.Web.UI.HtmlTextWriter)
writer.WriteEndTag("div")
writer.WriteLine()
End Sub
Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
writer.Indent += 1
Dim item As SiteMapPath = CType(Me, SiteMapPath)
Dim Provider As SiteMapProvider = item.Provider
Dim collection As New SiteMapNodeCollection()
Dim node As SiteMapNode = Provider.CurrentNode
While Not node Is Nothing
collection.Add(node)
node = node.ParentNode
End While
BuildItems(collection, True, writer)
writer.Indent -= 1
writer.WriteLine()
End Sub
Private Sub BuildItems(ByVal items As SiteMapNodeCollection, ByVal isRoot As Boolean, ByVal writer As HtmlTextWriter)
If items.Count > 0 Then
For i As Integer = items.Count - 1 To -1 + 1 Step -1
BuildItem(items(i), writer, (i = 0)) '0 is current node
Next
'close nested list
For i As Integer = 0 To items.Count - 1
writer.Indent -= 1
writer.WriteLine()
writer.WriteEndTag("li")
writer.Indent -= 1
writer.WriteLine()
writer.WriteEndTag("ul")
Next
End If
End Sub
Private Sub BuildItem(ByVal item As SiteMapNode, ByVal writer As HtmlTextWriter, ByVal isCurrentNode As Boolean)
If (item IsNot Nothing) AndAlso (writer IsNot Nothing) Then
If item.Url.Length > 0 Then
writer.WriteLine()
writer.WriteFullBeginTag("ul")
writer.Indent += 1
writer.WriteLine()
writer.WriteFullBeginTag("li")
writer.Indent += 1
writer.WriteLine()
writer.WriteBeginTag("a")
writer.WriteAttribute("href", Page.ResolveUrl(item.Url))
writer.WriteAttribute("class", "AspNet-SiteMap-Link")
writer.Write(HtmlTextWriter.TagRightChar)
writer.Write(item.Title)
writer.WriteEndTag("a")
End If
End If
End Sub
Private Function IsPublishingPage() As Boolean
Dim url As String = HttpContext.Current.Request.RawUrl
Dim pattern As String = ".*\/pages\/.+\.aspx"
Dim urlMatch As Match = Regex.Match(url, pattern, RegexOptions.IgnoreCase)
Return urlMatch.Success
End Function
End Class
End Namespace
Mark the assembly as safe in the web.config file of the web application:
<SafeControl Assembly="CustomSiteMapPath, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3f64c3f72c5f0c95" Namespace="Custom.Web.UI.WebControls" TypeName="*" Safe="True" />
Register the control in the master page or page layout:
<%@ Register TagPrefix="uc" Namespace="Custom.Web.UI.WebControls" Assembly="CustomSiteMapPath, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3f64c3f72c5f0c95" %>
And finally add an instance of the control into the master page or page layout:
<uc:CustomSiteMapPath ID="CustomSiteMapPath1" runat="server" SiteMapProvider="SPContentMapProvider" SkipLinkText="" AdapterEnabled="False"></uc:CustomSiteMapPath>
Note that if you are using the ASP.NET CSS Friendly Control Adapters in your SharePoint site then you must set the AdapterEnabled property on your control instance to False otherwise the CSS Friendly Control Adapter will continue to take precedence.

No comments:
Post a Comment