Flow/Architecture/Templating

The Flow/Epic Front-End rewrite of April 2014 uses Handlebars to render in JavaScript, and the lightncandy PHP implementation. This allows templates to be shared between front-end and back-end.

MediaWiki is in the middle of Requests for comment/HTML templating library, but the Flow team couldnt wait.

Using
The templates are in the handlebars subdirectory.

For example, :

This
 * 1) sets the scope to the 'revision' key of the API response.
 * 2) outputs some HTML
 * 3) uses handlebars' limited logic to conditionally output a class if the key   is true in this scope
 * 4) sets the scope to the 'author' key within 'revision', in preparation of outputting the usual MediaWiki Username (talk | contribs) HTML.
 * 5) outputs the value of various bits within the response.revision.author structure.
 * 6) Uses the   helper function to output some message strings.
 * 7) Then uses the   helper function (described below) to render the revision.content.

General template structure
In handlebars templates:
 * includes in another template
 * outputs the string value of some key in the current "this" scope
 * inside the curly braces eats whitespace, thus eats all whitespace before the   and   eats all trailing whitespace.
 * invokes a block function, like  above. Flow has its own block helper function, like
 * invokes a block function, like  above. Flow has its own block helper function, like

Note that templates aren't JavaScript (or PHP). You can't have expressions in template parameters. For example,  won't work. You have to supply appropriate values to the template, or in this case nest #if blocks.

In general one main template includes other templates, often in #if or #each or #eachPost blocks.

PHP
We compile the templates into PHP in advance by make compile-lightncandy, and we check the compiled templates into git.

On your development server, set a variable to compile templates as needed (you may have to change permissions on handlebars/compiled.

JavaScript
The API response is in JSON.

We use a ResourceLoader add-on in extension:Mantle allowing us to specify "resource blobs". This makes the template available to front-end. See that extension's page for some documentation.

TODO compile JS templates in advance? Use ResourceLoader to do this?

Helper functions
Handlebars helper functions have to be re-implemented in JavaScript (in ) and PHP in order for a template to work both front-end and back-end.

E.g. invokes the   helper function to render HTML (rather than escaping '<' and '>', etc.).

Another example, the template code invokes the  helper to get the timestamp from the UUID   and format it using the 'time_ago' i18n message.

Wiring up functions in JavaScript
flow-handlebars.js wraps Mantle extension which wraps Handlebars

will get a template and compile it, and returns function that renders the template.

will actually return a DocumentFragment. It caches the compiled template, so there's no reason to get templates before rendering them.

Note: Seems _tplcache[ name] duplicates Mantle's cache of compiled templates!?

helper functions
In JS, you add functions to flow-handlebars.js, then add to FlowHandlebars.prototype.html.MyFunName, then call handlebars.registerHelper( 'helpername', function ).

SafeString is for when you know you're outputting safe HTML, used by helper.

Init
flow.js runs flowinitComponent for every component on the page.

It looks for data-flow-component=some_name tags in the HTML, then instantiates that component's class

E.g. a mention of data-flow-component="board" on page will initialize the FlowBoardComponent (the one for 'board') JavaScript.

flow-board.js has  name e.g. 'board', and the class name, that's how the data-flow-component and class are glued together. The class extends : Usual OO dance of constructor, calling parent FlowComponent, creating an object.

Associating actions
Typically grab some elements in the HTML and bint actions to them. Instead of doing this programmatically by binding to elements,

give attributes and classes to HTML elements that indicate that something should be done.

Use interactive handlers and load handlers

give it class 'flow-load-interactive' and a data-flow-interactive-handler=XXX

You set up a loadHandlers thing

also a class='flow-click-interactive' that will trigger a xxx.interativeHandlers.YourFuncName

General approach: bind on the root container rather than individual bits of HTML, let the event bubble up to this and then call the component function.

Example of an interactive handler function for music, define in Handlers.oiasdfasdf

then add to template the class="flow-click-interactive" and the data-flow-interactive-handler="music"

Insert example from Shahyar

Debugging
Comment out a line in View.php to view the JSON output before it's templated.

Best practices
Handlebars has implicit triple-braces to output pre-computed HTML. This is easy to miss, so invoke an explicit  when we want to output HTML

TODO: have a flag to disable this?