وحدة:Infobox
توثيق الوحدة [أنشئ] [محو الاختزان][استخدامات] [قوالب]
--
-- This module implements {{بطاقة}}
--
local p = {}
local navbar = require('Module:Navbar')._navbar
local args = {}
local origArgs
local root
local function notempty( s ) return s and s:match( '%S' ) end
local function fixChildBoxes(sval, tt)
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
-- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=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
local function union(t1, t2)
-- Returns the union of the values of two tables, as a sequence.
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
local function getArgNums(prefix)
-- 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 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
local function addRow(rowArgs)
-- Adds a row to the infobox, with either a header cell
-- or a label/data cell combination.
if rowArgs.header and rowArgs.header ~= '_BLANK_' then
root
:tag('tr')
:addClass(rowArgs.rowclass)
:cssText(rowArgs.rowstyle)
:attr('id', rowArgs.rowid)
:tag('th')
:attr('colspan', 2)
:attr('id', rowArgs.headerid)
:addClass(rowArgs.class)
:addClass(args.headerclass)
:css('text-align', 'center')
:cssText(args.headerstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.header, 'th'))
if rowArgs.data then
root:wikitext('[[تصنيف:Pages which use infobox templates with ignored data cells]]')
end
elseif rowArgs.data then
if not rowArgs.data:gsub('%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]', ''):match('^%S') then
rowArgs.rowstyle = 'display:none'
end
local row = root:tag('tr')
row:addClass(rowArgs.rowclass)
row:cssText(rowArgs.rowstyle)
row:attr('id', rowArgs.rowid)
if rowArgs.label then
row
:tag('th')
:attr('scope', 'row')
:attr('id', rowArgs.labelid)
:cssText(args.labelstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(rowArgs.label)
:done()
end
local dataCell = row:tag('td')
if not rowArgs.label then
dataCell
:attr('colspan', 2)
:css('text-align', 'center')
end
dataCell
:attr('id', rowArgs.dataid)
:addClass(rowArgs.class)
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
end
end
local function renderTitle()
if not args.title then return end
root
:tag('caption')
:addClass(args.titleclass)
:cssText(args.titlestyle)
:wikitext(args.title)
end
local function renderAboveRow()
if not args.above then return end
root
:tag('tr')
:tag('th')
:attr('colspan', 2)
:addClass(args.aboveclass)
:css('text-align', 'center')
:css('font-size', '125%')
:css('font-weight', 'bold')
:cssText(args.abovestyle)
: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(args.belowclass)
:css('text-align', 'center')
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(args.below,'td'))
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
addRow({
data = args['subheader' .. tostring(num)],
datastyle = args.subheaderstyle,
rowcellstyle = args['subheaderstyle' .. tostring(num)],
class = args.subheaderclass,
rowclass = args['subheaderrowclass' .. tostring(num)]
})
end
end
local function renderImages()
-- إذا كانت هناك صورة، قم بتعيين الصورة الأولى
if args.image or args['صورة'] then
args.image1 = args.image or args['صورة']
end
-- إذا كان هناك تعليق، قم بتعيين التعليق الأول
if args.caption or args['تعليق'] then
args.caption1 = args.caption or args['تعليق']
end
-- الحصول على أرقام الصور
local imagenums = getArgNums('image') or getArgNums('صورة')
for k, num in ipairs(imagenums) do
-- الحصول على تعليق الصورة
local caption = args['caption' .. tostring(num)] or args['تعليق' .. tostring(num)]
-- إنشاء عنصر HTML للصورة
local data = mw.html.create():wikitext(args['image' .. tostring(num)] or args['صورة' .. tostring(num)])
-- إضافة التعليق إلى الصورة إذا كان موجوداً
if caption then
data
:tag('div')
:cssText(args.captionstyle or args['نمط التعليق']) -- تطبيق نمط التعليق
:wikitext(caption) -- تعيين نص التعليق
end
-- إضافة السطر إلى العرض
addRow({
data = tostring(data),
datastyle = args.imagestyle or args['نمط الصورة'], -- تطبيق نمط الصورة
class = args.imageclass or args['فئة الصورة'], -- تعيين فئة الصورة
rowclass = args['imagerowclass' .. tostring(num)] or args['فئة صف الصورة' .. tostring(num)] -- تعيين فئة صف الصورة
})
end
end
local function preprocessRows()
-- الحصول على الاتحاد بين أرقام المعاملات "header" و "data"،
-- ثم يتم عرضهم جميعًا باستخدام addRow.
local rownums = union(getArgNums('header', 'رأس'), getArgNums('data', 'بيان'))
table.sort(rownums)
local lastheader
for k, num in ipairs(rownums) do
if args['header' .. tostring(num)] or args['رأس' .. tostring(num)] then
if lastheader then
args['header' .. tostring(lastheader)] = nil
args['رأس' .. tostring(lastheader)] = nil
end
lastheader = num
elseif (args['data' .. tostring(num)] or args['بيان' .. tostring(num)]) and
(args['data' .. tostring(num)] or args['بيان' .. tostring(num)]):gsub('%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]', ''):match('^%S') then
local data = args['data' .. tostring(num)] or args['بيان' .. tostring(num)]
if data:gsub('%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]', ''):match('%S') then
lastheader = nil
end
end
end
if lastheader then
args['header' .. tostring(lastheader)] = nil
args['رأس' .. tostring(lastheader)] = nil
end
end
local function renderRows()
-- الحصول على الاتحاد بين أرقام المعاملات "header" و "data"،
-- ثم يتم عرضهم جميعًا بترتيب باستخدام addRow.
local rownums = union(getArgNums('header', 'رأس'), getArgNums('data', 'بيان'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addRow({
header = args['header' .. tostring(num)] or args['رأس' .. tostring(num)], -- رأس
label = args['label' .. tostring(num)] or args['تسمية' .. tostring(num)], -- تسمية
data = args['data' .. tostring(num)] or args['بيان' .. tostring(num)], -- بيان
datastyle = args.datastyle or args['نمط_البيان'], -- نمط البيانات
class = args['class' .. tostring(num)] or args['فئة' .. tostring(num)], -- فئة
rowclass = args['rowclass' .. tostring(num)] or args['فئة_الصف' .. tostring(num)], -- فئة الصف
rowstyle = args['rowstyle' .. tostring(num)] or args['نمط_الصف' .. tostring(num)], -- نمط الصف
rowcellstyle = args['rowcellstyle' .. tostring(num)] or args['نمط_خلية_الصف' .. tostring(num)], -- نمط خلية الصف
dataid = args['dataid' .. tostring(num)] or args['معرف_البيان' .. tostring(num)], -- معرف البيان
labelid = args['labelid' .. tostring(num)] or args['معرف_التسمية' .. tostring(num)], -- معرف التسمية
headerid = args['headerid' .. tostring(num)] or args['معرف_الرأس' .. tostring(num)], -- معرف الرأس
rowid = args['rowid' .. tostring(num)] or args['معرف_الصف' .. tostring(num)] -- معرف الصف
})
end
end
local function renderNavBar()
if not args.name then return end
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:css('text-align', 'right')
:wikitext(navbar{
args.name,
mini = 1,
})
end
local function renderItalicTitle()
local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
end
end
local function renderTrackingCategories()
if args.decat ~= 'yes' then
if args.child == 'yes' then
if args.title then
root:wikitext('[[تصنيف:Pages which use embedded infobox templates with the title parameter]]')
end
elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
root:wikitext('[[تصنيف:مقالات تستخدم صناديق معلومات بدون صفوف بيانات]]')
end
end
if(mw.title.getCurrentTitle().namespace == 0) then
root:wikitext('[[تصنيف:مقالات تستعمل قوالب معلومات]]')
end
end
local function loadTemplateStyles()
local frame = mw.getCurrentFrame()
-- See function description
local base_templatestyles = ''
-- local base_templatestyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Module:Infobox/styles.css' } }
local templatestyles = ''
if args['templatestyles'] then
templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['templatestyles'] }
}
end
local child_templatestyles = ''
if args['child templatestyles'] then
child_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['child templatestyles'] }
}
end
local grandchild_templatestyles = ''
if args['grandchild templatestyles'] then
grandchild_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['grandchild templatestyles'] }
}
end
return table.concat({
base_templatestyles, -- see function description
templatestyles,
child_templatestyles,
grandchild_templatestyles
})
end
local function _infobox()
-- Specify the overall layout of the infobox, with special settings
-- if the infobox is used as a 'child' inside another infobox.
if args.child ~= 'yes' then
root = mw.html.create('table')
root
:addClass((args.subbox ~= 'yes') and 'infobox' or nil)
:addClass(args.bodyclass)
if args.subbox == 'yes' then
root
:css('padding', '0')
:css('border', 'none')
:css('margin', '-3px')
:css('width', 'auto')
:css('min-width', '100%')
:css('font-size', '100%')
:css('clear', 'none')
:css('float', 'none')
:css('background-color', 'transparent')
else
root
:css('width', '22em')
end
root
:cssText(args.bodystyle)
renderTitle()
renderAboveRow()
else
root = mw.html.create()
root
:wikitext(args.title)
end
renderSubheaders()
renderImages()
if args.autoheaders then
preprocessRows()
end
renderRows()
renderBelowRow()
renderNavBar()
renderItalicTitle()
renderTrackingCategories()
return loadTemplateStyles() .. tostring(root)
end
local function preprocessSingleArg(argName)
-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
if origArgs[argName] and origArgs[argName] ~= '' then
args[argName] = origArgs[argName]
end
end
local function preprocessArgs(prefixTable, step)
-- Assign the parameters with the given prefixes to the args table, in order, in batches
-- of the step size specified. This is to prevent references etc. from appearing in the
-- wrong order. The prefixTable should be an array containing tables, each of which has
-- two possible fields, a "prefix" string and a "depend" table. The function always parses
-- parameters containing the "prefix" string, but only parses parameters in the "depend"
-- table if the prefix parameter is present and non-blank.
if type(prefixTable) ~= 'table' then
error("Non-table value detected for the prefix table", 2)
end
if type(step) ~= 'number' then
error("Invalid step value detected", 2)
end
-- Get arguments without a number suffix, and check for bad input.
for i,v in ipairs(prefixTable) do
if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
error('Invalid input detected to preprocessArgs prefix table', 2)
end
preprocessSingleArg(v.prefix)
-- Only parse the depend parameter if the prefix parameter is present and not blank.
if args[v.prefix] and v.depend then
for j, dependValue in ipairs(v.depend) do
if type(dependValue) ~= 'string' then
error('Invalid "depend" parameter value detected in preprocessArgs')
end
preprocessSingleArg(dependValue)
end
end
end
-- Get arguments with number suffixes.
local a = 1 -- Counter variable.
local moreArgumentsExist = true
while moreArgumentsExist == true do
moreArgumentsExist = false
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
local prefixArgName = v.prefix .. tostring(i)
if origArgs[prefixArgName] then
moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
preprocessSingleArg(prefixArgName)
end
-- Process the depend table if the prefix argument is present and not blank, or
-- we are processing "prefix1" and "prefix" is present and not blank, and
-- if the depend table is present.
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
for j,dependValue in ipairs(v.depend) do
local dependArgName = dependValue .. tostring(i)
preprocessSingleArg(dependArgName)
end
end
end
end
a = a + step
end
end
local function parseDataParameters()
-- تحليل معلمات البيانات بنفس الترتيب الذي كان يعتمده {{infobox}} القديم،
-- حتى يتم عرض المراجع وما إلى ذلك في الأماكن المتوقعة.
-- المعلمات التي تعتمد على معلمة أخرى يتم معالجتها فقط إذا كانت تلك المعلمة موجودة،
-- لتجنب ظهور مراجع غير متوقعة في قوائم مراجع المقالات.
preprocessSingleArg('autoheaders', 'رؤوس تلقائية')
preprocessSingleArg('child', 'فرعي')
preprocessSingleArg('bodyclass', 'فئة الجسم')
preprocessSingleArg('subbox', 'صندوق فرعي')
preprocessSingleArg('bodystyle', 'نمط الجسم')
preprocessSingleArg('title', 'العنوان')
preprocessSingleArg('titleclass', 'فئة العنوان')
preprocessSingleArg('titlestyle', 'نمط العنوان')
preprocessSingleArg('above', 'نص علوي')
preprocessSingleArg('aboveclass', 'فئة النص العلوي')
preprocessSingleArg('abovestyle', 'نمط النص العلوي')
-- معالجة سلسلة من المعلمات مع اعتماد بعضها على الآخر
preprocessArgs({
{prefix = 'subheader', 'رأس فرعي', depend = {'subheaderstyle', 'نمط الرأس الفرعي', 'subheaderrowclass', 'فئة صف الرأس الفرعي'}}
}, 10)
preprocessSingleArg('subheaderstyle', 'نمط الرأس الفرعي')
preprocessSingleArg('subheaderclass', 'فئة الرأس الفرعي')
preprocessArgs({
{prefix = 'image', 'صورة', depend = {'caption', 'تعليق', 'imagerowclass', 'فئة صف الصورة'}}
}, 10)
preprocessSingleArg('captionstyle', 'نمط التعليق')
preprocessSingleArg('imagestyle', 'نمط الصورة')
preprocessSingleArg('imageclass', 'فئة الصورة')
preprocessArgs({
{prefix = 'header', 'رأس'}, -- رؤوس
{prefix = 'data', 'بيان', depend = {'label', 'تسمية'}}, -- بيانات وتعتمد على التسمية
{prefix = 'rowclass', 'فئة الصف'}, -- فئة الصف
{prefix = 'rowstyle', 'نمط الصف'}, -- نمط الصف
{prefix = 'rowcellstyle', 'نمط خلية الصف'}, -- نمط خلية الصف
{prefix = 'class', 'فئة'}, -- فئة
{prefix = 'dataid', 'معرف البيان'}, -- معرف البيانات
{prefix = 'labelid', 'معرف التسمية'}, -- معرف التسمية
{prefix = 'headerid', 'معرف الرأس'}, -- معرف الرأس
{prefix = 'rowid', 'معرف الصف'} -- معرف الصف
}, 50)
preprocessSingleArg('headerclass', 'فئة الرأس')
preprocessSingleArg('headerstyle', 'نمط الرأس')
preprocessSingleArg('labelstyle', 'نمط التسمية')
preprocessSingleArg('datastyle', 'نمط البيانات')
preprocessSingleArg('below', 'تحت')
preprocessSingleArg('belowclass', 'فئة تحت')
preprocessSingleArg('belowstyle', 'نمط تحت')
preprocessSingleArg('name', 'الاسم')
-- معاملة خاصة لمعامل "العنوان المائل" (italic title)
args['italic title'] = origArgs['italic title']
preprocessSingleArg('decat', 'تصنيف معطل')
preprocessSingleArg('templatestyles', 'أنماط القالب')
preprocessSingleArg('child templatestyles', 'أنماط القالب الفرعي')
preprocessSingleArg('grandchild templatestyles', 'أنماط القالب الفرعي الثاني')
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
function p.infoboxTemplate(frame)
-- For calling via #invoke within a template
origArgs = {}
for k,v in pairs(frame.args) do origArgs[k] = mw.text.trim(v) end
parseDataParameters()
return _infobox()
end
return p