Line 1: |
Line 1: |
− | ---------------------------------------------------------------------------------------------------- | + | --[[ |
− | -- -- | + | -------------------------------------------------------------------------------- |
− | -- NAMESPACE DETECT -- | + | -- -- |
− | -- -- | + | -- NAMESPACE DETECT -- |
− | -- This module implements the {{namespace detect}} template in Lua, with a few -- | + | -- -- |
− | -- improvements: all namespaces and all namespace aliases are supported, and namespace -- | + | -- This module implements the {{namespace detect}} template in Lua, with a -- |
− | -- names are detected automatically for the local wiki. The module can also use the -- | + | -- few improvements: all namespaces and all namespace aliases are supported, -- |
− | -- corresponding subject namespace value if it is used on a talk page. Parameter names --
| + | -- and namespace names are detected automatically for the local wiki. The -- |
− | -- can be configured for different wikis by altering the values in the "cfg" table. --
| + | -- module can also use the corresponding subject namespace value if it is -- |
− | -- -- | + | -- used on a talk page. Parameter names can be configured for different wikis -- |
− | ---------------------------------------------------------------------------------------------------- | + | -- by altering the values in the "cfg" table in -- |
| + | -- Module:Namespace detect/config. -- |
| + | -- -- |
| + | -------------------------------------------------------------------------------- |
| + | --]] |
| | | |
− | ----------------------------------------------------------------------------------------------------
| + | local data = mw.loadData('Module:Namespace detect/data') |
− | -- Configuration data --
| + | local argKeys = data.argKeys |
− | -- Language-specific parameter names can be set here. --
| + | local cfg = data.cfg |
− | ----------------------------------------------------------------------------------------------------
| + | local mappings = data.mappings |
| | | |
− | local cfg = {} | + | local yesno = require('Module:Yesno') |
| + | local mArguments -- Lazily initialise Module:Arguments |
| + | local mTableTools -- Lazily initilalise Module:TableTools |
| + | local ustringLower = mw.ustring.lower |
| | | |
− | -- This parameter displays content for the main namespace:
| + | local p = {} |
− | cfg.main = 'main'
| |
| | | |
− | -- This parameter displays in talk namespaces: | + | local function fetchValue(t1, t2) |
− | cfg.talk = 'talk'
| + | -- Fetches a value from the table t1 for the first key in array t2 where |
| + | -- a non-nil value of t1 exists. |
| + | for i, key in ipairs(t2) do |
| + | local value = t1[key] |
| + | if value ~= nil then |
| + | return value |
| + | end |
| + | end |
| + | return nil |
| + | end |
| | | |
− | -- This parameter displays content for "other" namespaces (namespaces for which
| + | local function equalsArrayValue(t, value) |
− | -- parameters have not been specified, or for when cfg.demospace is set to cfg.other):
| + | -- Returns true if value equals a value in the array t. Otherwise |
− | cfg.other = 'other'
| + | -- returns false. |
− | | + | for i, arrayValue in ipairs(t) do |
− | -- This parameter makes talk pages behave as though they are the corresponding subject namespace. | + | if value == arrayValue then |
− | -- Note that this parameter is used with [[Module:Yesno]]. Edit that module to change | + | return true |
− | -- the default values of "yes", "no", etc.
| + | end |
− | cfg.subjectns = 'subjectns'
| + | end |
− | | + | return false |
− | -- This parameter sets a demonstration namespace:
| + | end |
− | cfg.demospace = 'demospace'
| |
− | | |
− | -- This parameter sets a specific page to compare:
| |
− | cfg.page = 'page'
| |
− | | |
− | -- The header for the namespace column in the wikitable containing the list of possible subject-space parameters.
| |
− | cfg.wikitableNamespaceHeader = 'Namespace'
| |
− | | |
− | -- The header for the wikitable containing the list of possible subject-space parameters.
| |
− | cfg.wikitableAliasesHeader = 'Aliases'
| |
− | | |
− | ----------------------------------------------------------------------------------------------------
| |
− | -- End configuration data --
| |
− | ----------------------------------------------------------------------------------------------------
| |
− | | |
− | local yesno = require('Module:Yesno')
| |
− | | |
− | local p = {}
| |
| | | |
| function p.getPageObject(page) | | function p.getPageObject(page) |
− | -- Get the page object, passing the function through pcall in case we are over the expensive function count limit. | + | -- Get the page object, passing the function through pcall in case of |
| + | -- errors, e.g. being over the expensive function count limit. |
| if page then | | if page then |
− | local noError, pageObject = pcall(mw.title.new, page) | + | local success, pageObject = pcall(mw.title.new, page) |
− | if not noError then | + | if success then |
| + | return pageObject |
| + | else |
| return nil | | return nil |
− | else
| |
− | return pageObject
| |
| end | | end |
| else | | else |
Line 67: |
Line 65: |
| end | | end |
| | | |
| + | -- Provided for backward compatibility with other modules |
| function p.getParamMappings() | | function p.getParamMappings() |
− | --[[ Returns a table of how parameter names map to namespace names. The keys are the actual namespace
| |
− | names, in lower case, and the values are the possible parameter names for that namespace, also in
| |
− | lower case. The table entries are structured like this:
| |
− | {
| |
− | [''] = {'main'},
| |
− | ['wikipedia'] = {'wikipedia', 'project', 'wp'},
| |
− | ...
| |
− | }
| |
− | ]]
| |
− | local mappings = {}
| |
− | mappings[mw.ustring.lower(mw.site.namespaces[0].name)] = {cfg.main}
| |
− | mappings[cfg.talk] = {cfg.talk}
| |
− | for nsid, ns in pairs(mw.site.subjectNamespaces) do
| |
− | if nsid ~= 0 then -- Exclude main namespace.
| |
− | local nsname = mw.ustring.lower(ns.name)
| |
− | local canonicalName = mw.ustring.lower(ns.canonicalName)
| |
− | mappings[nsname] = {nsname}
| |
− | if canonicalName ~= nsname then
| |
− | table.insert(mappings[nsname], canonicalName)
| |
− | end
| |
− | for _, alias in ipairs(ns.aliases) do
| |
− | table.insert(mappings[nsname], mw.ustring.lower(alias))
| |
− | end
| |
− | end
| |
− | end
| |
| return mappings | | return mappings |
| end | | end |
| | | |
| local function getNamespace(args) | | local function getNamespace(args) |
− | -- Gets the namespace name from the page object. | + | -- This function gets the namespace name from the page object. |
− | local page = args[cfg.page] | + | local page = fetchValue(args, argKeys.demopage) |
− | local demospace = args[cfg.demospace] | + | if page == '' then |
− | local subjectns = args[cfg.subjectns] | + | page = nil |
| + | end |
| + | local demospace = fetchValue(args, argKeys.demospace) |
| + | if demospace == '' then |
| + | demospace = nil |
| + | end |
| + | local subjectns = fetchValue(args, argKeys.subjectns) |
| local ret | | local ret |
| if demospace then | | if demospace then |
| -- Handle "demospace = main" properly. | | -- Handle "demospace = main" properly. |
− | if mw.ustring.lower(demospace) == cfg.main then | + | if equalsArrayValue(argKeys.main, ustringLower(demospace)) then |
| ret = mw.site.namespaces[0].name | | ret = mw.site.namespaces[0].name |
| else | | else |
Line 113: |
Line 93: |
| if pageObject then | | if pageObject then |
| if pageObject.isTalkPage then | | if pageObject.isTalkPage then |
− | -- If cfg.subjectns is set, get the subject namespace, otherwise use cfg.talk. | + | -- Get the subject namespace if the option is set, |
| + | -- otherwise use "talk". |
| if yesno(subjectns) then | | if yesno(subjectns) then |
| ret = mw.site.namespaces[pageObject.namespace].subject.name | | ret = mw.site.namespaces[pageObject.namespace].subject.name |
| else | | else |
− | ret = cfg.talk | + | ret = 'talk' |
| end | | end |
| else | | else |
Line 126: |
Line 107: |
| end | | end |
| end | | end |
− | ret = mw.ustring.gsub(ret, '_', ' ') | + | ret = ret:gsub('_', ' ') |
− | return mw.ustring.lower(ret) | + | return ustringLower(ret) |
| end | | end |
| | | |
| function p._main(args) | | function p._main(args) |
− | -- Get the namespace to compare the parameters to, and the parameter mapping table. | + | -- Check the parameters stored in the mappings table for any matches. |
− | local namespace = getNamespace(args) | + | local namespace = getNamespace(args) or 'other' -- "other" avoids nil table keys |
− | local mappings = p.getParamMappings()
| + | local params = mappings[namespace] or {} |
− | -- Check for any matches in the namespace arguments. The order we check them doesn't matter,
| + | local ret = fetchValue(args, params) |
− | -- as there can only be one match.
| + | --[[ |
− | for ns, params in pairs(mappings) do | + | -- If there were no matches, return parameters for other namespaces. |
− | if ns == namespace then
| + | -- This happens if there was no text specified for the namespace that |
− | -- Check all aliases for matches. The default local namespace is checked first, as
| + | -- was detected or if the demospace parameter is not a valid |
− | -- {{namespace detect}} checked these before alias names.
| + | -- namespace. Note that the parameter for the detected namespace must be |
− | for _, param in ipairs(params) do
| |
− | if args[param] ~= nil then
| |
− | return args[param]
| |
− | end
| |
− | end
| |
− | end
| |
− | end
| |
− | -- If there were no matches, return parameters for other namespaces. This happens if there | |
− | -- was no text specified for the namespace that was detected or if the demospace parameter
| |
− | -- is not a valid namespace. Note that the parameter for the detected namespace must be | |
| -- completely absent for this to happen, not merely blank. | | -- completely absent for this to happen, not merely blank. |
− | if args[cfg.other] ~= nil then | + | --]] |
− | return args[cfg.other] | + | if ret == nil then |
| + | ret = fetchValue(args, argKeys.other) |
| end | | end |
| + | return ret |
| end | | end |
| | | |
| function p.main(frame) | | function p.main(frame) |
− | -- If called via #invoke, use the args passed into the invoking template, or the args | + | mArguments = require('Module:Arguments') |
− | -- passed to #invoke if any exist. Otherwise assume args are being passed directly in. | + | local args = mArguments.getArgs(frame, {removeBlanks = false}) |
− | local origArgs | + | local ret = p._main(args) |
− | if frame == mw.getCurrentFrame() then | + | return ret or '' |
− | origArgs = frame:getParent().args | + | end |
− | for k, v in pairs(frame.args) do | + | |
− | origArgs = frame.args | + | function p.table(frame) |
− | break | + | --[[ |
| + | -- Create a wikitable of all subject namespace parameters, for |
| + | -- documentation purposes. The talk parameter is optional, in case it |
| + | -- needs to be excluded in the documentation. |
| + | --]] |
| + | |
| + | -- Load modules and initialise variables. |
| + | mTableTools = require('Module:TableTools') |
| + | local namespaces = mw.site.namespaces |
| + | local cfg = data.cfg |
| + | local useTalk = type(frame) == 'table' |
| + | and type(frame.args) == 'table' |
| + | and yesno(frame.args.talk) -- Whether to use the talk parameter. |
| + | |
| + | -- Get the header names. |
| + | local function checkValue(value, default) |
| + | if type(value) == 'string' then |
| + | return value |
| + | else |
| + | return default |
| end | | end |
− | else
| |
− | origArgs = frame
| |
| end | | end |
− | -- Trim whitespace and remove blank arguments for demospace and page parameters. | + | local nsHeader = checkValue(cfg.wikitableNamespaceHeader, 'Namespace') |
− | local args = {} | + | local aliasesHeader = checkValue(cfg.wikitableAliasesHeader, 'Aliases') |
− | for k, v in pairs(origArgs) do | + | |
− | if type(v) == 'string' then | + | -- Put the namespaces in order. |
− | v = mw.text.trim(v) -- Trim whitespace. | + | local mappingsOrdered = {} |
− | end
| + | for nsname, params in pairs(mappings) do |
− | if k == cfg.demospace or k == cfg.page then
| + | if useTalk or nsname ~= 'talk' then |
− | if v ~= '' then | + | local nsid = namespaces[nsname].id |
− | args[k] = v
| + | -- Add 1, as the array must start with 1; nsid 0 would be lost otherwise. |
− | end
| + | nsid = nsid + 1 |
− | else
| + | mappingsOrdered[nsid] = params |
− | args[k] = v | |
| end | | end |
| end | | end |
− | return p._main(args) | + | mappingsOrdered = mTableTools.compressSparseArray(mappingsOrdered) |
− | end
| |
| | | |
− | function p.table(frame)
| + | -- Build the table. |
− | --[[ Create a wikitable of all subject namespace parameters, for documentation purposes. The talk | |
− | parameter is optional, in case it needs to be excluded in the documentation.
| |
− | ]]
| |
− | local useTalk = type(frame) == 'table' and type(frame.args) == 'table' and frame.args.talk == 'yes' -- Whether to use the talk parameter.
| |
− | local mappings = p.getParamMappings()
| |
− | -- Start the wikitable.
| |
| local ret = '{| class="wikitable"' | | local ret = '{| class="wikitable"' |
| .. '\n|-' | | .. '\n|-' |
− | .. '\n! ' .. cfg.wikitableNamespaceHeader | + | .. '\n! ' .. nsHeader |
− | .. '\n! ' .. cfg.wikitableAliasesHeader | + | .. '\n! ' .. aliasesHeader |
− | | + | for i, params in ipairs(mappingsOrdered) do |
− | -- Generate the row for the main namespace, as we want this to be first in the list.
| + | for j, param in ipairs(params) do |
− | ret = ret .. '\n|-'
| + | if j == 1 then |
− | .. '\n| <code>' .. cfg.main .. '</code>'
| + | ret = ret .. '\n|-' |
− | .. '\n|'
| + | .. '\n| <code>' .. param .. '</code>' |
− | if useTalk then
| + | .. '\n| ' |
− | ret = ret .. '\n|-'
| + | elseif j == 2 then |
− | .. '\n| <code>' .. cfg.talk .. '</code>'
| + | ret = ret .. '<code>' .. param .. '</code>' |
− | .. '\n|' | + | else |
− | end
| + | ret = ret .. ', <code>' .. param .. '</code>' |
− | -- Enclose all parameter names in <code> tags.
| |
− | for ns, params in pairs(mappings) do
| |
− | if ns ~= mw.site.namespaces[0].name then
| |
− | for i, param in ipairs(params) do
| |
− | mappings[ns][i] = '<code>' .. param .. '</code>'
| |
| end | | end |
| end | | end |
| end | | end |
− | -- Generate the other wikitable rows.
| |
− | for ns, params in pairs(mappings) do
| |
− | if ns ~= mw.site.namespaces[0].name then -- Ignore the main namespace.
| |
− | ret = ret .. '\n|-'
| |
− | .. '\n| ' .. params[1]
| |
− | .. '\n| ' .. table.concat(params, ', ', 2)
| |
− | end
| |
− | end
| |
− | -- End the wikitable.
| |
| ret = ret .. '\n|-' | | ret = ret .. '\n|-' |
| .. '\n|}' | | .. '\n|}' |