모듈:Navbox: 두 판 사이의 차이

imported>Toohool
fix handling of the border param
imported>Izno
templatestyles, basic i18n, look for titlegroup
 
(사용자 20명의 중간 판 83개는 보이지 않습니다)
1번째 줄: 1번째 줄:
--
local p = {}
-- This module will implement {{Navbox}}
local navbar = require('Module:Navbar')._navbar
--
local cfg = mw.loadData('Module:Navbox/configuration')
local getArgs -- lazily initialized
local args
local format = string.format
 
local function striped(wikitext, border)
-- Return wikitext with markers replaced for odd/even striping.
-- Child (subgroup) navboxes are flagged with a category that is removed
-- by parent navboxes. The result is that the category shows all pages
-- where a child navbox is not contained in a parent navbox.
local orphanCat = cfg.category.orphan
if border == cfg.keyword.border_subgroup and args[cfg.arg.orphan] ~= cfg.keyword.orphan_yes then
-- No change; striping occurs in outermost navbox.
return wikitext .. orphanCat
end
local first, second = cfg.class.navbox_odd_part, cfg.class.navbox_even_part
if args[cfg.arg.evenodd] then
if args[cfg.arg.evenodd] == cfg.keyword.evenodd_swap then
first, second = second, first
else
first = args[cfg.arg.evenodd]
second = first
end
end
local changer
if first == second then
changer = first
else
local index = 0
changer = function (code)
if code == '0' then
-- Current occurrence is for a group before a nested table.
-- Set it to first as a valid although pointless class.
-- The next occurrence will be the first row after a title
-- in a subgroup and will also be first.
index = 0
return first
end
index = index + 1
return index % 2 == 1 and first or second
end
end
local regex = orphanCat:gsub('([%[%]])', '%%%1')
return (wikitext:gsub(regex, ''):gsub(cfg.marker.regex, changer)) -- () omits gsub count
end
 
local function processItem(item, nowrapitems)
if item:sub(1, 2) == '{|' then
-- Applying nowrap to lines in a table does not make sense.
-- Add newlines to compensate for trim of x in |parm=x in a template.
return '\n' .. item ..'\n'
end
if nowrapitems == cfg.keyword.nowrapitems_yes then
local lines = {}
for line in (item .. '\n'):gmatch('([^\n]*)\n') do
local prefix, content = line:match('^([*:;#]+)%s*(.*)')
if prefix and not content:match(cfg.pattern.nowrap) then
line = format(cfg.nowrap_item, prefix, content)
end
table.insert(lines, line)
end
item = table.concat(lines, '\n')
end
if item:match('^[*:;#]') then
return '\n' .. item ..'\n'
end
return item
end
 
-- we will want this later when we want to add tstyles for hlist/plainlist
local function has_navbar()
return args[cfg.arg.navbar] ~= cfg.keyword.navbar_off
and args[cfg.arg.navbar] ~= cfg.keyword.navbar_plain
and (
args[cfg.arg.name]
or mw.getCurrentFrame():getParent():getTitle():gsub(cfg.pattern.sandbox, '')
~= cfg.pattern.navbox
)
end
 
local function renderNavBar(titleCell)
if has_navbar() then
titleCell:wikitext(navbar{
[cfg.navbar.name] = args[cfg.arg.name],
[cfg.navbar.mini] = 1,
[cfg.navbar.fontstyle] = (args[cfg.arg.basestyle] or '') .. ';' ..
(args[cfg.arg.titlestyle] or '') ..
';background:none transparent;border:none;box-shadow:none;padding:0;'
})
end
 
end
 
local function renderTitleRow(tbl)
if not args[cfg.arg.title] then return end
 
local titleRow = tbl:tag('tr')
 
if args[cfg.arg.titlegroup] then
titleRow
:tag('th')
:attr('scope', 'row')
:addClass(cfg.class.navbox_group)
:addClass(args[cfg.arg.titlegroupclass])
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.groupstyle])
:cssText(args[cfg.arg.titlegroupstyle])
:wikitext(args[cfg.arg.titlegroup])
end
 
local titleCell = titleRow:tag('th'):attr('scope', 'col')
 
if args[cfg.arg.titlegroup] then
titleCell
:css('border-left', '2px solid #fdfdfd')
:css('width', '100%')
end
 
local titleColspan = 2
if args[cfg.arg.imageleft] then titleColspan = titleColspan + 1 end
if args[cfg.arg.image] then titleColspan = titleColspan + 1 end
if args[cfg.arg.titlegroup] then titleColspan = titleColspan - 1 end
 
titleCell
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.titlestyle])
:addClass(cfg.class.navbox_title)
:attr('colspan', titleColspan)
 
renderNavBar(titleCell)
 
titleCell
:tag('div')
-- id for aria-labelledby attribute
:attr('id', mw.uri.anchorEncode(args[cfg.arg.title]))
:addClass(args[cfg.arg.titleclass])
:css('font-size', '114%')
:css('margin', '0 4em')
:wikitext(processItem(args[cfg.arg.title]))
end
 
local function getAboveBelowColspan()
local ret = 2
if args[cfg.arg.imageleft] then ret = ret + 1 end
if args[cfg.arg.image] then ret = ret + 1 end
return ret
end
 
local function renderAboveRow(tbl)
if not args[cfg.arg.above] then return end
 
tbl:tag('tr')
:tag('td')
:addClass(cfg.class.navbox_abovebelow)
:addClass(args[cfg.arg.aboveclass])
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.abovestyle])
:attr('colspan', getAboveBelowColspan())
:tag('div')
-- id for aria-labelledby attribute, if no title
:attr('id', args[cfg.arg.title] and nil or mw.uri.anchorEncode(args[cfg.arg.above]))
:wikitext(processItem(args[cfg.arg.above], args[cfg.arg.nowrapitems]))
end
 
local function renderBelowRow(tbl)
if not args[cfg.arg.below] then return end
 
tbl:tag('tr')
:tag('td')
:addClass(cfg.class.navbox_abovebelow)
:addClass(args[cfg.arg.belowclass])
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.belowstyle])
:attr('colspan', getAboveBelowColspan())
:tag('div')
:wikitext(processItem(args[cfg.arg.below], args[cfg.arg.nowrapitems]))
end
 
local function renderListRow(tbl, index, listnum, listnums_size)
local row = tbl:tag('tr')
 
if index == 1 and args[cfg.arg.imageleft] then
row
:tag('td')
:addClass(cfg.class.noviewer)
:addClass(cfg.class.navbox_image)
:addClass(args[cfg.arg.imageclass])
:css('width', '1px')              -- Minimize width
:css('padding', '0 2px 0 0')
:cssText(args[cfg.arg.imageleftstyle])
:attr('rowspan', listnums_size)
:tag('div')
:wikitext(processItem(args[cfg.arg.imageleft]))
end
 
local group_and_num = format(cfg.arg.group_and_num, listnum)
local groupstyle_and_num = format(cfg.arg.groupstyle_and_num, listnum)
if args[group_and_num] then
local groupCell = row:tag('th')
 
-- id for aria-labelledby attribute, if lone group with no title or above
if listnum == 1 and not (args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group2]) then
groupCell
:attr('id', mw.uri.anchorEncode(args[cfg.arg.group1]))
end
 
groupCell
:attr('scope', 'row')
:addClass(cfg.class.navbox_group)
:addClass(args[cfg.arg.groupclass])
:cssText(args[cfg.arg.basestyle])
-- If groupwidth not specified, minimize width
:css('width', args[cfg.arg.groupwidth] or '1%')
 
groupCell
:cssText(args[cfg.arg.groupstyle])
:cssText(args[groupstyle_and_num])
:wikitext(args[group_and_num])
end
 
local listCell = row:tag('td')
 
if args[group_and_num] then
listCell
:addClass(cfg.class.navbox_list_with_group)
else
listCell:attr('colspan', 2)
end
 
if not args[cfg.arg.groupwidth] then
listCell:css('width', '100%')
end


local p = {}
local rowstyle  -- usually nil so cssText(rowstyle) usually adds nothing
if index % 2 == 1 then
rowstyle = args[cfg.arg.oddstyle]
else
rowstyle = args[cfg.arg.evenstyle]
end
 
local list_and_num = format(cfg.arg.list_and_num, listnum)
local listText = args[list_and_num]
local oddEven = cfg.marker.oddeven
if listText:sub(1, 12) == '</div><table' then
-- Assume list text is for a subgroup navbox so no automatic striping for this row.
oddEven = listText:find(cfg.pattern.navbox_title) and cfg.marker.restart or cfg.class.navbox_odd_part
end


local gutterRow = '<tr style="height:2px;"><td></td></tr>'
local liststyle_and_num = format(cfg.arg.liststyle_and_num, listnum)
local border
local listclass_and_num = format(cfg.arg.listclass_and_num, listnum)
local listnums = {}
listCell
local ret = {}
:css('padding', '0')
:cssText(args[cfg.arg.liststyle])
:cssText(rowstyle)
:cssText(args[liststyle_and_num])
:addClass(cfg.class.navbox_list)
:addClass(cfg.class.navbox_part .. oddEven)
:addClass(args[cfg.arg.listclass])
:addClass(args[listclass_and_num])
:tag('div')
:css('padding',
(index == 1 and args[cfg.arg.list1padding]) or args[cfg.arg.listpadding] or '0 0.25em'
)
:wikitext(processItem(listText, args[cfg.arg.nowrapitems]))


function add(...)
if index == 1 and args[cfg.arg.image] then
    local args = {...}
row
    for i = 1, #args do
:tag('td')
        if args[i] then
:addClass(cfg.class.noviewer)
            table.insert(ret, args[i])
:addClass(cfg.class.navbox_image)
        end
:addClass(args[cfg.arg.imageclass])
    end
:css('width', '1px')              -- Minimize width
:css('padding', '0 0 0 2px')
:cssText(args[cfg.arg.imagestyle])
:attr('rowspan', listnums_size)
:tag('div')
:wikitext(processItem(args[cfg.arg.image]))
end
end
end


function trim(s)
-- uses this now to make the needHlistCategory correct
    return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
-- to use later for when we add list styles via navbox
local function has_list_class(htmlclass)
local class_args = { -- rough order of probability of use
cfg.arg.bodyclass, cfg.arg.listclass, cfg.arg.aboveclass,
cfg.arg.belowclass, cfg.arg.titleclass, cfg.arg.navboxclass,
cfg.arg.groupclass, cfg.arg.titlegroupclass, cfg.arg.imageclass
}
local patterns = {
'^' .. htmlclass .. '$',
'%s' .. htmlclass .. '$',
'^' .. htmlclass .. '%s',
'%s' .. htmlclass .. '%s'
}
for _, arg in ipairs(class_args) do
for _, pattern in ipairs(patterns) do
if mw.ustring.find(args[arg] or '', pattern) then
return true
end
end
end
return false
end
end


function renderTitleRow(args)
local function needsHorizontalLists(border)
    if not args.title then return end
if border == cfg.keyword.border_subgroup or args[cfg.arg.tracking] == cfg.keyword.tracking_no then
   
return false
    add('<tr>')
end
    if args.titlegroup then
return not has_list_class(cfg.pattern.hlist) and not has_list_class(cfg.pattern.plainlist)
        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%;')
end
    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>'
local function hasBackgroundColors()
    if args.navbar == 'plain' or args.navbar == 'off' or (not args.name and (border == 'subgroup' or border == 'child' or border == 'none')) then
for _, key in ipairs({cfg.arg.titlestyle, cfg.arg.groupstyle,
        if args.navbar == 'off' then
cfg.arg.basestyle, cfg.arg.abovestyle, cfg.arg.belowstyle}) do
            if args.state == 'plain' then add(stateLinkPlaceholder) end
if tostring(args[key]):find('background', 1, true) then
        else
return true
            if args.state ~= 'plain' then add(stateLinkPlaceholder) end
end
        end
end
    else
return false
        if args.name then
end
            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%;">')
local function hasTitleGroup()
    add(args.title)
if args[cfg.arg.titlegroup] and args[cfg.arg.titlegroup] ~= '' then
    add('</div></th></tr>')
return true
end
return false
end
end


function renderAboveRow(args)
local function hasBorders()
    if not args.above then return end
for _, key in ipairs({cfg.arg.groupstyle, cfg.arg.basestyle,
   
cfg.arg.abovestyle, cfg.arg.belowstyle}) do
    if args.title then add(gutterRow) end
if tostring(args[key]):find('border', 1, true) then
    add('<tr><td class="navbox-abovebelow ', args.aboveclass, '" style="', args.basestyle, ';', args.abovestyle, '" colspan="', getAboveBelowColspan(args), '">')
return true
    add('<div>\n', args.above, '</div></td></tr>')
end
end
return false
end
end
function renderBelowRow(args)
 
    if args.below then
local function isIllegible()
        if args.title or args.above or #listnums > 0 then add(gutterRow) end
local styleratio = require('Module:Color contrast')._styleratio
        add('<tr><td class="navbox-abovebelow ', args.belowclass, '" style="', args.basestyle, ';', args.belowstyle, '"  colspan="', getAboveBelowColspan(args), '">')
for key, style in pairs(args) do
        add('<div>\n', args.below, '</div></td></tr>')
if tostring(key):match(cfg.pattern.style) then
    end
if styleratio{mw.text.unstripNoWiki(style)} < 4.5 then
return true
end
end
end
return false
end
end
function getAboveBelowColspan(args)
 
    local ret = 2
local function getTrackingCategories(border)
    if args.imageleft then ret = ret + 1 end
local cats = {}
    if args.image then ret = ret + 1 end
if needsHorizontalLists(border) then table.insert(cats, cfg.category.horizontal_lists) end
    return ret
if hasBackgroundColors() then table.insert(cats, cfg.category.background_colors) end
if isIllegible() then table.insert(cats, cfg.category.illegible) end
if hasBorders() then table.insert(cats, cfg.category.borders) end
if hasTitleGroup() then table.insert(cats, cfg.category.titlegroup) end
return cats
end
end


function renderFirstListRow(args)
local function renderTrackingCategories(builder, border)
    if not args.list1 then return end
local title = mw.title.getCurrentTitle()
   
if title.namespace ~= 10 then return end -- not in template space
    if args.title or args.above then add(gutterRow) end
local subpage = title.subpageText
    add('<tr>')
if subpage == cfg.keyword.subpage_doc or subpage == cfg.keyword.subpage_sandbox
    if args.imageleft then
or subpage == cfg.keyword.subpage_testcases then return end
        add('<td class="navbox-image ', args.imageclass, '" style="width:0%;padding:0px 2px 0px 0px;', args.imageleftstyle, '"')
 
        add(' rowspan=', (2 * #listnums - 1), '><div>', args.imageleft, '</div></td>')
for _, cat in ipairs(getTrackingCategories(border)) do
    end
builder:wikitext('[[Category:' .. cat .. ']]')
end
end


    if args.group1 then
local function renderMainTable(border, listnums)
        add('<th scope="row" class="navbox-group ', args.groupclass, '" style="', args.basestyle, ';')
local tbl = mw.html.create('table')
        if args.groupwidth then add('width:', args.groupwidth, ';') end
:addClass(cfg.class.nowraplinks)
        add(args.groupstyle, ';', args.group1style, '">')
:addClass(args[cfg.arg.bodyclass])
        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
local state = args[cfg.arg.state]
        add('<td class="navbox-image ', args.imageclass, '" style="width:0%;padding:0px 0px 0px 2px;', args.imagestyle, '" ')
if args[cfg.arg.title] and state ~= cfg.keyword.state_plain and state ~= cfg.keyword.state_off then
        add(' rowspan=', (2 * #listnums - 1), '>')
if state == cfg.keyword.state_collapsed then
        add('<div>', args.image, '</div></td>')
state = cfg.class.collapsed
    end
end
   
tbl
    add('</tr>')
:addClass(cfg.class.collapsible)
:addClass(state or cfg.class.autocollapse)
end
 
tbl:css('border-spacing', 0)
if border == cfg.keyword.border_subgroup or border == cfg.keyword.border_none then
tbl
:addClass(cfg.class.navbox_subgroup)
:cssText(args[cfg.arg.bodystyle])
:cssText(args[cfg.arg.style])
else  -- regular navbox - bodystyle and style will be applied to the wrapper table
tbl
:addClass(cfg.class.navbox_inner)
:css('background', 'transparent')
:css('color', 'inherit')
end
tbl:cssText(args[cfg.arg.innerstyle])
 
renderTitleRow(tbl)
renderAboveRow(tbl)
local listnums_size = #listnums
for i, listnum in ipairs(listnums) do
renderListRow(tbl, i, listnum, listnums_size)
end
renderBelowRow(tbl)
 
return tbl
end
end


function renderNthListRow(args, listnum)
local function add_navbox_styles()
    if args.title or args.above or args.list1 then
local frame = mw.getCurrentFrame()
        add(gutterRow)
-- This is a lambda so that it doesn't need the frame as a parameter
    end
local function add_user_styles(templatestyles)
    add('<tr>')
if templatestyles and templatestyles ~= '' then
    if args['group' .. listnum] then
return frame:extensionTag{
        add('<th scope="row" class="navbox-group ', args.groupclass, '" style="', args.basestyle, ';')
name = 'templatestyles', args = { src = templatestyles }
        if args.groupwidth then add('width:', args.groupwidth, ';') end
}
        add(args.groupstyle, ';', args['group' .. listnum .. 'style'], '">')
end
        add(args['group' .. listnum])
return ''
        add('</th><td style="text-align:left;border-left-width:2px;border-left-style:solid;')
end
    else
 
        add('<td colspan=2 style="')
-- get templatestyles. load base from config so that Lua only needs to do
    end
-- the work once of parser tag expansion
    if not args.groupwidth then add('width:100%;') end
local base_templatestyles = cfg.templatestyles
   
local templatestyles = add_user_styles(args[cfg.arg.templatestyles])
    local isOdd = (listnum % 2) == 1
local child_templatestyles = add_user_styles(args[cfg.arg.child_templatestyles])
    local rowstyle = args.evenstyle
 
    if isOdd then rowstyle = args.oddstyle end
-- The 'navbox-styles' div exists for two reasons:
       
-- 1. To wrap the styles to work around T200206 more elegantly. Instead
     add('padding:0px;', args.liststyle, ';', rowstyle, ';', args['list' .. listnum .. 'style'], '" ')
--     of combinatorial rules, this ends up being linear number of CSS rules.
    add('class="navbox-list navbox-')
--  2. To allow MobileFrontend to rip the styles out with 'nomobile' such that
     if args.evenodd == 'swap' then
--    they are not dumped into the mobile view.
        if isOdd then add('even') else add('odd') end
return mw.html.create('div')
    else
:addClass(cfg.class.navbox_styles)
        if isOdd then add(args.evenodd or 'odd') else add(args.evenodd or 'even') end
:addClass(cfg.class.nomobile)
    end
:wikitext(base_templatestyles .. templatestyles .. child_templatestyles)
    add(' ', args.listclass, '">')
:done()
   
    add('<div style="padding:', args.listpadding or '0em 0.25em', '">\n', args['list' .. listnum], '</div></td></tr>')
end
end


function p._navbox(args)
function p._navbox(navboxArgs)
    for k, v in pairs(args) do
args = navboxArgs
        local listnum = ('' .. k):match('^list(%d+)$')
local listnums = {}
        if listnum then table.insert(listnums, tonumber(listnum)) end
 
    end
for k, _ in pairs(args) do
    table.sort(listnums)
if type(k) == 'string' then
   
local listnum = k:match(cfg.pattern.listnum)
    border = trim(args.border or args[1] or '')
if listnum then table.insert(listnums, tonumber(listnum)) end
    if border == 'subgroup' or border == 'child' then
end
        add('</div>')
end
    elseif border ~= 'none' then
table.sort(listnums)
        add('<table cellspacing="0" class="navbox" style="border-spacing:0;', args.bodystyle, ';', args.style, '"><tr><td style="padding:2px;">')
 
    end
local border = mw.text.trim(args[cfg.arg.border] or args[1] or '')
   
if border == cfg.keyword.border_child then
    add('<table cellspacing="0" class="nowraplinks ', args.bodyclass, ' ')
border = cfg.keyword.border_subgroup
   
end
    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
-- render the main body of the navbox
    for i, listnum in ipairs(listnums) do
local tbl = renderMainTable(border, listnums)
        if listnum > 1 then
            renderNthListRow(args, listnum)
        end
    end


    renderBelowRow(args)
local res = mw.html.create()
-- render the appropriate wrapper for the navbox, based on the border param


    add('</table>')
if border == cfg.keyword.border_none then
   
res:node(add_navbox_styles())
    if border == 'subgroup' or border == 'child' then
local nav = res:tag('div')
        add('<div>')
:attr('role', 'navigation')
    elseif border ~= 'none' then
:node(tbl)
        add('</td></tr></table>')
-- aria-labelledby title, otherwise above, otherwise lone group
    end
if args[cfg.arg.title] or args[cfg.arg.above] or (args[cfg.arg.group1]
and not args[cfg.arg.group2]) then
nav:attr(
'aria-labelledby',
mw.uri.anchorEncode(
args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group1]
)
)
else
nav:attr('aria-label', cfg.aria_label)
end
elseif border == cfg.keyword.border_subgroup 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
:wikitext('</div>')
:node(tbl)
:wikitext('<div>')
else
res:node(add_navbox_styles())
local nav = res:tag('div')
:attr('role', 'navigation')
:addClass(cfg.class.navbox)
:addClass(args[cfg.arg.navboxclass])
:cssText(args[cfg.arg.bodystyle])
:cssText(args[cfg.arg.style])
:css('padding', '3px')
:node(tbl)
-- aria-labelledby title, otherwise above, otherwise lone group
if args[cfg.arg.title] or args[cfg.arg.above]
or (args[cfg.arg.group1] and not args[cfg.arg.group2]) then
nav:attr(
'aria-labelledby',
mw.uri.anchorEncode(args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group1])
)
else
nav:attr('aria-label', cfg.aria_label)
end
end


    -- TODO: add tracking categories
if (args[cfg.arg.nocat] or cfg.keyword.nocat_false):lower() == cfg.keyword.nocat_false then
   
renderTrackingCategories(res, border)
    return table.concat(ret, '')
end
return striped(tostring(res), border)
end
end


function p.navbox(frame)
function p.navbox(frame)
    return p._navbox(frame:getParent().args)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
args = getArgs(frame, {wrappers = {cfg.pattern.navbox}})
 
-- Read the arguments in the order they'll be output in, to make references
-- number in the right order.
local _
_ = args[cfg.arg.title]
_ = args[cfg.arg.above]
-- Limit this to 20 as covering 'most' cases (that's a SWAG) and because
-- iterator approach won't work here
for i = 1, 20 do
_ = args[format(cfg.arg.group_and_num, i)]
_ = args[format(cfg.arg.list_and_num, i)]
end
_ = args[cfg.arg.below]
 
return p._navbox(args)
end
end


return p
return p

2021년 11월 27일 (토) 09:04 기준 최신판

이 모듈에 대한 설명문서는 모듈:Navbox/설명문서에서 만들 수 있습니다

local p = {}
local navbar = require('Module:Navbar')._navbar
local cfg = mw.loadData('Module:Navbox/configuration')
local getArgs -- lazily initialized
local args
local format = string.format

local function striped(wikitext, border)
	-- Return wikitext with markers replaced for odd/even striping.
	-- Child (subgroup) navboxes are flagged with a category that is removed
	-- by parent navboxes. The result is that the category shows all pages
	-- where a child navbox is not contained in a parent navbox.
	local orphanCat = cfg.category.orphan
	if border == cfg.keyword.border_subgroup and args[cfg.arg.orphan] ~= cfg.keyword.orphan_yes then
		-- No change; striping occurs in outermost navbox.
		return wikitext .. orphanCat
	end
	local first, second = cfg.class.navbox_odd_part, cfg.class.navbox_even_part
	if args[cfg.arg.evenodd] then
		if args[cfg.arg.evenodd] == cfg.keyword.evenodd_swap then
			first, second = second, first
		else
			first = args[cfg.arg.evenodd]
			second = first
		end
	end
	local changer
	if first == second then
		changer = first
	else
		local index = 0
		changer = function (code)
			if code == '0' then
				-- Current occurrence is for a group before a nested table.
				-- Set it to first as a valid although pointless class.
				-- The next occurrence will be the first row after a title
				-- in a subgroup and will also be first.
				index = 0
				return first
			end
			index = index + 1
			return index % 2 == 1 and first or second
		end
	end
	local regex = orphanCat:gsub('([%[%]])', '%%%1')
	return (wikitext:gsub(regex, ''):gsub(cfg.marker.regex, changer)) -- () omits gsub count
end

local function processItem(item, nowrapitems)
	if item:sub(1, 2) == '{|' then
		-- Applying nowrap to lines in a table does not make sense.
		-- Add newlines to compensate for trim of x in |parm=x in a template.
		return '\n' .. item ..'\n'
	end
	if nowrapitems == cfg.keyword.nowrapitems_yes then
		local lines = {}
		for line in (item .. '\n'):gmatch('([^\n]*)\n') do
			local prefix, content = line:match('^([*:;#]+)%s*(.*)')
			if prefix and not content:match(cfg.pattern.nowrap) then
				line = format(cfg.nowrap_item, prefix, content)
			end
			table.insert(lines, line)
		end
		item = table.concat(lines, '\n')
	end
	if item:match('^[*:;#]') then
		return '\n' .. item ..'\n'
	end
	return item
end

-- we will want this later when we want to add tstyles for hlist/plainlist
local function has_navbar()
	return args[cfg.arg.navbar] ~= cfg.keyword.navbar_off
		and args[cfg.arg.navbar] ~= cfg.keyword.navbar_plain
		and (
			args[cfg.arg.name]
			or mw.getCurrentFrame():getParent():getTitle():gsub(cfg.pattern.sandbox, '')
				~= cfg.pattern.navbox
		)
end

local function renderNavBar(titleCell)
	if has_navbar() then
		titleCell:wikitext(navbar{
			[cfg.navbar.name] = args[cfg.arg.name],
			[cfg.navbar.mini] = 1,
			[cfg.navbar.fontstyle] = (args[cfg.arg.basestyle] or '') .. ';' ..
				(args[cfg.arg.titlestyle] or '') ..
				';background:none transparent;border:none;box-shadow:none;padding:0;'
		})
	end

end

local function renderTitleRow(tbl)
	if not args[cfg.arg.title] then return end

	local titleRow = tbl:tag('tr')

	if args[cfg.arg.titlegroup] then
		titleRow
			:tag('th')
				:attr('scope', 'row')
				:addClass(cfg.class.navbox_group)
				:addClass(args[cfg.arg.titlegroupclass])
				:cssText(args[cfg.arg.basestyle])
				:cssText(args[cfg.arg.groupstyle])
				:cssText(args[cfg.arg.titlegroupstyle])
				:wikitext(args[cfg.arg.titlegroup])
	end

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

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

	local titleColspan = 2
	if args[cfg.arg.imageleft] then titleColspan = titleColspan + 1 end
	if args[cfg.arg.image] then titleColspan = titleColspan + 1 end
	if args[cfg.arg.titlegroup] then titleColspan = titleColspan - 1 end

	titleCell
		:cssText(args[cfg.arg.basestyle])
		:cssText(args[cfg.arg.titlestyle])
		:addClass(cfg.class.navbox_title)
		:attr('colspan', titleColspan)

	renderNavBar(titleCell)

	titleCell
		:tag('div')
			-- id for aria-labelledby attribute
			:attr('id', mw.uri.anchorEncode(args[cfg.arg.title]))
			:addClass(args[cfg.arg.titleclass])
			:css('font-size', '114%')
			:css('margin', '0 4em')
			:wikitext(processItem(args[cfg.arg.title]))
end

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

local function renderAboveRow(tbl)
	if not args[cfg.arg.above] then return end

	tbl:tag('tr')
		:tag('td')
			:addClass(cfg.class.navbox_abovebelow)
			:addClass(args[cfg.arg.aboveclass])
			:cssText(args[cfg.arg.basestyle])
			:cssText(args[cfg.arg.abovestyle])
			:attr('colspan', getAboveBelowColspan())
			:tag('div')
				-- id for aria-labelledby attribute, if no title
				:attr('id', args[cfg.arg.title] and nil or mw.uri.anchorEncode(args[cfg.arg.above]))
				:wikitext(processItem(args[cfg.arg.above], args[cfg.arg.nowrapitems]))
end

local function renderBelowRow(tbl)
	if not args[cfg.arg.below] then return end

	tbl:tag('tr')
		:tag('td')
			:addClass(cfg.class.navbox_abovebelow)
			:addClass(args[cfg.arg.belowclass])
			:cssText(args[cfg.arg.basestyle])
			:cssText(args[cfg.arg.belowstyle])
			:attr('colspan', getAboveBelowColspan())
			:tag('div')
				:wikitext(processItem(args[cfg.arg.below], args[cfg.arg.nowrapitems]))
end

local function renderListRow(tbl, index, listnum, listnums_size)
	local row = tbl:tag('tr')

	if index == 1 and args[cfg.arg.imageleft] then
		row
			:tag('td')
				:addClass(cfg.class.noviewer)
				:addClass(cfg.class.navbox_image)
				:addClass(args[cfg.arg.imageclass])
				:css('width', '1px')               -- Minimize width
				:css('padding', '0 2px 0 0')
				:cssText(args[cfg.arg.imageleftstyle])
				:attr('rowspan', listnums_size)
				:tag('div')
					:wikitext(processItem(args[cfg.arg.imageleft]))
	end

	local group_and_num = format(cfg.arg.group_and_num, listnum)
	local groupstyle_and_num = format(cfg.arg.groupstyle_and_num, listnum)
	if args[group_and_num] then
		local groupCell = row:tag('th')

		-- id for aria-labelledby attribute, if lone group with no title or above
		if listnum == 1 and not (args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group2]) then
			groupCell
				:attr('id', mw.uri.anchorEncode(args[cfg.arg.group1]))
		end

		groupCell
			:attr('scope', 'row')
			:addClass(cfg.class.navbox_group)
			:addClass(args[cfg.arg.groupclass])
			:cssText(args[cfg.arg.basestyle])
			-- If groupwidth not specified, minimize width
			:css('width', args[cfg.arg.groupwidth] or '1%')

		groupCell
			:cssText(args[cfg.arg.groupstyle])
			:cssText(args[groupstyle_and_num])
			:wikitext(args[group_and_num])
	end

	local listCell = row:tag('td')

	if args[group_and_num] then
		listCell
			:addClass(cfg.class.navbox_list_with_group)
	else
		listCell:attr('colspan', 2)
	end

	if not args[cfg.arg.groupwidth] then
		listCell:css('width', '100%')
	end

	local rowstyle  -- usually nil so cssText(rowstyle) usually adds nothing
	if index % 2 == 1 then
		rowstyle = args[cfg.arg.oddstyle]
	else
		rowstyle = args[cfg.arg.evenstyle]
	end

	local list_and_num = format(cfg.arg.list_and_num, listnum)
	local listText = args[list_and_num]
	local oddEven = cfg.marker.oddeven
	if listText:sub(1, 12) == '</div><table' then
		-- Assume list text is for a subgroup navbox so no automatic striping for this row.
		oddEven = listText:find(cfg.pattern.navbox_title) and cfg.marker.restart or cfg.class.navbox_odd_part
	end

	local liststyle_and_num = format(cfg.arg.liststyle_and_num, listnum)
	local listclass_and_num = format(cfg.arg.listclass_and_num, listnum)
	listCell
		:css('padding', '0')
		:cssText(args[cfg.arg.liststyle])
		:cssText(rowstyle)
		:cssText(args[liststyle_and_num])
		:addClass(cfg.class.navbox_list)
		:addClass(cfg.class.navbox_part .. oddEven)
		:addClass(args[cfg.arg.listclass])
		:addClass(args[listclass_and_num])
		:tag('div')
			:css('padding',
				(index == 1 and args[cfg.arg.list1padding]) or args[cfg.arg.listpadding] or '0 0.25em'
			)
			:wikitext(processItem(listText, args[cfg.arg.nowrapitems]))

	if index == 1 and args[cfg.arg.image] then
		row
			:tag('td')
				:addClass(cfg.class.noviewer)
				:addClass(cfg.class.navbox_image)
				:addClass(args[cfg.arg.imageclass])
				:css('width', '1px')               -- Minimize width
				:css('padding', '0 0 0 2px')
				:cssText(args[cfg.arg.imagestyle])
				:attr('rowspan', listnums_size)
				:tag('div')
					:wikitext(processItem(args[cfg.arg.image]))
	end
end

-- uses this now to make the needHlistCategory correct
-- to use later for when we add list styles via navbox
local function has_list_class(htmlclass)
	local class_args = { -- rough order of probability of use
		cfg.arg.bodyclass, cfg.arg.listclass, cfg.arg.aboveclass,
		cfg.arg.belowclass, cfg.arg.titleclass, cfg.arg.navboxclass,
		cfg.arg.groupclass, cfg.arg.titlegroupclass, cfg.arg.imageclass
	}
	local patterns = {
		'^' .. htmlclass .. '$',
		'%s' .. htmlclass .. '$',
		'^' .. htmlclass .. '%s',
		'%s' .. htmlclass .. '%s'
	}
	
	for _, arg in ipairs(class_args) do
		for _, pattern in ipairs(patterns) do
			if mw.ustring.find(args[arg] or '', pattern) then
				return true
			end
		end
	end
	return false
end

local function needsHorizontalLists(border)
	if border == cfg.keyword.border_subgroup or args[cfg.arg.tracking] == cfg.keyword.tracking_no then
		return false
	end
	return not has_list_class(cfg.pattern.hlist) and not has_list_class(cfg.pattern.plainlist)
end

local function hasBackgroundColors()
	for _, key in ipairs({cfg.arg.titlestyle, cfg.arg.groupstyle,
		cfg.arg.basestyle, cfg.arg.abovestyle, cfg.arg.belowstyle}) do
		if tostring(args[key]):find('background', 1, true) then
			return true
		end
	end
	return false
end

local function hasTitleGroup()
	if args[cfg.arg.titlegroup] and args[cfg.arg.titlegroup] ~= '' then
		return true
	end
	return false
end

local function hasBorders()
	for _, key in ipairs({cfg.arg.groupstyle, cfg.arg.basestyle,
		cfg.arg.abovestyle, cfg.arg.belowstyle}) do
		if tostring(args[key]):find('border', 1, true) then
			return true
		end
	end
	return false
end

local function isIllegible()
	local styleratio = require('Module:Color contrast')._styleratio
	for key, style in pairs(args) do
		if tostring(key):match(cfg.pattern.style) then
			if styleratio{mw.text.unstripNoWiki(style)} < 4.5 then
				return true
			end
		end
	end
	return false
end

local function getTrackingCategories(border)
	local cats = {}
	if needsHorizontalLists(border) then table.insert(cats, cfg.category.horizontal_lists) end
	if hasBackgroundColors() then table.insert(cats, cfg.category.background_colors) end
	if isIllegible() then table.insert(cats, cfg.category.illegible) end
	if hasBorders() then table.insert(cats, cfg.category.borders) end
	if hasTitleGroup() then table.insert(cats, cfg.category.titlegroup) end
	return cats
end

local function renderTrackingCategories(builder, border)
	local title = mw.title.getCurrentTitle()
	if title.namespace ~= 10 then return end -- not in template space
	local subpage = title.subpageText
	if subpage == cfg.keyword.subpage_doc or subpage == cfg.keyword.subpage_sandbox
		or subpage == cfg.keyword.subpage_testcases then return end

	for _, cat in ipairs(getTrackingCategories(border)) do
		builder:wikitext('[[Category:' .. cat .. ']]')
	end
end

local function renderMainTable(border, listnums)
	local tbl = mw.html.create('table')
		:addClass(cfg.class.nowraplinks)
		:addClass(args[cfg.arg.bodyclass])

	local state = args[cfg.arg.state]
	if args[cfg.arg.title] and state ~= cfg.keyword.state_plain and state ~= cfg.keyword.state_off then
		if state == cfg.keyword.state_collapsed then
			state = cfg.class.collapsed
		end
		tbl
			:addClass(cfg.class.collapsible)
			:addClass(state or cfg.class.autocollapse)
	end

	tbl:css('border-spacing', 0)
	if border == cfg.keyword.border_subgroup or border == cfg.keyword.border_none then
		tbl
			:addClass(cfg.class.navbox_subgroup)
			:cssText(args[cfg.arg.bodystyle])
			:cssText(args[cfg.arg.style])
	else  -- regular navbox - bodystyle and style will be applied to the wrapper table
		tbl
			:addClass(cfg.class.navbox_inner)
			:css('background', 'transparent')
			:css('color', 'inherit')
	end
	tbl:cssText(args[cfg.arg.innerstyle])

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

	return tbl
end

local function add_navbox_styles()
	local frame = mw.getCurrentFrame()
	-- This is a lambda so that it doesn't need the frame as a parameter
	local function add_user_styles(templatestyles)
		if templatestyles and templatestyles ~= '' then
			return frame:extensionTag{
				name = 'templatestyles', args = { src = templatestyles }
			}
		end
		return ''
	end

	-- get templatestyles. load base from config so that Lua only needs to do
	-- the work once of parser tag expansion
	local base_templatestyles = cfg.templatestyles
	local templatestyles = add_user_styles(args[cfg.arg.templatestyles])
	local child_templatestyles = add_user_styles(args[cfg.arg.child_templatestyles])

	-- The 'navbox-styles' div exists for two reasons:
	--  1. To wrap the styles to work around T200206 more elegantly. Instead
	--     of combinatorial rules, this ends up being linear number of CSS rules.
	--  2. To allow MobileFrontend to rip the styles out with 'nomobile' such that
	--     they are not dumped into the mobile view.
	return mw.html.create('div')
		:addClass(cfg.class.navbox_styles)
		:addClass(cfg.class.nomobile)
		:wikitext(base_templatestyles .. templatestyles .. child_templatestyles)
		:done()
end

function p._navbox(navboxArgs)
	args = navboxArgs
	local listnums = {}

	for k, _ in pairs(args) do
		if type(k) == 'string' then
			local listnum = k:match(cfg.pattern.listnum)
			if listnum then table.insert(listnums, tonumber(listnum)) end
		end
	end
	table.sort(listnums)

	local border = mw.text.trim(args[cfg.arg.border] or args[1] or '')
	if border == cfg.keyword.border_child then
		border = cfg.keyword.border_subgroup
	end

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

	local res = mw.html.create()
	-- render the appropriate wrapper for the navbox, based on the border param

	if border == cfg.keyword.border_none then
		res:node(add_navbox_styles())
		local nav = res:tag('div')
			:attr('role', 'navigation')
			:node(tbl)
		-- aria-labelledby title, otherwise above, otherwise lone group
		if args[cfg.arg.title] or args[cfg.arg.above] or (args[cfg.arg.group1]
			and not args[cfg.arg.group2]) then
			nav:attr(
				'aria-labelledby',
				mw.uri.anchorEncode(
					args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group1]
				)
			)
		else
			nav:attr('aria-label', cfg.aria_label)
		end
	elseif border == cfg.keyword.border_subgroup 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
			:wikitext('</div>')
			:node(tbl)
			:wikitext('<div>')
	else
		res:node(add_navbox_styles())
		local nav = res:tag('div')
			:attr('role', 'navigation')
			:addClass(cfg.class.navbox)
			:addClass(args[cfg.arg.navboxclass])
			:cssText(args[cfg.arg.bodystyle])
			:cssText(args[cfg.arg.style])
			:css('padding', '3px')
			:node(tbl)
		-- aria-labelledby title, otherwise above, otherwise lone group
		if args[cfg.arg.title] or args[cfg.arg.above]
			or (args[cfg.arg.group1] and not args[cfg.arg.group2]) then
			nav:attr(
				'aria-labelledby',
				mw.uri.anchorEncode(args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group1])
			)
		else
			nav:attr('aria-label', cfg.aria_label)
		end
	end

	if (args[cfg.arg.nocat] or cfg.keyword.nocat_false):lower() == cfg.keyword.nocat_false then
		renderTrackingCategories(res, border)
	end
	return striped(tostring(res), border)
end

function p.navbox(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	args = getArgs(frame, {wrappers = {cfg.pattern.navbox}})

	-- Read the arguments in the order they'll be output in, to make references
	-- number in the right order.
	local _
	_ = args[cfg.arg.title]
	_ = args[cfg.arg.above]
	-- Limit this to 20 as covering 'most' cases (that's a SWAG) and because
	-- iterator approach won't work here
	for i = 1, 20 do
		_ = args[format(cfg.arg.group_and_num, i)]
		_ = args[format(cfg.arg.list_and_num, i)]
	end
	_ = args[cfg.arg.below]

	return p._navbox(args)
end

return p

최근 바뀜

더 보기