Requests for comment/Fluent interface for Html building

These are some rough thoughts I had, which I wanted to write down. I'm not entirely sure about this yet, and its not ready to be an RFC yet. But I thought it'd be useful to write it down.

Currently we primarily use the Html class to generate html in mediawiki. This class is somewhat awkward to use when generating complex html structures. There has been some movement towards templates, but they don't seem to have overly caught on in core.

Problems with current Html class:
 * Easy to loose track of where stuff is escaped. Is the enclosing content an Html::element, or Html::rawElement. Often code is htmlspecialchars several lines before wrapping in an Html::rawElement (violates rule of escape at the very end). With messages things get harder - since often you do $bar = wfMessage( 'foo' )->parse quite a bit before you output. Or maybe you do wfMessage( 'foo' )->escaped in a Html::rawElement. Or perhaps you do wfMessage( 'foo' )->text in an Html::element. Its all very confusing and easy to loose track
 * Generating html by doing things like $part1 = Html::element( 'div', ... ); $part2 = Html::rawElement( 'div', [], $part1 ); all gets rather hard to keep straight, or you end up with 17 billion levels of indentation.

However, in javascript, we often use things like $( ' ' ).append( ... ) and somehow it all seems less confusing.

Similarly, lua has HtmlBuilder, which seems quite popular.

So lets build a wrapper around the Html class for MW that's more in the style of jQuery or lua HtmlBuilder (I guess this style is called "fluent").

Design goals:
 * Make it very clear when raw html is being included
 * Avoid any pattern where you concat or include raw html, unless you are actually including arbitrary html (So avoid )
 * Use the method chaining style, like wfMessage and jQuery's $

So what I envision is have a new class:

This would make something like:

Actual API
So far, I'm envisioning two classes: HtmlBuilder and HtmlBuilderTag

Roughly speaking I'm imaginging something like:

HtmlBuilder

 * HtmlBuilder::tag( $tagName )


 * Returns an HtmlBuilderTag with the starting content being 
 * HtmlBuilder::text( $text )


 * HtmlBuilderTag that's just (escaped) text. Maybe equivalent to HtmlBuilder->tag( '' )->appendText( $text );
 * HtmlBuilder::rawHtml( $text )


 * same as ->text but for raw Html.

HtmlBuilderTag

 * HtmlBuilderTag::attr( $attr, $value )


 * Adjust attributes of the current context tag. Returns HtmlBuilderTag
 * HtmlBuilderTag::appendText( $text )


 * Escape and append some text
 * HtmlBuilderTag::append( $arg )


 * Append argument. Do something different depending on what the argument is. If its a string, same as appendText. If its an instance of Message, same as appendMsgParsed (Or maybe it should default to ->escaped??), if its an instance of HtmlBuilderTag, append that as a subtree
 * HtmlBuilderTag::appendRawHtml( $html )


 * Strongly discouraged, but allow user to append arbitrary html
 * HtmlBuilderTag::renderAsString

[And probably more]
 * Output html as string

Also similar methods for prepend*, insertBefore*, insertAfter*

Example
Todo: Should rewrite something using Html::[raw]Element to see what it would look like using this proposal.

Other questions
Maybe someone has already implemented something like this for PHP which we could just steal?