Copied to clipboard

Flag this post as spam?

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


  • Bjarne Fyrstenborg 1281 posts 3992 karma points MVP 8x c-trib
    Jul 29, 2012 @ 16:57
    Bjarne Fyrstenborg
    0

    Hide pages with specific doc types

    Hi..

    I use the xslt navigation below with a parameter ignoreDocumentTypes ( a commalist of doc type aliases to ignore/leave out).. I have a document type Page and TabPage.. but when I want to hide pages which use TabPage, it also hide pages from menu which use Page as document type. It seems that it check if it contains "page" in the name?

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <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="html" omit-xml-declaration="yes"/>
    
    <!--
        WHAT IS THIS FILE?
        The almighty navigation xslt.
        Will write a simple ul li menu with all
        the classes needed to style it in every possible way.
        Settings include:
        - imageProperty (For background images)
        - sort (descending/ascending)
        - ignoreDocumentTypes (Commalist of doc type aliases to ignore/leave out)
        - rootNodeId (Specifc node as root instead of the currentPage)
        - fromLevel (Index of level to start on. Relative to the content root)
        - toLevel (Index of level to end on. Relative to the content root)
        - showOnlyCurrentPath (Set 1 or 0. )
        - isSitemap (Will help sort out all nodes that should be hidden from the sitemap)
    -->
    
    <xsl:param name="currentPage"/>
    
    <xsl:variable name="Navigation.imageProperty" select="/macro/imageProperty" />
    <xsl:variable name="Navigation.sort">
      <xsl:choose>
        <xsl:when test="/macro/sort != ''">
          <xsl:value-of select="/macro/sort" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>ascending</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    
    <xsl:variable name="Navigation.ignoreDocumentTypes" select="/macro/ignoreDocumentTypes"/>
    
    <xsl:variable name="Navigation.rootNodeId">
      <xsl:choose>
        <xsl:when test="/macro/rootPage != ''">
        <xsl:value-of select="/macro/rootPage" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$currentPage/@id" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    
    <xsl:variable name="Navigation.rootNode" select="umbraco.library:GetXmlNodeById($Navigation.rootNodeId)"/>
    
    <xsl:variable name="Navigation.fromLevel">
      <xsl:choose>
        <xsl:when test="string(/macro/useSelfAsRoot) = '1'">
          <xsl:value-of select="number($Navigation.rootNode/@level) + 1" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="/macro/fromLevel != ''">
              <xsl:value-of select="/macro/fromLevel" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="2" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="Navigation.toLevel">
      <xsl:choose>
        <xsl:when test="/macro/numberOfLevels != ''">
          <xsl:value-of select="number($Navigation.fromLevel) + number(/macro/numberOfLevels) - 1" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="1000" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    
    <xsl:variable name="Navigation.showOnlyCurrentPath">
      <xsl:choose>
        <xsl:when test="/macro/showOnlyCurrentPath != ''">
          <xsl:value-of select="/macro/showOnlyCurrentPath" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="1" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    
    <xsl:variable name="Navigation.isSitemap">
      <xsl:choose>
        <xsl:when test="/macro/isSitemap != ''">
          <xsl:value-of select="/macro/isSitemap " />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="0" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    
    
    <xsl:template match="/">
    
      <xsl:call-template name="MenuItems">
        <xsl:with-param name="menuItems" select="$Navigation.rootNode/ancestor-or-self::* [@level=number($Navigation.fromLevel - 1)]/* [@isDoc and not(contains($Navigation.ignoreDocumentTypes, name())) and ( ( $Navigation.isSitemap != '1' and string(./umbracoNaviHide) = '0' ) or ( $Navigation.isSitemap = '1' and string(./umbracoSitemapHide) = '0' ) )]" />
        <xsl:with-param name="currentLevel" select="$Navigation.fromLevel" />
        <xsl:with-param name="levelCounter" select="1" />
      </xsl:call-template>
    
    </xsl:template>
    
    <xsl:template name="MenuItems">
      <xsl:param name="menuItems"/>
      <xsl:param name="currentLevel"/>
      <xsl:param name="levelCounter"/>
    
      <xsl:variable name="count" select="count($menuItems)"/>
    
      <xsl:if test="$count &gt; 0">
    
        <ul>
          <xsl:if test="$levelCounter = 1 and /macro/navigationId">
            <xsl:attribute name="id"><xsl:value-of select="/macro/navigationId"/></xsl:attribute>
          </xsl:if>
          <xsl:attribute name="class"><xsl:value-of select="concat('lvl', $levelCounter)"/></xsl:attribute>
    
          <xsl:for-each select="$menuItems">
            <xsl:sort select="@sortOrder" order="{$Navigation.sort}" data-type="number"/>
    
            <xsl:if test="umbraco.library:HasAccess(@id, @path)">
    
    
              <xsl:variable name="childMenuItems" select="./* [@isDoc and not(contains($Navigation.ignoreDocumentTypes, name())) and ( ( $Navigation.isSitemap != '1' and ( string(./umbracoNaviHide) = '0' or string(./umbracoNaviHide) = '0' ) ) or ( $Navigation.isSitemap = '1' and (string(./umbracoSitemapHide) = '0' or string(./umbracoSitemapHide) = '' ) ) )]"/>
              <xsl:variable name="active" select="$currentPage [@isDoc]/@id=@id"/>
              <xsl:variable name="inpath" select="$currentPage/ancestor-or-self::* [@isDoc]/@id=@id"/>
              <xsl:variable name="firstitem" select="position() = 1"/>
              <xsl:variable name="lastitem" select="position() = $count"/>
              <xsl:variable name="hasChildren" select="count($childMenuItems) &gt; 0"/>
              <xsl:variable name="childrenShown" select="count($childMenuItems) &gt; 0 and number($currentLevel) &lt; number($Navigation.toLevel) and ( ( $inpath = '1' and string($Navigation.showOnlyCurrentPath) != '0' ) or string($Navigation.showOnlyCurrentPath) = '0' )" />
    
              <xsl:variable name="className">
                <xsl:value-of select="concat('lvl', $levelCounter)"/>
                <xsl:value-of select="concat(' pos', position())"/>
                <xsl:if test="$active = '1'"> active</xsl:if>
                <xsl:if test="$inpath = '1'"> inpath</xsl:if>
                <xsl:if test="$firstitem = '1'"> firstitem</xsl:if>
                <xsl:if test="$lastitem = '1'"> lastitem</xsl:if>
                <xsl:if test="$hasChildren = '1'"><xsl:text> hasChildren</xsl:text></xsl:if>
                <xsl:if test="$childrenShown = '1'"><xsl:text> childrenShown</xsl:text></xsl:if>
              </xsl:variable>
    
              <li>
                <xsl:if test="$className != ''"><xsl:attribute name="class"><xsl:value-of select="$className" /></xsl:attribute></xsl:if>
    
                <a title="{@nodeName}">
                  <xsl:if test="$className != ''"><xsl:attribute name="class"><xsl:value-of select="$className" /></xsl:attribute></xsl:if>
                  <xsl:attribute name="href">
                    <xsl:choose>
                      <xsl:when test="local-name() != 'ExternalLink'">
                        <xsl:value-of select="umbraco.library:NiceUrl(@id)" />
                      </xsl:when>
                      <xsl:otherwise>
                        <xsl:value-of select="./externalURL" />
                      </xsl:otherwise>
                    </xsl:choose>
                  </xsl:attribute>
                  <xsl:if test="$Navigation.imageProperty != ''">
                    <xsl:attribute name="style">
                      <xsl:text>background-image:url(</xsl:text><xsl:value-of select="umbraco.library:GetMedia(* [$Navigation.imageProperty = name()], 0)/umbracoFile" /><xsl:text>);</xsl:text>
                    </xsl:attribute>
                   </xsl:if>
                   <xsl:value-of select="@nodeName" />
                </a>
    
                <xsl:if test="number($currentLevel) &lt; number($Navigation.toLevel) and ( ( $inpath = '1' and string($Navigation.showOnlyCurrentPath) != '0' ) or string($Navigation.showOnlyCurrentPath) = '0' )">
                  <xsl:call-template name="MenuItems">
                    <xsl:with-param name="menuItems" select="$childMenuItems" />
                    <xsl:with-param name="currentLevel" select="$currentLevel+1" />
                    <xsl:with-param name="levelCounter" select="$levelCounter+1" />
                  </xsl:call-template>
                </xsl:if>
              </li>
            </xsl:if>
          </xsl:for-each>   
        </ul>
      </xsl:if> 
    </xsl:template>
    </xsl:stylesheet>

    It's these lines that might have a bug..

    <xsl:with-param name="menuItems" select="$Navigation.rootNode/ancestor-or-self::* [@level=number($Navigation.fromLevel - 1)]/* [@isDoc and not(contains($Navigation.ignoreDocumentTypes, name())) and ( ( $Navigation.isSitemap != '1' and string(./umbracoNaviHide) = '0' ) or ( $Navigation.isSitemap = '1' and string(./umbracoSitemapHide) = '0' ) )]" />
    <xsl:variable name="childMenuItems" select="./* [@isDoc and not(contains($Navigation.ignoreDocumentTypes, name())) and ( ( $Navigation.isSitemap != '1' and ( string(./umbracoNaviHide) = '0' or string(./umbracoNaviHide) = '0' ) ) or ( $Navigation.isSitemap = '1' and (string(./umbracoSitemapHide) = '0' or string(./umbracoSitemapHide) = '' ) ) )]"/>

    The macro look like this.. I think it's in the contains method the problem is..

    <umbraco:Macro fromLevel="3" sort="ascending" navigationId="mainmenu" numberOfLevels="1" rootPage="" showOnlyCurrentPath="1" useSelfAsRoot="0" isSitemap="0" Alias="Navigation" imageProperty="" ignoreDocumentTypes="Cart, News, TabPage" runat="server" />

    /Bjarne

  • Jordy Vialoux 73 posts 103 karma points
    Jul 31, 2012 @ 03:17
    Jordy Vialoux
    0

    Have you thought of using "umbracoNaviHide"? It's a pain if you have many nodes but does the job in terms of hiding the page from the navigation. 

  • Bjarne Fyrstenborg 1281 posts 3992 karma points MVP 8x c-trib
    Jul 31, 2012 @ 08:31
    Bjarne Fyrstenborg
    0

    Hi Jordy

    Yes, I am also use umbracoNaviHide in the navigation and is also able to hide each node from navigation with this property.

    But sometimes you want to exclude a lot of nodes from the navigation, e.g. news items, products.. in this case I have a TagPage document type to create tabs on the page (children of current page) .. and keep the umbracoNaviHide on this document type to allow hiding the tabs.. but I don't want them in the navigation. But still there may come subpages (standard textpages)..

    /Bjarne

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 8x admin c-trib
    Jul 31, 2012 @ 11:15
    Chriztian Steinmeier
    0

    Hi Bjarne,

    You're right - it's the contains() method that screws it up for you - basically, a check is made to see if ignoreDocumentTypes contains the name of the doctype - when the doctype's name is "Page" and the ignoreDocumentTypes contains "TabPage", the check will of course return true...

    I can not really tell if you're using any specific features of the "Almighty Navigation XSLT" - but I would definitely recommend you took a look at a much simpler approach to navigation that I've been putting into shape the last couple of months - it's on GitHub as part of my XSLT Helpers project.

    It uses the "match template" approach that XSLT was sort of built for; It doesn't do any of the security checks (HasAccess(), IsLoggedOn() etc.) but it provides some seriously simple ways to create the 4 most widely used types of navigation.

    /Chriztian

  • Bjarne Fyrstenborg 1281 posts 3992 karma points MVP 8x c-trib
    Jul 31, 2012 @ 13:09
    Bjarne Fyrstenborg
    0

    Hi Chriztian

    Yes, that's also what I thought it did.. so I'm not sure when you loop through the nodes how to check if the nodes match one value in en comma seperated list, e.g. TabPage.. and where it should match the whole value not only check if the value contains e.g. Page as it does now..

    I'm using the navigation from the Tea Commerce starterkit 

    Thanks for sharing the xslt helper project.. I'll take a look at it.

    /Bjarne

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 8x admin c-trib
    Jul 31, 2012 @ 13:18
    Chriztian Steinmeier
    1

    Hi Bjarne,

    Quick fix - what you need to do is to set the ignoreDocumentTypes parameter to "|Cart|News|TabPage|" (leading and trailing pipes - no spaces)

    Then perform the check like this:

    <xsl:if test="contains($Navigation.ignoreDocumentTypes, concat('|', name() ,'|'))">
       ...
    </xsl:if>

    (Only using pipes so the concat() check doesn't get crowded with commas :-)

    /Chriztian

  • Bjarne Fyrstenborg 1281 posts 3992 karma points MVP 8x c-trib
    Jul 31, 2012 @ 13:37
    Bjarne Fyrstenborg
    0

    Okay.. I actually tried that with comma, but it didn't quite work.. I think I saw something with comma in concat and then with a combination with substring-before and substring-after the values in the commalist was splitted (something like this http://stackoverflow.com/questions/8500652/comma-separated-string-parsing-xslt-to-for-each-node)..

    and I had also seen an example with the leading and trailing pipes, where I instead tried to fix it using a comma separated list, but didn't solve that..

    I'll try with leading and trailing pipes.. I guess the same would work if I wrote with comma like this concat(',', name(), ',') ? But the problem was probably that the ignoreDocumentTypes parameter was written ignoreDocumentTypes="News, Cart, TabPage" not ignoreDocumentTypes=",News,Cart,TabPage," ..

    /Bjarne

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 8x admin c-trib
    Jul 31, 2012 @ 13:45
    Chriztian Steinmeier
    0

    Yes - if you can't control the ignoreDocumentTypes parameter, you need to add the space after the first comma in the concat() too:

    concat(', ', name(), ',')
             ^-- that one!

    The contains() method just checks if the 1st argument string contains the 2nd argument string (using exact matching).

    But then you have a problem checking for the first doctype in there, you see? 

    /Chriztian

  • Bjarne Fyrstenborg 1281 posts 3992 karma points MVP 8x c-trib
    Jul 31, 2012 @ 14:08
    Bjarne Fyrstenborg
    0

    Yes, when the list is writting with a space.. if $Navigation.ignoreDocumentTypes was surrounded by normalize-space, would it works without the space in concat no matter the values in the parameter is written with space or not?

    but it won't be a problem to write leading and trailing pipes.. a comma list is just, I think, the most common way to separate values.. :)

    /Bjarne

  • Bjarne Fyrstenborg 1281 posts 3992 karma points MVP 8x c-trib
    Jul 31, 2012 @ 18:38
    Bjarne Fyrstenborg
    0

    It works great with using:

    <xsl:iftest="contains($Navigation.ignoreDocumentTypes, concat('|', name() ,'|'))">
       ...
    </xsl:if>

    Nice to use ignoreDocumentTypes to exclude nodes from navigation especially with a lot of nodes e.g. product nodes, without the end user should check umbracoNaviHide property for all products :)

    /Bjarne

     

Please Sign in or register to post replies

Write your reply to:

Draft