Difference between revisions of "Module:Class"
Jump to navigation
Jump to search
blackwiki>Nihiltres (Fixed logical error, derp) |
blackwiki>Nihiltres (A first pass at cleaning up the defaulting a bit…) |
||
| Line 33: | Line 33: | ||
-- String helper functions | -- String helper functions | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
| + | |||
| + | function trim(str) | ||
| + | if type(str) == 'string' then str = str:match('^%s*(.-)%s*$') end | ||
| + | return str | ||
| + | end | ||
function normalizeValue(val) | function normalizeValue(val) | ||
| − | if type(val) == 'string' then val = val | + | if type(val) == 'string' then val = trim(val):lower() end |
if val == '' then val = nil end | if val == '' then val = nil end | ||
return val | return val | ||
| Line 50: | Line 55: | ||
function getDefinition(code) | function getDefinition(code) | ||
local canonicalCode = normalizeValue(code) | local canonicalCode = normalizeValue(code) | ||
| + | if code == 'DEFAULT' then canonicalCode = code end --DEFAULT special-case | ||
local class = definitions[canonicalCode] | local class = definitions[canonicalCode] | ||
while class and class.alias do | while class and class.alias do | ||
| Line 60: | Line 66: | ||
return class, canonicalCode | return class, canonicalCode | ||
end | 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 = ((prop ~= nil) or nil) and prop[pop] | ||
| + | dProp = ((dProp ~=nil) 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 | ||
| + | |||
| + | --for debug | ||
| + | function p.getDefinition(...) return getDefinition(...) end | ||
| + | function p.getDefault() return getDefault() end | ||
| + | function p.getProperties(...) return getProperties(...) end | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
| Line 67: | Line 103: | ||
function p._colour(code) | function p._colour(code) | ||
local class = getDefinition(code) | local class = getDefinition(code) | ||
| − | return class | + | local default = getDefault() |
| − | + | return getProperty(class, default, {'colour'}) | |
end | end | ||
| Line 85: | Line 121: | ||
function p._icon(args) | function p._icon(args) | ||
local class = getDefinition(args.class or args[1]) | local class = getDefinition(args.class or args[1]) | ||
| − | local | + | local default = getDefault() |
| − | + | local file, label, attribution = getProperties(class, default, | |
| − | local span = mw.html.create('span') | + | {"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:%s|%s|16px%s]]', | ||
| − | + | file, | |
| − | + | label, | |
| − | + | attribution and '' or '|link=|alt=' | |
| − | + | ) | |
| − | )) | + | ) |
| − | + | return tostring(span) | |
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| Line 113: | Line 150: | ||
function p._class(args) | function p._class(args) | ||
local classDef, classCode = getDefinition(args.class or args[1]) | local classDef, classCode = getDefinition(args.class or args[1]) | ||
| − | local cell = mw.html.create( | + | 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 | --image=yes forces icon, image=no disables it, otherwise checks default | ||
| − | local icon = | + | local icon = iconDefault and (o.image ~= 'no') or (o.image == 'yes') |
| − | |||
| − | |||
| − | |||
| − | |||
icon = icon and p.icon(args) .. ' ' or '' | icon = icon and p.icon(args) .. ' ' or '' | ||
| − | |||
| − | |||
local categoryRoot = ( | local categoryRoot = ( | ||
| − | ( | + | ((classCode ~= 'unassessed') and categoryRoot) or |
| − | + | ((o.category or o.topic) and 'Unassessed') or | |
| − | |||
| − | |||
| − | ( | ||
| − | |||
| − | |||
'Unassessed-Class' | 'Unassessed-Class' | ||
) | ) | ||
| Line 137: | Line 181: | ||
local category = string.format( | local category = string.format( | ||
'Category:%s', | 'Category:%s', | ||
| − | + | o.fullcategory or ( | |
string.format( | string.format( | ||
'%s %s', | '%s %s', | ||
categoryRoot, | categoryRoot, | ||
| − | + | o.category or | |
string.format( | string.format( | ||
'%sarticles', | '%sarticles', | ||
| − | + | o.topic and (o.topic .. ' ') or '' | |
) | ) | ||
) | ) | ||
) | ) | ||
) | ) | ||
| − | text = string.format( | + | local text = string.format( |
'[[:%s|%s]]', | '[[:%s|%s]]', | ||
category, | category, | ||
| − | + | shortLabel | |
| − | ) | + | ) |
cell | cell | ||
:addClass('assess') | :addClass('assess') | ||
| Line 159: | Line 203: | ||
:css('text-align', 'center') | :css('text-align', 'center') | ||
:css('white-space', 'nowrap') | :css('white-space', 'nowrap') | ||
| − | :css('font-weight', | + | :css('font-weight', o.bold ~= 'no' and 'bold' or nil) |
:css('background', p._colour(classCode)) | :css('background', p._colour(classCode)) | ||
| − | :attr('rowspan', tonumber( | + | :attr('rowspan', tonumber(o.rowspan)) |
:wikitext(icon, text) | :wikitext(icon, text) | ||
Revision as of 00:52, 24 December 2016
| This module is rated as ready for general use. It has reached a mature form and is thought to be bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
Usage
This module will implement Template:Class, Template:Class/icon and Template:Class/colour.
{{#invoke:Class|function_name}}
-- 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 = ((prop ~= nil) or nil) and prop[pop]
dProp = ((dProp ~=nil) 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
--for debug
function p.getDefinition(...) return getDefinition(...) end
function p.getDefault() return getDefault() end
function p.getProperties(...) return getProperties(...) 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