Module:Video game reviews

require('strict')

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("notheme") :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('skin-nightmode-reset-color') :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(data.i18n.class.dark) :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