User Tools

Site Tools


hack:module:html_builder

– 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

hack/module/html_builder.txt · Last modified: 2019/03/11 15:56 by 127.0.0.1