Module:Lister

Lua
CodeDiscussionLinksLink count SubpagesDocumentationTestsResultsSandboxLive code All modules

Code

local p = {}
local wikidata = require 'Module:Wikidata' 
local lang = mw.getCurrentFrame():preprocess('{{int:lang}}')

-- LISTS 

local listtypes = {
	exhibition = { -- works in a catalogue raisonné, columns = 1: catalogue number, 2: image, 3: artowrkbox
		columns = {
			[1] = function(item, catalogue, exhibition) -- catalogue number
				local val
				if catalogue then -- first try to get the value from the catalogue, most reliable
					val = wikidata.formatStatements({entity=item, property = 'P528', qualifier='P972', qualifiervalue = catalogue, lang=lang})
				end
				if (not val) and exhibition then
					val = wikidata.showQualifier({entity=item, property = 'P608', qualifiers={'P528'}, targetvalue = exhibition, lang=lang}) 
				end
				return val
			end,
			[2] = 'image',
			[3]= function(item) return require 'Module:Artwork'.artworkbox(item) end
		},
		sortkey = 1, -- catalogue as the sortkey
		query = function(item, catalogue) return 'claim[528]{claim[972:' .. catalogue .. ']}' end,
	},
	['catalogue raisonné']= { -- works in a catalogue raisonné, columns = 1: catalogue number, 2: image, 3: artowrkbox
		columns = {
			[1] = function(item, catalogue) -- catalogue number
				return wikidata.formatStatements({entity=item, property = 'P528', qualifier='P972', qualifiervalue = catalogue, lang=lang})
			end,
			[2] = 'image',
			[3]= function(item) return require 'Module:Artwork'.artworkbox(item) end
		},
		sortkey = 1, -- catalogue as the sortkey
		query = function(item, catalogue) return 'claim[528]{claim[972:' .. catalogue .. ']}' end,
	},
	['museum collection']  = { --museum collection etc.
		columns = {
			[1] = 'image',
			[2]= function(item) return require 'Module:Artwork'.artworkbox(item) end,
			[3] = function(item, catalogue, collection) -- accesssion number
				return wikidata.formatStatements({entity=item, property = 'P217',  qualifier='P195', qualifiervalue = collection, lang=lang})
			end,
		},
		sortkey = function(item) 
				-- sort by artist and by date, and sort artists by birth date
				local artist = wikidata.formatStatements{item = item, property = 'P170', numval = 1, displayformat = 'raw'}
				local birthdate = '?'
				if artist then
					birthdate = wikidata.formatStatements{item = artist, property = 'P569', displayformat = 'raw', numval = 1}
				end
				local workdate = wikidata.formatStatements{item = item, property = 'P571', numval=1, displayformat = 'raw'}
				return (birthdate or '?') .. ' ' .. (artist or '?') .. ' ' .. (workdate or '?')
			end,
		query = function(item, collection) return 'claim[195:' .. collection .. ']' end,
	},
	artwork = { -- artwork without any additional parameter
		columns = {
			[1] = 'image',
			[2] = function(item) return require 'Module:Artwork'.artworkbox(item) end,
		},
		sortkey = function(item) 
				-- sort be artist then by date, and artists by birth date
				local artist = wikidata.formatStatements{item = item, property = 'P170', numval = 1, displayformat = 'raw'}
				local birthdate = '?'
				if artist then
					birthdate = wikidata.formatStatements{item = artist, property = 'P569', displayformat = 'raw', numval = 1}
				end
				local workdate = wikidata.formatStatements{item = item, property = 'P571', numval=1, displayformat = 'raw'}
				return (birthdate or '?') .. ' ' .. (artist or '?') .. ' ' .. (workdate or '?')
			end
	},
	default = {
		columns = {
			[1] = 'image',
			[2] = 	function(item) return wikidata.formatEntity(item, {}) end, 
		}
}
		
}

local fb = require 'Module:Fallback'

local i18n = {
	wdqlink = {
		en = 'Update',
		fr = 'Mettre à jour',
	},
	invalidlisttype = {
		en = 'You requested an unknown type of list',
		fr = 'Type de liste inconnu',
	}
}


local function langSwitch(msg)
	return fb._langSwitch(msg, lang)
end


-- Commonly used data
local function makeimage(entity)
	local image = wikidata.formatStatements({entity=entity, property='P18', numval=1, lang=lang})
	return '[[File:' .. (image or 'Missing image text.png') .. '|200px]]'

end

local function before(a, b) -- return true if a is a smaller sortkey than b
	if tonumber(a) and tonumber(b) then -- if both are numeric
		return tonumber(a) < tonumber(b)
	end
	a, b = tostring(a), tostring(b)
	if tonumber(string.sub(a, 1,1)) and tonumber(string.sub(b, 1, 1)) then -- if they are numeric, but with something afterwards like catalogue number 12A
		local newa, newb = '', ''
		local i = 1 	-- only keeps the numeric first part of the value (the numeric one) could be better
		while tonumber(string.sub(a, 1, i)) and i <= string.len(a) do
			newa = string.sub(a, 1, i) 
			i = i + 1
		end
		i = 1
		while tonumber(string.sub(b, 1, i))  and i <= string.len(b)  do
			newb = string.sub(b, 1, i)
			i = i + 1
		end
		return tonumber(newa) < tonumber(newb)
	end
	return a < b -- default: sort alphabetically
end

local function sortrows(rows)
	table.sort(rows, function(a,b) return before(a.sortkey, b.sortkey) end)
	return rows
end

local function getvalue(entity, query, catalogue, topic)
	local querylibrary = { -- maps keyword to the function it represents
		image = makeimage	
	}
	-- if query is a string, look for the function it represents
	if type(query) == 'string' and querylibrary[query] then
		 query = querylibrary[query]
	end
	-- if query is is a function, expand it
	if type(query) == 'function' then
		return query(entity, catalogue, topic)
	end

	return query
end

local function wdqlink(query, topic)
	if not query then
		return ''
	end
	query = getvalue(entity, query, topic)
	query = string.gsub(query, 'Q', '')
	local link = mw.getCurrentFrame():preprocess('https://tools.wmflabs.org/listeria/index.php?action=update&lang=wikidata&page={{FULLPAGENAMEE}}')
	local text = langSwitch(i18n.wdqlink)
	return '[' .. link .. ' ' .. text .. ']'
end


local function splitlist(list)
	if type(list) == 'table' then
		return list
	else
		return mw.text.split(list, ',')
	end
end

local function makerow(item, columns, sortkey, catalogue, topic)
	local entity = mw.wikibase.getEntityObject('Q' .. item)
	-- get cell values
	local vals = {}
	for k, l in pairs(columns) do
		local val = getvalue(entity, l, catalogue, topic) or ''
		table.insert(vals, val)
	end
	
	-- add sortkey
	local key
	if type(sortkey) == 'function' then
		key = sortkey(entity)
	elseif type(sortkey) == 'number' then -- column number sortkey is the key
		key = vals[sortkey]
	end
	if not key then
		key = '?'
	end

	-- make html object
	local content = mw.html.create('tr')
	for i, j in pairs(vals) do
		content:tag('td'):wikitext(j)
	end
	content:done()
	return {sortkey = key, content = content}	
end

function p.makelist(items, columns, sortkey, listtype, query, catalogue, topic, class, style) 
	local rows = {}
	items = splitlist(items)

	-- if listtype, formats according to predefined rules
	if not columns then
		listtype = listtype or 'default'
		local listparams = listtypes[listtype]
		if not listparams then
			return langSwitch(i18n['invalidlisttype'])
		end
		if not query or query == '' then -- should not override a more accuate query parameter (that may be provided to avoid huge list)
			query = listparams.query
		end
		columns, sortkey, class = listparams.columns, listparams.sortkey, listparams.class
	end
	for i, item in pairs(items) do
		local newrow = makerow(item, columns, sortkey, catalogue, topic)
		table.insert(rows, newrow) 
	end
	
	local header =  mw.html.create('tr')
	for i, j in pairs(columns) do
		local text
		local sorttype
		if type(j) == 'table' then
			text = j.header
			sorttype = j.sorttype
		end
		local val = mw.html.create('th')
			:addClass(sorttype)
			:wikitext(text or '&nbsp;')
		header:node(val)
	end
	header:done()
	
	if not class then
		class = 'wikitable sortable'
	end
	if not style then
		style = {width = '100%'}
	end
	local outtable = mw.html.create('table')
		:addClass(class)
		:css(style)
		:node(header)

	rows = sortrows(rows)
	-- add rows
	for i, row in pairs(rows) do
		outtable:node(row.content)
	end
	local link = wdqlink(query, topic)
	return link .. tostring(outtable)
end

function p.listfromFrame(frame)
	local nargs = {}
	for i, j in pairs(frame.args) do
		if j ~= '' then nargs[i] = j end
	end
	return p.makelist(nargs.items, nil, nil, nargs.listtype, nargs.query, nargs.catalogue, nargs.topic) 
end
return p