Jump to content

Module:Class

Permanently protected module
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Nihiltres (talk | contribs) at 01:06, 24 December 2016 (Removed debug lines and improved some logic in getProperty()). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

-- This module implements [[Template:Class]], [[Template:Class/icon]] and
-- [[Template:Class/colour]].

local mArguments, mIcon -- modules to lazily load
local definitions = mw.loadData('Module:Class/importDefinitions')

local p = {}

-- Initialize helper function variables
local getDefinition, getRawArgs, makeInvokeFunction, normalizeValue

--------------------------------------------------------------------------------
-- Argument helper functions
--------------------------------------------------------------------------------

function getRawArgs(frame, wrapper)
	mArguments = mArguments or require('Module:Arguments')
	return mArguments.getArgs(frame, {
		wrappers = wrapper,
		trim = false,
		removeBlanks = false
	})
end

function makeInvokeFunction(func, wrapper)
	return function (frame)
		local args = getRawArgs(frame, wrapper)
		return func(args)
	end
end

--------------------------------------------------------------------------------
-- String helper functions
--------------------------------------------------------------------------------

function trim(str)
	if type(str) == 'string' then str = str:match('^%s*(.-)%s*$') end
	return str
end

function normalizeValue(val)
	if type(val) == 'string' then val = trim(val):lower() end
	if val == '' then val = nil end
	return val
end

function ucfirst(str)
	return mw.ustring.upper(mw.ustring.sub(str, 1, 1)) .. mw.ustring.sub(str, 2)
end

--------------------------------------------------------------------------------
-- Definition helper functions
--------------------------------------------------------------------------------

function getDefinition(code)
	local canonicalCode = normalizeValue(code)
	if code == 'DEFAULT' then canonicalCode = code end --DEFAULT special-case
	local class = definitions[canonicalCode]
	while class and class.alias do
		canonicalCode = class.alias
		class = definitions[class.alias]
	end
	if not class then
		return nil, nil
	end
	return class, canonicalCode
end

function getDefault() return getDefinition('DEFAULT') end

function getProperty(class, default, map)
	local pop = table.remove(map, 1)
	local prop, dProp = class and class[pop], default and default[pop]
	while #map > 0 do
		pop = table.remove(map, 1)
		prop = ((type(prop) == 'table') or nil) and prop[pop]
		dProp = ((type(dProp) == 'table') or nil) and dProp[pop]
	end
	if prop == nil then prop = dProp end
	return prop
end

function getProperties(class, default, ...)
	local props, maps, i, map, prop = {}, {...}, 1
	while #maps > 0 do
		map = table.remove(maps, 1)
		prop = getProperty(class, default, map)
		props[i] = prop --manual index because table could be sparse
		i = i + 1
	end
	return unpack(props)
end

--------------------------------------------------------------------------------
-- Color functions
--------------------------------------------------------------------------------

function p._colour(code)
	local class = getDefinition(code)
	local default = getDefault()
	return getProperty(class, default, {'colour'})
end

function p.colour(frame)
	local args = getRawArgs(frame, 'Template:Class/colour')
	local colour = p._colour(args[1])
	-- We need nowiki tags as template output beginning with "#" triggers
	-- bug 14974.
	return frame:extensionTag('nowiki', colour)
end

--------------------------------------------------------------------------------
-- Icon functions
--------------------------------------------------------------------------------

function p._icon(args)
	local class = getDefinition(args.class or args[1])
	local default = getDefault()
	local file, label, attribution = getProperties(class, default,
		{"icon", "file"},
		{"labels", "full"},
		{"icon", "requiresAttribution"})
	label = ucfirst(label)
	local span = mw.html.create('span')
	span
		:cssText(args.style)
		:attr('title', label)
		:wikitext(
			string.format(
				'[[File:%s|%s|16px%s]]',
				file,
				label,
				attribution and '' or '|link=|alt='
			)
		)
	return tostring(span)
end

p.icon = makeInvokeFunction(p._icon, 'Template:Class/icon')

--------------------------------------------------------------------------------
-- Class functions
--------------------------------------------------------------------------------

function p._class(args)
	local classDef, classCode = getDefinition(args.class or args[1])
	local default = getDefault()
	local iconDefault, shortLabel, categoryRoot = getProperties(
		classDef, default,
		{"icon", "default"},
		{"labels", "short"},
		{"categoryRoot"}
	)
	--o is short for "options"
	local o = {
		bold = args.bold,
		heading = args.heading,
		image = args.image,
		rowspan = args.rowspan
	}
	for k, v in pairs(o) do o[k] = normalizeValue(v) end
	o.fullcategory, o.category, o.topic = trim(args.fullcategory),
		trim(args.category), trim(args.topic)

	local cell = mw.html.create(o.heading and 'th' or 'td')
	--image=yes forces icon, image=no disables it, otherwise checks default
	local icon = iconDefault and (o.image ~= 'no') or (o.image == 'yes')
	icon = icon and p.icon(args) .. ' ' or ''
	local categoryRoot = (
		((classCode ~= 'unassessed') and categoryRoot) or
		((o.category or o.topic) and 'Unassessed') or
		'Unassessed-Class'
	)
	--^ Special case for 'unassessed' class because of inconsistent
	--  top-level category name; cat. name ought to be fixed :\
	local category = string.format(
		'Category:%s',
		o.fullcategory or (
			string.format(
				'%s %s',
				categoryRoot,
				o.category or
					string.format(
						'%sarticles',
						o.topic and (o.topic .. ' ') or ''
					)
			)
		)
	)
	local text = string.format(
			'[[:%s|%s]]',
			category,
			shortLabel
		)
	cell
		:addClass('assess')
		:addClass('assess-' .. (classCode or ''))
		:css('text-align', 'center')
		:css('white-space', 'nowrap')
		:css('font-weight', o.bold ~= 'no' and 'bold' or nil)
		:css('background', p._colour(classCode))
		:attr('rowspan', tonumber(o.rowspan))
		:wikitext(icon, text)

		return tostring(cell)
end

p.class = makeInvokeFunction(p._class, 'Template:Class')

return p