Module:HtmlBuilder

From para.wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Documentation for this module may be created at Module:HtmlBuilder/doc

-- 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
 
local 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 type(val) == 'string' or type(val) == 'number' then
        -- 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
    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