Requests for comment/Redo skin framework

We would like to create a skin framework to:


 * Make modification, extension and creation of skins quicker and less prone to error
 * Achieve compatibility between skins through an object-based API on the server and client
 * Liberate developers from having to maintain HTML output compatibility between skins

Problem
Currently, most MediaWiki UI elements don't have APIs, or have poor ones, and instead the HTML output by the skins for these elements is treated as the API. The HTML output of skins is kept as similar as possible between each skin as to support the many assumptions that are made by core, extension and gadget software that modify them on the client. On the server side, the few features we do have are centered around this approach of nearly identical HTML output being treated as the API.

This dependency is extremely fragile and resistant to change. Changing a skin or even just adjusting a style can easily involve updating code in hundreds of locations – and there's no way to be sure which assumptions have been made – discouraging iteration and innovation. New skins that do not have a nearly identical HTML structure will fail to work with many features and take a very long time to come to maturity, discouraging creation. In the best case, features try to work around minor differences, but still make lots of assumptions about the HTML. In the worst case, a skin's HTML output is so different that nothing works unless it is written specifically for it.

Solution
Skins are assembled using a collection of view objects, each responsible for a different set of controls on the page. The view objects render controls based on model objects that represent the site, the page and user. As the model objects are modified on either the client or the server, the views automatically update accordingly. The specifics of how the views render model information is changed by extending the view objects for a particular skin. A skin is created by specifying which views to include, the order in which to include them, and styles to apply to them. Views are extended or replaced completely by providing a server and client implementation and including them in the skin. Other systems interact with the skin on either the server or the client by modifying the page, site or user model objects through an API.

On the server, rendering is not performed until the final state, allowing interactions with the site page and user model objects to be completed before responding to the client. The model objects are serialized and embedded into the page for the client to use. On the client, if the client is capable, the model is unserialized and view objects are generated and bound to the DOM the browser built from the HTML the server rendered. Further modification of the model objects triggers changes in the view objects.

Throughout this remainder of this document, view objects are referred to as "widgets", and model objects as "models". Especially on the client, widgets handle their own events during user interactions, making them a combination of view and controller objects. Widgets are persistent objects which wrap around a rendering element, providing a persistent API for modification of the rendering. When models are modified, events are emitted that the widgets listen and respond to. This is distinctly a superset of the functionality of a template, which only manages the production of a rendering based on a model. Widgets may use templates internally to produce a rendering, but the interconnection between widgets and models does not concern itself with the technologies used to produce the final rendering, and over time any desirable technology can be used.

Proposal

 * Skin class for defining which widgets to use
 * Standard widgets which can be styled and extended
 * Client-side API for defining dynamic rendering and behavior of widgets
 * Server-side API for defining static rendering and behavior of widgets
 * Convert existing skins to use the new system
 * Document the server and client APIs
 * Introduce a radically different skin (doesn't need to be the "next" skin) as a test to prove flexibility

Definitions

 * Template
 * A named item in the template registry with a reference to a file or string containing the actual template (written in a template language supporting property placeholders, implicit escaping, loops and conditionals). These can be used by the server-side in PHP, as well in javascript by associating them with a ResourceLoader module (similar to message keys) and used there.
 * Widget
 * An object that takes zero or more data parameters that it uses to create an HTML structure. It may defer html generation to one or more templates. For example a " " widget would use the " " template to create its HTML. It would loop through   and create headings and a list item for each in.
 * If the template library supports dynamic data binding and events (e.g. it doesn't compile HTML once, but maintains references to relevant nodes and allows adding items to lists and changing values without manually digging in the DOM), then we may not have to implement widgets separate from templates, we'd just have templates.
 * On the client side widgets have additional features such as dynamically changing the properties (thus affecting the rendering), and listening for relevant data and user events.
 * On the client side widgets have additional features such as dynamically changing the properties (thus affecting the rendering), and listening for relevant data and user events.

Details

 * Output manager

MediaWiki's output page, skin system and special pages should not write html directly to the output buffer.

Rationale:
 * Re-usable.
 * Guaranteed to be balanced.
 * Enforced and easily reviewable security/escaping.

Instead any HTML is handled through an abstraction layer. This output manager takes a widget instead.

So where previously one would have something like: $out->addHTML( ' .... '  . Html::element( 'div', array( .. ), .. ) . ' ' ); There'd now be: $out->add( new Widget( 'sidebar', array( 'sections' => array( .. ) ) ); $out->add( 'sidebar', array( 'sections' => array( .. ) );


 * Template / widget registry

Widgets would provide an interface agonistic of which template is used by the skin for that widget. In the event that we'd not have separate widget and template models, there would be no widgets and its features provided by templates. However one feature remains that templates wouldn't have built-in. Namely the ability to have the skin decide what html template to use.
 * The last sentence seems to contradict the first sentence. This entire paragraph is confusing. Kaldari (talk) 22:30, 8 July 2014 (UTC)

Looking at different skins today, I'd say it's a worthwhile pursuit to try to keep this ability absent. While different skins do have slightly different HTML structures for the same concepts, they don't seem to be justifiably different.
 * It sounds like you haven't looked at the Minerva (mobile) skin. Kaldari (talk) 22:30, 8 July 2014 (UTC)

If we do need this, we'd have a mutable registry where the skin can provide a different template string for a standardised component.
 * What is a "component"? (An example would be useful.) Kaldari (talk) 22:30, 8 July 2014 (UTC)


 * Unified page interface

To separate concerns and aim for easier maintainability and compatibility, any software outside the skin itself would use the provided interface. Not invoke templates directly. For example, on the client side one could invoke  to add a new section to the sidebar and   to add a list item. These methods would have a reference to the instance of the sidebar widget, thus making it trivial to extend it without needing to know about its HTML structure.