Spring til indhold

Modul:Sandkasse/Poul G/Dataliste

Fra Wikipedia, den frie encyklopædi

-- test Bruger:Poul G/Infobox


local i18n = require('Module:Sandkasse/Poul G/I18n').new()
    .append("Module:Sandkasse/Poul G/Dataliste")
    .append{
		["error-item-not-found"] = "item not found",
		["errors"] = {
			["item-not-found"] = "Ukendt emne (item).",
			["no-frame"] = "Ingen system-ramme (frame) angivet.",
		},
		["somevalue"] = "''unknown value''",
		["novalue"] = "''no value''",
		["wikidata-differs"] = "different value in Wikidata",
		["localdata-differs"] = "different local value",
	}

local config = {
	paramWithDefault = {
		link = true,
		rank = true,
		},
	imageProperties = {
		p18 = true, P18 = true, -- image
		p94 = true, P94 = true, -- coat of arms image
		p154 = true, P154 = true, -- logo image
		-- TODO https://www.wikidata.org/wiki/Wikidata:Requests_for_comment/Image_properties:_many_properties_or_many_qualifiers
		},
	}

--[[
local content = {
	["p31=q5"] = { -- is a person
		"p18", -- image
		"p106", -- profession
		"p569", -- date of birth
		"p570", -- date of death
		},
}
]]

local wikidata = require('Module:Wikidata/sandkasse') -- TODO


-- returns a sorted table with the suffixes found in templateArgs
-- example: getIndexes({"a5"=1,"b4"=2,"c16"=3,"c2"=4},{"a","c"}) --> {2,5,16}
local function getIndexes(templateArgs,prefixes)
	-- extract removing duplicates
	local keys = {}
	for param, v in pairs(templateArgs) do
		for __, prefix in pairs(prefixes) do
			local num = tostring(param):match('^' .. prefix .. '([1-9]%d*)$')
			if num then keys[tonumber(num)] = true end
		end
	end
	if not #keys then return nil end
	-- move to values and sort
	local nums = {}
	for key, _ in pairs(keys) do
		table.insert(nums,key)
	end
	table.sort(nums)
	return nums
end


-- pushes headers, lines and tailing to listener in top-down-left-right order
-- returns nil on success, otherwise error-info
local function datalistGenerator(frame, listener)
	local templateArg = ( frame and frame.args ) or {}
	local pageArg = ( frame and frame:getParent() and frame:getParent().args ) or templateArg
	if pageArg and #pageArg == 0 then pageArg = templateArg end

	-- grabs a parameter from templateArg; index will be appended  if positive; if negative the absolute value will be tested first, then prefix without index
	local function pick(prefix, index)
		if type(index) ~= "number" or index == 0 then
			return templateArg[prefix]
		elseif index > 0 then
			return templateArg[prefix..index]
		else
			return templateArg[prefix..(-index)] or templateArg[prefix]
		end
	end
	
	local item, item1id = {}, pick("item",-1)
	if item1id then
		item[1] = mw.wikibase.getEntity(item1id:upper())
	else
		item[1] = mw.wikibase.getEntity() -- use wikidata associated to this page
	end
	-- TODO item[2+] (tabular)
	
	local indexes = getIndexes(templateArg,{"header","image","data","property","itemformatter"})
	
	if pick("title") then listener.title(pick("title"), pick("titleclass"), pick("titlestyle")) end
	if pick("above") then listener.above(pick("above"), pick("aboveclass"), pick("abovestyle")) end
	
	for _, index in pairs(indexes) do
		-- listener.error("index = "..index)
		if pick("header",index) then -- header-case
			listener.header(pick("header",index), pick("headerclass",-index), pick("headerstyle",-index))
		elseif pick("image",index) then -- image-case
			listener.image(pick("image",index), pick("imageclass",-index), pick("imagestyle",-index))
		elseif config.imageProperties[pick('property',index)] then
			local propId = pick( 'property', index )
			local propValue = wikidata.formatStatementsFromLua{ entity = item[1], property = propId, rank = 'one', }
			listener.value('TODO image', nil, nil, propId .. " /" .. propValue .. "/ " )
		elseif pick("data",index) or pick("property",index) or pick("itemformatter",index) then -- label/value-cases
			-- listener.error("value")
			local label, labelclass, labelstyle = pick("label",index), pick("labelclass",-index), pick("labelstyle",-index)
			-- value specified; retrieve from the page calling the template
			local dataId = pick("data",index)
			local dataValue = dataId and pageArg[dataId]
			if dataValue == "" then dataValue = nil end
			-- property specified; retrieve from wikidata
			local propId, propValue = pick("property",index)
			if propId and not item[1] then return i18n.error("error-item-not-found") end
			if propId then
				propId = propId:upper() -- wikidata keys are uppercase
				local wdArg = {
					entity = item[1],
					property = propId,
					formatter = pick("propertyformatter",index),
				}
				setmetatable( wdArg, { __index = function( t, key )
							if config.paramWithDefault[key] then
								return pick( key, -index )
							else
								return pick( key, index )
							end
						end } )
				propValue = wikidata.formatStatementsFromLua( wdArg )
				if propValue == "" then propValue = nil end
				-- take label from the property, if not given
				if propValue and not label then
					label = mw.language.getContentLanguage():ucfirst(mw.wikibase.label(propName) or '') -- TODO language fallback
				end
			end
			-- itemformatter given; let it replace property
			local formatter = pick("itemformatter",index)
			if formatter then
				formatter = mw.text.split(formatter,".",true)
				formatter = require("Module:"..formatter[1])[formatter[2]] -- TODO errorhandling
				propValue = formatter(item[1])
			end
			if propValue == "" then propValue = nil end
			-- choose if needed
			local showValue = dataValue or propValue
			if dataValue and propValue and dataValue ~= propValue then
				if pick("priority",-index) == "property" then
					showValue = propValue .. '<sup title="'..i18n('localdata-differs')..'">&Delta;</sup>'
				else
					showValue = showValue .. '<sup title="'..i18n('wikidata-differs')..'">&Delta;[[:d:'..item[1]["id"]..'|WD]]</sup>' -- TODO note
				end
			end
			-- TODO include empty values
			if showValue then
				listener.value(label,labelclass,labelstyle,showValue)
			end
		else
			listener.error("unhandled index "..index)
		end
	end
	
	if pick("below") then listener.below(pick("below"), pick("belowclass"),pick("belowstyle")) end
	-- TODO notes
end



local Datalist = {}

function Datalist.infobox( frame )
	local buffer = mw.html.create("table")
	buffer
		:addClass("infobox")
		:css('width', '22em')
	local listener = {
		title = function(text, cls, style)
			buffer
				:tag('caption')
					:addClass(cls)
					:cssText(style)
					:wikitext(text)
			end,
		above = function(text,cls,style)
			buffer
				:tag('tr')
					:tag('th')
						:attr('colspan', 2)
						:addClass(cls)
						:css('text-align', 'center')
						:css('font-size', '125%')
						:css('font-weight', 'bold')
						:cssText(style)
						:wikitext(text)
			end,
		header = function(text,cls,style)
			buffer
				:tag('tr')
					:tag('th')
						:attr('colspan','2')
						:addClass(cls)
						:css('text-align', 'center')
						:cssText(style)
						:wikitext(text)
			end,
		image = function(code,cls,style)
			buffer
				:tag('tr')
					:tag('td')
						:attr('colspan',2)
						:addClass(cls)
						:css('text-align', 'center')
						:cssText(style)
						:wikitext(code)
			end,
		value = function(label,labelclass,labelstyle,text)
			local row = buffer:tag('tr')
			if label then
				row
					:tag('th')
						:addClass(labelclass)
						:cssText(labelstyle)
						:wikitext(label)
			end
			local dataCell = row:tag('td')
			if not label then
				dataCell
					:attr('colspan', 2)
					:css('text-align', 'center')
			end
			dataCell
				:wikitext(text)
			end,
		below = function(text,cls,style)
			buffer
				:tag('tr')
					:tag('td')
						:attr('colspan', 2)
						:addClass(cls)
						:css('text-align', 'center')
						:cssText(style)
						:newline()
						:wikitext(text)
			end,
		error = function(text)
			buffer
				:tag('tr')
					:tag('td')
						:attr('colspan', 2)
						:addClass('error')
						:css('text-align', 'center')
						:wikitext(text)
			end,
	}
	local err = datalistGenerator(frame, listener)
	return err or tostring(buffer)
end


function Datalist.section(frame)
	local buffer = mw.html.create("table")
	local listener = {
		title = function(text, cls, style)
			buffer
				:tag('h2') -- TODO control level by parameter
					:addClass(cls)
					:cssText(style)
					-- :addClass('mw-headline') -- TODO check in TOC
					:wikitext(text)
			end,
		above = function(text,cls,style)
			buffer
				:tag('p')
					:addClass(cls)
					-- :cssText(style)
					:wikitext(text)
			end,
		header = function(text,cls,style)
			buffer
				:tag('h3') -- TODO control level by parameter
					-- :addClass('mw-headline')
					:addClass(cls)
					-- :cssText(style)
					:wikitext(text)
			end,
		image = function(code,cls,style)
			buffer
				:tag('div')
					:addClass(cls)
					:css('text-align', 'center')
					:cssText(style)
					:wikitext(code)
			end,
		value = function(label,labelclass,labelstyle,text)
			local row = buffer:tag('p')
			if label then
				row
					:tag('span')
						:addClass(labelclass)
						:cssText(labelstyle)
						:wikitext(label..": ") -- TODO i18n
			end
			local dataCell = row:tag('span')
			dataCell
				:wikitext(text)
			end,
		below = function(text,cls,style)
			buffer
				:tag('p')
					:addClass(cls)
					:cssText(style)
					:wikitext(text)
			end,
		error = function(text)
			buffer
				:tag('div')
					:addClass('error')
					-- :css('text-align', 'center')
					:wikitext(text)
			end,
	}
	datalistGenerator(frame, listener)
	return tostring(buffer)
end

function Datalist.spam(arg,options)
	return "spam " .. mw.dumpObject{arg=arg,options=options}
end

return Datalist