Modul:Sandkasse/Poul G/Dataliste

Fra Wikipedia, den frie encyklopædi
Documentation icon Moduldokumentation[vis] [redigér] [historik] [opfrisk]

Datalist is a module intended to support presentation ordered sequences (lists) of different dataitems.

The presentation can take three forms:

  1. infobox - the boxes normally found at the right side of the top of an article with key facts about the subject.
  2. section - a section presented in the article. This section will be more fact centered and less prose-like than other sections. Eg an article about an engine could have a secion covering specifications such as dimension, volume, performance etc.
  3. table - a tabular form, where the data of the subject of the article is comparet to relevant other subjects. TODO

Datalist is ment to be "wrapped" in a template, where the template controls the behaviour of Datalist.

The data presented can originate from Wikidata properties (property) or from parameters supplied from the calling page (data).

Parameters[rediger kildetekst]

Parameters Explanation Example
Headlines above it all
title titleclass titlestyle Specifies the title to appear before the datalist. For infobox it will appear above the table. For setion it will generate a heading (==title==) for the section. title=Engine
above aboveclass abovestyle Specifies something to appear before the datalist, but after the title. For infobox it will generate a heading inside the box. For section it will generate normal text in the beginning of the section.
Value-lines # denotes numerically indexed parameters; they will be presented in their numerical order. [#] denotes parameters, which can be indexed or specified as a default value for all instances. If the same index are used for multiple purposes, the priority will be header, image & itemformatter/data/property.
header# headerclass[#] headerstyle[#] Specifies a headline to appear above a subsection. Intended for use, when many values might clutter the view. header10=Developement and intro
image# imageclass[#] imagestyle[#] Specifies an image to be displayed at the given position. The specification should include with and could include caption and alt-text. Images specified in Wikidata can not be included this way; use the data-parameter instead. image20=[[File:Harley-Davidson-WL.jpg|200px|Harley-Davidson 1947]]
label# labelclass[#] labelstyle[#] Specifies the label to appear before the value. If no label is given, and a wikidata-property is specified, the wikidata-label will be used. label30=Designer
data# Specifies the name of the field to search for a value from the calling page. data30=designer

and in the item-page: designer=Davidson

property# link[#] rank[#] propertyformatter# Specifies the property (attribute) to retrive from wikidata. Formatting of the value is delegated to Module:Wikidatas formatStatementsFromLua. If link, rank or (property-) formatter are specified, they are feed to Wikidata.formatStatementsFromLua. property40=P22
itemformatter# Specifies a formatter to generate a value based on the complete item. The format is Module.function. Intended for use, when more than one attribute is needed. The value vil override values found by property. itemformatter50=Wikidata.lifespan
priority[#] As per. default, specified values (data) and takes precedence over values found in wikidata (property/itemformatter). Priority can be given to wikidata with this parameter. priority=wikidata
Tail
below belowclass belowstyle Specifies something to appear below the datalist. For infobox it will generate some centered text at the bottom of the box. For section it will generate normal text in the end of the section.
Shared
item[#] Specifies the wikidata-item to fetch data from. Default the item linked to the displayed page will be used. Must be specified for item2++ in table. item2=Q42


More Comprehensive Examples[rediger kildetekst]

Infobox[rediger kildetekst]

Lua-fejl i linje 107: attempt to concatenate local 'propValue' (a nil value).

{{#invoke:Sandkasse/Poul G/Dataliste|infobox
 | item = Q544661
 | above = Svævefly<br/>Rolladen-Schneider LS4
 | abovestyle = background: #87CEEB; font-size: larger;
 | link = local
 | rank = valid
 | image10 = [[file:Ls-4.JPG|300px|... caption ...]]
 | label20 = Class               | property20 = P279
 | label30 = Country             | property30 = p17         | propertyformatter30 = iconItem
 | label40 = Manufacturer        | property40 = p176
 | label50 = Series length       | property50 = p1092
 | label51 = i DK                | data51 = antalDK         | antalDK = Ca. 30
 | label60 = Designer            | property60 = p287
 | label70 = First flight        | property70 = p606
 | label90 = Handicap            | data90 = handicap        | handicap = 103.8 (EGU)
 | below = Demonstration only
}}

Section[rediger kildetekst]

Lua-fejl i Modul:Math på linje 517: attempt to call field '?' (a nil value).

Table[rediger kildetekst]

TBS

-- 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