Module:ConceptRelation

From No Subject
Jump to navigation Jump to search

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

local p = {}
local cargo = mw.ext.cargo

local typeCache = nil
local domainCache = nil

local function norm(s)
	if not s or s == '' then
		return ''
	end
	return mw.ustring.lower(mw.text.trim(s))
end

local function loadTypeCache()
	if typeCache then
		return typeCache
	end

	typeCache = {}
	local rows = cargo.query(
		'ConceptRelationTypes_v1',
		'type_key,label_forward,label_reverse,description,css_class,group_name,directionality,display_order,active',
		{
			where = 'active=1',
			orderBy = 'display_order,type_key'
		}
	)

	for _, row in ipairs(rows) do
		typeCache[norm(row.type_key)] = row
	end

	return typeCache
end

local function loadDomainCache()
	if domainCache then
		return domainCache
	end

	domainCache = {}
	local rows = cargo.query(
		'ConceptRelationDomains_v1',
		'domain_key,domain_label,description,css_class,display_order,active',
		{
			where = 'active=1',
			orderBy = 'display_order,domain_key'
		}
	)

	for _, row in ipairs(rows) do
		domainCache[norm(row.domain_key)] = row
	end

	return domainCache
end

local function makeLink(pageName)
	if not pageName or pageName == '' then
		return ''
	end
	return tostring(mw.title.makeTitle(0, pageName))
end

local function renderRelation(row, types, domains)
	local typeMeta = types[norm(row.relation_type)] or {}
	local domainMeta = domains[norm(row.relation_domain)] or {}

	local cssClass = typeMeta.css_class or 'rel-generic'
	local domainClass = domainMeta.css_class or 'dom-general'
	local label = typeMeta.label_forward or row.relation_type or 'Related to'
	local domainLabel = domainMeta.domain_label or row.relation_domain or ''

	local root = mw.html.create('div')
	root:addClass('concept-relation')
	root:addClass(cssClass)

	local head = root:tag('div')
	head:addClass('concept-relation__head')

	head:tag('span')
		:addClass('concept-relation__label')
		:wikitext(label)

	head:tag('span')
		:addClass('concept-relation__target')
		:wikitext('[[' .. row.target_concept .. ']]')

	if domainLabel ~= '' then
		head:tag('span')
			:addClass('concept-relation__domain')
			:addClass(domainClass)
			:wikitext(domainLabel)
	end

	if row.relation_note and mw.text.trim(row.relation_note) ~= '' then
		root:tag('div')
			:addClass('concept-relation__body')
			:wikitext(row.relation_note)
	end

	return tostring(root)
end

function p.renderSection(frame)
	local args = frame.args
	local source = args.source or mw.title.getCurrentTitle().text
	source = mw.text.trim(source)

	local rows = cargo.query(
		'ConceptRelations_v1',
		'source_concept,target_concept,relation_type,relation_domain,relation_note,relation_order',
		{
			where = 'source_concept="' .. source:gsub('"', '\\"') .. '"',
			orderBy = 'relation_order,target_concept'
		}
	)

	if #rows == 0 then
		return "''No conceptual relations recorded.''"
	end

	local types = loadTypeCache()
	local domains = loadDomainCache()

	local out = {}
	table.insert(out, frame:extensionTag('templatestyles', '', { src = 'Template:ConceptRelation/styles.css' }))
	table.insert(out, '<div class="concept-relations">')

	for _, row in ipairs(rows) do
		table.insert(out, renderRelation(row, types, domains))
	end

	table.insert(out, '</div>')

	return table.concat(out, '\n')
end

return p