Module:Pagetype: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
m (fix for files and interface messages which do exist but are not stored locally) |
m (1 revision imported) |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
||
-- -- |
-- -- |
||
+ | -- PAGETYPE -- |
||
− | -- This meta-module which automatically detects namespaces, and allows -- |
||
+ | -- -- |
||
− | -- for a great deal of customisation. It can easily be ported to other -- |
||
+ | -- This is a meta-module intended to replace {{pagetype}} and similar -- |
||
+ | -- templates. It automatically detects namespaces, and allows for a -- |
||
+ | -- great deal of customisation. It can easily be ported to other -- |
||
-- wikis by changing the values in the [[Module:Pagetype/config]]. -- |
-- wikis by changing the values in the [[Module:Pagetype/config]]. -- |
||
-- -- |
-- -- |
||
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
||
+ | |||
-- Load config. |
-- Load config. |
||
local cfg = mw.loadData('Module:Pagetype/config') |
local cfg = mw.loadData('Module:Pagetype/config') |
||
-- Load required modules. |
-- Load required modules. |
||
+ | local getArgs = require('Module:Arguments').getArgs |
||
local yesno = require('Module:Yesno') |
local yesno = require('Module:Yesno') |
||
+ | local nsDetectModule = require('Module:Namespace detect') |
||
+ | local nsDetect = nsDetectModule._main |
||
+ | local getParamMappings = nsDetectModule.getParamMappings |
||
+ | local getPageObject = nsDetectModule.getPageObject |
||
+ | |||
local p = {} |
local p = {} |
||
+ | local function shallowCopy(t) |
||
− | -- Look up a namespace argument in the args table. |
||
+ | -- Makes a shallow copy of a table. |
||
− | local function lookUpNamespaceArg(args, key) |
||
− | local |
+ | local ret = {} |
+ | for k, v in pairs(t) do |
||
− | -- Convert "yes", "1" etc. to true, "no", "0" etc. to false, and leave |
||
+ | ret[k] = v |
||
− | -- other values the same. |
||
− | return yesno(arg, arg) |
||
− | end |
||
− | |||
− | -- Append multiple values to an array |
||
− | local function appendMultiple(target, source) |
||
− | for _, value in ipairs(source) do |
||
− | table.insert(target, value) |
||
end |
end |
||
+ | return ret |
||
end |
end |
||
+ | local function checkPagetypeInput(namespace, val) |
||
− | -- Get argument keys for a title's namespace |
||
+ | -- Checks to see whether we need the default value for the given namespace, |
||
− | local function getNamespaceArgKeys(title) |
||
+ | -- and if so gets it from the pagetypes table. |
||
− | local nsInfo = mw.site.namespaces[title.namespace] |
||
+ | -- The yesno function returns true/false for "yes", "no", etc., and returns |
||
− | local customAliases = cfg.customNamespaceAliases[title.namespace] or {} |
||
+ | -- val for other input. |
||
− | local keys = {} |
||
+ | local ret = yesno(val, val) |
||
− | if nsInfo.name ~= '' then |
||
+ | if ret and type(ret) ~= 'string' then |
||
− | table.insert(keys, nsInfo.name) |
||
+ | ret = cfg.pagetypes[namespace] |
||
end |
end |
||
+ | return ret |
||
− | if nsInfo.canonicalName ~= nsInfo.name and nsInfo.canonicalName ~= '' then |
||
− | table.insert(keys, nsInfo.canonicalName) |
||
− | end |
||
− | appendMultiple(keys, nsInfo.aliases) |
||
− | appendMultiple(keys, customAliases) |
||
− | return keys |
||
end |
end |
||
+ | local function getPagetypeFromClass(class, param, aliasTable, default) |
||
− | -- Get the argument for a title's namespace, if it was specified in the args table. |
||
+ | -- Gets the pagetype from a class specified from the first positional |
||
− | local function getNamespaceArg(title, args) |
||
+ | -- parameter. |
||
− | if title.isTalkPage then |
||
+ | param = yesno(param, param) |
||
− | return lookUpNamespaceArg(args, cfg.talk) |
||
+ | if param ~= false then -- No check if specifically disallowed. |
||
− | end |
||
− | + | for _, alias in ipairs(aliasTable) do |
|
+ | if class == alias then |
||
− | local arg = lookUpNamespaceArg(args, mw.ustring.lower(key)) |
||
− | if |
+ | if type(param) == 'string' then |
− | return |
+ | return param |
+ | else |
||
+ | return default |
||
+ | end |
||
+ | end |
||
end |
end |
||
end |
end |
||
− | return nil |
||
end |
end |
||
+ | local function getNsDetectValue(args) |
||
− | -- Look up a page type specific to the title's namespace |
||
+ | -- Builds the arguments to pass to [[Module:Namespace detect]] and returns |
||
− | local function getExplicitPageType(title) |
||
+ | -- the result. |
||
− | if title.isTalkPage then |
||
− | return cfg.talkDefault |
||
− | else |
||
− | return cfg.pagetypes[title.namespace] |
||
− | end |
||
− | end |
||
− | -- Get |
+ | -- Get the default values. |
+ | local ndArgs = {} |
||
− | local function getDefaultPageType(args) |
||
− | local |
+ | local defaultns = args[cfg.defaultns] |
− | if |
+ | if defaultns == cfg.defaultnsAll then |
+ | ndArgs = shallowCopy(cfg.pagetypes) |
||
− | return other |
||
else |
else |
||
+ | local defaultnsArray |
||
− | return cfg.otherDefault |
||
+ | if defaultns == cfg.defaultnsExtended then |
||
+ | defaultnsArray = cfg.extendedNamespaces |
||
+ | elseif defaultns == cfg.defaultnsNone then |
||
+ | defaultnsArray = {} |
||
+ | else |
||
+ | defaultnsArray = cfg.defaultNamespaces |
||
+ | end |
||
+ | for _, namespace in ipairs(defaultnsArray) do |
||
+ | ndArgs[namespace] = cfg.pagetypes[namespace] |
||
+ | end |
||
end |
end |
||
− | end |
||
+ | --[[ |
||
− | local function detectRedirects(title, args) |
||
+ | -- Add custom values passed in from the arguments. These overwrite the |
||
− | local redirect = lookUpNamespaceArg(args, cfg.redirect) |
||
+ | -- defaults. The possible argument names are fetched from |
||
− | if redirect == false then |
||
+ | -- Module:Namespace detect automatically in case new namespaces are |
||
− | -- Don't detect redirects if they have been specifically disallowed. |
||
+ | -- added. Although we accept namespace aliases as parameters, we only pass |
||
− | return nil |
||
+ | -- the local namespace name as a parameter to Module:Namespace detect. |
||
− | end |
||
+ | -- This means that the "image" parameter can overwrite defaults for the |
||
− | |||
+ | -- File: namespace, which wouldn't work if we passed the parameters through |
||
− | -- Allow custom values for redirects. |
||
+ | -- separately. |
||
− | if not title.isRedirect then |
||
+ | --]] |
||
− | return nil |
||
+ | local mappings = getParamMappings() |
||
− | elseif type(redirect) == 'string' then |
||
+ | for ns, paramAliases in pairs(mappings) do |
||
− | return redirect |
||
+ | -- Copy the aliases table, as # doesn't work with tables returned from |
||
− | else |
||
+ | -- mw.loadData. |
||
− | return cfg.redirectDefault |
||
+ | paramAliases = shallowCopy(paramAliases) |
||
− | end |
||
+ | local paramName = paramAliases[1] |
||
− | end |
||
+ | -- Iterate backwards along the array so that any values for the local |
||
− | |||
+ | -- namespace names overwrite those for namespace aliases. |
||
− | local function capitalize(pageType) |
||
− | + | for i = #paramAliases, 1, -1 do |
|
+ | local paramAlias = paramAliases[i] |
||
− | local rest = mw.ustring.sub(pageType, 2) |
||
+ | local ndArg = checkPagetypeInput(paramAlias, args[paramAlias]) |
||
− | return mw.ustring.upper(first) .. rest |
||
+ | if ndArg == false then |
||
− | end |
||
+ | -- If any arguments are false, convert them to nil to protect |
||
− | |||
+ | -- against breakage by future changes to |
||
− | local function pluralize(pageType) |
||
+ | -- [[Module:Namespace detect]]. |
||
− | if cfg.irregularPlurals[pageType] then |
||
+ | ndArgs[paramName] = nil |
||
− | return cfg.irregularPlurals[pageType] |
||
+ | elseif ndArg then |
||
− | else |
||
+ | ndArgs[paramName] = ndArg |
||
− | return pageType .. cfg.plural -- often 's' |
||
− | end |
||
− | end |
||
− | |||
− | local function parseContent(title, args, optionsList) |
||
− | if title.namespace==828 and title.subpageText~='doc' -- don't detect modules |
||
− | or not title.exists -- can't check unless page exists |
||
− | then |
||
− | return nil |
||
− | end |
||
− | local content = title:getContent() |
||
− | if content == nil then |
||
− | return nil |
||
− | end |
||
− | local templates -- lazily evaluated |
||
− | for _, options in next, optionsList do |
||
− | local list, parameter, default, articleOnly = unpack(options, 1, 4) |
||
− | if not articleOnly or title.namespace==0 then -- only check for templates if we should... |
||
− | local out = lookUpNamespaceArg(args, parameter) |
||
− | if type(out) == "string" or (out ~= false and default) then -- ...and if we actually have anything to say about them |
||
− | if not templates then |
||
− | templates = {} -- do our delayed evaluation now that we are required to |
||
− | content = require('Module:Wikitext Parsing').PrepareText(content) -- disregard templates which do not have any affect |
||
− | for template in string.gmatch(content, "{{%s*([^|}]-)%s*[|}]") do |
||
− | templates[#templates+1] = capitalize(template) |
||
− | end |
||
− | end |
||
− | local wantedTemplates = mw.loadData('Module:Pagetype/' .. list) |
||
− | local templateFound = false |
||
− | for _, template in next, templates do |
||
− | if wantedTemplates[template] then |
||
− | templateFound = true |
||
− | break |
||
− | end |
||
− | end |
||
− | if templateFound then |
||
− | if type(out)=='string' then |
||
− | return out |
||
− | elseif out ~= false and default then |
||
− | return default |
||
− | end |
||
− | end |
||
end |
end |
||
end |
end |
||
end |
end |
||
+ | -- Check for disambiguation-class and N/A-class pages in mainspace. |
||
− | end |
||
+ | if ndArgs.main then |
||
− | |||
+ | local class = args[1] |
||
− | -- Find pages which do not exist |
||
+ | if type(class) == 'string' then |
||
− | local function nonExistent(title, args) |
||
+ | -- Put in lower case so e.g. "Dab" and "dab" will both match. |
||
− | local arg = lookUpNamespaceArg(args, cfg.ne) |
||
+ | class = mw.ustring.lower(class) |
||
− | if arg == false then |
||
+ | end |
||
− | return nil |
||
+ | local dab = getPagetypeFromClass( |
||
− | end |
||
+ | class, |
||
− | local exists = false |
||
+ | args[cfg.dab], |
||
− | if title.exists then -- not an article if it does not exist |
||
+ | cfg.dabAliases, |
||
− | exists = true |
||
+ | cfg.dabDefault |
||
− | elseif title.namespace==8 and mw.message.new(title.text):exists() then |
||
+ | ) |
||
− | exists = true |
||
+ | if dab then |
||
− | elseif title.namespace==6 and title.fileExists then |
||
− | + | ndArgs.main = dab |
|
− | end |
||
− | if not exists then |
||
− | if type(arg) == 'string' then |
||
− | return arg |
||
else |
else |
||
+ | local na = getPagetypeFromClass( |
||
− | return cfg.naDefault |
||
+ | class, |
||
+ | args[cfg.na], |
||
+ | cfg.naAliases, |
||
+ | cfg.naDefault |
||
+ | ) |
||
+ | if na then |
||
+ | ndArgs.main = na |
||
+ | end |
||
end |
end |
||
end |
end |
||
+ | -- If there is no talk value specified, use the corresponding subject |
||
− | end |
||
+ | -- namespace for talk pages. |
||
− | |||
+ | if not ndArgs.talk then |
||
− | -- Get page types for mainspaces pages with an explicit class specified |
||
+ | ndArgs.subjectns = true |
||
− | local function getMainNamespaceClassPageType(title, args) |
||
− | local class = args[1] |
||
− | if type(class) == 'string' then -- Put in lower case so e.g. "na" and "NA" will both match |
||
− | class = mw.ustring.lower(class) |
||
end |
end |
||
+ | -- Add the fallback value. This can also be customised, but it cannot be |
||
− | local arg = lookUpNamespaceArg(args, cfg.na) |
||
+ | -- disabled. |
||
− | if arg == false then -- don't check for this class if it is specifically disallowed |
||
+ | local other = args[cfg.other] |
||
− | return nil |
||
+ | -- We will ignore true/false/nil results from yesno here, but using it |
||
− | end |
||
+ | -- anyway for consistency. |
||
− | if cfg.naAliases[class] then |
||
+ | other = yesno(other, other) |
||
− | if type(arg) == 'string' then |
||
+ | if type(other) == 'string' then |
||
− | return arg |
||
+ | ndArgs.other = other |
||
− | else |
||
− | return cfg.naDefault |
||
− | end |
||
else |
else |
||
+ | ndArgs.other = cfg.otherDefault |
||
− | return nil |
||
end |
end |
||
+ | -- Allow custom page values. |
||
+ | ndArgs.page = args.page |
||
+ | return nsDetect(ndArgs) |
||
end |
end |
||
+ | local function detectRedirects(args) |
||
− | -- Get page type specified by an explicit namespace argument. |
||
+ | local redirect = args[cfg.redirect] |
||
− | local function getNamespaceArgPageType(title, args) |
||
+ | -- The yesno function returns true/false for "yes", "no", etc., and returns |
||
− | local namespaceArg = getNamespaceArg(title, args) |
||
+ | -- redirect for other input. |
||
− | if namespaceArg == true then |
||
+ | redirect = yesno(redirect, redirect) |
||
− | -- Namespace has been explicitly enabled, so return the default for |
||
+ | if redirect == false then |
||
− | -- this namespace |
||
+ | -- Detect redirects unless they have been explicitly disallowed with |
||
− | return getExplicitPageType(title) |
||
+ | -- "redirect=no" or similar. |
||
− | elseif namespaceArg == false then |
||
+ | return |
||
− | -- Namespace has been explicitly disabled |
||
− | return getDefaultPageType(args) |
||
− | elseif namespaceArg then |
||
− | -- This namespaces uses custom text |
||
− | return namespaceArg |
||
− | else |
||
− | return nil |
||
end |
end |
||
+ | local pageObject = getPageObject(args.page) |
||
− | end |
||
+ | -- If we are using subject namespaces elsewhere, do so here as well. |
||
− | |||
+ | if pageObject |
||
− | |||
+ | and not yesno(args.talk, true) |
||
− | -- Get page type not specified or detected by other means |
||
+ | and args[cfg.defaultns] ~= cfg.defaultnsAll |
||
− | local function getOtherPageType(title, args) |
||
+ | then |
||
− | -- Whether the title is in the set of default active namespaces which are looked up in cfg.pagetypes. |
||
+ | pageObject = getPageObject( |
||
− | local isInDefaultActiveNamespace = false |
||
+ | pageObject.subjectNsText .. ':' .. pageObject.text |
||
− | local defaultNamespacesKey = args[cfg.defaultns] |
||
+ | ) |
||
− | if defaultNamespacesKey == cfg.defaultnsAll then |
||
+ | end |
||
− | isInDefaultActiveNamespace = true |
||
+ | -- Allow custom values for redirects. |
||
− | else |
||
+ | if pageObject and pageObject.isRedirect then |
||
− | local defaultNamespaces |
||
− | if |
+ | if type(redirect) == 'string' then |
+ | return redirect |
||
− | defaultNamespaces = cfg.extendedNamespaces |
||
− | elseif defaultNamespacesKey == cfg.defaultnsNone then |
||
− | defaultNamespaces = {} |
||
else |
else |
||
+ | return cfg.redirectDefault |
||
− | defaultNamespaces = cfg.defaultNamespaces |
||
end |
end |
||
− | isInDefaultActiveNamespace = defaultNamespaces[title.namespace] |
||
− | end |
||
− | if isInDefaultActiveNamespace then |
||
− | return getExplicitPageType(title) |
||
− | else |
||
− | return getDefaultPageType(args) |
||
end |
end |
||
end |
end |
||
function p._main(args) |
function p._main(args) |
||
+ | local redirect = detectRedirects(args) |
||
− | local title |
||
+ | local pagetype = "" |
||
− | if args.page then |
||
+ | if redirect then |
||
− | title = mw.title.new(args.page) |
||
+ | pagetype = redirect |
||
else |
else |
||
+ | pagetype = getNsDetectValue(args) |
||
− | title = mw.title.getCurrentTitle() |
||
end |
end |
||
− | if title and not yesno(args.talk, true) and args[cfg.defaultns] ~= cfg.defaultnsAll then |
||
− | title = title.subjectPageTitle |
||
− | end |
||
− | local pageType = detectRedirects(title, args) |
||
− | or nonExistent(title, args) |
||
− | or parseContent(title, args, { |
||
− | {'softredirect', cfg.softRedirect, cfg.softRedirectDefault}, |
||
− | {'setindex', cfg.sia, cfg.siaDefault, true}, |
||
− | {'disambiguation', cfg.dab, cfg.dabDefault, true}, |
||
− | {'rfd', cfg.rfd, cfg.rfdDefault}, |
||
− | }) |
||
− | or (title.namespace == 0 and getMainNamespaceClassPageType(title, args)) |
||
− | or getNamespaceArgPageType(title, args) |
||
− | or getOtherPageType(title, args) |
||
if yesno(args.plural, false) then |
if yesno(args.plural, false) then |
||
+ | if cfg.irregularPlurals[pagetype] then |
||
− | pageType = pluralize(pageType) |
||
+ | pagetype = cfg.irregularPlurals[pagetype] |
||
+ | else |
||
+ | pagetype = pagetype .. cfg.plural -- often 's' |
||
+ | end |
||
end |
end |
||
if yesno(args.caps, false) then |
if yesno(args.caps, false) then |
||
+ | pagetype = mw.ustring.upper(mw.ustring.sub(pagetype, 1, 1)) .. |
||
− | pageType = capitalize(pageType) |
||
+ | mw.ustring.sub(pagetype, 2) |
||
end |
end |
||
− | return |
+ | return pagetype |
end |
end |
||
function p.main(frame) |
function p.main(frame) |
||
− | local args = |
+ | local args = getArgs(frame) |
return p._main(args) |
return p._main(args) |
||
end |
end |
Latest revision as of 01:35, 12 November 2024
Documentation for this module may be created at Module:Pagetype/doc
-------------------------------------------------------------------------------- -- -- -- PAGETYPE -- -- -- -- This is a meta-module intended to replace {{pagetype}} and similar -- -- templates. It automatically detects namespaces, and allows for a -- -- great deal of customisation. It can easily be ported to other -- -- wikis by changing the values in the [[Module:Pagetype/config]]. -- -- -- -------------------------------------------------------------------------------- -- Load config. local cfg = mw.loadData('Module:Pagetype/config') -- Load required modules. local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local nsDetectModule = require('Module:Namespace detect') local nsDetect = nsDetectModule._main local getParamMappings = nsDetectModule.getParamMappings local getPageObject = nsDetectModule.getPageObject local p = {} local function shallowCopy(t) -- Makes a shallow copy of a table. local ret = {} for k, v in pairs(t) do ret[k] = v end return ret end local function checkPagetypeInput(namespace, val) -- Checks to see whether we need the default value for the given namespace, -- and if so gets it from the pagetypes table. -- The yesno function returns true/false for "yes", "no", etc., and returns -- val for other input. local ret = yesno(val, val) if ret and type(ret) ~= 'string' then ret = cfg.pagetypes[namespace] end return ret end local function getPagetypeFromClass(class, param, aliasTable, default) -- Gets the pagetype from a class specified from the first positional -- parameter. param = yesno(param, param) if param ~= false then -- No check if specifically disallowed. for _, alias in ipairs(aliasTable) do if class == alias then if type(param) == 'string' then return param else return default end end end end end local function getNsDetectValue(args) -- Builds the arguments to pass to [[Module:Namespace detect]] and returns -- the result. -- Get the default values. local ndArgs = {} local defaultns = args[cfg.defaultns] if defaultns == cfg.defaultnsAll then ndArgs = shallowCopy(cfg.pagetypes) else local defaultnsArray if defaultns == cfg.defaultnsExtended then defaultnsArray = cfg.extendedNamespaces elseif defaultns == cfg.defaultnsNone then defaultnsArray = {} else defaultnsArray = cfg.defaultNamespaces end for _, namespace in ipairs(defaultnsArray) do ndArgs[namespace] = cfg.pagetypes[namespace] end end --[[ -- Add custom values passed in from the arguments. These overwrite the -- defaults. The possible argument names are fetched from -- Module:Namespace detect automatically in case new namespaces are -- added. Although we accept namespace aliases as parameters, we only pass -- the local namespace name as a parameter to Module:Namespace detect. -- This means that the "image" parameter can overwrite defaults for the -- File: namespace, which wouldn't work if we passed the parameters through -- separately. --]] local mappings = getParamMappings() for ns, paramAliases in pairs(mappings) do -- Copy the aliases table, as # doesn't work with tables returned from -- mw.loadData. paramAliases = shallowCopy(paramAliases) local paramName = paramAliases[1] -- Iterate backwards along the array so that any values for the local -- namespace names overwrite those for namespace aliases. for i = #paramAliases, 1, -1 do local paramAlias = paramAliases[i] local ndArg = checkPagetypeInput(paramAlias, args[paramAlias]) if ndArg == false then -- If any arguments are false, convert them to nil to protect -- against breakage by future changes to -- [[Module:Namespace detect]]. ndArgs[paramName] = nil elseif ndArg then ndArgs[paramName] = ndArg end end end -- Check for disambiguation-class and N/A-class pages in mainspace. if ndArgs.main then local class = args[1] if type(class) == 'string' then -- Put in lower case so e.g. "Dab" and "dab" will both match. class = mw.ustring.lower(class) end local dab = getPagetypeFromClass( class, args[cfg.dab], cfg.dabAliases, cfg.dabDefault ) if dab then ndArgs.main = dab else local na = getPagetypeFromClass( class, args[cfg.na], cfg.naAliases, cfg.naDefault ) if na then ndArgs.main = na end end end -- If there is no talk value specified, use the corresponding subject -- namespace for talk pages. if not ndArgs.talk then ndArgs.subjectns = true end -- Add the fallback value. This can also be customised, but it cannot be -- disabled. local other = args[cfg.other] -- We will ignore true/false/nil results from yesno here, but using it -- anyway for consistency. other = yesno(other, other) if type(other) == 'string' then ndArgs.other = other else ndArgs.other = cfg.otherDefault end -- Allow custom page values. ndArgs.page = args.page return nsDetect(ndArgs) end local function detectRedirects(args) local redirect = args[cfg.redirect] -- The yesno function returns true/false for "yes", "no", etc., and returns -- redirect for other input. redirect = yesno(redirect, redirect) if redirect == false then -- Detect redirects unless they have been explicitly disallowed with -- "redirect=no" or similar. return end local pageObject = getPageObject(args.page) -- If we are using subject namespaces elsewhere, do so here as well. if pageObject and not yesno(args.talk, true) and args[cfg.defaultns] ~= cfg.defaultnsAll then pageObject = getPageObject( pageObject.subjectNsText .. ':' .. pageObject.text ) end -- Allow custom values for redirects. if pageObject and pageObject.isRedirect then if type(redirect) == 'string' then return redirect else return cfg.redirectDefault end end end function p._main(args) local redirect = detectRedirects(args) local pagetype = "" if redirect then pagetype = redirect else pagetype = getNsDetectValue(args) end if yesno(args.plural, false) then if cfg.irregularPlurals[pagetype] then pagetype = cfg.irregularPlurals[pagetype] else pagetype = pagetype .. cfg.plural -- often 's' end end if yesno(args.caps, false) then pagetype = mw.ustring.upper(mw.ustring.sub(pagetype, 1, 1)) .. mw.ustring.sub(pagetype, 2) end return pagetype end function p.main(frame) local args = getArgs(frame) return p._main(args) end return p