Module:InfoboxNeue: Difference between revisions
From Amaranth Legacy, available at amaranth-legacy.community
More actions
Content deleted Content added
Tesinormed (talk | contribs) No edit summary Tag: Manual revert |
Tesinormed (talk | contribs) No edit summary |
||
| Line 4: | Line 4: | ||
local methodtable = {} |
local methodtable = {} |
||
local libraryUtil = require( |
local libraryUtil = require('libraryUtil') |
||
local checkType = libraryUtil.checkType |
local checkType = libraryUtil.checkType |
||
local checkTypeMulti = libraryUtil.checkTypeMulti |
local checkTypeMulti = libraryUtil.checkTypeMulti |
||
local i18n = require( |
local i18n = require('Module:i18n'):new() |
||
metatable.__index = methodtable |
metatable.__index = methodtable |
||
metatable.__tostring = function |
metatable.__tostring = function(self) |
||
return tostring( |
return tostring(self:renderInfobox()) |
||
end |
end |
||
-- http://lua-users.org/wiki/SortedIteration |
-- http://lua-users.org/wiki/SortedIteration |
||
local function __genOrderedIndex( |
local function __genOrderedIndex(t) |
||
local orderedIndex = {} |
|||
for key in pairs(t) do |
|||
table.insert(orderedIndex, key) |
|||
end |
|||
table.sort(orderedIndex) |
|||
return orderedIndex |
|||
end |
end |
||
local function orderedNext(t, state) |
local function orderedNext(t, state) |
||
-- Equivalent of the next function, but returns the keys in the alphabetic |
|||
-- order. We use a temporary ordered key table that is stored in the |
|||
-- table being iterated. |
|||
local key = nil |
|||
--print("orderedNext: state = "..tostring(state) ) |
|||
if state == nil then |
|||
-- the first time, generate the index |
|||
t.__orderedIndex = __genOrderedIndex(t) |
|||
key = t.__orderedIndex[1] |
|||
else |
|||
-- fetch the next value |
|||
for i = 1, table.getn(t.__orderedIndex) do |
|||
if t.__orderedIndex[i] == state then |
|||
key = t.__orderedIndex[i + 1] |
|||
end |
|||
end |
|||
end |
|||
end |
|||
if key then |
|||
return key, t[key] |
|||
end |
|||
-- no more value to return, cleanup |
|||
t.__orderedIndex = nil |
|||
return |
|||
end |
end |
||
local function orderedPairs(t) |
local function orderedPairs(t) |
||
-- Equivalent of the pairs() function on tables. Allows to iterate |
|||
-- in order |
|||
return orderedNext, t, nil |
|||
end |
end |
||
| Line 65: | Line 65: | ||
--- @param key string The translation key |
--- @param key string The translation key |
||
--- @return string If the key was not found, the key is returned |
--- @return string If the key was not found, the key is returned |
||
local function t( |
local function t(key) |
||
return i18n:translate( |
return i18n:translate(key) |
||
end |
end |
||
| Line 74: | Line 74: | ||
--- For some reason SMW property converts underscore into space |
--- For some reason SMW property converts underscore into space |
||
--- mw.uri.encode can't be used on full URL |
--- mw.uri.encode can't be used on full URL |
||
local function restoreUnderscore( |
local function restoreUnderscore(s) |
||
return s:gsub( |
return s:gsub(' ', '%%5F') |
||
end |
end |
||
local function removeprefix( |
local function removeprefix(s, p) |
||
return (s:sub(0, #p) == p) and s:sub(#p+1) or s |
return (s:sub(0, #p) == p) and s:sub(#p + 1) or s |
||
end |
end |
||
| Line 85: | Line 85: | ||
--- Helper function to format string to number with separators |
--- Helper function to format string to number with separators |
||
--- It is usually use to re-format raw number from SMW into more readable format |
--- It is usually use to re-format raw number from SMW into more readable format |
||
local function formatNumber( |
local function formatNumber(s) |
||
local lang = mw.getContentLanguage() |
local lang = mw.getContentLanguage() |
||
if s == nil then |
if s == nil then |
||
| Line 91: | Line 91: | ||
end |
end |
||
if type( |
if type(s) ~= 'number' then |
||
s = tonumber( |
s = tonumber(s) |
||
end |
end |
||
if type( |
if type(s) == 'number' then |
||
return lang:formatNum( |
return lang:formatNum(s) |
||
end |
end |
||
| Line 103: | Line 103: | ||
-- TODO: Perhaps we should turn this into another module |
-- TODO: Perhaps we should turn this into another module |
||
local function getDetailsHTML( |
local function getDetailsHTML(data, frame) |
||
local summary = frame:extensionTag { |
local summary = frame:extensionTag { |
||
name = 'summary', |
name = 'summary', |
||
| Line 127: | Line 127: | ||
--- @param data table |
--- @param data table |
||
--- @return string |
--- @return string |
||
function methodtable.tableToCommaList( |
function methodtable.tableToCommaList(data) |
||
if type( |
if type(data) == 'table' then |
||
return table.concat( |
return table.concat(data, ', ') |
||
else |
else |
||
return data |
return data |
||
| Line 140: | Line 140: | ||
--- @param s2 string|nil |
--- @param s2 string|nil |
||
--- @return string|nil |
--- @return string|nil |
||
function methodtable.formatRange( |
function methodtable.formatRange(s1, s2, formatNum) |
||
if s1 == nil and s2 == nil then |
if s1 == nil and s2 == nil then |
||
return |
return |
||
| Line 149: | Line 149: | ||
if formatNum then |
if formatNum then |
||
if s1 then |
if s1 then |
||
s1 = formatNumber( |
s1 = formatNumber(s1) |
||
end |
end |
||
if s2 then |
if s2 then |
||
s2 = formatNumber( |
s2 = formatNumber(s2) |
||
end |
end |
||
end |
end |
||
| Line 168: | Line 168: | ||
--- @param unit string |
--- @param unit string |
||
--- @return string|nil |
--- @return string|nil |
||
function methodtable.addUnitIfExists( |
function methodtable.addUnitIfExists(s, unit) |
||
if s == nil then |
if s == nil then |
||
return |
return |
||
| Line 180: | Line 180: | ||
--- @param data table {title, desc) |
--- @param data table {title, desc) |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderMessage( |
function methodtable.renderMessage(self, data, noInsert) |
||
checkType( |
checkType('Module:InfoboxNeue.renderMessage', 1, self, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderMessage', 2, data, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderMessage', 3, noInsert, 'boolean', true) |
||
noInsert = noInsert or false |
noInsert = noInsert or false |
||
local item = self:renderSection( |
local item = self:renderSection({ content = self:renderItem({ data = data.title, desc = data.desc }) }, noInsert) |
||
if not noInsert then |
if not noInsert then |
||
table.insert( |
table.insert(self.entries, item) |
||
end |
end |
||
| Line 200: | Line 200: | ||
--- @param filename string |
--- @param filename string |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderImage( |
function methodtable.renderImage(self, filename) |
||
checkType( |
checkType('Module:InfoboxNeue.renderImage', 1, self, 'table') |
||
local hasPlaceholderImage = false |
local hasPlaceholderImage = false |
||
if type( |
if type(filename) ~= 'string' and self.config.displayPlaceholder == true then |
||
hasPlaceholderImage = true |
hasPlaceholderImage = true |
||
filename = self.config.placeholderImage |
filename = self.config.placeholderImage |
||
-- Add tracking category for infoboxes using placeholder image |
-- Add tracking category for infoboxes using placeholder image |
||
table.insert( |
table.insert(self.categories, |
||
string.format( |
string.format('[[Category:%s]]', t('category_infobox_using_placeholder_image')) |
||
) |
) |
||
end |
end |
||
if type( |
if type(filename) ~= 'string' then |
||
return '' |
return '' |
||
end |
end |
||
local parts = mw.text.split( |
local parts = mw.text.split(filename, ':', true) |
||
if #parts > 1 then |
if #parts > 1 then |
||
table.remove( |
table.remove(parts, 1) |
||
filename = table.concat( |
filename = table.concat(parts, ':') |
||
end |
end |
||
local html = mw.html.create( |
local html = mw.html.create('div') |
||
:addClass( |
:addClass('infobox__image') |
||
:wikitext( |
:wikitext(string.format('[[File:%s|400px]]', filename)) |
||
if hasPlaceholderImage == true then |
if hasPlaceholderImage == true then |
||
local icon = mw.html.create( |
local icon = mw.html.create('span'):addClass('citizen-ui-icon mw-ui-icon-wikimedia-upload') |
||
-- TODO: Point the Upload link to a specific file name |
-- TODO: Point the Upload link to a specific file name |
||
html:tag( |
html:tag('div'):addClass('infobox__image-upload') |
||
:wikitext( |
:wikitext(string.format('[[%s|%s]]', 'Special:UploadWizard', |
||
tostring( |
tostring(icon) .. t('label_upload_image'))) |
||
end |
end |
||
local item = tostring( |
local item = tostring(html) |
||
table.insert( |
table.insert(self.entries, item) |
||
return item |
return item |
||
| Line 247: | Line 247: | ||
--- @param data table {data, class, color, nopadding) |
--- @param data table {data, class, color, nopadding) |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderIndicator( |
function methodtable.renderIndicator(self, data) |
||
checkType( |
checkType('Module:InfoboxNeue.renderIndicator', 1, self, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderIndicator', 2, data, 'table') |
||
if data == nil or data[ |
if data == nil or data['data'] == nil or data['data'] == '' then return '' end |
||
local html = mw.html.create( |
local html = mw.html.create('div'):addClass('infobox__indicators') |
||
local htmlClasses = { |
local htmlClasses = { |
||
| Line 259: | Line 259: | ||
} |
} |
||
if data[ |
if data['class'] then |
||
table.insert( |
table.insert(htmlClasses, data['class']) |
||
end |
end |
||
if data[ |
if data['color'] then |
||
table.insert( |
table.insert(htmlClasses, 'infobox__indicator--' .. data['color']) |
||
end |
end |
||
if data[ |
if data['nopadding'] == true then |
||
table.insert( |
table.insert(htmlClasses, 'infobox__indicator--nopadding') |
||
end |
end |
||
| Line 274: | Line 274: | ||
self:renderItem( |
self:renderItem( |
||
{ |
{ |
||
[ |
['data'] = data['data'], |
||
[ |
['class'] = table.concat(htmlClasses, ' '), |
||
row = true, |
row = true, |
||
spacebetween = true |
spacebetween = true |
||
| Line 282: | Line 282: | ||
) |
) |
||
local item = tostring( |
local item = tostring(html) |
||
table.insert( |
table.insert(self.entries, item) |
||
return item |
return item |
||
| Line 293: | Line 293: | ||
--- @param data table {title, subtitle, badge) |
--- @param data table {title, subtitle, badge) |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderHeader( |
function methodtable.renderHeader(self, data) |
||
checkType( |
checkType('Module:InfoboxNeue.renderHeader', 1, self, 'table') |
||
checkTypeMulti( |
checkTypeMulti('Module:InfoboxNeue.renderHeader', 2, data, { 'table', 'string' }) |
||
if type( |
if type(data) == 'string' then |
||
data = { |
data = { |
||
title = data |
title = data |
||
| Line 303: | Line 303: | ||
end |
end |
||
if data == nil or data[ |
if data == nil or data['title'] == nil then return '' end |
||
local html = mw.html.create( |
local html = mw.html.create('div'):addClass('infobox__header') |
||
if data[ |
if data['badge'] then |
||
html:tag( |
html:tag('div') |
||
:addClass( |
:addClass('infobox__item infobox__badge') |
||
:wikitext( |
:wikitext(data['badge']) |
||
end |
end |
||
local titleItem = mw.html.create( |
local titleItem = mw.html.create('div'):addClass('infobox__item') |
||
titleItem:tag( |
titleItem:tag('div') |
||
:addClass( |
:addClass('infobox__title') |
||
:wikitext( |
:wikitext(data['title']) |
||
if data[ |
if data['subtitle'] then |
||
titleItem:tag( |
titleItem:tag('div') |
||
-- Subtitle is always data |
-- Subtitle is always data |
||
:addClass( |
:addClass('infobox__subtitle infobox__data') |
||
:wikitext( |
:wikitext(data['subtitle']) |
||
end |
end |
||
html:node( |
html:node(titleItem) |
||
local item = tostring( |
local item = tostring(html) |
||
table.insert( |
table.insert(self.entries, item) |
||
return item |
return item |
||
| Line 340: | Line 340: | ||
--- @param noInsert boolean whether to insert this section into the internal table table |
--- @param noInsert boolean whether to insert this section into the internal table table |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderSection( |
function methodtable.renderSection(self, data, noInsert) |
||
checkType( |
checkType('Module:InfoboxNeue.renderSection', 1, self, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderSection', 2, data, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderSection', 3, noInsert, 'boolean', true) |
||
noInsert = noInsert or false |
noInsert = noInsert or false |
||
if type( |
if type(data.content) == 'table' then |
||
data.content = table.concat( |
data.content = table.concat(data.content) |
||
end |
end |
||
if data == nil or data[ |
if data == nil or data['content'] == nil or data['content'] == '' then return '' end |
||
local html = mw.html.create( |
local html = mw.html.create('div'):addClass('infobox__section') |
||
if data[ |
if data['title'] then |
||
local header = html:tag( |
local header = html:tag('div'):addClass('infobox__sectionHeader') |
||
header:tag( |
header:tag('div') |
||
:addClass( |
:addClass('infobox__sectionTitle') |
||
:wikitext( |
:wikitext(data['title']) |
||
if data[ |
if data['subtitle'] then |
||
header:tag( |
header:tag('div') |
||
:addClass( |
:addClass('infobox__sectionSubtitle') |
||
:wikitext( |
:wikitext(data['subtitle']) |
||
end |
end |
||
end |
end |
||
local content = html:tag( |
local content = html:tag('div') |
||
content:addClass( |
content:addClass('infobox__sectionContent') |
||
:wikitext( |
:wikitext(data['content']) |
||
if data[ |
if data['border'] == false then html:addClass('infobox__section--noborder') end |
||
if data[ |
if data['col'] then content:addClass('infobox__grid--cols-' .. data['col']) end |
||
if data[ |
if data['class'] then html:addClass(data['class']) end |
||
local item = tostring( |
local item = tostring(html) |
||
if not noInsert then |
if not noInsert then |
||
table.insert( |
table.insert(self.entries, item) |
||
end |
end |
||
| Line 388: | Line 388: | ||
--- @param data table {label, link, page} |
--- @param data table {label, link, page} |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderLinkButton( |
function methodtable.renderLinkButton(self, data) |
||
checkType( |
checkType('Module:InfoboxNeue.renderLinkButton', 1, self, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderLinkButton', 2, data, 'table') |
||
if data == nil or data[ |
if data == nil or data['label'] == nil or (data['link'] == nil and data['page'] == nil) then return '' end |
||
--- Render multiple linkButton when link is a table |
--- Render multiple linkButton when link is a table |
||
if type( |
if type(data['link']) == 'table' then |
||
local htmls = {} |
local htmls = {} |
||
for i, url in ipairs( |
for i, url in ipairs(data['link']) do |
||
table.insert( |
table.insert(htmls, |
||
self:renderLinkButton( |
self:renderLinkButton({ |
||
label = string.format( |
label = string.format('%s %d', data['label'], i), |
||
link = url |
link = url |
||
} |
}) |
||
) |
) |
||
end |
end |
||
return table.concat( |
return table.concat(htmls) |
||
end |
end |
||
local html = mw.html.create( |
local html = mw.html.create('div'):addClass('infobox__linkButton') |
||
if data[ |
if data['link'] then |
||
html:wikitext( |
html:wikitext(string.format('[%s %s]', restoreUnderscore(data['link']), data['label'])) |
||
elseif data[ |
elseif data['page'] then |
||
html:wikitext( |
html:wikitext(string.format('[[%s|%s]]', data['page'], data['label'])) |
||
end |
end |
||
return tostring( |
return tostring(html) |
||
end |
end |
||
| Line 425: | Line 425: | ||
--- @param data table {content, button} |
--- @param data table {content, button} |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderFooter( |
function methodtable.renderFooter(self, data) |
||
checkType( |
checkType('Module:InfoboxNeue.renderFooter', 1, self, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderFooter', 2, data, 'table') |
||
if data == nil then return '' end |
if data == nil then return '' end |
||
-- Checks if an input is of type 'table' or 'string' and if it is not empty |
-- Checks if an input is of type 'table' or 'string' and if it is not empty |
||
local function isNonEmpty( |
local function isNonEmpty(input) |
||
return (type( |
return (type(input) == 'table' and next(input) ~= nil) or (type(input) == 'string' and #input > 0) |
||
end |
end |
||
local hasContent = isNonEmpty( |
local hasContent = isNonEmpty(data['content']) |
||
local hasButton = isNonEmpty( |
local hasButton = isNonEmpty(data['button']) and isNonEmpty(data['button']['content']) and |
||
isNonEmpty( |
isNonEmpty(data['button']['label']) |
||
if not hasContent and not hasButton then return '' end |
if not hasContent and not hasButton then return '' end |
||
local html = mw.html.create( |
local html = mw.html.create('div'):addClass('infobox__footer') |
||
if hasContent then |
if hasContent then |
||
local content = data[ |
local content = data['content'] |
||
if type( |
if type(content) == 'table' then content = table.concat(content) end |
||
html:addClass( |
html:addClass('infobox__footer--has-content') |
||
html:tag( |
html:tag('div') |
||
:addClass( |
:addClass('infobox__section') |
||
:wikitext( |
:wikitext(content) |
||
end |
end |
||
if hasButton then |
if hasButton then |
||
html:addClass( |
html:addClass('infobox__footer--has-button') |
||
local buttonData = data[ |
local buttonData = data['button'] |
||
local button = html:tag( |
local button = html:tag('div'):addClass('infobox__button') |
||
local label = button:tag( |
local label = button:tag('div'):addClass('infobox__buttonLabel') |
||
if buttonData[ |
if buttonData['icon'] ~= nil then |
||
label:wikitext( |
label:wikitext(string.format('[[File:%s|16px|link=]]%s', buttonData['icon'], buttonData['label'])) |
||
else |
else |
||
label:wikitext( |
label:wikitext(buttonData['label']) |
||
end |
end |
||
if buttonData[ |
if buttonData['type'] == 'link' then |
||
button:tag( |
button:tag('div') |
||
:addClass( |
:addClass('infobox__buttonLink') |
||
:wikitext( |
:wikitext(buttonData['content']) |
||
elseif buttonData[ |
elseif buttonData['type'] == 'popup' then |
||
button:tag( |
button:tag('div') |
||
:addClass( |
:addClass('infobox__buttonCard') |
||
:wikitext( |
:wikitext(buttonData['content']) |
||
end |
end |
||
end |
end |
||
local item = tostring( |
local item = tostring(html) |
||
table.insert( |
table.insert(self.entries, item) |
||
return item |
return item |
||
| Line 488: | Line 488: | ||
--- @param data table {icon, label, type, content} |
--- @param data table {icon, label, type, content} |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderFooterButton( |
function methodtable.renderFooterButton(self, data) |
||
checkType( |
checkType('Module:InfoboxNeue.renderFooterButton', 1, self, 'table') |
||
checkType( |
checkType('Module:InfoboxNeue.renderFooterButton', 2, data, 'table') |
||
if data == nil then return '' end |
if data == nil then return '' end |
||
return self:renderFooter( |
return self:renderFooter({ button = data }) |
||
end |
end |
||
| Line 502: | Line 502: | ||
--- @param content string|number|nil optional |
--- @param content string|number|nil optional |
||
--- @return string html |
--- @return string html |
||
function methodtable.renderItem( |
function methodtable.renderItem(self, data, content) |
||
checkType( |
checkType('Module:InfoboxNeue.renderItem', 1, self, 'table') |
||
checkTypeMulti( |
checkTypeMulti('Module:InfoboxNeue.renderItem', 2, data, { 'table', 'string' }) |
||
checkTypeMulti( |
checkTypeMulti('Module:InfoboxNeue.renderItem', 3, content, { 'string', 'number', 'nil' }) |
||
-- The arguments are not passed as a table |
-- The arguments are not passed as a table |
||
| Line 516: | Line 516: | ||
end |
end |
||
if data == nil or data[ |
if data == nil or data['data'] == nil or data['data'] == '' then return '' end |
||
if self.config.removeEmpty == true and data[ |
if self.config.removeEmpty == true and data['data'] == self.config.emptyString then |
||
return '' |
return '' |
||
end |
end |
||
local html = mw.html.create( |
local html = mw.html.create('div'):addClass('infobox__item') |
||
if data[ |
if data['class'] then html:addClass(data['class']) end |
||
if data[ |
if data['tooltip'] then html:attr('title', data['tooltip']) end |
||
if data[ |
if data['row'] == true then html:addClass('infobox__grid--row') end |
||
if data[ |
if data['spacebetween'] == true then html:addClass('infobox__grid--space-between') end |
||
if data[ |
if data['colspan'] then html:addClass('infobox__grid--col-span-' .. data['colspan']) end |
||
local textWrapper = html |
local textWrapper = html |
||
if data[ |
if data['link'] then |
||
html:addClass( |
html:addClass('infobox__itemButton') |
||
html:tag( |
html:tag('div') |
||
:addClass( |
:addClass('infobox__itemButtonLink') |
||
:wikitext( |
:wikitext(string.format('[%s]', data['link'])) |
||
elseif data[ |
elseif data['page'] then |
||
html:addClass( |
html:addClass('infobox__itemButton') |
||
html:tag( |
html:tag('div') |
||
:addClass( |
:addClass('infobox__itemButtonLink') |
||
:wikitext( |
:wikitext(string.format('[[%s]]', data['link'])) |
||
end |
end |
||
if data[ |
if data['icon'] then |
||
html:addClass( |
html:addClass('infobox__item--hasIcon') |
||
html:tag( |
html:tag('div') |
||
:addClass( |
:addClass('infobox__icon') |
||
:wikitext( |
:wikitext(string.format('[[File:%s|16px|link=]]', data['icon'])) |
||
-- Create wrapper for text to align with icon |
-- Create wrapper for text to align with icon |
||
textWrapper = html:tag( |
textWrapper = html:tag('div'):addClass('infobox__text') |
||
end |
end |
||
local dataOrder = { 'label', 'data', 'desc' } |
local dataOrder = { 'label', 'data', 'desc' } |
||
for _, key in ipairs( |
for _, key in ipairs(dataOrder) do |
||
if data[ |
if data[key] then |
||
if type( |
if type(data[key]) == 'table' then |
||
data[ |
data[key] = table.concat(data[key], ', ') |
||
end |
end |
||
local actualData = data[ |
local actualData = data[key] |
||
if key == 'data' and type( |
if key == 'data' and type(string.find(data[key], '^%*')) ~= 'nil' then |
||
actualData = "\n\n" .. data[ |
actualData = "\n\n" .. data[key] |
||
end |
end |
||
textWrapper:tag( |
textWrapper:tag('div') |
||
:addClass( |
:addClass('infobox__' .. key) |
||
:wikitext( |
:wikitext(actualData) |
||
end |
end |
||
end |
end |
||
-- Add arrow indicator as affordnance |
-- Add arrow indicator as affordnance |
||
if data[ |
if data['link'] or data['page'] then |
||
html:tag( |
html:tag('div'):addClass('infobox__itemButtonArrow citizen-ui-icon mw-ui-icon-wikimedia-collapse') |
||
end |
end |
||
return tostring( |
return tostring(html) |
||
end |
end |
||
| Line 586: | Line 586: | ||
--- @param snippetText string text used in snippet in mobile view |
--- @param snippetText string text used in snippet in mobile view |
||
--- @return string html infobox html with templatestyles |
--- @return string html infobox html with templatestyles |
||
function methodtable.renderInfobox( |
function methodtable.renderInfobox(self, innerHtml, snippetText) |
||
checkType( |
checkType('Module:InfoboxNeue.renderInfobox', 1, self, 'table') |
||
checkTypeMulti( |
checkTypeMulti('Module:InfoboxNeue.renderInfobox', 2, innerHtml, { 'table', 'string', 'nil' }) |
||
checkType( |
checkType('Module:InfoboxNeue.renderInfobox', 3, snippetText, 'string', true) |
||
innerHtml = innerHtml or self.entries |
innerHtml = innerHtml or self.entries |
||
if type( |
if type(innerHtml) == 'table' then |
||
innerHtml = table.concat( |
innerHtml = table.concat(self.entries) |
||
end |
end |
||
local function renderContent() |
local function renderContent() |
||
local html = mw.html.create( |
local html = mw.html.create('div') |
||
:addClass( |
:addClass('infobox__content') |
||
:wikitext( |
:wikitext(innerHtml) |
||
return tostring( |
return tostring(html) |
||
end |
end |
||
| Line 607: | Line 607: | ||
local html = mw.html.create() |
local html = mw.html.create() |
||
html:tag( |
html:tag('div') |
||
:addClass( |
:addClass('citizen-ui-icon mw-ui-icon-wikimedia-collapse') |
||
:done() |
:done() |
||
:tag( |
:tag('div') |
||
:addClass( |
:addClass('infobox__data') |
||
:wikitext( |
:wikitext(string.format('%s:', t('label_quick_facts'))) |
||
:done() |
:done() |
||
:tag( |
:tag('div') |
||
:addClass( |
:addClass('infobox__desc') |
||
:wikitext( |
:wikitext(snippetText) |
||
return tostring( |
return tostring(html) |
||
end |
end |
||
local frame = |
local frame = mw.getCurrentFrame() |
||
local output = getDetailsHTML( |
local output = getDetailsHTML({ |
||
details = { |
details = { |
||
class = 'infobox floatright noexcerpt', |
class = 'infobox floatright noexcerpt', |
||
| Line 632: | Line 632: | ||
content = renderSnippet() |
content = renderSnippet() |
||
} |
} |
||
}, frame |
}, frame) |
||
return frame:extensionTag { |
return frame:extensionTag { |
||
name = 'templatestyles', args = { src = 'Module:InfoboxNeue/styles.css' } |
name = 'templatestyles', args = { src = 'Module:InfoboxNeue/styles.css' } |
||
} .. output .. table.concat( |
} .. output .. table.concat(self.categories) |
||
end |
end |
||
--- Just an accessor for the class method |
--- Just an accessor for the class method |
||
function methodtable.showDescIfDiff( |
function methodtable.showDescIfDiff(s1, s2) |
||
return InfoboxNeue.showDescIfDiff( |
return InfoboxNeue.showDescIfDiff(s1, s2) |
||
end |
end |
||
| Line 649: | Line 649: | ||
--- @param s2 string|nil comparsion |
--- @param s2 string|nil comparsion |
||
--- @return string|nil html |
--- @return string|nil html |
||
function InfoboxNeue.showDescIfDiff( |
function InfoboxNeue.showDescIfDiff(s1, s2) |
||
if s1 == nil or s2 == nil or s1 == s2 then return s1 end |
if s1 == nil or s2 == nil or s1 == s2 then return s1 end |
||
return string.format( |
return string.format('%s <span class="infobox__desc">(%s)</span>', s1, s2) |
||
end |
end |
||
| Line 657: | Line 657: | ||
--- |
--- |
||
--- @return table InfoboxNeue |
--- @return table InfoboxNeue |
||
function InfoboxNeue.new( |
function InfoboxNeue.new(self, config) |
||
local baseConfig = { |
local baseConfig = { |
||
-- Flag to discard empty rows |
-- Flag to discard empty rows |
||
| Line 669: | Line 669: | ||
} |
} |
||
for k, v in pairs( |
for k, v in pairs(config or {}) do |
||
baseConfig[ |
baseConfig[k] = v |
||
end |
end |
||
| Line 679: | Line 679: | ||
} |
} |
||
setmetatable( |
setmetatable(instance, metatable) |
||
return instance |
return instance |
||
| Line 688: | Line 688: | ||
--- @param frame table |
--- @param frame table |
||
--- @return string |
--- @return string |
||
function InfoboxNeue.fromArgs( |
function InfoboxNeue.fromArgs(frame) |
||
local instance = InfoboxNeue:new() |
local instance = InfoboxNeue:new() |
||
local args = require( |
local args = require('Module:Arguments').getArgs(frame) |
||
local sections = { |
local sections = { |
||
| Line 700: | Line 700: | ||
local currentSection |
local currentSection |
||
if args[ |
if args['image'] then |
||
instance:renderImage( |
instance:renderImage(args['image']) |
||
if args[ |
if args['indicator'] then |
||
instance:renderIndicator( |
instance:renderIndicator({ |
||
data = args[ |
data = args['indicator'], |
||
class = args[ |
class = args['indicatorClass'] |
||
} |
}) |
||
end |
end |
||
else |
else |
||
for i = 1, 3, 1 do |
for i = 1, 3, 1 do |
||
if args[ |
if args['image' .. i] then |
||
instance:renderImage( |
instance:renderImage(args['image' .. i]) |
||
if args[ |
if args['indicator' .. i] then |
||
instance:renderIndicator( |
instance:renderIndicator({ |
||
data = args[ |
data = args['indicator' .. i], |
||
class = args[ |
class = args['indicatorClass' .. i] |
||
} |
}) |
||
end |
end |
||
end |
end |
||
| Line 722: | Line 722: | ||
end |
end |
||
if args[ |
if args['title'] then |
||
instance:renderHeader( |
instance:renderHeader({ |
||
title = args[ |
title = args['title'], |
||
subtitle = args[ |
subtitle = args['subtitle'], |
||
} |
}) |
||
end |
end |
||
for key, value in orderedPairs( |
for key, value in orderedPairs(args) do |
||
if type( |
if type(string.match(key, '^label')) ~= 'nil' then |
||
if args[ |
if args['section' .. removeprefix(key, 'label')] then |
||
currentSection = args[ |
currentSection = args['section' .. removeprefix(key, 'label')] |
||
table.insert( |
table.insert(sections, { |
||
title = currentSection, |
title = currentSection, |
||
subtitle = args[ |
subtitle = args['section-subtitle' .. removeprefix(key, 'label')], |
||
col = args[ |
col = args['section-col' .. removeprefix(key, 'label')] or 2, |
||
content = {} |
content = {} |
||
} |
}) |
||
sectionMap[ |
sectionMap[currentSection] = #sections |
||
end |
end |
||
local data = { |
local data = { |
||
label = |
label = value, |
||
data = args['content' .. removeprefix(key, 'label')] |
|||
data = value |
|||
} |
} |
||
table.insert( |
table.insert(sections[sectionMap[(currentSection or 'default')]].content, |
||
instance:renderItem( |
instance:renderItem(data, nil)) |
||
end |
end |
||
end |
end |
||
for _, section in ipairs( |
for _, section in ipairs(sections) do |
||
instance:renderSection( |
instance:renderSection(section) |
||
end |
end |
||
return instance:renderInfobox( |
return instance:renderInfobox(nil, args['snippet']) |
||
end |
end |
||
Revision as of 18:30, December 30, 2024
This module is used for Template:InfoboxNeue. See the template's page for more information.
local InfoboxNeue = {}
local metatable = {}
local methodtable = {}
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
local i18n = require('Module:i18n'):new()
metatable.__index = methodtable
metatable.__tostring = function(self)
return tostring(self:renderInfobox())
end
-- http://lua-users.org/wiki/SortedIteration
local function __genOrderedIndex(t)
local orderedIndex = {}
for key in pairs(t) do
table.insert(orderedIndex, key)
end
table.sort(orderedIndex)
return orderedIndex
end
local function orderedNext(t, state)
-- Equivalent of the next function, but returns the keys in the alphabetic
-- order. We use a temporary ordered key table that is stored in the
-- table being iterated.
local key = nil
--print("orderedNext: state = "..tostring(state) )
if state == nil then
-- the first time, generate the index
t.__orderedIndex = __genOrderedIndex(t)
key = t.__orderedIndex[1]
else
-- fetch the next value
for i = 1, table.getn(t.__orderedIndex) do
if t.__orderedIndex[i] == state then
key = t.__orderedIndex[i + 1]
end
end
end
if key then
return key, t[key]
end
-- no more value to return, cleanup
t.__orderedIndex = nil
return
end
local function orderedPairs(t)
-- Equivalent of the pairs() function on tables. Allows to iterate
-- in order
return orderedNext, t, nil
end
--- Wrapper function for Module:i18n.translate
---
--- @param key string The translation key
--- @return string If the key was not found, the key is returned
local function t(key)
return i18n:translate(key)
end
--- Helper function to restore underscore from space
--- so that it does not screw up the external link wikitext syntax
--- For some reason SMW property converts underscore into space
--- mw.uri.encode can't be used on full URL
local function restoreUnderscore(s)
return s:gsub(' ', '%%5F')
end
local function removeprefix(s, p)
return (s:sub(0, #p) == p) and s:sub(#p + 1) or s
end
--- Helper function to format string to number with separators
--- It is usually use to re-format raw number from SMW into more readable format
local function formatNumber(s)
local lang = mw.getContentLanguage()
if s == nil then
return
end
if type(s) ~= 'number' then
s = tonumber(s)
end
if type(s) == 'number' then
return lang:formatNum(s)
end
return s
end
-- TODO: Perhaps we should turn this into another module
local function getDetailsHTML(data, frame)
local summary = frame:extensionTag {
name = 'summary',
content = data.summary.content,
args = {
class = data.summary.class
}
}
local details = frame:extensionTag {
name = 'details',
content = summary .. data.details.content,
args = {
class = data.details.class,
open = true
}
}
return details
end
--- Put table values into a comma-separated list
---
--- @param data table
--- @return string
function methodtable.tableToCommaList(data)
if type(data) == 'table' then
return table.concat(data, ', ')
else
return data
end
end
--- Show range if value1 and value2 are different
---
--- @param s1 string|nil
--- @param s2 string|nil
--- @return string|nil
function methodtable.formatRange(s1, s2, formatNum)
if s1 == nil and s2 == nil then
return
end
formatNum = formatNum or false
if formatNum then
if s1 then
s1 = formatNumber(s1)
end
if s2 then
s2 = formatNumber(s2)
end
end
if s1 and s2 and s1 ~= s2 then
return s1 .. ' – ' .. s2
end
return s1 or s2
end
--- Append unit to the value if exists
---
--- @param s string
--- @param unit string
--- @return string|nil
function methodtable.addUnitIfExists(s, unit)
if s == nil then
return
end
return s .. ' ' .. unit
end
--- Shortcut to return the HTML of the infobox message component as string
---
--- @param data table {title, desc)
--- @return string html
function methodtable.renderMessage(self, data, noInsert)
checkType('Module:InfoboxNeue.renderMessage', 1, self, 'table')
checkType('Module:InfoboxNeue.renderMessage', 2, data, 'table')
checkType('Module:InfoboxNeue.renderMessage', 3, noInsert, 'boolean', true)
noInsert = noInsert or false
local item = self:renderSection({ content = self:renderItem({ data = data.title, desc = data.desc }) }, noInsert)
if not noInsert then
table.insert(self.entries, item)
end
return item
end
--- Return the HTML of the infobox image component as string
---
--- @param filename string
--- @return string html
function methodtable.renderImage(self, filename)
checkType('Module:InfoboxNeue.renderImage', 1, self, 'table')
local hasPlaceholderImage = false
if type(filename) ~= 'string' and self.config.displayPlaceholder == true then
hasPlaceholderImage = true
filename = self.config.placeholderImage
-- Add tracking category for infoboxes using placeholder image
table.insert(self.categories,
string.format('[[Category:%s]]', t('category_infobox_using_placeholder_image'))
)
end
if type(filename) ~= 'string' then
return ''
end
local parts = mw.text.split(filename, ':', true)
if #parts > 1 then
table.remove(parts, 1)
filename = table.concat(parts, ':')
end
local html = mw.html.create('div')
:addClass('infobox__image')
:wikitext(string.format('[[File:%s|400px]]', filename))
if hasPlaceholderImage == true then
local icon = mw.html.create('span'):addClass('citizen-ui-icon mw-ui-icon-wikimedia-upload')
-- TODO: Point the Upload link to a specific file name
html:tag('div'):addClass('infobox__image-upload')
:wikitext(string.format('[[%s|%s]]', 'Special:UploadWizard',
tostring(icon) .. t('label_upload_image')))
end
local item = tostring(html)
table.insert(self.entries, item)
return item
end
--- Return the HTML of the infobox indicator component as string
---
--- @param data table {data, class, color, nopadding)
--- @return string html
function methodtable.renderIndicator(self, data)
checkType('Module:InfoboxNeue.renderIndicator', 1, self, 'table')
checkType('Module:InfoboxNeue.renderIndicator', 2, data, 'table')
if data == nil or data['data'] == nil or data['data'] == '' then return '' end
local html = mw.html.create('div'):addClass('infobox__indicators')
local htmlClasses = {
'infobox__indicator'
}
if data['class'] then
table.insert(htmlClasses, data['class'])
end
if data['color'] then
table.insert(htmlClasses, 'infobox__indicator--' .. data['color'])
end
if data['nopadding'] == true then
table.insert(htmlClasses, 'infobox__indicator--nopadding')
end
html:wikitext(
self:renderItem(
{
['data'] = data['data'],
['class'] = table.concat(htmlClasses, ' '),
row = true,
spacebetween = true
}
)
)
local item = tostring(html)
table.insert(self.entries, item)
return item
end
--- Return the HTML of the infobox header component as string
---
--- @param data table {title, subtitle, badge)
--- @return string html
function methodtable.renderHeader(self, data)
checkType('Module:InfoboxNeue.renderHeader', 1, self, 'table')
checkTypeMulti('Module:InfoboxNeue.renderHeader', 2, data, { 'table', 'string' })
if type(data) == 'string' then
data = {
title = data
}
end
if data == nil or data['title'] == nil then return '' end
local html = mw.html.create('div'):addClass('infobox__header')
if data['badge'] then
html:tag('div')
:addClass('infobox__item infobox__badge')
:wikitext(data['badge'])
end
local titleItem = mw.html.create('div'):addClass('infobox__item')
titleItem:tag('div')
:addClass('infobox__title')
:wikitext(data['title'])
if data['subtitle'] then
titleItem:tag('div')
-- Subtitle is always data
:addClass('infobox__subtitle infobox__data')
:wikitext(data['subtitle'])
end
html:node(titleItem)
local item = tostring(html)
table.insert(self.entries, item)
return item
end
--- Wrap the HTML into an infobox section
---
--- @param data table {title, subtitle, content, border, col, class}
--- @param noInsert boolean whether to insert this section into the internal table table
--- @return string html
function methodtable.renderSection(self, data, noInsert)
checkType('Module:InfoboxNeue.renderSection', 1, self, 'table')
checkType('Module:InfoboxNeue.renderSection', 2, data, 'table')
checkType('Module:InfoboxNeue.renderSection', 3, noInsert, 'boolean', true)
noInsert = noInsert or false
if type(data.content) == 'table' then
data.content = table.concat(data.content)
end
if data == nil or data['content'] == nil or data['content'] == '' then return '' end
local html = mw.html.create('div'):addClass('infobox__section')
if data['title'] then
local header = html:tag('div'):addClass('infobox__sectionHeader')
header:tag('div')
:addClass('infobox__sectionTitle')
:wikitext(data['title'])
if data['subtitle'] then
header:tag('div')
:addClass('infobox__sectionSubtitle')
:wikitext(data['subtitle'])
end
end
local content = html:tag('div')
content:addClass('infobox__sectionContent')
:wikitext(data['content'])
if data['border'] == false then html:addClass('infobox__section--noborder') end
if data['col'] then content:addClass('infobox__grid--cols-' .. data['col']) end
if data['class'] then html:addClass(data['class']) end
local item = tostring(html)
if not noInsert then
table.insert(self.entries, item)
end
return item
end
--- Return the HTML of the infobox link button component as string
---
--- @param data table {label, link, page}
--- @return string html
function methodtable.renderLinkButton(self, data)
checkType('Module:InfoboxNeue.renderLinkButton', 1, self, 'table')
checkType('Module:InfoboxNeue.renderLinkButton', 2, data, 'table')
if data == nil or data['label'] == nil or (data['link'] == nil and data['page'] == nil) then return '' end
--- Render multiple linkButton when link is a table
if type(data['link']) == 'table' then
local htmls = {}
for i, url in ipairs(data['link']) do
table.insert(htmls,
self:renderLinkButton({
label = string.format('%s %d', data['label'], i),
link = url
})
)
end
return table.concat(htmls)
end
local html = mw.html.create('div'):addClass('infobox__linkButton')
if data['link'] then
html:wikitext(string.format('[%s %s]', restoreUnderscore(data['link']), data['label']))
elseif data['page'] then
html:wikitext(string.format('[[%s|%s]]', data['page'], data['label']))
end
return tostring(html)
end
--- Return the HTML of the infobox footer component as string
---
--- @param data table {content, button}
--- @return string html
function methodtable.renderFooter(self, data)
checkType('Module:InfoboxNeue.renderFooter', 1, self, 'table')
checkType('Module:InfoboxNeue.renderFooter', 2, data, 'table')
if data == nil then return '' end
-- Checks if an input is of type 'table' or 'string' and if it is not empty
local function isNonEmpty(input)
return (type(input) == 'table' and next(input) ~= nil) or (type(input) == 'string' and #input > 0)
end
local hasContent = isNonEmpty(data['content'])
local hasButton = isNonEmpty(data['button']) and isNonEmpty(data['button']['content']) and
isNonEmpty(data['button']['label'])
if not hasContent and not hasButton then return '' end
local html = mw.html.create('div'):addClass('infobox__footer')
if hasContent then
local content = data['content']
if type(content) == 'table' then content = table.concat(content) end
html:addClass('infobox__footer--has-content')
html:tag('div')
:addClass('infobox__section')
:wikitext(content)
end
if hasButton then
html:addClass('infobox__footer--has-button')
local buttonData = data['button']
local button = html:tag('div'):addClass('infobox__button')
local label = button:tag('div'):addClass('infobox__buttonLabel')
if buttonData['icon'] ~= nil then
label:wikitext(string.format('[[File:%s|16px|link=]]%s', buttonData['icon'], buttonData['label']))
else
label:wikitext(buttonData['label'])
end
if buttonData['type'] == 'link' then
button:tag('div')
:addClass('infobox__buttonLink')
:wikitext(buttonData['content'])
elseif buttonData['type'] == 'popup' then
button:tag('div')
:addClass('infobox__buttonCard')
:wikitext(buttonData['content'])
end
end
local item = tostring(html)
table.insert(self.entries, item)
return item
end
--- Return the HTML of the infobox footer button component as string
---
--- @param data table {icon, label, type, content}
--- @return string html
function methodtable.renderFooterButton(self, data)
checkType('Module:InfoboxNeue.renderFooterButton', 1, self, 'table')
checkType('Module:InfoboxNeue.renderFooterButton', 2, data, 'table')
if data == nil then return '' end
return self:renderFooter({ button = data })
end
--- Return the HTML of the infobox item component as string
---
--- @param data table {label, data, desc, class, tooltip, icon, row, spacebetween, colspan)
--- @param content string|number|nil optional
--- @return string html
function methodtable.renderItem(self, data, content)
checkType('Module:InfoboxNeue.renderItem', 1, self, 'table')
checkTypeMulti('Module:InfoboxNeue.renderItem', 2, data, { 'table', 'string' })
checkTypeMulti('Module:InfoboxNeue.renderItem', 3, content, { 'string', 'number', 'nil' })
-- The arguments are not passed as a table
-- Allows to call this as box:renderItem( 'Label', 'Data' )
if content ~= nil then
data = {
label = data,
data = content
}
end
if data == nil or data['data'] == nil or data['data'] == '' then return '' end
if self.config.removeEmpty == true and data['data'] == self.config.emptyString then
return ''
end
local html = mw.html.create('div'):addClass('infobox__item')
if data['class'] then html:addClass(data['class']) end
if data['tooltip'] then html:attr('title', data['tooltip']) end
if data['row'] == true then html:addClass('infobox__grid--row') end
if data['spacebetween'] == true then html:addClass('infobox__grid--space-between') end
if data['colspan'] then html:addClass('infobox__grid--col-span-' .. data['colspan']) end
local textWrapper = html
if data['link'] then
html:addClass('infobox__itemButton')
html:tag('div')
:addClass('infobox__itemButtonLink')
:wikitext(string.format('[%s]', data['link']))
elseif data['page'] then
html:addClass('infobox__itemButton')
html:tag('div')
:addClass('infobox__itemButtonLink')
:wikitext(string.format('[[%s]]', data['link']))
end
if data['icon'] then
html:addClass('infobox__item--hasIcon')
html:tag('div')
:addClass('infobox__icon')
:wikitext(string.format('[[File:%s|16px|link=]]', data['icon']))
-- Create wrapper for text to align with icon
textWrapper = html:tag('div'):addClass('infobox__text')
end
local dataOrder = { 'label', 'data', 'desc' }
for _, key in ipairs(dataOrder) do
if data[key] then
if type(data[key]) == 'table' then
data[key] = table.concat(data[key], ', ')
end
local actualData = data[key]
if key == 'data' and type(string.find(data[key], '^%*')) ~= 'nil' then
actualData = "\n\n" .. data[key]
end
textWrapper:tag('div')
:addClass('infobox__' .. key)
:wikitext(actualData)
end
end
-- Add arrow indicator as affordnance
if data['link'] or data['page'] then
html:tag('div'):addClass('infobox__itemButtonArrow citizen-ui-icon mw-ui-icon-wikimedia-collapse')
end
return tostring(html)
end
--- Wrap the infobox HTML
---
--- @param innerHtml string inner html of the infobox
--- @param snippetText string text used in snippet in mobile view
--- @return string html infobox html with templatestyles
function methodtable.renderInfobox(self, innerHtml, snippetText)
checkType('Module:InfoboxNeue.renderInfobox', 1, self, 'table')
checkTypeMulti('Module:InfoboxNeue.renderInfobox', 2, innerHtml, { 'table', 'string', 'nil' })
checkType('Module:InfoboxNeue.renderInfobox', 3, snippetText, 'string', true)
innerHtml = innerHtml or self.entries
if type(innerHtml) == 'table' then
innerHtml = table.concat(self.entries)
end
local function renderContent()
local html = mw.html.create('div')
:addClass('infobox__content')
:wikitext(innerHtml)
return tostring(html)
end
local function renderSnippet()
if snippetText == nil then snippetText = mw.title.getCurrentTitle().text end
local html = mw.html.create()
html:tag('div')
:addClass('citizen-ui-icon mw-ui-icon-wikimedia-collapse')
:done()
:tag('div')
:addClass('infobox__data')
:wikitext(string.format('%s:', t('label_quick_facts')))
:done()
:tag('div')
:addClass('infobox__desc')
:wikitext(snippetText)
return tostring(html)
end
local frame = mw.getCurrentFrame()
local output = getDetailsHTML({
details = {
class = 'infobox floatright noexcerpt',
content = renderContent()
},
summary = {
class = 'infobox__snippet',
content = renderSnippet()
}
}, frame)
return frame:extensionTag {
name = 'templatestyles', args = { src = 'Module:InfoboxNeue/styles.css' }
} .. output .. table.concat(self.categories)
end
--- Just an accessor for the class method
function methodtable.showDescIfDiff(s1, s2)
return InfoboxNeue.showDescIfDiff(s1, s2)
end
--- Format text to show comparison as desc text if two strings are different
---
--- @param s1 string|nil base
--- @param s2 string|nil comparsion
--- @return string|nil html
function InfoboxNeue.showDescIfDiff(s1, s2)
if s1 == nil or s2 == nil or s1 == s2 then return s1 end
return string.format('%s <span class="infobox__desc">(%s)</span>', s1, s2)
end
--- New Instance
---
--- @return table InfoboxNeue
function InfoboxNeue.new(self, config)
local baseConfig = {
-- Flag to discard empty rows
removeEmpty = true,
-- Optional string which is valued as empty
emptyString = nil,
-- Display a placeholder image if addImage does not find an image
displayPlaceholder = true,
-- Placeholder Image
placeholderImage = 'Unknown.png',
}
for k, v in pairs(config or {}) do
baseConfig[k] = v
end
local instance = {
categories = {},
config = baseConfig,
entries = {}
}
setmetatable(instance, metatable)
return instance
end
--- Create an Infobox from args
---
--- @param frame table
--- @return string
function InfoboxNeue.fromArgs(frame)
local instance = InfoboxNeue:new()
local args = require('Module:Arguments').getArgs(frame)
local sections = {
{ content = {}, col = 2 }
}
local sectionMap = { default = 1 }
local currentSection
if args['image'] then
instance:renderImage(args['image'])
if args['indicator'] then
instance:renderIndicator({
data = args['indicator'],
class = args['indicatorClass']
})
end
else
for i = 1, 3, 1 do
if args['image' .. i] then
instance:renderImage(args['image' .. i])
if args['indicator' .. i] then
instance:renderIndicator({
data = args['indicator' .. i],
class = args['indicatorClass' .. i]
})
end
end
end
end
if args['title'] then
instance:renderHeader({
title = args['title'],
subtitle = args['subtitle'],
})
end
for key, value in orderedPairs(args) do
if type(string.match(key, '^label')) ~= 'nil' then
if args['section' .. removeprefix(key, 'label')] then
currentSection = args['section' .. removeprefix(key, 'label')]
table.insert(sections, {
title = currentSection,
subtitle = args['section-subtitle' .. removeprefix(key, 'label')],
col = args['section-col' .. removeprefix(key, 'label')] or 2,
content = {}
})
sectionMap[currentSection] = #sections
end
local data = {
label = value,
data = args['content' .. removeprefix(key, 'label')]
}
table.insert(sections[sectionMap[(currentSection or 'default')]].content,
instance:renderItem(data, nil))
end
end
for _, section in ipairs(sections) do
instance:renderSection(section)
end
return instance:renderInfobox(nil, args['snippet'])
end
return InfoboxNeue