模块:Navbox:修订间差异
小无编辑摘要 |
小无编辑摘要 |
||
| 第5行: | 第5行: | ||
local p = {} | local p = {} | ||
local getArgs -- lazily initialized | local getArgs -- lazily initialized | ||
| 第14行: | 第13行: | ||
local RESTART_MARKER = '\127_ODDEVEN0_\127' | local RESTART_MARKER = '\127_ODDEVEN0_\127' | ||
local REGEX_MARKER = '\127_ODDEVEN(%d?)_\127' | local REGEX_MARKER = '\127_ODDEVEN(%d?)_\127' | ||
local lists = { | |||
plainlist_t = { | |||
patterns = { | |||
'^plainlist$', | |||
'%splainlist$', | |||
'^plainlist%s', | |||
'%splainlist%s' | |||
}, | |||
found = false, | |||
styles = 'Plainlist/styles.css' | |||
}, | |||
hlist_t = { | |||
patterns = { | |||
'^hlist$', | |||
'%shlist$', | |||
'^hlist%s', | |||
'%shlist%s' | |||
}, | |||
found = false, | |||
styles = 'Hlist/styles.css' | |||
} | |||
} | |||
local function has_list_class(args_to_check) | |||
for _, list in pairs(lists) do | |||
if not list.found then | |||
for _, arg in pairs(args_to_check) do | |||
for _, pattern in ipairs(list.patterns) do | |||
if mw.ustring.find(arg or '', pattern) then | |||
list.found = true | |||
break | |||
end | |||
end | |||
if list.found then break end | |||
end | |||
end | |||
end | |||
end | |||
local function striped(wikitext) | local function striped(wikitext) | ||
| 第20行: | 第58行: | ||
-- by parent navboxes. The result is that the category shows all pages | -- by parent navboxes. The result is that the category shows all pages | ||
-- where a child navbox is not contained in a parent navbox. | -- where a child navbox is not contained in a parent navbox. | ||
local orphanCat = '[[Category: | local orphanCat = '[[Category:孤立的子导航框]]' | ||
if border == 'subgroup' and args.orphan ~= 'yes' then | if border == 'subgroup' and args.orphan ~= 'yes' then | ||
-- No change; striping occurs in outermost navbox. | -- No change; striping occurs in outermost navbox. | ||
| 第56行: | 第94行: | ||
end | end | ||
local function | local function addNewline(s) | ||
if | if s:match('^[*:;#]') or s:match('^{|') then | ||
return '\n' .. s ..'\n' | |||
else | |||
return '\n' .. | return s | ||
end | end | ||
end | |||
local function has_collapsible_toggle() | |||
return args.state ~= 'off' | |||
and args.state ~= 'plain' | |||
end | |||
local function has_navbar() | |||
return args.navbar ~= 'off' | |||
and args.navbar ~= 'plain' | |||
and ( | |||
args.name | |||
or ( | |||
mw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$', '') | |||
~= 'Template:Navbox' and | |||
mw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$', '') | |||
~= 'Template:Navbox subgroup' | |||
) | |||
) | |||
end | |||
-- extract text color from css, which is the only permitted inline CSS for the navbar | |||
local function extract_color(css_str) | |||
-- return nil because navbar takes its argument into mw.html which handles | |||
-- nil gracefully, removing the associated style attribute | |||
return mw.ustring.match(';' .. css_str .. ';', '.*;%s*([Cc][Oo][Ll][Oo][Rr]%s*:%s*.-)%s*;') or nil | |||
end | end | ||
local function renderNavBar(titleCell) | local function renderNavBar(titleCell) | ||
if | if has_navbar() then | ||
local navbar = require('Module:Navbar')._navbar | |||
titleCell:wikitext(navbar{ | titleCell:wikitext(navbar{ | ||
args.name, | args.name, | ||
mini = 1, | mini = 1, | ||
fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') | fontstyle = extract_color( | ||
(args.basestyle or '') .. ';' .. (args.titlestyle or '') | |||
) | |||
}) | }) | ||
end | end | ||
| 第96行: | 第148行: | ||
local function renderTitleRow(tbl) | local function renderTitleRow(tbl) | ||
if not args.title then return end | if not args.title then return end | ||
has_list_class({args.titleclass}) | |||
local titleRow = tbl:tag('tr') | local titleRow = tbl:tag('tr') | ||
local titleCell = titleRow:tag('th'):attr('scope', 'col') | local titleCell = titleRow:tag('th'):attr('scope', 'col') | ||
if | if has_collapsible_toggle() then | ||
titleCell | titleCell | ||
: | :addClass('collapsible-title') | ||
end | end | ||
| 第122行: | 第163行: | ||
if args.imageleft then titleColspan = titleColspan + 1 end | if args.imageleft then titleColspan = titleColspan + 1 end | ||
if args.image then titleColspan = titleColspan + 1 end | if args.image then titleColspan = titleColspan + 1 end | ||
titleCell | titleCell | ||
| 第137行: | 第177行: | ||
:attr('id', mw.uri.anchorEncode(args.title)) | :attr('id', mw.uri.anchorEncode(args.title)) | ||
:addClass(args.titleclass) | :addClass(args.titleclass) | ||
:css('font-size', ' | :css('font-size', '110%') | ||
:css('margin', '0 | :css('margin', '0 5em') | ||
:wikitext( | :wikitext(addNewline(args.title)) | ||
end | end | ||
| 第155行: | 第195行: | ||
local function renderAboveRow(tbl) | local function renderAboveRow(tbl) | ||
if not args.above then return end | if not args.above then return end | ||
has_list_class({ args.aboveclass }) | |||
tbl:tag('tr') | tbl:tag('tr') | ||
| 第165行: | 第207行: | ||
:tag('div') | :tag('div') | ||
-- id for aria-labelledby attribute, if no title | -- id for aria-labelledby attribute, if no title | ||
:attr('id', args.title and | :attr('id', (not args.title) and mw.uri.anchorEncode(args.above) or nil) | ||
:wikitext( | :wikitext(addNewline(args.above)) | ||
end | end | ||
local function renderBelowRow(tbl) | local function renderBelowRow(tbl) | ||
if not args.below then return end | if not args.below then return end | ||
has_list_class({ args.belowclass }) | |||
tbl:tag('tr') | tbl:tag('tr') | ||
| 第180行: | 第224行: | ||
:attr('colspan', getAboveBelowColspan()) | :attr('colspan', getAboveBelowColspan()) | ||
:tag('div') | :tag('div') | ||
:wikitext( | :wikitext(addNewline(args.below)) | ||
end | end | ||
| 第186行: | 第230行: | ||
-- List rows | -- List rows | ||
-- | -- | ||
local function renderListRow(tbl | local function renderListRow(tbl, listnum) | ||
local row = tbl:tag('tr') | local row = tbl:tag('tr') | ||
if | if listnum == 1 and args.imageleft then | ||
has_list_class({ args.imageclass }) | |||
row | row | ||
:tag('td') | :tag('td') | ||
| 第200行: | 第246行: | ||
:attr('rowspan', #listnums) | :attr('rowspan', #listnums) | ||
:tag('div') | :tag('div') | ||
:wikitext( | :wikitext(addNewline(args.imageleft)) | ||
end | end | ||
if args['group' .. listnum] then | if args['group' .. listnum] then | ||
has_list_class({ args.groupclass }) | |||
local groupCell = row:tag('th') | local groupCell = row:tag('th') | ||
| 第224行: | 第272行: | ||
:wikitext(args['group' .. listnum]) | :wikitext(args['group' .. listnum]) | ||
end | end | ||
has_list_class({ args.listclass, args['list' .. listnum .. 'class'] }) | |||
local listCell = row:tag('td') | local listCell = row:tag('td') | ||
| 第229行: | 第279行: | ||
if args['group' .. listnum] then | if args['group' .. listnum] then | ||
listCell | listCell | ||
: | :addClass('navbox-list-with-group') | ||
else | else | ||
listCell:attr('colspan', 2) | listCell:attr('colspan', 2) | ||
| 第241行: | 第289行: | ||
local rowstyle -- usually nil so cssText(rowstyle) usually adds nothing | local rowstyle -- usually nil so cssText(rowstyle) usually adds nothing | ||
if | if listnum % 2 == 1 then | ||
rowstyle = args.oddstyle | rowstyle = args.oddstyle | ||
else | else | ||
| 第251行: | 第299行: | ||
if listText:sub(1, 12) == '</div><table' then | if listText:sub(1, 12) == '</div><table' then | ||
-- Assume list text is for a subgroup navbox so no automatic striping for this row. | -- Assume list text is for a subgroup navbox so no automatic striping for this row. | ||
oddEven = listText:find('<th[^>]*"navbox%-title"') and RESTART_MARKER or 'odd' | oddEven = listText:find('<th[^>]*["? ?]navbox%-title"') and RESTART_MARKER or 'odd' | ||
end | end | ||
listCell | listCell | ||
| 第263行: | 第311行: | ||
:addClass(args['list' .. listnum .. 'class']) | :addClass(args['list' .. listnum .. 'class']) | ||
:tag('div') | :tag('div') | ||
:css('padding', ( | :css('padding', (listnum == 1 and args.list1padding) or args.listpadding or '0em 0.25em') | ||
:wikitext( | :wikitext(addNewline(listText)) | ||
if listnum == 1 and args.image then | |||
has_list_class({ args.imageclass }) | |||
row | row | ||
:tag('td') | :tag('td') | ||
| 第277行: | 第327行: | ||
:attr('rowspan', #listnums) | :attr('rowspan', #listnums) | ||
:tag('div') | :tag('div') | ||
:wikitext( | :wikitext(addNewline(args.image)) | ||
end | end | ||
end | end | ||
-- | -- | ||
| 第290行: | 第339行: | ||
return false | return false | ||
end | end | ||
return not lists.hlist_t.found and not lists.plainlist_t.found | |||
return not | |||
end | end | ||
| 第306行: | 第351行: | ||
end | end | ||
local function | local function argNameAndRealTitleAreDifferent() | ||
if border == 'subgroup' or args.tracking == 'no' then | |||
return false | |||
end | end | ||
if has_navbar() and args.name ~= mw.title.getCurrentTitle().text then | |||
return true | |||
end | |||
return false | return false | ||
end | end | ||
| 第329行: | 第365行: | ||
local function getTrackingCategories() | local function getTrackingCategories() | ||
local cats = {} | local cats = {} | ||
if needsHorizontalLists() then table.insert(cats, ' | if needsHorizontalLists() then table.insert(cats, '没有使用水平列表的导航框') end | ||
if hasBackgroundColors() then table.insert(cats, ' | if hasBackgroundColors() then table.insert(cats, '使用背景颜色的导航框') end | ||
if | if argNameAndRealTitleAreDifferent() then table.insert(cats, 'name參數和實際不同的導航框') end | ||
return cats | return cats | ||
end | end | ||
| 第345行: | 第380行: | ||
builder:wikitext('[[Category:' .. cat .. ']]') | builder:wikitext('[[Category:' .. cat .. ']]') | ||
end | end | ||
end | |||
-- | |||
-- Load the templatestyles for the navbox | |||
-- | |||
local function loadTemplateStyles(hiding_templatestyles) | |||
local frame = mw.getCurrentFrame() | |||
local hlist_templatestyles = '' | |||
if lists.hlist_t.found then | |||
hlist_templatestyles = frame:extensionTag{ | |||
name = 'templatestyles', args = { src = lists.hlist_t.styles } | |||
} | |||
end | |||
-- a second workaround for [[phab:T303378]] | |||
-- when that issue is fixed, we can actually use has_navbar not to emit the | |||
-- tag here if we want | |||
if has_navbar() and hlist_templatestyles == '' then | |||
hlist_templatestyles = frame:extensionTag{ | |||
name = 'templatestyles', args = { src = lists.hlist_t.styles } | |||
} | |||
end | |||
local plainlist_templatestyles = '' | |||
if lists.plainlist_t.found then | |||
plainlist_templatestyles = frame:extensionTag{ | |||
name = 'templatestyles', args = { src = lists.plainlist_t.styles } | |||
} | |||
end | |||
local base_templatestyles = frame:extensionTag{ | |||
name = 'templatestyles', args = { src = 'Module:Navbox/styles.css' } | |||
} | |||
local templatestyles = '' | |||
if args['templatestyles'] then | |||
templatestyles = frame:extensionTag{ | |||
name = 'templatestyles', args = { src = args['templatestyles'] } | |||
} | |||
end | |||
local child_templatestyles = '' | |||
if args['child templatestyles'] then | |||
child_templatestyles = frame:extensionTag{ | |||
name = 'templatestyles', args = { src = args['child templatestyles'] } | |||
} | |||
end | |||
return mw.html.create('div') | |||
:addClass('navbox-styles') | |||
:wikitext( | |||
-- hlist -> plainlist -> base is best-effort to preserve old Common.css ordering. | |||
-- this ordering is not a guarantee because the rows of interest invoking | |||
-- each class may not be on a specific page | |||
hlist_templatestyles .. | |||
plainlist_templatestyles .. | |||
base_templatestyles .. | |||
templatestyles .. | |||
child_templatestyles .. | |||
table.concat(hiding_templatestyles) | |||
) | |||
:done() | |||
end | |||
-- work around [[phab:T303378]] | |||
-- for each arg: find all the templatestyles strip markers, insert them into a | |||
-- table. then remove all templatestyles markers from the arg | |||
local function move_hiding_templatestyles(args) | |||
local gfind = string.gfind | |||
local gsub = string.gsub | |||
local templatestyles_markers = {} | |||
local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)' | |||
for k, arg in pairs(args) do | |||
for marker in gfind(arg, strip_marker_pattern) do | |||
table.insert(templatestyles_markers, marker) | |||
end | |||
args[k] = gsub(arg, strip_marker_pattern, '') | |||
end | |||
return templatestyles_markers | |||
end | end | ||
| 第355行: | 第470行: | ||
:addClass(args.bodyclass) | :addClass(args.bodyclass) | ||
if args.title and ( | has_list_class({ args.bodyclass }) | ||
if args.title and has_collapsible_toggle() then | |||
if args.state == 'collapsed' then args.state = 'mw-collapsed' end | if args.state == 'collapsed' then args.state = 'mw-collapsed' end | ||
tbl | tbl | ||
| 第379行: | 第496行: | ||
renderAboveRow(tbl) | renderAboveRow(tbl) | ||
for i, listnum in ipairs(listnums) do | for i, listnum in ipairs(listnums) do | ||
renderListRow(tbl | renderListRow(tbl, listnum) | ||
end | end | ||
renderBelowRow(tbl) | renderBelowRow(tbl) | ||
| 第388行: | 第505行: | ||
function p._navbox(navboxArgs) | function p._navbox(navboxArgs) | ||
args = navboxArgs | args = navboxArgs | ||
local hiding_templatestyles = move_hiding_templatestyles(args) | |||
listnums = {} | listnums = {} | ||
for k, | for k, v in pairs(args) do | ||
local listnum = ('' .. k):match('^list(%d+)$') | |||
if listnum then table.insert(listnums, tonumber(listnum)) end | |||
end | end | ||
table.sort(listnums) | table.sort(listnums) | ||
| 第409行: | 第525行: | ||
local res = mw.html.create() | local res = mw.html.create() | ||
if border == 'none' then | if border == 'none' then | ||
res:node(loadTemplateStyles(hiding_templatestyles)) | |||
local nav = res:tag('div') | local nav = res:tag('div') | ||
:attr('role', 'navigation') | :attr('role', 'navigation') | ||
| 第423行: | 第540行: | ||
-- 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>') | :wikitext('</div>') -- mw.html 未支持 unclosed | ||
:node(tbl) | :node(tbl) | ||
:wikitext('<div>') | :wikitext('<div>') -- mw.html 未支持 unclosed | ||
else | else | ||
res:node(loadTemplateStyles(hiding_templatestyles)) | |||
has_list_class({ args.navboxclass }) | |||
local nav = res:tag('div') | local nav = res:tag('div') | ||
:attr('role', 'navigation') | :attr('role', 'navigation') | ||
| 第453行: | 第574行: | ||
getArgs = require('Module:Arguments').getArgs | getArgs = require('Module:Arguments').getArgs | ||
end | end | ||
args = getArgs(frame, {wrappers = {'Template:Navbox'}}) | args = getArgs(frame, {wrappers = {'Template:Navbox', 'Template:Navbox subgroup'}}) | ||
if frame.args.border then | |||
-- This allows Template:Navbox_subgroup to use {{#invoke:Navbox|navbox|border=...}}. | |||
args.border = frame.args.border | |||
end | |||
-- Read the arguments in the order they'll be output in, to make references number in the right order. | -- Read the arguments in the order they'll be output in, to make references number in the right order. | ||
| 第459行: | 第584行: | ||
_ = args.title | _ = args.title | ||
_ = args.above | _ = args.above | ||
for i = 1, | for i = 1, 35 do | ||
_ = args["group" .. tostring(i)] | _ = args["group" .. tostring(i)] | ||
_ = args["list" .. tostring(i)] | _ = args["list" .. tostring(i)] | ||