Module : HtmlBuilder

Mai Wikipedia

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