Jump to: navigation, search

The Treeview skin is a custom addition that bolts on some extra structuring and navigation support to MediaWiki's Monobook skin, and that gives this wiki a new and independent look.

The skin is installed as the default skin for this wiki. There are also a couple of (very slightly outdated) preview screenshots.


The skin adds the concept of "pseudo-namespaces" - termed "contexts" or "sub-contexts" - in wiki article titles using colons as separators, and creates a hierarchy out of them. It then displays that hierarchy as a treeview that replaces Monobook's native sidebar navigation pane. It also displays a navigation bar at the top of the page for traversal of the hierarchy without using the treeview.

Aside from the treeview and navigation bar, the concept is pretty similar to MediaWiki's native sub-page functionality that uses forward slashes. The hierarchy can be configured through the (by default) MediaWiki:Treeview article using variables, conditionals, static nodes, grafting and pruning. Sub-trees can be grafted in multiple places with different prunings applied. This configuration article corresponds to the navigation pane's MediaWiki:Sidebar configuration article.

Detailed feature listing

Feature Description Motivation
revised colour scheme, borders and general style A curved border around content, a single background colour and a new, simple, logo To differentiate this site from Wikipedia and to provide it with a unique style
navigation bar Provides buttons linking to the first, previous, previous child (last child of the previous parent), previous parent, next parent, first child, next, and last node relative to the current node. Links that don't exist are greyed out. The location of the "current node" in the hierarchy is the first match if the title appears in multiple places. When there is no previous sibling, the previous button turns into a "previous node at same depth" icon; likewise for the next button. Adds rel="<value>" attributes to links as appropriate. Bars like this are reportedly supported by some browsers based on the "rel" link attribute - here we do the opposite and supply the rel attribute after generating the bar.
tree view A graphical aid for visualising and categorising the site. Auto-expands to the currently viewed title and highlights that node and its ancestors. The tree view is (should be) expandable and collapsable for all browsers, from simple text-based browsers to javascript + css + cookie-enabled graphical browsers. A fair bit of (ongoing) effort has been put into getting reasonable results and avoiding unnecessary downloading. Comments on what works/fails would be appreciated. Further details in the "Historical status" section below.
colons denote subcontexts Contexts can be of an arbitrary number and namespaces are recognised and treated appropriately; some care has gone into dealing with MediaWiki's translation of leading and trailing underscores. Inspiration has been drawn from the way that interwiki links are specified in wikitext - Wikipedia:Help:Contents can specify an interwiki context, now C standard library:stdlib.h:NULL can specify an internal context. Also the forward slashes of the native "subpage" feature were avoided partly because of the reputation/baggage of subpages in the MediaWiki/Wikipedia community.
contextualised titles in the page heading Each separate sub-context is linked in page headings i.e. C standard library and stdlib.h are separately clickable when the title is C standard library:stdlib.h:NULL. The set of contexts is based on the wiki title rather than any location(s) onto which it may have been grafted in the virtual hierarchy shown by the treeview. This is a pretty standard feature for navigating; I've read about, but not installed, a breadcrumbs extension that does something similar.
aliases are supported When one title redirects to another title, the two are said to alias. The displayed title is not, as occurs natively, that of the redirected-to title, but of the redirected-from title. This will allow us on clc-wiki for example, to redirect from C standard library:stdlib.h:NULL to C standard library:string.h:NULL - NULL is defined in several headers - and have the title vary based on the header it was linked from. We looked at several other ways of achieving this but none were (at the time - I believe that things are better in MediaWiki 1.6.5) fully functional - notably transclusion of full pages had updating issues.
a list of aliases in the header The aliases list is auto-generated by the skin by querying for all redirects to the primary content page - even if we got to that page through a redirect. The alias holding the actual content is given a [primary] subtext. The main title heading either has a subtext [alias] that links to the article's title with &redirect=no as a query parameter, or a subtext [primary]. Using the previous example, it's handy to see at a glance all of the other headers that NULL occurs in by looking at the aliases list
a "closely related" list in the header This is also auto-generated based on the full list (duplicates removed) of articles in all categories that this article (primary alias since redirects can't be categorised) is a member of. So e.g. we can categorise NULL with Null pointer constant in the category "Null pointers" and gain some sense of related concepts. Due to the lack of treeview-like navigation for categories, this is a handy alternate use for them. We can still sub-categorise categories and make use of the hierarchy they provide during editing and content-structuring, but we can avoid their use for end-user navigation.
title underscore remappings Remappings can be specified in the config page so that e.g. "STDC VERSION" will be correctly shown as "__STDC_VERSION__". This is a pretty important requirement for a programming-related wiki - along with correct capitalisation.

It avoids the need for a template explaining technical limitations.

Demo article

The C standard library:stdlib.h:NULL article demonstrates the contextualised heading and the handling as an "alias" of what by MediaWiki-core is handled as a "redirect", the aliases list and the closely related list.

Feedback / bug reports

Bug reports, especially relating to javascript updating, accessibility and gracefulness of degrading - as well as simple indications that "it seems to work OK on browser XYZ" - can be left on the anonymously editable Planning:Treeview_skin:Feedback article.

Treeview-specific features

The treeview itself is expandable/collapsible without need for a full-page reload when javascript is enabled; load-on-demand, node-at-a-time expansion works when supported by the browser. The fall-back method is a full-page reload.

The complete expanded/collapsed state of the treeview persists across page views in most situations, best when cookies and javascript are enabled - cookies provide some other benefits too, but they're not required and their absence doesn't make the treeview inaccessible. For more details see Help:Treeview skin:Treeview.

Custom icons can be uploaded to the wiki and specified per-node in the config article. The config article can also specify the default state of a node as expanded (collapsed is default without this).

Comparison, critique and rationale

Following are some possible critical questions and a response to each.

Why re-invent categories?

The skin evolved to solve several problems at the same time - one concern was to allow aliasing of content. One thing categories don't support is inclusion of redirect articles, meaning that aliasing was not possible without reworking them. Since they are a core-code feature, it seemed better to avoid messing with them. Now that there's a proof-of-concept implementation, it may be possible/desirable to work in support for categories.

There's another important reason: category nodes exist purely in the Category namespace - perhaps implying non-primary content, but certainly not suitable as-is for presenting primary content due to the subsequent list of categorised articles. Treeview parent nodes can exist in any namespace, with primary content uncluttered by a list of child nodes - that list is separated out into the treeview.

Hasn't Wikipedia already found by experience that hierarchy within titles is flawed?

Yes, it seems to have, and some of the arguments that were generated by that experience partly inspired the concept of aliasing and of being able to graft sub-trees at different places in the virtual hierarchy for this Treeview skin. It would probably be useful for the skin to indicate aliased sub-trees as well as individually aliased articles, but that concept and implementation hasn't been carefully considered yet. What it comes down to is that really, a limited hierarchy is sensible in some circumstances, such as the well-structured area of knowledge surrounding C programming. It wouldn't be sensible for titles to extend to twenty sub-contexts, but two, three or four should be fairly logically supportable, and beyond that grafting is a good option.

Another appropriate situation for a limited-depth hierarchy in article titles is for book-like content structuring - i.e. "A wiki book:Chapter 1:Section 1" (we can make good use of this on clc-wiki for the K&R2 solutions and C tutorial). Here, pure-category structuring with a simple article title in the main namespace is impossible, since identically named articles are not allowed - so e.g. "Section 1" and "Chapter 3" are not acceptable title forms. Given then that some per-chapter and per-book differentiation is required anyway, it seems sensible for it to be of a form that allows the wiki to extract navigational meta-information.

Why is everything centralised in a single config article? Wouldn't it be better/more wiki-like to have it spread out as tags or magic words in page content?

It may be, especially for a large wiki. This skin was written for a small/medium sized wiki where it's probably OK to keep everything on one page, and in some ways more maintainable. There are possibilities to incorporate per-page or per-node configuration directives whilst maintaining an overriding master configuration page.

Current status and code availability

The skin has been released as a beta, and is available here: http://creativeandcritical.net/mediawiki-treeview-skin/.

Other documentation

There's a README for the skin as a whole (some of the files described in the introduction and the "Installation" section are not accessible for web viewing - the link to this README is provided mostly to give readers an idea of caching and performance issues as described in later sections) and for the client-side javascript: README.treeview_javascript.

Future directions

One simple addition is support for external links as nodes, and following on from that is sharing hierarchies across sites. The skin adds an extension Special:Hierarchy which returns the xml for a node using a subset of xhtml. So the configuration file could be extended to allow the import of not only contexts on the current wiki, but also nodes from the virtual hierarchies of other wikis.

There are also possibilities for "virtual sub-trees" that would allow e.g. the sub-tree currently in the top level and labelled "This article" to appear below an individual article, or for the TOC to appear in the hierarchy below the article. Also it would be possible to do client-side processing of lists in content pages so that e.g. sections in the user preferences appear under the Accounts->{Username}->preferences node, or that the list of special pages appears under Special->All pages.

Generally there's a lot of scope for providing an overall navigation structure for a wiki.

Historical status with updates for currency (no longer updated)


Everything described above is fully functional. The skin is pretty slow though for two reasons - firstly it doesn't use caching at all aside from Mediawiki's default client-side caching, so the entire treeview is reconstructed each time a page view is generated by Mediawiki, even if the parser cache is used for content. This involves at least one database query. Secondly, it uses javascript to convert a list hierarchy into a treeview, and this could do with some optimisation. Right now on my local machine total round-trip time for a page view - including javascript running - is between 6 and 10 seconds.

Update: total local round-trip page view time is now consistently under 5 seconds, and the actual php server-side treeview component of that is well under a second. Most of it seems to be browser rendering time varying between browsers from about 1 to 3 seconds; the treeview-setup javascript component of that varies between 0.1 and 0.5 seconds. There's still a lot of scope for improvement and caching but the skin's now viable for this wiki so long as nothing equivalent to a slashdotting happens (in which case bandwidth would probably be as much of a constraint as back-end performance anyhow).

Update 2: I've sorted out a caching scheme that works pretty well - the skin now generally feels close to as snappy as Monobook on my local machine. This relies on Mediawiki being configured to use something like memcached, which clc-wiki already does so there shouldn't be any performance dramas. I'm now looking at reducing the amount of treeview html sent on each page view and using javascript to send on demand as nodes are expanded, falling back to a full page reload with the new expanded/collapsed state if javascript is disabled. This should restore the final missing bits of snappiness on page load - a (large) treeview hierarchy will no longer have to be processed by the browser - and it will save dial-up users some bandwidth.

Update 3: On-demand loading

Javascript-based on-demand loading is now functional for all browsers that I've been able to test against, including the big two. This means that a short burst of xml containing the child node data is transferred when an unloaded node is expanded. It's practically instantaneous on my local machine but I don't know yet how it'll fare across the net. Full-page reloads are used as a fallback for expanding/collapsing a node when javascript is disabled or when the load-on-demand javascript methods are not present or when those methods fail.

There are a few niggles to sort out before an alpha version can be put up on the test server - mostly related to state persistence through url query strings as a fallback method for when cookies are disabled.

Update 4: Design and philosophy

(if you're going to do the job in the first place...)

Sorting out the niggles has taken a bit more thought. The treeview should maintain state across page views in a reasonable manner, so that during a session (fuzzy hand-waving definition) the nodes a user has expanded or collapsed don't change unless by manual click, with all ancestor nodes of the currently viewed page auto-expanded unless one of them is subsequently manually collapsed. On the other hand, and in keeping with the comp.lang.c attitude, no particular browser features should be required - the treeview should "work" the same whether using an old non-css text-based browser or the latest snazzy graphical browser with cookies, css, javascript and xml update features.

After some experimentation and pondering I've come upon a scheme that mostly has all of these properties, with some minor variations between browser functionality - in particular links in page content will re-set the treeview state unless cookies are enabled. Navigation links - those in the treeview and navigation bar - however, will maintain treeview state no matter what features a browser supports.

And the scheme itself? The rest of this section describes it, going into a little bit of detail so it's best read by the technically-inclined. Chances are that since you're reading a page detailing a new skin for a wiki devoted to a programming language as discussed on a strictly focussed technical newsgroup, you can safely skip this warning...

The base

(or: let's not incite the intelligence agencies with that more exotic word)

The wiki server will totally ignore treeview-related cookies and instead rely on a query parameter to determine in what state to output the treeview. This allows client-side caching to be predictable since the url fully reflects the content of the page (aside from logged-in state, which depends on cookies and for which MediaWiki already handles cache invalidation).

This means that a full-page reload is required for each expand/collapse, and since each url is different, the client-side browser cache can't be shared between different (tree)view(state)s of the same page.

That's not so crash hot, I hear you say? Sure, for a dial-up user it's a hassle to have to redownload the entire page just to expand/collapse a node in the treeview (and being a dial-up user I understand the perspective). It's also a drain on server bandwidth and processing - although server-side caching minimises the amount of processing required. But I'm sticking with the "new" css model here, where framesets are for good reason eschewed.

The extensions: look ma, caching and persistent state without frames

And for a dial-up user, there is a solution: use a browser with cookies enabled and javascript support. In that case, when a page is first loaded, client-side processing will remove the query parameter appended to navigation (treeview and navbar) links. The state of the treeview can then be determined in the client-side code by examining the browser cookie. On returning to a previously browser-cached page, the state of the treeview can be sorted out by client-side code without requiring a full-page reload - possibly requiring a download of parts of the treeview (or the entire treeview) as xml from the server, but also being able to take advantage of client-side caching for those partial downloads.

And for browsers supporting this model, never will a page be redownloaded simply because it has a few extra query parameters to communicate treeview state - in fact, those query parameters won't ever be sent back to the server - they'll be more-or-less a fallback for browsers with javascript and cookies disabled.

The corner-case: coffee, but hold the biscuits

If you're a stickler for details, you may have picked up that there's a hole in this scheme. What about browsers with javascript enabled but cookies disabled - how can we keep track of the treeview state across pages? Well, to be blunt, as far as I can see we can't - not in a cross-browser manner anyway. What we can do though is to keep track of its state within a single page view by using a global variable instead of a cookie. Then - and here I'm hypothesising having not written this part of the code yet - we can replace treeview/navigation links with a javascript hook that loads the page through the same process by which it loads treeview nodes on demand, and that thereafter performs the same treeview update process for the newly loaded page as described above for when cookies are enabled - it would use the page-specific global variable rather than the (disabled) cookie to determine what state to sync the treeview to. There are some potential problems with this approach, but it should be able to both make use of client-side caching as well as maintain treeview state, all without requiring that those concerned with privacy enable cookies.

So what are the potential problems? Worst-case scenario is that a link to an uncached page is clicked in the treeview, triggering the javascript handler. The handler downloads the new page and in the process of replacing the current page with the new page, encounters an error. A full-page reload is triggered as a fallback. Thus worst-case scenario is a double-download of a page - the full-page reload includes the treeview state as a url query parameter whereas the failed handler-based download does not.

The only way to know if this is going to be an actual problem is to write the code and have it used on as many different real-world browsers as possible.

Update 5: It turns out that this isn't such a robust approach. Firstly, there's the problem that the url doesn't change and the new page isn't included in the browser history. Secondly, downloading an html document and attempting to replace the current document with it whilst not ceding javascript control to the new document is not a very portable thing to attempt. There seem to be three main options:

  • the document.open(), document.write(), and document.close() functions
  • specifying the downloaded content as xml and cloning it through DOM functions as html elements
  • innerHTML

Without going into much detail on this page, each of these is fraught but at least some of them work on at least some browsers. So in the end I've left out any mechanism that tries to avoid accessing content pages with different state querystrings in the url when cookies aren't enabled. I think it's a reasonable compromise - at least a user on a slow connection has a couple of options -

  • enable cookies
  • avoid clicking on links in the treeview/nav-bar unless everything's expanded/collapsed to its default state.

If I after all come across some portable mechanism I'll see about adding it.

Hidden assumptions

The above [everything in update 4 excluding update 5] partly assumes that client-side caching is enabled in both the client browser and the server - on the MediaWiki end it's configurable site-wide through a global variable as well as per-user through preferences. Some pages are also (self-)designated uncacheable such as most pages in the "Special" namespace.

Nothing much changes in general either way except for the corner-case described above, where it would be better to avoid the potential problem of a double-download by simply triggering a full-page reload in the first place given that we can't get a cache hit anyway. If the code is written and maintained well enough though, that problem will with any luck be kept at bay, avoiding the need to deal with yet another variable factor.

And in case it's not already known or clear to a casual reader, MediaWiki's handling of client-side caching does instruct browsers to check back in at each reload to make sure that nothing has changed.

Whilst the current code is functional, it's not in sync with the ideas above and state persistence is inconsistent. The code is also untidier than suitable for public release, so I'll hold off on installing it on this wiki until these ideas have been incorporated and I've cleaned it up a bit.

Update: The untidyness has been mostly sorted out and persistence works as described. The code's still not suitable for widespread use but it seems to be free of major issues.

Outstanding issues

  • treeview formatting for oversize lines is ugly resolved
  • CSS woes with at least one browser resolved
  • the reversal of displaying redirected-from as the title rather than redirected-to is not yet reflected in the html page title resolved - also remappings of titles for underscores now shows in the html title
  • some of the icons are pretty rough and could do with some work


It might be useful to add a small LED-style button top-right that's green to indicate 'currently logged in' and that links to the login/account creation page otherwise. Update: I've added this; it also shows the current Monobook skin's top-of-page personal menu as a dropdown on mouseover when javascript is enabled

It might also be useful to add page history and discussion buttons to the navigation buttons, or to otherwise maintain some of the Monobook actions tab - most of that functionality's been moved into the treeview so that the content division is geared towards reference viewing. Update: I've added this - when javascript is enabled the buttons are hidden by default but a slider button can reveal them; state persists across page views when cookies are enabled

Javascript-defined access-keys for editing actions as for Monobook might be useful to add to the config page, as well as ability to set the tooltip title. Update: Per-user javascript is supported as per Monobook through the {username}/Treeview.js article. So to set access-keys to the Monobook defaults, MediaWiki:Monobook.js can be copied to {username}/Treeview.js.

Personal tools