편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.
최신판 | 당신의 편집 | ||
1번째 줄: | 1번째 줄: | ||
-- This is a meta-module for producing message box templates, including | -- This is a meta-module for producing message box templates, including {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}. | ||
local htmlBuilder = require('Module:HtmlBuilder') | |||
require('Module: | local nsDetect = require('Module:Namespace detect') | ||
local | |||
local yesno = require('Module:Yesno') | local yesno = require('Module:Yesno') | ||
local p = {} | |||
local | |||
local function getTitleObject(page) | |||
local | 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 | |||
success, page = pcall(mw.title.new, page) | |||
if not success then | |||
page = nil | |||
end | |||
end | |||
return page | |||
end | end | ||
local function | local function presentButBlank(s) | ||
if type(s) ~= 'string' then return end | |||
if s and not mw.ustring.find(s, '%S') then | |||
return true | |||
else | |||
return false | |||
end | |||
end | end | ||
function p.build(data, args) | |||
-- Get the title object and the namespace. | |||
local title = mw.title.getCurrentTitle() | |||
local nsid = title.namespace | |||
local | |||
function | -- Get a language object for formatDate. | ||
local lang = mw.language.getContentLanguage() | |||
-- Commenting this out for now - this will require tinkering with Namespace detect to differentiate between | |||
-- invalid titles and pages where the expensive parser function count has been exceeded. | |||
--[[ | |||
local title = nsDetect.getPageObject(args.page) | |||
local namespace = nsDetect.main{ | |||
page = args.page, | |||
demospace = args.demospace, | |||
main = 'main', | |||
talk = 'talk', | |||
file = 'file', | |||
category = 'category', | |||
other = 'other' | |||
} | |||
]] | |||
------------------------ Process config data ---------------------------- | |||
-- Type data. | |||
local typeData = data.types[args.type] | |||
local invalidType = args.type and not typeData and true or false | |||
typeData = typeData or data.types[data.default] | |||
-- Process data for collapsible text fields | |||
local name, issue, talk, fix, date, info | |||
if data.useCollapsibleTextFields then | |||
name = args.name | |||
local nameTitle = getTitleObject(name) | |||
local isTemplatePage = nameTitle and title.prefixedText == ('Template:' .. nameTitle.text) and true or false | |||
local sect = args.sect | |||
if presentButBlank(sect) then | |||
sect = 'This article ' | |||
elseif type(sect) == 'string' then | |||
sect = 'This ' .. sect .. ' ' | |||
end | |||
issue = (sect or '') .. (args.issue or '') .. ' ' .. (args.text or '') | |||
talk = args.talk | |||
if presentButBlank(talk) and isTemplatePage then | |||
talk = '#' | |||
end | |||
fix = args.fix | |||
date = args.date | |||
if presentButBlank(date) and isTemplatePage then | |||
date = lang:formatDate('F Y') | |||
end | |||
info = args.info | |||
end | |||
-- Process the talk link, if present. | |||
if talk then | |||
-- See if the talk link exists and is for a talk or a content namespace. | |||
local talkTitle = type(talk) == 'string' and getTitleObject(talk) | |||
if not talkTitle or not talkTitle.isTalkPage then | |||
-- If we couldn't process the talk page link, get the talk page of the current page. | |||
local success | |||
success, talkTitle = pcall(title.talkPageTitle, title) | |||
if not success then | |||
talkTitle = nil | |||
end | |||
end | |||
if talkTitle and talkTitle.exists then | |||
local talkText = ' Relevant discussion may be found on' | |||
if talkTitle.isTalkPage then | |||
talkText = mw.ustring.format('%s [[%s|%s]].', talkText, talk, talkTitle.prefixedText) | |||
else | |||
talkText = mw.ustring.format('%s the [[%s#%s|talk page]].', talkText, talkTitle.prefixedText, talk) | |||
end | |||
talk = talkText | |||
end | |||
end | |||
-- Find whether we are using a small message box and process our data accordingly. | |||
local isSmall = data.allowSmall and (args.small == 'yes' or args.small == true) and true or false | |||
local smallClass, image, imageRight, text, imageSize | |||
if isSmall then | |||
smallClass = data.smallClass or 'mbox-small' | |||
image = args.smallimage or args.image | |||
imageRight = args.smallimageright or args.imageright | |||
if data.useCollapsibleTextFields then | |||
text = args.smalltext or issue | |||
else | |||
text = args.smalltext or args.text | |||
end | |||
imageSize = data.imageSmallSize or '30x30px' | |||
else | |||
image = args.image | |||
imageRight = args.imageright | |||
imageSize = '40x40px' | |||
text = args.text | |||
end | |||
------------------------ Build the box ---------------------------- | |||
local root = htmlBuilder.create() | |||
-- Do the subst check. | |||
if data.substCheck and args.subst == 'SUBST' then | |||
if type(args.name) == 'string' then | |||
root | |||
.tag('b') | |||
.addClass('error') | |||
.wikitext(mw.ustring.format( | |||
'Template <code>%s%s%s</code> has been incorrectly substituted.', | |||
mw.text.nowiki('{{'), | |||
args.name, | |||
mw.text.nowiki('}}') | |||
)) | |||
end | end | ||
root.wikitext('[[Category:Pages with incorrectly substituted templates]]') | |||
end | |||
-- Build the box. | |||
local box = root.tag('table') | |||
box | |||
.attr('id', args.id) | |||
for i, class in ipairs(data.classes) do | |||
box | |||
.addClass(class) | |||
end | |||
box | |||
.addClass(isSmall and smallClass) | |||
.addClass(data.classPlainlinksYesno and yesno(args.plainlinks or true) and 'plainlinks') | |||
.addClass(typeData.class) | |||
.addClass(args.class) | |||
.cssText(args.style) | |||
.attr('role', 'presentation') | |||
-- Add the left-hand image. | |||
local row = box.tag('tr') | |||
local imageLeftCell = row.tag('td').addClass('mbox-image') | |||
local imageCheckBlank = data.imageCheckBlank | |||
if image ~= 'none' and not imageCheckBlank or image ~= 'none' and imageCheckBlank and image ~= 'blank' then | |||
if not isSmall and data.imageCellDiv then | |||
imageLeftCell = imageLeftCell.tag('div').css('width', '52px') -- If we are using a div, redefine imageLeftCell so that the image is inside it. | |||
end | |||
imageLeftCell | |||
.wikitext(image or mw.ustring.format('[[File:%s|%s|link=|alt=]]', typeData.image, imageSize)) | |||
elseif data.imageEmptyCell then | |||
row.tag('td') | |||
.addClass('mbox-empty-cell') -- No image. Cell with some width or padding necessary for text cell to have 100% width. | |||
.cssText(data.imageEmptyCellStyle and 'border:none;padding:0px;width:1px') | |||
end | |||
-- Add the text. | |||
local textCell = row.tag('td').addClass('mbox-text') | |||
if data.useCollapsibleTextFields then | |||
textCell | |||
.cssText(args.textstyle) | |||
local textCellSpan = textCell.tag('span') | |||
textCellSpan | |||
.addClass('mbox-text-span') | |||
.wikitext(issue) | |||
if not isSmall then | |||
textCellSpan | |||
.tag('span') | |||
.addClass('hide-when-compact') | |||
.wikitext(talk) | |||
.wikitext(' ') | |||
.wikitext(fix) | |||
.done() | |||
end | |||
textCellSpan | |||
.wikitext(date and mw.ustring.format(" <small>''(%s)''</small>", date)) | |||
if not isSmall then | |||
textCellSpan | |||
.tag('span') | |||
.addClass('hide-when-compact') | |||
.wikitext(info and ' ' .. info) | |||
end | |||
else | |||
textCell | |||
.cssText(args.textstyle) | |||
.wikitext(text) | |||
end | |||
-- Add the right-hand image. | |||
local imageRightCell = row.tag('td').addClass('mbox-imageright') | |||
if imageRight and not (data.imageRightNone and imageRight == 'none') then | |||
if not isSmall and data.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(imageRight) | |||
end | |||
-- Add the below row. | |||
if data.below and args.below then | |||
box.tag('tr') | |||
.tag('td') | |||
.attr('colspan', args.imageright and '3' or '2') | |||
.addClass('mbox-text') | |||
.cssText(args.textstyle) | |||
.wikitext(args.below) | |||
end | |||
------------------------ Add error messages and categories ---------------------------- | |||
-- Add error message and tracking category for invalid type parameters. | |||
if invalidType then | |||
local catsort = (nsid == 0 and 'Main:' or '') .. title.prefixedText | |||
root | |||
.tag('div') | |||
.css('text-align', 'center') | |||
.wikitext(mw.ustring.format('This message box is using an invalid "type=%s" parameter and needs fixing.', args.type or '')) | |||
.done() | |||
.wikitext(mw.ustring.format('[[Category:Wikipedia message box parameter needs fixing|%s]]', catsort)) | |||
end | |||
-- Categorise template pages. | |||
if data.category and nsid == 10 and not title.isSubpage and not yesno(args.nocat) then | |||
root.wikitext(mw.ustring.format('[[Category:%s]]', data.category)) | |||
end | |||
return tostring(root) | |||
end | end | ||
function | function p._ambox(args) | ||
local data = {} | |||
data.types = { | |||
speedy = { | |||
class = 'ambox-speedy', | |||
image = 'Ambox speedy deletion.png' | |||
}, | |||
delete = { | |||
class = 'ambox-delete', | |||
image = 'Ambox deletion.png' | |||
}, | |||
content = { | |||
class = 'ambox-content', | |||
image = 'Ambox content.png' | |||
}, | |||
style = { | |||
class = 'ambox-style', | |||
image = 'Edit-clear.svg' | |||
}, | |||
move = { | |||
class = 'ambox-move', | |||
image = 'Ambox move.png' | |||
}, | |||
protection = { | |||
class = 'ambox-protection', | |||
image = 'Ambox protection.png' | |||
}, | |||
notice = { | |||
class = 'ambox-notice', | |||
image = 'Ambox notice.png' | |||
} | |||
} | |||
data.default = 'notice' | |||
data.allowSmall = true | |||
data.substCheck = true | |||
data.classes = {'metadata', 'plainlinks', 'ambox'} | |||
data.smallClass = 'mbox-small-left' | |||
data.imageEmptyCell = true | |||
data.imageCheckBlank = true | |||
data.imageSmallSize = '20x20px' | |||
data.imageCellDiv = true | |||
data.useCollapsibleTextFields = true | |||
data.imageRightNone = true | |||
return p.build(data, args) | |||
end | end | ||
function | function p._fmbox(args) | ||
local data = {} | |||
data.types = { | |||
warning = { | |||
class = 'fmbox-warning', | |||
image = 'Cmbox deletion.png' | |||
}, | |||
editnotice = { | |||
class = 'fmbox-editnotice', | |||
image = 'Imbox notice.png' | |||
}, | |||
system = { | |||
class = 'fmbox-system', | |||
image = 'Imbox notice.png' | |||
} | |||
} | |||
data.default = 'system' | |||
data.classes = { 'plainlinks', 'fmbox' } | |||
data.imageEmptyCell = false | |||
data.imageRightNone = false | |||
return p.build(data, args) | |||
end | end | ||
function | function p._ombox(args) | ||
local data = {} | |||
data.types = { | |||
speedy = { | |||
class = 'ombox-speedy', | |||
image = 'Imbox speedy deletion.png' | |||
}, | |||
delete = { | |||
class = 'ombox-delete', | |||
image = 'Imbox deletion.png' | |||
}, | |||
content = { | |||
class = 'ombox-content', | |||
image = 'Imbox content.png' | |||
}, | |||
style = { | |||
class = 'ombox-style', | |||
image = 'Edit-clear.svg' | |||
}, | |||
move = { | |||
class = 'ombox-move', | |||
image = 'Imbox move.png' | |||
}, | |||
protection = { | |||
class = 'ombox-protection', | |||
image = 'Imbox protection.png' | |||
}, | |||
notice = { | |||
class = 'ombox-notice', | |||
image = 'Imbox notice.png' | |||
} | |||
} | |||
data.default = 'notice' | |||
data.classes = {'plainlinks', 'ombox'} | |||
data.allowSmall = true | |||
data.imageEmptyCell = true | |||
data.imageRightNone = true | |||
return p.build(data, args) | |||
end | end | ||
function | function p._imbox(args) | ||
local data = {} | |||
data.types = { | |||
speedy = { | |||
class = 'imbox-speedy', | |||
image = 'Imbox speedy deletion.png' | |||
}, | |||
delete = { | |||
class = 'imbox-delete', | |||
image = 'Imbox deletion.png' | |||
}, | |||
content = { | |||
class = 'imbox-content', | |||
image = 'Imbox content.png' | |||
}, | |||
style = { | |||
class = 'imbox-style', | |||
image = 'Edit-clear.svg' | |||
}, | |||
move = { | |||
class = 'imbox-move', | |||
image = 'Imbox move.png' | |||
}, | |||
protection = { | |||
class = 'imbox-protection', | |||
image = 'Imbox protection.png' | |||
}, | |||
license = { | |||
class = 'imbox-license', | |||
image = 'Imbox license.png' | |||
}, | |||
featured = { | |||
class = 'imbox-featured', | |||
image = 'Imbox featured.png' | |||
}, | |||
notice = { | |||
class = 'imbox-notice', | |||
image = 'Imbox notice.png' | |||
} | |||
} | |||
data.default = 'notice' | |||
data.classes = {'imbox'} | |||
data.classPlainlinksYesno = true | |||
data.imageEmptyCell = true | |||
data.below = true | |||
return p.build(data, args) | |||
end | end | ||
function | function p._cmbox(args) | ||
local data = {} | |||
data.types = { | |||
speedy = { | |||
class = 'cmbox-speedy', | |||
image = 'Cmbox deletion.png' | |||
}, | |||
delete = { | |||
class = 'cmbox-delete', | |||
image = 'Cmbox deletion.png' | |||
}, | |||
content = { | |||
class = 'cmbox-content', | |||
image = 'Cmbox content.png' | |||
}, | |||
style = { | |||
class = 'cmbox-style', | |||
image = 'Edit-clear.svg' | |||
}, | |||
move = { | |||
class = 'cmbox-move', | |||
image = 'Cmbox move.png' | |||
}, | |||
protection = { | |||
class = 'cmbox-protection', | |||
image = 'Cmbox protection.png' | |||
}, | |||
notice = { | |||
class = 'cmbox-notice', | |||
image = 'Cmbox notice.png' | |||
} | |||
} | |||
data.default = 'notice' | |||
data.classes = {'plainlinks', 'cmbox'} | |||
return p.build(data, args) | |||
end | end | ||
----- | function p._tmbox(args) | ||
local data = {} | |||
- | data.types = { | ||
speedy = { | |||
class = 'tmbox-speedy', | |||
image = 'Imbox speedy deletion.png' | |||
}, | |||
delete = { | |||
class = 'tmbox-delete', | |||
image = 'Imbox deletion.png' | |||
}, | |||
content = { | |||
class = 'tmbox-content', | |||
image = 'Imbox content.png' | |||
}, | |||
style = { | |||
class = 'tmbox-style', | |||
image = 'Edit-clear.svg ' | |||
}, | |||
move = { | |||
class = 'tmbox-move', | |||
image = 'Imbox move.png' | |||
}, | |||
protection = { | |||
class = 'tmbox-protection', | |||
image = 'Imbox protection.png' | |||
}, | |||
notice = { | |||
class = 'tmbox-notice', | |||
image = 'Imbox notice.png' | |||
} | |||
} | |||
data.default = 'notice' | |||
data.classes = {'plainlinks', 'tmbox'} | |||
data.allowSmall = true | |||
data.imageRightNone = true | |||
data.imageEmptyCellStyle = true | |||
data.category = 'Talk message boxes' | |||
return p.build(data, args) | |||
end | end | ||
function | local function makeWrapper(func) | ||
return function (frame) | |||
-- If called via #invoke, use the args passed into the invoking | |||
-- template, or the args passed to #invoke if any exist. Otherwise | |||
-- assume args are being passed directly in from the debug console | |||
-- or from another Lua module. | |||
local origArgs | |||
if frame == mw.getCurrentFrame() then | |||
origArgs = frame:getParent().args | |||
for k, v in pairs(frame.args) do | |||
origArgs = frame.args | |||
break | |||
end | |||
else | |||
origArgs = frame | |||
end | |||
-- Trim whitespace and remove blank arguments. | |||
local args = {} | |||
for k, v in pairs(origArgs) do | |||
if type(v) == 'string' then | |||
v = mw.text.trim(v) | |||
end | |||
if v ~= '' or k == 'talk' or k == 'sect' or k == 'date' then | |||
args[k] = v | |||
end | |||
end | |||
return func(args) | |||
end | |||
end | end | ||
p.ambox = makeWrapper(p._ambox) | |||
p.fmbox = makeWrapper(p._fmbox) | |||
p.imbox = makeWrapper(p._imbox) | |||
p.ombox = makeWrapper(p._ombox) | |||
p.cmbox = makeWrapper(p._cmbox) | |||
p.tmbox = makeWrapper(p._tmbox) | |||
return | return p |