Documentation for the Textpattern plugin smd_style by Stef Dawson follows this short message from our sponsor ;-)
If you like my code and it soothes an otherwise unscratchable itch, feel free to show your appreciation with something from my UK Amazon wish list (or US) or donate to the Stef Dawson community coding pot, either via paypal.me/stefdawson or by following the Donate button below to PayPal. Thanks!
smd_style
Manage alternate stylesheets and (optionally) switch between them via Javascript. Alternatively, switch between CSS class names on arbitrary objects to effect style changes.
Features:
- Provide a list of style sheet names derived from:
- a given list
- any article field
- a
<txp:variable />
- a URL variable
- some combination of the above
- Use either the built-in stylesheet switching ability of modern browsers or the plugin’s javascript switchers
- Current style stored in a cookie: can be instructed to load that style first on subsequent pages
- Compatible with Txp stylesheets, ‘real’ stylesheets and the rvm_css plugin
- Optionally build your own stylesheet syntax via a form/container
- Put Txp tags inside your stylesheets if you wish (requires Txp-style sheet processing, i.e real_sheets must be off)
Author
Installation / Uninstallation
Download the plugin from either textpattern.org, or the software page, paste the code into the Txp Admin -> Plugins pane, install and enable the plugin. Visit the forum thread for more info and to report the success (or otherwise) of this plugin.
To uninstall, simply delete from the Admin -> Plugins page.
Usage
There are two tags available: one for use in the <head>
of your page to set up the alternate styles, and the other adds a javascript stylesheet switcher to the page, wherever you want it to appear.
smd_style
Somewhere in your HTML <head>
tag, add a call to smd_style
to include a list of alternate stylesheets. Use the following attributes to customise the output:
Attributes
- sheets : a comma-separated list of stylesheets to include. These are their Txp names as given on the Presentation->Styles tab. See sheet names for more
- form : the Txp form in which to build your own
<link>
tags. See replacement tags. If not specified (and no container is used) a standard HTML link will be output - use_default : the list of stylesheets given in the
sheets
parameter does not usually contain the ‘default’ stylesheet associated with the section. This allows you to always include a ‘global’ sheet with core rules in it and have the alternates override/fill in the gaps. If, however, you wish smd_style to output the default stylesheet so you don’t have to do it elsewhere, specifyuse_default="1"
- promote_recent : Determine what to do when the page loads and the visitor has already switched to an alternate stylesheet. This can be useful to try and help prevent ‘flashes of unstyled content’ in good browsers. Can take one of three values:
0
: do nothing, i.e. sheets are always loaded in the given order1
(the default) : any style sheet that has been chosen by the visitor will be loaded as soon as possible after any core sheets (i.e. sheets that you want to be non-alternate). Thus if you have 2 ‘core’ sheets and the visitor chooses the alternate sheet that used to be #4 in the list, it will now be loaded 3rd2
: any style sheet that has been chosen by the visitor will be loaded first, i.e. the chosen sheet will always be promoted to the #1 slot
- skip : in the list of sheets, skip this number of sheets before starting to label them as ‘alternate’. The special default setting of
auto
behaves thus:- if
use_default="1"
, the first sheet in the list will be skipped (i.e. will always be a true stylesheet). Equivalent toskip="1"
- if
use_default="0"
the first sheet in the list will be an alternate stylesheet (i.e. equivalent toskip="0"
)
- if
- skip_titles : in the list of sheets, skip this number of sheets before starting to add
title
attributes. The special default setting ofauto
works the same as for theskip
attribute. Note that some combinations of skip/skip_title are not permitted by the HTML specification so are disallowed. See skipping for more details - show_empty : by default, if any field (e.g. a custom field) has no value assigned to it and you try to read a sheet name, the field will be ignored. Setting this to
1
will include a stylesheet with the name of the field itself. See Example 5 for a practical application of this - real_sheets : normally, standard
css.php?n=sheet_name
references are output. If you prefer ‘real’ stylesheet filename references, set this attribute to 1. Note you will have to ensure that the stylesheet files really exist on your server in the given directory (seesheets_dir
) - sheets_dir : location (relative to the root of your textpattern installation) where your stylesheets are to be found if using
real_sheets="1"
. If you have the rvm_css plugin installed it will default to the directory specified in Admin -> Preferences -> Advanced -> Style directory - parse_tags : if you wish to be able to put Txp tags inside your style sheets and have them parsed, set this attribute to 1. Note that this only works if
real_styles="0"
because there’s no way for Textpattern to intercept a direct call to a stylesheet. Using this feature also incurs a (small) time penalty as each sheet is parsed - delim : the delimiter to use between
sheets
. Default is the comma (,) - paramdelim : the delimiter to use between additional sheet information. Default is the colon (:)
Sheet names
When using the sheets
attribute, if you precede any sheet name with a ?
the Txp environment will be searched for a matching location. For example, sheets="core, ?custom3"
would load core.css and then look in the custom3 field for a further list of stylesheets to load. The order in which the locations are searched is: 1) Article fields; 2) <txp:variable />
; 3) The URL. If a ?
value is supplied and a suitable location cannot be found, the value you gave will be used verbatim.
You may also specify up to two additional pieces of information in each sheet definition: 1) the sheet’s “pretty name” that people will see, and 2) its media type (usually screen
). To do this, separate the values with colons (unless changed via the paramdelim
attribute) like this:
<txp:smd_style use_default="1"
sheets="core, cats:Cats of the world, printer:Print layout:print" />
That would output something similar to the following:
<link rel="stylesheet" type="text/css" media="screen"
title="default" href="http://site.com/textpattern/css.php?n=default" />
<link rel="alternate stylesheet" type="text/css" media="screen"
title="core" href="http://site.com/textpattern/css.php?n=core" />
<link rel="alternate stylesheet" type="text/css" media="screen"
title="Cats of the world" href="http://site.com/textpattern/css.php?n=cats" />
<link rel="alternate stylesheet" type="text/css" media="print"
title="Print layout" href="http://site.com/textpattern/css.php?n=printer" />
Replacement tags
If you don’t like the standard output or wish to fashion your own <link>
tags then you can specify container content or a form
with which to process the results. There are replacement variables you can employ within your layout to insert the relevant content for each stylesheet:
{smd_style_name}
: the stylesheet name as given in the Txp Styles tab{smd_style_url}
: the complete URL (Txp-style or ‘real’ URL depending on thereal_sheets
attribute){smd_style_media}
: the media type of stylesheet (e.g. screen, print…){smd_style_rel}
: the stylesheet relationship (either ‘stylesheet’ or ‘alternate stylesheet’){smd_style_title}
: the human-friendly title you have assigned to the stylesheet. If not specified, it defaults to the stylesheet name{smd_style_counter}
: the current stylesheet number being processed{smd_style_total}
: the total number of stylesheets in the list
Skipping
The HTML specification allows for three types of stylesheet:
- Persistent : ones that are forced on the user unless they choose “No Styles” from their browser menu
- Preferred : ones that are always loaded but can be swapped out for others
- Alternate : ones that are not loaded by default but can be switched in and out freely by the user
With a combination of use_default
, skip
and skip_title
you can offer any of these types. Some combinations of skip
and skip_title
are not permitted because they would render illegal HTML (e.g. the case when you have an alternate stylesheet without a title).
To try and make it a little easier to visualise, here is a table that shows which of the stylesheet flavours are served with varying values of these attributes. Assume you have two stylesheets labelled A and B. Sheet A will be set to:
skip=0 | skip=1 | |
skip_title=0 | Alternate | Preferred |
skip_title=1 | (disallowed) Alternate | Persistent |
The same logic applies if using the auto
parameter and/or the use_default
attribute. The first sheet in the list will become one of those flavours of Stylesheet where the values of skip
and skip_title
intersect. If using higher values, the first few sheets become those particular flavours.
smd_styleswitch
Requires jQuery to be loaded on your page, before the call to smd_styleswitch. Tested with v1.7.
On its own the smd_style tag gives the visitor the ability to switch styles via the ‘View alternate stylesheet’ facility of modern browsers. If you wish to offer them a way of instantaneously switching (and remembering) the chosen theme from within your content, use smd_styleswitch
somewhere in the flow of your page to insert a stylesheet switcher.
Alternatively, you may decide not to bother with traditional stylesheet switching at all and may prefer to simply switch class names on certain elements of the page to effect changes.
It can be customised as follows:
Mode 1: Stylesheet switcher
Attributes
- wraptag : standard HTML tag to wrap the entire switcher with. Default is
ul
. If you do not specify this attribute you must create your own container somewhere else in the page and tell the plugin its ID or class so it can find it - html_id : HTML ID to apply to the wraptag. Default is unset. If you have not specified a
wraptag
, you may give the ID of your own container so the switcher can be inserted - class : CSS class to apply to the wraptag. Default is
smd_switcher
. If you have not specified awraptag
, you may give the class name of your own container so the switcher can be inserted - break : Default is
li
. Can be either:- a standard HTML tag to wrap each stylesheet name and link with.
- text to place between each element, such as
break="--"
(seebreak_is_tag
)
- break_is_tag : if the
break
attribute is a tag, this should be set to 1 (which it is by default). If you wish to use something else between each stylesheet name (e.g.break=" | "
) set this to 0 - linkclass : CSS class to apply to each stylesheet link that is inserted. Default is
smd_styleswitch
- linkloc : the HTML attribute to compare for a match. When you click a link, in order to determine which one has been clicked, some unique information must be present in each link. You might choose the anchor’s ‘name’ attribute (in which case, use
linkloc="name"
) or perhaps the ‘rel’. Default:rel
(in this mode) orname
in class switching mode - activeclass : CSS class to indicate the currently selected stylesheet link. Default is
smd_currstyle
- alt_only : if set to
1
will only offer stylesheets with a rel that includes ‘alternate’ in the list. The default behaviour (0) is to list all stylesheets on the page that contain a ‘title’ attribute - sort : set to 1 (the default) to sort the stylesheets in alphabetical order. If set to 0, the most recently used stylesheet will be shown at the head of the list
- case_sensitive : whether the
sort
is case sensitive (1) or not (0). Default is 0 - expiry : number of days after which the
smd_style
cookie that holds the current style information remains valid. Default is30
. Set to 0 to disable cookie storing - form : if you prefer to make your own links instead of using the default anchor tags, either use the tag as a container or specify a Txp form with which to process each link. Default: unset
The stylesheet switcher that is inserted at the given location consists of an anchor tag with a link to the new stylesheet. The text within the anchor is the stylesheet title (if supplied) or its name if not. Note that the switcher will pick up all stylesheets that have a title attribute so if any of your other stylesheets not controlled by the plugin have titles, they will be included as well. This could be considered a feature(!)
If you are a neatness buff and prefer that all javascript goes in the <head>
, using wraptag=""
will allow you to insert the <txp:smd_styleswitch />
tag in the head of your document while locating your switching container elsewhere. Just tell the plugin either the html_id
or class
of your switch container and the switcher will be inserted there.
Mode 2: Class switcher
The other way to use the tag is as a class changer. You may target any selector on the page and offer a list of class names that will be applied to that element when the relevant switch link is chosen.
Attributes
Takes the same attributes as above, with the exception that alt_only
is ignored. In addition:
- byclass : this puts the plugin into “class switching mode”. It works like the
sheets
attribute of the smd_style tag. Specify a list of class names that users may choose between. If you follow the class name with a colon (:) you may specify a “friendly” name to show to people instead of the class name itself. The special class namedefault
removes all classes that have been applied to the selector. See example 7. - destination : the DOM element ID you wish to add classes to, e.g.
destination="#my_div"
ordestination=".my_class"
. Default:body
- clean : if this is set to 1, anything inside your designated wraptag container will be removed before adding the switcher content. Default: 1
- delim : the delimiter to use between items in the
byclass
attribute. Default: comma - paramdelim : the delimiter to use between class and name in the
byclass
attribute. Default: colon
If you put more than one smd_styleswitch tag in this mode, each will function independently so you can add class combos to the same element (see example 8). Very useful for specifying two different lists of classes: one for “screen” styles and one for “print styles” that operate independently.
But beware the following caveats when putting multiple smd_styleswitch tags on a single page. For hassle-free operation, you should:
- attach each tag to a unique element. In other words, change the
class
orhtml_id
to something different in each tag - ensure that
linkclass
is also unique for each tag, otherwise you may get odd results when choosing a style - be aware that using the same classname twice (e.g.
default
in two tags) will not switch properly if you are using alinkloc="id"
because the plugin will try and assign the same name to two different IDs, which is illegal DOM markup
Gotchas
- Make sure jQuery can be found by the page, or smd_styleswitch will do nothing
- If using certain wraptag elements (e.g. the default “ul”), the HTML validator may complain that the element is “unfinished” because it does not render the javascript which inserts the remaining ‘li’ tags. If this bothers you, set
wraptag=""
and specify your own container, filling it with an empty child tag (e.g.<li> </li>
). The plugin will empty the contents of the container before adding the links as long as theclean="1"
is used in the tag (which it does by default) - You must use one (or both) of either
class
orhtml_id
attributes, otherwise the plugin will not be able to attach itself. the html_id is used in preference toclass
if both are used
Examples
Example 1: alternate stylesheets
<txp:smd_style
sheets="yellow, green, brown, blue, pink, black" />
<txp:smd_styleswitch wraptag="" />
Somewhere further down the page you would have to add:
<ul class="smd_switcher"></ul>
That will add six alternate stylesheets to the page and add a switcher wherever your <ul>
appears on the page. A few modifications are possible:
- with rvm_css installed, adding
real_sheets="1"
to thesmd_style
tag would change the URLs to ‘real’ CSS file paths - adding
use_default="1"
will add the current section’s stylesheet to the list as well. If it happens to be the same as one of the ones in the list already, it will only be used once - adding
skip="2"
will cause the ‘yellow’ and ‘green’ sheets to be static (non-alternate) - using
promote_recent
will change the load order as follows:0
: load order will always be yellow, green, brown, blue, pink, black1
: promote the chosen sheet up the list. Withuse_default="1" skip="2"
, if the visitor chose ‘pink’ as their theme and refreshed the page, the load order would be: yellow, pink, green, brown, blue, black (yellow and pink would be listed as “static” stylesheets)2
: force whichever sheet was most recently chosen to be the first loaded. Again, if the visitor chose ‘pink’ as their preferred sheet and refreshed the page, the load order would be pink, yellow, green, brown, blue, black (pink and yellow would be static sheets)
Example 2: using txp_variable
To set up the names of the stylesheets you want to include in a <txp:variable />
try this:
<txp:variable name="alt_styles"
value="girls:Girly theme, boys:Lads only" />
<txp:smd_style sheets="?alt_styles" />
Example 3: persistent sheets
Grab the default sheet, the “fixed” sheet (and make them both ‘static’) then look in the custom field labelled alt_styles
and the URL variable mytheme
for more sheet definitions.
<txp:smd_style sheets="fixed, ?alt_styles, ?mytheme"
use_default="1" skip="2" />
Note that no distinction is made where to find the variables, they are just checked in order and the first one it finds that matches (if at all) will be used. Thus if you had a custom field labelled alt_styles
and someone put site.com/my_page?alt_styles=two,three,four
on the URL, you would still have them read from the custom field because it is ‘higher’ in the hierarchy. One caveat is that if the custom field is empty, the next place in the list is checked until all locations are exhausted, though you can ignore empty fields with show_empty="0"
.
Example 4: custom link layout
For a non-HTML DTD you may need to drop the trailing /
on the <link>
elements, so you could do this:
<txp:smd_style sheets="blue, red, green">
<link rel="{smd_style_rel}" type="text/css"
media="{smd_style_media}" href="{smd_style_url}"
title="{smd_style_title}">
</txp:smd_style>
Example 5: show_empty
The show_empty
attribute seems fairly pointless on the surface, but imagine this scenario: you set up a custom field called default_style
. When authoring articles, people can insert the name of a stylesheet in there to style the page with. But if they leave it blank you could ensure the page renders with at least some default content by creating a stylesheet called “default_style” (i.e. the same name as the custom field) and using a tag like this:
<txp:smd_style sheets="?default_style"
show_empty="1" />
If the custom field is empty, the plugin converts the request to <txp:smd_style sheets="default_style" />
.
Example 6: tag parsing
<txp:smd_style sheets="first, second, third"
parse_tags="1" />
If one of your stylesheets contained the following:
.filler {
background:url(<txp:site_url />images/bg.jpg);
color:red;
}
The Txp tag would be replaced with the contents before being served. This does have a performance penalty as the stylesheet is fetched and parsed, but can be very useful. You may use <txp:php></txp:php>
tags in the stylesheet as long as the admin preference to allow page level PHP is enabled. Many thanks to akokskis for some of the code from ako_cssParse that enables this feature.
Example 7: class switching
<txp:smd_styleswitch
byclass="default:Normal, mini:Small,
maxi:Large" class="switcher" />
That tag will show a three-way class switcher containing three anchors as an unordered list. When you click:
- Small the
mini
class is added to the<body>
tag - Large the
maxi
class replaces themini
class - Normal either
mini
ormaxi
are removed (whichever was in force at the time)
Thus with appropriate rules in a stylesheet you can switch the font size of the document on the fly. For example:
body {
font-size:1em;
}
body.mini {
font-size:.8em;
}
body.maxi {
font-size:1.3em;
}
If you loaded your stylesheet with media="print"
then the styles would only be applied to the printed version of the page.
Example 8: multiple class switchers
Let’s add a second smd_styleswitch tag to the page, in addition to the one in example 7.
<txp:smd_styleswitch
byclass="default:Black on white, yob:Yellow on blue,
gob:Green on black" linkclass="smd_colours" />
Notice first that this one takes linkclass
. This is so that the two switchers are uniquely addressable — the first used the default linkclass of smd_styleswitch
. Without this, the two switchers will clash and things won’t work properly.
The second switcher will be rendered and the two work independently; visitors can choose one style from each switcher. So they might click:
- Large and Yellow on blue : both
maxi
andyob
classes would be added to the<body>
tag - Large and Green on black :
maxi
andgob
classes would apply to the body - Normal and Green on black : just the
gob
style is applied - Normal and Black on white : both styles are removed. Note that any other styles you may have manually applied are left untouched
Again, with suitable classes you can allow people to combine the look of a page to their tastes. By default, their preferences are saved in the smd_style
cookie so each page will have the same style applied.
Changelog
- 12 Oct 2008 | 0.10 | Initial release
- 18 Oct 2008 | 0.20 | Added
parse_tags
(thanks akokskis / johnstephens) ; addedskip_title
; fixed invalid link tags ;real_sheets
now work without a form/container - 17 Nov 2011 | 0.30 | smd_styleswitch can now switch classes too ; added
html_id
andform
attributes ; cookie can be disabled ; jQuery 1.3 fix
Source code
If you’d rather wander aimlessly through thousands of lines of PHP source code, you’ll need to step into the view source page.
Legacy software
If, for some inexplicable reason, you need the un-current version of a plugin, it can probably be found on the plugin archive page.
Experimental software
If you’re feeling brave, or fancy dipping your toe in shark-infested water, you can test out some of my beta code. It can be found on the plugin beta page.