I'm a novice in umbraco and the macrodevelopment in XSLT, and I am trying to make a 2 level topmenu with individual styling on each menu item. Perhaps not a good starting point in Umbraco learning but here goes:
Problem: When I select a submenu item I have to make 1level menu item and second level item active (some kind of highlighting). So I have to manipulate the class attributes with XSLT. It works fine with 1level but when I hit a secondlevel menu item all 'active' styling dissapappears.
To keep the 'active' info you need to check if the current node is in the ancestor axis of $currentPage (you're only checking if the current node is $currentPage).
I'd do something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:param name="currentPage" />
<xsl:param name="level" select="/macro/StartAtLevel" />
<xsl:template match="/">
<ul class="mainMenu">
<xsl:apply-templates select="$currentPage/ancestor-or-self::node[@level = $level]/node" />
</ul>
</xsl:template>
<!-- Output template for nodes -->
<xsl:template match="node">
<xsl:variable name="uniqueclass" select="concat('menu', position() + 1)" />
<li>
<!-- class attribute only at the first level -->
<xsl:if test="@level = $level + 1">
<xsl:attribute name="class"><xsl:value-of select="concat($uniqueclass, ' menu')" /></xsl:attribute>
<xsl:if test="$currentPage/ancestor-or-self::node[@id = current()/@id]">
<xsl:attribute name="class"><xsl:value-of select="concat($uniqueclass, ' active')" /></xsl:attribute>
</xsl:if>
</xsl:if>
<!-- Create the link -->
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:if test="$currentPage/@nodeName = current()/@nodeName">
<xsl:attribute name="class">active</xsl:attribute>
</xsl:if>
<xsl:value-of select="@nodeName" />
</a>
<!-- Test if any of the subnodes are visible (otherwise we could get an empty <ul />) -->
<!-- If you want infinite levels, remove the ' and @level = $level + 1' part -->
<xsl:if test="node[not(data[@alias = 'umbracoNaviHide'] = 1)] and @level = $level + 1">
<div>
<ul>
<xsl:apply-templates select="node" />
</ul>
</div>
</xsl:if>
</li>
</xsl:template>
<!-- Never output these (empty template) -->
<xsl:template match="node[data[@alias = 'umbracoNaviHide'] = 1]" />
</xsl:stylesheet>
Also (but not XSLT-related): I'd prefer to use id attributes for the unique values...
Menu with individual styling
Hi
I'm a novice in umbraco and the macrodevelopment in XSLT, and I am trying to make a 2 level topmenu with individual styling on each menu item. Perhaps not a good starting point in Umbraco learning but here goes:
Problem:
When I select a submenu item I have to make 1level menu item and second level item active (some kind of highlighting). So I have to manipulate the class attributes with XSLT.
It works fine with 1level but when I hit a secondlevel menu item all 'active' styling dissapappears.
My XSLT is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:param name="level" select="/macro/StartAtLevel"/>
<xsl:template match="/">
<xsl:call-template name="menu">
<xsl:with-param name="level" select="$level"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="menu">
<xsl:param name="level"/>
<ul class="mainMenu">
<xsl:if test="count($currentPage/ancestor-or-self::node [@level=$level]/node [string(data [@alias='umbracoNaviHide']) != '1']) > '0'">
<xsl:for-each select="$currentPage/ancestor-or-self::node [@level=$level]/node [string(data [@alias='umbracoNaviHide']) != '1']">
<li>
<xsl:attribute name="class">
menu<xsl:value-of select="position() + 1"/> menu
</xsl:attribute>
<xsl:if test="$currentPage/@id = current()/@id">
<xsl:attribute name="class">
menu<xsl:value-of select="position() + 1"/> active
</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:if test="$currentPage/@id = current()/@id">
<xsl:attribute name="class">active</xsl:attribute>
</xsl:if>
<xsl:value-of select="@nodeName"/>
</a>
<div>
<ul>
<xsl:for-each select="current()/node [string(data [@alias='umbracoNaviHide']) != '1']">
<li>
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:if test="$currentPage/@id = current()/@id">
<xsl:attribute name="class">active</xsl:attribute>
</xsl:if>
<xsl:value-of select="@nodeName"/>
</a>
</li>
</xsl:for-each>
</ul>
</div>
</li>
</xsl:for-each>
</xsl:if>
</ul>
</xsl:template>
</xsl:stylesheet>
Hope somebody can tell me where my XSLT is wrong.
Thanks
Jesper
Hi Jesper,
To keep the 'active' info you need to check if the current node is in the ancestor axis of $currentPage (you're only checking if the current node is $currentPage).
I'd do something like this:
Also have a look at this project. May be what you need. Ok, you won't learn so much from copy'n'paste, but may get you started.
Cheers,
/Dirk
Thank you both. I'm very grateful.
/Jesper
is working on a reply...