モジュール:Infobox/former/sandbox
表示
< モジュール:Infobox | former
これはモジュール:Infobox/former (差分)のモジュール・サンドボックスページです。 |
このLuaモジュールは550,000以上のページで使われています。 余計な混乱やサーバーへの負荷を避けるために、どんな変更でも最初はモジュールのサンドボックス・サブページ、テストケース・サブページで試すべきです。そうすれば、試した変更を1度の編集でこのモジュールに加えることができます。しかし、最初にあなたの提案した変更を、この項目のノートで議論するようにお願いします。 |
local p = {}
local args = {}
local origArgs = {}
local root
local empty_row_categories = {}
local category_in_empty_row_pattern = '%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]'
local function fixChildBoxes(sval, tt)
local function notempty( s ) return s and s:match( '%S' ) end
if notempty(sval) then
local marker = '<span class=special_infobox_marker>'
local s = sval
s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker)
if s:match(marker) then
s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '')
s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1')
s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1')
s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1')
end
if s:match(marker) then
local subcells = mw.text.split(s, marker)
s = ''
for k = 1, #subcells do
if k == 1 then
s = s .. subcells[k] .. '</' .. tt .. '></tr>'
elseif k == #subcells then
local rowstyle = ' style="display:none"'
if notempty(subcells[k]) then rowstyle = '' end
s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' ..
subcells[k]
elseif notempty(subcells[k]) then
if (k % 2) == 0 then
s = s .. subcells[k]
else
s = s .. '<tr><' .. tt .. ' colspan=2>\n' ..
subcells[k] .. '</' .. tt .. '></tr>'
end
end
end
end
-- the next two lines add a newline at the end of lists for the PHP parser
-- [[Special:Diff/849054481]]
-- remove when [[:phab:T191516]] is fixed or OBE
s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1')
s = mw.ustring.gsub(s, '^(%{%|)', '\n%1')
return s
else
return sval
end
end
-- Returns the union of the values of two tables, as a sequence.
local function union(t1, t2)
local vals = {}
for k, v in pairs(t1) do
vals[v] = true
end
for k, v in pairs(t2) do
vals[v] = true
end
local ret = {}
for k, v in pairs(vals) do
table.insert(ret, k)
end
return ret
end
-- Returns a table containing the numbers of the arguments that exist
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local function getArgNums(prefix)
local nums = {}
for k, v in pairs(args) do
local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
if num then table.insert(nums, tonumber(num)) end
end
table.sort(nums)
return nums
end
-- Adds a row to the infobox, with either a header cell
-- or a label/data cell combination.
local function addRow(rowArgs)
if rowArgs.header and rowArgs.header ~= '_BLANK_' then
root
:tag('tr')
:addClass(rowArgs.rowclass)
:cssText(rowArgs.rowstyle)
:tag('th')
:attr('colspan', '2')
:addClass('infobox-header')
:addClass(rowArgs.class)
:addClass(args.headerclass)
-- @deprecated next; target .infobox-<name> .infobox-header
:cssText(args.headerstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.header, 'th'))
if rowArgs.data then
--root:wikitext(
--'[[Category:Pages which use infobox templates with ignored data cells]]'
--)
end
elseif rowArgs.data and rowArgs.data:gsub(
category_in_empty_row_pattern, ''
):match('^%S') then
local row = root:tag('tr')
row:addClass(rowArgs.rowclass)
row:cssText(rowArgs.rowstyle)
if rowArgs.label then
row
:tag('th')
:attr('scope', 'row')
:addClass('infobox-label')
:cssText('white-space:nowrap;')
-- @deprecated next; target .infobox-<name> .infobox-label
:cssText(args.labelstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(rowArgs.label)
:done()
end
local dataCell = row:tag('td')
dataCell
:attr('colspan', not rowArgs.label and '2' or nil)
:addClass(not rowArgs.label and 'infobox-full-data' or 'infobox-data')
:addClass(rowArgs.class)
-- @deprecated next; target .infobox-<name> .infobox(-full)-data
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
else
table.insert(empty_row_categories, rowArgs.data or '')
end
end
local function renderTitle()
if not args.title then return end
root
:tag('caption')
:addClass('infobox-title')
:addClass(args.titleclass)
-- @deprecated next; target .infobox-<name> .infobox-title
:cssText(args.titlestyle)
:attr('itemprop', 'name')
:wikitext(args.title)
end
local function renderAboveRow()
if not args.above then return end
root
:tag('tr')
:tag('th')
:attr('colspan', '2')
:addClass('infobox-above')
:addClass(args.aboveclass)
-- @deprecated next; target .infobox-<name> .infobox-above
:cssText(args.abovestyle)
:attr('itemprop', args.aboveitemprop)
:attr('itemtype', args.aboveitemtype)
:attr('itemref', args.aboveitemref)
:wikitext(fixChildBoxes(args.above,'th'))
end
local function renderBelowRow()
if not args.below then return end
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass('infobox-below')
:addClass(args.belowclass)
-- @deprecated next; target .infobox-<name> .infobox-below
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(args.below,'td'))
end
local function addSubheaderRow(subheaderArgs)
if subheaderArgs.data and
subheaderArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
local row = root:tag('tr')
row:addClass(subheaderArgs.rowclass)
local dataCell = row:tag('td')
dataCell
:attr('colspan', '2')
:addClass('infobox-subheader')
:addClass(subheaderArgs.class)
:cssText(subheaderArgs.datastyle)
:cssText(subheaderArgs.rowcellstyle)
:wikitext(fixChildBoxes(subheaderArgs.data, 'td'))
else
table.insert(empty_row_categories, subheaderArgs.data or '')
end
end
local function renderSubheaders()
if args.subheader then
args.subheader1 = args.subheader
end
if args.subheaderrowclass then
args.subheaderrowclass1 = args.subheaderrowclass
end
local subheadernums = getArgNums('subheader')
for k, num in ipairs(subheadernums) do
addSubheaderRow({
data = args['subheader' .. tostring(num)],
-- @deprecated next; target .infobox-<name> .infobox-subheader
datastyle = args.subheaderstyle,
rowcellstyle = args['subheaderstyle' .. tostring(num)],
class = args.subheaderclass,
rowclass = args['subheaderrowclass' .. tostring(num)]
})
end
end
local function addImageRow(imageArgs)
if imageArgs.data and
imageArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
local row = root:tag('tr')
row:addClass(imageArgs.rowclass)
local dataCell = row:tag('td')
dataCell
:attr('colspan', '2')
:addClass('infobox-image')
:addClass(imageArgs.class)
:cssText(imageArgs.datastyle)
:wikitext(fixChildBoxes(imageArgs.data, 'td'))
else
table.insert(empty_row_categories, imageArgs.data or '')
end
end
local function renderImages()
if args.image then
args.image1 = args.image
end
if args.caption then
args.caption1 = args.caption
end
local imagenums = getArgNums('image')
for k, num in ipairs(imagenums) do
local caption = args['caption' .. tostring(num)]
local data = mw.html.create():wikitext(args['image' .. tostring(num)])
if caption then
data
:tag('div')
:addClass('infobox-caption')
-- @deprecated next; target .infobox-<name> .infobox-caption
:cssText(args.captionstyle)
:wikitext(caption)
end
addImageRow({
data = tostring(data),
-- @deprecated next; target .infobox-<name> .infobox-image
datastyle = args.imagestyle,
class = args.imageclass,
rowclass = args['imagerowclass' .. tostring(num)]
})
end
end
-- When autoheaders are turned on, preprocesses the rows
local function preprocessRows()
if not args.autoheaders then return end
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
local lastheader
for k, num in ipairs(rownums) do
if args['header' .. tostring(num)] then
if lastheader then
args['header' .. tostring(lastheader)] = nil
end
lastheader = num
elseif args['data' .. tostring(num)] and
args['data' .. tostring(num)]:gsub(
category_in_empty_row_pattern, ''
):match('^%S') then
local data = args['data' .. tostring(num)]
if data:gsub(category_in_empty_row_pattern, ''):match('%S') then
lastheader = nil
end
end
end
if lastheader then
args['header' .. tostring(lastheader)] = nil
end
end
-- Gets the union of the header and data argument numbers,
-- and renders them all in order
local function renderRows()
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addRow({
header = args['header' .. tostring(num)],
label = args['label' .. tostring(num)],
data = args['data' .. tostring(num)],
datastyle = args.datastyle,
class = args['class' .. tostring(num)],
rowclass = args['rowclass' .. tostring(num)],
-- @deprecated next; target .infobox-<name> rowclass
rowstyle = args['rowstyle' .. tostring(num)],
rowcellstyle = args['rowcellstyle' .. tostring(num)]
})
end
end
local function renderNavBar()
if not args.name and not args.tnavbar then return end
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass('infobox-navbar')
:wikitext(require('Module:Navbar/sandbox')._navbar{
template = args.name,
text = 'テンプレートを',
})
end
local function loadTemplateStyles()
local frame = mw.getCurrentFrame()
local base_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = 'Template:Infobox/styles.css' }
}
return table.concat({
base_templatestyles,
})
end
local function _infobox()
args = require('Module:Arguments').getArgs(origArgs, {parentOnly = true}) --引数取得
local child = (args.child == 'yes')
local subbox = (args.subbox == 'yes')
local h = {subheader = {}, image = {{}}} --ヘッダー部(subheader, image)テーブル
local body, sbody = {}, {} --本体部テーブル, ソート済み本体部テーブル
local link = args.tnavbar or args.name --(フッター部)テンプレート名
local result = '' --結果格納用
--[[
subheader, image用引数振り分け
]]
local function args2tbl(str, k, v)
local num = string.match(k, '%d*$')
num = (num == '') and 1 or tonumber(num)
h[str][num] = h[str][num] or {}
if k == str then
h[str][1][1] = v
elseif string.match(k, str .. '%d+') then
h[str][num][1] = v
elseif string.find(k, 'style') then
if string.match(k, 'style$') then
h[str]['style'] = v
else
h[str][num]['style'] = v
end
elseif string.find(k, 'rowclass') then
if string.match(k, 'rowclass$') then
h[str]['rowclass'] = v
else
h[str][num]['rowclass'] = v
end
elseif string.match(k, 'class$') then
h[str]['class'] = v
end
end
--[[
引数振り分け
]]
for k, v in pairs(args) do
--subheader
if string.find(k, 'subheader') then
args2tbl('subheader', k, v)
--image
elseif string.find(k, 'image') then
args2tbl('image', k, v)
elseif string.find(k, 'caption') then
if string.match(k, 'caption$') then
h['image'][1]['caption'] = '<div style="' .. (args.captionstyle or '') .. '">' .. v .. '</div>'
elseif string.match(k, 'caption%d+') then
local num = tonumber(string.match(k, '%d*$'))
h['image'][num] = h['image'][num] or {}
h['image'][num]['caption'] = '<div style="' .. (args.captionstyle or '') .. '">' .. v .. '</div>'
end
--その他(本体部)
elseif string.match(k, '^%D+%d+$') then
local str, num = string.match(k, '^(%D+)(%d+)$')
num = tonumber(num)
if not body[num] then
local OddOrEven = (num % 2 ~= 0) and 'odd' or 'even'
body[num] = {
num,
headerstyle = (args.headerstyle or '') .. (args[OddOrEven .. 'headerstyle'] or ''),
labelstyle = (args.labelstyle or '') .. (args[OddOrEven .. 'labelstyle'] or ''),
datastyle = (args.datastyle or '') .. (args[OddOrEven .. 'datastyle'] or '')
}
end
body[num][str] = (body[num][str] or '') .. v
end
end
--[[
Template:Infobox
]]
--ヘッダー部
if not child then
root = mw.html.create('table')
root
:addClass(args.subbox == 'yes' and 'infobox-subbox' or 'infobox')
:addClass(args.bodyclass)
-- @deprecated next; target .infobox-<name>
:cssText(args.subbox == 'yes' and 'min-width:100%; width:calc(100% + 6px); margin:-3px;' or 'width:22em;')
:cssText(args.bodystyle)
:attr('itemtype', args.bodyitemtype)
renderTitle()
renderAboveRow()
else
root = mw.html.create()
root
:tag('b')
:attr('itemprop', 'name')
:attr('itemtype', args.bodyitemtype)
:attr('itemref', args.bodyitemref)
:wikitext(args.title)
end
renderSubheaders()
renderImages()
preprocessRows()
renderRows()
renderBelowRow()
renderNavBar()
--tableタグ閉じ
if not child then
result = result .. '</table>'
end
--出力
return loadTemplateStyles() .. tostring(root)
end
function p.infobox(frame)
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
else
origArgs = frame
end
-- parseDataParameters() -- 後ほど移入する
return _infobox()
end
return p