編集の要約なし
(←新しいページ: '-- This is a meta-module for producing message box templates, including {{mbox}}, {{ambox}}, -- {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}. --...') |
編集の要約なし |
||
1行目: | 1行目: | ||
-- This is a meta-module for producing message box templates, including {{mbox}}, {{ambox}}, | -- This is a meta-module for producing message box templates, including | ||
-- {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}. | |||
-- Require necessary modules. | -- Require necessary modules. | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
7行目: | 7行目: | ||
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. | -- Load the configuration page. | ||
local cfgTables = mw.loadData('Module:Message box/configuration') | 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() | ||
-- 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 | ||
19行目: | 19行目: | ||
local tconcat = table.concat | local tconcat = table.concat | ||
local trim = mw.text.trim | local trim = mw.text.trim | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- Helper functions | -- Helper functions | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local function getTitleObject(page, ...) | local function getTitleObject(page, ...) | ||
if type(page) == 'string' then | if type(page) == 'string' then | ||
34行目: | 34行目: | ||
end | end | ||
end | end | ||
local function union(t1, t2) | local function union(t1, t2) | ||
-- Returns the union of two arrays. | -- Returns the union of two arrays. | ||
51行目: | 51行目: | ||
return ret | return ret | ||
end | end | ||
local function getArgNums(args, prefix) | local function getArgNums(args, prefix) | ||
local nums = {} | local nums = {} | ||
63行目: | 63行目: | ||
return nums | return nums | ||
end | end | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- Box class definition | -- Box class definition | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local box = {} | local box = {} | ||
box.__index = box | box.__index = box | ||
function box.new() | function box.new() | ||
local obj = {} | local obj = {} | ||
76行目: | 76行目: | ||
return obj | return obj | ||
end | end | ||
function box.getNamespaceId(ns) | function box.getNamespaceId(ns) | ||
if not ns then return end | if not ns then return end | ||
90行目: | 90行目: | ||
end | end | ||
end | end | ||
function box.getMboxType(nsid) | function box.getMboxType(nsid) | ||
-- Gets the mbox type from a namespace number. | -- Gets the mbox type from a namespace number. | ||
108行目: | 108行目: | ||
end | end | ||
end | end | ||
function box:addCat(ns, cat, sort) | function box:addCat(ns, cat, sort) | ||
if type(cat) ~= 'string' then return end | if type(cat) ~= 'string' then return end | ||
122行目: | 122行目: | ||
nsVals[i] = format('"%s"', val) | nsVals[i] = format('"%s"', val) | ||
end | end | ||
error('invalid ns parameter passed to box:addCat; valid values are ' .. mw.text.listToText(nsVals, nil, ' or ')) | error( | ||
'invalid ns parameter passed to box:addCat; valid values are ' | |||
.. mw.text.listToText(nsVals, nil, ' or ') | |||
) | |||
end | end | ||
self[tname] = self[tname] or {} | self[tname] = self[tname] or {} | ||
131行目: | 134行目: | ||
end | end | ||
end | end | ||
function box:addClass(class) | function box:addClass(class) | ||
if type(class) ~= 'string' then return end | if type(class) ~= 'string' then return end | ||
137行目: | 140行目: | ||
tinsert(self.classes, class) | tinsert(self.classes, class) | ||
end | end | ||
function box:addAttr(attr, val) | |||
if type(attr) ~= 'string' or type(val) ~= 'string' then return end | |||
self.attrs = self.attrs or {} | |||
tinsert(self.attrs, attr) | |||
end | |||
function box:setTitle(args) | function box:setTitle(args) | ||
-- Get the title object and the namespace. | -- Get the title object and the namespace. | ||
145行目: | 154行目: | ||
self.nsid = box.getNamespaceId(self.demospace) or self.title.namespace | self.nsid = box.getNamespaceId(self.demospace) or self.title.namespace | ||
end | end | ||
function box:getConfig(boxType) | function box:getConfig(boxType) | ||
-- Get the box config data from the data page. | -- Get the box config data from the data page. | ||
158行目: | 167行目: | ||
end | end | ||
tinsert(boxTypes, '"mbox"') | tinsert(boxTypes, '"mbox"') | ||
error(format('invalid message box type "%s"; valid types are %s', tostring(boxType), mw.text.listToText(boxTypes)), 2) | error(format( | ||
'invalid message box type "%s"; valid types are %s', | |||
tostring(boxType), | |||
mw.text.listToText(boxTypes) | |||
), 2) | |||
end | end | ||
return cfg | return cfg | ||
end | end | ||
function box:removeBlankArgs(cfg, args) | function box:removeBlankArgs(cfg, args) | ||
-- Only allow blank arguments for the parameter names listed in cfg.allowBlankParams. | -- Only allow blank arguments for the parameter names listed in | ||
-- cfg.allowBlankParams. | |||
local newArgs = {} | local newArgs = {} | ||
for k, v in pairs(args) do | for k, v in pairs(args) do | ||
176行目: | 190行目: | ||
return newArgs | return newArgs | ||
end | end | ||
function box:setBoxParameters(cfg, args) | function box:setBoxParameters(cfg, args) | ||
-- Get type data. | -- Get type data. | ||
self.type = args.type | self.type = args.type | ||
local typeData = cfg.types[self.type] | local typeData = cfg.types[self.type] | ||
self.invalidTypeError = cfg.showInvalidTypeError and self.type and not typeData and true or false | self.invalidTypeError = cfg.showInvalidTypeError | ||
and self.type | |||
and not typeData | |||
and true | |||
or false | |||
typeData = typeData or cfg.types[cfg.default] | typeData = typeData or cfg.types[cfg.default] | ||
self.typeClass = typeData.class | self.typeClass = typeData.class | ||
self.typeImage = typeData.image | self.typeImage = typeData.image | ||
-- Find if the box has been wrongly substituted. | -- Find if the box has been wrongly substituted. | ||
if cfg.substCheck and args.subst == 'SUBST' then | if cfg.substCheck and args.subst == 'SUBST' then | ||
self.isSubstituted = true | self.isSubstituted = true | ||
end | end | ||
-- Find whether we are using a small message box. | -- Find whether we are using a small message box. | ||
if cfg.allowSmall and ( | if cfg.allowSmall and ( | ||
201行目: | 219行目: | ||
self.isSmall = false | self.isSmall = false | ||
end | end | ||
-- Add attributes, classes and styles. | -- Add attributes, classes and styles. | ||
if cfg.allowId then | if cfg.allowId then | ||
self.id = args.id | self.id = args.id | ||
end | end | ||
self:addClass(cfg.usePlainlinksParam and yesno(args.plainlinks or true) and 'plainlinks') | self:addClass( | ||
cfg.usePlainlinksParam and yesno(args.plainlinks or true) and 'plainlinks' | |||
) | |||
for _, class in ipairs(cfg.classes or {}) do | for _, class in ipairs(cfg.classes or {}) do | ||
self:addClass(class) | self:addClass(class) | ||
212行目: | 232行目: | ||
if self.isSmall then | if self.isSmall then | ||
self:addClass(cfg.smallClass or 'mbox-small') | self:addClass(cfg.smallClass or 'mbox-small') | ||
end | end | ||
self:addClass(self.typeClass) | self:addClass(self.typeClass) | ||
self:addClass(args.class) | self:addClass(args.class) | ||
self.style = args.style | self.style = args.style | ||
self.attrs = args.attrs | |||
-- Set text style. | -- Set text style. | ||
self.textstyle = args.textstyle | self.textstyle = args.textstyle | ||
-- Find if we are on the template page or not. This functionality is only used if useCollapsibleTextFields is set, | -- Find if we are on the template page or not. This functionality is only | ||
-- used if useCollapsibleTextFields is set, 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 | |||
self.name = args.name | self.name = args.name | ||
if self.name then | if self.name then | ||
local templateName = mw.ustring.match(self.name, '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$') or self.name | local templateName = mw.ustring.match( | ||
self.name, | |||
'^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$' | |||
) or self.name | |||
templateName = 'Template:' .. templateName | templateName = 'Template:' .. templateName | ||
self.templateTitle = getTitleObject(templateName) | self.templateTitle = getTitleObject(templateName) | ||
end | end | ||
self.isTemplatePage = self.templateTitle and mw.title.equals(self.title, self.templateTitle) or false | self.isTemplatePage = self.templateTitle | ||
and mw.title.equals(self.title, self.templateTitle) | |||
or false | |||
end | end | ||
-- Process data for collapsible text fields. At the moment these are only used in {{ambox}}. | -- Process data for collapsible text fields. At the moment these are only | ||
-- used in {{ambox}}. | |||
if self.useCollapsibleTextFields then | if self.useCollapsibleTextFields then | ||
-- Get the self.issue value. | -- Get the self.issue value. | ||
258行目: | 286行目: | ||
self.issue = tconcat(issues, ' ') | self.issue = tconcat(issues, ' ') | ||
end | end | ||
-- Get the self.talk value. | -- Get the self.talk value. | ||
local talk = args.talk | local talk = args.talk | ||
-- Show talk links on the template page or template subpages if the talk | |||
-- parameter is blank. | |||
if talk == '' | |||
and self.templateTitle | and self.templateTitle | ||
and (mw.title.equals(self.templateTitle, self.title) or self.title:isSubpageOf(self.templateTitle)) | and ( | ||
mw.title.equals(self.templateTitle, self.title) | |||
or self.title:isSubpageOf(self.templateTitle) | |||
) | |||
then | then | ||
talk = '#' | talk = '#' | ||
270行目: | 303行目: | ||
end | end | ||
if talk then | 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, | -- 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 talkTitle = getTitleObject(talk) | ||
local talkArgIsTalkPage = true | local talkArgIsTalkPage = true | ||
if not talkTitle or not talkTitle.isTalkPage then | if not talkTitle or not talkTitle.isTalkPage then | ||
talkArgIsTalkPage = false | talkArgIsTalkPage = false | ||
talkTitle = getTitleObject(self.title.text, mw.site.namespaces[self.title.namespace].talk.id) | talkTitle = getTitleObject( | ||
self.title.text, | |||
mw.site.namespaces[self.title.namespace].talk.id | |||
) | |||
end | end | ||
if talkTitle and talkTitle.exists then | if talkTitle and talkTitle.exists then | ||
local talkText = 'Relevant discussion may be found on' | local talkText = 'Relevant discussion may be found on' | ||
if talkArgIsTalkPage then | if talkArgIsTalkPage then | ||
talkText = format('%s [[%s|%s]].', talkText, talk, talkTitle.prefixedText) | talkText = format( | ||
'%s [[%s|%s]].', | |||
talkText, | |||
talk, | |||
talkTitle.prefixedText | |||
) | |||
else | else | ||
talkText = format('%s the [[%s#%s|talk page]].', talkText, talkTitle.prefixedText, talk) | talkText = format( | ||
'%s the [[%s#%s|talk page]].', | |||
talkText, | |||
talkTitle.prefixedText, | |||
talk | |||
) | |||
end | end | ||
self.talk = talkText | self.talk = talkText | ||
end | end | ||
end | end | ||
-- Get other values. | -- Get other values. | ||
self.fix = args.fix ~= '' and args.fix or nil | self.fix = args.fix ~= '' and args.fix or nil | ||
302行目: | 349行目: | ||
self.info = args.info | self.info = args.info | ||
end | end | ||
-- Set the non-collapsible text field. At the moment this is used by all box types other than ambox, | -- Set the non-collapsible text field. At the moment this is used by all box | ||
-- types other than ambox, 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 | ||
310行目: | 357行目: | ||
self.text = args.text | self.text = args.text | ||
end | end | ||
-- Set the below row. | -- Set the below row. | ||
self.below = cfg.below and args.below | self.below = cfg.below and args.below | ||
-- General image settings. | -- General image settings. | ||
self.imageCellDiv = not self.isSmall and cfg.imageCellDiv and true or false | self.imageCellDiv = not self.isSmall and cfg.imageCellDiv and true or false | ||
320行目: | 367行目: | ||
self.imageEmptyCellStyle = 'border:none;padding:0px;width:1px' | self.imageEmptyCellStyle = 'border:none;padding:0px;width:1px' | ||
end | end | ||
-- Left image settings. | -- Left image settings. | ||
local imageLeft = self.isSmall and args.smallimage or args.image | local imageLeft = self.isSmall and args.smallimage or args.image | ||
328行目: | 375行目: | ||
self.imageLeft = imageLeft | self.imageLeft = imageLeft | ||
if not imageLeft then | if not imageLeft then | ||
local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or '40x40px' | local imageSize = self.isSmall | ||
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage or 'Imbox notice.png', imageSize) | and (cfg.imageSmallSize or '30x30px') | ||
or '40x40px' | |||
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage | |||
or 'Imbox notice.png', imageSize) | |||
end | end | ||
end | end | ||
-- Right image settings. | -- Right image settings. | ||
local imageRight = self.isSmall and args.smallimageright or args.imageright | local imageRight = self.isSmall and args.smallimageright or args.imageright | ||
338行目: | 388行目: | ||
self.imageRight = imageRight | self.imageRight = imageRight | ||
end | end | ||
-- Add mainspace categories. At the moment these are only used in {{ambox}}. | -- Add mainspace categories. At the moment these are only used in {{ambox}}. | ||
if cfg.allowMainspaceCategories then | if cfg.allowMainspaceCategories then | ||
360行目: | 410行目: | ||
local preposition = 'from' | local preposition = 'from' | ||
for _, num in ipairs(self.categoryParamNums) do | for _, num in ipairs(self.categoryParamNums) do | ||
local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)] | local mainCat = args['cat' .. tostring(num)] | ||
or args['category' .. tostring(num)] | |||
local allCat = args['all' .. tostring(num)] | local allCat = args['all' .. tostring(num)] | ||
mainCat = type(mainCat) == 'string' and mainCat | mainCat = type(mainCat) == 'string' and mainCat | ||
369行目: | 420行目: | ||
catTitle = getTitleObject('Category:' .. catTitle) | catTitle = getTitleObject('Category:' .. catTitle) | ||
if not catTitle or not catTitle.exists then | if not catTitle or not catTitle.exists then | ||
self:addCat('main', 'Articles with invalid date parameter in template') | self:addCat( | ||
'main', | |||
'Articles with invalid date parameter in template' | |||
) | |||
end | end | ||
elseif mainCat and (not date or date == '') then | elseif mainCat and (not date or date == '') then | ||
379行目: | 433行目: | ||
end | end | ||
end | end | ||
-- Add template-namespace categories. | -- Add template-namespace categories. | ||
if cfg.templateCategory then | if cfg.templateCategory then | ||
390行目: | 444行目: | ||
end | end | ||
end | end | ||
-- Add template error category. | -- Add template error category. | ||
if cfg.templateErrorCategory then | if cfg.templateErrorCategory then | ||
416行目: | 470行目: | ||
self:addCat('template', templateCat, templateSort) | self:addCat('template', templateCat, templateSort) | ||
end | end | ||
-- Categories for all namespaces. | -- Categories for all namespaces. | ||
if self.invalidTypeError then | if self.invalidTypeError then | ||
425行目: | 479行目: | ||
self:addCat('all', 'Pages with incorrectly substituted templates') | self:addCat('all', 'Pages with incorrectly substituted templates') | ||
end | end | ||
-- Convert category tables to strings and pass them through [[Module:Category handler]]. | -- Convert category tables to strings and pass them through | ||
-- [[Module:Category handler]]. | |||
self.categories = categoryHandler{ | self.categories = categoryHandler{ | ||
main = tconcat(self.mainCats or {}), | main = tconcat(self.mainCats or {}), | ||
436行目: | 491行目: | ||
} | } | ||
end | end | ||
function box:export() | function box:export() | ||
local root = htmlBuilder.create() | local root = htmlBuilder.create() | ||
-- Add the subst check error. | -- Add the subst check error. | ||
if self.isSubstituted and self.name then | if self.isSubstituted and self.name then | ||
450行目: | 505行目: | ||
)) | )) | ||
end | end | ||
-- Create the box table. | -- Create the box table. | ||
local boxTable = root.tag('table') | local boxTable = root.tag('table') | ||
462行目: | 517行目: | ||
.cssText(self.style) | .cssText(self.style) | ||
.attr('role', 'presentation') | .attr('role', 'presentation') | ||
for attr, val in pairs(self.attrs or {}) do | |||
boxTable | |||
.attr(attr, val) | |||
end | |||
-- Add the left-hand image. | -- Add the left-hand image. | ||
local row = boxTable.tag('tr') | local row = boxTable.tag('tr') | ||
468行目: | 527行目: | ||
local imageLeftCell = row.tag('td').addClass('mbox-image') | local imageLeftCell = row.tag('td').addClass('mbox-image') | ||
if self.imageCellDiv then | if self.imageCellDiv then | ||
-- If we are using a div, redefine imageLeftCell so that the image is inside it. | -- 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') | imageLeftCell = imageLeftCell.tag('div').css('width', '52px') | ||
end | end | ||
477行目: | 536行目: | ||
.wikitext(self.imageLeft) | .wikitext(self.imageLeft) | ||
elseif self.imageEmptyCell then | elseif self.imageEmptyCell then | ||
-- Some message boxes define an empty cell if no image is specified, and some don't. | -- 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('td') | row.tag('td') | ||
.addClass('mbox-empty-cell') | .addClass('mbox-empty-cell') | ||
.cssText(self.imageEmptyCellStyle) | .cssText(self.imageEmptyCellStyle) | ||
end | end | ||
-- Add the text. | -- Add the text. | ||
local textCell = row.tag('td').addClass('mbox-text') | local textCell = row.tag('td').addClass('mbox-text') | ||
if self.useCollapsibleTextFields then | if self.useCollapsibleTextFields then | ||
-- The message box uses advanced text parameters that allow things to be collapsible. At the | -- The message box uses advanced text parameters that allow things to be | ||
-- collapsible. At the moment, only ambox uses this. | |||
textCell | textCell | ||
.cssText(self.textstyle) | .cssText(self.textstyle) | ||
517行目: | 577行目: | ||
.wikitext(self.text) | .wikitext(self.text) | ||
end | end | ||
-- Add the right-hand image. | -- Add the right-hand image. | ||
if self.imageRight then | if self.imageRight then | ||
local imageRightCell = row.tag('td').addClass('mbox-imageright') | local imageRightCell = row.tag('td').addClass('mbox-imageright') | ||
if self.imageCellDiv then | 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. | |||
imageRightCell = imageRightCell.tag('div').css('width', '52px') | |||
end | end | ||
imageRightCell | imageRightCell | ||
.wikitext(self.imageRight) | .wikitext(self.imageRight) | ||
end | end | ||
-- Add the below row. | -- Add the below row. | ||
if self.below then | if self.below then | ||
537行目: | 599行目: | ||
.wikitext(self.below) | .wikitext(self.below) | ||
end | end | ||
-- Add error message for invalid type parameters. | -- Add error message for invalid type parameters. | ||
if self.invalidTypeError then | if self.invalidTypeError then | ||
543行目: | 605行目: | ||
.tag('div') | .tag('div') | ||
.css('text-align', 'center') | .css('text-align', 'center') | ||
.wikitext(format('This message box is using an invalid "type=%s" parameter and needs fixing.', self.type or '')) | .wikitext(format( | ||
'This message box is using an invalid "type=%s" parameter and needs fixing.', | |||
self.type or '' | |||
)) | |||
end | end | ||
-- Add categories. | -- Add categories. | ||
root | root | ||
.wikitext(self.categories) | .wikitext(self.categories) | ||
return tostring(root) | return tostring(root) | ||
end | end | ||
local function main(boxType, args) | local function main(boxType, args) | ||
local outputBox = box.new() | local outputBox = box.new() | ||
561行目: | 626行目: | ||
return outputBox:export() | return outputBox:export() | ||
end | end | ||
local function makeWrapper(boxType) | local function makeWrapper(boxType) | ||
return function (frame) | return function (frame) | ||
568行目: | 633行目: | ||
end | end | ||
end | end | ||
local p = { | local p = { | ||
main = main, | main = main, | ||
mbox = makeWrapper('mbox') | mbox = makeWrapper('mbox') | ||
} | } | ||
for boxType in pairs(cfgTables) do | for boxType in pairs(cfgTables) do | ||
p[boxType] = makeWrapper(boxType) | p[boxType] = makeWrapper(boxType) | ||
end | end | ||
return p | return p |