Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Thomas Skyum 3 posts 15 karma points
    Jun 25, 2009 @ 07:36
    Thomas Skyum
    0

    Help needed for advanced XSLT navigation

    Hello

     

    I am making a navigation which involves some quite intensive CSS joggling, so basically what I would like to achieve is adding classes to the <li> elements based on different things.

    Now I have classes for: first, last and selected and any combination of these. What I would also like is to get classes added for "selected - 1" and "selected + 1" in order to style the menu-tabs on either side of the selected tab.

     

    So a menu could look like this:

    <ul>

    <li class="first">....</li>

    <li>...</li>

    <li class="next_selected">...</li>

    <li class="selected last">....</li>

    </ul>

    or like this:

  • Jamie Pollock 27 posts 102 karma points c-trib
    Jun 25, 2009 @ 09:40
    Jamie Pollock
    1

    I would imagine first you have your menu in a xsl:for-each tag so you can loop through each menu node, while in a for-each you have access to the "position()" of a node, this is a standard function not specific to any kind of xml node, but as you can imagine it allows you to get the position in a node-set of a found node.

    A practical use would be as such:

    <xsl:for-each select="$menuNodes">
    <!-- using a variable here to make the markup below clearer, this will contain the value of the class -->
    <!-- the first line adds the "first" class -->
    <!-- the second line adds the "last" class -->
    <!-- the third line adds the "selected" class, this logic is very basic if the currentPage id is the same as the current menu node id then we have a winner :)-->

    <xsl:variable name="classValue">
    <xsl:if test="position() = 1">first </xsl:if>
    <xsl:if test="position() = last()">last </xsl:if>
    <xsl:if text="$currentPage/@id = ./@id">selected</xsl:if>
    </xsl:variable>
    <li>
    <!-- only add a class attribute if we have anything to show from the variable above, cleaner HTML code, yay... -->
    <xsl:if test="string-length($classValue) &gt; 0">
    <xsl:attribute name="class"><xsl:value-of select="$classValue" /></xsl:attribute>
    </xsl:if>
    <!-- whatever you want to display in your li tag goes here -->
    </li>
    </xsl:for-each>

    You can combine the above ideas in the logic in the classValue to get the kind of class name you're looking for, I hope this helped you find your solution (if so mark it :) ).

  • Jesper Hauge 298 posts 486 karma points c-trib
    Jun 25, 2009 @ 10:36
    Jesper Hauge
    0

    Jamies answer is spot on, but I noticed it didn't contain the selected - 1 / selected + 1 functionality you asked for, so I've expanded his solution to accomodate this.

    Below you'll find an xslt-file ready to use with the runway example, in the homepage template and second level textpages:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet 
    <span style="white-space: pre;">  </span>version="1.0" 
    <span style="white-space: pre;">  </span>xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    <span style="white-space: pre;">  </span>xmlns:msxml="urn:schemas-microsoft-com:xslt"
    <span style="white-space: pre;">  </span>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" 
    <span style="white-space: pre;">  </span>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:variable name="menuNodes" select="$currentPage/ancestor-or-self::node[@nodeTypeAlias='RunwayHomepage']/node[./data[@alias='umbracoNaviHide'] = '0']" />
    
    <xsl:template match="/">
    <span style="white-space: pre;">  </span><ul>
    <span style="white-space: pre;">      </span><xsl:for-each select="$menuNodes">
    <span style="white-space: pre;">      </span> <xsl:variable name="currPos" select="position()" />
    <span style="white-space: pre;">      </span> <xsl:variable name="classValue">
    <span style="white-space: pre;">          </span> <xsl:if test="position() = 1">first </xsl:if>
    <span style="white-space: pre;">          </span> <xsl:if test="position() = last()">last </xsl:if>
    <span style="white-space: pre;">          </span> <xsl:if test="$currentPage/@id = ./@id">selected</xsl:if>
    <span style="white-space: pre;">          </span><!-- Next two lines implements befor and after selected item classes -->
    <span style="white-space: pre;">          </span> <xsl:if test="$menuNodes[number($currPos)+1]/@id = $currentPage/@id">beforeSelected</xsl:if>
    <span style="white-space: pre;">          </span> <xsl:if test="$menuNodes[number($currPos)-1]/@id = $currentPage/@id">afterSelected</xsl:if>
    <span style="white-space: pre;">      </span> </xsl:variable>
    <span style="white-space: pre;">      </span> <li>
    <span style="white-space: pre;">              </span><xsl:if test="string-length($classValue) &gt; 0">
    <span style="white-space: pre;">                  </span><xsl:attribute name="class"><xsl:value-of select="$classValue" /></xsl:attribute>
    <span style="white-space: pre;">              </span></xsl:if>
    <span style="white-space: pre;">              </span><a href="{umbraco.library:NiceUrl(@id)}">
    <span style="white-space: pre;">                  </span><xsl:value-of select="$classValue" /> : <xsl:value-of select="@nodeName" />
    <span style="white-space: pre;">              </span>
    <span style="white-space: pre;">          </span></li>
    <span style="white-space: pre;">      </span></xsl:for-each>
    <span style="white-space: pre;">  </span></ul>
    </xsl:template>
    </xsl:stylesheet>

    Regards
    .Hauge

  • Jesper Hauge 298 posts 486 karma points c-trib
    Jun 25, 2009 @ 10:44
    Jesper Hauge
    1

    Once again burned by the editor in this forum

    Seems only way to get code properly into the forum is if you type it in by hand:

    Short version:

    To add before and after classe youll need three more lines of xsl in the classValue variable:

    Outside the classValue variable You'll need a variable that stores the current position.

    <xsl:variable name="currPos" select="position()" />

    Inside the classValue you'll need two more lines

    <xsl:if test="$menuNodes[number($currPos)+1]/@id = $currentPage/@id">beforeSelected</xsl:if>
    <xsl:if test="$menuNodes[number($currPos)-1]/@id = $currentPage/@id">afterSelected</xsl:if>

    They basically look at the next or the previous node in $menuNodes and checks if next or previous node is the current page node.

    Regards
    .Hauge

  • Thomas Skyum 3 posts 15 karma points
    Jun 25, 2009 @ 11:32
    Thomas Skyum
    0

    Thanks Jamie for the answer, but as Jesper said I already had that covered :)

     

    Now you both seem to be going out from the same navigation template am I right? E.g. the variable $menuNodes is used to iterate. Now the template I wa using (which is the one that came with the Runway navigation module) does not store the nodes in a variable, it just selects them directly in the for-each statement. Can I find the template you are basing your code on somewhere? Because when I try to "decode" some the first post by Jesper, I don't get into the for-each loop.

    From what I can see in the post, this is declared prior to the for-each loop:

     

  • Jesper Hauge 298 posts 486 karma points c-trib
    Jun 25, 2009 @ 12:38
    Jesper Hauge
    1

    Hi Thomas

    You're right; there is something missing: A variable right after the currentPage param, it looks like this:

    <xsl:variable name="menuNodes"  select="$currentPage/ancestor-or-self::node[@nodeTypeAlias='RunwayHomepage']/node[./data[@alias='umbracoNaviHide'] = '0']" />

    I actually tested the xslt from my first post on a runway site, drop me a mail on jesper {at} jm-net {dot} dk, and I'll send you the file.

    .Hauge

  • Thomas Skyum 3 posts 15 karma points
    Jun 25, 2009 @ 16:24
    Thomas Skyum
    0

    Hurray, it works great! 

     

    Now on to finding out why it won't include my own document types..

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies