Module:HtmlBuilder

HtmlBuilder provides a way to construct complex HTML and CSS markup by creating a tree of nodes, similar to the Document Object Model. The result is code that i…

HtmlBuilder provides a way to construct complex HTML and CSS markup by creating a tree of nodes, similar to the Document Object Model. The result is code that is more comprehensible and maintainable than if you simply concatenated strings together. It offers a fluent interface that should look familiar to any user of jQuery.

Usage

First, you need to load the module:

local HtmlBuilder = require('Module:HtmlBuilder')

Next, create the root HtmlBuilder instance:

local builder = HtmlBuilder.create()

Then, you can build HTML using the methods of the HtmlBuilder instance, listed below.

Finally, get the resulting HTML markup as a string:

local s = tostring(builder)

Methods

To allow chaining, all methods return a reference to the builder, unless otherwise stated.

tag

local div = builder.tag('div') Appends a new child node to the builder, and returns an HtmlBuilder instance representing that new node.

done

builder = div.done() 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.

allDone

builder = div.allDone() Like .done(), but traverses all the way to the root node of the tree and returns it.

wikitext

div.wikitext('This is some [[example]] text.') Appends some markup to the node. It may include plain text, wiki markup, and even HTML markup.

newline

div.newline() Appends a newline character to the node. Equivalent to .wikitext('\n').

attr

div.attr('title', 'Attr value') Set an HTML attribute on the node.

css

div.css('color', '#f00') Set a CSS property to be added to the node's style attribute.

cssText

div.cssText('color:#f00; font-size:1.5em') 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, such as the liststyle parameter of {{Navbox}}.

addClass

div.addClass('even') Adds a class name to the node's class attribute. Spaces will be automatically added to delimit each added class name.

Examples

local HtmlBuilder = require('Module:HtmlBuilder')

local root = HtmlBuilder.create()

root
    .wikitext('Lorem ')
    .tag('span')
        .css('color', 'red')
        .attr('title', 'ipsum dolor')
        .wikitext('sit amet')
        .done()
    .tag('div')
        .wikitext('consectetur adipisicing')

local s = tostring(root)
-- s = 'Lorem <span style="color:red;" title="ipsum dolor">sit amet</span><div>consectetur adipisicing</div>'


For more examples, please see the test cases page and the test cases results.


-- Experimental module for building complex HTML (e.g. infoboxes, navboxes) using a fluent interface

local HtmlBuilder = {}

local metatable = {}

metatable.__index = function(t, key)
    local ret = rawget(t, key)
    if ret then
        return ret
    end
    
    ret = metatable[key]
    if type(ret) == 'function' then
        return function(...) 
            return ret(t, ...) 
        end 
    else
        return ret
    end
end

metatable.__tostring = function(t)
    local ret = {}
    t._build(ret)
    return table.concat(ret, '')
end

metatable._build = function(t, ret)
    if t.tagName then 
        table.insert(ret, '<' .. t.tagName)
        for i, attr in ipairs(t.attributes) do
            table.insert(ret, ' ' .. attr.name .. '="' .. attr.val .. '"') 
        end
        if #t.styles > 0 then
            table.insert(ret, ' style="')
            for i, prop in ipairs(t.styles) do
                if type(prop) == 'string' then -- added with cssText()
                    table.insert(ret, prop .. ';')
                else -- added with css()
                    table.insert(ret, prop.name .. ':' .. prop.val .. ';')
                end
            end
            table.insert(ret, '"')
        end
        if t.selfClosing then
            table.insert(ret, ' /')
        end
        table.insert(ret, '>') 
    end
    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
    if t.tagName and not t.unclosed and not t.selfClosing then
        table.insert(ret, '</' .. t.tagName .. '>')
    end
end
   
metatable.node = function(t, builder)
    if builder then
        table.insert(t.nodes, builder)
    end
    return t
end

metatable.wikitext = function(t, ...) 
    local vals = {...}
    for i = 1, #vals do
        if vals[i] then
            table.insert(t.nodes, vals[i])
        end
    end
    return t
end

metatable.newline = function(t)
    table.insert(t.nodes, '\n')
    return t
end

metatable.tag = function(t, tagName, args)
    args = args or {}
    args.parent = t
    local builder = HtmlBuilder.create(tagName, args)
    table.insert(t.nodes, builder)
    return builder
end

function getAttr(t, name)
    for i, attr in ipairs(t.attributes) do
        if attr.name == name then
            return attr
        end
    end
end

metatable.attr = function(t, name, val)
    -- 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
    
    local attr = getAttr(t, name)
    if attr then
        attr.val = val
    else
        table.insert(t.attributes, {name = name, val = val})
    end
    
    return t
end

metatable.addClass = function(t, class)
    if class then
        local attr = getAttr(t, 'class')
        if attr then
            attr.val = attr.val .. ' ' .. class
        else
            t.attr('class', class)
        end
    end

    return t
end

metatable.css = function(t, name, val)
    if type(val) == 'string' or type(val) == 'number' then
        for i, prop in ipairs(t.styles) do
            if prop.name == name then
                prop.val = val
                return t
            end
        end
        
        table.insert(t.styles, {name = name, val = val})
    end
    
    return t
end

metatable.cssText = function(t, css)
    if css then
        table.insert(t.styles, css)
    end
    return t
end

metatable.done = function(t)
    return t.parent or t
end

metatable.allDone = function(t)
    while t.parent do
        t = t.parent
    end
    return t
end

function HtmlBuilder.create(tagName, args)
    args = args or {}
    local builder = {}
    setmetatable(builder, metatable)
    builder.nodes = {}
    builder.attributes = {}
    builder.styles = {}
    builder.tagName = tagName
    builder.parent = args.parent
    builder.unclosed = args.unclosed or false
    builder.selfClosing = args.selfClosing or false
    return builder
end

return HtmlBuilder


Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.