پودمان:Navbox: تفاوت بین نسخه‌ها

از پژوهشکده امر به معروف
پرش به: ناوبری، جستجو
جز (۱ نسخه واردشده)
(۱ نسخهٔ میانی ویرایش شده توسط ۱ کاربر نشان داده نشده)
سطر ۱: سطر ۱:
 
--
 
--
-- This module implements {{Navbox}}
+
-- This module will implement {{Navbox}}
 
--
 
--
  
 
local p = {}
 
local p = {}
  
local navbar = require('Module:Navbar')._navbar
+
local HtmlBuilder = require('Module:HtmlBuilder')
local getArgs -- lazily initialized
+
local Navbar = require('Module:Navbar')
  
 
local args
 
local args
 +
local frame
 
local tableRowAdded = false
 
local tableRowAdded = false
 
local border
 
local border
 
local listnums = {}
 
local listnums = {}
  
local function trim(s)
+
function trim(s)
 
     return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
 
     return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
 
end
 
end
  
local function addNewline(s)
+
function addTableRow(tbl)
    if s:match('^[*:;#]') or s:match('^{|') then
+
        return '\n' .. s ..'\n'
+
    else
+
        return s
+
    end
+
end
+
 
+
local function addTableRow(tbl)
+
 
     -- If any other rows have already been added, then we add a 2px gutter row.
 
     -- If any other rows have already been added, then we add a 2px gutter row.
 
     if tableRowAdded then
 
     if tableRowAdded then
 
         tbl
 
         tbl
             :tag('tr')
+
             .tag('tr')
                 :css('height', '2px')
+
                 .css('height', '2px')
                 :tag('td')
+
                 .tag('td')
                    :attr('colspan',2)
+
 
     end
 
     end
  
 
     tableRowAdded = true
 
     tableRowAdded = true
  
     return tbl:tag('tr')
+
     return tbl.tag('tr')
 
end
 
end
  
local function renderNavBar(titleCell)
+
 
 +
--
 +
--  Title row
 +
--
 +
function renderTitleRow(tbl)
 +
    if not args.title then return end
 +
 
 +
    local titleRow = addTableRow(tbl)
 +
 
 +
    if args.titlegroup then
 +
        titleRow
 +
            .tag('th')
 +
                .attr('scope', 'row')
 +
                .addClass('navbox-group')
 +
                .addClass(args.titlegroupclass)
 +
                .cssText(args.basestyle)
 +
                .cssText(args.groupstyle)
 +
                .cssText(args.titlegroupstyle)
 +
                .wikitext(args.titlegroup)
 +
    end
 +
 
 +
    local titleCell = titleRow.tag('th').attr('scope', 'col')
 +
 
 +
    if args.titlegroup then
 +
        titleCell
 +
            .css('border-left', '2px solid #fdfdfd')
 +
            .css('width', '100%')
 +
    end
 +
 
 +
    local titleColspan = 2
 +
    if args.imageleft then titleColspan = titleColspan + 1 end
 +
    if args.image then titleColspan = titleColspan + 1 end
 +
    if args.titlegroup then titleColspan = titleColspan - 1 end
 +
 
 +
    titleCell
 +
        .cssText(args.basestyle)
 +
        .cssText(args.titlestyle)
 +
        .addClass('navbox-title')
 +
        .attr('colspan', titleColspan)
 +
 
 +
    renderNavBar(titleCell)
 +
 
 +
    titleCell
 +
        .tag('div')
 +
            .addClass(args.titleclass)
 +
            .css('font-size', '110%')
 +
            .newline()
 +
            .wikitext(args.title)
 +
end
 +
 
 +
function renderNavBar(titleCell)
 
     -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
 
     -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
 
     -- or right to keep the title centered.
 
     -- or right to keep the title centered.
سطر ۴۹: سطر ۹۱:
 
         -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
 
         -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
 
         if args.state == 'plain' then spacerSide = 'right' end
 
         if args.state == 'plain' then spacerSide = 'right' end
     elseif args.navbar == 'plain' or (not args.name and mw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$', '') == 'Template:Navbox') then
+
     elseif args.navbar == 'plain' or args.navbar == 'off' or (not args.name and (border == 'subgroup' or border == 'child' or border == 'none')) then
 
         -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
 
         -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
 
         if args.state ~= 'plain' then spacerSide = 'left' end
 
         if args.state ~= 'plain' then spacerSide = 'left' end
سطر ۵۷: سطر ۹۹:
 
         if args.state == 'plain' then spacerSide = 'right' end
 
         if args.state == 'plain' then spacerSide = 'right' end
  
         titleCell:wikitext(navbar{
+
         titleCell.wikitext(Navbar.navbar({
 
             args.name,
 
             args.name,
 
             mini = 1,
 
             mini = 1,
 
             fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
 
             fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
         })
+
         }))
 
     end
 
     end
  
 
     -- Render the spacer div.
 
     -- Render the spacer div.
 +
    --            .css('float', spacerSide)
 
     if spacerSide then
 
     if spacerSide then
 
         titleCell
 
         titleCell
             :tag('span')
+
             .tag('span')
                 :css('float', spacerSide)
+
   
                 :css('width', '6em')
+
                 .css('float', 'right')
                 :wikitext(' ')
+
                 .css('width', '6em')
 +
                 .wikitext(' ')
 
     end
 
     end
 
end
 
end
 +
  
 
--
 
--
--  Title row
+
--  Above/Below rows
 
--
 
--
local function renderTitleRow(tbl)
+
function renderAboveRow(tbl)
     if not args.title then return end
+
     if not args.above then return end
  
     local titleRow = addTableRow(tbl)
+
     addTableRow(tbl)
 +
        .tag('td')
 +
            .addClass('navbox-abovebelow')
 +
            .addClass(args.aboveclass)
 +
            .cssText(args.basestyle)
 +
            .cssText(args.abovestyle)
 +
            .attr('colspan', getAboveBelowColspan())
 +
            .tag('div')
 +
                .newline()
 +
                .wikitext(args.above)
 +
end
  
     if args.titlegroup then
+
function renderBelowRow(tbl)
        titleRow
+
     if not args.below then return end
            :tag('th')
+
                :attr('scope', 'row')
+
                :addClass('navbox-group')
+
                :addClass(args.titlegroupclass)
+
                :cssText(args.basestyle)
+
                :cssText(args.groupstyle)
+
                :cssText(args.titlegroupstyle)
+
                :wikitext(args.titlegroup)
+
    end
+
  
     local titleCell = titleRow:tag('th'):attr('scope', 'col')
+
     addTableRow(tbl)
 
+
        .tag('td')
    if args.titlegroup then
+
            .addClass('navbox-abovebelow')
        titleCell
+
             .addClass(args.belowclass)
            :css('border-left', '2px solid #fdfdfd')
+
            .cssText(args.basestyle)
             :css('width', '100%')
+
            .cssText(args.belowstyle)
    end
+
            .attr('colspan', getAboveBelowColspan())
 
+
            .tag('div')
    local titleColspan = 2
+
                .newline()
    if args.imageleft then titleColspan = titleColspan + 1 end
+
                .wikitext(args.below)
    if args.image then titleColspan = titleColspan + 1 end
+
    if args.titlegroup then titleColspan = titleColspan - 1 end
+
 
+
    titleCell
+
        :cssText(args.basestyle)
+
        :cssText(args.titlestyle)
+
        :addClass('navbox-title')
+
        :attr('colspan', titleColspan)
+
 
+
    renderNavBar(titleCell)
+
 
+
    titleCell
+
        :tag('div')
+
            :addClass(args.titleclass)
+
            :css('font-size', '114%')
+
            :wikitext(addNewline(args.title))
+
 
end
 
end
  
--
+
function getAboveBelowColspan()
--  Above/Below rows
+
--
+
 
+
local function getAboveBelowColspan()
+
 
     local ret = 2
 
     local ret = 2
 
     if args.imageleft then ret = ret + 1 end
 
     if args.imageleft then ret = ret + 1 end
سطر ۱۳۳: سطر ۱۵۹:
 
end
 
end
  
local function renderAboveRow(tbl)
 
    if not args.above then return end
 
 
    addTableRow(tbl)
 
        :tag('td')
 
            :addClass('navbox-abovebelow')
 
            :addClass(args.aboveclass)
 
            :cssText(args.basestyle)
 
            :cssText(args.abovestyle)
 
            :attr('colspan', getAboveBelowColspan())
 
            :tag('div')
 
                :wikitext(addNewline(args.above))
 
end
 
 
local function renderBelowRow(tbl)
 
    if not args.below then return end
 
 
    addTableRow(tbl)
 
        :tag('td')
 
            :addClass('navbox-abovebelow')
 
            :addClass(args.belowclass)
 
            :cssText(args.basestyle)
 
            :cssText(args.belowstyle)
 
            :attr('colspan', getAboveBelowColspan())
 
            :tag('div')
 
                :wikitext(addNewline(args.below))
 
end
 
  
 
--
 
--
 
--  List rows
 
--  List rows
 
--
 
--
local function renderListRow(tbl, listnum)
+
function renderListRow(tbl, listnum)
 
     local row = addTableRow(tbl)
 
     local row = addTableRow(tbl)
  
 
     if listnum == 1 and args.imageleft then
 
     if listnum == 1 and args.imageleft then
 
         row
 
         row
             :tag('td')
+
             .tag('td')
                 :addClass('navbox-image')
+
                 .addClass('navbox-image')
                 :addClass(args.imageclass)
+
                 .addClass(args.imageclass)
                 :css('width', '0%')
+
                 .css('width', '0%')
                 :css('padding', '0px 2px 0px 0px')
+
                 .css('padding', '0px 2px 0px 0px')
                 :cssText(args.imageleftstyle)
+
                 .cssText(args.imageleftstyle)
                 :attr('rowspan', 2 * #listnums - 1)
+
                 .attr('rowspan', 2 * #listnums - 1)
                 :tag('div')
+
                 .tag('div')
                     :wikitext(addNewline(args.imageleft))
+
                     .newline()
 +
                    .wikitext(args.imageleft)
 
     end
 
     end
  
 
     if args['group' .. listnum] then
 
     if args['group' .. listnum] then
         local groupCell = row:tag('th')
+
         local groupCell = row.tag('th')
  
 
         groupCell
 
         groupCell
            :attr('scope', 'row')
+
              .attr('scope', 'row')
            :addClass('navbox-group')
+
              .addClass('navbox-group')
            :addClass(args.groupclass)
+
              .addClass(args.groupclass)
            :cssText(args.basestyle)
+
              .cssText(args.basestyle)
  
 
         if args.groupwidth then
 
         if args.groupwidth then
             groupCell:css('width', args.groupwidth)
+
             groupCell.css('width', args.groupwidth)
 
         end
 
         end
  
 
         groupCell
 
         groupCell
             :cssText(args.groupstyle)
+
             .cssText(args.groupstyle)
             :cssText(args['group' .. listnum .. 'style'])
+
             .cssText(args['group' .. listnum .. 'style'])
             :wikitext(args['group' .. listnum])
+
             .wikitext(args['group' .. listnum])
 
     end
 
     end
  
     local listCell = row:tag('td')
+
     local listCell = row.tag('td')
  
 
     if args['group' .. listnum] then
 
     if args['group' .. listnum] then
 
         listCell
 
         listCell
             :css('text-align', 'left')
+
             .css('text-align', 'left')
             :css('border-left-width', '2px')
+
             .css('border-left-width', '2px')
             :css('border-left-style', 'solid')
+
             .css('border-left-style', 'solid')
 
     else
 
     else
         listCell:attr('colspan', 2)
+
         listCell.attr('colspan', 2)
 
     end
 
     end
  
 
     if not args.groupwidth then
 
     if not args.groupwidth then
         listCell:css('width', '100%')
+
         listCell.css('width', '100%')
 
     end
 
     end
  
سطر ۲۲۶: سطر ۲۲۶:
  
 
     listCell
 
     listCell
         :css('padding', '0px')
+
         .css('padding', '0px')
         :cssText(args.liststyle)
+
         .cssText(args.liststyle)
         :cssText(rowstyle)
+
         .cssText(rowstyle)
         :cssText(args['list' .. listnum .. 'style'])
+
         .cssText(args['list' .. listnum .. 'style'])
         :addClass('navbox-list')
+
         .addClass('navbox-list')
         :addClass('navbox-' .. evenOdd)
+
         .addClass('navbox-' .. evenOdd)
         :addClass(args.listclass)
+
         .addClass(args.listclass)
         :tag('div')
+
         .tag('div')
             :css('padding', (listnum == 1 and args.list1padding) or args.listpadding or '0em 0.25em')
+
             .css('padding', (listnum == 1 and args.list1padding) or args.listpadding or '0em 0.25em')
             :wikitext(addNewline(args['list' .. listnum]))
+
             .newline()
 +
            .wikitext(args['list' .. listnum])
  
 
     if listnum == 1 and args.image then
 
     if listnum == 1 and args.image then
 
         row
 
         row
             :tag('td')
+
             .tag('td')
                 :addClass('navbox-image')
+
                 .addClass('navbox-image')
                 :addClass(args.imageclass)
+
                 .addClass(args.imageclass)
                 :css('width', '0%')
+
                 .css('width', '0%')
                 :css('padding', '0px 0px 0px 2px')
+
                 .css('padding', '0px 0px 0px 2px')
                 :cssText(args.imagestyle)
+
                 .cssText(args.imagestyle)
                 :attr('rowspan', 2 * #listnums - 1)
+
                 .attr('rowspan', 2 * #listnums - 1)
                 :tag('div')
+
                 .tag('div')
                     :wikitext(addNewline(args.image))
+
                     .newline()
 +
                    .wikitext(args.image)
 
     end
 
     end
 
end
 
end
سطر ۲۵۵: سطر ۲۵۷:
 
--  Tracking categories
 
--  Tracking categories
 
--
 
--
 +
function renderTrackingCategories(builder)
 +
    local frame = mw.getCurrentFrame()
  
local function needsHorizontalLists()
+
    if not frame then return end
 +
 
 +
    local s = frame:preprocess('{{#ifeq:{{NAMESPACE}}|{{ns:10}}|1|0}}{{SUBPAGENAME}}')
 +
    if mw.ustring.sub(s, 1, 1) == '0' then return end -- not in template space
 +
    local subpage = mw.ustring.lower(mw.ustring.sub(s, 2))
 +
    if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end
 +
 
 +
    for i, cat in ipairs(getTrackingCategories()) do
 +
        builder.wikitext('')
 +
    end
 +
end
 +
 
 +
function getTrackingCategories()
 +
    local cats = {}
 +
    if needsHorizontalLists() then table.insert(cats, 'Navigational boxes without horizontal lists') end
 +
    if hasBackgroundColors() then table.insert(cats, 'Navboxes using background colours') end
 +
    return cats
 +
end
 +
 
 +
function needsHorizontalLists()
 
     if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end
 
     if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end
  
سطر ۲۶۹: سطر ۲۹۲:
 
end
 
end
  
local function hasBackgroundColors()
+
function hasBackgroundColors()
     return mw.ustring.match(args.titlestyle or '','background') or mw.ustring.match(args.groupstyle or '','background') or mw.ustring.match(args.basestyle or '','background')
+
     return args.titlestyle or args.groupstyle
 
end
 
end
  
local function isIllegible()
 
    local styleratio = require('Module:Color contrast')._styleratio
 
 
    for key, style in pairs(args) do
 
        if tostring(key):match("style$") then
 
            if styleratio{mw.text.unstripNoWiki(style)} < 4.5 then
 
                return true
 
            end
 
        end
 
    end
 
    return false
 
end
 
 
local function getTrackingCategories()
 
    local cats = {}
 
    if needsHorizontalLists() then table.insert(cats, 'Navigational boxes without horizontal lists') end
 
    if hasBackgroundColors() then table.insert(cats, 'Navboxes using background colours') end
 
    if isIllegible() then table.insert(cats, 'Potentially illegible navboxes') end
 
    return cats
 
end
 
 
local function renderTrackingCategories(builder)
 
    local title = mw.title.getCurrentTitle()
 
    if title.namespace ~= 10 then return end -- not in template space
 
    local subpage = title.subpageText
 
    if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end
 
 
    for i, cat in ipairs(getTrackingCategories()) do
 
        builder:wikitext('[[Category:' .. cat .. ']]')
 
    end
 
end
 
  
 
--
 
--
 
--  Main navbox tables
 
--  Main navbox tables
 
--
 
--
local function renderMainTable()
+
function renderMainTable()
     local tbl = mw.html.create('table')
+
     local tbl = HtmlBuilder.create('table')
         :addClass('nowraplinks')
+
         .attr('cellspacing', 0)
         :addClass(args.bodyclass)
+
        .addClass('nowraplinks')
 +
         .addClass(args.bodyclass)
  
 
     if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
 
     if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
 
         tbl
 
         tbl
             :addClass('collapsible')
+
             .addClass('collapsible')
             :addClass(args.state or 'autocollapse')
+
             .addClass(args.state or 'autocollapse')
 
     end
 
     end
  
     tbl:css('border-spacing', 0)
+
     tbl.css('border-spacing', 0)
 
     if border == 'subgroup' or border == 'child' or border == 'none' then
 
     if border == 'subgroup' or border == 'child' or border == 'none' then
 
         tbl
 
         tbl
             :addClass('navbox-subgroup')
+
             .addClass('navbox-subgroup')
             :cssText(args.bodystyle)
+
             .cssText(args.bodystyle)
             :cssText(args.style)
+
             .cssText(args.style)
 
     else -- regular navobx - bodystyle and style will be applied to the wrapper table
 
     else -- regular navobx - bodystyle and style will be applied to the wrapper table
 
         tbl
 
         tbl
             :addClass('navbox-inner')
+
             .addClass('navbox-inner')
             :css('background', 'transparent')
+
             .css('background', 'transparent')
             :css('color', 'inherit')
+
             .css('color', 'inherit')
 
     end
 
     end
     tbl:cssText(args.innerstyle)
+
     tbl.cssText(args.innerstyle)
  
 
     renderTitleRow(tbl)
 
     renderTitleRow(tbl)
سطر ۳۵۸: سطر ۳۵۱:
  
 
     -- render the appropriate wrapper around the navbox, depending on the border param
 
     -- render the appropriate wrapper around the navbox, depending on the border param
     local res = mw.html.create()
+
     local res = HtmlBuilder.create()
 
     if border == 'none' then
 
     if border == 'none' then
         res:node(tbl)
+
         res.node(tbl)
 
     elseif border == 'subgroup' or border == 'child' then
 
     elseif border == 'subgroup' or border == 'child' then
 
         -- We assume that this navbox is being rendered in a list cell of a parent navbox, and is
 
         -- We assume that this navbox is being rendered in a list cell of a parent navbox, and is
سطر ۳۶۶: سطر ۳۵۹:
 
         -- padding being applied, and at the end add a <div> to balance out the parent's </div>
 
         -- padding being applied, and at the end add a <div> to balance out the parent's </div>
 
         res
 
         res
             :wikitext('</div>') -- XXX: hack due to lack of unclosed support in mw.html.
+
             .tag('/div', {unclosed = true})
             :node(tbl)
+
                .done()
             :wikitext('<div>') -- XXX: hack due to lack of unclosed support in mw.html.
+
             .node(tbl)
 +
             .tag('div', {unclosed = true})
 
     else
 
     else
 
         res
 
         res
             :tag('table')
+
             .tag('table')
                 :addClass('navbox')
+
                 .attr('cellspacing', 0)
                 :css('border-spacing', 0)
+
                .addClass('navbox')
                 :cssText(args.bodystyle)
+
                 .css('border-spacing', 0)
                 :cssText(args.style)
+
                 .cssText(args.bodystyle)
                 :tag('tr')
+
                 .cssText(args.style)
                     :tag('td')
+
                 .tag('tr')
                         :css('padding', '2px')
+
                     .tag('td')
                         :node(tbl)
+
                         .css('padding', '2px')
 +
                         .node(tbl)
 
     end
 
     end
  
سطر ۳۸۸: سطر ۳۸۳:
  
 
function p.navbox(frame)
 
function p.navbox(frame)
     if not getArgs then
+
     -- ParserFunctions considers the empty string to be false, so to preserve the previous
        getArgs = require('Module:Arguments').getArgs
+
    -- behavior of {{navbox}}, change any empty arguments to nil, so Lua will consider
     end
+
     -- them false too.
     args = getArgs(frame, {wrappers = 'Template:Navbox'})
+
     local args = {}
 +
    local parent_args = frame:getParent().args;
  
     -- Read the arguments in the order they'll be output in, to make references number in the right order.
+
     -- Out of order parsing bug.
     local _
+
     local temp;
     _ = args.title
+
     temp = parent_args.title;
     _ = args.above
+
     temp = parent_args.above;
 
     for i = 1, 20 do
 
     for i = 1, 20 do
         _ = args["group" .. tostring(i)]
+
         temp = parent_args["group" .. tostring(i)];
         _ = args["list" .. tostring(i)]
+
         temp = parent_args["list" .. tostring(i)];
 
     end
 
     end
     _ = args.below
+
     temp = parent_args.below;
  
 +
    for k, v in pairs(parent_args) do
 +
        if v ~= '' then
 +
            args[k] = v
 +
        end
 +
    end
 
     return p._navbox(args)
 
     return p._navbox(args)
 
end
 
end
  
 
return p
 
return p

نسخهٔ ‏۱۱ فروردین ۱۳۹۴، ساعت ۱۲:۴۶

توضیحات این پودمان می‌تواند در پودمان:Navbox/توضیحات قرار گیرد.

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

local p = {}

local HtmlBuilder = require('Module:HtmlBuilder')
local Navbar = require('Module:Navbar')

local args
local frame
local tableRowAdded = false
local border
local listnums = {}

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

function addTableRow(tbl)
    -- If any other rows have already been added, then we add a 2px gutter row.
    if tableRowAdded then
        tbl
            .tag('tr')
                .css('height', '2px')
                .tag('td')
    end

    tableRowAdded = true

    return tbl.tag('tr')
end


--
--   Title row
--
function renderTitleRow(tbl)
    if not args.title then return end

    local titleRow = addTableRow(tbl)

    if args.titlegroup then
        titleRow
            .tag('th')
                .attr('scope', 'row')
                .addClass('navbox-group')
                .addClass(args.titlegroupclass)
                .cssText(args.basestyle)
                .cssText(args.groupstyle)
                .cssText(args.titlegroupstyle)
                .wikitext(args.titlegroup)
    end

    local titleCell = titleRow.tag('th').attr('scope', 'col')

    if args.titlegroup then
        titleCell
            .css('border-left', '2px solid #fdfdfd')
            .css('width', '100%')
    end

    local titleColspan = 2
    if args.imageleft then titleColspan = titleColspan + 1 end
    if args.image then titleColspan = titleColspan + 1 end
    if args.titlegroup then titleColspan = titleColspan - 1 end

    titleCell
        .cssText(args.basestyle)
        .cssText(args.titlestyle)
        .addClass('navbox-title')
        .attr('colspan', titleColspan)

     renderNavBar(titleCell)

     titleCell
         .tag('div')
             .addClass(args.titleclass)
             .css('font-size', '110%')
             .newline()
             .wikitext(args.title)
end

function renderNavBar(titleCell)
    -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
    -- or right to keep the title centered.
    local spacerSide = nil

    if args.navbar == 'off' then
        -- No navbar, and client wants no spacer, i.e. wants the title to be shifted to the left. If there's
        -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
        if args.state == 'plain' then spacerSide = 'right' end
    elseif args.navbar == 'plain' or args.navbar == 'off' or (not args.name and (border == 'subgroup' or border == 'child' or border == 'none')) then
        -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
        if args.state ~= 'plain' then spacerSide = 'left' end
    else
        -- Will render navbar (or error message). If there's no show/hide link, need a spacer on the right
        -- to balance out the width of the navbar.
        if args.state == 'plain' then spacerSide = 'right' end

        titleCell.wikitext(Navbar.navbar({
            args.name,
            mini = 1,
            fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
        }))
    end

    -- Render the spacer div.
    --            .css('float', spacerSide)
    if spacerSide then
        titleCell
            .tag('span')
    
                .css('float', 'right')
                .css('width', '6em')
                .wikitext('&nbsp;')
    end
end


--
--   Above/Below rows
--
function renderAboveRow(tbl)
    if not args.above then return end

    addTableRow(tbl)
        .tag('td')
            .addClass('navbox-abovebelow')
            .addClass(args.aboveclass)
            .cssText(args.basestyle)
            .cssText(args.abovestyle)
            .attr('colspan', getAboveBelowColspan())
            .tag('div')
                .newline()
                .wikitext(args.above)
end

function renderBelowRow(tbl)
    if not args.below then return end

    addTableRow(tbl)
        .tag('td')
            .addClass('navbox-abovebelow')
            .addClass(args.belowclass)
            .cssText(args.basestyle)
            .cssText(args.belowstyle)
            .attr('colspan', getAboveBelowColspan())
            .tag('div')
                .newline()
                .wikitext(args.below)
end

function getAboveBelowColspan()
    local ret = 2
    if args.imageleft then ret = ret + 1 end
    if args.image then ret = ret + 1 end
    return ret
end


--
--   List rows
--
function renderListRow(tbl, listnum)
    local row = addTableRow(tbl)

    if listnum == 1 and args.imageleft then
        row
            .tag('td')
                .addClass('navbox-image')
                .addClass(args.imageclass)
                .css('width', '0%')
                .css('padding', '0px 2px 0px 0px')
                .cssText(args.imageleftstyle)
                .attr('rowspan', 2 * #listnums - 1)
                .tag('div')
                    .newline()
                    .wikitext(args.imageleft)
    end

    if args['group' .. listnum] then
        local groupCell = row.tag('th')

        groupCell
               .attr('scope', 'row')
               .addClass('navbox-group')
               .addClass(args.groupclass)
               .cssText(args.basestyle)

        if args.groupwidth then
            groupCell.css('width', args.groupwidth)
        end

        groupCell
            .cssText(args.groupstyle)
            .cssText(args['group' .. listnum .. 'style'])
            .wikitext(args['group' .. listnum])
    end

    local listCell = row.tag('td')

    if args['group' .. listnum] then
        listCell
            .css('text-align', 'left')
            .css('border-left-width', '2px')
            .css('border-left-style', 'solid')
    else
        listCell.attr('colspan', 2)
    end

    if not args.groupwidth then
        listCell.css('width', '100%')
    end

    local isOdd = (listnum % 2) == 1
    local rowstyle = args.evenstyle
    if isOdd then rowstyle = args.oddstyle end

    local evenOdd
    if args.evenodd == 'swap' then
        if isOdd then evenOdd = 'even' else evenOdd = 'odd' end
    else
        if isOdd then evenOdd = args.evenodd or 'odd' else evenOdd = args.evenodd or 'even' end
    end

    listCell
        .css('padding', '0px')
        .cssText(args.liststyle)
        .cssText(rowstyle)
        .cssText(args['list' .. listnum .. 'style'])
        .addClass('navbox-list')
        .addClass('navbox-' .. evenOdd)
        .addClass(args.listclass)
        .tag('div')
            .css('padding', (listnum == 1 and args.list1padding) or args.listpadding or '0em 0.25em')
            .newline()
            .wikitext(args['list' .. listnum])

    if listnum == 1 and args.image then
        row
            .tag('td')
                .addClass('navbox-image')
                .addClass(args.imageclass)
                .css('width', '0%')
                .css('padding', '0px 0px 0px 2px')
                .cssText(args.imagestyle)
                .attr('rowspan', 2 * #listnums - 1)
                .tag('div')
                    .newline()
                    .wikitext(args.image)
    end
end


--
--   Tracking categories
--
function renderTrackingCategories(builder)
    local frame = mw.getCurrentFrame()

    if not frame then return end

    local s = frame:preprocess('{{#ifeq:{{NAMESPACE}}|{{ns:10}}|1|0}}{{SUBPAGENAME}}')
    if mw.ustring.sub(s, 1, 1) == '0' then return end -- not in template space
    local subpage = mw.ustring.lower(mw.ustring.sub(s, 2))
    if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end

    for i, cat in ipairs(getTrackingCategories()) do
        builder.wikitext('')
    end
end

function getTrackingCategories()
    local cats = {}
    if needsHorizontalLists() then table.insert(cats, 'Navigational boxes without horizontal lists') end
    if hasBackgroundColors() then table.insert(cats, 'Navboxes using background colours') end
    return cats
end

function needsHorizontalLists()
    if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end

    local listClasses = {'plainlist', 'hlist', 'hlist hnum', 'hlist hwrap', 'hlist vcard', 'vcard hlist', 'hlist vevent'}
    for i, cls in ipairs(listClasses) do
        if args.listclass == cls or args.bodyclass == cls then
            return false
        end
    end

    return true
end

function hasBackgroundColors()
    return args.titlestyle or args.groupstyle
end


--
--   Main navbox tables
--
function renderMainTable()
    local tbl = HtmlBuilder.create('table')
        .attr('cellspacing', 0)
        .addClass('nowraplinks')
        .addClass(args.bodyclass)

    if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
        tbl
            .addClass('collapsible')
            .addClass(args.state or 'autocollapse')
    end

    tbl.css('border-spacing', 0)
    if border == 'subgroup' or border == 'child' or border == 'none' then
        tbl
            .addClass('navbox-subgroup')
            .cssText(args.bodystyle)
            .cssText(args.style)
    else -- regular navobx - bodystyle and style will be applied to the wrapper table
        tbl
            .addClass('navbox-inner')
            .css('background', 'transparent')
            .css('color', 'inherit')
    end
    tbl.cssText(args.innerstyle)

    renderTitleRow(tbl)
    renderAboveRow(tbl)
    for i, listnum in ipairs(listnums) do
        renderListRow(tbl, listnum)
    end
    renderBelowRow(tbl)

    return tbl
end

function p._navbox(navboxArgs)
    args = navboxArgs

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

    -- render the main body of the navbox
    local tbl = renderMainTable()

    -- render the appropriate wrapper around the navbox, depending on the border param
    local res = HtmlBuilder.create()
    if border == 'none' then
        res.node(tbl)
    elseif border == 'subgroup' or border == 'child' then
        -- We assume that this navbox is being rendered in a list cell of a parent navbox, and is
        -- therefore inside a div with padding:0em 0.25em. We start with a </div> to avoid the
        -- padding being applied, and at the end add a <div> to balance out the parent's </div>
        res
            .tag('/div', {unclosed = true})
                .done()
            .node(tbl)
            .tag('div', {unclosed = true})
    else
        res
            .tag('table')
                .attr('cellspacing', 0)
                .addClass('navbox')
                .css('border-spacing', 0)
                .cssText(args.bodystyle)
                .cssText(args.style)
                .tag('tr')
                    .tag('td')
                        .css('padding', '2px')
                        .node(tbl)
    end

    renderTrackingCategories(res)

    return tostring(res)
end

function p.navbox(frame)
    -- ParserFunctions considers the empty string to be false, so to preserve the previous
    -- behavior of {{navbox}}, change any empty arguments to nil, so Lua will consider
    -- them false too.
    local args = {}
    local parent_args = frame:getParent().args;

    -- Out of order parsing bug.
    local temp;
    temp = parent_args.title;
    temp = parent_args.above;
    for i = 1, 20 do
        temp = parent_args["group" .. tostring(i)];
        temp = parent_args["list" .. tostring(i)];
    end
    temp = parent_args.below;

    for k, v in pairs(parent_args) do
        if v ~= '' then
            args[k] = v
        end
    end
    return p._navbox(args)
end

return p