小 (已保护“Module:Catnav”:机器用户批量保护高风险模板([编辑=仅允许模板编辑员](无限期)[移动=仅允许模板编辑员](无限期))) |
小 (导入1个版本:导入自求闻百科的页面[页面文字原许可:CC BY-SA 4.0]) |
(没有差异)
|
2023年5月1日 (一) 02:52的最新版本
local yesno = require 'Module:Yesno'
local getArgs = require 'Module:Arguments'.getArgs
local tools = require 'Module:TableTools'
-- 根分类的名称。若为 nil,则即使 noroot 不为 false,也不会补充根分类。
local rootCatName = '总览'
-- 在自动补充分类树模式下,每一条分类树的最大项数(超出数量则不再往前面补充分类名称,而是添加省略号)。
local max_catList_size = 8
-- 在自动补充分类树模式下,最多多少个分类树(超出数量会停止产生分类树,并报出警告)。
local max_catLists_size = 20
-- 用于避免一个分类树的一个部分产生过多的分支,数字越大允许的数量也越多。当分支数量过多时,即使还没有到达上述两个限制,分类树最左侧也会使用“(x个分类)”的表述代替
local branch_detection_level = 12
local p = {}
-- 可用作分类命名空间名称的集合。
local categoryNamespaces = tools.listToSet(mw.site.namespaces.category.aliases)
categoryNamespaces.Category = true
p.categoryNamespaces = categoryNamespaces
function p._main(args)
local auto = yesno(args.auto) -- boolean
if auto then
--[[
注意:一般args[1]参数为该分类的上一级分类(自己手动设置),如果有多个,
则多次调用此模板。当然你也可以留空,使其直接获取*当前*页面的分类,但
需要注意的是,在分类页面预览页面时,捕获到的*当前*页面的分类时编辑
之前的,这种情况只有提交后才能看到更改,所以不建议这么做。
]]
return p._auto(args)
end
if rootCatName and not yesno(args.noroot) then -- noroot=1时,不自动补充根分类。
if args[1] ~= rootCatName then
table.insert(args, 1, rootCatName)
end
end
-- args:
-- rootCatName; aaa; bbb; ccc
local currentTitle = mw.title.getCurrentTitle()
local currentIsCategory = currentTitle.namespace == 14
if currentIsCategory and not yesno(args.nohere) then -- nohere=1时,不自动补充本页链接
if currentTitle.text ~= args[#args] then
args[#args+1] = currentTitle.text
end
end
-- args:
-- rootCatName; aaa; bbb; ccc; 页面名
local cat = nil
if (not auto) and currentIsCategory and not yesno(args.nocat) then
cat = args[#args]
if cat == currentTitle.text then
cat = args[#args-1]
end
end
local list = {} -- 承载链接字符串的表
for k, v in ipairs(args) do
if v == '' then
v = nil
elseif type(v) == 'table' then
v = v.custom
elseif v == '...' or v == '…' or v == '……' then
else
v = "[[:Category:" .. v .. "|" .. v .. "]]"
end
list[#list+1] = v
end
return tostring(mw.html.create("div")
:addClass("catnav")
:wikitext(table.concat(list," > "))
:wikitext(cat and '[[Category:' .. cat .. ']]' or ''))
end
function p.main(frame)
return p._main(tools.shallowClone(getArgs(frame)))
end
local unpack = unpack or table.unpack
--[[
根据页面名称判断其子分类,如果没有子分类了则说明当前的catList完成了,将其
加入catLists,否则继续递归,直到不再有子分类,或者已经超限了。
@string name 当前页面的名称。
@list <string> catList 当前的分类树。它有可能直接被修改,也有可能被复制。
@list <list <string>> catLists 当前的分类树的列表。检测到catList完成之后,就
会将其加入catLists。任何时候在执行此函数之前,catLists都是不包含catList的。
最终通过递归,catLists自身可能会被添加元素。
]]
local function appendCategoryTrees(catList, catLists)
local name = catList[1]
local categories = p.getCategories(name)
if #categories == 0 then
-- 说明当前页面没有分类了,是相对的根分类,将保存的catList追加至catLists。
catLists[#catLists + 1] = catList
return
elseif #catLists >= max_catLists_size then
mw.addWarning '[[Module:Catnav]]检测到一个分类具有过多的分类树,可能是因为存在分类循环。'
catLists.exceeded = true
return
elseif #catList >= max_catList_size then
table.insert(catList, 1, '...')
catLists[#catLists + 1] = catList
return
else
local index = -1
for i, catName in ipairs(catList) do
if i > 1 and catName == name then
local category = catList[i + 1]
local msg = {}
for j = i, 1, -1 do
msg[#msg + 1] = '[[:Category:' .. catList[j] .. '|' .. catList[j] .. ']]'
end
mw.addWarning ('[[Module:Catnav]]检测到分类循环:'
.. table.concat(msg, ' → ')
)
table.insert(catList, 1, '...')
catLists[#catLists + 1] = catList
return
end
end
end
if #categories == 1 then
-- 当前分类只有一个上级分类,故直接修改catList,然后进行下一轮。
local category = categories[1]
table.insert(catList, 1, category)
appendCategoryTrees(catList, catLists)
else
if 2*#categories + #catList >= branch_detection_level then
-- 说明该分类的上级分类过多,不再逐个展示。
table.insert(catList, 1, {custom = '...(' .. #categories .. '个分类)'})
catLists[#catLists + 1] = catList
return
else
for i, category in ipairs(categories) do
local clonedCatList = {unpack(catList)}
table.insert(clonedCatList, 1, category)
appendCategoryTrees(clonedCatList, catLists)
end
end
end
end
p.appendCategoryTrees = appendCategoryTrees
function p.getCategoryTrees(initialCatList)
local catLists = {}
appendCategoryTrees(initialCatList, catLists)
return catLists
end
function p._auto(args)
if not args[1] then
args[1] = mw.title.getCurrentTitle().text
end
local catLists = p.getCategoryTrees(args)
local result = {} -- list of string
for i, catList in ipairs(catLists) do
catList.noroot = true
catList.nocat = true
catList.nohere = yesno(args.nohere)
catList.auto = false
if #catList < 2 then return end
result[#result + 1] = p._main(catList)
end
if catLists.exceeded then
result[#result + 1] = '<div>(仅列举出部分可能的分类关系)</div>'
end
return table.concat(result, '\n')
end
--[=[
获取指定分类页面(或任意页面)所属的分类。将根据源代码进行判断。
这意味着只有在分类页面中直接使用 [[Category:xxx]] 这样的链接才会被识别。
通过模板等方式间接添加的分类不会被识别。
@string name 页面名。
@return list of string
]=]
function p.getCategories(name)
local title = mw.title.new(name, 'category')
local content = title:getContent()
if not content then return {} end
return p.findCategoriesFromContent(content)
end
--[=[
根据内容进行正则解析,从而判断其拥有的分类。
不会尝试将其展开。
@string content
@return list of string
]=]
function p.findCategoriesFromContent(content)
local result = {}
for namespace, text in content:gmatch '%[%[%s*([^:%|%[%]]+)%s*:%s*([^%[%]]+)%s*]]' do
if categoryNamespaces[namespace] then
text = text:match '(.-)%|' or text
result[#result + 1] = text
end
end
return result
end
return p