Difference between revisions of ":HtmlBuilder"

From MediaWiki
Jump to: navigation, search
m (1 revision)
(don't add attributes with no values, plus a couple of minor tweaks)
Line 1: Line 1:
-- Experimental module for building complex HTML (e.g. infoboxes, navboxes) using a fluent interface
+
-- Module for building complex HTML (e.g. infoboxes, navboxes) using a fluent interface.
  
 
local HtmlBuilder = {}
 
local HtmlBuilder = {}
Line 24: Line 24:
 
     local ret = {}
 
     local ret = {}
 
     t._build(ret)
 
     t._build(ret)
     return table.concat(ret, '')
+
     return table.concat(ret)
 
end
 
end
  
Line 43: Line 43:
 
             end
 
             end
 
             table.insert(ret, '"')
 
             table.insert(ret, '"')
 +
        end
 +
        if t.selfClosing then
 +
            table.insert(ret, ' /')
 
         end
 
         end
 
         table.insert(ret, '>')  
 
         table.insert(ret, '>')  
Line 55: Line 58:
 
         end
 
         end
 
     end
 
     end
     if t.tagName and not t.unclosed then
+
     if t.tagName and not t.unclosed and not t.selfClosing then
 
         table.insert(ret, '</' .. t.tagName .. '>')
 
         table.insert(ret, '</' .. t.tagName .. '>')
 
     end
 
     end
 
end
 
end
 
+
 
 
metatable.node = function(t, builder)
 
metatable.node = function(t, builder)
 
     if builder then
 
     if builder then
Line 90: Line 93:
 
end
 
end
  
function getAttr(t, name)
+
local function getAttr(t, name)
 
     for i, attr in ipairs(t.attributes) do
 
     for i, attr in ipairs(t.attributes) do
 
         if attr.name == name then
 
         if attr.name == name then
Line 99: Line 102:
  
 
metatable.attr = function(t, name, val)
 
metatable.attr = function(t, name, val)
     -- if caller sets the style attribute explicitly, then replace all styles previously added with css() and cssText()
+
     if type(val) == 'string' or type(val) == 'number' then
    if name == 'style' then
+
        -- if caller sets the style attribute explicitly, then replace all styles previously added with css() and cssText()
        t.styles = {val}
+
        if name == 'style' then
        return t
+
            t.styles = {val}
    end
+
            return t
   
+
        end
    local attr = getAttr(t, name)
+
       
    if attr then
+
        local attr = getAttr(t, name)
        attr.val = val
+
        if attr then
    else
+
            attr.val = val
        table.insert(t.attributes, {name = name, val = val})
+
        else
 +
            table.insert(t.attributes, {name = name, val = val})
 +
        end
 
     end
 
     end
 
      
 
      
Line 124: Line 129:
 
         end
 
         end
 
     end
 
     end
 
+
   
 
     return t
 
     return t
 
end
 
end
Line 171: Line 176:
 
     builder.parent = args.parent
 
     builder.parent = args.parent
 
     builder.unclosed = args.unclosed or false
 
     builder.unclosed = args.unclosed or false
 +
    builder.selfClosing = args.selfClosing or false
 
     return builder
 
     return builder
 
end
 
end
  
 
return HtmlBuilder
 
return HtmlBuilder

Revision as of 02:22, 19 September 2013

-- 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

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox