This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing.
require('Module:No globals')
local p = {}
local data = require('Module:Video game reviews/data')
local yesno = require('Module:Yesno')
local vgwd = require('Module:Video game wikidata')
local getArgs
local function getActiveSystems(args)
local activeSystems = {}
for k, v in pairs(args) do
if data.systems[k] and yesno(v) then
table.insert(activeSystems, k)
end
end
table.sort(activeSystems, function(a, b)
return data.systems[a].sortkey < data.systems[b].sortkey
end)
return activeSystems
end
local function getArgKeyTables(args)
local reviewers, aggregators, awards = {}, {}, {}
for k in pairs(args) do
if string.match(k, data.i18n.pattern.reviewer) then
table.insert(reviewers, k)
elseif string.match(k, data.i18n.pattern.aggregator) then
table.insert(aggregators, k)
elseif string.match(k, data.i18n.pattern.award) then
table.insert(awards, k)
end
end
local function comparator(a, b)
return tonumber(a:match('%d+')) < tonumber(b:match('%d+'))
end
table.sort(reviewers, comparator)
table.sort(aggregators, comparator)
table.sort(awards, comparator)
return reviewers, aggregators, awards
end
local function getProvidedReviewersAndAggregators(args, usePlatforms)
local providedReviewers, providedAggregators = {}, {}
if usePlatforms then
local seen = {}
for k in pairs(args) do
local splitPos = string.find(k, '_')
if splitPos then
local halfarg = string.sub(k, 1, splitPos - 1)
if not seen[halfarg] then
seen[halfarg] = true
if data.reviewers[halfarg] then
table.insert(providedReviewers, halfarg)
elseif data.aggregators[halfarg] then
table.insert(providedAggregators, halfarg)
end
end
end
end
else
for k in pairs(args) do
if not string.find(k, '_') then
if data.reviewers[k] then
table.insert(providedReviewers, k)
elseif data.aggregators[k] then
table.insert(providedAggregators, k)
end
end
end
end
table.sort(providedReviewers, function(a, b)
return data.reviewers[a].sortkey < data.reviewers[b].sortkey
end)
table.sort(providedAggregators, function(a, b)
return data.aggregators[a].sortkey < data.aggregators[b].sortkey
end)
return providedReviewers, providedAggregators
end
local function renderHeadingRowWithSystems(builder, activeSystems, headingText)
builder:tag('tr')
:addClass(data.i18n.class.headerrow)
:tag('th')
:attr('scope', 'col')
:attr('rowspan', '2')
:wikitext(headingText)
:done()
:tag('th')
:attr('scope', 'colgroup')
:attr('colspan', #activeSystems)
:wikitext(data.i18n.display.score)
:done()
builder = builder:tag('tr')
for _, v in ipairs(activeSystems) do
builder:tag('th')
:wikitext(data.systems[v].name)
:attr('scope', 'col')
:done()
end
end
local function renderHeadingRow(builder, nameHeading)
builder:tag('tr')
:addClass(data.i18n.class.headerrow)
:tag('th')
:attr('scope', 'col')
:wikitext(nameHeading)
:done()
:tag('th')
:attr('scope', 'col')
:wikitext(data.i18n.display.score)
:done()
end
local function renderRatingsBySystem(builder, code, name, activeSystems, args, na)
builder = builder:tag('tr')
builder:tag('td')
:wikitext(name)
for _, v in ipairs(activeSystems) do
local combinedCode = code .. '_' .. v
local cell = builder:tag('td')
if args[combinedCode] then
cell
:wikitext(args[combinedCode])
:done()
elseif na then
cell
:addClass(data.i18n.class.na)
:wikitext(data.i18n.display.na)
:done()
end
end
end
local function renderRating(builder, name, rating)
builder:tag('tr')
:tag('td')
:addClass(data.i18n.class.centeredpub)
:wikitext(name)
:done()
:tag('td')
:wikitext(rating)
:done()
end
local function renderAggregators(builder, providedAggregators, activeSystems, customAggregatorKeys, args)
local aggregatorCount = #providedAggregators + #customAggregatorKeys
if aggregatorCount == 0 then return end
builder = builder:tag('table')
:addClass(data.i18n.class.aggregators)
:addClass(data.i18n.class.wikitable)
:addClass(args.state and 'mw-collapsible-content' or nil)
:tag('caption')
:wikitext(data.i18n.display[aggregatorCount == 1 and 'aggregateScore' or 'aggregateScores'])
:done()
if #activeSystems ~= 0 then
local na = yesno(args.na)
local showplatforms = #activeSystems ~= 1 or yesno(args.showplatforms)
if showplatforms then
renderHeadingRowWithSystems(builder, activeSystems, data.i18n.display.aggregator)
else
renderHeadingRow(builder, data.i18n.display.aggregator)
end
for _, v in ipairs(providedAggregators) do
renderRatingsBySystem(builder, v, data.aggregators[v].name, activeSystems, args, na)
end
for _, v in ipairs(customAggregatorKeys) do
renderRatingsBySystem(builder, v, args[v], activeSystems, args, na)
end
else
renderHeadingRow(builder, data.i18n.display.aggregator)
for _, v in ipairs(providedAggregators) do
renderRating(builder, data.aggregators[v].name, args[v])
end
for _, v in ipairs(customAggregatorKeys) do
renderRating(builder, args[v], args[v .. 'Score'])
end
end
end
local function renderReviews(builder, providedReviewers, activeSystems,
customReviewerKeys, args, reviewerCount, priorReviewCount)
if reviewerCount == 0 then return end
builder = builder:tag('table')
:addClass(data.i18n.class.reviews)
:addClass(data.i18n.class.wikitable)
:addClass(args.state and 'mw-collapsible-content' or nil)
:tag('caption')
:wikitext(data.i18n.display[reviewerCount == 1 and 'reviewScore' or 'reviewScores'])
:addClass(priorReviewCount > 0 and data.i18n.class.stacked or nil)
:done()
if #activeSystems ~= 0 then
local na = yesno(args.na)
local showplatforms = #activeSystems ~= 1 or yesno(args.showplatforms)
if showplatforms then
renderHeadingRowWithSystems(builder, activeSystems, data.i18n.display.publication)
else
renderHeadingRow(builder, data.i18n.display.publication)
end
for _, v in ipairs(providedReviewers) do
renderRatingsBySystem(builder, v, data.reviewers[v].name, activeSystems, args, na)
end
for _, v in ipairs(customReviewerKeys) do
renderRatingsBySystem(builder, v, args[v], activeSystems, args, na)
end
else
renderHeadingRow(builder, data.i18n.display.publication)
for _, v in ipairs(providedReviewers) do
renderRating(builder, data.reviewers[v].name, args[v])
end
for _, v in ipairs(customReviewerKeys) do
renderRating(builder, args[v], args[v .. 'Score'])
end
end
end
local function renderAwards(builder, args, awardKeys, priorReviewCount)
if #awardKeys == 0 then return end
builder = builder:tag('table')
:addClass(data.i18n.class.awards)
:addClass(data.i18n.class.wikitable)
:addClass(args.state and 'mw-collapsible-content' or nil)
:tag('caption')
:wikitext(data.i18n.display[#awardKeys == 1 and 'award' or 'awards'])
:addClass(priorReviewCount > 0 and data.i18n.class.stacked or nil)
:done()
:tag('tr')
:tag('th')
:attr('scope', 'col')
:wikitext(data.i18n.display.publication)
:done()
:tag('th')
:attr('scope', 'col')
:wikitext(data.i18n.display.award)
:done()
for _, v in ipairs(awardKeys) do
builder:tag('tr')
:tag('td')
:wikitext(args[v .. 'Pub'])
:done()
:tag('td')
:wikitext(args[v])
:done()
end
builder:done()
builder:done()
end
local function renderEditOnWikidata(builder, wikidata, state)
if not wikidata then return end
builder:tag('div')
:addClass(data.i18n.class.wikidata)
:addClass(state and 'mw-collapsible-content' or nil)
:wikitext(vgwd.getUpdateLink())
:done()
end
local function categorizePlatformCount(builder, platformCount)
if platformCount ~= 0 then
builder:wikitext(data.i18n.category.multiplatform)
else
builder:wikitext(data.i18n.category.singleplatform)
end
end
local function renderTitles(builder, title, subtitle)
builder:tag('div')
:addClass(data.i18n.class.title)
:wikitext(title or data.i18n.display.reception)
:done()
if subtitle then
builder:tag('div')
:addClass(data.i18n.class.subtitle)
-- The only reason to use the subtitle is collapsible content
-- So always add the related class.
:addClass('mw-collapsible-content')
:wikitext(subtitle)
:done()
end
end
local function render(providedReviewers, providedAggregators, awardKeys,
activeSystems, customAggregatorKeys, customReviewerKeys, args, wikidata)
local is_collapsible = args.title and args.state and
(args.state == data.i18n.state.autocollapse or
args.state == data.i18n.state.collapsed or
args.state == data.i18n.state.expanded
)
local div = mw.html.create('div')
:attr('role', 'complementary')
:addClass(data.i18n.class.container)
:addClass(#activeSystems == 0 and data.i18n.class.containersingle or nil)
:addClass(args.align == data.i18n.align.left and data.i18n.class.containerleft or nil)
:addClass(args.align == data.i18n.align.none and data.i18n.class.containernone or nil)
:addClass(is_collapsible and 'mw-collapsible' or nil)
:addClass(is_collapsible and args.state == data.i18n.state.collapsed and 'mw-collapsed' or nil)
:addClass(is_collapsible and args.state == data.i18n.state.autocollapse and args.state or nil)
renderTitles(div, args.title, args.subtitle)
local aggregatorCount = #providedAggregators + #customAggregatorKeys
renderAggregators(
div,
providedAggregators,
activeSystems,
customAggregatorKeys,
args,
aggregatorCount
)
local reviewerCount = #customReviewerKeys + #providedReviewers
renderReviews(
div,
providedReviewers,
activeSystems,
customReviewerKeys,
args,
reviewerCount,
aggregatorCount
)
renderAwards(
div,
args,
awardKeys,
reviewerCount + aggregatorCount
)
renderEditOnWikidata(div, wikidata, args.state)
categorizePlatformCount(div, #activeSystems)
return div
end
local function checkForWikidata(frame, args, activeSystems, providedAggregators)
local wikidata = false
if args.qid == 'none' then
return wikidata
end
vgwd.setDateFormat(args.df)
vgwd.setGame(args.qid)
vgwd.setSystem(nil)
vgwd.setGenerateReferences(true)
vgwd.setShowUpdateLink(false)
vgwd.setUpdateLinkStyle("text and pen")
vgwd.setSystemFormat(args.systemFormat)
-- Loop through aggregators if we have any.
if #providedAggregators ~= 0 then
for _, aggr in ipairs(providedAggregators) do
-- Check if vgwd knows this aggregator.
if vgwd.setReviewer(aggr) == nil then
-- Loop through active systems
if #activeSystems ~= 0 then
for _, sys in ipairs(activeSystems) do
local combinedCode = aggr .. '_' .. sys
if args[combinedCode] == 'wikidata' then
vgwd.setSystem(sys)
vgwd.setShowSystem(false)
local vgwdScore = vgwd.printReviewScores(frame)
if vgwdScore then
args[combinedCode] = vgwdScore
end
wikidata = true
end
end
else
vgwd.setShowSystem(true)
if args[aggr] == 'wikidata' then
local vgwdScore = vgwd.printReviewScores(frame)
if vgwdScore then
args[aggr] = vgwdScore
end
wikidata = true
end
end
end
end
end
return wikidata
end
function p._reviewbox(frame, args)
local activeSystems = getActiveSystems(args)
local customReviewerKeys, customAggregatorKeys, awardKeys = getArgKeyTables(args)
local providedReviewers, providedAggregators = getProvidedReviewersAndAggregators(args, #activeSystems ~= 0)
local wikidata = checkForWikidata(frame, args, activeSystems, providedAggregators)
if #customAggregatorKeys ~= 0 or #customReviewerKeys ~= 0 or
#providedAggregators ~= 0 or #providedReviewers ~= 0 or #awardKeys ~= 0 then
return frame:extensionTag{
name='templatestyles', args = { src = data.i18n.templatestyles }
} .. tostring(render(
providedReviewers,
providedAggregators,
awardKeys,
activeSystems,
customAggregatorKeys,
customReviewerKeys,
args,
wikidata
))
elseif mw.title.getCurrentTitle().namespace == 0 then
return data.i18n.category.empty
end
end
function p.reviewbox(frame)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
return p._reviewbox(frame, getArgs(frame,
{ wrappers = data.i18n.wrapper, trim = false, translate = data.argi18n }
))
end
return p