Module:AVDevice: Difference between revisions
Rename args.oem_manufacturer to args.oem to match CRT model convention (via update-page on MediaWiki MCP Server) |
Fix Lua error at line 612: wrap bare gsub() calls in parentheses to prevent multi-return value issue with table.insert (TBC + Documents sections) (via update-page on MediaWiki MCP Server) |
||
| Line 394: | Line 394: | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
table.insert(cells, cellContent:gsub('<[^>]+>', '')) | table.insert(cells, (cellContent:gsub('<[^>]+>', ''))) | ||
end | end | ||
if #cells >= 2 then | if #cells >= 2 then | ||
| Line 610: | Line 610: | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
table.insert(cells, cellContent:gsub('<[^>]+>', '')) | table.insert(cells, (cellContent:gsub('<[^>]+>', ''))) | ||
end | end | ||
if #cells >= 2 then | if #cells >= 2 then | ||
Revision as of 05:31, 25 February 2026
Documentation for this module may be created at Module:AVDevice/doc
-- Module:AVDevice
-- Builds the AV device infobox as strict HTML to avoid whitespace issues
-- Uses frame:preprocess() so parser functions like #ask and #formredlink evaluate.
local p = {}
local function trim(s)
if s == nil then return nil end
s = tostring(s)
s = s:gsub('^%s+', ''):gsub('%s+$', '')
if s == '' then return nil end
return s
end
local function css(node, cssText)
if cssText and cssText ~= '' then
node:cssText(cssText)
end
return node
end
local function addSectionRow(container, title)
local section = container:tag('div')
section:addClass('infobox-section-header')
css(section, 'grid-column: 1 / -1; text-align:center; padding:0.5em; font-weight:bold;')
section:wikitext(title)
end
local function addRow(container, label, valueHtmlOrWikitext, isRawHtml)
local labelDiv = container:tag('div')
labelDiv:addClass('infobox-label')
css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
labelDiv:wikitext(label)
local valueDiv = container:tag('div')
valueDiv:addClass('infobox-value')
css(valueDiv, 'padding:0.2em 0.4em;')
if isRawHtml then
valueDiv:node(mw.html.create('span'):wikitext(valueHtmlOrWikitext))
else
valueDiv:wikitext(valueHtmlOrWikitext)
end
end
local function addFullRow(container, valueHtmlOrWikitext, cssText, isRawHtml, extraClass)
local fullDiv = container:tag('div')
css(fullDiv, 'grid-column: 1 / -1; ' .. (cssText or ''))
if extraClass then
fullDiv:addClass(extraClass)
end
if isRawHtml then
fullDiv:wikitext(valueHtmlOrWikitext)
else
fullDiv:wikitext(valueHtmlOrWikitext)
end
end
local function getDisplayTextWithoutBrand(itemName, deviceBrand)
if not itemName then return nil end
if not deviceBrand then return itemName end
local brandPrefix = deviceBrand .. ' '
if itemName:sub(1, #brandPrefix) == brandPrefix then
return itemName:sub(#brandPrefix + 1)
end
return itemName
end
local function formatList(value, inline)
if not value then return nil end
local items = {}
for item in value:gmatch('[^,]+') do
local trimmed = trim(item)
if trimmed then table.insert(items, trimmed) end
end
if #items == 0 then return nil end
if inline or #items <= 3 then
return table.concat(items, ', ')
else
local ul = mw.html.create('ul')
ul:css('margin', '0'):css('padding-left', '1.2em')
for _, item in ipairs(items) do ul:tag('li'):wikitext(item) end
return tostring(ul)
end
end
local function formatMSRP(value)
if not value then return nil end
local num = tonumber(value)
if not num then return '$' .. value end
local formatted = string.format("%.2f", num)
local intPart, decPart = formatted:match("^(%d+)%.(%d+)$")
if intPart then
local reversed = intPart:reverse()
local withCommas = reversed:gsub("(%d%d%d)", "%1,"):reverse():gsub("^,", "")
return '$' .. withCommas .. '.' .. decPart
end
return '$' .. formatted
end
local function formatRelatedModels(value, deviceBrand)
if not value then return nil end
local items = {}
for item in value:gmatch('[^,]+') do
local trimmed = trim(item)
if trimmed then
local displayText = getDisplayTextWithoutBrand(trimmed, deviceBrand)
table.insert(items, '[[' .. trimmed .. '|' .. displayText .. ']]')
end
end
if #items == 0 then return nil end
return table.concat(items, '<br>')
end
local function queryIOByLocation(frame, fullPageName, ioType, location)
local locationFilter = ''
if location then
locationFilter = ' [[Has ' .. (ioType == 'input' and 'input' or 'output') .. ' location::' .. location .. ']]\n'
end
local signalProp = ioType == 'input' and 'Has video signal format' or 'Has output signal format'
local countProp = ioType == 'input' and 'Has input count' or 'Has output count'
local connectorProp = ioType == 'input' and 'Has connector type' or 'Has output connector'
local notesProp = ioType == 'input' and 'Has input notes' or 'Has output notes'
local labelProp = ioType == 'input' and 'Has input label' or 'Has output label'
local templateName = ioType == 'input' and 'AV device input row' or 'AV device output row'
local audioProps = ''
if ioType == 'input' then
audioProps = ' |?Has audio type=audio\n' ..
' |?Has audio connector=audio_connector\n' ..
' |?Has audio shared with=audio_shared\n'
end
local queryWikitext =
'{{#ask:\n' ..
' [[Has AV device::' .. fullPageName .. ']]\n' ..
' [[' .. signalProp .. '::+]]\n' ..
locationFilter ..
' |?' .. countProp .. '=count\n' ..
' |?' .. signalProp .. '=signal\n' ..
' |?' .. connectorProp .. '=connector\n' ..
' |?' .. labelProp .. '=label\n' ..
' |?' .. notesProp .. '=notes\n' ..
audioProps ..
' |format=template\n' ..
' |template=' .. templateName .. '\n' ..
' |named args=yes\n' ..
' |link=none\n' ..
'}}'
local result = frame:preprocess(queryWikitext)
return trim(result)
end
local function discoverLocations(frame, fullPageName, ioType)
local locationProp, signalProp
if ioType == 'input' then
locationProp = 'Has input location'
signalProp = 'Has video signal format'
else
locationProp = 'Has output location'
signalProp = 'Has output signal format'
end
local queryWikitext =
'{{#ask:\n' ..
' [[Has AV device::' .. fullPageName .. ']]\n' ..
' [[' .. signalProp .. '::+]]\n' ..
' [[' .. locationProp .. '::+]]\n' ..
' |?' .. locationProp .. '=location\n' ..
' |format=broadtable\n' ..
' |headers=hide\n' ..
' |link=none\n' ..
'}}'
local result = frame:preprocess(queryWikitext)
local seen = {}
local locations = {}
local preferredOrder = {rear = 1, front = 2, side = 3, top = 4, bottom = 5, internal = 6}
if result then
for rowContent in result:gmatch('<tr[^>]*>(.-)</tr>') do
local cells = {}
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do
local cleanContent = cellContent:gsub('<[^>]+>', '')
table.insert(cells, trim(cleanContent))
end
if #cells >= 2 and cells[2] then
local loc = mw.text.trim(cells[2])
local locLower = loc:lower()
if locLower ~= '' and not seen[locLower] then
seen[locLower] = true
table.insert(locations, locLower)
end
end
end
end
table.sort(locations, function(a, b)
local orderA = preferredOrder[a] or 1000
local orderB = preferredOrder[b] or 1000
if orderA ~= orderB then return orderA < orderB end
return a < b
end)
return locations
end
local function locationLabel(loc)
if not loc or loc == '' then return '' end
return loc:sub(1, 1):upper() .. loc:sub(2)
end
function p.infobox(frame)
local parent = frame:getParent()
local args = parent and parent.args or frame.args
local title = mw.title.getCurrentTitle()
local pageName = title.text
local fullPageName = title.fullText
local pageId = title.id or 0
local brand = trim(args.brand)
local model_code = trim(args.model_code)
local oem_manufacturer = trim(args.oem)
local device_type = trim(args.device_type)
local format_family = trim(args.format_family)
local market = trim(args.market)
local supported_formats = trim(args.supported_formats)
local recording_formats = trim(args.recording_formats)
local image_main = trim(args.image_main)
local year_released = trim(args.year_released)
local year_discontinued = trim(args.year_discontinued)
local msrp = trim(args.msrp)
local av_system = trim(args.av_system)
local tuner_system = trim(args.tuner_system)
local frequency = trim(args.frequency)
local power_avg = trim(args.power_avg)
local power_max = trim(args.power_max)
local features = trim(args.features)
local height = trim(args.height)
local width = trim(args.width)
local depth = trim(args.depth)
local weight = trim(args.weight)
local related_models = trim(args.related_models)
local styleTag = frame:extensionTag('templatestyles', '', {src = 'Template:Infobox styles.css'})
local container = mw.html.create('div')
container:addClass('infobox')
container:addClass('infobox-av-device')
css(container, 'float:right; clear:right; margin:0 0 1em 1em; width:22em; font-size:88%; line-height:1.5em; display:grid; grid-template-columns:auto 1fr; gap:3px; padding:3px;')
addFullRow(container, (brand or '') .. ' ' .. (model_code or ''), 'text-align:center; font-size:125%; font-weight:bold; padding:0.5em;', false, 'infobox-title')
local badgeWikitext = '[[AV Device Search|AV device]]'
if device_type then
local typeUrl = tostring(mw.uri.fullUrl('AV Device Search', {device_type = device_type}))
badgeWikitext = badgeWikitext .. ' › <span class="plainlinks">[' .. typeUrl .. ' ' .. device_type .. ']</span>'
end
addFullRow(container, badgeWikitext, '', false, 'infobox-type-badge')
if image_main then
local file = image_main:gsub('^File:', '')
addFullRow(container, string.format('[[File:%s|frameless|300px]]', file), 'text-align:center; padding:0;', false, 'infobox-image')
end
addSectionRow(container, 'Overview')
if brand then
local brandWikitext = string.format('{{#formredlink: target=%s |form=Manufacturer |existing page link text=%s }}', brand, brand)
addRow(container, 'Brand', frame:preprocess(brandWikitext), true)
end
if oem_manufacturer then
local oemWikitext = string.format('{{#formredlink: target=%s |form=Manufacturer |existing page link text=%s }}', oem_manufacturer, oem_manufacturer)
addRow(container, 'OEM', frame:preprocess(oemWikitext), true)
end
if model_code then addRow(container, 'Model', model_code, false) end
if market then addRow(container, 'Market', market, false) end
if device_type then
local typeSearchUrl = tostring(mw.uri.fullUrl('AV Device Search', {device_type = device_type}))
addRow(container, 'Type', '<span class="plainlinks">[' .. typeSearchUrl .. ' ' .. device_type .. ']</span>', true)
end
if format_family then
addRow(container, 'Format family', '[[:Category:' .. format_family .. ' devices|' .. format_family .. ']]', true)
end
if year_released or year_discontinued then
local yearStr = ''
if year_released and year_discontinued then yearStr = year_released .. ' – ' .. year_discontinued
elseif year_released then yearStr = year_released .. ' –'
elseif year_discontinued then yearStr = '– ' .. year_discontinued end
addRow(container, 'Years', yearStr, false)
end
if msrp then addRow(container, 'MSRP', formatMSRP(msrp), false) end
if av_system then
local formattedAV = formatList(av_system, true)
if formattedAV then addRow(container, 'AV system', formattedAV, false) end
end
if related_models then
local formattedRelated = formatRelatedModels(related_models, brand)
if formattedRelated then addRow(container, 'Related', formattedRelated, true) end
end
local ecidWikitext = string.format('[{{fullurl:%s|curid=%d}} EC%d]', pageName, pageId, pageId)
addRow(container, 'ECID', frame:preprocess(ecidWikitext), true)
if supported_formats or recording_formats then
addSectionRow(container, 'Format Compatibility')
if supported_formats then
local f = formatList(supported_formats, true)
if f then addRow(container, 'Plays', f, false) end
end
if recording_formats then
local f = formatList(recording_formats, true)
if f then addRow(container, 'Records', f, false) end
end
end
local function renderIOSection(sectionTitle, ioType)
local locations = discoverLocations(frame, fullPageName, ioType)
local locationData = {}
for _, loc in ipairs(locations) do
local content = queryIOByLocation(frame, fullPageName, ioType, loc)
if content and content ~= '' then
table.insert(locationData, {location = loc, content = content})
end
end
if #locationData > 0 then
addSectionRow(container, sectionTitle)
for _, data in ipairs(locationData) do
local labelDiv = container:tag('div')
labelDiv:addClass('infobox-label')
css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
labelDiv:wikitext(locationLabel(data.location))
local valueDiv = container:tag('div')
valueDiv:addClass('infobox-value')
css(valueDiv, 'padding:0.2em 0.4em;')
valueDiv:node(mw.html.create('span'):wikitext(data.content))
end
end
end
renderIOSection('Inputs', 'input')
renderIOSection('Outputs', 'output')
if features then
addSectionRow(container, 'Features')
addFullRow(container, features, 'padding:0.2em 0.4em;', false)
end
if height or width or depth or weight then
addSectionRow(container, 'Dimensions')
if height or width or depth then
addRow(container, 'H × W × D', string.format('%s × %s × %s', height or '–', width or '–', depth or '–'), false)
end
if weight then
local weightWikitext = '{{#show: ' .. fullPageName .. ' |?Weight # lb }} / {{#show: ' .. fullPageName .. ' |?Weight # kg }}'
addRow(container, 'Weight', frame:preprocess(weightWikitext), true)
end
end
local voltageQueryWikitext =
'{{#ask:\n [[Has AV device::' .. pageName .. ']]\n [[Voltage min::+]]\n |?Voltage min=vmin\n |?Voltage max=vmax\n |format=template\n |template=AV device voltage row\n |named args=yes\n |link=none\n}}'
local voltageResult = frame:preprocess(voltageQueryWikitext)
local hasVoltage = voltageResult and trim(voltageResult) and trim(voltageResult) ~= ''
if hasVoltage or frequency or power_avg or power_max then
addSectionRow(container, 'Power')
if hasVoltage then addRow(container, 'Voltage', voltageResult, true) end
if frequency then
local formattedFreq = formatList(frequency, true)
if formattedFreq then addRow(container, 'AC frequency', formattedFreq, false) end
end
if power_avg or power_max then
local powerStr = ''
if power_avg and power_max then powerStr = power_avg .. 'W (avg) / ' .. power_max .. 'W (max)'
elseif power_avg then powerStr = power_avg .. 'W'
elseif power_max then powerStr = power_max .. 'W (max)' end
addRow(container, 'Power', powerStr, false)
end
end
local tbcCountWikitext = '{{#ask:\n [[TBC type::+]]\n [[-Has subobject::' .. fullPageName .. ']]\n |format=count\n}}'
local tbcCountResult = frame:preprocess(tbcCountWikitext)
local hasTBC = tbcCountResult and tonumber(trim(tbcCountResult)) and tonumber(trim(tbcCountResult)) > 0
if hasTBC then
addSectionRow(container, 'Time Base Correction')
local tbcQueryWikitext = '{{#ask:\n [[TBC type::+]]\n [[-Has subobject::' .. fullPageName .. ']]\n |?TBC type\n |?TBC buffer size\n |?TBC notes\n |format=broadtable\n |headers=hide\n |link=none\n}}'
local tbcResult = frame:preprocess(tbcQueryWikitext)
if tbcResult then
for rowContent in tbcResult:gmatch('<tr[^>]*>(.-)</tr>') do
local cells = {}
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do
table.insert(cells, (cellContent:gsub('<[^>]+>', '')))
end
if #cells >= 2 then
local tbcType = trim(cells[2])
local tbcBuffer = trim(cells[3])
local tbcNotes = trim(cells[4])
if tbcType then
local group = container:tag('div')
group:addClass('infobox-tbc-group')
css(group, 'grid-column: 1 / -1; display:grid; grid-template-columns:auto 1fr; gap:3px;')
local tl = group:tag('div'):addClass('infobox-label')
css(tl, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
tl:wikitext('Type')
local tv = group:tag('div'):addClass('infobox-value')
css(tv, 'padding:0.2em 0.4em;')
tv:wikitext(tbcType)
if tbcBuffer then
local bl = group:tag('div'):addClass('infobox-label')
css(bl, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
bl:wikitext('Buffer')
local bv = group:tag('div'):addClass('infobox-value')
css(bv, 'padding:0.2em 0.4em;')
bv:wikitext(tbcBuffer)
end
if tbcNotes then
local nl = group:tag('div'):addClass('infobox-label')
css(nl, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
nl:wikitext('Notes')
local nv = group:tag('div'):addClass('infobox-value')
css(nv, 'padding:0.2em 0.4em; font-size:0.92em;')
nv:wikitext(tbcNotes)
end
end
end
end
end
end
-- Accessories section
addSectionRow(container, 'Accessories')
local addAccessoryUrl = mw.uri.fullUrl("Create an accessory", {av_devices = pageName})
local accessoriesCountWikitext = '{{#ask:\n [[Category:Accessories]]\n [[Has related AV device::' .. fullPageName .. ']]\n |format=count\n}}'
local accessoryCount = frame:preprocess(accessoriesCountWikitext)
local hasAccessories = accessoryCount and tonumber(trim(accessoryCount)) and tonumber(trim(accessoryCount)) > 0
local accDiv = container:tag('div')
css(accDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;')
if hasAccessories then
local accessoriesQueryWikitext = '{{#ask:\n [[Category:Accessories]]\n [[Has related AV device::' .. fullPageName .. ']]\n |?Has accessory type=type\n |?Has model code=model\n |format=broadtable\n |headers=hide\n |link=none\n}}'
local accessoriesResult = frame:preprocess(accessoriesQueryWikitext)
local accessoriesByType = {}
local typeOrder = {}
if accessoriesResult then
for rowContent in accessoriesResult:gmatch('<tr[^>]*>(.-)</tr>') do
local cells = {}
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do
table.insert(cells, trim(cellContent:gsub('<[^>]+>', '')))
end
if #cells >= 2 then
local accPageName = cells[1]
local accType = cells[2] or 'Accessory'
if accPageName then
if not accessoriesByType[accType] then
accessoriesByType[accType] = {}
table.insert(typeOrder, accType)
end
table.insert(accessoriesByType[accType], {page = accPageName})
end
end
end
end
local accGrid = accDiv:tag('div')
css(accGrid, 'display:grid; grid-template-columns:auto 1fr; gap:3px;')
for _, accType in ipairs(typeOrder) do
local accs = accessoriesByType[accType]
if accs and #accs > 0 then
local accLinks = {}
for _, acc in ipairs(accs) do table.insert(accLinks, '[[' .. acc.page .. ']]') end
local ld = accGrid:tag('div'):addClass('infobox-label')
css(ld, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
ld:wikitext(accType)
local vd = accGrid:tag('div'):addClass('infobox-value')
css(vd, 'padding:0.2em 0.4em;')
vd:wikitext(table.concat(accLinks, '<br>'))
end
end
local addAccDiv = mw.html.create('div')
addAccDiv:css('margin-top', '0.5em'):css('text-align', 'center')
addAccDiv:wikitext('[' .. tostring(addAccessoryUrl) .. ' <span class="infobox-button infobox-button-secondary">Add accessory</span>]')
accDiv:node(addAccDiv)
else
local addAccDiv = mw.html.create('div')
addAccDiv:css('text-align', 'center')
addAccDiv:wikitext('[' .. tostring(addAccessoryUrl) .. ' <span class="infobox-button infobox-button-secondary">Add accessory</span>]')
accDiv:node(addAccDiv)
end
-- Parts section
addSectionRow(container, 'Parts')
local addPartUrl = mw.uri.fullUrl("Create a part", {av_devices = pageName})
local partsCountWikitext = '{{#ask:\n [[Category:Parts]]\n [[Has related AV device::' .. fullPageName .. ']]\n |format=count\n}}'
local partsCount = frame:preprocess(partsCountWikitext)
local hasParts = partsCount and tonumber(trim(partsCount)) and tonumber(trim(partsCount)) > 0
local partsDiv = container:tag('div')
css(partsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;')
if hasParts then
local partsQueryWikitext = '{{#ask:\n [[Category:Parts]]\n [[Has related AV device::' .. fullPageName .. ']]\n |?Has part type=type\n |?Has part subtype=subtype\n |?Has model code=model\n |format=broadtable\n |headers=hide\n |link=none\n}}'
local partsResult = frame:preprocess(partsQueryWikitext)
local partsByType = {}
local partTypeOrder = {}
if partsResult then
for rowContent in partsResult:gmatch('<tr[^>]*>(.-)</tr>') do
local cells = {}
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do
table.insert(cells, trim(cellContent:gsub('<[^>]+>', '')))
end
if #cells >= 2 then
local partPageName = cells[1]
local partType = cells[2] or 'Part'
local partSubtype = cells[3]
local groupKey = partType
if partSubtype and partSubtype ~= '' then groupKey = partSubtype .. ' ' .. partType end
if partPageName then
if not partsByType[groupKey] then
partsByType[groupKey] = {}
table.insert(partTypeOrder, groupKey)
end
table.insert(partsByType[groupKey], {page = partPageName})
end
end
end
end
local partsGrid = partsDiv:tag('div')
css(partsGrid, 'display:grid; grid-template-columns:auto 1fr; gap:3px;')
for _, partType in ipairs(partTypeOrder) do
local parts = partsByType[partType]
if parts and #parts > 0 then
local partLinks = {}
for _, part in ipairs(parts) do table.insert(partLinks, '[[' .. part.page .. ']]') end
local ld = partsGrid:tag('div'):addClass('infobox-label')
css(ld, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;')
ld:wikitext(partType)
local vd = partsGrid:tag('div'):addClass('infobox-value')
css(vd, 'padding:0.2em 0.4em;')
vd:wikitext(table.concat(partLinks, '<br>'))
end
end
local addPartDiv = mw.html.create('div')
addPartDiv:css('margin-top', '0.5em'):css('text-align', 'center')
addPartDiv:wikitext('[' .. tostring(addPartUrl) .. ' <span class="infobox-button infobox-button-secondary">Add part</span>]')
partsDiv:node(addPartDiv)
else
local addPartDiv = mw.html.create('div')
addPartDiv:css('text-align', 'center')
addPartDiv:wikitext('[' .. tostring(addPartUrl) .. ' <span class="infobox-button infobox-button-secondary">Add part</span>]')
partsDiv:node(addPartDiv)
end
-- Archival Links section
local linksQueryWikitext = '{{#ask:\n [[AV device::' .. fullPageName .. ']]\n |?Model link type\n |?Model link source\n |?Model link URL\n |format=broadtable\n |headers=hide\n |link=none\n}}'
local linksResult = frame:preprocess(linksQueryWikitext)
local linksByType = {Manufacturer = {}, Retailer = {}, Database = {}}
local hasLinks = false
if linksResult then
for rowContent in linksResult:gmatch('<tr[^>]*>(.-)</tr>') do
local cells = {}
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do
table.insert(cells, trim(cellContent:gsub('<[^>]+>', '')))
end
if #cells >= 4 then
local linkType = cells[2]
local linkSource = cells[3]
local linkUrl = cells[4]
if linkType and linkSource and linkUrl and linkUrl ~= '' and linksByType[linkType] then
table.insert(linksByType[linkType], {source = linkSource, url = linkUrl})
hasLinks = true
end
end
end
end
if hasLinks then
addSectionRow(container, 'Archival Links')
for _, linkType in ipairs({'Database', 'Manufacturer', 'Retailer'}) do
if #linksByType[linkType] > 0 then
local linksHtml = {}
for _, link in ipairs(linksByType[linkType]) do
table.insert(linksHtml, '[' .. link.url .. ' ' .. link.source .. ']')
end
addRow(container, linkType, table.concat(linksHtml, '<br>'), true)
end
end
end
-- Documents section
addSectionRow(container, 'Documents')
local timestamp = os.time()
math.randomseed(timestamp + pageId)
local random = math.random(1000, 9999)
local target = "Document:" .. timestamp .. "-" .. random
local uploadUrl = mw.uri.fullUrl("Special:FormEdit", {form = "Document", target = target, ["Document[av_devices]"] = pageName})
local documentsCountWikitext = '{{#ask:\n [[Category:Documents]]\n [[Has related AV device::' .. fullPageName .. ']]\n |format=count\n}}'
local documentCount = frame:preprocess(documentsCountWikitext)
local hasDocuments = documentCount and tonumber(trim(documentCount)) and tonumber(trim(documentCount)) > 0
local docsDiv = container:tag('div')
css(docsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;')
if hasDocuments then
local docsQueryWikitext = '{{#ask:\n [[Category:Documents]]\n [[Has related AV device::' .. fullPageName .. ']]\n |?Has document type\n |?Has document URL\n |?Has document file\n |?Has document title\n |format=broadtable\n |headers=hide\n |link=none\n}}'
local docsResult = frame:preprocess(docsQueryWikitext)
local ul = mw.html.create('ul')
ul:css('margin', '0'):css('padding-left', '1.5em')
if docsResult then
for rowContent in docsResult:gmatch('<tr[^>]*>(.-)</tr>') do
local cells = {}
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do
table.insert(cells, (cellContent:gsub('<[^>]+>', '')))
end
if #cells >= 2 then
local docType = trim(cells[2])
local docTitle = trim(cells[5])
local docPageName = trim(cells[1])
if docPageName then
local displayText = 'Document'
if docTitle then displayText = docTitle
elseif docType then displayText = docType end
ul:tag('li'):wikitext('[[' .. docPageName .. '|' .. displayText .. ']]')
end
end
end
end
docsDiv:node(ul)
local uploadDiv = mw.html.create('div')
uploadDiv:css('margin-top', '0.5em'):css('text-align', 'center')
uploadDiv:wikitext('[' .. tostring(uploadUrl) .. ' <span class="infobox-button infobox-button-secondary">Add document</span>]')
docsDiv:node(uploadDiv)
else
local uploadDiv = mw.html.create('div')
uploadDiv:css('text-align', 'center')
uploadDiv:wikitext('[' .. tostring(uploadUrl) .. ' <span class="infobox-button infobox-button-secondary">Add document</span>]')
docsDiv:node(uploadDiv)
end
-- Contribute section
addSectionRow(container, 'Contribute')
local editUrl = mw.uri.fullUrl("Special:FormStart", {form = "AV device", page_name = pageName})
local editDiv = container:tag('div')
css(editDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em; text-align:center;')
editDiv:wikitext('[' .. tostring(editUrl) .. ' <span class="infobox-button infobox-button-primary">Edit this data</span>]')
return styleTag .. tostring(container)
end
return p