Difference between revisions of "Module:HtmlBuilder"
Jump to navigation
Jump to search
m |
(FnControlOption changed the content model of the page Module:HtmlBuilder from "plain text" to "Scribunto") Tag: content model change |
||
(8 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
fluent interface. | fluent interface. | ||
− | + | Originally written on the English Wikipedia by | |
− | + | Toohool and Mr. Stradivarius. | |
− | + | Modified for the Minetest Wiki. | |
− | |||
− | |||
− | + | Code released under the GPL v2+ as per: | |
− | + | https://en.wikipedia.org/w/index.php?diff=next&oldid=581399786 | |
+ | https://en.wikipedia.org/w/index.php?diff=next&oldid=581403025 | ||
+ | |||
+ | @license GNU GPL v2+ | ||
+ | @author Marius Hoch < hoo@online.de > | ||
+ | @author MrIbby < siribby@outlook.com > | ||
]] | ]] | ||
local HtmlBuilder = {} | local HtmlBuilder = {} | ||
− | local options | + | local options = mw.loadData( 'Module:HtmlBuilder/options' ) |
− | local util = require('Module:LibraryUtil') | + | local util = require( 'Module:LibraryUtil' ) |
local checkType = util.checkType | local checkType = util.checkType | ||
local checkTypeMulti = util.checkTypeMulti | local checkTypeMulti = util.checkTypeMulti | ||
Line 25: | Line 28: | ||
local selfClosingTags = { | local selfClosingTags = { | ||
− | + | area = true, | |
− | + | base = true, | |
− | + | br = true, | |
− | + | col = true, | |
− | + | command = true, | |
− | + | embed = true, | |
− | + | hr = true, | |
− | + | img = true, | |
− | + | input = true, | |
− | + | keygen = true, | |
− | + | link = true, | |
− | + | meta = true, | |
− | + | param = true, | |
− | + | source = true, | |
− | + | track = true, | |
− | + | wbr = true, | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
Line 53: | Line 49: | ||
metatable.__tostring = function( t ) | metatable.__tostring = function( t ) | ||
− | + | local ret = {} | |
− | + | t:_build( ret ) | |
− | + | return table.concat( ret ) | |
end | end | ||
Line 62: | Line 58: | ||
-- @param name | -- @param name | ||
local function getAttr( t, name ) | local function getAttr( t, name ) | ||
− | + | for i, attr in ipairs( t.attributes ) do | |
− | + | if attr.name == name then | |
− | + | return attr, i | |
− | + | end | |
− | + | end | |
end | end | ||
Line 73: | Line 69: | ||
-- @param s | -- @param s | ||
local function isValidAttributeName( s ) | local function isValidAttributeName( s ) | ||
− | + | -- Good estimate: http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name | |
− | + | return s:match( '^[a-zA-Z_:][a-zA-Z0-9_.:-]*$' ) | |
end | end | ||
Line 81: | Line 77: | ||
-- @param s | -- @param s | ||
local function isValidTag( s ) | local function isValidTag( s ) | ||
− | + | return s:match( '^[a-zA-Z0-9]+$' ) | |
end | end | ||
Line 88: | Line 84: | ||
-- @param s | -- @param s | ||
local function htmlEncode( s ) | local function htmlEncode( s ) | ||
− | + | -- The parentheses ensure that there is only one return value | |
− | + | local tmp = string.gsub( s, '[<>&"]', options.htmlencodeMap ); | |
− | + | -- Don't encode strip markers here (T110143) | |
− | + | tmp = string.gsub( tmp, options.encodedUniqPrefixPat, options.uniqPrefixRepl ) | |
− | + | tmp = string.gsub( tmp, options.encodedUniqSuffixPat, options.uniqSuffixRepl ) | |
− | + | return tmp | |
end | end | ||
local function cssEncode( s ) | local function cssEncode( s ) | ||
− | + | -- mw.ustring is so slow that it's worth searching the whole string | |
− | + | -- for non-ASCII characters to avoid it if possible | |
− | + | return ( string.find( s, '[^%z\1-\127]' ) and mw.ustring or string ) | |
− | + | -- XXX: I'm not sure this character set is complete. | |
− | + | -- bug #68011: allow delete character (\127) | |
− | + | .gsub( s, '[^\32-\57\60-\127]', function ( m ) | |
− | + | return string.format( '\\%X ', mw.ustring.codepoint( m ) ) | |
− | + | end ) | |
end | end | ||
Line 113: | Line 109: | ||
-- @param args | -- @param args | ||
local function createBuilder( tagName, args ) | local function createBuilder( tagName, args ) | ||
− | + | if tagName ~= nil and tagName ~= '' and not isValidTag( tagName ) then | |
− | + | error( string.format( "invalid tag name '%s'", tagName ), 3 ) | |
− | + | end | |
− | + | args = args or {} | |
− | + | local builder = {} | |
− | + | setmetatable( builder, metatable ) | |
− | + | builder.nodes = {} | |
− | + | builder.attributes = {} | |
− | + | builder.styles = {} | |
− | + | if tagName ~= '' then | |
− | + | builder.tagName = tagName | |
− | + | end | |
− | + | builder.parent = args.parent | |
− | + | builder.selfClosing = selfClosingTags[tagName] or args.selfClosing or false | |
− | + | return builder | |
end | end | ||
Line 139: | Line 135: | ||
-- @param builder | -- @param builder | ||
local function appendBuilder( t, builder ) | local function appendBuilder( t, builder ) | ||
− | + | if t.selfClosing then | |
− | + | error( "self-closing tags can't have child nodes", 3 ) | |
− | + | end | |
− | + | if builder then | |
− | + | table.insert( t.nodes, builder ) | |
− | + | end | |
− | + | return t | |
+ | end | ||
+ | |||
+ | methodtable._buildAttributes = function( t, ret ) | ||
+ | for i, attr in ipairs( t.attributes ) do | ||
+ | table.insert( | ||
+ | ret, | ||
+ | -- Note: Attribute names have already been validated | ||
+ | ' ' .. attr.name .. '="' .. htmlEncode( attr.val ) .. '"' | ||
+ | ) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | methodtable._buildStyles = function( t, ret ) | ||
+ | if #t.styles > 0 then | ||
+ | table.insert( ret, ' style="' ) | ||
+ | local css = {} | ||
+ | for i, prop in ipairs( t.styles ) do | ||
+ | if type( prop ) ~= 'table' then -- added with cssText() | ||
+ | table.insert( css, htmlEncode( prop ) ) | ||
+ | else -- added with css() | ||
+ | table.insert( | ||
+ | css, | ||
+ | htmlEncode( cssEncode( prop.name ) .. ':' .. cssEncode( prop.val ) ) | ||
+ | ) | ||
+ | end | ||
+ | end | ||
+ | table.insert( ret, table.concat( css, ';' ) ) | ||
+ | table.insert( ret, '"' ) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | methodtable._buildNodes = function( t, ret ) | ||
+ | for i, node in ipairs( t.nodes ) do | ||
+ | if node then | ||
+ | if type( node ) == 'table' then | ||
+ | node:_build( ret ) | ||
+ | else | ||
+ | table.insert( ret, tostring( node ) ) | ||
+ | end | ||
+ | end | ||
+ | end | ||
end | end | ||
methodtable._build = function( t, ret ) | methodtable._build = function( t, ret ) | ||
− | + | if t.tagName then | |
− | + | table.insert( ret, '<' .. t.tagName ) | |
− | + | t:_buildAttributes( ret ) | |
− | + | t:_buildStyles( ret ) | |
− | + | if t.selfClosing then | |
− | + | table.insert( ret, ' />' ) | |
− | + | return | |
− | + | end | |
− | + | table.insert( ret, '>' ) | |
− | + | end | |
− | + | t:_buildNodes( ret ) | |
− | + | if t.tagName then | |
− | + | table.insert( ret, '</' .. t.tagName .. '>' ) | |
− | + | end | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
Line 199: | Line 207: | ||
-- @param builder | -- @param builder | ||
methodtable.node = function( t, builder ) | methodtable.node = function( t, builder ) | ||
− | + | return appendBuilder( t, builder ) | |
end | end | ||
-- Appends some markup to the node. This will be treated as wikitext. | -- Appends some markup to the node. This will be treated as wikitext. | ||
methodtable.wikitext = function( t, ... ) | methodtable.wikitext = function( t, ... ) | ||
− | + | for k,v in ipairs{...} do | |
− | + | checkTypeMulti( 'wikitext', k, v, { 'string', 'number' } ) | |
− | + | appendBuilder( t, v ) | |
− | + | end | |
− | + | return t | |
end | end | ||
-- Appends a newline character to the node. | -- Appends a newline character to the node. | ||
methodtable.newline = function( t ) | methodtable.newline = function( t ) | ||
− | + | return t:wikitext( '\n' ) | |
end | end | ||
Line 222: | Line 230: | ||
-- @param args | -- @param args | ||
methodtable.tag = function( t, tagName, args ) | methodtable.tag = function( t, tagName, args ) | ||
− | + | checkType( 'tag', 1, tagName, 'string' ) | |
− | + | checkType( 'tag', 2, args, 'table', true ) | |
− | + | args = args or {} | |
− | + | args.parent = t | |
− | + | local builder = createBuilder( tagName, args ) | |
− | + | t:node( builder ) | |
− | + | return builder | |
end | end | ||
Line 236: | Line 244: | ||
-- @param name | -- @param name | ||
methodtable.getAttr = function( t, name ) | methodtable.getAttr = function( t, name ) | ||
− | + | checkType( 'getAttr', 1, name, 'string' ) | |
− | + | local attr = getAttr( t, name ) | |
− | + | return attr and attr.val | |
end | end | ||
Line 247: | Line 255: | ||
-- @param val Value of the attribute. Nil causes the attribute to be unset | -- @param val Value of the attribute. Nil causes the attribute to be unset | ||
methodtable.attr = function( t, name, val ) | methodtable.attr = function( t, name, val ) | ||
− | + | if type( name ) == 'table' then | |
− | + | if val ~= nil then | |
− | + | error( | |
− | + | "bad argument #2 to 'attr' " .. | |
− | + | '(if argument #1 is a table, argument #2 must be left empty)', | |
− | + | 2 | |
− | + | ) | |
− | + | end | |
− | + | local callForTable = function() | |
− | + | for attrName, attrValue in pairs( name ) do | |
− | + | t:attr( attrName, attrValue ) | |
− | + | end | |
− | + | end | |
− | + | if not pcall( callForTable ) then | |
− | + | error( | |
− | + | "bad argument #1 to 'attr' " .. | |
− | + | '(table keys must be strings, and values must be strings or numbers)', | |
− | + | 2 | |
− | + | ) | |
− | + | end | |
− | + | return t | |
− | + | end | |
− | + | checkType( 'attr', 1, name, 'string' ) | |
− | + | checkTypeMulti( 'attr', 2, val, { 'string', 'number', 'nil' } ) | |
− | + | -- if caller sets the style attribute explicitly, then replace all styles | |
− | + | -- previously added with css() and cssText() | |
− | + | if name == 'style' then | |
− | + | t.styles = { val } | |
− | + | return t | |
− | + | end | |
− | + | if not isValidAttributeName( name ) then | |
− | + | error( string.format( | |
− | + | "bad argument #1 to 'attr' (invalid attribute name '%s')", | |
− | + | name | |
− | + | ), 2 ) | |
− | + | end | |
− | + | local attr, i = getAttr( t, name ) | |
− | + | if attr then | |
− | + | if val ~= nil then | |
− | + | attr.val = val | |
− | + | else | |
− | + | table.remove( t.attributes, i ) | |
− | + | end | |
− | + | elseif val ~= nil then | |
− | + | table.insert( t.attributes, { name = name, val = val } ) | |
− | + | end | |
− | + | return t | |
end | end | ||
Line 309: | Line 317: | ||
-- @param class | -- @param class | ||
methodtable.addClass = function( t, class ) | methodtable.addClass = function( t, class ) | ||
− | + | checkTypeMulti( 'addClass', 1, class, { 'string', 'number', 'nil' } ) | |
− | + | if class ~= nil then | |
− | + | local attr = getAttr( t, 'class' ) | |
− | + | if attr then | |
− | + | attr.val = attr.val .. ' ' .. class | |
− | + | else | |
− | + | t:attr( 'class', class ) | |
− | + | end | |
− | + | end | |
− | + | return t | |
end | end | ||
Line 327: | Line 335: | ||
-- @param val The value to set. Nil causes it to be unset | -- @param val The value to set. Nil causes it to be unset | ||
methodtable.css = function( t, name, val ) | methodtable.css = function( t, name, val ) | ||
− | + | if type( name ) == 'table' then | |
− | + | if val ~= nil then | |
− | + | error( | |
− | + | "bad argument #2 to 'css' " .. | |
− | + | '(if argument #1 is a table, argument #2 must be left empty)', | |
− | + | 2 | |
− | + | ) | |
− | + | end | |
− | + | local callForTable = function() | |
− | + | for attrName, attrValue in pairs( name ) do | |
− | + | t:css( attrName, attrValue ) | |
− | + | end | |
− | + | end | |
− | + | if not pcall( callForTable ) then | |
− | + | error( | |
− | + | "bad argument #1 to 'css' " .. | |
− | + | '(table keys and values must be strings or numbers)', | |
− | + | 2 | |
− | + | ) | |
− | + | end | |
− | + | return t | |
− | + | end | |
− | + | checkTypeMulti( 'css', 1, name, { 'string', 'number' } ) | |
− | + | checkTypeMulti( 'css', 2, val, { 'string', 'number', 'nil' } ) | |
− | + | for i, prop in ipairs( t.styles ) do | |
− | + | if prop.name == name then | |
− | + | if val ~= nil then | |
− | + | prop.val = val | |
− | + | else | |
− | + | table.remove( t.styles, i ) | |
− | + | end | |
− | + | return t | |
− | + | end | |
− | + | end | |
− | + | if val ~= nil then | |
− | + | table.insert( t.styles, { name = name, val = val } ) | |
− | + | end | |
− | + | return t | |
end | end | ||
Line 379: | Line 387: | ||
-- @param css | -- @param css | ||
methodtable.cssText = function( t, css ) | methodtable.cssText = function( t, css ) | ||
− | + | checkTypeMulti( 'cssText', 1, css, { 'string', 'number', 'nil' } ) | |
− | + | table.insert( t.styles, css ) | |
− | + | return t | |
end | end | ||
Line 388: | Line 396: | ||
-- several child nodes to be chained together into a single statement. | -- several child nodes to be chained together into a single statement. | ||
methodtable.done = function( t ) | methodtable.done = function( t ) | ||
− | + | return t.parent or t | |
end | end | ||
Line 394: | Line 402: | ||
-- returns it. | -- returns it. | ||
methodtable.allDone = function( t ) | methodtable.allDone = function( t ) | ||
− | + | while t.parent do | |
− | + | t = t.parent | |
− | + | end | |
− | + | return t | |
end | end | ||
Line 405: | Line 413: | ||
-- @param args | -- @param args | ||
function HtmlBuilder.create( tagName, args ) | function HtmlBuilder.create( tagName, args ) | ||
− | + | checkType( 'HtmlBuilder.create', 1, tagName, 'string', true ) | |
− | + | checkType( 'HtmlBuilder.create', 2, args, 'table', true ) | |
− | + | return createBuilder( tagName, args ) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
return HtmlBuilder | return HtmlBuilder |
Latest revision as of 17:36, 7 June 2022
Documentation for this module may be created at Module:HtmlBuilder/doc
--[[ A module for building complex HTML from Lua using a fluent interface. Originally written on the English Wikipedia by Toohool and Mr. Stradivarius. Modified for the Minetest Wiki. Code released under the GPL v2+ as per: https://en.wikipedia.org/w/index.php?diff=next&oldid=581399786 https://en.wikipedia.org/w/index.php?diff=next&oldid=581403025 @license GNU GPL v2+ @author Marius Hoch < hoo@online.de > @author MrIbby < siribby@outlook.com > ]] local HtmlBuilder = {} local options = mw.loadData( 'Module:HtmlBuilder/options' ) local util = require( 'Module:LibraryUtil' ) local checkType = util.checkType local checkTypeMulti = util.checkTypeMulti local metatable = {} local methodtable = {} local selfClosingTags = { area = true, base = true, br = true, col = true, command = true, embed = true, hr = true, img = true, input = true, keygen = true, link = true, meta = true, param = true, source = true, track = true, wbr = true, } metatable.__index = methodtable metatable.__tostring = function( t ) local ret = {} t:_build( ret ) return table.concat( ret ) end -- Get an attribute table (name, value) and its index -- -- @param name local function getAttr( t, name ) for i, attr in ipairs( t.attributes ) do if attr.name == name then return attr, i end end end -- Is this a valid attribute name? -- -- @param s local function isValidAttributeName( s ) -- Good estimate: http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name return s:match( '^[a-zA-Z_:][a-zA-Z0-9_.:-]*$' ) end -- Is this a valid tag name? -- -- @param s local function isValidTag( s ) return s:match( '^[a-zA-Z0-9]+$' ) end -- Escape a value, for use in HTML -- -- @param s local function htmlEncode( s ) -- The parentheses ensure that there is only one return value local tmp = string.gsub( s, '[<>&"]', options.htmlencodeMap ); -- Don't encode strip markers here (T110143) tmp = string.gsub( tmp, options.encodedUniqPrefixPat, options.uniqPrefixRepl ) tmp = string.gsub( tmp, options.encodedUniqSuffixPat, options.uniqSuffixRepl ) return tmp end local function cssEncode( s ) -- mw.ustring is so slow that it's worth searching the whole string -- for non-ASCII characters to avoid it if possible return ( string.find( s, '[^%z\1-\127]' ) and mw.ustring or string ) -- XXX: I'm not sure this character set is complete. -- bug #68011: allow delete character (\127) .gsub( s, '[^\32-\57\60-\127]', function ( m ) return string.format( '\\%X ', mw.ustring.codepoint( m ) ) end ) end -- Create a builder object. This is a separate function so that we can show the -- correct error levels in both HtmlBuilder.create and metatable.tag. -- -- @param tagName -- @param args local function createBuilder( tagName, args ) if tagName ~= nil and tagName ~= '' and not isValidTag( tagName ) then error( string.format( "invalid tag name '%s'", tagName ), 3 ) end args = args or {} local builder = {} setmetatable( builder, metatable ) builder.nodes = {} builder.attributes = {} builder.styles = {} if tagName ~= '' then builder.tagName = tagName end builder.parent = args.parent builder.selfClosing = selfClosingTags[tagName] or args.selfClosing or false return builder end -- Append a builder to the current node. This is separate from methodtable.node -- so that we can show the correct error level in both methodtable.node and -- methodtable.wikitext. -- -- @param builder local function appendBuilder( t, builder ) if t.selfClosing then error( "self-closing tags can't have child nodes", 3 ) end if builder then table.insert( t.nodes, builder ) end return t end methodtable._buildAttributes = function( t, ret ) for i, attr in ipairs( t.attributes ) do table.insert( ret, -- Note: Attribute names have already been validated ' ' .. attr.name .. '="' .. htmlEncode( attr.val ) .. '"' ) end end methodtable._buildStyles = function( t, ret ) if #t.styles > 0 then table.insert( ret, ' style="' ) local css = {} for i, prop in ipairs( t.styles ) do if type( prop ) ~= 'table' then -- added with cssText() table.insert( css, htmlEncode( prop ) ) else -- added with css() table.insert( css, htmlEncode( cssEncode( prop.name ) .. ':' .. cssEncode( prop.val ) ) ) end end table.insert( ret, table.concat( css, ';' ) ) table.insert( ret, '"' ) end end methodtable._buildNodes = function( t, ret ) for i, node in ipairs( t.nodes ) do if node then if type( node ) == 'table' then node:_build( ret ) else table.insert( ret, tostring( node ) ) end end end end methodtable._build = function( t, ret ) if t.tagName then table.insert( ret, '<' .. t.tagName ) t:_buildAttributes( ret ) t:_buildStyles( ret ) if t.selfClosing then table.insert( ret, ' />' ) return end table.insert( ret, '>' ) end t:_buildNodes( ret ) if t.tagName then table.insert( ret, '</' .. t.tagName .. '>' ) end end -- Append a builder to the current node -- -- @param builder methodtable.node = function( t, builder ) return appendBuilder( t, builder ) end -- Appends some markup to the node. This will be treated as wikitext. methodtable.wikitext = function( t, ... ) for k,v in ipairs{...} do checkTypeMulti( 'wikitext', k, v, { 'string', 'number' } ) appendBuilder( t, v ) end return t end -- Appends a newline character to the node. methodtable.newline = function( t ) return t:wikitext( '\n' ) end -- Appends a new child node to the builder, and returns an HtmlBuilder instance -- representing that new node. -- -- @param tagName -- @param args methodtable.tag = function( t, tagName, args ) checkType( 'tag', 1, tagName, 'string' ) checkType( 'tag', 2, args, 'table', true ) args = args or {} args.parent = t local builder = createBuilder( tagName, args ) t:node( builder ) return builder end -- Get the value of an html attribute -- -- @param name methodtable.getAttr = function( t, name ) checkType( 'getAttr', 1, name, 'string' ) local attr = getAttr( t, name ) return attr and attr.val end -- Set an HTML attribute on the node. -- -- @param name Attribute to set, alternative table of name-value pairs -- @param val Value of the attribute. Nil causes the attribute to be unset methodtable.attr = function( t, name, val ) if type( name ) == 'table' then if val ~= nil then error( "bad argument #2 to 'attr' " .. '(if argument #1 is a table, argument #2 must be left empty)', 2 ) end local callForTable = function() for attrName, attrValue in pairs( name ) do t:attr( attrName, attrValue ) end end if not pcall( callForTable ) then error( "bad argument #1 to 'attr' " .. '(table keys must be strings, and values must be strings or numbers)', 2 ) end return t end checkType( 'attr', 1, name, 'string' ) checkTypeMulti( 'attr', 2, val, { 'string', 'number', 'nil' } ) -- if caller sets the style attribute explicitly, then replace all styles -- previously added with css() and cssText() if name == 'style' then t.styles = { val } return t end if not isValidAttributeName( name ) then error( string.format( "bad argument #1 to 'attr' (invalid attribute name '%s')", name ), 2 ) end local attr, i = getAttr( t, name ) if attr then if val ~= nil then attr.val = val else table.remove( t.attributes, i ) end elseif val ~= nil then table.insert( t.attributes, { name = name, val = val } ) end return t end -- Adds a class name to the node's class attribute. Spaces will be -- automatically added to delimit each added class name. -- -- @param class methodtable.addClass = function( t, class ) checkTypeMulti( 'addClass', 1, class, { 'string', 'number', 'nil' } ) if class ~= nil then local attr = getAttr( t, 'class' ) if attr then attr.val = attr.val .. ' ' .. class else t:attr( 'class', class ) end end return t end -- Set a CSS property to be added to the node's style attribute. -- -- @param name CSS attribute to set, alternative table of name-value pairs -- @param val The value to set. Nil causes it to be unset methodtable.css = function( t, name, val ) if type( name ) == 'table' then if val ~= nil then error( "bad argument #2 to 'css' " .. '(if argument #1 is a table, argument #2 must be left empty)', 2 ) end local callForTable = function() for attrName, attrValue in pairs( name ) do t:css( attrName, attrValue ) end end if not pcall( callForTable ) then error( "bad argument #1 to 'css' " .. '(table keys and values must be strings or numbers)', 2 ) end return t end checkTypeMulti( 'css', 1, name, { 'string', 'number' } ) checkTypeMulti( 'css', 2, val, { 'string', 'number', 'nil' } ) for i, prop in ipairs( t.styles ) do if prop.name == name then if val ~= nil then prop.val = val else table.remove( t.styles, i ) end return t end end if val ~= nil then table.insert( t.styles, { name = name, val = val } ) end return t end -- Add some raw CSS to the node's style attribute. This is typically used -- when a template allows some CSS to be passed in as a parameter -- -- @param css methodtable.cssText = function( t, css ) checkTypeMulti( 'cssText', 1, css, { 'string', 'number', 'nil' } ) table.insert( t.styles, css ) return t end -- Returns the parent node under which the current node was created. Like -- jQuery.end, this is a convenience function to allow the construction of -- several child nodes to be chained together into a single statement. methodtable.done = function( t ) return t.parent or t end -- Like .done(), but traverses all the way to the root node of the tree and -- returns it. methodtable.allDone = function( t ) while t.parent do t = t.parent end return t end -- Create a new instance -- -- @param tagName -- @param args function HtmlBuilder.create( tagName, args ) checkType( 'HtmlBuilder.create', 1, tagName, 'string', true ) checkType( 'HtmlBuilder.create', 2, args, 'table', true ) return createBuilder( tagName, args ) end return HtmlBuilder