Модуль:Video game reviews

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку
{{i}} Документація модуля[перегляд] [редагувати] [історія] [очистити кеш]

Цей модуль реалізує шаблон {{Оцінки відеогри}}.

Використання

{{#invoke:Video game reviews|назва функції}}

require('strict')

local p = {}
local data = require('Модуль:Video game reviews/data')
local yesno = require('Модуль:Yesno')
local vgwd = require('Модуль: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, reviewersUA, 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.reviewerUA) then
            table.insert(reviewersUA, 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(reviewersUA, comparator)
	table.sort(aggregators, comparator)
	table.sort(awards, comparator)
	return reviewers, reviewersUA, aggregators, awards
end

local function getProvidedReviewersAndAggregators(args, usePlatforms)
	local providedReviewers, providedReviewersUA, 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.reviewersUA[halfarg] then
						table.insert(providedReviewersUA, 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.reviewersUA[k] then
					table.insert(providedReviewersUA, 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(providedReviewersUA, function(a, b)
		return data.reviewersUA[a].sortkey < data.reviewersUA[b].sortkey
	end)
	table.sort(providedAggregators, function(a, b)
		return data.aggregators[a].sortkey < data.aggregators[b].sortkey
	end)
	return providedReviewers, providedReviewersUA, 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
        if v ~= 'GEN' then
		    builder:tag('th')
			    :wikitext(data.systems[v].name)
			    :attr('scope', 'col')
			    :done()
        end
	end
end

local function renderColWithSystems(builder, headingText)
	builder = builder:tag('tr')
		:addClass(data.i18n.class.headerrow)
		:tag('th')
			:attr('scope', 'col')
			:wikitext(headingText)
			:done()
		:tag('th')
		    :attr('scope', 'col')
		    :attr('class', 'platform-col')
		    :wikitext(data.i18n.display.platform)
    		:done()
		:tag('th')
			:attr('scope', 'col')
			:wikitext(data.i18n.display.score)
			:done()
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

function table.contains(table, element)
	for _, value in pairs(table) do
		if value == element then
			return true
		end
	end
	return false
end

local function renderRatingsBySystem(builder, code, name, activeSystems, args, na)
	builder = builder:tag('tr')
	builder:tag('td')
		:wikitext(name)

	if table.contains(activeSystems, 'GEN') then
		local combinedCode = code .. '_GEN'
		if args[combinedCode] then
			local cell = builder:tag('td')
				:attr('colspan', #activeSystems)
				:wikitext(args[combinedCode])
				:done()
			return builder
		end
	end
	
	for _, v in ipairs(activeSystems) do
		if v ~= 'GEN' then
			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

	return builder
end

local function renderColRatingsBySystem(builder, code, name, activeSystems, args, na)
	local activePlatforms = {}
	for _, v in ipairs(activeSystems) do
		local combinedCode = code .. '_' .. v
		if args[combinedCode] then
			table.insert(activePlatforms, v)
		end
	end

	local numRows = #activePlatforms + 1

	builder = builder:tag('tr')

	builder:tag('td')
		:attr('rowspan', numRows)
		:wikitext(name)
		:done()

	for _, v in ipairs(activePlatforms) do
		local combinedCode = code .. '_' .. v
		builder = builder:tag('tr')
		local platformCell = builder:tag('td')
		if v == 'GEN' then
			platformCell:addClass(data.i18n.class.na):wikitext(data.i18n.display.na):done()
		else
			platformCell:wikitext(data.systems[v].name):done()
		end
		local cell = builder:tag('td')
		if args[combinedCode] then
			cell:wikitext(args[combinedCode]):done()
		end
	end

	return builder
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 renderAggregatorsFunction
	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['aggregateScores'])
			:done()

	if #activeSystems ~= 0 then
		local na = yesno(args.na)
		local showplatforms = #activeSystems ~= 1 or yesno(args.showplatforms)
		if showplatforms then
			if yesno(args.platformcols) then
			    renderColWithSystems(builder, data.i18n.display.aggregator)
			    renderAggregatorsFunction = renderColRatingsBySystem
			else
			    renderHeadingRowWithSystems(builder, activeSystems, data.i18n.display.aggregator)
			    renderAggregatorsFunction = renderRatingsBySystem
			end
		else
			renderHeadingRow(builder, data.i18n.display.aggregator)
		end

		for _, v in ipairs(providedAggregators) do
			renderAggregatorsFunction(builder, v, data.aggregators[v].name, activeSystems, args, na)
		end
		for _, v in ipairs(customAggregatorKeys) do
			renderAggregatorsFunction(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 .. 'Оцінка'])
		end
	end
end

local function renderReviews(builder, providedReviewers, providedReviewersUA, activeSystems,
	customReviewerKeys, customReviewerUAKeys, args, reviewerCount, priorReviewCount)
	
	if reviewerCount == 0 then return end
	local renderReviewsFunction
	local hasReviewers = #providedReviewers ~= 0 or #customReviewerKeys ~= 0
	local hasReviewersUA = #providedReviewersUA ~= 0 or #customReviewerUAKeys ~= 0
			
	if #activeSystems ~= 0 then
		local na = yesno(args.na)
		local showplatforms = #activeSystems ~= 1 or yesno(args.showplatforms)
		
		if hasReviewers then
			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['reviewScores'])
				    :addClass(priorReviewCount > 0 and data.i18n.class.stacked or nil)
				    :done()
			
			if showplatforms then
				if yesno(args.platformcols) then
				    renderColWithSystems(builder, data.i18n.display.publication)
				    renderReviewsFunction = renderColRatingsBySystem
				else
				    renderHeadingRowWithSystems(builder, activeSystems, data.i18n.display.publication)
				    renderReviewsFunction = renderRatingsBySystem
				end
			else
				renderHeadingRow(builder, data.i18n.display.publication)
			end
			
			for _, v in ipairs(providedReviewers) do
				renderReviewsFunction(builder, v, data.reviewers[v].name, activeSystems, args, na)
			end
			for _, v in ipairs(customReviewerKeys) do
				renderReviewsFunction(builder, v, args[v], activeSystems, args, na)
			end
		end
		if hasReviewersUA then
			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['reviewScoresUA'])
				    :addClass(priorReviewCount > 0 and data.i18n.class.stacked or nil)
				    :done()
			
			if showplatforms then
				if yesno(args.platformcols) then
				    renderColWithSystems(builder, data.i18n.display.publication)
				    renderReviewsFunction = renderColRatingsBySystem
				else
				    renderHeadingRowWithSystems(builder, activeSystems, data.i18n.display.publication)
				    renderReviewsFunction = renderRatingsBySystem
				end
			else
				renderHeadingRow(builder, data.i18n.display.publication)
			end

			for _, v in ipairs(providedReviewersUA) do
				renderReviewsFunction(builder, v, data.reviewersUA[v].name, activeSystems, args, na)
			end
			for _, v in ipairs(customReviewerUAKeys) do
				renderReviewsFunction(builder, v, args[v], activeSystems, args, na)
			end
		end
	else
		if hasReviewers then
			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['reviewScores'])
				    :addClass(priorReviewCount > 0 and data.i18n.class.stacked or nil)
				    :done()
			
			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 .. 'Оцінка'])
			end
		end
		if hasReviewersUA then
			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['reviewScoresUA'])
				    :addClass(priorReviewCount > 0 and data.i18n.class.stacked or nil)
				    :done()
			    
			renderHeadingRow(builder, data.i18n.display.publication)
			    
			for _, v in ipairs(providedReviewersUA) do
				renderRating(builder, data.reviewersUA[v].name, args[v])
			end
			for _, v in ipairs(customReviewerUAKeys) do
				renderRating(builder, args[v], args[v .. 'Оцінка'])
			end
		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 .. 'Вид'])
				: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 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, providedReviewersUA, providedAggregators, awardKeys,
	activeSystems, customAggregatorKeys, customReviewerKeys, customReviewerUAKeys, 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 + #customReviewerUAKeys + #providedReviewersUA
	renderReviews(
		div,
		providedReviewers,
		providedReviewersUA,
		activeSystems,
		customReviewerKeys,
		customReviewerUAKeys,
		args,
		reviewerCount,
		aggregatorCount
	)
	renderAwards(
		div,
		args,
		awardKeys,
		reviewerCount + aggregatorCount
	)
	renderEditOnWikidata(div, wikidata, args.state)
		
	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, customReviewerUAKeys, customAggregatorKeys, awardKeys = getArgKeyTables(args)
	local providedReviewers, providedReviewersUA, providedAggregators = getProvidedReviewersAndAggregators(args, #activeSystems ~= 0)
	local wikidata = checkForWikidata(frame, args, activeSystems, providedAggregators)
	if #customAggregatorKeys ~= 0 or #customReviewerKeys ~= 0 or #customReviewerUAKeys ~= 0 or
		#providedAggregators ~= 0 or #providedReviewers ~= 0 or #providedReviewersUA ~= 0 or #awardKeys ~= 0 then
		return frame:extensionTag{
			name='templatestyles', args = { src = data.i18n.templatestyles }
		} ..  tostring(render(
				providedReviewers,
				providedReviewersUA,
				providedAggregators,
				awardKeys,
				activeSystems,
				customAggregatorKeys,
				customReviewerKeys,
				customReviewerUAKeys,
				args,
				wikidata
		))
	end
end

function p.reviewbox(frame)
	if not getArgs then
		getArgs = require('Модуль:Arguments').getArgs
	end
	return p._reviewbox(frame, getArgs(frame,
		{ wrappers = data.i18n.wrapper, trim = false, translate = data.argi18n }
	))
end

return p