Difference between revisions of "Module:HtmlBuilder"

From Creation History Wiki
Jump to: navigation, search
(add css support)
(add addClass method and support for unclosed tags)
Line 44: Line 44:
 
         table.insert(ret, tostring(node))
 
         table.insert(ret, tostring(node))
 
     end
 
     end
     if t.tagName then
+
     if t.tagName and not t.unclosed then
 
         table.insert(ret, '</' .. t.tagName .. '>')
 
         table.insert(ret, '</' .. t.tagName .. '>')
 
     end
 
     end
Line 71: Line 71:
 
     table.insert(t.nodes, builder)
 
     table.insert(t.nodes, builder)
 
     return 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
 
end
  
Line 79: Line 87:
 
         return t
 
         return t
 
     end
 
     end
       
+
   
     for i, attr in ipairs(t.attributes) do
+
     local attr = getAttr(t, name)
        if attr.name == name then
+
    if attr then
            attr.val = val
+
        attr.val = val
            return t
+
    else
         end
+
         table.insert(t.attributes, {name = name, val = val})
 
     end
 
     end
 +
   
 +
    return t
 +
end
  
    table.insert(t.attributes, {name = name, val = val})
+
metatable.addClass = function(t, class)
 +
    local attr = getAttr(t, 'class')
 +
    if attr then
 +
        attr.val = attr.val .. ' ' .. class
 +
    else
 +
        t.attr('class', class)
 +
    end
 +
   
 
     return t
 
     return t
 
end
 
end
Line 128: Line 146:
 
     builder.tagName = tagName
 
     builder.tagName = tagName
 
     builder.parent = args.parent
 
     builder.parent = args.parent
 +
    builder.unclosed = args.unclosed or false
 
     return builder
 
     return builder
 
end
 
end
  
 
return HtmlBuilder
 
return HtmlBuilder

Revision as of 03:35, 28 February 2013

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

-- 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 = {}
    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
        table.insert(ret, '>') 
    end
    for i, node in ipairs(t.nodes) do
        table.insert(ret, tostring(node))
    end
    if t.tagName and not t.unclosed then
        table.insert(ret, '</' .. t.tagName .. '>')
    end
    return table.concat(ret, '')
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)
    local attr = getAttr(t, 'class')
    if attr then
        attr.val = attr.val .. ' ' .. class
    else
        t.attr('class', class)
    end
    
    return t
end

metatable.css = function(t, name, val)
    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})
    return t
end

metatable.cssText = function(t, css)
    table.insert(t.styles, css)
    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
    return builder
end

return HtmlBuilder