User:Robchurch/Extension output handlers

This document is intended as an explanation of the output handler mechanism for parser hook extensions.

Rationale
The existing parser hook mechanism allows for the creation of flexible extension code to inject block content into rendered pages, which can provide users with filtered or otherwise limited access to insert more complicated HTML code into pages.

Parser hook output is subject to the standard parser cache, and should avoid interacting with transient global objects such as,   and. This, however, limits their ability to be used to alter the  object used for page rendering. In particular, parser hook extensions cannot add inclusions for CSS or JavaScript into the  portion of a page.

The custom output handler mechanism was devised as a means to work around this problem.

How it works
An extension wishing to alter the  object on view will define a custom output handler which implements the   interface. This includes an  method, which is passed the   to be modified.

This handler is then passed to the parser using, which inserts it into the  , that is, the object stored in the parser cache.

When the  is used to prepare a page for viewing, which happens regardless of whether the   object has just been rendered, or has been pulled from the parser cache, the   method iterates through all attached output handlers and calls the   method on each, passing the   which will eventually be rendered and sent to the client's browser.

The  method of a given output handler is then free to alter the supplied , for instance, attaching custom CSS or JavaScript files, or injecting JavaScript into the page header.

Sample implementation

 * The Aggregator extension in Subversion can be used as a reference when writing an extension using output handlers.

Assume that our parser hook returns content using custom CSS rules, and we want to attach a supplied CSS document containing these.

The hook function might look something like this:

function efHookFunction( $input, $args, $parser ) { // Attach our custom output handler to the parser output $parser->addOutputHandler( new SampleCssHandler ); // Generate our content and output as usual return ' [...] '; } We define an output handler, :

class SampleCssHandler implements ExtensionOutputHandler {

public function apply( $output ) { // Attach an external CSS document global $wgScriptPath; $outputPage->addScript( Xml::element( 'link', array(           'rel' => 'stylesheet',            'type' => 'text/css',            'href' => "$wgScriptPath/extensions/Stuff/stuff.css" ) ) ); }

} The hook function attaches the output handler to the parser output. When this is used for page rendering, our handler's  method will be called, and the stylesheet element will be added to the , ready for inclusion in the header.