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 487 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 487 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 487 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..

Please Sign in or register to post replies

Write your reply to:

Draft