Module:Tag: Difference between revisions

From OpenStreetMap Wiki
Jump to navigation Jump to search
(Avoid interpreting a key component as a deprecated key; deprecated keys are less likely to be real key components)
(Only check deprecation of keys that have data items; see Special:Diff/2442689)
Line 153: Line 153:
if (description or not mw.ustring.find(key, ":")) and
if (description or not mw.ustring.find(key, ":")) and
-- Avoid deprecated keys, which are less likely to be key components.
-- Avoid deprecated keys, which are less likely to be key components.
#mw.wikibase.getBestStatements(entityId, "P17") == 0 then
(not entityId or #mw.wikibase.getBestStatements(entityId, "P17") == 0) then
table.insert(resolvedComponents, component)
table.insert(resolvedComponents, component)
mostSpecificTitle = title
mostSpecificTitle = title

Revision as of 01:12, 27 November 2022

[Edit] [Purge] Documentation

Usage

Utilities related to OSM tags.

A number of testcases verify the correctness of these functions. Run the unit tests.

value

Returns a human-readable reference to a tag value.

Parameters:

|key = or |1 =
The name of a key.
|value =
A tag value, which will be linked or unlinked depending on the value of |link =.
|link =
Determines the link target of the link that this template outputs:
|link = key
Links to the key's description page.
|link = key#
Links to a named anchor on the key's description page in the form key-value.
|link = value
Links to the value's description page.
|link = none
No link.
|2 =
A tag value to be linked to a value description page. Use this parameter or the combination of |link = value and |value = for any value of an enumeration-typed key.
|3 =
A tag value to be linked to the key's description page. Use this parameter or the combination of |link = key# and |value = for any value of an enumeration-typed key that is specifically documented on the key's description page.
|4 =
An unlinked tag value. Use this parameter and leave |2 = and |3 = blank, or combine |link = key with |value =, for any value of a key that is not specifically documented anywhere. Alternatively, this parameter and leave |2 = and |3 = blank, or combine |link = none with |value =, for any value of a key that holds freeform text, a URL, or more complex syntax.
|lang = or |kl =
The language code of the link target. If the language is unspecified, the key component is linked to the page in the same language as the page that transcludes this template, falling back to English.

tag

Returns a human-readable reference to a key or key-value pair using key=value syntax.

Parameters:

|1 =
The name of a key.
|subkey = (|subkey1 =), |subkey2 =, |subkey3 =, etc.
The name of each successive subkeys. A subkey is separated by a semicolon and links to the key description page of the base key.
|: =, |:: =, |::: =, etc.
The name of each successive key components. A key component is separated by a semicolon and links to a key description page specifically about the key component.
|kl =, |kl: =, |kl:: =, etc.
The language code of the page to link each successive key component. |kl = determines the link for |1 =, |kl: = for |: =, and so on. If the language is unspecified, the key component is linked to the page in the same language as the page that transcludes this template, falling back to English.
|2 =, |; = (|subval =), |;; = (|subval2 =), etc.
Tag values separated by semicolons. Each value is linked to a value description page. Use these parameters for any value of an enumeration-typed key.
|vl =, |vl2 =, |vl3 =, etc.
The language code of the page to link each successive value. |vl = determines the link for |2 =, |vl2 = for |; = or |subval =, |vl3 = for |;; = or |subval2 =, and so on. If the language is unspecified, the value is linked to the page in the same language as the page that transcludes this template, falling back to English.
|3 =
A tag value. The value is unlinked. Use this parameter and leave |2 = blank for any value of a key that holds freeform text, a URL, or more complex syntax, or for explanatory placeholder text. A value of *:wikipedia=*, *:wikidata=*, *:wikimedia_commons=*, *:url=*, or *:website=* is linked to the referenced URL.

keyComponentList

Returns an unordered list of key components that form the given key. Each key component is annotated with its description from the associated data item, if available.

Parameters:

|1 =
The key to split into components.
|intro =
Introductory text to insert before the list.

See also

local p = {}
local languages = require("Module:Languages")
local currentTitle = mw.title.getCurrentTitle()
local defaultLangCode = languages.languageFromTitle(currentTitle)

function pageLink(pageName, label, langCode)
	if langCode then
		if #langCode > 0 then
			pageName = languages.translationPageName(langCode, mw.title.new(pageName))
		end
	elseif defaultLangCode ~= "en" and pageName ~= currentTitle.fullText then
		local translatedPageName = languages.translationPageName(defaultLangCode, mw.title.new(pageName))
		if mw.title.new(translatedPageName).exists then
			pageName = translatedPageName
		end
	end
	return "[[" .. pageName .. "|" .. label .. "]]"
end

function valueLink(key, value, langCode)
	local pageName = "Tag:" .. key .. "=" .. value
	return pageLink(pageName, tostring(mw.html.create("bdi"):wikitext(value)), langCode)
end

function p.tag(frame)
	-- Get arguments from the calling frame, falling back to its calling frame
	local args = frame.args[1] and frame.args or frame:getParent().args
	
	local components = {}
	local keyComponents = {}
	
	-- Key
	local key = args[1]
	table.insert(keyComponents, key)
	
	-- Give |subkey= precedence over |subkey1=.
	if args.subkey then
		table.insert(keyComponents, args.subkey)
	end
	
	-- Collect subkeys.
	local subkeyIndex = 2
	while args["subkey" .. subkeyIndex] do
		local subkey = args["subkey" .. subkeyIndex]
		table.insert(keyComponents, subkey)
		subkeyIndex = subkeyIndex + 1
	end
	
	-- Combine |subkey*= with |key=.
	-- TODO: Keep this from affecting links.
	keyComponents = {
		table.concat(keyComponents, mw.text.nowiki(":")),
	}
	
	-- Collect subkeys to be linked separately.
	local subkeyIndex = 1
	while args[string.rep(":", subkeyIndex)] do
		local subkey = args[string.rep(":", subkeyIndex)]
		table.insert(keyComponents, subkey)
		subkeyIndex = subkeyIndex + 1
	end
	
	-- Link the key and any subkeys.
	local linkedKeyComponents = {}
	for i, key in ipairs(keyComponents) do
		local langCode = args["kl" .. string.rep(":", i - 1)]
		table.insert(linkedKeyComponents, pageLink("Key:" .. key, key, langCode))
	end
	table.insert(components, table.concat(linkedKeyComponents, ":"))
	
	components = {
		tostring(mw.html.create("bdi")
			:css("white-space", "nowrap")
			:wikitext(table.concat(components)))
	}
	table.insert(components, "=")
	
	-- Values
	local lastKeyComponent = keyComponents[#keyComponents]
	if args[2] and #args[2] > 0 then
		local values = {}
		if args[2] then
			table.insert(values, args[2])
		end
		if args[";"] or args.subval then
			table.insert(values, args[";"] or args.subval)
		end
		local subvalueIndex = 2
		while args[string.rep(";", subvalueIndex)] or args["subval" .. subvalueIndex] do
			local otherValue = args[string.rep(";", subvalueIndex)] or args["subval" .. subvalueIndex]
			if #otherValue > 0 then
				table.insert(values, otherValue)
			end
			subvalueIndex = subvalueIndex + 1
		end
		local linkedValues = {}
		for i, value in ipairs(values) do
			local langCode = args[i > 1 and ("vl" .. i) or "vl"]
			table.insert(linkedValues, valueLink(lastKeyComponent, value, langCode))
		end
		table.insert(components, table.concat(linkedValues, ";"))
	elseif args[3] and #args[3] > 0 then
		local value = args[3]
		local pageName
		if lastKeyComponent == "wikipedia" then
			pageName = "w:" .. value
		elseif lastKeyComponent == "wikidata" then
			pageName = "d:" .. value
		elseif lastKeyComponent == "commons" then
			pageName = "Commons:" .. value
		end
		
		if lastKeyComponent == "url" or lastKeyComponent == "website" then
			local label = mw.html.create("bdi")
				:css("white-space", "normal")
				:wikitext(mw.text.nowiki(value))
			table.insert(components, "[" .. value .. " " .. tostring(label) .. "]")
		elseif pageName then
			local label = mw.html.create("bdi"):wikitext(args[3])
			table.insert(components, pageLink(pageName, tostring(label), ""))
		else
			local label = mw.html.create("bdi"):wikitext(args[3])
			table.insert(components, tostring(label))
		end
	else
		table.insert(components, "*")
	end
	
	return table.concat(components)
end

function p.keyComponents(key)
	if #key == 0 then
		return {}
	end
	
	local rawComponents = mw.text.split(key, ":", true)
	local resolvedComponents = {}
	local mostSpecificTitle
	local mostSpecificEntityId
	local mostSpecificDescription
	for i, component in ipairs(rawComponents) do
		local base = table.concat(resolvedComponents, ":")
		if #base > 0 then
			base = base .. ":"
		end
		local key = mw.ustring.format("%s%s", base, component)
		local pageName = mw.ustring.format("Key:%s", key)
		local title = mw.title.new(pageName)
		local entityId = mw.wikibase.getEntityIdForTitle(pageName)
		if entityId or title.exists then
			local description = mw.wikibase.getDescription(entityId)
			if (description or not mw.ustring.find(key, ":")) and
					-- Avoid deprecated keys, which are less likely to be key components.
					(not entityId or #mw.wikibase.getBestStatements(entityId, "P17") == 0) then
				table.insert(resolvedComponents, component)
				mostSpecificTitle = title
				mostSpecificEntityId = entityId
				mostSpecificDescription = description
			else
				break
			end
		else
			break
		end
	end
	
	if #resolvedComponents == 0 then
		local component = rawComponents[1]
		if mw.language.isKnownLanguageTag(component) then
			table.insert(resolvedComponents, component)
			mostSpecificDescription = mw.ustring.format("[[w:ISO 639:%s|%s]]",
				component,
				mw.language.fetchLanguageName(component, defaultLangCode))
		end
	end
	
	local subkey = table.concat(rawComponents, ":", #resolvedComponents + 1)
	if #resolvedComponents == 0 then
		local component = {
			name = subkey,
		}
		return { component }
	end
	
	local superkey = {
		name = table.concat(resolvedComponents, ":"),
		title = mostSpecificTitle,
		entityId = mostSpecificEntityId,
		description = mostSpecificDescription,
	}
	resolvedComponents = p.keyComponents(subkey)
	table.insert(resolvedComponents, 1, superkey)
	return resolvedComponents
end

function p.keyComponentList(frame)
	-- Get arguments from the calling frame, falling back to its calling frame
	local args = frame.args[1] and frame.args or frame:getParent().args
	
	local key = args[1]
	local components = p.keyComponents(key)
	if #components < 2 then
		return ""
	end
	
	local listItems = {}
	for i, component in ipairs(components) do
		local tag
		if i == 1 then
			tag = frame:expandTemplate {
				title = "Tag",
				args = { component["name"] },
			}
		elseif component["title"] or component["entityId"] then
			tag = frame:expandTemplate {
				title = "Tag",
				args = {
					"*",
					[":"] = component["name"]
				},
			}
		else
			tag = frame:expandTemplate {
				title = "Value",
				args = {
					mw.ustring.format("&#x2a;&#x3a;%s=*", component["name"]),
				},
			}
		end
		local description = component.description
		local edit = component.entityId and frame:expandTemplate {
			title = "Edit",
			args = {
				"Item:" .. component.entityId,
			},
		} or ""
		if description then
			table.insert(listItems, mw.ustring.format("* %s: %s %s", tag, description, edit))
		else
			table.insert(listItems, mw.ustring.format("* %s %s", tag, edit))
		end
	end
	
	if args.intro and #args.intro > 0 then
		table.insert(listItems, 1, args.intro)
	end
	
	return table.concat(listItems, "\n")
end

return p