PC Gaming Shelter
An archive dedicated to preserving PC Gaming history and more

Module:ResourceList: Difference between revisions

From PC Gaming Shelter
No edit summary
No edit summary
 
(24 intermediate revisions by the same user not shown)
Line 4: Line 4:
{
{
key = "resources",
key = "resources",
title = "Resources",
title = "Type",
property = "Has resource type",
property = "Has resource type",
},
},
{
{
key = "types",
key = "types",
title = "Types",
title = "Content",
property = "Has content type",
property = "Has content type",
},
},
{
{
key = "langs",
key = "langs",
title = "Languages",
title = "Language",
property = "Has language",
property = "Has language",
},
},
{
{
key = "years",
key = "years",
title = "Years",
title = "Year",
property = "Has date",
property = "Has date",
},
},
Line 121: Line 121:


local function renderList(frame, field, bucket, game, showCounts)
local function renderList(frame, field, bucket, game, showCounts)
local lines = {
local html = mw.html.create()
"==" .. field.title .. "==",
local resItem = html:tag('div'):addClass('card bg-transparent flex-md-row mb-2')
}
 
resItem:tag('div'):addClass('resources-header'):wikitext(field.title)
local cardBody = resItem:tag('div'):addClass('d-flex flex-wrap px-3 text-muted'):css({
['gap'] = '0 .5rem'
})
local keys = sortedKeys(bucket)
local keys = sortedKeys(bucket)


if #keys == 0 then
if #keys == 0 then
table.insert(lines, "''None found.''")
cardBody:tag('div'):wikitext("None found.")
return table.concat(lines, "\n")
return html
end
end


Line 137: Line 141:


if showCounts then
if showCounts then
table.insert(lines, "* " .. link .. " (" .. bucket.counts[key] .. ")")
cardBody:tag('div'):wikitext(link .. " (" .. bucket.counts[key] .. ")")
else
else
table.insert(lines, "* " .. link)
cardBody:tag('div'):wikitext(link)
end
end
end
end


return table.concat(lines, "\n")
return html
end
end


local function askRows(args)
local function askRows(args)
local game = args.game or "Half-Life"
local game = args.game
if not game then
return
end
local limit = args.limit or "5000"
local limit = args.limit or "5000"


Line 163: Line 171:


function p.render(frame)
function p.render(frame)
local parent = frame:getParent()
local args = setmetatable(frame.args, {
local args = frame.args or {}
__index = parent and parent.args or {},
})


local game = args.game or "Half-Life"
local game = args.game
local showCounts = args.counts ~= "no"
local showCounts = args.counts ~= "no"
local rows = askRows(args)
local rows = askRows(args)
local buckets = collect(rows)
local buckets = collect(rows)
local header = args.header or 'External Resources'


local output = {}
local html = mw.html.create()
 
local res = html:tag('div'):attr('id', 'more-resources')
res:tag('h2'):wikitext(header)
for _, field in ipairs(FIELDS) do
for _, field in ipairs(FIELDS) do
table.insert(output, renderList(frame, field, buckets[field.key], game, showCounts))
res:node(renderList(frame, field, buckets[field.key], game, showCounts))
end
end


return table.concat(output, "\n\n")
return html
end
end


Line 195: Line 205:
"[[Resource:+]][[Related game::" .. game .. "]][[" .. filter .. "::~" .. item .. "]]",
"[[Resource:+]][[Related game::" .. game .. "]][[" .. filter .. "::~" .. item .. "]]",
"format=embedded",
"format=embedded",
"embedonly=yes",
"embedformat=h5",
"limit=5000",
"limit=5000",
})
})

Latest revision as of 14:07, 12 July 2026

Documentation for this module may be created at Module:ResourceList/doc

local p = {}

local FIELDS = {
	{
		key = "resources",
		title = "Type",
		property = "Has resource type",
	},
	{
		key = "types",
		title = "Content",
		property = "Has content type",
	},
	{
		key = "langs",
		title = "Language",
		property = "Has language",
	},
	{
		key = "years",
		title = "Year",
		property = "Has date",
	},
}

local function trim(value)
	return mw.text.trim(tostring(value or ""))
end

local function valueText(value)
	if type(value) ~= "table" then
		return trim(value)
	end

	return trim(
		value.fulltext
			or value.fullText
			or value.label
			or value.text
			or value.displaytitle
			or value[1]
			or ""
	)
end

local function addValue(bucket, rawValue)
	local value = valueText(rawValue)

	if value == "" then
		return
	end

	local key = mw.ustring.lower(value)

	if bucket.counts[key] == nil then
		bucket.counts[key] = 0
		bucket.labels[key] = value
	end

	bucket.counts[key] = bucket.counts[key] + 1
end

local function collect(rows)
	local buckets = {}

	for _, field in ipairs(FIELDS) do
		buckets[field.key] = {
			counts = {},
			labels = {},
		}
	end

	for _, row in ipairs(rows) do
		for _, field in ipairs(FIELDS) do
			local values = row[field.key]
			local bucket = buckets[field.key]

			if type(values) == "table" then
				for _, value in ipairs(values) do
					addValue(bucket, value)
				end
			else
				addValue(bucket, values)
			end
		end
	end

	return buckets
end

local function sortedKeys(bucket)
	local keys = {}

	for key in pairs(bucket.counts) do
		table.insert(keys, key)
	end

	table.sort(keys, function(a, b)
		return mw.ustring.lower(bucket.labels[a]) < mw.ustring.lower(bucket.labels[b])
	end)

	return keys
end

local function queryFormLink(frame, game, propertyName, item)
	return frame:preprocess(string.format(
		"{{#queryformlink: form=Resource filter" ..
		"|link text=%s" ..
		"|Resource filter[Related game]=%s" ..
		"|Resource filter[%s]=%s" ..
		"|Resource filter[Has filter]=%s" ..
		"|_run=1" ..
		"}}",
		item,
		game,
		propertyName,
		item,
		propertyName
	))
end

local function renderList(frame, field, bucket, game, showCounts)
	local html = mw.html.create()
	local resItem = html:tag('div'):addClass('card bg-transparent flex-md-row mb-2')
	
	resItem:tag('div'):addClass('resources-header'):wikitext(field.title)
	local cardBody = resItem:tag('div'):addClass('d-flex flex-wrap px-3 text-muted'):css({
		['gap'] = '0 .5rem'
	})
	
	local keys = sortedKeys(bucket)

	if #keys == 0 then
		cardBody:tag('div'):wikitext("None found.")
		return html
	end

	for _, key in ipairs(keys) do
		local label = bucket.labels[key]
		local link = queryFormLink(frame, game, field.property, label)

		if showCounts then
			cardBody:tag('div'):wikitext(link .. " (" .. bucket.counts[key] .. ")")
		else
			cardBody:tag('div'):wikitext(link)
		end
	end

	return html
end

local function askRows(args)
	local game = args.game
	if not game then
		return
	end
	
	local limit = args.limit or "5000"

	return mw.smw.ask({
		"[[Resource:+]]",
		"[[Related game::" .. game .. "]]",
		"?Has resource type=resources",
		"?Has content type=types",
		"?Has language=langs",
		"?Has date#-F[Y]=years",
		"limit=" .. limit,
		"mainlabel=-",
	}) or {}
end

function p.render(frame)
	
	local args = frame.args or {}

	local game = args.game
	local showCounts = args.counts ~= "no"
	local rows = askRows(args)
	local buckets = collect(rows)
	local header = args.header or 'External Resources' 

	local html = mw.html.create()
	
	local res = html:tag('div'):attr('id', 'more-resources')
	res:tag('h2'):wikitext(header)
	
	for _, field in ipairs(FIELDS) do
		res:node(renderList(frame, field, buckets[field.key], game, showCounts))
	end

	return html
end

function p.filtered(frame)
	local item   = frame.args['item']
	local parent = frame:getParent()
	local args = setmetatable(frame.args, {
		__index = parent and parent.args or {},
	})

	local game   = args['Related game']
	local filter = args['Has filter']

	local query = frame:callParserFunction("#ask", {
		"[[Resource:+]][[Related game::" .. game .. "]][[" .. filter .. "::~" .. item .. "]]",
		"format=embedded",
		"embedformat=h5",
		"limit=5000",
	})

	return query
end

p.main = p.render

return p