Module:Wikidata art/sandbox

From Wikimedia Commons, the free media repository
Jump to: navigation, search
--[[  
  __  __           _       _      __        ___ _    _     _       _                     _   
 |  \/  | ___   __| |_   _| | ___ \ \      / (_) | _(_) __| | __ _| |_ __ _    __ _ _ __| |_ 
 | |\/| |/ _ \ / _` | | | | |/ _ (_) \ /\ / /| | |/ / |/ _` |/ _` | __/ _` |  / _` | '__| __|
 | |  | | (_) | (_| | |_| | |  __/_ \ V  V / | |   <| | (_| | (_| | || (_| | | (_| | |  | |_ 
 |_|  |_|\___/ \__,_|\__,_|_|\___(_) \_/\_/  |_|_|\_\_|\__,_|\__,_|\__\__,_|  \__,_|_|   \__|
                                                                                             
This module is intended to provide localized text for different infobox fields.
At the moment we have:
|====================|===========================|=====================|
| Infobox Field      | Property                  | Template            |
|====================|===========================|=====================|
| object history     | commissioned by (P88)     | {{ProvenanceEvent}} |
|                    | owned by (P127)           |                     |
|                    | significant event (P793)  |                     |
| exhibition history | exhibition history (P608) | none                |
| inscriptions       | inscription (P1684)       | {{inscription}}m    |
| medium             | material used (P186)      | {{Technique}}       |
|====================|===========================|=====================|


Please do not modify this code without applying the changes first at 
"Module:Artwork/sandbox" and testing at "Module:Artwork/testcases".

Authors and maintainers:
* User:Jarekt - original version 
]]
local getLabel         = require("Module:Wikidata label")._getLabel                      -- used for creation of name based on wikidata
local qualifierDate    = require("Module:Wikidata date")._qualifierDate        -- used for processing of date qualifiers
local material_LUT     = require('Module:Artwork/Technique LUT')   


-- ==================================================
-- === Internal functions ===========================
-- ==================================================
local function langSwitch(list,lang)
	local langList = mw.language.getFallbacksFor(lang)
	table.insert(langList,1,lang)
	for i,language in ipairs(langList) do
		if list[language] then
			return list[language]
		end
	end
	return nil
end

local function getPropertyQual(entity, prop, qualifiers, lang, offset)
	local Res = {}
	if entity.claims and entity.claims[prop] then
		for k, statement in ipairs( entity:getBestStatements( prop )) do
			if (statement.mainsnak.snaktype == "value") then 
				local res = {} -- table with fields: key, value, P... (qualifiers)
				local jdn = k + (offset or 0) -- "Julian day number" will be used as a key for sorting events; initialize
				local val = statement.mainsnak.datavalue.value
				if val.id then 
					res.value_id = val.id
					val = getLabel(val.id, lang)
				elseif val.text then
					res.value_lang = val.language
					val = val.text
				end
				res.value = val
				for iQual, qual in ipairs( qualifiers ) do
					if statement.qualifiers and statement.qualifiers[qual] then
						local snak = statement.qualifiers[qual][1]
						if (snak.snaktype == "value" and snak.datatype == 'wikibase-item') then 
							val = getLabel(snak.datavalue.value.id, lang)
							res[qual ..'_id'] = snak.datavalue.value.id
						elseif (snak.snaktype == "value" and snak.datatype == 'time') then
							val = qualifierDate(snak, lang)
							if iQual==1 then -- first qualifier in the qualifiers list will be used as a sorting value
								jdn = val.jdn
							end
							val = val.str
						end
						res[qual] = val
					end
				end
				res.key = jdn
				table.insert(Res, res)
			end
		end
	end
	local tableComp = function (rec1, rec2) return rec1.key<rec2.key end
	table.sort(Res, tableComp)
	return Res
end

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

-- ===========================================================================
function p.get_object_history(entity, lang)
	-- Provenance look up table converting items IDs to template inputs
	local ProvenanceLUT = {
		Q22340494  = "acquisition", --acquisition
		Q707482    = "gift", --gift
		Q211557    = "bequest", --bequest
		Q194189    = "sale", --sales
		Q184303    = "gift", --gift
		Q177923    = "auction", --auction
		Q5260774   = "deposit", --deposit
		Q1124860   = "gift", --donation
		Q1362753   = "acquisition", --acquisition
		Q1756454   = "theft", --art theft
		Q17781833  = "destruction", --destruction
		Q217102    = "restored", --conservation
		Q2727213   = "theft", --theft
		Q6498684   = "in collection", --ownership
		Q753297    = "discovery", --discovery
		Q14903979  = "conveyance", --change of ownership
		Q189539    = "loan", --loan
		Q601401    = "exchange", --trade
		Q6160      = "damaged", --vandalism
		Q19880899  = "theft", --Isabella Stewart Gardner Museum theft
		Q1156800   = "restitution", --restitution
		Q1369832   = "purchase", --purchasing
		Q851304    = "theft", --Looted art
		Q3030513   = "missing", --disappearance
		Q21745157  = "destruction", --destroyed artwork
		Q53706     = "theft", --robbery
		Q328376    = "theft", --Nazi plunder
		Q420708    = "acquisition", --Acquisition
		Q760089    = "commission", --commission
		Q200303    = "inheritance", --inheritance
		Q3196      = "burnt", --fire
		Q192623    = "theft", --looting
	}
	local frame = mw.getCurrentFrame()
	local EventList = {}
	-- from   commissioned by (P88) / point in time (P585) (time property)
	local provEvents = getPropertyQual(entity, 'P88', {'P585'}, lang) -- 0 is where the numbering of undated events will start
	for _, event in ipairs( provEvents) do
		if event.P585 then
			event.str = frame:expandTemplate{ title = 'ProvenanceEvent', args = { type='commissioned', time=event.P585, newowner=event.value, lang=lang } } 
			--event.str = '(P88)  ' .. event.str
			table.insert(EventList, event)
		end
	end
	-- from  owned by (P127) / P580 (time property)
	local provEvents = getPropertyQual(entity, 'P127', {'P580'}, lang, 100) -- 100 is where the numbering of undated events will start
	for _, event in ipairs( provEvents) do
		if event.P580 then
			event.str = frame:expandTemplate{ title = 'ProvenanceEvent', args = { type='acquisition', time=event.P580, newowner=event.value, lang=lang } } 
			--event.str = '(P127)  ' .. event.str
			table.insert(EventList, event)
		end
	end
	-- from significant event P793 property with point in time (P585) qualifier
	local provEvents = getPropertyQual(entity, 'P793', {'P585'}, lang, 200) -- 200 is where the numbering of undated events will start
	for _, event in ipairs( provEvents) do
		local eventType = ProvenanceLUT[event.value_id] -- look up event type based on stored item ID
		if event.P585 and eventType then
			event.str = frame:expandTemplate{ title = 'ProvenanceEvent', args = { type=eventType, time=event.P585, lang=lang } } 
			--event.str = '(P793)  ' .. event.str
			table.insert(EventList, event)
		elseif event.P585  then
			event.str = event.P585 .. ": unknown event: "..event.value.."<br/>"
			--event.str = '(P793)  ' .. event.str
			table.insert(EventList, event)
		end
	end
	if #EventList>0 then -- if any events
		local tableComp = function (rec1, rec2) return rec1.key<rec2.key end
		table.sort(EventList, tableComp) -- sort them by the date using sort key
		local X, event = {}, {}
		for _, event in ipairs(EventList) do -- collect just text of the template
			table.insert(X, event.str)
		end
		return '* ' .. table.concat(X,"\n* ")
	end
	return nil
end

-- ===========================================================================
function p.get_exhibition_history(entity, lang)	
--  exhibition history (P608)  (item property) /  'P580', 'P582' (time properties) 
	local prop = getPropertyQual(entity, 'P608', {'P580', 'P582'}, lang)
	local X={}
	for _, p in ipairs(prop) do
		local str = p.value
		if p.P580 then
			str = string.format("%s (%s - %s)", p.value, p.P580, p.P582 or '')
		end
		table.insert(X, str)
	end
	if #X>0 then
		return "\n*" .. table.concat(X,"\n*")
	end
	return nil
end

-- ===========================================================================
function p.get_medium(entity, lang)
	-- material used (P186) (item property) /  applies to part (P518) (item property) 
	local prop = getPropertyQual(entity, 'P186', {'P518'}, lang)
	if not prop then
		return nil -- if no P186 statements than exit
	end
	local temp_args = {} -- technique template arguments
	local And = {'1', 'and', 'and2', 'and3', 'and4'} -- field names to use
	temp_args.lang = lang
	local material = {}
	local n = 0;
	local ok = true;
	for _, p in ipairs( prop) do
		table.insert(material, p.value)
		local mat = material_LUT[p.value_id] -- use lookup table to convert item IDs to terms used by the template
		if not mat then
			ok = false;                      -- unrecognized material
		end
		if p.P518_id=='Q861259' then         -- applies to part: painting surface
			temp_args.on = mat
		elseif n<4 then
			n = n + 1;
			temp_args[And[n]] = mat
		end
	end
	if #material==2 and temp_args["1"]=='oil' and temp_args.on=='canvas' then
		local LUT = require("Module:i18n/oil on canvas")  -- oil on canvas can be done in LUA
		return langSwitch(LUT, lang)
	elseif ok then -- if 
		local frame = mw.getCurrentFrame()
		return frame:expandTemplate{ title = 'technique', args=temp_args }
	else 
		return table.concat(material,", ")
	end
	return nil
end

-- ===========================================================================
function p.get_inscription(entity, lang)
--[[
 Wikidata
	 inscription (P1684) - Monolingual text
	 applies to part (P518) - item property
	 instance of (P31) - item property
 Commons template:
	{{inscription |1= |full form= |type= |side= |position= |description= |comment= |ID= |language= |translation= |en= |de= |medium= }}
]]
	local LUT = {
	  -- positions
		Q15332388    = "bottom",
		Q17525439    = "bottom",
		Q16421635    = "bottom",
		Q23595       = "center",
		Q13196750    = "left",
		Q17525441    = "left",
		Q257418      = "obverse",
		Q82383       = "on base",
		Q11193       = "on base",
		Q860792      = "on frame",
		Q1542661     = "reverse",
		Q32198402    = "reverse",
		Q16938807    = "reverse",
		Q14565199    = "right",
		Q17525442    = "right",
		Q15332375    = "top",
		Q17525438    = "top",
		-- sides
		Q9305022     = "recto",
		Q9368452     = "verso",
		-- type
		Q188675      = "signature",
		Q205892      = "date",
		Q1898184     = "dedication",
		Q168346      = "monogram",
		Q2221906     = "place",
		Q783521      = "title",
		Q206287      = "quotation",
		Q644099      = "stamp",
		Q162919      = "seal",
		-- complex positions
		bottom_left   = "bottom left",
		bottom_right  = "bottom right",
		bottom_center = "bottom center",
		center_left   = "center left",
		center_right  = "center right",
		left_top      = "top left",
		right_top     = "top right",
		center_top    = "top center"
	}
	local frame = mw.getCurrentFrame()
	local X = {}
	for _, statement in ipairs( entity:getBestStatements( 'P1684' )) do
		if (statement.mainsnak.snaktype == "value") then 
			local val = statement.mainsnak.datavalue.value
			local temp_args, position, iType = {}, {}, {}
			temp_args['1']     = val.text -- text
			temp_args.language = val.language -- language of the text
			temp_args.lang     = lang -- language of the reader

			if statement.qualifiers then
				if statement.qualifiers.P31 then
					temp_args.type = LUT[statement.qualifiers.P31[1].datavalue.value.id]
				end				
				if statement.qualifiers.P518 then
					for _, snak in ipairs( statement.qualifiers.P518) do
						local part = LUT[snak.datavalue.value.id]
						if (part=="recto" or part=="verso") then
							temp_args.side = part
						else
							table.insert(position, part)
						end
					end
				end
				if #position==1 then
					temp_args.position = position[1]
				elseif #position==2 then
					table.sort(position)
					temp_args.position = LUT[table.concat(position, '_')]
				end
			end
					
			val = frame:expandTemplate{ title = 'inscription', args=temp_args }
			table.insert(X, val)
		end
	end
	if #X>0 then
		return "\n*" .. table.concat(X,"\n*")
	end
	return nil
end

-- ===========================================================================
function p.debug(frame)
	local field  = frame.args.field
	local lang   = frame.args.lang
	local entity = mw.wikibase.getEntity(frame.args.wikidata)
	if field=='object_history' then
		return p.get_object_history(entity, lang)     -- object history
	elseif field=='exhibition_history' then
		return p.get_exhibition_history(entity, lang) -- exhibition history
	elseif field=='inscription' then
		return p.get_inscription(entity, lang)
	elseif field=='medium' then
		return p.get_medium(entity, lang)
	end
	return ''
end

return p