Module:Navbox

From Test Wiki
Revision as of 08:30, 27 February 2013 by wikipedia>Toohool (fix for lists in image and imageleft)

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

--
-- This module will implement {{Navbox}}
--

local p = {}

local gutterRow = '<tr style="height:2px;"><td></td></tr>'
local border
local listnums = {}
local ret = {}

function add(...)
    local args = {...}
    for i = 1, #args do
        if args[i] then
            table.insert(ret, args[i])
        end
    end
end

function trim(s)
    return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
end

function renderTitleRow(args)
    if not args.title then return end
    
    add('<tr>')
    if args.titlegroup then
        add('<th scope="row" class="navbox-group ', args.titlegroupclass, '" style="', args.basestyle, ';', args.groupstyle, ';', args.titlegroupstyle, '">', args.titlegroup, '</th><th scope="col" style="border-left:2px solid #fdfdfd;width:100%;')
    else
        add('<th scope="col" style="')
    end
    local colspan = 2
    if args.imageleft then colspan = colspan + 1 end
    if args.image then colspan = colspan + 1 end
    if args.titlegroup then colspan = colspan - 1 end
    add(args.basestyle, ';', args.titlestyle, '" class="navbox-title" colspan=', colspan, '>')

    local stateLinkPlaceholder = '<span style="float:right;width:6em;">&nbsp;</span>'
    if args.navbar == 'plain' or args.navbar == 'off' or (not args.name and (border == 'subgroup' or border == 'child' or border == 'none')) then
        if args.navbar == 'off' then
            if args.state == 'plain' then add(stateLinkPlaceholder) end
        else
            if args.state ~= 'plain' then add(stateLinkPlaceholder) end
        end
    else
        if args.name then
            add(mw.getCurrentFrame():expandTemplate{ title = 'navbar', args = { 
                args.name, 
                mini = 1, 
                fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
            }})
        else
            add('<span class="error" style="float:left;white-space:nowrap;">Error: No name provided</span>')
            if args.state == 'plain' then add(stateLinkPlaceholder) end
        end
    end

    add('<div class="', args.titleclass, '" style="font-size:110%;">')
    add(args.title)
    add('</div></th></tr>')
end

function renderAboveRow(args)
    if not args.above then return end
    
    if args.title then add(gutterRow) end
    add('<tr><td class="navbox-abovebelow ', args.aboveclass, '" style="', args.basestyle, ';', args.abovestyle, '" colspan="', getAboveBelowColspan(args), '">')
    add('<div>\n', args.above, '</div></td></tr>')
end
function renderBelowRow(args)
    if args.below then
        if args.title or args.above or #listnums > 0 then add(gutterRow) end
        add('<tr><td class="navbox-abovebelow ', args.belowclass, '" style="', args.basestyle, ';', args.belowstyle, '"  colspan="', getAboveBelowColspan(args), '">')
        add('<div>\n', args.below, '</div></td></tr>')
    end
end
function getAboveBelowColspan(args)
    local ret = 2
    if args.imageleft then ret = ret + 1 end
    if args.image then ret = ret + 1 end
    return ret
end

function renderFirstListRow(args)
    if not args.list1 then return end
    
    if args.title or args.above then add(gutterRow) end
    add('<tr>')
    if args.imageleft then
        add('<td class="navbox-image ', args.imageclass, '" style="width:0%;padding:0px 2px 0px 0px;', args.imageleftstyle, '"')
        add(' rowspan=', (2 * #listnums - 1), '><div>\n', args.imageleft, '</div></td>')
    end

    if args.group1 then
        add('<th scope="row" class="navbox-group ', args.groupclass, '" style="', args.basestyle, ';')
        if args.groupwidth then add('width:', args.groupwidth, ';') end
        add(args.groupstyle, ';', args.group1style, '">')
        add(args.group1, '</th>')
        add('<td style="text-align:left;border-left-width:2px;border-left-style:solid;')
    else
        add('<td colspan=2 style="')
    end
    if not args.groupwidth then add('width:100%;') end
    add('padding:0px;', args.liststyle, ';', args.oddstyle, ';', args.list1style, '" class="navbox-list navbox-')
    if args.evenodd == 'swap' then
        add('even')
    else
        add(args.evenodd or 'odd')
    end
    add(' ', args.listclass, '">')
    add('<div style="padding:', args.list1padding or args.listpadding or '0em 0.25em', '">\n')
    add(args.list1)
    add('</div></td>')

    if args.image then
        add('<td class="navbox-image ', args.imageclass, '" style="width:0%;padding:0px 0px 0px 2px;', args.imagestyle, '" ')
        add(' rowspan=', (2 * #listnums - 1), '>')
        add('<div>\n', args.image, '</div></td>')
    end
    
    add('</tr>')
end

function renderNthListRow(args, listnum)
    if args.title or args.above or args.list1 then
        add(gutterRow)
    end
    add('<tr>')
    if args['group' .. listnum] then
        add('<th scope="row" class="navbox-group ', args.groupclass, '" style="', args.basestyle, ';')
        if args.groupwidth then add('width:', args.groupwidth, ';') end
        add(args.groupstyle, ';', args['group' .. listnum .. 'style'], '">')
        add(args['group' .. listnum])
        add('</th><td style="text-align:left;border-left-width:2px;border-left-style:solid;')
    else
        add('<td colspan=2 style="')
    end
    if not args.groupwidth then add('width:100%;') end
    
    local isOdd = (listnum % 2) == 1
    local rowstyle = args.evenstyle
    if isOdd then rowstyle = args.oddstyle end
        
    add('padding:0px;', args.liststyle, ';', rowstyle, ';', args['list' .. listnum .. 'style'], '" ')
    add('class="navbox-list navbox-')
    if args.evenodd == 'swap' then
        if isOdd then add('even') else add('odd') end
    else
        if isOdd then add(args.evenodd or 'odd') else add(args.evenodd or 'even') end
    end
    add(' ', args.listclass, '">')
    
    add('<div style="padding:', args.listpadding or '0em 0.25em', '">\n', args['list' .. listnum], '</div></td></tr>')
end

function p._navbox(args)
    for k, v in pairs(args) do
        local listnum = ('' .. k):match('^list(%d+)$')
        if listnum then table.insert(listnums, tonumber(listnum)) end
    end
    table.sort(listnums)
    
    border = trim(args.border or args[1] or '')
    if border == 'subgroup' or border == 'child' then
        add('</div>')
    elseif border ~= 'none' then
        add('<table cellspacing="0" class="navbox" style="border-spacing:0;', args.bodystyle, ';', args.style, '"><tr><td style="padding:2px;">')
    end
    
    add('<table cellspacing="0" class="nowraplinks ', args.bodyclass, ' ')
    
    if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
        add('collapsible ', args.state or 'autocollapse', ' ')
    end
    
    if border == 'subgroup' or border == 'child' or border == 'none' then
        add('navbox-subgroup" style="border-spacing:0;', args.bodystyle, ';', args.style)
    else
        add('navbox-inner" style="border-spacing:0;background:transparent;color:inherit')
    end
    add(';', args.innerstyle, ';">')
    
    renderTitleRow(args)
    renderAboveRow(args)
    renderFirstListRow(args)

    -- render lists 2 through N
    for i, listnum in ipairs(listnums) do
        if listnum > 1 then
            renderNthListRow(args, listnum) 
        end
    end

    renderBelowRow(args)

    add('</table>')
    
    if border == 'subgroup' or border == 'child' then
        add('<div>')
    elseif border ~= 'none' then
        add('</td></tr></table>')
    end

    -- TODO: add tracking categories
    
    return table.concat(ret, '')
end

function p.navbox(frame)
    return p._navbox(frame:getParent().args)
end

return p