Module:CRTModel: Difference between revisions
Fix badge: replace broken mw.html.create('a') with plain wikilinks (MediaWiki sanitizer strips raw a tags) (via update-page on MediaWiki MCP Server) |
Change "Add accessory" button to link to Create_an_accessory with crt_models parameter (via update-page on MediaWiki MCP Server) |
||
| (3 intermediate revisions by the same user not shown) | |||
| Line 298: | Line 298: | ||
) | ) | ||
-- Type badge (breadcrumb) — | -- Type badge (breadcrumb) — plainlinks hides external icon, $wgNoFollowDomainExceptions handles nofollow | ||
local badgeWikitext = '[[CRT Search|CRT]]' | local badgeWikitext = '[[CRT Search|CRT]]' | ||
if crt_type then | if crt_type then | ||
badgeWikitext = badgeWikitext .. ' › [ | local typeUrl = mw.title.new('CRT Search'):fullUrl({crt_type = crt_type}) | ||
badgeWikitext = badgeWikitext .. ' › <span class="plainlinks">[' .. typeUrl .. ' ' .. crt_type .. ']</span>' | |||
end | end | ||
addFullRow(container, badgeWikitext, '', false, 'infobox-type-badge') | addFullRow(container, badgeWikitext, '', false, 'infobox-type-badge') | ||
| Line 413: | Line 413: | ||
if chassis_family then | if chassis_family then | ||
-- Link directly to the chassis family page (no namespace prefix) | |||
local familyWikitext = string.format( | local familyWikitext = string.format( | ||
'{{#formredlink: target=%s |form=Chassis family |existing page link text=%s }}', | '{{#formredlink: target=%s |form=Chassis family |existing page link text=%s }}', | ||
| Line 420: | Line 421: | ||
if chassis then | if chassis then | ||
-- Both: show chassis with family in parentheses on next line | |||
chassisDisplay = chassisDisplay .. '<br><small>Family: ' .. familyHtml .. '</small>' | chassisDisplay = chassisDisplay .. '<br><small>Family: ' .. familyHtml .. '</small>' | ||
else | else | ||
-- Only family: show family alone | |||
chassisDisplay = familyHtml .. ' <small>(family)</small>' | chassisDisplay = familyHtml .. ' <small>(family)</small>' | ||
end | end | ||
| Line 440: | Line 443: | ||
end | end | ||
-- ECID row | -- ECID row: build as a normal external link wikitext; preprocess not required, but fine. | ||
local ecidWikitext = string.format('[{{fullurl:%s|curid=%d}} EC%d]', pageName, pageId, pageId) | local ecidWikitext = string.format('[{{fullurl:%s|curid=%d}} EC%d]', pageName, pageId, pageId) | ||
addRow(container, 'ECID', frame:preprocess(ecidWikitext), true) | addRow(container, 'ECID', frame:preprocess(ecidWikitext), true) | ||
-- Tube section | -- Tube section: show if we have any tube specs | ||
if mask_type or pitch or phosphor_type or gun_type or deflection_angle or neck_diameter or visible_w or visible_h or visible_diag then | if mask_type or pitch or phosphor_type or gun_type or deflection_angle or neck_diameter or visible_w or visible_h or visible_diag then | ||
addSectionRow(container, 'Tube') | addSectionRow(container, 'Tube') | ||
if mask_type then addRow(container, 'Mask', mask_type, false) end | |||
if pitch then addRow(container, 'Pitch', pitch .. ' mm', false) end | if mask_type then | ||
if phosphor_type then addRow(container, 'Phosphors', phosphor_type, false) end | addRow(container, 'Mask', mask_type, false) | ||
if gun_type then addRow(container, 'Gun type', gun_type, false) end | end | ||
if deflection_angle then addRow(container, 'Deflection', deflection_angle .. '°', false) end | |||
if neck_diameter then addRow(container, 'Neck', neck_diameter .. ' mm', false) end | if pitch then | ||
addRow(container, 'Pitch', pitch .. ' mm', false) | |||
end | |||
if phosphor_type then | |||
addRow(container, 'Phosphors', phosphor_type, false) | |||
end | |||
if gun_type then | |||
addRow(container, 'Gun type', gun_type, false) | |||
end | |||
if deflection_angle then | |||
addRow(container, 'Deflection', deflection_angle .. '°', false) | |||
end | |||
if neck_diameter then | |||
addRow(container, 'Neck', neck_diameter .. ' mm', false) | |||
end | |||
-- Visible picture size | |||
if visible_w and visible_h then | if visible_w and visible_h then | ||
addRow(container, 'Visible area', visible_w .. ' × ' .. visible_h .. ' mm', false) | addRow(container, 'Visible area', visible_w .. ' × ' .. visible_h .. ' mm', false) | ||
| Line 458: | Line 481: | ||
addRow(container, 'Visible area', visible_diag .. '″ (diagonal)', false) | addRow(container, 'Visible area', visible_diag .. '″ (diagonal)', false) | ||
end | end | ||
-- Show diagonal even if we have W×H, as supplementary info | |||
if visible_diag and visible_w and visible_h then | if visible_diag and visible_w and visible_h then | ||
addRow(container, 'Visible diag.', visible_diag .. '″', false) | addRow(container, 'Visible diag.', visible_diag .. '″', false) | ||
| Line 463: | Line 488: | ||
end | end | ||
-- Dimensions section | -- Dimensions section: show if we have height/width/depth OR weight | ||
if height or width or depth or weight then | if height or width or depth or weight then | ||
addSectionRow(container, 'Dimensions') | addSectionRow(container, 'Dimensions') | ||
if height or width or depth then | if height or width or depth then | ||
local h = height or '–' | local h = height or '–' | ||
| Line 472: | Line 498: | ||
addRow(container, 'H × W × D', string.format('%s × %s × %s', h, w, d), false) | addRow(container, 'H × W × D', string.format('%s × %s × %s', h, w, d), false) | ||
end | end | ||
-- Weight row: uses #show, so preprocess it | |||
if weight then | if weight then | ||
local weightWikitext = '{{#show: ' .. fullPageName .. ' |?Weight # lb }} / {{#show: ' .. fullPageName .. ' |?Weight # kg }}' | local weightWikitext = '{{#show: ' .. fullPageName .. ' |?Weight # lb }} / {{#show: ' .. fullPageName .. ' |?Weight # kg }}' | ||
| Line 478: | Line 506: | ||
end | end | ||
-- Speakers section | -- Speakers section: show if we have any speaker specs | ||
if speaker_type or speaker_watts or subwoofer then | if speaker_type or speaker_watts or subwoofer then | ||
addSectionRow(container, 'Speakers') | addSectionRow(container, 'Speakers') | ||
if speaker_type then addRow(container, 'Type', speaker_type, false) end | |||
if speaker_watts then addRow(container, 'Power', speaker_watts, false) end | if speaker_type then | ||
if subwoofer then addRow(container, 'Subwoofer', subwoofer, false) end | addRow(container, 'Type', speaker_type, false) | ||
end | |||
if speaker_watts then | |||
addRow(container, 'Power', speaker_watts, false) | |||
end | |||
if subwoofer then | |||
addRow(container, 'Subwoofer', subwoofer, false) | |||
end | |||
end | end | ||
-- Power section | -- Power section: query voltage ranges from subobjects | ||
-- First, query for voltage range subobjects | |||
local voltageQueryWikitext = | local voltageQueryWikitext = | ||
'{{#ask:\n' .. | '{{#ask:\n' .. | ||
| Line 500: | Line 538: | ||
'}}' | '}}' | ||
local voltageResult = frame:preprocess(voltageQueryWikitext) | local voltageResult = frame:preprocess(voltageQueryWikitext) | ||
-- Parse voltage ranges from broadtable result | |||
local voltageRanges = {} | local voltageRanges = {} | ||
if voltageResult then | if voltageResult then | ||
| Line 508: | Line 548: | ||
table.insert(cells, trim(cleanContent)) | table.insert(cells, trim(cleanContent)) | ||
end | end | ||
-- cells[1] = subobject, cells[2] = voltage_min, cells[3] = voltage_max | |||
if #cells >= 3 then | if #cells >= 3 then | ||
local vMin = tonumber(cells[2]) | local vMin = tonumber(cells[2]) | ||
| Line 517: | Line 559: | ||
end | end | ||
end | end | ||
local hasVoltageRanges = #voltageRanges > 0 | local hasVoltageRanges = #voltageRanges > 0 | ||
-- Show Power section if we have voltage ranges, frequency, or power consumption | |||
if hasVoltageRanges or frequency or power_avg or power_max then | if hasVoltageRanges or frequency or power_avg or power_max then | ||
addSectionRow(container, 'Power') | addSectionRow(container, 'Power') | ||
-- Voltage row: display ranges from subobjects | |||
if hasVoltageRanges then | if hasVoltageRanges then | ||
local rangeStrings = {} | local rangeStrings = {} | ||
| Line 536: | Line 582: | ||
rangeStr = range.max .. 'V' | rangeStr = range.max .. 'V' | ||
end | end | ||
if rangeStr then table.insert(rangeStrings, rangeStr) end | if rangeStr then | ||
table.insert(rangeStrings, rangeStr) | |||
end | |||
end | end | ||
if #rangeStrings > 0 then | if #rangeStrings > 0 then | ||
addRow(container, 'Voltage', table.concat(rangeStrings, ' / '), false) | addRow(container, 'Voltage', table.concat(rangeStrings, ' / '), false) | ||
end | end | ||
end | end | ||
if frequency then addRow(container, 'Frequency', frequency, false) end | |||
-- Frequency row | |||
if frequency then | |||
addRow(container, 'Frequency', frequency, false) | |||
end | |||
-- Power consumption row | |||
if power_avg or power_max then | if power_avg or power_max then | ||
local powerDisplay | local powerDisplay | ||
| Line 556: | Line 611: | ||
end | end | ||
-- TV Systems section | -- TV Systems section: show if we have AV system or tuner system | ||
if av_system or tuner_system then | if av_system or tuner_system then | ||
addSectionRow(container, 'TV Systems') | addSectionRow(container, 'TV Systems') | ||
if av_system then | if av_system then | ||
local systems = {} | local systems = {} | ||
for system in av_system:gmatch('[^,]+') do | for system in av_system:gmatch('[^,]+') do | ||
local s = trim(system) | local s = trim(system) | ||
if s then table.insert(systems, '[[' .. s .. '|' .. s .. ']]') end | if s then | ||
table.insert(systems, '[[' .. s .. '|' .. s .. ']]') | |||
end | |||
end | |||
if #systems > 0 then | |||
addRow(container, 'AV system', table.concat(systems, ', '), true) | |||
end | end | ||
end | end | ||
if tuner_system then | if tuner_system then | ||
local systems = {} | local systems = {} | ||
for system in tuner_system:gmatch('[^,]+') do | for system in tuner_system:gmatch('[^,]+') do | ||
local s = trim(system) | local s = trim(system) | ||
if s then table.insert(systems, '[[' .. s .. '|' .. s .. ']]') end | if s then | ||
table.insert(systems, '[[' .. s .. '|' .. s .. ']]') | |||
end | |||
end | |||
if #systems > 0 then | |||
addRow(container, 'Tuner', table.concat(systems, ', '), true) | |||
end | end | ||
end | end | ||
end | end | ||
| Line 580: | Line 645: | ||
if h_scan_min or h_scan_max or v_scan_min or v_scan_max then | if h_scan_min or h_scan_max or v_scan_min or v_scan_max then | ||
addSectionRow(container, 'Scan Range') | addSectionRow(container, 'Scan Range') | ||
if h_scan_min or h_scan_max then | if h_scan_min or h_scan_max then | ||
local hDisplay | local hDisplay | ||
if h_scan_min and h_scan_max then | if h_scan_min and h_scan_max then | ||
if h_scan_min == h_scan_max then | |||
hDisplay = h_scan_min .. ' kHz' | |||
else | |||
hDisplay = h_scan_min .. '–' .. h_scan_max .. ' kHz' | |||
end | |||
elseif h_scan_min then | |||
hDisplay = h_scan_min .. ' kHz' | |||
else | else | ||
hDisplay = | hDisplay = h_scan_max .. ' kHz' | ||
end | end | ||
addRow(container, 'Horizontal', hDisplay, false) | addRow(container, 'Horizontal', hDisplay, false) | ||
end | end | ||
if v_scan_min or v_scan_max then | if v_scan_min or v_scan_max then | ||
local vDisplay | local vDisplay | ||
if v_scan_min and v_scan_max then | if v_scan_min and v_scan_max then | ||
if v_scan_min == v_scan_max then | |||
vDisplay = v_scan_min .. ' Hz' | |||
else | |||
vDisplay = v_scan_min .. '–' .. v_scan_max .. ' Hz' | |||
end | |||
elseif v_scan_min then | |||
vDisplay = v_scan_min .. ' Hz' | |||
else | else | ||
vDisplay = | vDisplay = v_scan_max .. ' Hz' | ||
end | end | ||
addRow(container, 'Vertical', vDisplay, false) | addRow(container, 'Vertical', vDisplay, false) | ||
| Line 604: | Line 683: | ||
local locations = discoverLocations(frame, fullPageName, ioType) | local locations = discoverLocations(frame, fullPageName, ioType) | ||
local locationData = {} | local locationData = {} | ||
for _, loc in ipairs(locations) do | for _, loc in ipairs(locations) do | ||
local content = queryIOByLocation(frame, fullPageName, ioType, loc) | local content = queryIOByLocation(frame, fullPageName, ioType, loc) | ||
| Line 610: | Line 690: | ||
end | end | ||
end | end | ||
if #locationData > 0 then | if #locationData > 0 then | ||
addSectionRow(container, sectionTitle) | addSectionRow(container, sectionTitle) | ||
| Line 617: | Line 698: | ||
css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;') | css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;') | ||
labelDiv:wikitext(locationLabel(data.location)) | labelDiv:wikitext(locationLabel(data.location)) | ||
local valueDiv = container:tag('div') | local valueDiv = container:tag('div') | ||
valueDiv:addClass('infobox-value') | valueDiv:addClass('infobox-value') | ||
| Line 631: | Line 713: | ||
-- Accessories section | -- Accessories section | ||
addSectionRow(container, 'Accessories') | addSectionRow(container, 'Accessories') | ||
local addAccessoryUrl = mw.uri.fullUrl(" | |||
local addAccessoryUrl = mw.uri.fullUrl( | |||
"Create an accessory", | |||
{ | |||
crt_models = pageName | |||
} | |||
) | |||
local accessoriesCountWikitext = | local accessoriesCountWikitext = | ||
'{{#ask:\n [[Category:Accessories]]\n [[Has related CRT model::' .. fullPageName .. ']]\n [[Has accessory type::!Remote control]]\n |format=count\n}}' | '{{#ask:\n' .. | ||
' [[Category:Accessories]]\n' .. | |||
' [[Has related CRT model::' .. fullPageName .. ']]\n' .. | |||
' [[Has accessory type::!Remote control]]\n' .. | |||
' |format=count\n' .. | |||
'}}' | |||
local accessoryCount = frame:preprocess(accessoriesCountWikitext) | local accessoryCount = frame:preprocess(accessoriesCountWikitext) | ||
local hasAccessories = accessoryCount and tonumber(trim(accessoryCount)) and tonumber(trim(accessoryCount)) > 0 | local hasAccessories = accessoryCount and tonumber(trim(accessoryCount)) and tonumber(trim(accessoryCount)) > 0 | ||
| Line 642: | Line 736: | ||
if hasAccessories then | if hasAccessories then | ||
local accessoriesQueryWikitext = | local accessoriesQueryWikitext = | ||
'{{#ask:\n [[Category:Accessories]]\n [[Has related CRT model::' .. fullPageName .. ']]\n [[Has accessory type::!Remote control]]\n |?Has accessory type=type\n |?Has model code=model\n |format=broadtable\n |headers=hide\n |link=none\n}}' | '{{#ask:\n' .. | ||
' [[Category:Accessories]]\n' .. | |||
' [[Has related CRT model::' .. fullPageName .. ']]\n' .. | |||
' [[Has accessory type::!Remote control]]\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 accessoriesResult = frame:preprocess(accessoriesQueryWikitext) | ||
local accessoriesByType = {} | local accessoriesByType = {} | ||
local typeOrder = {} | local typeOrder = {} | ||
if accessoriesResult then | if accessoriesResult then | ||
for rowContent in accessoriesResult:gmatch('<tr[^>]*>(.-)</tr>') do | for rowContent in accessoriesResult:gmatch('<tr[^>]*>(.-)</tr>') do | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
local cleanContent = cellContent:gsub('<[^>]+>', '') | |||
table.insert(cells, trim(cleanContent)) | |||
end | end | ||
if #cells >= 2 then | if #cells >= 2 then | ||
local accPageName = cells[1] | local accPageName = cells[1] | ||
local accType = cells[2] or 'Accessory' | local accType = cells[2] or 'Accessory' | ||
if accPageName then | if accPageName then | ||
if not accessoriesByType[accType] then | if not accessoriesByType[accType] then | ||
| Line 660: | Line 768: | ||
table.insert(typeOrder, accType) | table.insert(typeOrder, accType) | ||
end | end | ||
table.insert(accessoriesByType[accType], {page = accPageName}) | |||
table.insert(accessoriesByType[accType], { | |||
page = accPageName | |||
}) | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
local accGrid = accDiv:tag('div') | local accGrid = accDiv:tag('div') | ||
css(accGrid, 'display:grid; grid-template-columns:auto 1fr; gap:3px;') | css(accGrid, 'display:grid; grid-template-columns:auto 1fr; gap:3px;') | ||
for _, accType in ipairs(typeOrder) do | for _, accType in ipairs(typeOrder) do | ||
local accs = accessoriesByType[accType] | local accs = accessoriesByType[accType] | ||
if accs and #accs > 0 then | if accs and #accs > 0 then | ||
local accLinks = {} | local accLinks = {} | ||
for _, acc in ipairs(accs) do table.insert(accLinks, '[[' .. acc.page .. ']]') end | for _, acc in ipairs(accs) do | ||
table.insert(accLinks, '[[' .. acc.page .. ']]') | |||
end | |||
local labelDiv = accGrid:tag('div') | local labelDiv = accGrid:tag('div') | ||
labelDiv:addClass('infobox-label') | labelDiv:addClass('infobox-label') | ||
css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;') | css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;') | ||
labelDiv:wikitext(accType) | labelDiv:wikitext(accType) | ||
local valueDiv = accGrid:tag('div') | local valueDiv = accGrid:tag('div') | ||
valueDiv:addClass('infobox-value') | valueDiv:addClass('infobox-value') | ||
| Line 682: | Line 799: | ||
end | end | ||
end | end | ||
local addAccDiv = mw.html.create('div') | local addAccDiv = mw.html.create('div') | ||
addAccDiv:css('margin-top', '0.5em'):css('text-align', 'center') | addAccDiv:css('margin-top', '0.5em'):css('text-align', 'center') | ||
| Line 695: | Line 813: | ||
-- Parts section | -- Parts section | ||
addSectionRow(container, 'Parts') | addSectionRow(container, 'Parts') | ||
local addPartUrl = mw.uri.fullUrl(" | |||
local addPartUrl = mw.uri.fullUrl( | |||
"Create a part", | |||
{ | |||
crt_models = pageName | |||
} | |||
) | |||
local partsCountWikitext = | local partsCountWikitext = | ||
'{{#ask:\n [[Category:Parts]]\n [[Has related CRT model::' .. fullPageName .. ']]\n |format=count\n}}' | '{{#ask:\n' .. | ||
' [[Category:Parts]]\n' .. | |||
' [[Has related CRT model::' .. fullPageName .. ']]\n' .. | |||
' |format=count\n' .. | |||
'}}' | |||
local partsCount = frame:preprocess(partsCountWikitext) | local partsCount = frame:preprocess(partsCountWikitext) | ||
local hasParts = partsCount and tonumber(trim(partsCount)) and tonumber(trim(partsCount)) > 0 | local hasParts = partsCount and tonumber(trim(partsCount)) and tonumber(trim(partsCount)) > 0 | ||
local partsDiv = container:tag('div') | local partsDiv = container:tag('div') | ||
css(partsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;') | css(partsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;') | ||
if hasParts then | if hasParts then | ||
local partsQueryWikitext = | local partsQueryWikitext = | ||
'{{#ask:\n [[Category:Parts]]\n [[Has related CRT model::' .. 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}}' | '{{#ask:\n' .. | ||
' [[Category:Parts]]\n' .. | |||
' [[Has related CRT model::' .. 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 partsResult = frame:preprocess(partsQueryWikitext) | ||
local partsByType = {} | local partsByType = {} | ||
local partTypeOrder = {} | local partTypeOrder = {} | ||
if partsResult then | if partsResult then | ||
for rowContent in partsResult:gmatch('<tr[^>]*>(.-)</tr>') do | for rowContent in partsResult:gmatch('<tr[^>]*>(.-)</tr>') do | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
local cleanContent = cellContent:gsub('<[^>]+>', '') | |||
table.insert(cells, trim(cleanContent)) | |||
end | end | ||
if #cells >= 2 then | if #cells >= 2 then | ||
local partPageName = cells[1] | local partPageName = cells[1] | ||
local partType = cells[2] or 'Part' | local partType = cells[2] or 'Part' | ||
local partSubtype = cells[3] | local partSubtype = cells[3] | ||
local groupKey = partType | local groupKey = partType | ||
if partSubtype and partSubtype ~= '' then groupKey = partSubtype .. ' ' .. partType end | if partSubtype and partSubtype ~= '' then | ||
groupKey = partSubtype .. ' ' .. partType | |||
end | |||
if partPageName then | if partPageName then | ||
if not partsByType[groupKey] then | if not partsByType[groupKey] then | ||
| Line 726: | Line 873: | ||
table.insert(partTypeOrder, groupKey) | table.insert(partTypeOrder, groupKey) | ||
end | end | ||
table.insert(partsByType[groupKey], {page = partPageName}) | |||
table.insert(partsByType[groupKey], { | |||
page = partPageName | |||
}) | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
local partsGrid = partsDiv:tag('div') | local partsGrid = partsDiv:tag('div') | ||
css(partsGrid, 'display:grid; grid-template-columns:auto 1fr; gap:3px;') | css(partsGrid, 'display:grid; grid-template-columns:auto 1fr; gap:3px;') | ||
for _, partType in ipairs(partTypeOrder) do | for _, partType in ipairs(partTypeOrder) do | ||
local parts = partsByType[partType] | local parts = partsByType[partType] | ||
if parts and #parts > 0 then | if parts and #parts > 0 then | ||
local partLinks = {} | local partLinks = {} | ||
for _, part in ipairs(parts) do table.insert(partLinks, '[[' .. part.page .. ']]') end | for _, part in ipairs(parts) do | ||
table.insert(partLinks, '[[' .. part.page .. ']]') | |||
end | |||
local labelDiv = partsGrid:tag('div') | local labelDiv = partsGrid:tag('div') | ||
labelDiv:addClass('infobox-label') | labelDiv:addClass('infobox-label') | ||
css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;') | css(labelDiv, 'padding:0.2em 0.4em; font-weight:bold; text-align:left;') | ||
labelDiv:wikitext(partType) | labelDiv:wikitext(partType) | ||
local valueDiv = partsGrid:tag('div') | local valueDiv = partsGrid:tag('div') | ||
valueDiv:addClass('infobox-value') | valueDiv:addClass('infobox-value') | ||
| Line 748: | Line 904: | ||
end | end | ||
end | end | ||
local addPartDiv = mw.html.create('div') | local addPartDiv = mw.html.create('div') | ||
addPartDiv:css('margin-top', '0.5em'):css('text-align', 'center') | addPartDiv:css('margin-top', '0.5em'):css('text-align', 'center') | ||
| Line 761: | Line 918: | ||
-- Mods section | -- Mods section | ||
local modsQueryWikitext = | local modsQueryWikitext = | ||
'{{#ask:\n [[Has CRT model::' .. fullPageName .. ']]\n [[Has mod URL::+]]\n |?Has mod type=type\n |?Has mod description=description\n |?Has mod feasible=feasible\n |?Has mod URL=url\n |format=broadtable\n |headers=hide\n |link=none\n}}' | '{{#ask:\n' .. | ||
' [[Has CRT model::' .. fullPageName .. ']]\n' .. | |||
' [[Has mod URL::+]]\n' .. | |||
' |?Has mod type=type\n' .. | |||
' |?Has mod description=description\n' .. | |||
' |?Has mod feasible=feasible\n' .. | |||
' |?Has mod URL=url\n' .. | |||
' |format=broadtable\n' .. | |||
' |headers=hide\n' .. | |||
' |link=none\n' .. | |||
'}}' | |||
local modsResult = frame:preprocess(modsQueryWikitext) | local modsResult = frame:preprocess(modsQueryWikitext) | ||
local mods = {} | local mods = {} | ||
if modsResult then | if modsResult then | ||
for rowContent in modsResult:gmatch('<tr[^>]*>(.-)</tr>') do | for rowContent in modsResult:gmatch('<tr[^>]*>(.-)</tr>') do | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
local cleanContent = cellContent:gsub('<[^>]+>', '') | |||
table.insert(cells, trim(cleanContent)) | |||
end | end | ||
if #cells >= 3 then | if #cells >= 3 then | ||
local modData = {type = nil, description = nil, feasible = nil, url = nil} | local modData = { | ||
type = nil, | |||
description = nil, | |||
feasible = nil, | |||
url = nil | |||
} | |||
for i = 2, #cells do | for i = 2, #cells do | ||
local cell = cells[i] | local cell = cells[i] | ||
if cell then | if cell then | ||
if cell:match('^https?://') then modData.url = cell | if cell:match('^https?://') then | ||
elseif cell == 'Yes' or cell == 'No' then modData.feasible = cell | modData.url = cell | ||
elseif cell == 'RGB' or cell == 'S-video' or cell == 'Other' then modData.type = cell | elseif cell == 'Yes' or cell == 'No' then | ||
else modData.description = cell end | modData.feasible = cell | ||
elseif cell == 'RGB' or cell == 'S-video' or cell == 'Other' then | |||
modData.type = cell | |||
else | |||
modData.description = cell | |||
end | |||
end | end | ||
end | end | ||
if modData.url and modData.type then table.insert(mods, modData) end | |||
if modData.url and modData.type then | |||
table.insert(mods, modData) | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
if #mods > 0 then | if #mods > 0 then | ||
addSectionRow(container, 'Mods') | addSectionRow(container, 'Mods') | ||
local modsDiv = container:tag('div') | local modsDiv = container:tag('div') | ||
css(modsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;') | css(modsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;') | ||
local ul = modsDiv:tag('ul') | local ul = modsDiv:tag('ul') | ||
ul:css('margin', '0'):css('padding-left', '1.5em') | ul:css('margin', '0'):css('padding-left', '1.5em') | ||
for _, mod in ipairs(mods) do | for _, mod in ipairs(mods) do | ||
local li = ul:tag('li') | local li = ul:tag('li') | ||
local displayText = mod.description or mod.type | local displayText = mod.description or mod.type | ||
local isFeasible = mod.feasible ~= 'No' | local isFeasible = mod.feasible ~= 'No' | ||
if isFeasible then | if isFeasible then | ||
li:wikitext('[' .. mod.url .. ' ' .. displayText .. ']') | li:wikitext('[' .. mod.url .. ' ' .. displayText .. ']') | ||
| Line 810: | Line 1,001: | ||
-- Documents section | -- Documents section | ||
addSectionRow(container, 'Documents') | addSectionRow(container, 'Documents') | ||
local timestamp = os.time() | local timestamp = os.time() | ||
math.randomseed(timestamp + pageId) | math.randomseed(timestamp + pageId) | ||
local random = math.random(1000, 9999) | local random = math.random(1000, 9999) | ||
local target = "Document:" .. timestamp .. "-" .. random | local target = "Document:" .. timestamp .. "-" .. random | ||
local uploadUrl = mw.uri.fullUrl("Special:FormEdit", {form = "Document", target = target, ["Document[crt_models]"] = pageName}) | local uploadUrl = mw.uri.fullUrl( | ||
"Special:FormEdit", | |||
{ | |||
form = "Document", | |||
target = target, | |||
["Document[crt_models]"] = pageName | |||
} | |||
) | |||
local documentsCountWikitext = | local documentsCountWikitext = | ||
'{{#ask:\n [[Category:Documents]]\n [[Has related CRT model::' .. fullPageName .. ']]\n |format=count\n}}' | '{{#ask:\n' .. | ||
' [[Category:Documents]]\n' .. | |||
' [[Has related CRT model::' .. fullPageName .. ']]\n' .. | |||
' |format=count\n' .. | |||
'}}' | |||
local documentCount = frame:preprocess(documentsCountWikitext) | local documentCount = frame:preprocess(documentsCountWikitext) | ||
local hasDocuments = documentCount and tonumber(trim(documentCount)) and tonumber(trim(documentCount)) > 0 | local hasDocuments = documentCount and tonumber(trim(documentCount)) and tonumber(trim(documentCount)) > 0 | ||
local docsDiv = container:tag('div') | local docsDiv = container:tag('div') | ||
css(docsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;') | css(docsDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em;') | ||
if hasDocuments then | if hasDocuments then | ||
local docsQueryWikitext = | local docsQueryWikitext = | ||
'{{#ask:\n [[Category:Documents]]\n [[Has related CRT model::' .. 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}}' | '{{#ask:\n' .. | ||
' [[Category:Documents]]\n' .. | |||
' [[Has related CRT model::' .. 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 docsResult = frame:preprocess(docsQueryWikitext) | ||
local ul = mw.html.create('ul') | local ul = mw.html.create('ul') | ||
ul:css('margin', '0'):css('padding-left', '1.5em') | ul:css('margin', '0'):css('padding-left', '1.5em') | ||
if docsResult then | if docsResult then | ||
for rowContent in docsResult:gmatch('<tr[^>]*>(.-)</tr>') do | for rowContent in docsResult:gmatch('<tr[^>]*>(.-)</tr>') do | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
local cleanContent = cellContent:gsub('<[^>]+>', '') | |||
table.insert(cells, cleanContent) | |||
end | end | ||
if #cells >= 2 then | if #cells >= 2 then | ||
local docType = trim(cells[2]) | local docType = trim(cells[2]) | ||
| Line 839: | Line 1,058: | ||
local docFile = trim(cells[4]) | local docFile = trim(cells[4]) | ||
local docTitle = trim(cells[5]) | local docTitle = trim(cells[5]) | ||
local linkTarget = nil | |||
if docUrl then | |||
linkTarget = docUrl | |||
elseif docFile then | |||
local filename = docFile:match('File:(.+)') or docFile | |||
linkTarget = tostring(mw.uri.fullUrl('File:' .. filename)) | |||
end | |||
local docPageName = trim(cells[1]) | local docPageName = trim(cells[1]) | ||
if docPageName then | if docPageName then | ||
local displayText = 'Document' | local displayText = 'Document' | ||
if docTitle then displayText = docTitle | if docTitle then | ||
elseif docType then displayText = docType end | displayText = docTitle | ||
elseif docType then | |||
displayText = docType | |||
end | |||
local li = ul:tag('li') | local li = ul:tag('li') | ||
li:wikitext('[[' .. docPageName .. '|' .. displayText .. ']]') | li:wikitext('[[' .. docPageName .. '|' .. displayText .. ']]') | ||
| Line 850: | Line 1,083: | ||
end | end | ||
end | end | ||
docsDiv:node(ul) | docsDiv:node(ul) | ||
local uploadDiv = mw.html.create('div') | local uploadDiv = mw.html.create('div') | ||
uploadDiv:css('margin-top', '0.5em'):css('text-align', 'center') | uploadDiv:css('margin-top', '0.5em'):css('text-align', 'center') | ||
uploadDiv:wikitext('[' .. tostring(uploadUrl) .. ' <span class="infobox-button infobox-button-secondary">Add document</span>]') | uploadDiv:wikitext('[' .. tostring(uploadUrl) .. ' <span class="infobox-button infobox-button-secondary">Add document</span>]') | ||
docsDiv:node(uploadDiv) | docsDiv:node(uploadDiv) | ||
else | else | ||
| Line 859: | Line 1,095: | ||
uploadDiv:css('text-align', 'center') | uploadDiv:css('text-align', 'center') | ||
uploadDiv:wikitext('[' .. tostring(uploadUrl) .. ' <span class="infobox-button infobox-button-secondary">Add document</span>]') | uploadDiv:wikitext('[' .. tostring(uploadUrl) .. ' <span class="infobox-button infobox-button-secondary">Add document</span>]') | ||
docsDiv:node(uploadDiv) | docsDiv:node(uploadDiv) | ||
end | end | ||
| Line 864: | Line 1,101: | ||
-- Links section | -- Links section | ||
local linksQueryWikitext = | local linksQueryWikitext = | ||
'{{#ask:\n [[CRT model::' .. fullPageName .. ']]\n |?Model link type\n |?Model link source\n |?Model link URL\n |format=broadtable\n |headers=hide\n |link=none\n}}' | '{{#ask:\n' .. | ||
' [[CRT model::' .. 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 linksResult = frame:preprocess(linksQueryWikitext) | ||
local linksByType = {Manufacturer = {}, Retailer = {}, Database = {}} | |||
local linksByType = { | |||
Manufacturer = {}, | |||
Retailer = {}, | |||
Database = {} | |||
} | |||
local hasLinks = false | local hasLinks = false | ||
if linksResult then | if linksResult then | ||
for rowContent in linksResult:gmatch('<tr[^>]*>(.-)</tr>') do | for rowContent in linksResult:gmatch('<tr[^>]*>(.-)</tr>') do | ||
local cells = {} | local cells = {} | ||
for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | for cellContent in rowContent:gmatch('<td[^>]*>(.-)</td>') do | ||
local cleanContent = cellContent:gsub('<[^>]+>', '') | |||
table.insert(cells, trim(cleanContent)) | |||
end | end | ||
if #cells >= 4 then | if #cells >= 4 then | ||
local linkType = cells[2] | local linkType = cells[2] | ||
local linkSource = cells[3] | local linkSource = cells[3] | ||
local linkUrl = cells[4] | local linkUrl = cells[4] | ||
if linkType and linkSource and linkUrl and linkUrl ~= '' | |||
if linkType and linkSource and linkUrl and linkUrl ~= '' then | |||
if linksByType[linkType] then | |||
table.insert(linksByType[linkType], {source = linkSource, url = linkUrl}) | |||
hasLinks = true | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
if hasLinks then | if hasLinks then | ||
addSectionRow(container, 'Archival Links') | addSectionRow(container, 'Archival Links') | ||
local linkTypeOrder = {'Database', 'Manufacturer', 'Retailer'} | local linkTypeOrder = {'Database', 'Manufacturer', 'Retailer'} | ||
for _, linkType in ipairs(linkTypeOrder) do | for _, linkType in ipairs(linkTypeOrder) do | ||
| Line 901: | Line 1,159: | ||
-- Contribute section | -- Contribute section | ||
addSectionRow(container, 'Contribute') | addSectionRow(container, 'Contribute') | ||
local editUrl = mw.uri.fullUrl("Special:FormStart", {form = "CRT model", page_name = pageName}) | |||
local editUrl = mw.uri.fullUrl( | |||
"Special:FormStart", | |||
{ | |||
form = "CRT model", | |||
page_name = pageName | |||
} | |||
) | |||
local editDiv = container:tag('div') | local editDiv = container:tag('div') | ||
css(editDiv, 'grid-column: 1 / -1; padding:0.2em 0.4em; text-align:center;') | 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>]') | editDiv:wikitext('[' .. tostring(editUrl) .. ' <span class="infobox-button infobox-button-primary">Edit this data</span>]') | ||