Skip to content

Instantly share code, notes, and snippets.

@greystate
Created September 5, 2012 22:18
Show Gist options
  • Save greystate/3646182 to your computer and use it in GitHub Desktop.
Save greystate/3646182 to your computer and use it in GitHub Desktop.
Umbraco CSS Style Switcher (XSLT)

A single macro for integrating a style switcher in an Umbraco website.

Progressively built on the fly, to answer this forum post on Our Umbraco.

The macro must have a mode parameter (type: text) in which you specify either link or switcher as the value - link creates the <link rel="stylesheet" href="stylesheet.css"> tag, switcher renders a set of links for switching the stylesheet.

The possible stylesheets are configured in the macro itself, and the chosen stylesheet is stored in a cookie so the site remembers the choice.

(It doesn't seem to be possible to specify the order of files in this Gist, so that's why the explanation comes before the code it explains :-)

Explaining the set trickery bit

Short version

We select the 1st stylesheet in a temporary nodeset created from the default stylesheet and the stylesheet referenced by the either the QueryString or a Cookie value.

Long version

Here's a commented version of the XPath that creates the $activeCSS variable:

(
# Select the stylesheet from the Cookie
	$stylesheets[@id = $cssCookie]

# - if there wasn't one specified in the QueryString
	[not(normalize-space($cssfile))]
|
# Add the stylesheet from QueryString
	$stylesheets[@id = $cssfile]

# - if one was specified
	[normalize-space($cssfile)]
|
# Add the last (default) stylesheet in the list
	$stylesheets[last()]
)
# Finally, select the first stylesheet in the set
[1]

Notes

  • The two first selections are mutually exclusive - only one of them will actually add a node to the set.

  • A node can only ever exist once in a set, so if both the Cookie and the QueryString reference the default stylesheet, only that single node will be in the set - even though it's technically added to the set in all three steps.

  • Nodes in a set are effectively in what's called document order, so because the default stylesheet is the last in the $stylesheets variable, any other stylesheet selected will end up before it in the created set.

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:umb="urn:umbraco.library"
xmlns:make="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="umb make"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<!-- Name of the QueryString parameter -->
<xsl:variable name="cssParam" select="'css'" />
<!-- Name of Cookie key -->
<xsl:variable name="cssCookieKey" select="'CSSFILE'" />
<xsl:variable name="mode" select="/macro/mode" />
<xsl:variable name="cssfile" select="umb:RequestQueryString($cssParam)" />
<xsl:variable name="cssCookie" select="umb:RequestCookies($cssCookieKey)" />
<!-- Configure available StyleSheets here -->
<xsl:variable name="stylesheetsProxy">
<css name="Smaller" id="small">/css/small.css</css>
<css name="Bigger" id="large">/css/large.css</css>
<!-- Last one is default -->
<css name="Standard" id="normal">/css/normal.css</css>
</xsl:variable>
<xsl:variable name="stylesheets" select="make:node-set($stylesheetsProxy)/css" />
<!-- Get the active stylesheet using some set trickery -->
<xsl:variable name="activeCSS" select="($stylesheets[@id = $cssCookie][not(normalize-space($cssfile))] | $stylesheets[@id = $cssfile][normalize-space($cssfile)] | $stylesheets[last()])[1]" />
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$mode = 'link'">
<xsl:call-template name="writeLink" />
</xsl:when>
<xsl:when test="$mode = 'switcher'">
<xsl:call-template name="writeSwitcher" />
</xsl:when>
</xsl:choose>
<!-- If a valid StyleSheet was selected, set the Cookie -->
<xsl:if test="$stylesheets[@id = $cssfile]">
<xsl:value-of select="umb:setCookie($cssCookieKey, $cssfile)" />
</xsl:if>
</xsl:template>
<xsl:template name="writeLink">
<link rel="stylesheet" href="{$activeCSS}" />
</xsl:template>
<xsl:template name="writeSwitcher">
<xsl:for-each select="$stylesheets">
<a href="?{$cssParam}={@id}" title="Use '{@name}' view">
<!-- Mark the active one -->
<xsl:if test="@id = $activeCSS/@id"><xsl:attribute name="class">active</xsl:attribute></xsl:if>
<xsl:value-of select="@name" />
</a>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment