Module:Cat main: Difference between revisions
Jump to navigation
Jump to search
(Created page with "-- This module implements {{cat main}}. local mHatnote = require('Module:Hatnote') local yesno = require('Module:Yesno') local mTableTools -- lazily initialise local mArgumen...") |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 2: | Line 2: | ||
local mHatnote = require('Module:Hatnote') | local mHatnote = require('Module:Hatnote') | ||
local mFormatLink = require('Module:Format link') | |||
local yesno = require('Module:Yesno') | local yesno = require('Module:Yesno') | ||
local mTableTools -- lazily initialise | local mTableTools -- lazily initialise | ||
| Line 7: | Line 8: | ||
local p = {} | local p = {} | ||
-- Helper: true if the page is in Template: or Module: namespace | |||
local function isTemplateOrModule(title) | |||
local t = (type(title) == 'string' and title) or (title and title.prefixedText) or '' | |||
if t == '' then | |||
return false | |||
end | |||
local ok, tt = pcall(mw.title.new, t) | |||
if not ok or not tt then | |||
return false | |||
end | |||
local ns = tt.namespace | |||
return ns == 10 or ns == 828 | |||
end | |||
function p.catMain(frame) | function p.catMain(frame) | ||
mTableTools = require('Module:TableTools') | mTableTools = require('Module:TableTools') | ||
mArguments = require('Module:Arguments') | mArguments = require('Module:Arguments') | ||
local args = mArguments.getArgs(frame, {wrappers = 'Template: | |||
-- Grab args | |||
local args = mArguments.getArgs(frame, {wrappers = 'Template:Category main article'}) | |||
local pages = mTableTools.compressSparseArray(args) | local pages = mTableTools.compressSparseArray(args) | ||
if #pages == 0 and args[1] then | |||
pages = { args[1] } | |||
end | |||
local options = { | local options = { | ||
article = args.article, | article = args.article, | ||
selfref = args.selfref | selfref = args.selfref, | ||
_rawPages = pages, | |||
} | } | ||
-- Determine the outer page (the page using the template) | |||
local thisTitle = frame and frame.getParent and frame:getParent() and frame:getParent().title or mw.title.getCurrentTitle() | |||
local titleText = thisTitle and thisTitle.prefixedText or '' | |||
local ns = thisTitle and thisTitle.namespace or nil | |||
-- Skip tracking categories on template/module pages | |||
local isTemplate = isTemplateOrModule(titleText) | |||
-- Remember original arg count | |||
local origCount = #pages | |||
-- Generate hatnote text | |||
local text, firstLink, usedAutoFill = p._catMain(options, thisTitle, unpack(pages)) | |||
if isTemplate then | |||
-- On templates/modules, just return the hatnote (no tracking categories) | |||
return text | |||
end | |||
-- Add tracking categories | |||
local cats = {} | |||
-- Wrong namespace detection (Article, Draft) | |||
if ns == 0 or ns == 118 then | |||
table.insert(cats, '[[Category:Articles using category hatnotes]]') | |||
end | |||
-- Title mismatch detection | |||
if firstLink and (origCount == 1 or (origCount == 0 and usedAutoFill)) then | |||
local function normalizeTitle(s) | |||
return (s or ''):gsub('^%s+', ''):gsub('%s+$', ''):gsub('^[^:]*:', ''):gsub('%s+', ' ') | |||
end | |||
local compareStr | |||
if usedAutoFill then | |||
compareStr = normalizeTitle(firstLink) | |||
else | |||
local raw = (options._rawPages and options._rawPages[1]) or firstLink | |||
compareStr = normalizeTitle(raw:gsub("|.*", "")) | |||
end | |||
local catName = normalizeTitle(thisTitle and thisTitle.text or '') | |||
if compareStr ~= catName then | |||
table.insert(cats, '[[Category:Category main article does not match category title]]') | |||
end | |||
end | |||
if #cats > 0 then | |||
text = text .. '\n' .. table.concat(cats, '\n') | |||
end | |||
return text | |||
end | end | ||
function p._catMain(options, ...) | function p._catMain(options, thisTitle, ...) | ||
options = options or {} | options = options or {} | ||
local pages = {...} | |||
thisTitle = thisTitle or mw.title.getCurrentTitle() | |||
local fullTitle = thisTitle and thisTitle.prefixedText or '' | |||
local thisText = thisTitle and thisTitle.text or (pages[1] or '') | |||
-- | local isTemplate = isTemplateOrModule(fullTitle) | ||
local | |||
-- Red link detection | |||
local rawLinks = mFormatLink.formatPages({ | |||
links[ | categorizeMissing = not isTemplate and 'Categories with hatnote templates targeting a non-existent page' or nil | ||
}, pages) | |||
-- Convert to plain strings | |||
local links = {} | |||
for i, link in ipairs(rawLinks or {}) do | |||
links[i] = tostring(link) | |||
end | end | ||
-- Auto-fill if empty | |||
local firstOutputLink = nil | |||
local usedAutoFill = false | |||
if not links[1] or links[1] == '' then | |||
local title = mw.title.new(thisText) | |||
if title and title.isRedirect then | |||
title = title.redirectTarget | |||
end | |||
firstOutputLink = title and title.text or thisText | |||
usedAutoFill = true | |||
links[1] = tostring(mFormatLink._formatLink{ | |||
link = firstOutputLink, | |||
categorizeMissing = not isTemplate and 'Categories with hatnote templates targeting a non-existent page' or nil | |||
}) | |||
pages = { firstOutputLink } | |||
else | |||
local visible = links[1] | |||
visible = visible:gsub("^'''", ""):gsub("'''$", "") | |||
visible = visible:gsub("%[%[", ""):gsub("%]%]", "") | |||
visible = visible:gsub("|.*$", "") | |||
visible = visible:gsub("#.*$", "") | |||
firstOutputLink = visible | |||
usedAutoFill = false | |||
end | |||
-- Bold links | |||
for i, link in ipairs(links) do | for i, link in ipairs(links) do | ||
links[i] = string.format("'''%s'''", link) | links[i] = string.format("'''%s'''", link) | ||
end | end | ||
-- | -- Determine pagetype | ||
local pagetype | local pagetype | ||
if yesno(options.article) ~= false then | if options.article ~= nil then | ||
pagetype = | pagetype = yesno(options.article) ~= false and 'article' or 'page' | ||
elseif pages and pages[1] then | |||
local page = pages[1]:gsub("|.*","") | |||
local tt = mw.title.new(page) | |||
pagetype = tt and tt.namespace == 0 and "article" or "page" | |||
else | else | ||
pagetype = | pagetype = "article" | ||
end | end | ||
-- Work out whether we need to be singular or plural | -- Work out whether we need to be singular or plural | ||
local stringToFormat | local stringToFormat | ||
if #links > 1 then | if #links > 1 then | ||
| Line 49: | Line 164: | ||
end | end | ||
-- | -- Build hatnote text | ||
local text = string.format( | local text = string.format( | ||
stringToFormat, | stringToFormat, | ||
| Line 55: | Line 170: | ||
mw.text.listToText(links) | mw.text.listToText(links) | ||
) | ) | ||
-- Pass through Module:Hatnote | |||
local hnOptions = { selfref = options.selfref } | |||
text = mHatnote._hatnote(text, hnOptions) | |||
return text, firstOutputLink, usedAutoFill | |||
end | end | ||
return p | return p | ||
Latest revision as of 00:26, 29 November 2025
- The following documentation is located at Module:Cat main/doc.[edit]
- Useful links: subpage list • links • transclusions • testcases • sandbox
-- This module implements {{cat main}}.
local mHatnote = require('Module:Hatnote')
local mFormatLink = require('Module:Format link')
local yesno = require('Module:Yesno')
local mTableTools -- lazily initialise
local mArguments -- lazily initialise
local p = {}
-- Helper: true if the page is in Template: or Module: namespace
local function isTemplateOrModule(title)
local t = (type(title) == 'string' and title) or (title and title.prefixedText) or ''
if t == '' then
return false
end
local ok, tt = pcall(mw.title.new, t)
if not ok or not tt then
return false
end
local ns = tt.namespace
return ns == 10 or ns == 828
end
function p.catMain(frame)
mTableTools = require('Module:TableTools')
mArguments = require('Module:Arguments')
-- Grab args
local args = mArguments.getArgs(frame, {wrappers = 'Template:Category main article'})
local pages = mTableTools.compressSparseArray(args)
if #pages == 0 and args[1] then
pages = { args[1] }
end
local options = {
article = args.article,
selfref = args.selfref,
_rawPages = pages,
}
-- Determine the outer page (the page using the template)
local thisTitle = frame and frame.getParent and frame:getParent() and frame:getParent().title or mw.title.getCurrentTitle()
local titleText = thisTitle and thisTitle.prefixedText or ''
local ns = thisTitle and thisTitle.namespace or nil
-- Skip tracking categories on template/module pages
local isTemplate = isTemplateOrModule(titleText)
-- Remember original arg count
local origCount = #pages
-- Generate hatnote text
local text, firstLink, usedAutoFill = p._catMain(options, thisTitle, unpack(pages))
if isTemplate then
-- On templates/modules, just return the hatnote (no tracking categories)
return text
end
-- Add tracking categories
local cats = {}
-- Wrong namespace detection (Article, Draft)
if ns == 0 or ns == 118 then
table.insert(cats, '[[Category:Articles using category hatnotes]]')
end
-- Title mismatch detection
if firstLink and (origCount == 1 or (origCount == 0 and usedAutoFill)) then
local function normalizeTitle(s)
return (s or ''):gsub('^%s+', ''):gsub('%s+$', ''):gsub('^[^:]*:', ''):gsub('%s+', ' ')
end
local compareStr
if usedAutoFill then
compareStr = normalizeTitle(firstLink)
else
local raw = (options._rawPages and options._rawPages[1]) or firstLink
compareStr = normalizeTitle(raw:gsub("|.*", ""))
end
local catName = normalizeTitle(thisTitle and thisTitle.text or '')
if compareStr ~= catName then
table.insert(cats, '[[Category:Category main article does not match category title]]')
end
end
if #cats > 0 then
text = text .. '\n' .. table.concat(cats, '\n')
end
return text
end
function p._catMain(options, thisTitle, ...)
options = options or {}
local pages = {...}
thisTitle = thisTitle or mw.title.getCurrentTitle()
local fullTitle = thisTitle and thisTitle.prefixedText or ''
local thisText = thisTitle and thisTitle.text or (pages[1] or '')
local isTemplate = isTemplateOrModule(fullTitle)
-- Red link detection
local rawLinks = mFormatLink.formatPages({
categorizeMissing = not isTemplate and 'Categories with hatnote templates targeting a non-existent page' or nil
}, pages)
-- Convert to plain strings
local links = {}
for i, link in ipairs(rawLinks or {}) do
links[i] = tostring(link)
end
-- Auto-fill if empty
local firstOutputLink = nil
local usedAutoFill = false
if not links[1] or links[1] == '' then
local title = mw.title.new(thisText)
if title and title.isRedirect then
title = title.redirectTarget
end
firstOutputLink = title and title.text or thisText
usedAutoFill = true
links[1] = tostring(mFormatLink._formatLink{
link = firstOutputLink,
categorizeMissing = not isTemplate and 'Categories with hatnote templates targeting a non-existent page' or nil
})
pages = { firstOutputLink }
else
local visible = links[1]
visible = visible:gsub("^'''", ""):gsub("'''$", "")
visible = visible:gsub("%[%[", ""):gsub("%]%]", "")
visible = visible:gsub("|.*$", "")
visible = visible:gsub("#.*$", "")
firstOutputLink = visible
usedAutoFill = false
end
-- Bold links
for i, link in ipairs(links) do
links[i] = string.format("'''%s'''", link)
end
-- Determine pagetype
local pagetype
if options.article ~= nil then
pagetype = yesno(options.article) ~= false and 'article' or 'page'
elseif pages and pages[1] then
local page = pages[1]:gsub("|.*","")
local tt = mw.title.new(page)
pagetype = tt and tt.namespace == 0 and "article" or "page"
else
pagetype = "article"
end
-- Work out whether we need to be singular or plural
local stringToFormat
if #links > 1 then
stringToFormat = 'The main %ss for this [[Help:Categories|category]] are %s.'
else
stringToFormat = 'The main %s for this [[Help:Categories|category]] is %s.'
end
-- Build hatnote text
local text = string.format(
stringToFormat,
pagetype,
mw.text.listToText(links)
)
-- Pass through Module:Hatnote
local hnOptions = { selfref = options.selfref }
text = mHatnote._hatnote(text, hnOptions)
return text, firstOutputLink, usedAutoFill
end
return p