User:Dantman/Skinning system

Misc ToDo:
 * Currently the styles for the special preferences box and tabs, and also for the user login/creation form are hardcoded into skins. We should be defining the default style in a common stylesheet and letting skins like vector add their improvements to the style over top. Right now new custom skins have to copy monobook's or vector's css after they realize that those two special pages aren't styled right.

Defined areas
MediaWiki's SKinTemplate system has several defined areas. ie: Areas which are expected to be part of a skin and generally have a similar pattern across multiple skins. Some of these are good defined areas for skins, some result in limitations in the ability to skin MediaWiki in the desired way.

page title
Our page title is fairly fine right now,. The addition of the class was a nice thing, we need to try switching more things to use reasonable css classes instead of id's. I do have some pipe dreams of letting extensions play well with skins that are designed in a way that plays nicely with having a list of multiple content areas of some sort. Classes get in the way of that less.

One notable thing over the years though has been title icons. A lot of wiki like to put icons on the right side of the title. This is usually done with some ugly css or js. There is a bug open (to lazy to find a link to it right now) on it, we should be defining an api to add icons to this area and making the skin include it.

body area
The current body area is a mix of hardcoded and freeform stuff.

tagline: The tagline is a hardcoded message. Right now  is used to insert it into the page.

subtitle: subtitle/contentSub is also semi-hardcoded  this time it is defined as a key in SkinTemplate.

undelete: The undelete subtitle appears to be tacked on as a hack. I expect it was added because someone needed to add the

newtalk: User newtalk notice. We may want to consider including this inside the subtitle helper, or perhaps not. If we do include it we should probably include a way to easily omit it as it's reasonable to want to put the user newtalk notice in a different location in a custom skin.

jumplinks: Can't say too much... accessibility is nice. This one seams to use hardcoded i18n messages, I think some people might confuse this when building skin though. This is located inside the content area in monobook because it sits near the very top of the page, there is no long navigation list before this. If a custom skin has navigation before the content area then these jump links should very well not be in the content area. I suppose in this case the hardcoded messages is the desirable behavior as different skins have different layouts and this will vary from skin to skin. It would probably be best if this was left out of helpers. Though educating skin developers on good web accessibility may be tricky. The location inside monobook is actually a little bit questionable. These jump links, or "skip links" as they are usually called, are for web accessibility, they are usually expected to be at the absolute start of the page, before any content of any sort. They exist for users tabbing through links and especially for blind users who would have to sequentially go through entire blocks of content, or entire navigation lists, to get to the next area, so they let them "skip" to another section of the page. However in monobook this sits in the content area below the page title and a bunch of subtitles, this may not be desirable.

bodytext: The body text of the page. Well, this one is a pretty much natural and a given. We have one block of text. This area also implicitly includes the print source footer, and the debug (eh?) html, I'm not sure quite what that part is, it's not the debug comment which is inserted before the end of the body. I may have some pipe dreams about being able to designate output in a little more structured way so a skin can decide "hey there is a better way to render this block (edit form, certain special page pieces, etc...) inside this skin" but those can come later, or later later ...

catlinks: A standard category box...... BAH!!!, I'd like to kill this one. We use the same style box in all skins, it's basically hardcoded. This one is a restriction, skins should be free to style the category area however they want, and wherever they want, however many times they want, and without being required to override a method in the SkinTemplate class (Not the actual template, the root skin class right now, wrong place for template markup). (one of the reasons I hate the categoryhtml added to 1.17 which was better off not added).

dataAfterContent: This is a rather ugly way to do things. It seams to be a holdover from the old skin.

Goals:
 * We should provide an abstract BaseTemplate helper method for inserting the (below the header) standard subtitles that can easily be called.
 * We should probably consider fixing up the subtitle setup. Instead of adding a mess of hardcoded siteSub/tagline, contentSub/subtitle, undelete which are essentially nearly the same style of thing we should define a list of site subtitles, have each one define what class they are (sometimes site css likes to hide things like the tagline and redirect link on the main page, however we must make sure that we have a differentiating class so that we can make sure not to hide things like like undelete and diff related stuff which are important), and have a standard helper to simply iterate over the list and output it with proper styling. We may want to try doing away with some hardcoded id's.
 * A helper method to simplify output of the standard bodyContent run we have here would be a nice idea.

content_actions / content_navigation
content_actions / content_navigation define the primary navigation related to the page. They are usually expressed as tabs above the page in de-facto wiki style. Originally these were defined inside content_actions as a array. Vector then re-implemented, or rather duplicated the whole content_actions code locally to create a new version which was categorized. This new version has been merged back into SkinTemplate and unified with content_actions to create a single standard that works with both formats. The vector hooks are used when building build the new content_navigation, and the old content_actions hooks are completely gone, instead content_actions is now built by folding content_navigation's arrays into a single array, with a 'redundant' key for things like "Read" to indicate they should be discarded when folded.

Bug: Legacy skins have a hack inside them that is still hardcoding a call to the old SkinTemplateTabs hook.

Goals?:
 * For now the categorization is probably good enough. There might be a more free form way to do this, but that needs more thought.
 * Right now we have a variety of js which expects all skins to use the #ca- style of ids on the li, we should try fixing this to avoid restricting custom skins.
 * We have a hardcoded 'class' key which contains things like 'new selected', if possible it would be MUCH better to define these standard attributes as keys themselves instead of classes and merge them into classes later. So that extensions can hook these in a much better way.
 * We have a 'redundant' key that causes tabs like 'read' to be discarded when content_navigation is folded into content_actions. On the todo is also something like an 'after' key. Some tabs may have a good location inside categorized menus and whatnot, however when folded to a single array they don't get placed in the optimum place. An 'after' key would be used to reorganize them to a location right after another key in the array.

logo
Our wiki logo setup simply defines one url. $wgLogo defines the location of the logo. In SkinTemplate a 'logopath' key is directly set from $wgLogo, we have a Skin::getLogo which simply returns $wgLogo, which is used by a logoText which is called by SkinTemplate and simply set as part of a 'logo' key. However modern skins appear to only use logopath in building their own logo box.

Right now the logo set by $wgLogo is expected to be sized at something around 150x150px, absolute maximum 155x155px. This is not hardcoded into the system, but rather every skin we have made was built with a logo area of this size, and it's become a de-facto standard as the only logo size we have. Skins which don't like the size of this logo region are either forced to compromise their design in order to fit the standard logo region in them or they are forced to define a hardcoded or non-standard method of configuration for the skin's logo.

Goals:
 * Define some way for multiple logo sizes to be configured in LocalSettings.php, skins should be able to make a logo call defining what size their logo region is and MW should give them the best fit logo size it can find.

search
Search area was traditionally inside the sidebar on monobook, vector has it in the upper right. Our search form is defined yet not defined. I've abstracted some of the buttons however it's best I abstract more of it, we still have to much boilerplate for a simple search box. The way vector has hardcoded some of it's fancy features isn't completely desirable either. We may want to setup the skin helpers in a way we can vary what box type is used skin by skin but still use the same helper.

I'm not quite sure what to think about our go vs. fulltext searching. Our interfaces that include the distinction aren't entirely desirable, they look ugly, hence people like the pure 'go' style search box. At the same time there are cases where go does not take us where we actually want, and we want to do a fulltext search instead. In these cases the pure-go search boxes get in the way. Search boxes also don't preload what we just searched, which may be desire-able for search tweaks in go results (html5 sessionStorage?, remember cookies are evil for this kind of thing, don't want cross tab pollution). My thought is we may want to go pure-go and have some sort of js inserted 'Is this what you were looking for? Would you like to try doing a full for " "?' message. Or we may want to consider the kind of search additions in things like Firefox's search box or ones on other websites, where there is a icon on the left side you open a dropdown for to select what type of search you are making. In this case it would allow users to switch from the default 'go' to a fulltext search.

sidebar

 * Fault: The SEARCH, LANGUAGES, TOOLBOX addition was interesting, however it was not implemented in a way very flexible to new custom areas. And some skins don't even have these areas. I need to mull over this area a little more.
 * Fault: Not every custom skin wants a sidebar the way we define. They may have areas like a header menu for navigation instead. Instead of this hardcoded sidebar we need a way to define customizable navigation areas, and account for the most common types (navigation sidebar with multiple boxes of one level links, a multi-level navigation hover menu, and a concise list of navigation tabs in the header, potentially a horizontal set of tabs with vertical hover menus (though this may be feedable by the earlier multi-level hover menu data)) we may also want to define a way for these areas to be hooked in by extensions wanting to simply define magic words to do things like expand #category-Foo# into a menu or set of links containing links to pages inside of the category "Foo". Primarily of all, it should be easy for custom skins to define various areas like these.

toolbox

 * I improved this, but it needs more improvement, more though. It used to be completely hardcoded. I need to make some improvements that'll let me integrate this better into Monaco's dynamiclinks so that things like SMW's data browsing link don't disappear.

footerlinks
Footerlinks lists a number of keys do dump into a list in the footer. This is a little ugly due to legacy stuff. It would really be nice if what we were dumping was not a list of keys in the skintemplate. We should be able to just add things to the actual footerlinks array, hard keys in the skintemplate should disappear, and it should be flexible enough that we can actually add links extracted from a MediaWiki: message, which we can't do now cleanly because each footerlink requires a coresponding template key.

copyrightico / poweredbyico
These two pieces formerly defined the copyright and poweredby icons. These have been deprecated in favor of footericons.

Improvement vs. rewrite
Right now a lot of the skin system improvements are improvements, not rewrites of the system. With the exception of the attempt at killing the previous-generation base "Skin" system so that we only have the SkinTemplate system. There are however some faults with the SkinTemplate system. The template has various areas where it is not consulted on what the markup should look like. Helpers are nice, but when the entire generation of the category box markup is hardcoded in the skin class and not defined by the template that is supposed to be defining markup... that doesn't look right. Improvement for now, but it does sound like creating a 3rd generation skin system that defines the separation between skin area logic and markup template logic much better is in order. A number of these pieces actually shouldn't be set as keys and then passed on to the template. The template should be much more involved in defining what areas there are in the skin, and asking for things. The fact that the template does not ask for things and is instead given a bunch of predefined keys is what causes limitations like skins not being able to easily say "I don't have a standard sidebar, however I have a classic website style of header tabs that need the ability for the user to customize them."

Extras
Tabbed areas: We appear to have some pages with a dedicated tab area. Internally we have one on Special:Preferences, though the MW bugzilla's custom theme styled after our skins has it too. And I can't say it's not a ui piece that special pages built by extensions won't have any reason to want to copy. We should make this ui piece more easy to utilize and style.

Icons and subtext
The use of icons in the page title area and a wikitext region below it (both on the right side). The icons are usually in the upper right (in ltr skins) positioned to be on the right side of the title (however the sitenotice can mess the location up), and are used for things like protection icons. Wikipedia seams to use 16px icons, however iirc the ones I've seen most commonly outside of Wikipedia are 32px. Flaggedrevs would also like to put it's ui dropdown here. The subtext/aside is usually located in a similar location, but below the title line instead of inside it. Wikipedia usually uses this area for things like geographic data.

Some examples:
 * wikipedia:User:Daniel
 * Toronto
 * wikipedia:pl:Wikipedysta:Beau/brudnopis

Notes:
 * Skins should be free to choose where they believe the best location for these icons are (in their traditional places for most skins), and free to choose what icon size to use for
 * Since 32px vs 16px as a standard in monobook/vector styles skins there will probably be a $wg config to choose the default size these skins use.
 * If the skin has not implemented support for icons or subtext we should consider prepending the content in a floated div to the bodytext.
 * Probably pageicon(s) for the icons.
 * For the wikitext usually below the title; -aside, -subtext, ...
 * We'll need some sort of hook or api so Flaggedrevs can work
 * We'll need a parser function to add these. Perhaps a tag using recursiveTagParse for the subtext.

New syntax?
Potentially a syntax, perhaps slightly strange. MonoBook is a bad example, the idea here is not that  works the same as it does in a normal template, the idea is that these keys are not preloaded, they're only loaded when you request them, and we start adding things not listed here like the markup for a hover navigation menu or a set of header navigation links. Still, a little odd. Also note this would ideally be a new api, so in this case execute is expected to output the contents of the body block. In other words, headelement, printTrail,, gone from the boilerplate. Also note things like catlinks and dataAfterContent (blech) don't use if conditions anymore. Only if you need wrapping.

xml/html template syntax
This one might be slightly awkward, though it's most likely a complete pipe dream.

Things to note:
 * Instead of userlangattributes and specialpageattributes lang="mw:user" and lang="mw:special" which get replaced
 * Things like  to output individual pieces of the skin. (Incorporating the idea of deferring things and making them more expandable as above)
 *  for quick message system outputs
 * The mw:if="foo" attribute is a shorthand for wrapping the whole thing in something like ... and is used to indicate that an element is intended to not be included if that part of the skin is not actually used.
 * mw:loop="key" works on loopable keys, (like the $this->loop above) it's another short code. It's probably equivalent to things like the ... you see, or perhaps ....
 * Make note that in this case we have nothing but a inside to indicate that the loop should simply dump out a  with nothing special.
 * Then again there is that  idea where  (or perhaps ) just dumps out pieces when you don't have anything special to do on the contents.
 * In loops things like id="p-*" are context sensitive, they know to expand the * to something relevant to the item in the loop.
 * Likewise class="{generated}...{/generated}" is considered an if block to only output when in the context of a generated sidebar item (a little fancy hooking and keying to play with in the skin system).
 * And similarly {logopath} and {nav.mainpage}. Note that these are context sensitive to their attributes. {logopath} understands it's not only inside of a attribute to escape, but that it's inside of a style="" and inside of a url and it should escape everything acordingly. In fact url({logopath}) may result in a nice url('...') style output. Likewise {nav.mainpage} understands it's part of a href="" and grabs what would essentially more verbosely be {nav.mainpage.href}.
 * The is a little bit of magic here, usually we would use text('jsmimetype') ?>">, however since this is a template syntax, and that pattern is common enough, we play up a bit of magic and automatically add the proper type to untyped scripts.
 * Also take mw:optional="yes" into account, it's similar to the mw:if and perhaps could be used in many of the mw:if examples, the idea is that if the looped contents have no items, the list itself is omitted instead of output as an empty list. The args to footerlinks may desire a nicer syntax though.
 * Through the example I disagree with xml vs html a bit. html style parsing would be really nice, just some simple no frills parsing, at the very least boolean attributes and attributes without quotes. However xml of course is much easier to get a php library to actually parse.

I've been experimenting with this and had a mix of success and trouble. I must note that using a html/xml mix that can be parsed into a dom leads to a beautiful situation where your markup is nicer to write (html style booleans and quote-less attributes) and a number of beautiful things become possible. Namely things like lang="mw:user". In the version I have in my experiment lang="mw:*" is very intelligent, it supports mw:user (user lang), mw:content (content lang), mw:page (lang the page uses, this is the same as mw:content in articles, but on special pages in the user's lang it is the same as mw:user), and it handles these very intelligently. Instead of outputting unnecessary lang tags or making guesses that lead to situations where necessary lang tags are omitted, since we have a dom when it goes through the dom, on the few elements in the template with a lang on it it checks to see if the first parent with a lang shares the same lang (making it redundant) and if so strips it out. In other words  becomes. I have however had issues doing the parsing the way I want. DOMDocument::loadHTML likes to throw warnings and strip the mw: from tags turning  into. I've heard of tidy's plugin supporting dom parsing but not everyone has tidy, and not everyone using tidy is using the php plugin (many are potentially using the executable). Additionally tidy never seamed to like  style tags anyways so it would probably screw that up as bad as DOMDocument::loadHTML. html5lib chokes on namespaced tags (well presumably it can handle a few predefined ones like svg). phpQuery and a variety of other libaries fail in various ways at parsing it, or querying it, and some are just wrappers around DOMDocument. The only one I've managed to get working so far is simplehtmldom, which unfortunately after so much of it working, I've found really screws up once you want to insert something before/after a node. It's probably not as efficient as it could be either (speaking just from looking at the api though).

templates + php
Originally the idea was there would be a template api and a php api. However after experimenting with  and seeing the ugliness that a simple   expands to I've found really good quality skinning is in some cases close to impossible to the php api or just plain too ugly (lang="mw:user"'s intelligent stripping of lang attributes can't be done reliably in a way compatible with improvements to our multilang support the way it can with templates, and I really don't like continuing the ugly way we do script tags).

I do have one potential idea to get the flexibility of having a php api and a template api, while getting the advantages of both, not losing the advantages of the templating when using php. Instead of defining a template to use for the body, the body method is always used, and it's "that" output that gets passed through the template. So instead of doing  you use. If you don't need any special php processing the default body method will just output the contents of the template so it will be handled.

I may have to mull some of this over though. There were some ideas like the extraction of region information from a template. I need to examine if there is anything in the way of providing that ability by doing it this way.

custom / semi-standard link lists
Right now our only link list is the sidebar built from MediaWiki:Sidebar. The parsing code for this is hardcoded. Skins don't always work with this, skins can vary on what kind of navigation they offer, the most common being the sidebar, a single list of tabs in the header, or a multi-level navigation menu. Each of these has different restrictions and advantages, so they must be sourced from different lists. However to avoid skins endlessly adding more lists that can be shared we should define a standard message for each of the most common types of primary navigation. Skins can then come up with new custom ones only when they have an extra custom area that is not suited to the primary navigation and doesn't really make to much sense to share.

I have a partially finished ListMessageParser class lying around I should probably commit.

regions
The dataAfterContent key (which takes data from the SkinAfterContent hook) has made it somewhat apparent we need some sort of structured regions for blocks of ui or content. dataAfterContent is a rather ugly hack creating an area for extensions like SMW, FlaggedRevs, ArticleComments, etc... to add stuff to the end of the body area. Note that these can't be integrated into the bodytext because catlinks goes in between them on standard skins, however at the same time hardcoding the location of catlinks (or even requiring we use catlinks and not a custom list of categories in a custom location) is counter to the idea of flexible skinning as well. Hence it seams apparent we need a way for skins to define a number of regions, and extensions to define blocks that go in arbitrary regions. Skins would define restrictions on regions, and extensions would define requirements. Both would define preferences, and the skin system would act as a goto deciding where to put the blocks in the regions the skin has given. An idea in list format:


 * Skins would specify regions. These may require some class config, or perhaps in the case of templates could be extracted from the markup. The regions would be defined with things like size=wide (wide areas like the content), size=narrow (narrow areas like sidebars), size=short (stubby areas like a header that shouldn't have to much).
 * In a php skin  would probably output a region, where somewhere else we define.
 * In a template based skin the template would probably just contain
 * Extensions would define blocks that should be outputted into regions. Marking requirements like how factboxes, etc... need a wide area, and are meant to be inside the primary location.
 * The bodytext and catlinks would be default blocks set to require a wide primary area.
 * Skins can define extra preferences for locations of certain blocks. Namely things like removing the catlinks, moving them to a new location, etc...
 * Potentially site users may be given the ability to reorganize these too in skin-specific ways using a message.