|
Skins /
Skin GuidelinesContent: Summary: A set of tips for skin design and packaging skins for distribution
Status: Stable
Version: 2007-07-21
Prerequisites: pmwiki 2
Maintainer: Hagan Fox
How A Skin WorksThe main component of a skin is its template file. Pmwiki goes through (parses) the template and makes substitutions when it sees special layout markers (e.g. layout variables, also called skin directives). The skin's template file is named either pub/skins/<skin-name>/<skin-name>.tmpl or pub/skins/<skin-name>/skin.tmpl where <skin-name> is all lower case with no spaces or hyphens. For example, a template file for "Foo Skin" would be pub/skins/foo/foo.tmpl. To have PmWiki use this skin, you'd add ## Use the Foo Skin. $Skin = 'foo'; to your local/config.php local configuration file. There are three required layout markers:
So a template file takes this basic form: <html> <head> ...some header stuff... <!--HTMLHeader--> ...some more header stuff... </head> <body> ...some HTML... <!--PageText--> ...some more HTML.... <!--HTMLFooter--> </body> </html> Of course the "header stuff" and "HTML" may include all kinds of things that may change dynamically in many ways. Often a skin also has at least one CSS stylesheet file and a PHP file. The PHP file must be named either skin.php or <the skin's folder name>.php, (e.g. foo.php for a skin in the pub/skins/foo/ directory). A documentation text file should also be included in a skin's folder. Example files for a Foo Skin: pub/skins/foo/ |-- README.txt Documentation |-- foo.tmpl Template |-- foo.css CSS stylesheet `-- foo.php PHP script Page SectionsSections of output can be denoted using When a section is "turned off", output is suppressed from the A page section can also be turned off in a recipe or local configuration script using markup like SetTmplDisplay('PageXyzFmt', 0);
that will suppress the Since PmWiki 2 beta 22, you can make your own Note that Skin directives that denote page sectionsThese are provided by default:
Special skin directivesPmWiki includes special markers for inserting content from a wiki page, markup in the template, a PHP function, or a file on disk.
The Page TitleEach HTML page requires a
One problem with this is that any
Define the variable in the skin PHP file, and add a modified markup for the global $HTMLTitle, $WikiTitle;
$HTMLTitle = $WikiTitle.' - '.PageVar($pagename, '$Titlespaced');
## Markup (:notitle:)
Markup('notitle','directives','/\\(:notitle:\\)/e',
"NoTitle2(\$pagename)");
function NoTitle2($pagename) {
global $HTMLTitle, $WikiTitle;
SetTmplDisplay('PageTitleFmt', 0);
$HTMLTitle = $WikiTitle;
}
Sample basic templatesIf all these elements are in place the resulting skin will be fully functional, but rather bare to look at. Here is a bare-bone skin template, with just a minimum of styling so the
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<title>$WikiTitle</title>
<style type='text/css'><!--
body { margin:1em 1em 0 14em; }
#location { margin:0 0 8px 0; }
#sidebar { position:absolute; top:10px; left:1em; width:10em; }
--></style>
<!--HTMLHeader-->
</head>
<body>
<!--PageHeaderFmt-->
<a href='$ScriptUrl/'><img src='$PageLogoUrl'
alt='$WikiTitle' border='0' /></a>
<!--/PageHeaderFmt-->
<hr />
<!--PageTitleFmt-->
<h1 id='location'><a href='$ScriptUrl/$Group'>$Group</a>
» $Title</h1>
<!--PageText-->
<hr />
<!--PageFooterFmt-->
<a href='$ScriptUrl/$[$Group/RecentChanges]'>$[Recent Changes]</a> |
<a href='$PageUrl?action=print' target='_blank'>$[Printable View]</a> |
<a href='$PageUrl?action=diff'>$[Page History]</a> |
<a href='$PageUrl?action=edit'>$[Edit Page]</a><br />
$[Page last modified on $LastModified]
<!--PageLeftFmt-->
<div id='sidebar'><!--wiki:$Group.SideBar $SiteGroup.SideBar--></div>
<!--HTMLFooter-->
</body>
</html>
This skin template provides functionality and a basic page layout with the content ahead of the menu, which is advantageous for handheld browsers. Here's another one, this time with a <!--PageActionsFmt--> section.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<title>$WikiTitle</title>
<style type='text/css'><!--
body { margin:1em 1em 0 14em; }
#location { margin:0 0 8px 0; }
#sidebar { position:absolute; top:10px; left:1em; width:10em; }
#actions
{ position:absolute; top:10px; right:1em; white-space:nowrap; }
#actions ul { list-style:none; margin:0px; padding:0px; }
#actions li { display:inline; margin:0px 5px; }
--></style>
<!--HTMLHeader-->
</head>
<body>
<!--PageHeaderFmt-->
<a href='$ScriptUrl/'><img src='$PageLogoUrl'
alt='$WikiTitle' border='0' /></a>
<!--/PageHeaderFmt-->
<hr />
<!--PageTitleFmt-->
<h1 id='location'><a href='$ScriptUrl/$Group'>$Group</a>
» $Title</h1>
<!--PageText-->
<hr />
<!--PageLeftFmt-->
<div id='sidebar'><!--wiki:$Group.SideBar $SiteGroup.SideBar--></div>
<!--PageActionsFmt-->
<div id='actions'><!--wiki:$SiteGroup.PageActions--></div>
<!--PageFooterFmt-->
<a href='$ScriptUrl/$[$Group/RecentChanges]'>$[Recent Changes]</a>
(<a href='$ScriptUrl/$[$SiteGroup/AllRecentChanges]'>$[All]</a>)<br />
$[Page last modified on $LastModified]
<!--HTMLFooter-->
</body>
</html>
TranslationThe text inside CSS Files: Controlling Page StylePage style can come from four places:
A skin can provide styling three ways:
The main difference among these three is the order in which styles appear, which affects how skin styles take precedence compared to styles from the other sources. This is important because with CSS values assigned to attributes later will take precedence over what was assigned earlier. The last wins. A single-stylesheet approachUsing this method, which is preferred by some very experienced skin authors, a single stylesheet is loaded via a global $HTMLHeaderFmt; $HTMLHeaderFmt['skin'] = " <link rel='stylesheet' href='\$SkinDirUrl/skin.css' type='text/css' />\n "; The Here a hierarchy is created where where the skin styles override the core PmWiki styles and recipe styles from local configuration files such as config.php. The wiki administrator can take final control over styling using local stylesheets (but not recipes). Of course multiple stylesheets may be loaded this way also, allowing logic to determine which stylesheet links appear late in the <head> section of the page. The point is that using
Two-stylesheet approachThe default PmWiki skin, which has no skin.php file, uses a single stylesheet linked from the skin.tmpl file. <link rel='stylesheet' href='$SkinDirUrl/skin.css' type='text/css' /> <!--HTMLHeader--> The order of the two lines is very important. If they are reversed, the skin stylesheet link appears extremely late in the <head> section and the wiki administrator can't override the skin's styling. With the two lines in the correct order the load order of styles is
A skin author may, however, want to override the PmWiki defaults.The most reliable way to override the PmWiki defaults is to insert a second stylesheet using global $HTMLHeaderFmt; $HTMLHeaderFmt['skin'] = " <link rel='stylesheet' href='\$SkinDirUrl/skin2.css' type='text/css' />\n "; By linking stylesheets from both skin.tmpl and skin.php, the skin author can allow some styles to be overridden by recipes, but not others. The load order of styles is
Why pmwiki.php embeds CSSThe reason why pmwiki.php embeds the CSS is to reduce the overhead on skin authors and to preserve an upgrade path. The styles defined by In the past many have indicated that we should "dis-embed" the CSS from pmwiki.php, and require every skin author to include these minimal definitions (possibly modified) in the skin's .css file. This slightly increases the work required to develop a skin, because the skin author has to copy the definitions somewhere. But more importantly, moving all of PmWiki's CSS properties into the skins can make future PmWiki upgrades a bit of a pain, because when a style definition is added or changed in the core, every existing skin would then need to be modified to incorporate the new minimal specification. I prefer to avoid that level of coupling between core and skins. The current approach allows skin CSS properties to be completely
decoupled from CSS properties needed for core and recipe markups.
In fact, in this sense pmwiki.php uses Replacing default CSS entirelyA skin that wants to completely replace the pmwiki.php defaults with its own can do the following in skin.php: global $HTMLStylesFmt; $HTMLStylesFmt['pmwiki'] = ''; $HTMLStylesFmt['diff'] = ''; $HTMLStylesFmt['simuledit'] = ''; $HTMLStylesFmt['markup'] = ''; $HTMLStylesFmt['urlapprove']= ''; $HTMLStylesFmt['vardoc'] = ''; $HTMLStylesFmt['wikistyles']= ''; Bundling wiki pagesStarting with PmWiki 2.0.beta51 (or perhaps beta44) you can distribute skin-specific pages with your skin. What those pages might contain is limited only by your imagination. Custom Edit Form and Preferences PageYou can use skin-specific pages to bundle a custom Edit Form and a Preferences page with your skin. Here's an example block of code from the Foo Skin's PHP script:
## Add a custom page storage location for bundled pages.
$PageStorePath = dirname(__FILE__)."/wikilib.d/\$FullName";
$where = count($WikiLibDirs);
if ($where>1) $where--;
array_splice($WikiLibDirs, $where, 0, array(new PageStore($PageStorePath)));
## Enable the Preferences page.
XLPage('foo', "$SiteGroup.FooXLPage");
array_splice($XLLangs, -1, 0, array_shift($XLLangs));
## Enable the skin's custom EditForm, either
## configurable via a prefs page (XLPage) or not.
if ($EnableEditFormPrefs == TRUE) {
SDV($PageEditForm, "$[$SiteGroup.FooEditForm]");
} else {
SDV($PageEditForm, "$SiteGroup.FooEditForm"); }
The customized edit page is This is the Foo Skin Preferences page: [= # Define a custom edit form. 'Site.EditForm' => 'Site.FooEditForm', =] The Preferences page tells PmWiki to use the custom Edit Form, but it could also be used for other translations as well. The preferences page would also be a good place to put translation strings that are specific to the skin. An admin who doesn't want users to create custom edit forms or other customizations can disable user preferences entirely by setting JavaScript TipNote: This tip is slightly obsolete because it's now possible for form directives to specify "focus=1" as an option to indicate the control that should receive focus when the page is loaded.
"Favouring writers over readers": Putting the following code into the onload-handler (i.e. in
var contentNode = document.getElementById("content");
var contentForms = contentNode.getElementsByTagName("form");
var firstContentForm = contentForms[0];
if (firstContentForm) {
for (var i=0; i < firstContentForm.length; i++) {
if (firstContentForm.elements[i].type != "hidden") {
firstContentForm.elements[i].focus();
break;
}
}
}
Enclose Tested with NotSoSimpleSkin. ThomasP (PmWiki 2.1.beta25) NotesIn references to skin.php above - skin can both be the literal 'skin' or the name of the skin in question, the latter takes precedence over the former. Chris Stiles About See also
User notes? : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Skins listings and will help newcomers browsing through the wiki. |