Module:Message box:修订间差异
外观
删除的内容 添加的内容
移植求闻版 Message box 模块(flex div 结构);修复 getConfig 报错分支引用未定义 dataTables、export 中 nsid 字符串比较两处 bug |
融合重构:工程组织取 mw.org 版(strict/常量表/类/方法拆分),行为对齐求闻版(div 输出、dmbox、中文、干支)——输出与 rev 71078 等价,配置/模板/样式不动 |
||
| (未显示同一用户的1个中间版本) | |||
| 第1行: | 第1行: | ||
-- 融合版 Module:Message box |
|||
-- This is a meta-module for producing message box templates, including {{mbox}}, {{ambox}}, {{tmbox}}, {{ombox}} and {{fmbox}}. |
|||
-- 工程组织:mediawiki.org 版风格(require('strict')、常量表、辅助函数、类方法拆分、命名规范) |
|||
-- 行为基准:求闻版(rev 71078)——div.flex 输出结构、dmbox(disambig/setindex)、全中文文案、干支排序键 |
|||
-- 输出 HTML 与求闻版严格一致(样式/配置/模板均依赖该结构,零漂移) |
|||
-- |
-- Load necessary modules. |
||
require('strict') |
|||
local getArgs = require('Module:Arguments').getArgs |
local getArgs = require('Module:Arguments').getArgs |
||
local categoryHandler = require('Module:Category handler').main |
local categoryHandler = require('Module:Category handler').main |
||
local yesno = require('Module:Yesno') |
local yesno = require('Module:Yesno') |
||
-- Load the configuration page. |
|||
local cfgTables = mw.loadData('Module:Message box/configuration') |
|||
-- Get a language object for formatDate and ucfirst. |
-- Get a language object for formatDate and ucfirst. |
||
local lang = mw.language.getContentLanguage() |
local lang = mw.language.getContentLanguage() |
||
-- Define constants |
|||
local CONFIG_MODULE = 'Module:Message box/configuration' |
|||
local DEFAULT_IMAGE = 'Information Mark (Blue).svg' |
|||
-- Set aliases for often-used functions to reduce table lookups. |
-- Set aliases for often-used functions to reduce table lookups. |
||
local format = mw.ustring.format |
local format = mw.ustring.format |
||
local tconcat = table.concat |
|||
local tinsert = table.insert |
local tinsert = table.insert |
||
local tconcat = table.concat |
|||
local trim = mw.text.trim |
|||
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
||
| 第24行: | 第28行: | ||
local function getTitleObject(page, ...) |
local function getTitleObject(page, ...) |
||
if type(page) == 'string' then |
if type(page) == 'string' then |
||
-- Get the title object, passing the function through pcall |
-- Get the title object, passing the function through pcall |
||
-- in case we are over the expensive function count limit. |
-- in case we are over the expensive function count limit. |
||
local success, title = pcall(mw.title.new, page, ...) |
local success, title = pcall(mw.title.new, page, ...) |
||
| 第63行: | 第67行: | ||
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
||
-- Namespace resolution |
|||
-- Box class definition |
|||
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
||
local |
local function getNamespaceId(ns) |
||
box.__index = box |
|||
function box.new() |
|||
local obj = {} |
|||
setmetatable(obj, box) |
|||
return obj |
|||
end |
|||
function box.getNamespaceId(ns) |
|||
if not ns then return end |
if not ns then return end |
||
if type(ns) == 'string' then |
if type(ns) == 'string' then |
||
| 第89行: | 第84行: | ||
end |
end |
||
function |
local function getMboxType(nsid) |
||
-- Gets the mbox type from a namespace number. |
-- Gets the mbox type from a namespace number. |
||
if nsid == 0 then |
if nsid == 0 then |
||
| 第103行: | 第98行: | ||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
function box:addCat(ns, cat, sort) |
|||
-- 干支日期排序键 |
|||
-------------------------------------------------------------------------------- |
|||
local dayName = { |
|||
[1] = '㏠', [2] = '㏡', [3] = '㏢', [4] = '㏣', [5] = '㏤', |
|||
[6] = '㏥', [7] = '㏦', [8] = '㏧', [9] = '㏨', [10] = '㏩', |
|||
[11] = '㏪', [12] = '㏫', [13] = '㏬', [14] = '㏭', [15] = '㏮', |
|||
[16] = '㏯', [17] = '㏰', [18] = '㏱', [19] = '㏲', [20] = '㏳', |
|||
[21] = '㏴', [22] = '㏵', [23] = '㏶', [24] = '㏷', [25] = '㏸', |
|||
[26] = '㏹', [27] = '㏺', [28] = '㏻', [29] = '㏼', [30] = '㏽', |
|||
[31] = '㏾' |
|||
} |
|||
-------------------------------------------------------------------------------- |
|||
-- Box class definition |
|||
-------------------------------------------------------------------------------- |
|||
local MessageBox = {} |
|||
MessageBox.__index = MessageBox |
|||
function MessageBox.new(boxType, args, cfgTables) |
|||
args = args or {} |
|||
local obj = {} |
|||
setmetatable(obj, MessageBox) |
|||
obj.boxType = boxType |
|||
-- Get the title object and the namespace. |
|||
obj.pageTitle = getTitleObject(args.page ~= '' and args.page) |
|||
obj.title = obj.pageTitle or mw.title.getCurrentTitle() |
|||
obj.demospace = args.demospace ~= '' and args.demospace or nil |
|||
obj.nsid = getNamespaceId(obj.demospace) or obj.title.namespace |
|||
-- Resolve mbox to the concrete box type from the namespace. |
|||
if obj.boxType == 'mbox' then |
|||
obj.boxType = getMboxType(obj.nsid) |
|||
end |
|||
-- Get the config for our box type. |
|||
obj.cfg = cfgTables[obj.boxType] |
|||
if not obj.cfg then |
|||
local boxTypes = {} |
|||
for k, v in pairs(cfgTables) do |
|||
tinsert(boxTypes, format('"%s"', k)) |
|||
end |
|||
tinsert(boxTypes, '"mbox"') |
|||
error(format('无效的消息框类型「%s」;有效的类型为%s', tostring(obj.boxType), mw.text.listToText(boxTypes)), 2) |
|||
end |
|||
obj.args = args |
|||
obj.classes = {} |
|||
obj.mainCats = nil |
|||
obj.templateCats = nil |
|||
obj.allCats = nil |
|||
return obj |
|||
end |
|||
function MessageBox:addCat(ns, cat, sort) |
|||
if type(cat) ~= 'string' then return end |
if type(cat) ~= 'string' then return end |
||
local nsVals = {'main', 'template', 'all'} |
local nsVals = {'main', 'template', 'all'} |
||
| 第126行: | 第179行: | ||
end |
end |
||
function |
function MessageBox:addClass(class) |
||
if type(class) ~= 'string' then return end |
if type(class) ~= 'string' then return end |
||
self.classes = self.classes or {} |
|||
tinsert(self.classes, class) |
tinsert(self.classes, class) |
||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
function box:setTitle(args) |
|||
-- Parameter processing |
|||
-- Get the title object and the namespace. |
|||
-------------------------------------------------------------------------------- |
|||
self.pageTitle = getTitleObject(args.page ~= '' and args.page) |
|||
self.title = self.pageTitle or mw.title.getCurrentTitle() |
|||
self.demospace = args.demospace ~= '' and args.demospace or nil |
|||
self.nsid = box.getNamespaceId(self.demospace) or self.title.namespace |
|||
end |
|||
function |
function MessageBox:setTypeData() |
||
local cfg = self.cfg |
|||
-- Get the box config data from the data page. |
|||
local args = self.args |
|||
if boxType == 'mbox' then |
|||
boxType = box.getMboxType(self.nsid) |
|||
end |
|||
local cfg = cfgTables[boxType] |
|||
if not cfg then |
|||
local boxTypes = {} |
|||
for k, v in pairs(cfgTables) do |
|||
tinsert(boxTypes, format('"%s"', k)) |
|||
end |
|||
tinsert(boxTypes, '"mbox"') |
|||
error(format('无效的消息框类型「%s」;有效的类型为%s', tostring(boxType), mw.text.listToText(boxTypes)), 2) |
|||
end |
|||
return cfg |
|||
end |
|||
function box:removeBlankArgs(cfg, args) |
|||
-- Only allow blank arguments for the parameter names listed in cfg.allowBlankParams. |
|||
local newArgs = {} |
|||
for k, v in pairs(args) do |
|||
if v ~= '' then |
|||
newArgs[k] = v |
|||
end |
|||
end |
|||
for i, param in ipairs(cfg.allowBlankParams or {}) do |
|||
newArgs[param] = args[param] |
|||
end |
|||
return newArgs |
|||
end |
|||
function box:setBoxParameters(cfg, args) |
|||
-- Get type data. |
-- Get type data. |
||
self.type = args.type |
self.type = args.type |
||
| 第195行: | 第215行: | ||
self.isSmall = false |
self.isSmall = false |
||
end |
end |
||
end |
|||
function MessageBox:setClasses() |
|||
local cfg = self.cfg |
|||
local args = self.args |
|||
-- Add attributes, classes and styles. |
-- Add attributes, classes and styles. |
||
| 第201行: | 第226行: | ||
self.name = args.name |
self.name = args.name |
||
if self.name then |
if self.name then |
||
self:addClass('box-' .. string.gsub(self.name,' ','_')) |
self:addClass('box-' .. string.gsub(self.name, ' ', '_')) |
||
end |
end |
||
end |
end |
||
| 第219行: | 第244行: | ||
-- Set text style. |
-- Set text style. |
||
self.textstyle = args.textstyle |
self.textstyle = args.textstyle |
||
self.abovestyle= args.abovestyle |
self.abovestyle = args.abovestyle |
||
self.belowstyle= args.belowstyle |
self.belowstyle = args.belowstyle |
||
end |
|||
function MessageBox:setCollapsibleTextFields() |
|||
local cfg = self.cfg |
|||
local args = self.args |
|||
-- Find if we are on the template page or not. |
-- Find if we are on the template page or not. |
||
-- or if both cfg.templateCategory and cfg.templateCategoryRequireName are set. |
|||
self.useCollapsibleTextFields = cfg.useCollapsibleTextFields |
self.useCollapsibleTextFields = cfg.useCollapsibleTextFields |
||
if self.useCollapsibleTextFields or cfg.templateCategory and cfg.templateCategoryRequireName then |
if self.useCollapsibleTextFields or cfg.templateCategory and cfg.templateCategoryRequireName then |
||
| 第235行: | 第264行: | ||
end |
end |
||
if not self.useCollapsibleTextFields then |
|||
-- Process data for collapsible text fields. At the moment these are only used in {{ambox}}. |
|||
return |
|||
if self.useCollapsibleTextFields then |
|||
end |
|||
-- Get the self.issue value. |
|||
if self.isSmall and args.smalltext then |
|||
-- Get the self.issue value. |
|||
if self.isSmall and args.smalltext then |
|||
else |
|||
self.issue = args.smalltext |
|||
local sect |
|||
else |
|||
if args.sect == '' then |
|||
local sect |
|||
sect = '此' .. (cfg.sectionDefault or '页面') |
|||
if args.sect == '' then |
|||
sect = '此' .. (cfg.sectionDefault or '页面') |
|||
elseif type(args.sect) == 'string' then |
|||
end |
|||
sect = '此' .. args.sect |
|||
issue = type(issue) == 'string' and issue ~= '' and issue or nil |
|||
local text = args.text |
|||
text = type(text) == 'string' and text or nil |
|||
local issues = {} |
|||
tinsert(issues, sect) |
|||
tinsert(issues, issue) |
|||
tinsert(issues, text) |
|||
self.issue = tconcat(issues) |
|||
end |
end |
||
local issue = args.issue |
|||
issue = type(issue) == 'string' and issue ~= '' and issue or nil |
|||
local text = args.text |
|||
text = type(text) == 'string' and text or nil |
|||
local issues = {} |
|||
tinsert(issues, sect) |
|||
tinsert(issues, issue) |
|||
tinsert(issues, text) |
|||
self.issue = tconcat(issues) |
|||
end |
|||
-- Get the self.talk value. |
|||
local talk = args.talk |
|||
if talk == '' -- Show talk links on the template page or template subpages if the talk parameter is blank. |
|||
and self.templateTitle |
|||
and (mw.title.equals(self.templateTitle, self.title) or self.title:isSubpageOf(self.templateTitle)) |
|||
then |
|||
talk = '#' |
|||
elseif talk == '' then |
|||
talk = nil |
|||
end |
|||
if talk then |
|||
-- If the talk value is a talk page, make a link to that page. Else assume that it's a section heading, |
|||
-- and make a link to the talk page of the current page with that section heading. |
|||
local talkTitle = getTitleObject(talk) |
|||
local talkArgIsTalkPage = true |
|||
if not talkTitle or not talkTitle.isTalkPage then |
|||
talkArgIsTalkPage = false |
|||
talkTitle = getTitleObject(self.title.text, mw.site.namespaces[self.title.namespace].talk.id) |
|||
end |
end |
||
if |
if talkTitle and talkTitle.exists then |
||
local talkText = '相关讨论可见于' |
|||
-- If the talk value is a talk page, make a link to that page. Else assume that it's a section heading, |
|||
if talkArgIsTalkPage then |
|||
-- and make a link to the talk page of the current page with that section heading. |
|||
talkText = format('%s[[%s|%s]]。', talkText, talk, talkTitle.prefixedText) |
|||
local talkTitle = getTitleObject(talk) |
|||
else |
|||
local talkArgIsTalkPage = true |
|||
talkText = format('%s[[%s#%s|讨论页]]。', talkText, talkTitle.prefixedText, talk) |
|||
if not talkTitle or not talkTitle.isTalkPage then |
|||
talkArgIsTalkPage = false |
|||
talkTitle = getTitleObject(self.title.text, mw.site.namespaces[self.title.namespace].talk.id) |
|||
end |
|||
if talkTitle and talkTitle.exists then |
|||
local talkText = '相关讨论可见于' |
|||
if talkArgIsTalkPage then |
|||
talkText = format('%s[[%s|%s]]。', talkText, talk, talkTitle.prefixedText) |
|||
else |
|||
talkText = format('%s[[%s#%s|讨论页]]。', talkText, talkTitle.prefixedText, talk) |
|||
end |
|||
self.talk = talkText |
|||
end |
end |
||
self.talk = talkText |
|||
end |
end |
||
end |
|||
-- Get other values. |
|||
local date |
|||
if args.date and args.date ~= '' then |
|||
date = args.date |
|||
elseif args.time == '' and self.isTemplatePage then |
|||
date = lang:formatDate('Y年n月j日') |
|||
elseif args.time and args.time ~= '' then |
|||
date = lang:formatDate('Y年n月j日', args.time) |
|||
end |
|||
if date then |
|||
local ok, tempdate = pcall(lang.formatDate, lang, 'Y年n月j日', date) -- 正規化日期 |
|||
if ok then |
|||
date = tempdate |
|||
end |
|||
end |
|||
if date then |
|||
self.date = string.format(" <small class='date-container'>''(<span class='date'>%s</span>)''</small>", date) |
|||
end |
end |
||
if args.fix and args.fix ~= '' then |
|||
self.fix = format("<br><small>%s</small>", args.fix) |
|||
else |
|||
self.fix = '' |
|||
end |
|||
self.info = args.info |
|||
end |
end |
||
if date then |
|||
self.date = string.format(" <small class='date-container'>''(<span class='date'>%s</span>)''</small>", date) |
|||
end |
|||
if args.fix and args.fix ~= '' then |
|||
self.fix = format('<br><small>%s</small>', args.fix) |
|||
else |
|||
self.fix = '' |
|||
end |
|||
self.info = args.info |
|||
end |
|||
function MessageBox:setTextFields() |
|||
local args = self.args |
|||
-- Set the non-collapsible text field. |
-- Set the non-collapsible text field. |
||
-- and also by ambox when small=yes. |
|||
if self.isSmall then |
if self.isSmall then |
||
self.text = args.smalltext or args.text |
self.text = args.smalltext or args.text |
||
| 第327行: | 第360行: | ||
-- Set the below row. |
-- Set the below row. |
||
self.below = args.below |
self.below = args.below |
||
end |
|||
function MessageBox:setImages() |
|||
local cfg = self.cfg |
|||
local args = self.args |
|||
-- General image settings. |
-- General image settings. |
||
| 第340行: | 第378行: | ||
if not imageLeft then |
if not imageLeft then |
||
local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or '40px' |
local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or '40px' |
||
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage or |
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage or DEFAULT_IMAGE, imageSize) |
||
end |
end |
||
end |
end |
||
| 第349行: | 第387行: | ||
self.imageRight = imageRight |
self.imageRight = imageRight |
||
end |
end |
||
end |
|||
-------------------------------------------------------------------------------- |
|||
-- Category processing |
|||
-------------------------------------------------------------------------------- |
|||
function MessageBox:setMainspaceCategories() |
|||
local cfg = self.cfg |
|||
local args = self.args |
|||
if not cfg.allowMainspaceCategories then |
|||
return |
|||
end |
|||
if args.cat then |
|||
args.cat1 = args.cat |
|||
end |
|||
self.catNums = getArgNums(args, 'cat') |
|||
if args.category then |
|||
args.category1 = args.category |
|||
end |
|||
self.categoryNums = getArgNums(args, 'category') |
|||
if args.all then |
|||
args.all1 = args.all |
|||
end |
|||
self.allNums = getArgNums(args, 'all') |
|||
self.categoryParamNums = union(self.catNums, self.categoryNums) |
|||
self.categoryParamNums = union(self.categoryParamNums, self.allNums) |
|||
-- The following is roughly equivalent to the old {{Ambox/category}}. |
|||
-- Add mainspace categories. At the moment these are only used in {{ambox}}. |
|||
local date |
|||
if cfg.allowMainspaceCategories then |
|||
local sortDay |
|||
if args.cat then |
|||
if args.date and args.date ~= '' then |
|||
date = args.date |
|||
local ok, tempdate = pcall(lang.formatDate, lang, 'Y年n月', date) -- 正規化日期 |
|||
if ok then |
|||
date = tempdate |
|||
end |
end |
||
elseif args.time and args.time ~= '' then |
|||
self.catNums = getArgNums(args, 'cat') |
|||
date = lang:formatDate('Y年n月', args.time) |
|||
if args.category then |
|||
sortDay = lang:formatDate('j', args.time) |
|||
args.category1 = args.category |
|||
sortDay = tonumber(sortDay) |
|||
end |
|||
sortDay = dayName[sortDay] |
|||
self.categoryNums = getArgNums(args, 'category') |
|||
end |
|||
if args.all then |
|||
date = type(date) == 'string' and date |
|||
args.all1 = args.all |
|||
local preposition = '自' |
|||
end |
|||
for _, num in ipairs(self.categoryParamNums) do |
|||
self.allNums = getArgNums(args, 'all') |
|||
local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)] |
|||
self.categoryParamNums = union(self.catNums, self.categoryNums) |
|||
local allCat = args['all' .. tostring(num)] |
|||
self.categoryParamNums = union(self.categoryParamNums, self.allNums) |
|||
mainCat = type(mainCat) == 'string' and mainCat |
|||
-- The following is roughly equivalent to the old {{Ambox/category}}. |
|||
allCat = type(allCat) == 'string' and allCat |
|||
local date |
|||
if mainCat and date and date ~= '' then |
|||
local sortDay |
|||
local catTitle = format('%s%s%s', preposition, date, mainCat) |
|||
local dayName = { |
|||
if sortDay then |
|||
self:addCat('main', catTitle, sortDay) |
|||
[2] = '㏡', |
|||
else |
|||
[3] = '㏢', |
|||
self:addCat('main', catTitle) |
|||
[4] = '㏣', |
|||
[5] = '㏤', |
|||
[6] = '㏥', |
|||
[7] = '㏦', |
|||
[8] = '㏧', |
|||
[9] = '㏨', |
|||
[10] = '㏩', |
|||
[11] = '㏪', |
|||
[12] = '㏫', |
|||
[13] = '㏬', |
|||
[14] = '㏭', |
|||
[15] = '㏮', |
|||
[16] = '㏯', |
|||
[17] = '㏰', |
|||
[18] = '㏱', |
|||
[19] = '㏲', |
|||
[20] = '㏳', |
|||
[21] = '㏴', |
|||
[22] = '㏵', |
|||
[23] = '㏶', |
|||
[24] = '㏷', |
|||
[25] = '㏸', |
|||
[26] = '㏹', |
|||
[27] = '㏺', |
|||
[28] = '㏻', |
|||
[29] = '㏼', |
|||
[30] = '㏽', |
|||
[31] = '㏾' |
|||
} |
|||
if args.date and args.date ~= '' then |
|||
date = args.date |
|||
local ok, tempdate = pcall(lang.formatDate, lang, 'Y年n月', date) -- 正規化日期 |
|||
if ok then |
|||
date = tempdate |
|||
end |
end |
||
catTitle = getTitleObject('Category:' .. catTitle) |
|||
elseif args.time and args.time ~= '' then |
|||
if not catTitle or not catTitle.exists then |
|||
date = lang:formatDate('Y年n月', args.time) |
|||
self:addCat('main', '模板中使用无效日期参数的条目') |
|||
sortDay = lang:formatDate('j', args.time) |
|||
sortDay = tonumber(sortDay) |
|||
sortDay = dayName[sortDay] |
|||
end |
|||
date = type(date) == 'string' and date |
|||
local preposition = '自' |
|||
for _, num in ipairs(self.categoryParamNums) do |
|||
local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)] |
|||
local allCat = args['all' .. tostring(num)] |
|||
mainCat = type(mainCat) == 'string' and mainCat |
|||
allCat = type(allCat) == 'string' and allCat |
|||
if mainCat and date and date ~= '' then |
|||
local catTitle = format('%s%s%s', preposition, date, mainCat) |
|||
if sortDay then |
|||
self:addCat('main', catTitle, sortDay) |
|||
else |
|||
self:addCat('main', catTitle) |
|||
end |
|||
catTitle = getTitleObject('Category:' .. catTitle) |
|||
if not catTitle or not catTitle.exists then |
|||
self:addCat('main', '模板中使用无效日期参数的条目') |
|||
end |
|||
elseif mainCat and (not date or date == '') then |
|||
self:addCat('main', mainCat) |
|||
end |
|||
if allCat then |
|||
self:addCat('main', allCat) |
|||
end |
end |
||
elseif mainCat and (not date or date == '') then |
|||
self:addCat('main', mainCat) |
|||
end |
|||
if allCat then |
|||
self:addCat('main', allCat) |
|||
end |
end |
||
end |
end |
||
end |
|||
function MessageBox:setTemplateCategories() |
|||
local cfg = self.cfg |
|||
local args = self.args |
|||
-- Add template-namespace categories. |
-- Add template-namespace categories. |
||
| 第477行: | 第498行: | ||
self:addCat('template', templateCat, templateSort) |
self:addCat('template', templateCat, templateSort) |
||
end |
end |
||
end |
|||
function MessageBox:setAllNamespaceCategories() |
|||
-- Categories for all namespaces. |
-- Categories for all namespaces. |
||
if self.invalidTypeError then |
if self.invalidTypeError then |
||
| 第486行: | 第509行: | ||
self:addCat('all', '错误使用替换引用的页面') |
self:addCat('all', '错误使用替换引用的页面') |
||
end |
end |
||
end |
|||
function MessageBox:setCategories() |
|||
if self.cfg.allowMainspaceCategories then |
|||
self:setMainspaceCategories() |
|||
end |
|||
if self.cfg.templateCategory then |
|||
self:setTemplateCategories() |
|||
end |
|||
self:setAllNamespaceCategories() |
|||
end |
|||
function MessageBox:renderCategories() |
|||
-- Convert category tables to strings and pass them through [[Module:Category handler]]. |
-- Convert category tables to strings and pass them through [[Module:Category handler]]. |
||
return categoryHandler{ |
|||
main = tconcat(self.mainCats or {}), |
main = tconcat(self.mainCats or {}), |
||
template = tconcat(self.templateCats or {}), |
template = tconcat(self.templateCats or {}), |
||
all = tconcat(self.allCats or {}), |
all = tconcat(self.allCats or {}), |
||
nocat = args.nocat, |
nocat = self.args.nocat, |
||
demospace = self.demospace, |
demospace = self.demospace, |
||
page = self.pageTitle and self.pageTitle.prefixedText or nil |
page = self.pageTitle and self.pageTitle.prefixedText or nil |
||
| 第498行: | 第533行: | ||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
function box:export() |
|||
-- Export |
|||
-------------------------------------------------------------------------------- |
|||
function MessageBox:export() |
|||
local root = mw.html.create() |
local root = mw.html.create() |
||
| 第533行: | 第572行: | ||
-- images in a div are wider than that, they may overlap with the text or cause |
-- images in a div are wider than that, they may overlap with the text or cause |
||
-- other display problems. |
-- other display problems. |
||
imageLeftCell = imageLeftCell:tag('div') --:css('width', '52px') |
imageLeftCell = imageLeftCell:tag('div') --:css('width', '52px') |
||
end |
end |
||
imageLeftCell |
imageLeftCell |
||
| 第542行: | 第581行: | ||
-- "No image. Cell with some width or padding necessary for text cell to have 100% width." |
-- "No image. Cell with some width or padding necessary for text cell to have 100% width." |
||
row:tag('div') |
row:tag('div') |
||
:addClass('mbox-empty-cell') |
:addClass('mbox-empty-cell') |
||
end |
end |
||
| 第613行: | 第652行: | ||
:wikitext(self.imageRight) |
:wikitext(self.imageRight) |
||
end |
end |
||
-- Add __DISAMBIG__ for {{dmbox|type=disambig}} |
-- Add __DISAMBIG__ for {{dmbox|type=disambig}} |
||
if self.type == 'disambig' then |
if self.type == 'disambig' then |
||
if self.nsid == 10 then |
if self.nsid == 10 then |
||
root:wikitext('[[Category:消歧义消息模板]]') |
root:wikitext('[[Category:消歧义消息模板]]') |
||
elseif self.nsid == 0 then |
elseif self.nsid == 0 then |
||
root:wikitext('__DISAMBIG__'):wikitext('[[Category:全部消歧义页面]]') |
root:wikitext('__DISAMBIG__'):wikitext('[[Category:全部消歧义页面]]') |
||
else |
else |
||
root:wikitext('<!-- omitted -->') |
root:wikitext('<!-- omitted -->') |
||
end |
end |
||
| 第626行: | 第665行: | ||
-- Add category for {{dmbox|type=setindex}} |
-- Add category for {{dmbox|type=setindex}} |
||
if self.type == 'setindex' then |
if self.type == 'setindex' then |
||
if self.nsid == 10 then |
if self.nsid == 10 then |
||
root:wikitext('[[Category:消歧义消息模板]]') |
root:wikitext('[[Category:消歧义消息模板]]') |
||
else |
else |
||
root:wikitext('__DISAMBIG__') |
root:wikitext('__DISAMBIG__') |
||
end |
end |
||
root:wikitext('[[Category:全部设置索引条目]]') |
root:wikitext('[[Category:全部设置索引条目]]') |
||
end |
end |
||
-- Add error message for invalid type parameters. |
-- Add error message for invalid type parameters. |
||
if self.invalidTypeError then |
if self.invalidTypeError then |
||
| 第645行: | 第684行: | ||
-- Add categories. |
-- Add categories. |
||
root |
root |
||
:wikitext(self |
:wikitext(self:renderCategories()) |
||
return tostring(root) |
return tostring(root) |
||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
-- Exports |
|||
-------------------------------------------------------------------------------- |
|||
local function main(boxType, args) |
local function main(boxType, args) |
||
local outputBox = |
local outputBox = MessageBox.new(boxType, args, mw.loadData(CONFIG_MODULE)) |
||
outputBox: |
outputBox.args = outputBox:removeBlankArgs(args) |
||
outputBox:setTypeData() |
|||
outputBox:setClasses() |
|||
outputBox: |
outputBox:setCollapsibleTextFields() |
||
outputBox:setTextFields() |
|||
outputBox:setImages() |
|||
outputBox:setCategories() |
|||
return outputBox:export() |
return outputBox:export() |
||
end |
|||
function MessageBox:removeBlankArgs(args) |
|||
-- Only allow blank arguments for the parameter names listed in cfg.allowBlankParams. |
|||
local cfg = self.cfg |
|||
local newArgs = {} |
|||
for k, v in pairs(args) do |
|||
if v ~= '' then |
|||
newArgs[k] = v |
|||
end |
|||
end |
|||
for i, param in ipairs(cfg.allowBlankParams or {}) do |
|||
newArgs[param] = args[param] |
|||
end |
|||
return newArgs |
|||
end |
end |
||
| 第671行: | 第732行: | ||
} |
} |
||
for boxType in pairs( |
for boxType in pairs(mw.loadData(CONFIG_MODULE)) do |
||
p[boxType] = makeWrapper(boxType) |
p[boxType] = makeWrapper(boxType) |
||
end |
|||
function p._exportClasses() |
|||
-- For testing. |
|||
return { |
|||
MessageBox = MessageBox |
|||
} |
|||
end |
end |
||
2026年8月7日 (五) 10:16的最新版本
此模块基于以下Lua语言模块编写:
本模块适用于{{mbox}}、{{fmbox}}、{{dmbox}}。
用法
在其它模块中引用本模块,您需要事先加载:
local messageBox = require('Module:Message box')
为创建一个消息框,您需要使用main函数,并给出两个参数:第一个对应消息框类型(字符串),第二个对应消息。
local box = messageBox.main( boxType, {
param1 = param1,
param2 = param2,
-- More parameters...
})
可用信息框类型:
| 类型 | 原对应模板 | 用途 |
|---|---|---|
ambox |
{{ambox}} | 条目命名空间 |
dmbox |
{{dmbox}} | 消歧义页面 |
fmbox |
{{fmbox}} | 界面消息及表单 |
tmbox |
{{tmbox}} | 讨论命名空间 |
ombox |
{{ombox}} | 其他命名空间 |
“#invoke”引入
除main函数外,本模块为每个消息框类型对应了分别的函数,例如{{#invoke:Message box|ombox|...}}、{{#invoke:Message box|ambox|...}}等。
技术细节
The module uses the same basic code for each of the templates listed above; the differences between each of them are configured using the data at Module:Message box/configuration. Here are the various configuration options and what they mean:
types- a table containing data used by the type parameter of the message box. The table keys are the values that can be passed to the type parameter, and the table values are tables containing the class and the image used by that type.default- the type to use if no value was passed to the type parameter, or if an invalid value was specified.showInvalidTypeError- whether to show an error if the value passed to the type parameter was invalid.allowBlankParams- usually blank values are stripped from parameters passed to the module. However, whitespace is preserved for the parameters included in the allowBlankParams table.allowId- whether it is possible to set an "id" attribute to the html table tag.allowSmall- whether a small version of the message box can be produced with "small=yes".smallParam- a custom name for the small parameter. For example, if set to "left" you can produce a small message box using "small=left".smallClass- the class to use for small message boxes.substCheck- whether to perform a subst check or not.classes- an array of classes to use with the message box.imageEmptyCell- whether to use an empty Template:Tag cell if there is no image set. This is used to preserve spacing for message boxes with a width of less than 100% of the screen.imageEmptyCellStyle- whether empty image cells should be styled.imageCheckBlank- whether "image=blank" results in no image being displayed.imageSmallSize- usually, images used in small message boxes are set to 30x30px. This sets a custom size.imageCellDiv- whether to enclose the image in a div enforcing a maximum image size.useCollapsibleTextFields- whether to use text fields that can be collapsed, i.e. "issue", "fix", "talk", etc. Currently only used in ambox.imageRightNone- whether imageright=none results in no image being displayed on the right-hand side of the message box.sectionDefault- the default name for the "section" parameter. Depends onuseCollapsibleTextFields.allowMainspaceCategories- allow categorisation in the main namespace.templateCategory- the name of a category to be placed on the template page.templateCategoryRequireName- whether thenameparameter is required to display the template category.templateErrorCategory- the name of the error category to be used on the template page.templateErrorParamsToCheck- an array of parameter names to check. If any are absent, thetemplateErrorCategoryis applied to the template page.
-- 融合版 Module:Message box
-- 工程组织:mediawiki.org 版风格(require('strict')、常量表、辅助函数、类方法拆分、命名规范)
-- 行为基准:求闻版(rev 71078)——div.flex 输出结构、dmbox(disambig/setindex)、全中文文案、干支排序键
-- 输出 HTML 与求闻版严格一致(样式/配置/模板均依赖该结构,零漂移)
-- Load necessary modules.
require('strict')
local getArgs = require('Module:Arguments').getArgs
local categoryHandler = require('Module:Category handler').main
local yesno = require('Module:Yesno')
-- Get a language object for formatDate and ucfirst.
local lang = mw.language.getContentLanguage()
-- Define constants
local CONFIG_MODULE = 'Module:Message box/configuration'
local DEFAULT_IMAGE = 'Information Mark (Blue).svg'
-- Set aliases for often-used functions to reduce table lookups.
local format = mw.ustring.format
local tconcat = table.concat
local tinsert = table.insert
--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------
local function getTitleObject(page, ...)
if type(page) == 'string' then
-- Get the title object, passing the function through pcall
-- in case we are over the expensive function count limit.
local success, title = pcall(mw.title.new, page, ...)
if success then
return title
end
end
end
local function union(t1, t2)
-- Returns the union of two arrays.
local vals = {}
for i, v in ipairs(t1) do
vals[v] = true
end
for i, v in ipairs(t2) do
vals[v] = true
end
local ret = {}
for k in pairs(vals) do
tinsert(ret, k)
end
table.sort(ret)
return ret
end
local function getArgNums(args, prefix)
local nums = {}
for k, v in pairs(args) do
local num = mw.ustring.match(tostring(k), '^' .. prefix .. '([1-9]%d*)$')
if num then
tinsert(nums, tonumber(num))
end
end
table.sort(nums)
return nums
end
--------------------------------------------------------------------------------
-- Namespace resolution
--------------------------------------------------------------------------------
local function getNamespaceId(ns)
if not ns then return end
if type(ns) == 'string' then
ns = lang:ucfirst(mw.ustring.lower(ns))
if ns == 'Main' then
ns = 0
end
end
local nsTable = mw.site.namespaces[ns]
if nsTable then
return nsTable.id
end
end
local function getMboxType(nsid)
-- Gets the mbox type from a namespace number.
if nsid == 0 then
return 'ambox' -- main namespace
else
local nsTable = mw.site.namespaces[nsid]
if nsTable and nsTable.isTalk then
return 'tmbox' -- any talk namespace
else
return 'ombox' -- other namespaces or invalid input
end
end
end
--------------------------------------------------------------------------------
-- 干支日期排序键
--------------------------------------------------------------------------------
local dayName = {
[1] = '㏠', [2] = '㏡', [3] = '㏢', [4] = '㏣', [5] = '㏤',
[6] = '㏥', [7] = '㏦', [8] = '㏧', [9] = '㏨', [10] = '㏩',
[11] = '㏪', [12] = '㏫', [13] = '㏬', [14] = '㏭', [15] = '㏮',
[16] = '㏯', [17] = '㏰', [18] = '㏱', [19] = '㏲', [20] = '㏳',
[21] = '㏴', [22] = '㏵', [23] = '㏶', [24] = '㏷', [25] = '㏸',
[26] = '㏹', [27] = '㏺', [28] = '㏻', [29] = '㏼', [30] = '㏽',
[31] = '㏾'
}
--------------------------------------------------------------------------------
-- Box class definition
--------------------------------------------------------------------------------
local MessageBox = {}
MessageBox.__index = MessageBox
function MessageBox.new(boxType, args, cfgTables)
args = args or {}
local obj = {}
setmetatable(obj, MessageBox)
obj.boxType = boxType
-- Get the title object and the namespace.
obj.pageTitle = getTitleObject(args.page ~= '' and args.page)
obj.title = obj.pageTitle or mw.title.getCurrentTitle()
obj.demospace = args.demospace ~= '' and args.demospace or nil
obj.nsid = getNamespaceId(obj.demospace) or obj.title.namespace
-- Resolve mbox to the concrete box type from the namespace.
if obj.boxType == 'mbox' then
obj.boxType = getMboxType(obj.nsid)
end
-- Get the config for our box type.
obj.cfg = cfgTables[obj.boxType]
if not obj.cfg then
local boxTypes = {}
for k, v in pairs(cfgTables) do
tinsert(boxTypes, format('"%s"', k))
end
tinsert(boxTypes, '"mbox"')
error(format('无效的消息框类型「%s」;有效的类型为%s', tostring(obj.boxType), mw.text.listToText(boxTypes)), 2)
end
obj.args = args
obj.classes = {}
obj.mainCats = nil
obj.templateCats = nil
obj.allCats = nil
return obj
end
function MessageBox:addCat(ns, cat, sort)
if type(cat) ~= 'string' then return end
local nsVals = {'main', 'template', 'all'}
local tname
for i, val in ipairs(nsVals) do
if ns == val then
tname = ns .. 'Cats'
end
end
if not tname then
for i, val in ipairs(nsVals) do
nsVals[i] = format('"%s"', val)
end
error('无效的ns参数传送到box:addCat;有效的数值为' .. mw.text.listToText(nsVals, '、', '或'))
end
self[tname] = self[tname] or {}
if type(sort) == 'string' then
tinsert(self[tname], format('[[Category:%s|%s]]', cat, sort))
else
tinsert(self[tname], format('[[Category:%s]]', cat))
end
end
function MessageBox:addClass(class)
if type(class) ~= 'string' then return end
tinsert(self.classes, class)
end
--------------------------------------------------------------------------------
-- Parameter processing
--------------------------------------------------------------------------------
function MessageBox:setTypeData()
local cfg = self.cfg
local args = self.args
-- Get type data.
self.type = args.type
local typeData = cfg.types[self.type]
self.invalidTypeError = cfg.showInvalidTypeError and self.type and not typeData and true or false
typeData = typeData or cfg.types[cfg.default]
self.typeClass = typeData.class
self.typeImage = typeData.image
-- Find if the box has been wrongly substituted.
if cfg.substCheck and args.subst == 'SUBST' then
self.isSubstituted = true
end
-- Find whether we are using a small message box.
if cfg.allowSmall and (
cfg.smallParam and args.small == cfg.smallParam
or not cfg.smallParam and yesno(args.small)
)
then
self.isSmall = true
else
self.isSmall = false
end
end
function MessageBox:setClasses()
local cfg = self.cfg
local args = self.args
-- Add attributes, classes and styles.
if cfg.allowId then
self.id = args.id
self.name = args.name
if self.name then
self:addClass('box-' .. string.gsub(self.name, ' ', '_'))
end
end
for _, class in ipairs(cfg.classes or {}) do
self:addClass(class)
end
if self.isSmall then
self:addClass(cfg.smallClass or 'mbox-small')
end
if yesno(args.hidden) then
self:addClass('infobox editsection')
end
self:addClass(self.typeClass)
self:addClass(args.class)
self.style = args.style
-- Set text style.
self.textstyle = args.textstyle
self.abovestyle = args.abovestyle
self.belowstyle = args.belowstyle
end
function MessageBox:setCollapsibleTextFields()
local cfg = self.cfg
local args = self.args
-- Find if we are on the template page or not.
self.useCollapsibleTextFields = cfg.useCollapsibleTextFields
if self.useCollapsibleTextFields or cfg.templateCategory and cfg.templateCategoryRequireName then
self.name = args.name
if self.name then
local templateName = mw.ustring.match(self.name, '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$') or self.name
templateName = 'Template:' .. templateName
self.templateTitle = getTitleObject(templateName)
end
self.isTemplatePage = self.templateTitle and mw.title.equals(self.title, self.templateTitle) or false
end
if not self.useCollapsibleTextFields then
return
end
-- Get the self.issue value.
if self.isSmall and args.smalltext then
self.issue = args.smalltext
else
local sect
if args.sect == '' then
sect = '此' .. (cfg.sectionDefault or '页面')
elseif type(args.sect) == 'string' then
sect = '此' .. args.sect
end
local issue = args.issue
issue = type(issue) == 'string' and issue ~= '' and issue or nil
local text = args.text
text = type(text) == 'string' and text or nil
local issues = {}
tinsert(issues, sect)
tinsert(issues, issue)
tinsert(issues, text)
self.issue = tconcat(issues)
end
-- Get the self.talk value.
local talk = args.talk
if talk == '' -- Show talk links on the template page or template subpages if the talk parameter is blank.
and self.templateTitle
and (mw.title.equals(self.templateTitle, self.title) or self.title:isSubpageOf(self.templateTitle))
then
talk = '#'
elseif talk == '' then
talk = nil
end
if talk then
-- If the talk value is a talk page, make a link to that page. Else assume that it's a section heading,
-- and make a link to the talk page of the current page with that section heading.
local talkTitle = getTitleObject(talk)
local talkArgIsTalkPage = true
if not talkTitle or not talkTitle.isTalkPage then
talkArgIsTalkPage = false
talkTitle = getTitleObject(self.title.text, mw.site.namespaces[self.title.namespace].talk.id)
end
if talkTitle and talkTitle.exists then
local talkText = '相关讨论可见于'
if talkArgIsTalkPage then
talkText = format('%s[[%s|%s]]。', talkText, talk, talkTitle.prefixedText)
else
talkText = format('%s[[%s#%s|讨论页]]。', talkText, talkTitle.prefixedText, talk)
end
self.talk = talkText
end
end
-- Get other values.
local date
if args.date and args.date ~= '' then
date = args.date
elseif args.time == '' and self.isTemplatePage then
date = lang:formatDate('Y年n月j日')
elseif args.time and args.time ~= '' then
date = lang:formatDate('Y年n月j日', args.time)
end
if date then
local ok, tempdate = pcall(lang.formatDate, lang, 'Y年n月j日', date) -- 正規化日期
if ok then
date = tempdate
end
end
if date then
self.date = string.format(" <small class='date-container'>''(<span class='date'>%s</span>)''</small>", date)
end
if args.fix and args.fix ~= '' then
self.fix = format('<br><small>%s</small>', args.fix)
else
self.fix = ''
end
self.info = args.info
end
function MessageBox:setTextFields()
local args = self.args
-- Set the non-collapsible text field.
if self.isSmall then
self.text = args.smalltext or args.text
else
self.text = args.text
end
-- Set the above row.
self.above = args.above
-- Set the below row.
self.below = args.below
end
function MessageBox:setImages()
local cfg = self.cfg
local args = self.args
-- General image settings.
self.imageCellDiv = not self.isSmall and cfg.imageCellDiv and true or false
self.imageEmptyCell = cfg.imageEmptyCell
-- Left image settings.
local imageLeft = self.isSmall and args.smallimage or args.image
if cfg.imageCheckBlank and imageLeft ~= 'blank' and imageLeft ~= 'none'
or not cfg.imageCheckBlank and imageLeft ~= 'none'
then
self.imageLeft = imageLeft
if not imageLeft then
local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or '40px'
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage or DEFAULT_IMAGE, imageSize)
end
end
-- Right image settings.
local imageRight = self.isSmall and args.smallimageright or args.imageright
if not (cfg.imageRightNone and imageRight == 'none') then
self.imageRight = imageRight
end
end
--------------------------------------------------------------------------------
-- Category processing
--------------------------------------------------------------------------------
function MessageBox:setMainspaceCategories()
local cfg = self.cfg
local args = self.args
if not cfg.allowMainspaceCategories then
return
end
if args.cat then
args.cat1 = args.cat
end
self.catNums = getArgNums(args, 'cat')
if args.category then
args.category1 = args.category
end
self.categoryNums = getArgNums(args, 'category')
if args.all then
args.all1 = args.all
end
self.allNums = getArgNums(args, 'all')
self.categoryParamNums = union(self.catNums, self.categoryNums)
self.categoryParamNums = union(self.categoryParamNums, self.allNums)
-- The following is roughly equivalent to the old {{Ambox/category}}.
local date
local sortDay
if args.date and args.date ~= '' then
date = args.date
local ok, tempdate = pcall(lang.formatDate, lang, 'Y年n月', date) -- 正規化日期
if ok then
date = tempdate
end
elseif args.time and args.time ~= '' then
date = lang:formatDate('Y年n月', args.time)
sortDay = lang:formatDate('j', args.time)
sortDay = tonumber(sortDay)
sortDay = dayName[sortDay]
end
date = type(date) == 'string' and date
local preposition = '自'
for _, num in ipairs(self.categoryParamNums) do
local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)]
local allCat = args['all' .. tostring(num)]
mainCat = type(mainCat) == 'string' and mainCat
allCat = type(allCat) == 'string' and allCat
if mainCat and date and date ~= '' then
local catTitle = format('%s%s%s', preposition, date, mainCat)
if sortDay then
self:addCat('main', catTitle, sortDay)
else
self:addCat('main', catTitle)
end
catTitle = getTitleObject('Category:' .. catTitle)
if not catTitle or not catTitle.exists then
self:addCat('main', '模板中使用无效日期参数的条目')
end
elseif mainCat and (not date or date == '') then
self:addCat('main', mainCat)
end
if allCat then
self:addCat('main', allCat)
end
end
end
function MessageBox:setTemplateCategories()
local cfg = self.cfg
local args = self.args
-- Add template-namespace categories.
if cfg.templateCategory then
if cfg.templateCategoryRequireName then
if self.isTemplatePage then
self:addCat('template', cfg.templateCategory)
end
elseif not self.title.isSubpage then
self:addCat('template', cfg.templateCategory)
end
end
-- Add template error category.
if cfg.templateErrorCategory then
local templateErrorCategory = cfg.templateErrorCategory
local templateCat, templateSort
if not self.name and not self.title.isSubpage then
templateCat = templateErrorCategory
elseif self.isTemplatePage then
local paramsToCheck = cfg.templateErrorParamsToCheck or {}
local count = 0
for i, param in ipairs(paramsToCheck) do
if not args[param] then
count = count + 1
end
end
if count > 0 then
templateCat = templateErrorCategory
templateSort = tostring(count)
end
if self.categoryNums and #self.categoryNums > 0 then
templateCat = templateErrorCategory
templateSort = 'C'
end
end
self:addCat('template', templateCat, templateSort)
end
end
function MessageBox:setAllNamespaceCategories()
-- Categories for all namespaces.
if self.invalidTypeError then
local allSort = (self.nsid == 0 and 'Main:' or '') .. self.title.prefixedText
self:addCat('all', '需要修复的信息框', allSort)
end
if self.isSubstituted then
self:addCat('all', '错误使用替换引用的页面')
end
end
function MessageBox:setCategories()
if self.cfg.allowMainspaceCategories then
self:setMainspaceCategories()
end
if self.cfg.templateCategory then
self:setTemplateCategories()
end
self:setAllNamespaceCategories()
end
function MessageBox:renderCategories()
-- Convert category tables to strings and pass them through [[Module:Category handler]].
return categoryHandler{
main = tconcat(self.mainCats or {}),
template = tconcat(self.templateCats or {}),
all = tconcat(self.allCats or {}),
nocat = self.args.nocat,
demospace = self.demospace,
page = self.pageTitle and self.pageTitle.prefixedText or nil
}
end
--------------------------------------------------------------------------------
-- Export
--------------------------------------------------------------------------------
function MessageBox:export()
local root = mw.html.create()
-- Add the subst check error.
if self.isSubstituted and self.name then
root
:tag('b')
:addClass('error')
:wikitext(format(
'模板<code>%s[[Template:%s|%s]]%s</code>被錯誤地替代。',
mw.text.nowiki('{{'), self.name, self.name, mw.text.nowiki('}}')
))
end
-- Create the box table.
local boxTable = root:tag('div')
boxTable
:attr('id', self.id)
for i, class in ipairs(self.classes or {}) do
boxTable
:addClass(class)
end
boxTable
:cssText(self.style)
:attr('role', 'presentation')
-- Add the left-hand image.
local row = boxTable:tag('div'):addClass('mbox-body')
if self.imageLeft then
local imageLeftCell = row:tag('div'):addClass('mbox-image')
if self.imageCellDiv then
-- If we are using a div, redefine imageLeftCell so that the image is inside it.
-- Divs use style="width: 52px;", which limits the image width to 52px. If any
-- images in a div are wider than that, they may overlap with the text or cause
-- other display problems.
imageLeftCell = imageLeftCell:tag('div') --:css('width', '52px')
end
imageLeftCell
:wikitext(self.imageLeft)
elseif self.imageEmptyCell then
-- Some message boxes define an empty cell if no image is specified, and some don't.
-- The old template code in templates where empty cells are specified gives the following hint:
-- "No image. Cell with some width or padding necessary for text cell to have 100% width."
row:tag('div')
:addClass('mbox-empty-cell')
end
local textCell = row:tag('div'):addClass('mbox-text')
-- Add the above row.
if self.above then
textCell
:tag('div')
:attr('colspan', self.imageRight and '3' or '2')
:addClass('mbox-above')
:cssText(self.abovestyle)
:wikitext(self.above)
end
-- Add the text.
if self.useCollapsibleTextFields then
-- The message box uses advanced text parameters that allow things to be collapsible. At the
-- moment, only ambox uses this.
textCell
:cssText(self.textstyle)
local textCellSpan = textCell:tag('span')
textCellSpan
:addClass('mbox-text-span')
:wikitext(self.issue)
if not self.isSmall then
textCellSpan
:tag('span')
:addClass('hide-when-compact')
:wikitext(self.talk and self.talk)
end
textCellSpan
:wikitext(self.date and self.date)
if not self.isSmall and self.fix ~= '' then
textCellSpan
:tag('span')
:addClass('hide-when-compact')
:wikitext(self.fix and self.fix)
end
if not self.isSmall then
textCellSpan
:tag('span')
:addClass('hide-when-compact')
:wikitext(self.info and self.info)
end
else
-- Default text formatting - anything goes.
textCell
:cssText(self.textstyle)
:wikitext(self.text)
end
-- Add the below row.
if self.below then
textCell
:tag('div')
:attr('colspan', self.imageRight and '3' or '2')
:addClass('mbox-below')
:cssText(self.belowstyle)
:wikitext(self.below)
end
-- Add the right-hand image.
if self.imageRight then
local imageRightCell = row:tag('div'):addClass('mbox-imageright')
if self.imageCellDiv then
imageRightCell = imageRightCell:tag('div') --:css('width', '52px') -- If we are using a div, redefine imageRightCell so that the image is inside it.
end
imageRightCell
:wikitext(self.imageRight)
end
-- Add __DISAMBIG__ for {{dmbox|type=disambig}}
if self.type == 'disambig' then
if self.nsid == 10 then
root:wikitext('[[Category:消歧义消息模板]]')
elseif self.nsid == 0 then
root:wikitext('__DISAMBIG__'):wikitext('[[Category:全部消歧义页面]]')
else
root:wikitext('<!-- omitted -->')
end
end
-- Add category for {{dmbox|type=setindex}}
if self.type == 'setindex' then
if self.nsid == 10 then
root:wikitext('[[Category:消歧义消息模板]]')
else
root:wikitext('__DISAMBIG__')
end
root:wikitext('[[Category:全部设置索引条目]]')
end
-- Add error message for invalid type parameters.
if self.invalidTypeError then
root
:tag('div')
:css('text-align', 'center')
:wikitext(format('此消息框使用无效的「type=%s」参数,需要修复。', self.type or ''))
end
-- Add categories.
root
:wikitext(self:renderCategories())
return tostring(root)
end
--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------
local function main(boxType, args)
local outputBox = MessageBox.new(boxType, args, mw.loadData(CONFIG_MODULE))
outputBox.args = outputBox:removeBlankArgs(args)
outputBox:setTypeData()
outputBox:setClasses()
outputBox:setCollapsibleTextFields()
outputBox:setTextFields()
outputBox:setImages()
outputBox:setCategories()
return outputBox:export()
end
function MessageBox:removeBlankArgs(args)
-- Only allow blank arguments for the parameter names listed in cfg.allowBlankParams.
local cfg = self.cfg
local newArgs = {}
for k, v in pairs(args) do
if v ~= '' then
newArgs[k] = v
end
end
for i, param in ipairs(cfg.allowBlankParams or {}) do
newArgs[param] = args[param]
end
return newArgs
end
local function makeWrapper(boxType)
return function (frame)
local args = getArgs(frame, {trim = false, removeBlanks = false})
return main(boxType, args)
end
end
local p = {
main = main,
mbox = makeWrapper('mbox')
}
for boxType in pairs(mw.loadData(CONFIG_MODULE)) do
p[boxType] = makeWrapper(boxType)
end
function p._exportClasses()
-- For testing.
return {
MessageBox = MessageBox
}
end
return p