Модул:category tree

Извор: Викиречник
Иди на навигацију Иди на претрагу

This module is used for generating category boilerplate templates. It is not meant to be used directly. Rather, each template will have its own submodule, which handles the specifics of that template.

This documentation only covers the generics of the category tree system. If you are looking for documentation on a specific template, or on how to add or modify category information, see the documentation of that template.

Параметри[уреди]

Модул стабло категорије се позива као:

{{#invoke:category tree|show|template=name of the template|...other parameters...}}

Сваки шаблон који користи овај модул треба да има подмодул овог модула са именом датим у |template= parameter. (For example, {{poscatboiler}} uses Модул:category tree/poscatboiler.) Овај подмодул треба да извози функцију названу new који узима један параметар: табела именована info који садржи различите параметре који су првобитно прослеђени шаблону. Ова функција треба вратити нову Category објекат који представља те параметре, или nil ако комбинација параметара није важећа (тј. таква категорија не постоји).

Већина предложака прихвата и усваја овај скуп скупова параметара. Параметри прослеђени модулу помоћу шаблона су дефинирани темом појединачно, тако да сваки образац нужно неће користити све ове. {{famcatboiler}} на пример само пролази |code= параметар за модул.

|code=
The code that specifies what 'owns' the category's contents. This is usually a language code such as en, but it can also be a script code like Latn or the code of a language family, depending on how the specific template treats it.
|label=
A name for the thing that is being categorised. The submodule determines how the label is interpreted, so it depends on the template being used. Many templates use it to look up data in a table, while others may interpret it as a language code of some kind.
|sc=
The script code of the items to be categorised. This is usually empty, but many categories such as those used by Mandarin Chinese can split into subcategories based on script.

Опште радње[уреди]

The module is based on the principle of two main kinds of category:

Basic categories are those for which the |code= parameter is not empty. These therefore belong to a specific language (or similar) and are the "regular" categories. Examples are: Категорија:Енглески именице, Категорија:Француски шаблони, Категорија:nl:Лингвистика, Категорија:Енглески појмови изведени из Јапански, Категорија:Латински текст карактери.

Umbrella categories do not have a code, but contain all basic categories of their label, one for each code. These are the "по језику" type categories. Examples are: Категорија:Именице по језику, Категорија:Шаблони по језику, Категорија:Лингвистика, Категорија:Појмови изведени из Јапански језици, Категорија:Карактери по писму.

Some templates also distinguish a third type of category, the fundamental category. This category is used as the parent category for umbrella categories.

Category objects[уреди]

Text-x-generic with pencil.svg This documentation is out of date.
The documentation on this page or section no longer reflects its current state, and some information may be missing or incorrect. Please help by editing the documentation page, and adding information about undocumented features, while removing information that is no longer applicable.

Category objects are returned by each submodule's new function. They represent a single category in the tree. A category object has a variety of methods which may be called on it to ask for information about the category.

getBreadcrumbName[уреди]

getBreadcrumbName()

Returns the name that is used for the category in the "breadcrumbs" at the top of the category page.

getDataModule[уреди]

getDataModule()

Returns the name of the module which contains the data for this category. This is used to create an "edit" link on the category, which allows users to find and edit the information more easily.

canBeEmpty[уреди]

canBeEmpty()

Returns true either if the category contains pages but might be empty or if the category only contains categories, otherwise returns false.

getCategoryName[уреди]

getCategoryName()

Returns the name of the category that this category object represents.

getDescription[уреди]

getDescription()

Returns the description text that is shown at the top of the category page. If the category has no description, this returns nil.

getParents[уреди]

getParents()

Returns a table of the parent categories of this category. Each element in the table is a table itself, with two elements:

.name
One of two possibilities: An category object representing the parent category, or a string that directly specifies the name of the parent category.
.sort
The sorting key that should be used when categorizing the current category in the parent.

If the category has no parents, this returns nil.

If there are two or more parent categories, the first will be used to generate the breadcrumbs that are displayed at the top of the category page. For example, Категорија:Енглески језик is in numerous categories (Сви језици, Западно германски језици, Латински текст језици, Braille script languages, and so on), but the first category, Сви језици, is the one displayed in the breadcrumbs: Почетак » Сви језици » Енглески језик.

getChildren[уреди]

getChildren()

Returns a table of the child categories of this category. Each element in the table is a category object representing the child category. If the category has no children, this returns nil.

getUmbrella[уреди]

getUmbrella()

Returns a category object for the current category's corresponding umbrella category. If the current category is already an umbrella category, this returns nil. It also returns nil if the category has no umbrella category.

getAppendix[уреди]

getAppendix()

Returns an appendix link (such as Додатак:Француски глаголи) if the page exists, else returns nil.


local export = {}

local m_utilities = require('Модул:utilities')
local inFundamental = mw.loadData("Модул:category tree/data")

local show_error, check_name, link_box, show_catfix, show_categories,
	show_editlink, show_pagelist, show_breadcrumbs, show_description,
	show_appendix, show_children, show_TOC


local function capitalize(text)
	return mw.getContentLanguage():ucfirst(text)
end

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
	local template = frame.args["template"]
	
	if not template or template == "" then
		error("The \"template\" parameter was not specified.")
	end
	
	if mw.title.getCurrentTitle().nsText == "Шаблон" then
		local text = {}
		table.insert(text, "This template should be used on pages in the Категорија: namespace, ")
		table.insert(text, "and automatically generates descriptions and categorization for categories of a recognized type (see below).")
		table.insert(text, " It is implemented by [[Модул:category tree]] and its submodule [[Модул:category tree/")
		table.insert(text, template .. "]].")
		if frame.args["useautocat"] then
			table.insert(text, " It is preferable not to invoke this template directly, but to simply use ")
			table.insert(text, require("Модул:template link").format_link({"auto cat"}))
			table.insert(text, " (with no parameters), which will automatically invoke this template on appropriately-named category pages.")
		end
		return table.concat(text)
	elseif mw.title.getCurrentTitle().nsText ~= "Категорија" then
		error("This template/module can only be used on pages in the Категорија: namespace.")
	end
	
	local submodule = require("Модул:category tree/" .. template)
	
	-- Get all the parameters and the label data
	local current
	
	if submodule.new_main then
		current = submodule.new_main(frame)
	else
		local info = {}
		
		for key, val in pairs(frame.args) do
			if val ~= "" and key ~= "useautocat" then
				info[key] = val
			end
		end
	
		info.template = nil
		current = submodule.new(info, true)
	end
	
	local functions = {
		"getBreadcrumbName",
		"getDataModule",
		"canBeEmpty",
		"getDescription",
		"getParents",
		"getChildren",
		"getUmbrella",
		"getAppendix",
	}
	
	if current then
		for i, functionName in pairs(functions) do
			if type(current[functionName]) ~= "function" then
				require("Модул:debug").track{ "category tree/missing function", "category tree/missing function/" .. functionName }
			end
		end
	end

	local boxes = {}
	local display = {}
	local categories = {}

	if template == "topic cat" then
		table.insert(categories, "[[Категорија:каталог тема]]")
	end
	
	-- Check if the category is empty
	local isEmpty = mw.site.stats.pagesInCategory(mw.title.getCurrentTitle().text, "all") == 0
	
	-- Are the parameters valid?
	if not current then
		table.insert(categories, "[[Категорија:Категорија са неважећом ознаком]]")
		table.insert(categories, isEmpty and "[[Категорија:Празне категорије]]" or nil)
		table.insert(display, show_error(
			"The label given to the " ..
			require("Модул:template link").format_link{template} ..
			" template is not valid. You may have mistyped it, or it simply has not been created yet. " ..
			"To add a new label, please consult the documentation of the template."))
		
		-- Exit here, as all code beyond here relies on current not being nil
		return table.concat(categories, "") .. table.concat(display, "\n\n")
	end
	
	-- Does the category have the correct name?
	if mw.title.getCurrentTitle().text ~= current:getCategoryName() then
		table.insert(categories, "[[Категорија:Категорије са погрешним именом]]")
		table.insert(display, show_error(
			"Based on the parameters given to the " ..
			require("Модул:template link").format_link{template} ..
			" template, this category should be called '''[[:Категорија:" .. current:getCategoryName() .. "]]'''."))
	end
	
	-- Add cleanup category for empty categories
	if isEmpty and not current:canBeEmpty() then
		table.insert(categories, "[[Категорија:Празне категорије]]")
	end
	
	if current:isHidden() then
		table.insert(categories, "__HIDDENCAT__")
	end

if canBeEmpty then
		table.insert(categories, " __EXPECTUNUSEDCATEGORY__")
	end	
	table.insert(boxes, show_editlink(current))
	table.insert(boxes, show_related_changes())
	table.insert(boxes, show_pagelist(current))
	
	-- Generate the displayed information
	table.insert(display, show_breadcrumbs(current))
	table.insert(display, show_description(current))
	table.insert(display, show_appendix(current))
	table.insert(display, show_children(current))
	table.insert(display, show_TOC(current))
	table.insert(display, show_catfix(current))
	
	show_categories(current, categories)
	
	return table.concat(boxes, "\n") .. "\n" .. table.concat(display, "\n\n") .. table.concat(categories, "")
end

function show_error(text)
	return  mw.getCurrentFrame():expandTemplate{title = "maintenance box", args = {
		"red",
		image = "[[File:Ambox warning pn.svg|50px]]",
		title = "The automatically-generated contents of this category has errors.",
		text = text,
		}}
end

-- Check the name of the current page, and return an error if it's not right.
function check_name(current, template, info)
	local errortext = nil
	local category = nil
	
	if not current then
		errortext =
			"The label \"" .. (info.label or "") .. "\" given to the " ..
			require("Модул:template link").format_link{template} .. " template is not valid. " ..
			"You may have mistyped it, or it simply has not been created yet. To add a new label, please consult the documentation of the template."
		category = "[[Категорија:Категорија са неважећом ознаком]]"
	else
		
	end
	
	if errortext then
		return (category or "") .. show_error(errortext)
	else
		return nil
	end
end

function show_catfix(current)
	if current._lang and not (current._info and current._info.no_catfix) then
		return m_utilities.catfix(current._lang,
			(current._info and current._info.sc
				and require("Модул:scripts").getByCode(current._info.sc) or nil))
	else
		return nil
	end
end

-- Show the parent categories that the current category should be placed in.
function show_categories(current, categories)
	local parents = current:getParents()
	
	if not parents then
		return
	end
	
	for _, parent in ipairs(parents) do
		if type(parent.name) == "string" then
			if not (current._lang and current:getCategoryName() == capitalize(current._lang:getCategoryName())) and not (current._sc and current:getCategoryName():find(capitalize(current._sc:getCategoryName()), nil, true)) and current:getInfo().code then
				require("Модул:debug").track("category tree/string")
			end
			
			table.insert(categories, "[[" .. parent.name .. "|" .. parent.sort .. "]]")
		else
			table.insert(categories, "[[Категорија:" .. parent.name:getCategoryName() .. "|" .. parent.sort .. "]]")
		end
	end
	
	-- Also put the category in its corresponding "umbrella" or "by language" category.
	local umbrella = current:getUmbrella()
	
	if umbrella then
		local sort
		if current._lang then
			sort = current._lang:getCanonicalName()
		else
			sort = current:getCategoryName()
		end
		
		if type(umbrella) == "string" then
			table.insert(categories, "[[" .. umbrella .. "|" .. sort .. "]]")
		else
			table.insert(categories, "[[Категорија:" .. umbrella:getCategoryName() .. "|" .. sort .. "]]")
		end
	end
end

function link_box(content)
	return "<div class=\"noprint plainlinks\" style=\"float: right; clear: both; margin: 0 0 .5em 1em; background: #f9f9f9; border: 1px #aaaaaa solid; margin-top: -1px; padding: 5px; font-weight: bold;\">"
		.. content .. "</div>"
end

function show_related_changes()
	local title = mw.title.getCurrentTitle().fullText
	return link_box(
		"["
		.. tostring(mw.uri.fullUrl("Special:RecentChangesLinked", {
			target = title,
			showlinkedto = 0,
		}))
		.. ' <span title="Недавне измене и друге промене на страницама у ' .. title .. '">Скорашње промене</span>]')
end

function show_editlink(current)
	return link_box(
		"[" .. tostring(mw.uri.fullUrl(current:getDataModule(), "action=edit"))
		.. " Унос категорије]")
end

function show_pagelist(current)
	local namespace = ""
	local info = current:getInfo()
	
	if info.label == "цитати" or info.label == "цитати од недефинисаних термина" then
		namespace = "Цитати"
	elseif info.code then
		local lang = require("Модул:languages").getByCode(info.code)
		
		if lang then
			if lang:getType() == "reconstructed" then
				namespace = "Реконструкција"
			elseif lang:getType() == "appendix-constructed" then
				namespace = "Додатак"
			end
		end
	end
	
	local recent = mw.getCurrentFrame():callParserFunction{
		name = "#tag",
		args = {
			"DynamicPageList",
			"category=" .. mw.title.getCurrentTitle().text .. "\n" ..
			"namespace=" .. namespace .. "\n" ..
			"count=10\n" ..
			"mode=ordered\n" ..
			"ordermethod=categoryadd\n" ..
			"order=descending"
		}
	}
	
	local oldest = mw.getCurrentFrame():callParserFunction{
		name = "#tag",
		args = {
			"DynamicPageList",
			"category=" .. mw.title.getCurrentTitle().text .. "\n" ..
			"namespace=" .. namespace .. "\n" ..
			"count=10\n" ..
			"mode=ordered\n" ..
			"ordermethod=lastedit\n" ..
			"order=ascending"
		}
	}
	
	return [=[
{| id="newest-and-oldest-pages" class="wikitable" style="float: right; clear: both; margin: 0 0 .5em 1em;"
! Недавна допуна категорије
|-
| id="recent-additions" style="font-size:0.9em;" | ]=] .. recent .. [=[

|-
! Најстарије странице по задњој измени
|-
| id="oldest-pages" style="font-size:0.9em;" | ]=] .. oldest .. [=[

|}]=]
end

-- Show navigational "breadcrumbs" at the top of the page.
function show_breadcrumbs(current)
	local steps = {}
	
	-- Start at the current label and move our way up the "chain" from child to parent, until we can't go further.
	while current do
		local category = nil
		local display_name = nil
		
		if type(current) == "string" then
			category = current
			display_name = current:gsub("^Категорија:", "")
		else
			category = "Категорија:" .. current:getCategoryName()
			display_name = current:getBreadcrumbName()
		end
		
		display_name = capitalize(display_name)
		table.insert(steps, 1, "[[:" .. category .. "|" .. display_name .. "]]")
		
		-- Move up the "chain" by one level.
		if type(current) == "string" then
			current = nil
		else
			current = current:getParents()
		end
		
		if current then
			current = current[1].name
		elseif inFundamental[category] then
			current = "Категорија:Почетак"
		end	
	end
	
	steps = table.concat(steps, " » ")
	
	return "<small>" .. steps .. "</small>"
end

-- Show a short description text for the category.
function show_description(current)
	return (current:getDescription() or "")
end

function show_appendix(current)
	local appendix
	
	if current.getAppendix then
		appendix = current:getAppendix()
	end
	
	if appendix then
		return "За више информација, видите [[" .. appendix .. "]]."
	else
		return nil
	end
end

-- Show a list of child categories.
function show_children(current)
	local children = current:getChildren()
	
	if not children then
		return nil
	end
	
	table.sort(children, function(first, second) return first.sort < second.sort end)
	
	local children_list = {}
	
	for _, child in ipairs(children) do
		local child_basic = child.name:getCategoryName()
		local child_page = mw.title.new("Категорија:" .. child_basic)
		
		if child_page.exists then
			local child_description = child.name:getDescription("child")
			table.insert(children_list, "* [[:Категорија:" .. child_basic .. "]]: " .. child_description)
		end
	end
	
	return table.concat(children_list, "\n")
end

-- Show a table of contents with links to each letter in the language's script.
function show_TOC(current)
	local code = current:getInfo().code
	
	if code and not require("Модул:languages").getByCode(code) then
		return nil
	end
	
	if not code then
		code = "en"
	end
	
	-- If category can be empty, then it only contains subcategories.
	local hasPages = not current:canBeEmpty()
	
	local titleText = mw.title.getCurrentTitle().text
	
	local inCategory

	if hasPages then
		inCategory = mw.site.stats.pagesInCategory(titleText, "pages")
	else
		inCategory = mw.site.stats.pagesInCategory(titleText, "subcats")
	end
	
	-- No need for a TOC if all pages or subcategories can fit on one page.
	if inCategory > 200 then
		
		-- This category is very large, see if there is an "extended" version of the TOC.
		if inCategory > 2500 then
			local TOC_template_extended = mw.title.new("Шаблон:" .. code .. "-categoryTOC/full")
			
			if TOC_template_extended.exists then
				return mw.getCurrentFrame():expandTemplate{title = TOC_template_extended.text, args = {}}
			end
		end
		
		local TOC_template = mw.title.new("Шаблон:" .. code .. "-categoryTOC")
		
		if TOC_template.exists then
			return mw.getCurrentFrame():expandTemplate{title = TOC_template.text, args = {}}
		end
	end
	
	return nil
end

function export.test(frame)
	local template = frame.args[1]
	local submodule = require("Модул:category tree/" .. template)
	
	if submodule.new_main then
		current = submodule.new_main(frame)
	else
		local info = {}
		
		for key, val in pairs(frame.args) do
			info[key] = val; if info[key] == "" then info[key] = nil end
		end
	
		info.template = nil
		current = submodule.new(info, true)
	end
end

return export