Module:TagQS

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Lua

CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules

Introduction

This module has functions for creation, reading and operating on invisible tags which can be used to pass language independent data between templates. The initial goal of those tags was for templates often called from infoboxes like {{Artwork}}, {{Book}}, {{Photograph}} to pass invisible language independent data to those infoboxes in addition to localized text. So for example, if we have file showing an artwork that has an item on Wikidata and that file has some metadata, like author or dimensions, which are missing on Wikidata, then with the help of those tags {{Artwork}} template an create an icon , which when clicked would allow the transfer of this metadata from Commons to Wikidata. See Category:Artworks with Wikidata item: quick statements for files where such transfer is possible.

Structure

Each tag has 3 parts:

  1. field - a broad category of tags. For example {{Size}} template adds tags using dimensions field, {{Institution}} template adds tags using institution field, etc.
  2. property - part one of property/value pair: id of a Wikidata property.
  3. value - part two of property/value pair: value of a property, as described in d:Help:QuickStatements

Templates and modules using TagQS

Template Module Tag's Field Tag's Properties Comment
{{Size}} Module:Size dimensions height (P2048), width (P2049), +8 more create tag
{{Title}} Module:Title title title (P1476) create tag
{{Title}} Module:Title label labels create tag
{{Creator}} Module:Creator creator creator (P170) create tag
{{Institution}} Module:Institution institution collection (P195) create tag
{{Complex date}} Module:Complex_date date not set create tag
{{Artwork}} (date or publication date field) Module:Artwork/core date not set create tags for simple dates like the ones in YYYY-MM-DD or YYYY formats
{{Technique}} Module:Technique medium made from material (P186), fabrication method (P2079) create tag without TagQS
{{Oil on canvas}} medium made from material (P186) create tag using {{CreateTag}}
{{Oil on panel}} medium made from material (P186) create tag using {{CreateTag}}
{{Wood carving}} medium made from material (P186) create tag using {{CreateTag}}

Code

--[[  
   _____             .___    .__              ___________              ________    _________
  /     \   ____   __| _/_ __|  |   ____   /\ \__    ___/____     ____ \_____  \  /   _____/
 /  \ /  \ /  _ \ / __ |  |  \  | _/ __ \  \/   |    |  \__  \   / ___\ /  / \  \ \_____  \ 
/    Y    (  <_> ) /_/ |  |  /  |_\  ___/  /\   |    |   / __ \_/ /_/  >   \_/.  \/        \
\____|__  /\____/\____ |____/|____/\___  > \/   |____|  (____  /\___  /\_____\ \_/_______  /
        \/            \/               \/                    \//_____/        \__>       \/ 

                                                                             
This module is intended for creating invisible tags which can be used to pass 
language independent data from some templates to infoboxes. Those tags are often 
used by templates like [Template:Artwork]  to pass data to Wikidata

Authors and maintainers:
* User:Jarekt - original version 
]]

require('strict') -- used for debugging purposes as it detects cases of unintended global variables

-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}

function p.replaceUnlessQuoted(str, oldChar, newChar)
	-- String "str" has some sections that are in quotes and some that are not. 
	-- Do replacements only in the text sections which are not in "" quotes.
	local quote = string.byte('"')
	local comma = string.byte(oldChar)
	local quoted = false
	for pos = 1, #str do
	   if str:byte(pos) == quote then
		  quoted = not quoted
	   end
	   if str:byte(pos) == comma and not quoted then
		  str = str:sub(1,pos-1) .. newChar .. str:sub(pos+1, str:len())
	   end
	end
	return str
end

-- ===========================================================================
-- === Version of the function to be called from other LUA codes
-- ===========================================================================
function p.createTag(field, property, value)
	-- create tags to insert using "field" "property" and "value" strings.
	-- "field" is an unique label to distinguish it from other tags. 
	-- "property" and "value" are actually in a format similar to the one expected by QuickStatements
	return mw.ustring.format('<div style="display: none;">%s QS:%s,%s</div>', field, property or 'P', value)
end

function p.changeField(text, old, new)
	-- replace "field" part of the tag. It is needed as sometimes template adding those tags does not 
	-- know the meaning, which is known the the outside template. For example in 
	-- "{{Book|translator={{Creator|wikidata=Q12345}}" the Creator template will create initial 
	-- tag with the wikidata item and {{Book}} template will add label and property for "transaltor".
	local patrn = '%<div style="display: none;"%>'.. old ..' QS:([^%<]+)%</div%>'
	local repl  =  '<div style="display: none;">'.. new ..' QS:%1</div>'
	return mw.ustring.gsub(text, patrn, repl)
end

function p.changeProperty(text, field, old, new)
	-- replace "property" part of the tag. It is needed as sometimes template adding those tags does not 
	-- know the meaning, which is known the the outside template. For example in 
	-- "{{Book|translator={{Creator|wikidata=Q12345}}" the Creator template will create initial 
	-- tag with the wikidata item and {{Book}} template will add label and property for "transaltor".
	if not old then -- string "old" is optional if nil than any property will be replaced
		old = '[^%,]+'
	end
	local patrn = '%<div style="display: none;"%>' .. field .. ' QS:' .. old .. ',([^%<]+)%</div%>'
	local repl  =   '<div style="display: none;">' .. field .. ' QS:' .. new .. ',%1</div>'
	return mw.ustring.gsub(text, patrn, repl)
end

function p.append2value(text, field, text2append)
	-- append "text" to the "value" part of the tag
	local patrn = '%<div style="display: none;"%>'.. field ..' QS:([^%<]+)%</div%>'
	local repl  =  '<div style="display: none;">' .. field ..' QS:%1,' .. text2append .. '</div>'
	return mw.ustring.gsub(text, patrn, repl)
end

function p.readTag(text, field)
	-- read a single tag
	local pat = '%<div style="display: none;"%>'..field..' QS:([^%<]+)%</div%>'
	local qs  = string.match(text, pat) -- find hidden tag with QS code
	local _, nMatch = string.gsub(text, pat, "") -- count matches
	if qs and nMatch==1 then -- allow only single matches
		return p.replaceUnlessQuoted(qs, ',', '|')
	end
end

function p.readTags(text, field)
	-- read multiple tags and return array of them
	local pat = '%<div style="display: none;"%>'..field..' QS:([^%<]+)%</div%>'
	local ret = {}
	for qs in mw.ustring.gmatch(text, pat) do
		table.insert(ret, p.replaceUnlessQuoted(qs, ',', '|') )
	end
	return ret
end

function p.hasTag(text, field)
	-- does the "text" has a tag with field "field", or if field=nil does it have any tags?
	return text~= p.removeTag(text, field)
end

function p.removeTag(text, field)
	-- remove tags with field "field" from the string. Field =nil will replace all tags
	if not field then
		field = '[^ ]+'
	end
	local patrn = '%<div style="display: none;"%>' .. field .. ' QS:[^%<]+%</div%>'
	return mw.ustring.gsub(text, patrn, '')
end

-- ===========================================================================
-- === Versions of the function to be called from template namespace
-- ===========================================================================
function p.CreateTag(frame)
	return p.createTag(frame.args[1], frame.args[2], frame.args[3])
end

return p