「モジュール:削除依頼ログ/sandbox」の版間の差分
表示
削除された内容 追加された内容
編集の要約なし |
|||
(同じ利用者による、間の40版が非表示) | |||
1行目: | 1行目: | ||
local yesno = require('Module:Yesno') |
local yesno = require('Module:Yesno') |
||
local mMessageBox = require('Module:Message box') |
|||
---Check whether an array includes a certain value |
|||
local TEMPLATE_PAGE = 'Template:Old XfD multi' |
|||
---@param array table |
|||
---@param value any |
|||
---@return boolean |
|||
local function includes(array, value) |
|||
for _, v in ipairs(array) do |
|||
if v == value then |
|||
return true |
|||
end |
|||
end |
|||
return false |
|||
end |
|||
---Push a value into an array if the array doesn't already have the value |
|||
---@param array table |
|||
---@param value any |
|||
local function push(array, value) |
|||
if not includes(array, value) then |
|||
table.insert(array, value) |
|||
end |
|||
end |
|||
------------------------------------------------------------------------------- |
------------------------------------------------------------------------------- |
||
-- |
-- AfDLog class |
||
------------------------------------------------------------------------------- |
------------------------------------------------------------------------------- |
||
local |
local AfDLog = {} |
||
AfDLog.__index = AfDLog |
|||
local success, exists = pcall(function () |
|||
local title = mw.title.new(page) |
|||
return title.exists |
|||
end) |
|||
return success and exists |
|||
end |
|||
---Create a new AfDLog object instance. |
|||
local function getAfdPage(page) |
|||
---@param args table |
|||
if page and mw.title.new(page) then |
|||
---@return AfDLog |
|||
if mw.title.new(page).namespace ~= 0 then |
|||
function AfDLog.new(args) |
|||
return page |
|||
else |
|||
return 'Wikipedia:Articles for deletion/' .. page |
|||
end |
|||
else return nil |
|||
end |
|||
end |
|||
local |
local self = setmetatable({}, AfDLog) |
||
if page and mw.title.new(page) then |
|||
if mw.title.new(page).rootPageTitle.fullText == 'Wikipedia:Votes for deletion' then |
|||
return page |
|||
else |
|||
return 'Wikipedia:Votes for deletion/' .. page |
|||
end |
|||
else return nil |
|||
end |
|||
end |
|||
-- Set class properties |
|||
local function makeWikilink(page, display) |
|||
display = display or 'discussion' |
|||
if page then |
|||
return string.format('[[%s|%s]]', page, display) |
|||
else |
|||
return display --probably a bad title |
|||
end |
|||
end |
|||
self.talk = not not yesno(args.talk) -- Whether the log is for the talk page |
|||
local function makeUrlLink(page, display) |
|||
self.collapse = tonumber(args.collapse) or not not yesno(args.collapse) -- Whether to collapse some data rows |
|||
display = display or 'discussion' |
|||
self.numbered = true --yesno(args.numbered) == nil or not not yesno(args.numbered) -- Disabled parameter |
|||
return string.format('[%s %s]', page, display) |
|||
self.reversed = yesno(args.reversed) == nil or not not yesno(args.reversed) -- Whether to reverse the order of data rows |
|||
end |
|||
self.currentTitle = mw.title.getCurrentTitle() -- The title object for the current page |
|||
self.omitCat = (function() -- Whether to omit error categories |
|||
local patterns = { |
|||
'^Template:(削除依頼ログ)$', |
|||
'^Template:(削除依頼ログ/.+)$', |
|||
'^Template:(削除済みノート[23]?)$', |
|||
'^Template:(削除済みノート[23]?/.+)$', |
|||
'^Template:(不削除ノート)$', |
|||
'^Template:(不削除ノート/.+)$', |
|||
'^Template:(特定版削除済みノート)$', |
|||
'^Template:(特定版削除済みノート/.+)$', |
|||
'^Template:(削除済みノートページ2?)$', |
|||
'^Template:(削除済みノートページ2?/.+)$' |
|||
} |
|||
for _, pat in ipairs(patterns) do |
|||
if string.find(self.currentTitle.prefixedText, pat) then |
|||
return true |
|||
end |
|||
end |
|||
return false |
|||
end)() |
|||
self.pageList = {} -- Keyed by pagetitles and valued by boolean values (true for existing pages) |
|||
self.errors = { -- Used to add error categories |
|||
invalidPage = false, -- True if some page doesn't exist |
|||
invalidDate = false, -- True if some date parameter has an unsupported format |
|||
badParameters = {}, -- An array of names of undefined parameter keys |
|||
cats = {} -- An array of error categories (`%s` in `Category:削除依頼ログエラー/%s`) |
|||
} |
|||
self._suppressPageError = args._suppressPageError == 'true' -- Private parameter |
|||
self.pageType = 'ページ' -- 「この`pageType`は過去に削除依頼の...」 |
|||
self.rowData = {} -- An array of objects to render row data |
|||
-- Get page type |
|||
local function pageTypeName(title) |
|||
if self.talk then |
|||
local display = mw.ustring.lower(title.subjectNsText) |
|||
self.pageType = 'ノート' |
|||
local pageTypes = { |
|||
else |
|||
[''] = 'article', |
|||
local subjTitle = self.currentTitle.subjectPageTitle |
|||
['user'] = 'user page', |
|||
local pageTypes = { |
|||
['wikipedia'] = 'project page', |
|||
[0] = '記事', |
|||
['mediawiki'] = 'interface page', |
|||
[2] = '利用者ページ', |
|||
['help'] = 'help page' |
|||
[4] = 'プロジェクトページ', |
|||
} |
|||
[6] = 'ファイル', |
|||
if pageTypes[display] then display = pageTypes[display] end |
|||
[8] = 'インターフェースページ', |
|||
return display |
|||
[10] = 'テンプレート', |
|||
end |
|||
[12] = 'ヘルプページ', |
|||
[14] = 'カテゴリ', |
|||
[100] = 'ポータル', |
|||
[102] = 'プロジェクト', |
|||
[828] = 'モジュール' |
|||
} |
|||
if pageTypes[subjTitle.namespace] then |
|||
self.pageType = pageTypes[subjTitle.namespace] |
|||
end |
|||
end |
|||
-- Process data paremeters (result, page, date) |
|||
local function cleanupTitle(title) |
|||
if not title then return title end |
|||
title = mw.uri.decode(title, 'PATH') |
|||
title = string.gsub(title, '|.*', '') |
|||
title = string.gsub(title, '[%[%]{}]', '') |
|||
return title |
|||
end |
|||
---@param date string |
|||
------------------------------------------------------------------------------- |
|||
---@return string|nil YYYY年MM月DD日 Nil if the input date has an unsupported format |
|||
-- OldAfdMulti class |
|||
local function formatDate(date) |
|||
------------------------------------------------------------------------------- |
|||
local patterns = { |
|||
'^(%d%d%d%d)年(%d%d?)月(%d%d?)日$', |
|||
'^(%d%d%d%d)年(%d%d?)月$', |
|||
'^(%d%d%d%d)%-(%d%d)%-(%d%d)T%d%d:%d%d:%d%dZ?$', |
|||
'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', |
|||
'^(%d%d%d%d)%-(%d%d)$' |
|||
} |
|||
for _, pat in ipairs(patterns) do |
|||
local y, m, d = string.match(date, pat) |
|||
if y and m then |
|||
return string.format('%s%s%s', |
|||
y:gsub('^0', '') .. '年', |
|||
m:gsub('^0', '') .. '月', |
|||
d and d:gsub('^0', '') .. '日' or '' |
|||
) |
|||
end |
|||
end |
|||
return nil |
|||
end |
|||
---@param prefix "result" | "page" | "fullpage" | "display" | "date" | "note" |
|||
local OldAfdMulti = {} |
|||
---@param num number |
|||
OldAfdMulti.__index = OldAfdMulti |
|||
---@param val string |
|||
local function setRowData(prefix, num, val) |
|||
if not self.rowData[num] then -- Set default data |
|||
self.rowData[num] = { |
|||
result = '削除', |
|||
page = 'Wikipedia:削除依頼/', -- No automatic substitution: Causes problems if the page is moved afterwards |
|||
fullpage = nil, |
|||
display = nil, |
|||
date = nil, |
|||
note = nil |
|||
} |
|||
end |
|||
if prefix == 'page' then |
|||
-- Remove leading/trailing brackets and spaces |
|||
-- Note: 'page' is a subpage name and leading spaces shouldn't be removed (XXX/A and XXX/_A are different) |
|||
local m = string.match(val, '^%[*(.-)[%s_%]]*$') |
|||
if m then |
|||
val = 'Wikipedia:削除依頼/' .. m |
|||
end |
|||
elseif prefix == 'fullpage' then |
|||
-- Remove leading/trailing brackets and spaces |
|||
local m = string.match(val, '^[%s_%[]*(.-)[%s_%]]*$') |
|||
if m then |
|||
val = m |
|||
end |
|||
elseif prefix == 'date' then |
|||
local date = formatDate(val) |
|||
if date then |
|||
val = date |
|||
else |
|||
self.errors.invalidDate = true |
|||
return |
|||
end |
|||
end |
|||
self.rowData[num][prefix] = val -- Set the specified data |
|||
end |
|||
-- List of accepted parameter names; true for ordered parameters and false for unordered ones |
|||
function OldAfdMulti.new(args) |
|||
local acceptedPrefixes = { |
|||
local self = setmetatable({}, OldAfdMulti) |
|||
result = true, |
|||
self.currentTitle = mw.title.getCurrentTitle() |
|||
page = true, |
|||
fullpage = true, |
|||
display = true, |
|||
date = true, |
|||
note = true, |
|||
talk = false, |
|||
collapse = false, |
|||
reversed = false, |
|||
_suppresspageerror = false, -- Private parameter |
|||
-- numbered = false -- Disabled parameter |
|||
} |
|||
-- Preprocess the row args for easier looping. |
|||
self.rowData = {} |
|||
for k, v in pairs(args) do |
for k, v in pairs(args) do |
||
local key = mw.ustring.lower(k) |
|||
if type(k) == 'string' then |
|||
local prefix, num = key:match('^(.-)(%d*)$') |
|||
if prefix and acceptedPrefixes[prefix] ~= nil and num ~= '0' then |
|||
num = tonumber(num) |
|||
if acceptedPrefixes[prefix] == true and num then |
|||
setRowData(prefix, num, v) |
|||
prefix == 'date' or |
|||
elseif acceptedPrefixes[prefix] == false and not num then |
|||
prefix == 'page' or |
|||
-- Do nothing |
|||
prefix == 'link' or |
|||
else |
|||
prefix == 'caption' or |
|||
push(self.errors.badParameters, k) |
|||
prefix == 'votepage' or |
|||
end |
|||
prefix == 'merge' |
|||
else |
|||
then |
|||
push(self.errors.badParameters, k) |
|||
self.rowData[num] = self.rowData[num] or {} |
|||
end |
|||
self.rowData[num][prefix] = v |
|||
if v and v ~= '' and prefix=='merge' then |
|||
self.isMerge = true |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
end |
||
-- Set aliases for parameters ending in "1". |
|||
---Remove any gaps in the array we made. |
|||
if self.rowData[1] then |
|||
---@param t table |
|||
self.rowData[1].result = self.rowData[1].result or args.result |
|||
---@return table |
|||
self.rowData[1].date = self.rowData[1].date or args.date |
|||
self.rowData[1].page = self.rowData[1].page or args.page |
|||
self.rowData[1].votepage = self.rowData[1].votepage or args.votepage |
|||
self.rowData[1].link = self.rowData[1].link or args.link |
|||
self.rowData[1].caption = self.rowData[1].caption or args.caption |
|||
self.rowData[1].merge = self.rowData[1].merge or args.merge |
|||
elseif args.result or |
|||
args.date or |
|||
args.page or |
|||
args.votepage or |
|||
args.link or |
|||
args.caption or |
|||
args.merge |
|||
then |
|||
self.rowData[1] = { |
|||
result = args.result, |
|||
date = args.date, |
|||
page = args.page, |
|||
votepage = args.votepage, |
|||
link = args.link, |
|||
caption = args.caption, |
|||
merge = args.merge |
|||
} |
|||
end |
|||
-- Remove any gaps in the array we made. |
|||
local function compressSparseArray(t) |
local function compressSparseArray(t) |
||
local ret, nums = {}, {} |
local ret, nums = {}, {} |
||
for num, |
for num, _ in pairs(t) do |
||
nums[#nums + 1] = num |
nums[#nums + 1] = num |
||
end |
end |
||
147行目: | 209行目: | ||
end |
end |
||
self.rowData = compressSparseArray(self.rowData) |
self.rowData = compressSparseArray(self.rowData) |
||
-- Set aliases that apply to all of the data tables. |
|||
for i, data in ipairs(self.rowData) do |
|||
data.page = data.page or data.votepage |
|||
data.page = cleanupTitle(data.page) |
|||
data.votepage = nil |
|||
end |
|||
-- Set collapsedness |
|||
self.collapse = tonumber(args.collapse) |
|||
if not self.collapse then |
|||
self.collapse = yesno(args.collapse) |
|||
end |
|||
-- Set other properties |
|||
self.isNumbered = yesno(args.numbered) |
|||
self.isSmall = yesno(args.small) |
|||
self.pageType = args.type or pageTypeName(self.currentTitle) |
|||
if args.merge and args.merge ~= '' then |
|||
self.isMerge = true |
|||
end |
|||
self.deletion = args.deletion |
|||
return self |
return self |
||
end |
|||
function OldAfdMulti:renderResult(result) |
|||
return result or "'''Keep'''" |
|||
end |
end |
||
---Render the AfDLog instance as a message box. |
|||
function OldAfdMulti:renderDate(date) |
|||
---@return string |
|||
if date then |
|||
function AfDLog:renderBox() |
|||
return date |
|||
return require('Module:Message box').main('tmbox', { |
|||
else |
|||
type = 'notice', |
|||
self.hasMissingDate = true |
|||
image = '[[File:Clipboard.svg|35px|削除依頼]]', |
|||
return string.format( |
|||
text = self:renderBoxText() |
|||
'<sup>%s[[%s|date missing]]%s</sup>', |
|||
}) |
|||
mw.text.nowiki('['), |
|||
TEMPLATE_PAGE, |
|||
mw.text.nowiki(']') |
|||
) |
|||
end |
|||
end |
end |
||
function AfDLog:renderBoxText() |
|||
function OldAfdMulti:renderPageText(linkFunc, page, caption) |
|||
return string.format(', see %s.', linkFunc(page, caption)) |
|||
end |
|||
local nRows = #self.rowData |
|||
function OldAfdMulti:renderRow(result, date, link, merge) |
|||
local |
local ret = {} |
||
local date = self:renderDate(date) |
|||
local mergeText = '' |
|||
if merge and merge ~= '' then |
|||
mergeText = string.format('Merge with [[:%s]]: ', merge) |
|||
end |
|||
if link then |
|||
return string.format('%s%s, %s, see %s.', mergeText, result, date, link) |
|||
else |
|||
return string.format('%s%s, %s', mergeText, result, date) |
|||
end |
|||
end |
|||
if nRows == 1 and self.rowData[1].date then |
|||
function OldAfdMulti:renderFirstRow(data) |
|||
ret[#ret + 1] = string.format( |
|||
local link |
|||
'この%sは%sに[[Wikipedia:削除依頼|削除依頼]]の審議対象になりました。', |
|||
if data.link then |
|||
self.pageType, |
|||
link = makeUrlLink(data.link, data.caption) |
|||
self.rowData[1].date |
|||
else |
|||
) |
|||
local page = data.page or self.currentTitle.text |
|||
else |
|||
link = makeWikilink(getAfdPage(page), data.caption) |
|||
ret[#ret + 1] = string.format( |
|||
'この%sは過去に[[Wikipedia:削除依頼|削除依頼]]の審議対象になりました。', |
|||
self.pageType |
|||
) |
|||
end |
|||
if nRows > 1 then |
|||
ret[#ret + 1] = '新しく依頼を提出する場合、以下を参考にしてください。\n' |
|||
ret[#ret + 1] = self:renderMultipleRows() |
|||
elseif nRows == 1 then |
|||
ret[#ret + 1] = self:renderFirstRow() |
|||
else -- There's no rowData |
|||
-- Do nothing |
|||
end |
end |
||
return self:renderRow(data.result, data.date, link, data.merge) |
|||
end |
|||
ret[#ret + 1] = self:renderErrors() |
|||
function OldAfdMulti:renderSubsequentRow(data) |
|||
local link |
|||
return table.concat(ret) |
|||
if data.page then |
|||
link = makeWikilink(getAfdPage(data.page), data.caption) |
|||
elseif data.link then |
|||
link = makeUrlLink(data.link, data.caption) |
|||
end |
|||
return self:renderRow(data.result, data.date, link, data.merge) |
|||
end |
end |
||
function |
function AfDLog:renderMultipleRows() |
||
local root = mw.html.create() |
local root = mw.html.create() |
||
local nRows = #self.rowData |
local nRows = #self.rowData |
||
local i = nRows |
local i = self.reversed and nRows or 1 |
||
local nCollapsedRows |
local nCollapsedRows |
||
259行目: | 287行目: | ||
:tag('tr') |
:tag('tr') |
||
:tag('td') |
:tag('td') |
||
:tag(self. |
:tag(self.numbered and 'ol' or 'ul') |
||
end |
|||
local function renderRow(html, method, data) |
|||
html |
|||
:tag('li') |
|||
:attr('value', self.isNumbered and i or nil) |
|||
:wikitext(self[method](self, data)) |
|||
end |
end |
||
272行目: | 293行目: | ||
if hasNormalRows then |
if hasNormalRows then |
||
local normalList = makeList(false) |
local normalList = makeList(false) |
||
if self.reversed then |
|||
while i > 1 and i > nCollapsedRows do |
|||
while i >= 1 and i > nCollapsedRows do |
|||
renderRow(normalList, 'renderSubsequentRow', self.rowData[i]) |
|||
self:renderRow(i, normalList) |
|||
i = i - 1 |
|||
i = i - 1 |
|||
end |
|||
end |
|||
if i == 1 and i > nCollapsedRows then |
|||
else |
|||
renderRow(normalList, 'renderFirstRow', self.rowData[i]) |
|||
while i <= nRows - nCollapsedRows do |
|||
i = i - 1 |
|||
self:renderRow(i, normalList) |
|||
end |
|||
i = i + 1 |
|||
end |
|||
end |
|||
end |
end |
||
286行目: | 310行目: | ||
local header |
local header |
||
if hasNormalRows then |
if hasNormalRows then |
||
header = ' |
header = '過去の削除依頼:' |
||
elseif nRows > 1 then |
|||
header = 'Deletion discussions:' |
|||
else |
else |
||
header = ' |
header = '削除依頼:' |
||
end |
end |
||
local collapsedList = makeList(true, header) |
local collapsedList = makeList(true, header) |
||
if self.reversed then |
|||
while i > 1 do |
|||
while i >= 1 do |
|||
renderRow(collapsedList, 'renderSubsequentRow', self.rowData[i]) |
|||
self:renderRow(i, collapsedList) |
|||
i = i - 1 |
|||
i = i - 1 |
|||
end |
|||
end |
|||
renderRow(collapsedList, 'renderFirstRow', self.rowData[i]) |
|||
else |
|||
while i <= nRows do |
|||
self:renderRow(i, collapsedList) |
|||
i = i + 1 |
|||
end |
|||
end |
|||
end |
end |
||
return tostring(root) |
return tostring(root) |
||
end |
end |
||
function |
function AfDLog:renderRow(rowNum, html) |
||
local data = self.rowData[rowNum] |
|||
local link = self:addPage(data) |
|||
local caption = data.caption or 'the discussion' |
|||
local wkt |
|||
if data.date and data.note then |
|||
wkt = string.format('<b>%s</b> %s (%s; %s)', data.result, link, data.date, data.note) |
|||
link = makeUrlLink(data.link, caption) |
|||
elseif data.date or data.note then |
|||
else |
|||
wkt = string.format('<b>%s</b> %s (%s)', data.result, link, data.date or data.note) |
|||
local page = data.page or self.currentTitle.text |
|||
else |
|||
if exists(getAfdPage(page)) then |
|||
wkt = string.format('<b>%s</b> %s', data.result, link) |
|||
link = makeWikilink(getAfdPage(page), caption) |
|||
end |
|||
elseif exists(getVfdPage(page)) then |
|||
html |
|||
link = makeWikilink(getVfdPage(page), caption) |
|||
:tag('li') |
|||
else |
|||
:attr('value', self.numbered and rowNum or nil) |
|||
link = caption -- Make this an error? |
|||
:wikitext(wkt) |
|||
end |
|||
end |
|||
local result = self:renderResult(data.result or "'''keep'''") |
|||
return string.format( |
|||
'The result of %s was %s.', |
|||
link, result |
|||
) |
|||
end |
end |
||
function |
function AfDLog:renderFirstRow() |
||
local |
local data = self.rowData[1] |
||
local ret = {} |
|||
if data.fullpage then |
|||
ret[#ret + 1] = string.format( |
|||
if nRows < 1 or not self.rowData[1].date then |
|||
'詳細は%sをご覧ください。', |
|||
ret[#ret + 1] = string.format( |
|||
self:addPage(data) |
|||
'This %s was previously nominated for %s.', |
|||
) |
|||
self.pageType, |
|||
else |
|||
self.deletion |
|||
ret[#ret + 1] = string.format( |
|||
) |
|||
'%sの結果、<b>%s</b>となりました。', |
|||
elseif nRows == 1 and self.rowData[1].date then |
|||
self:addPage(data, '議論'), |
|||
ret[#ret + 1] = string.format( |
|||
data.result |
|||
'This %s was nominated for %s on %s.', |
|||
) |
|||
self.pageType, |
|||
end |
|||
self.deletion, |
|||
if data.note then |
|||
self.rowData[1].date |
|||
ret[#ret + 1] = string.format('(%s)', data.note) |
|||
) |
|||
end |
|||
else |
|||
return table.concat(ret) |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was nominated for %s.', |
|||
self.pageType, |
|||
self.deletion |
|||
) |
|||
end |
|||
elseif self.isMerge then |
|||
if nRows < 1 or not self.rowData[1].date then |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was considered for [[Wikipedia:Deletion policy#Merging|merging]] with %s.', |
|||
self.pageType, |
|||
self.rowData[1].merge |
|||
) |
|||
elseif nRows == 1 and self.rowData[1].date then |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was considered for [[Wikipedia:Deletion policy#Merging|merging]] with [[:%s]] on %s.', |
|||
self.pageType, |
|||
self.rowData[1].merge, |
|||
self.rowData[1].date |
|||
) |
|||
else |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was nominated for [[Wikipedia:Deletion policy|deletion]] or considered for [[Wikipedia:Deletion policy#Merging|merging]].', |
|||
self.pageType |
|||
) |
|||
end |
|||
else |
|||
if nRows < 1 or not self.rowData[1].date then |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was previously nominated for [[Wikipedia:Deletion policy|deletion]].', |
|||
self.pageType |
|||
) |
|||
elseif nRows == 1 and self.rowData[1].date then |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was nominated for [[Wikipedia:Deletion policy|deletion]] on %s.', |
|||
self.pageType, |
|||
self.rowData[1].date |
|||
) |
|||
else |
|||
ret[#ret + 1] = string.format( |
|||
'This %s was nominated for [[Wikipedia:Deletion policy|deletion]].', |
|||
self.pageType |
|||
) |
|||
end |
|||
end |
|||
if nRows > 1 then |
|||
ret[#ret + 1] = ' ' |
|||
if self.isSmall then |
|||
ret[#ret + 1] = 'Review prior discussions if considering re-nomination:' |
|||
else |
|||
ret[#ret + 1] = 'Please review the prior discussions if you are considering re-nomination:' |
|||
end |
|||
ret[#ret + 1] = '\n' |
|||
ret[#ret + 1] = self:renderRows() |
|||
else |
|||
ret[#ret + 1] = ' ' |
|||
ret[#ret + 1] = self:renderFirstRowOnly() |
|||
end |
|||
return table.concat(ret) |
|||
end |
end |
||
---Clean up pagetitle, check its existence, and set the 'invalidPage' parameter to true if there's a problem. |
|||
function OldAfdMulti:renderBanner() |
|||
---@param data table rowData object |
|||
return mMessageBox.main('tmbox', { |
|||
---@param caption? string Priority: caption > data.display > data.fullpage > data.page (default) |
|||
small = self.isSmall, |
|||
---@return string wikilink |
|||
type = 'notice', |
|||
function AfDLog:addPage(data, caption) |
|||
image = '[[File:Clipboard.svg|35px|Articles for deletion]]', |
|||
caption = string.gsub(caption or data.display or data.fullpage or data.page, '_', ' ') |
|||
smallimage = 'none', |
|||
local key = data.fullpage and 'fullpage' or 'page' -- Override 'page' by 'fullpage' if the latter is specified |
|||
text = self:renderBannerText() |
|||
local title = mw.title.new(data[key]) |
|||
}) |
|||
local isValidPage = title and data[key] ~= 'Wikipedia:削除依頼/' |
|||
if isValidPage then |
|||
data[key] = title.prefixedText |
|||
if self.pageList[data[key]] == nil and not self._suppressPageError then |
|||
self.pageList[data[key]] = title.exists |
|||
else |
|||
self.pageList[data[key]] = true |
|||
end |
|||
else |
|||
self.pageList[data[key]] = false |
|||
end |
|||
if not self.errors.invalidPage and not self.pageList[data[key]] then |
|||
self.errors.invalidPage = true |
|||
end |
|||
if isValidPage then |
|||
return string.format( |
|||
'[[:%s|%s]]', |
|||
title.prefixedText .. (title.fragment ~= '' and ('#' .. title.fragment) or ''), |
|||
caption |
|||
) |
|||
else |
|||
return string.format( |
|||
'%s%s%s', |
|||
mw.text.nowiki('[['), |
|||
data[key], |
|||
mw.text.nowiki(']]') |
|||
) |
|||
end |
|||
end |
end |
||
function |
function AfDLog:renderErrors() |
||
local ret = {} |
|||
local function errorMessage(code) |
|||
if self.hasMissingDate and self.currentTitle.isTalkPage then |
|||
return string.format('<strong class="error" style="display:block;">エラー: %s</strong>', code) |
|||
ret[#ret + 1] = '[[Category:Old XfD multi templates with errors]]' |
|||
end |
|||
local ret = {} |
|||
if not self.rowData[1] then |
|||
ret[#ret + 1] = errorMessage('必須引数が指定されていません') |
|||
self:addCategory('引数未指定') |
|||
end |
|||
if #self.errors.badParameters > 0 then |
|||
ret[#ret + 1] = errorMessage(string.format( |
|||
'不正な引数が指定されています (%s)', |
|||
table.concat(self.errors.badParameters, ', ') |
|||
)) |
|||
self:addCategory('不正な引数') |
|||
end |
|||
if self.errors.invalidPage then |
|||
ret[#ret + 1] = errorMessage('不正なページ名が指定されています') |
|||
self:addCategory('不正なページ名') |
|||
end |
|||
if self.errors.invalidDate then |
|||
self:addCategory('不正なdate引数') |
|||
end |
|||
ret[#ret + 1] = self:renderCategories() |
|||
return table.concat(ret) |
|||
end |
|||
function AfDLog:addCategory(subcat) |
|||
push(self.errors.cats, subcat) |
|||
end |
|||
function AfDLog:renderCategories() |
|||
if self.omitCat then |
|||
return '' |
|||
end |
|||
local ret = {} |
|||
for _, subcat in ipairs(self.errors.cats) do |
|||
ret[#ret + 1] = string.format('[[Category:削除依頼ログエラー/%s]]', subcat) |
|||
end |
|||
if #ret > 0 then |
|||
ret[#ret + 1] = '[[Category:削除依頼ログエラー]]' |
|||
end |
|||
return table.concat(ret) |
return table.concat(ret) |
||
end |
end |
||
---@param rowNum? number If given, return a row, not a template |
|||
function OldAfdMulti:__tostring() |
|||
---@return string |
|||
return self:renderBanner() .. self:renderTrackingCategories() |
|||
function AfDLog:renderRawTemplate(rowNum) |
|||
local ret = {} |
|||
local function pushIfRowNumIsNil(str) |
|||
if not rowNum then |
|||
table.insert(ret, str) |
|||
end |
|||
end |
|||
pushIfRowNumIsNil('{{削除依頼ログ/sandbox') |
|||
for i, data in ipairs(self.rowData) do |
|||
pushIfRowNumIsNil('\n') |
|||
ret[#ret + 1] = string.format('|result%s=%s', rowNum or i, data.result) |
|||
if data.fullpage then |
|||
ret[#ret + 1] = string.format('|fullpage%s=%s', rowNum or i, data.fullpage) |
|||
else |
|||
ret[#ret + 1] = string.format('|page%s=%s', rowNum or i, string.gsub(data.page, '^Wikipedia:削除依頼/', '')) |
|||
end |
|||
if data.display then |
|||
ret[#ret + 1] = string.format('|display%s=%s', rowNum or i, data.display) |
|||
end |
|||
ret[#ret + 1] = string.format('|date%s=%s', rowNum or i, data.date or '') |
|||
if data.note then |
|||
ret[#ret + 1] = string.format('|note%s=%s', rowNum or i, data.note) |
|||
end |
|||
end |
|||
pushIfRowNumIsNil('\n|talk=' .. tostring(self.talk)) |
|||
-- pushIfRowNumIsNil('\n|collapse=' .. tostring(self.collapse)) |
|||
-- pushIfRowNumIsNil('\n|numbered=' .. tostring(self.numbered)) |
|||
pushIfRowNumIsNil('\n}}') |
|||
return table.concat(ret) |
|||
end |
end |
||
435行目: | 502行目: | ||
function p._main(args) |
function p._main(args) |
||
local afd = OldAfdMulti.new(args) |
|||
local afd = AfDLog.new(args) |
|||
return tostring(afd) |
|||
local caller = mw.getCurrentFrame():getParent():getTitle() |
|||
local substPatterns = { -- Templates that must be transcluded with `subst:` |
|||
'^Template:(削除済みノート[23]?)$', |
|||
'^Template:(削除済みノート[23]?/.+)$', |
|||
'^Template:(不削除ノート)$', |
|||
'^Template:(不削除ノート/.+)$', |
|||
'^Template:(特定版削除済みノート)$', |
|||
'^Template:(特定版削除済みノート/.+)$', |
|||
'^Template:(削除済みノートページ2?)$', |
|||
'^Template:(削除済みノートページ2?/.+)$' |
|||
} |
|||
local callerTitle |
|||
for _, pat in ipairs(substPatterns) do |
|||
callerTitle = caller:match(pat) |
|||
if callerTitle then break end |
|||
end |
|||
if mw.isSubsting() then |
|||
local rowNum |
|||
if args.n then |
|||
rowNum = string.match(args.n, '^(%d+)$') or 2 |
|||
end |
|||
return afd:renderRawTemplate(rowNum) |
|||
elseif callerTitle then |
|||
local ret = {} |
|||
ret[#ret + 1] = '<strong class="error">エラー: ' |
|||
ret[#ret + 1] = '[[Help:テンプレート#テンプレートの内容で置き換える|subst:]] がありません。' |
|||
ret[#ret + 1] = string.format('「%s」ではなく「subst:%s」としてください。', callerTitle, callerTitle) |
|||
ret[#ret + 1] = '</strong>' |
|||
afd:addCategory('subst違反') |
|||
ret[#ret + 1] = afd:renderCategories() |
|||
return table.concat(ret) |
|||
else |
|||
return afd:renderBox() |
|||
end |
|||
end |
end |
||
function p.main(frame) |
function p.main(frame) |
||
local args = require('Module:Arguments').getArgs(frame, { |
local args = require('Module:Arguments').getArgs(frame, { |
||
wrappers = |
wrappers = { |
||
'Template:削除依頼ログ' |
|||
} |
|||
}) |
}) |
||
return p._main(args) |
return p._main(args) |
2023年8月16日 (水) 20:32時点における最新版
これはモジュール:削除依頼ログ (差分)のモジュール・サンドボックスページです。 |
モジュールの解説[作成]
local yesno = require('Module:Yesno')
---Check whether an array includes a certain value
---@param array table
---@param value any
---@return boolean
local function includes(array, value)
for _, v in ipairs(array) do
if v == value then
return true
end
end
return false
end
---Push a value into an array if the array doesn't already have the value
---@param array table
---@param value any
local function push(array, value)
if not includes(array, value) then
table.insert(array, value)
end
end
-------------------------------------------------------------------------------
-- AfDLog class
-------------------------------------------------------------------------------
local AfDLog = {}
AfDLog.__index = AfDLog
---Create a new AfDLog object instance.
---@param args table
---@return AfDLog
function AfDLog.new(args)
local self = setmetatable({}, AfDLog)
-- Set class properties
self.talk = not not yesno(args.talk) -- Whether the log is for the talk page
self.collapse = tonumber(args.collapse) or not not yesno(args.collapse) -- Whether to collapse some data rows
self.numbered = true --yesno(args.numbered) == nil or not not yesno(args.numbered) -- Disabled parameter
self.reversed = yesno(args.reversed) == nil or not not yesno(args.reversed) -- Whether to reverse the order of data rows
self.currentTitle = mw.title.getCurrentTitle() -- The title object for the current page
self.omitCat = (function() -- Whether to omit error categories
local patterns = {
'^Template:(削除依頼ログ)$',
'^Template:(削除依頼ログ/.+)$',
'^Template:(削除済みノート[23]?)$',
'^Template:(削除済みノート[23]?/.+)$',
'^Template:(不削除ノート)$',
'^Template:(不削除ノート/.+)$',
'^Template:(特定版削除済みノート)$',
'^Template:(特定版削除済みノート/.+)$',
'^Template:(削除済みノートページ2?)$',
'^Template:(削除済みノートページ2?/.+)$'
}
for _, pat in ipairs(patterns) do
if string.find(self.currentTitle.prefixedText, pat) then
return true
end
end
return false
end)()
self.pageList = {} -- Keyed by pagetitles and valued by boolean values (true for existing pages)
self.errors = { -- Used to add error categories
invalidPage = false, -- True if some page doesn't exist
invalidDate = false, -- True if some date parameter has an unsupported format
badParameters = {}, -- An array of names of undefined parameter keys
cats = {} -- An array of error categories (`%s` in `Category:削除依頼ログエラー/%s`)
}
self._suppressPageError = args._suppressPageError == 'true' -- Private parameter
self.pageType = 'ページ' -- 「この`pageType`は過去に削除依頼の...」
self.rowData = {} -- An array of objects to render row data
-- Get page type
if self.talk then
self.pageType = 'ノート'
else
local subjTitle = self.currentTitle.subjectPageTitle
local pageTypes = {
[0] = '記事',
[2] = '利用者ページ',
[4] = 'プロジェクトページ',
[6] = 'ファイル',
[8] = 'インターフェースページ',
[10] = 'テンプレート',
[12] = 'ヘルプページ',
[14] = 'カテゴリ',
[100] = 'ポータル',
[102] = 'プロジェクト',
[828] = 'モジュール'
}
if pageTypes[subjTitle.namespace] then
self.pageType = pageTypes[subjTitle.namespace]
end
end
-- Process data paremeters (result, page, date)
---@param date string
---@return string|nil YYYY年MM月DD日 Nil if the input date has an unsupported format
local function formatDate(date)
local patterns = {
'^(%d%d%d%d)年(%d%d?)月(%d%d?)日$',
'^(%d%d%d%d)年(%d%d?)月$',
'^(%d%d%d%d)%-(%d%d)%-(%d%d)T%d%d:%d%d:%d%dZ?$',
'^(%d%d%d%d)%-(%d%d)%-(%d%d)$',
'^(%d%d%d%d)%-(%d%d)$'
}
for _, pat in ipairs(patterns) do
local y, m, d = string.match(date, pat)
if y and m then
return string.format('%s%s%s',
y:gsub('^0', '') .. '年',
m:gsub('^0', '') .. '月',
d and d:gsub('^0', '') .. '日' or ''
)
end
end
return nil
end
---@param prefix "result" | "page" | "fullpage" | "display" | "date" | "note"
---@param num number
---@param val string
local function setRowData(prefix, num, val)
if not self.rowData[num] then -- Set default data
self.rowData[num] = {
result = '削除',
page = 'Wikipedia:削除依頼/', -- No automatic substitution: Causes problems if the page is moved afterwards
fullpage = nil,
display = nil,
date = nil,
note = nil
}
end
if prefix == 'page' then
-- Remove leading/trailing brackets and spaces
-- Note: 'page' is a subpage name and leading spaces shouldn't be removed (XXX/A and XXX/_A are different)
local m = string.match(val, '^%[*(.-)[%s_%]]*$')
if m then
val = 'Wikipedia:削除依頼/' .. m
end
elseif prefix == 'fullpage' then
-- Remove leading/trailing brackets and spaces
local m = string.match(val, '^[%s_%[]*(.-)[%s_%]]*$')
if m then
val = m
end
elseif prefix == 'date' then
local date = formatDate(val)
if date then
val = date
else
self.errors.invalidDate = true
return
end
end
self.rowData[num][prefix] = val -- Set the specified data
end
-- List of accepted parameter names; true for ordered parameters and false for unordered ones
local acceptedPrefixes = {
result = true,
page = true,
fullpage = true,
display = true,
date = true,
note = true,
talk = false,
collapse = false,
reversed = false,
_suppresspageerror = false, -- Private parameter
-- numbered = false -- Disabled parameter
}
for k, v in pairs(args) do
local key = mw.ustring.lower(k)
local prefix, num = key:match('^(.-)(%d*)$')
if prefix and acceptedPrefixes[prefix] ~= nil and num ~= '0' then
num = tonumber(num)
if acceptedPrefixes[prefix] == true and num then
setRowData(prefix, num, v)
elseif acceptedPrefixes[prefix] == false and not num then
-- Do nothing
else
push(self.errors.badParameters, k)
end
else
push(self.errors.badParameters, k)
end
end
---Remove any gaps in the array we made.
---@param t table
---@return table
local function compressSparseArray(t)
local ret, nums = {}, {}
for num, _ in pairs(t) do
nums[#nums + 1] = num
end
table.sort(nums)
for i, num in ipairs(nums) do
ret[i] = t[num]
end
return ret
end
self.rowData = compressSparseArray(self.rowData)
return self
end
---Render the AfDLog instance as a message box.
---@return string
function AfDLog:renderBox()
return require('Module:Message box').main('tmbox', {
type = 'notice',
image = '[[File:Clipboard.svg|35px|削除依頼]]',
text = self:renderBoxText()
})
end
function AfDLog:renderBoxText()
local nRows = #self.rowData
local ret = {}
if nRows == 1 and self.rowData[1].date then
ret[#ret + 1] = string.format(
'この%sは%sに[[Wikipedia:削除依頼|削除依頼]]の審議対象になりました。',
self.pageType,
self.rowData[1].date
)
else
ret[#ret + 1] = string.format(
'この%sは過去に[[Wikipedia:削除依頼|削除依頼]]の審議対象になりました。',
self.pageType
)
end
if nRows > 1 then
ret[#ret + 1] = '新しく依頼を提出する場合、以下を参考にしてください。\n'
ret[#ret + 1] = self:renderMultipleRows()
elseif nRows == 1 then
ret[#ret + 1] = self:renderFirstRow()
else -- There's no rowData
-- Do nothing
end
ret[#ret + 1] = self:renderErrors()
return table.concat(ret)
end
function AfDLog:renderMultipleRows()
local root = mw.html.create()
local nRows = #self.rowData
local i = self.reversed and nRows or 1
local nCollapsedRows
if type(self.collapse) == 'number' then
nCollapsedRows = self.collapse
elseif self.collapse then
nCollapsedRows = nRows
else
nCollapsedRows = 0
end
local hasNormalRows = nRows - nCollapsedRows > 0
local function makeList(isCollapsed, header)
local tableRoot = root:tag('table')
tableRoot
:addClass(isCollapsed and 'mw-collapsible mw-collapsed' or nil)
:css('width', '100%')
:css('background-color', '#f8eaba')
if header then
tableRoot
:tag('tr')
:tag('th')
:wikitext(header)
end
return tableRoot
:tag('tr')
:tag('td')
:tag(self.numbered and 'ol' or 'ul')
end
-- Render normal rows
if hasNormalRows then
local normalList = makeList(false)
if self.reversed then
while i >= 1 and i > nCollapsedRows do
self:renderRow(i, normalList)
i = i - 1
end
else
while i <= nRows - nCollapsedRows do
self:renderRow(i, normalList)
i = i + 1
end
end
end
-- Render collapsed rows
if nCollapsedRows > 0 then
local header
if hasNormalRows then
header = '過去の削除依頼:'
else
header = '削除依頼:'
end
local collapsedList = makeList(true, header)
if self.reversed then
while i >= 1 do
self:renderRow(i, collapsedList)
i = i - 1
end
else
while i <= nRows do
self:renderRow(i, collapsedList)
i = i + 1
end
end
end
return tostring(root)
end
function AfDLog:renderRow(rowNum, html)
local data = self.rowData[rowNum]
local link = self:addPage(data)
local wkt
if data.date and data.note then
wkt = string.format('<b>%s</b> %s (%s; %s)', data.result, link, data.date, data.note)
elseif data.date or data.note then
wkt = string.format('<b>%s</b> %s (%s)', data.result, link, data.date or data.note)
else
wkt = string.format('<b>%s</b> %s', data.result, link)
end
html
:tag('li')
:attr('value', self.numbered and rowNum or nil)
:wikitext(wkt)
end
function AfDLog:renderFirstRow()
local data = self.rowData[1]
local ret = {}
if data.fullpage then
ret[#ret + 1] = string.format(
'詳細は%sをご覧ください。',
self:addPage(data)
)
else
ret[#ret + 1] = string.format(
'%sの結果、<b>%s</b>となりました。',
self:addPage(data, '議論'),
data.result
)
end
if data.note then
ret[#ret + 1] = string.format('(%s)', data.note)
end
return table.concat(ret)
end
---Clean up pagetitle, check its existence, and set the 'invalidPage' parameter to true if there's a problem.
---@param data table rowData object
---@param caption? string Priority: caption > data.display > data.fullpage > data.page (default)
---@return string wikilink
function AfDLog:addPage(data, caption)
caption = string.gsub(caption or data.display or data.fullpage or data.page, '_', ' ')
local key = data.fullpage and 'fullpage' or 'page' -- Override 'page' by 'fullpage' if the latter is specified
local title = mw.title.new(data[key])
local isValidPage = title and data[key] ~= 'Wikipedia:削除依頼/'
if isValidPage then
data[key] = title.prefixedText
if self.pageList[data[key]] == nil and not self._suppressPageError then
self.pageList[data[key]] = title.exists
else
self.pageList[data[key]] = true
end
else
self.pageList[data[key]] = false
end
if not self.errors.invalidPage and not self.pageList[data[key]] then
self.errors.invalidPage = true
end
if isValidPage then
return string.format(
'[[:%s|%s]]',
title.prefixedText .. (title.fragment ~= '' and ('#' .. title.fragment) or ''),
caption
)
else
return string.format(
'%s%s%s',
mw.text.nowiki('[['),
data[key],
mw.text.nowiki(']]')
)
end
end
function AfDLog:renderErrors()
local function errorMessage(code)
return string.format('<strong class="error" style="display:block;">エラー: %s</strong>', code)
end
local ret = {}
if not self.rowData[1] then
ret[#ret + 1] = errorMessage('必須引数が指定されていません')
self:addCategory('引数未指定')
end
if #self.errors.badParameters > 0 then
ret[#ret + 1] = errorMessage(string.format(
'不正な引数が指定されています (%s)',
table.concat(self.errors.badParameters, ', ')
))
self:addCategory('不正な引数')
end
if self.errors.invalidPage then
ret[#ret + 1] = errorMessage('不正なページ名が指定されています')
self:addCategory('不正なページ名')
end
if self.errors.invalidDate then
self:addCategory('不正なdate引数')
end
ret[#ret + 1] = self:renderCategories()
return table.concat(ret)
end
function AfDLog:addCategory(subcat)
push(self.errors.cats, subcat)
end
function AfDLog:renderCategories()
if self.omitCat then
return ''
end
local ret = {}
for _, subcat in ipairs(self.errors.cats) do
ret[#ret + 1] = string.format('[[Category:削除依頼ログエラー/%s]]', subcat)
end
if #ret > 0 then
ret[#ret + 1] = '[[Category:削除依頼ログエラー]]'
end
return table.concat(ret)
end
---@param rowNum? number If given, return a row, not a template
---@return string
function AfDLog:renderRawTemplate(rowNum)
local ret = {}
local function pushIfRowNumIsNil(str)
if not rowNum then
table.insert(ret, str)
end
end
pushIfRowNumIsNil('{{削除依頼ログ/sandbox')
for i, data in ipairs(self.rowData) do
pushIfRowNumIsNil('\n')
ret[#ret + 1] = string.format('|result%s=%s', rowNum or i, data.result)
if data.fullpage then
ret[#ret + 1] = string.format('|fullpage%s=%s', rowNum or i, data.fullpage)
else
ret[#ret + 1] = string.format('|page%s=%s', rowNum or i, string.gsub(data.page, '^Wikipedia:削除依頼/', ''))
end
if data.display then
ret[#ret + 1] = string.format('|display%s=%s', rowNum or i, data.display)
end
ret[#ret + 1] = string.format('|date%s=%s', rowNum or i, data.date or '')
if data.note then
ret[#ret + 1] = string.format('|note%s=%s', rowNum or i, data.note)
end
end
pushIfRowNumIsNil('\n|talk=' .. tostring(self.talk))
-- pushIfRowNumIsNil('\n|collapse=' .. tostring(self.collapse))
-- pushIfRowNumIsNil('\n|numbered=' .. tostring(self.numbered))
pushIfRowNumIsNil('\n}}')
return table.concat(ret)
end
-------------------------------------------------------------------------------
-- Exports
-------------------------------------------------------------------------------
local p = {}
function p._main(args)
local afd = AfDLog.new(args)
local caller = mw.getCurrentFrame():getParent():getTitle()
local substPatterns = { -- Templates that must be transcluded with `subst:`
'^Template:(削除済みノート[23]?)$',
'^Template:(削除済みノート[23]?/.+)$',
'^Template:(不削除ノート)$',
'^Template:(不削除ノート/.+)$',
'^Template:(特定版削除済みノート)$',
'^Template:(特定版削除済みノート/.+)$',
'^Template:(削除済みノートページ2?)$',
'^Template:(削除済みノートページ2?/.+)$'
}
local callerTitle
for _, pat in ipairs(substPatterns) do
callerTitle = caller:match(pat)
if callerTitle then break end
end
if mw.isSubsting() then
local rowNum
if args.n then
rowNum = string.match(args.n, '^(%d+)$') or 2
end
return afd:renderRawTemplate(rowNum)
elseif callerTitle then
local ret = {}
ret[#ret + 1] = '<strong class="error">エラー: '
ret[#ret + 1] = '[[Help:テンプレート#テンプレートの内容で置き換える|subst:]] がありません。'
ret[#ret + 1] = string.format('「%s」ではなく「subst:%s」としてください。', callerTitle, callerTitle)
ret[#ret + 1] = '</strong>'
afd:addCategory('subst違反')
ret[#ret + 1] = afd:renderCategories()
return table.concat(ret)
else
return afd:renderBox()
end
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = {
'Template:削除依頼ログ'
}
})
return p._main(args)
end
return p