Modul:Wikidata/Formatters

Z Enviwiki
Skočit na navigaci Skočit na vyhledávání

Věci přenesené přes šablony z cs:wiki


require "Modul:No globals"

local p = {}

local lib = require 'Modul:Wikidata/lib'

local function formatCoordinateValue(value, typeOfValue, field)
	local function fastConvertDdToDms(ddValue)
		local dmsArr = {
			degrees = 0,
			minutes = 0,
			seconds = 0.0
		}

		if ddValue then
			dmsArr.degrees = math.floor(tonumber(ddValue))
			dmsArr.minutes = math.floor((tonumber(ddValue) - dmsArr["degrees"]) * 60)
			dmsArr.seconds = (tonumber(ddValue) - dmsArr["degrees"] - dmsArr["minutes"]/60) * 3600
		end

		return dmsArr
	end

	-- type bude nepovinny - tj. "nil"
	-- priklad pouze -- je tam asi X chyb (mimo jine N vs S a podobne)
	local result = ""
	local latdmsText, londmsText
	if typeOfValue == 'dms' then
		local latDms = fastConvertDdToDms(value.latitude)
		local lonDms = fastConvertDdToDms(value.longitude)
		latdmsText = mw.ustring.format('N %s° %s\' %s"', latDms["degrees"], latDms["minutes"], latDms["seconds"])
		londmsText = mw.ustring.format('E %s° %s\' %s"', lonDms["degrees"], lonDms["minutes"], lonDms["seconds"])
		if field then
			if field == 'latitude' then
				result = latdmsText
			elseif field == 'longitude' then
				result = londmsText
			end
		else
			result = latdmsText .. " " .. londmsText
		end
	elseif typeOfValue == 'dd' then
		latdmsText = tonumber(value.latitude)
		londmsText = tonumber(value.longitude)
		if field then
			if field == 'latitude' then
				result = latdmsText
			elseif field == 'longitude' then
				result = londmsText
			end
		else
			result = latdmsText .. " " .. londmsText
		end
	else
		result = value.latitude .. ' / ' .. value.longitude .. ' (přesnost: ' .. value.precision .. ')'
	end

	return result
end

local function findPattern(property)
	local entity = mw.wikibase.getEntity(property:upper())
	if entity then
		local Statements = entity:getBestStatements('P1630')
		for _, statement in pairs(Statements) do
			if lib.IsSnakValue(statement.mainsnak) then
				return p.getRawValue(statement.mainsnak)
			end
		end
	end
	return nil
end

local function formatQuantity(value, options)
	local amount = tonumber(value.amount)
	local margin
	if lib.IsOptionTrue(options, 'showmargin') then
		margin = tonumber(value.upperBound) - amount
		if margin == 0 then
			margin = nil
		end
	end
	local prefix
	if amount < 0 then
		amount = tonumber(mw.ustring.sub(amount, 2))
		prefix = '-'
	end
	if lib.IsOptionTrue(options, 'formatted') then
		local function formatNumber(number)
			local integer, decimal
			if mw.ustring.find(number, '%.') then
				integer, decimal = mw.ustring.match(number, '^(.+)%.(.+)$')
			else
				integer = number
			end
			local length = mw.ustring.len(integer)
			local i = length % 3
			if i == 0 then
				i = 3
			end
			local formatted_num = mw.ustring.sub(integer, 1, i)
			while i < length do
				formatted_num = formatted_num .. '&nbsp;' .. mw.ustring.sub(integer, i + 1, i + 3)
				i = i + 3
			end
			if decimal then
				local length = mw.ustring.len(decimal)
				local i = 3
				formatted_num = formatted_num .. ',' .. mw.ustring.sub(decimal, 1, 3)
				while i < length do
					formatted_num = formatted_num .. '&nbsp;' .. mw.ustring.sub(decimal, i + 1, i + 3)
					i = i + 3
				end
			end
			return formatted_num
		end
		amount = formatNumber(amount)
		if margin then
			margin = formatNumber(margin)
		end
	end
	if margin then
		amount = amount .. '±' .. margin
	end
	if prefix then
		amount = prefix .. amount
	end
	local unit = value.unit
	if unit ~= '1' and tostring(options.showunit) ~= 'false' then
		local unit_id = mw.ustring.match(unit, '(Q%d+)') -- separate handler
		if unit_id then
			local module = require 'Modul:Wikidata'
			local unit = module.formatStatementsFromLua{
				id = unit_id,
				limit = 1,
				property = 'P558',
				rank = 'best'
			}
			if not unit then
				local ItemFormatter = require 'Modul:Wikidata/item'
				unit = ItemFormatter.formatEntityId(unit_id, {})
			end
			amount = amount .. '&nbsp;' .. unit
		end
	end
	return amount
end

local function executeFormatter(formatters, value, options)
	if formatters.module or formatters.withmodule then
		if not formatters.module or not formatters.func then
			return formatError('unknown-value-module')
		end

		local formatter = require ('Modul:' .. formatters.module)
		if not formatter then
			return formatError('value-module-not-found', formatters.module)
		end

		local fun = formatter[formatters.func]
		if not fun then
			return formatError('value-function-not-found', formatters.func)
		end

		return fun(value, options)
	else
		return formatters.func(value, options)
	end
end

local function getFormatter(datavalue, aspect, options)
	local FormattersMap = {
		globecoordinate = {
			formatted = {
				func = function(value, options)
					if not options.field or options.field == '' then
					--	return error(lib.formatError('param-not-provided', 'field'))
						return formatCoordinateValue(value, 'dms')
					elseif options.field == "latitude" or options.field == "longitude" then
						return formatCoordinateValue(value, options.typeOfCoordinates, options.field)
					elseif options.field == "precision" or options.field == "globe" then
						return value[options.field]
					else
						return error(lib.formatError('invalid-field', options.field))
					end
				end
			}
		},
		monolingualtext = {
			formatted = {
				func = function(value)
					return '<span lang="' .. value.language .. '">' .. value.text .. '</span>'
				end
			},
			raw = {
				func = function(value)
					return value.text
				end
			}
		},
		quantity = {
			formatted = {
				func = formatQuantity
			},
			raw = {
				func = function(value)
					return tonumber(value.amount)
				end
			}
		},
		string = {
			formatted = {
				func = function(value, options)
					if options.pattern and options.pattern ~= '' then
						return lib.formatFromPattern(value, options.pattern)
					elseif lib.IsOptionTrue(options, 'autoformat') then
						local pattern = findPattern(options.property)
						if pattern then
							return lib.formatFromPattern(value, '[' .. pattern .. ' $1]')
						end
					else
						return value
					end
				end,
			}
		},
		time = {
			formatted = {
				func = 'formatDateFromWikidataValue',
				module = 'Wikidata/datum'
			},
			raw = {
				func = 'newFromWikidataValue',
				module = 'Time'
			}
		},
		["wikibase-entityid"] = {
			convert = {
				func = '',
				module = 'Wikidata/item'
			},
			formatted = {
				func = function(value, options)
					local module = require 'Modul:Wikidata/item'
					return module.formatEntityId(lib.getEntityIdFromValue(value), options)
				end
			},
			raw = {
				func = function(...)
					return lib.getEntityIdFromValue(...)
				end
			}
		},
	}

	if not FormattersMap[datavalue.type] then
		return error(lib.formatError('unknown-datavalue-type', datavalue.type))
	end

	if not FormattersMap[datavalue.type][aspect] then
		if aspect == 'raw' then
			return datavalue.value
		else
			return error() -- TODO
		end
	end

	return executeFormatter(FormattersMap[datavalue.type][aspect], datavalue.value, options)
end

function p.getRawValue(snak, options)
	if snak.snaktype == 'value' then
		return getFormatter(snak.datavalue, 'raw', options)
	elseif snak.snaktype == 'somevalue' or snak.snaktype == 'novalue' then
		return snak.snaktype
	else
		return error(lib.formatError('unknown-snak-type', snak.snaktype))
	end
end

function p.getFormattedValue(snak, options)
	if snak.snaktype == 'somevalue' or snak.snaktype == 'novalue' then
		return snak.snaktype
	elseif snak.snaktype ~= 'value' then
		return error(lib.formatError('unknown-snak-type', snak.snaktype))
	end

	if options['value-module'] or options['value-function'] then
		local formatterMap = {
			func = options['value-function'],
			module = options['value-module'],
			withmodule = true -- force throwing error
		}
		return executeFormatter(formatterMap, snak.datavalue.value, options)
	end

	return getFormatter(snak.datavalue, 'formatted', options)
end

return p