Modul:WikidataIB: Forskjell mellom sideversjoner
Hopp til navigering
Hopp til søk
(sync from sandbox: only remove prefix from sitelink if it's a genuine namespace name) |
mIngen redigeringsforklaring |
||
Linje 1: | Linje 1: | ||
-- Module to implement use of a blacklist and whitelist for infobox fields |
|||
-- Can take a named parameter |qid which is the Wikidata ID for the article |
|||
-- if not supplied, it will use the Wikidata ID associated with the current page. |
|||
-- Fields in blacklist are never to be displayed, i.e. module must return nil in all circumstances |
|||
-- Fields in whitelist return local value if it exists or the Wikidata value otherwise |
|||
-- The name of the field that this function is called from is passed in named parameter |name |
|||
-- The name is compulsory when blacklist or whitelist is used, |
|||
-- so the module returns nil if it is not supplied. |
|||
-- blacklist is passed in named parameter |suppressfields (or |spf) |
|||
-- whitelist is passed in named parameter |fetchwikidata (or |fwd) |
|||
local p = {} |
local p = {} |
||
local rankOrder = { |
|||
local cdate -- initialise as nil and only load _complex_date function if needed |
|||
['truth'] = 1, |
|||
-- [[Module:Complex date]] is loaded lazily and has the following dependencies: |
|||
['preferred'] = 2, |
|||
-- Module:I18n/complex date, Module:ISOdate, Module:DateI18n (alternative for Module:Date), |
|||
['normal'] = 3, |
|||
-- Module:Formatnum, Module:I18n/date, Module:Yesno, Module:Linguistic, Module:Calendar |
|||
['deprecated'] = 4 |
|||
-- The following, taken from https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times, |
|||
-- is needed to use Module:Complex date which seemingly requires date precision as a string. |
|||
-- It would work better if only the authors of the mediawiki page could spell 'millennium'. |
|||
local dp = { |
|||
[6] = "millennium", |
|||
[7] = "century", |
|||
[8] = "decade", |
|||
[9] = "year", |
|||
[10] = "month", |
|||
[11] = "day", |
|||
} |
} |
||
local i18n = |
local i18n = { |
||
['wikidata-linkback-edit'] = 'Redigere på Wikidata', |
|||
{ |
|||
['wiki-article-not-available'] = 'Artikkelen er ikke tilgjengelig på denne wikien ennå', |
|||
["errors"] = |
|||
['wikidata-more-results-exists'] = 'Flere verdier er tilgjengelige på wikidata', |
|||
{ |
|||
['standard-timeformat'] = 'j. F Y', |
|||
["property-not-found"] = "Property not found.", |
|||
['argument-property'] = 'property', |
|||
['argument-list'] = 'liste', |
|||
["entity-not-found"] = "Wikidata entity not found.", |
|||
['argument-date'] = 'dato', |
|||
["unknown-claim-type"] = "Unknown claim type.", |
|||
['argument-value'] = 'verdi', |
|||
["unknown-entity-type"] = "Unknown entity type.", |
|||
['argument-label'] = 'pnavn', |
|||
["qualifier-not-found"] = "Qualifier not found.", |
|||
['argument-noedit'] = 'noedit', |
|||
["site-not-found"] = "Wikimedia project not found.", |
|||
['argument-fallback'] = 'fallback', |
|||
["labels-not-found"] = "No labels found.", |
|||
['argument-suffix'] = 'suffiks', |
|||
["descriptions-not-found"] = "No descriptions found.", |
|||
['argument-suffix-label'] = 'suffiksnavn', |
|||
["aliases-not-found"] = "No aliases found.", |
|||
['argument-bounds'] = 'usikkerhet', |
|||
["unknown-datetime-format"] = "Unknown datetime format.", |
|||
['category-rowproperty-no-arguments'] = '[[Kategori:Artikler med invoke WikidataIB rowProperty uten argumenter]]', |
|||
["local-article-not-found"] = "Article is available on Wikidata, but not on Wikipedia", |
|||
['category-getpropertyvalue-no-arguments'] = '[[Kategori:Artikler med invoke WikidataIB getPropertyValue uten argumenter]]', |
|||
["dab-page"] = " (dab)", |
|||
['category-getpropertylabel-no-arguments'] = '[[Kategori:Artikler med invoke WikidataIB getPropertyLabel uten argumenter]]' |
|||
}, |
|||
["months"] = |
|||
{ |
|||
"January", "February", "March", "April", "May", "June", |
|||
"July", "August", "September", "October", "November", "December" |
|||
}, |
|||
["century"] = "century", |
|||
["BC"] = "BC", |
|||
["BCE"] = "BCE", |
|||
["ordinal"] = |
|||
{ |
|||
[1] = "st", |
|||
[2] = "nd", |
|||
[3] = "rd", |
|||
["default"] = "th" |
|||
}, |
|||
["filespace"] = "File", |
|||
["Unknown"] = "Unknown", |
|||
["NaN"] = "Not a number", |
|||
-- set the following to the name of a tracking category, |
|||
-- e.g. "[[Category:Articles with missing Wikidata information]]", or "" to disable: |
|||
["missinginfocat"] = "[[Category:Articles with missing Wikidata information]]", |
|||
["editonwikidata"] = "Edit this on Wikidata", |
|||
["latestdatequalifier"] = function (date) return "before " .. date end, |
|||
-- some languages, e.g. Bosnian use a period as a suffix after each number in a date |
|||
["datenumbersuffix"] = "", |
|||
["list separator"] = ", ", |
|||
["multipliers"] = { |
|||
[0] = "", |
|||
[3] = " thousand", |
|||
[6] = " million", |
|||
[9] = " billion", |
|||
[12] = " trillion", |
|||
} |
|||
} |
} |
||
-- This allows an internationisation module to override the above table |
|||
if 'en' ~= mw.getContentLanguage():getCode() then |
|||
require("Module:i18n").loadI18n("Module:WikidataIB/i18n", i18n) |
|||
end |
|||
local arguments = { |
|||
-- This piece of html implements a collapsible container. Check the classes exist on your wiki. |
|||
property = nil, |
|||
local collapsediv = '<div class="mw-collapsible mw-collapsed" style="width:100%; overflow:auto;" data-expandtext="{{int:show}}" data-collapsetext="{{int:hide}}">' |
|||
list = nil, |
|||
date = nil, |
|||
wiki_value = nil, |
|||
edit = nil, |
|||
fallback = nil, |
|||
usesuffix = nil, |
|||
suffix_from_wiki = nil, |
|||
label = nil, |
|||
usebounds = nil, |
|||
} |
|||
-- Some items should not be linked. |
|||
-- Each wiki can create a list of those in Module:WikidataIB/nolinks |
|||
-- It should return a table called itemsindex, containing true for each item not to be linked |
|||
local donotlink = {} |
|||
local nolinks_exists, nolinks = pcall(mw.loadData, "Module:WikidataIB/nolinks") |
|||
if nolinks_exists then |
|||
donotlink = nolinks.itemsindex |
|||
end |
|||
local function dump(obj) |
|||
-- To satisfy Wikipedia:Manual of Style/Titles, certain types of items are italicised, and others are quoted. |
|||
return "<pre>" .. mw.dumpObject(obj) .. "</pre>" |
|||
-- The submodule [[Module:WikidataIB/titleformats]] lists the entity-ids used in 'instance of' (P31), |
|||
-- which allows this module to identify the values that should be formatted. |
|||
-- WikidataIB/titleformats exports a table p.formats, which is indexed by entity-id, and contains the value " or '' |
|||
local formats = {} |
|||
local titleformats_exists, titleformats = pcall(mw.loadData, "Module:WikidataIB/titleformats") |
|||
if titleformats_exists then |
|||
formats = titleformats.formats |
|||
end |
end |
||
local function getArgument(frame, argument) |
|||
------------------------------------------------------------------------------- |
|||
local args = frame.args |
|||
-- Private functions |
|||
if args[1] == nil then |
|||
------------------------------------------------------------------------------- |
|||
local pFrame = frame:getParent(); |
|||
-- |
|||
args = pFrame.args; |
|||
------------------------------------------------------------------------------- |
|||
for k,v in pairs( frame.args ) do |
|||
-- makeOrdinal needs to be internationalised along with the above: |
|||
args[k] = v; |
|||
-- takes cardinal numer as a numeric and returns the ordinal as a string |
|||
-- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local makeOrdinal = function(cardinal) |
|||
local ordsuffix = i18n.ordinal.default |
|||
if cardinal % 10 == 1 then |
|||
ordsuffix = i18n.ordinal[1] |
|||
elseif cardinal % 10 == 2 then |
|||
ordsuffix = i18n.ordinal[2] |
|||
elseif cardinal % 10 == 3 then |
|||
ordsuffix = i18n.ordinal[3] |
|||
end |
|||
-- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th' |
|||
-- similarly for 12 and 13, etc. |
|||
if (cardinal % 100 == 11) or (cardinal % 100 == 12) or (cardinal % 100 == 13) then |
|||
ordsuffix = i18n.ordinal.default |
|||
end |
|||
return tostring(cardinal) .. ordsuffix |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- findLang takes a "langcode" parameter if supplied and valid |
|||
-- otherwise it tries to create it from the user's set language ({{int:lang}}) |
|||
-- failing that it uses the wiki's content language. |
|||
-- It returns a language object |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local findLang = function(langcode) |
|||
local langobj |
|||
langcode = mw.text.trim(langcode or "") |
|||
if mw.language.isKnownLanguageTag(langcode) then |
|||
langobj = mw.language.new( langcode ) |
|||
else |
|||
langcode = mw.getCurrentFrame():preprocess( '{{int:lang}}' ) |
|||
if mw.language.isKnownLanguageTag(langcode) then |
|||
langobj = mw.language.new( langcode ) |
|||
else |
|||
langobj = mw.language.getContentLanguage() |
|||
end |
end |
||
end |
|||
if args[argument] then |
|||
return langobj |
|||
return args[argument] |
|||
end |
|||
return nil |
|||
end |
end |
||
local function getArguments(frame) |
|||
arguments.property = getArgument(frame, i18n['argument-property']) |
|||
------------------------------------------------------------------------------- |
|||
if not arguments.property then |
|||
-- _getItemLangCode takes a qid parameter (using the current page's qid if blank) |
|||
-- |
-- No such argument, try getting it as the first argument |
||
arguments.property = getArgument(frame, '1') |
|||
-- If the country has an official language (P37), it looks at the first preferred value |
|||
-- If that official language has a language code (P424), it returns the first preferred value |
|||
-- Otherwise it returns nothing. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local _getItemLangCode = function(qid) |
|||
qid = mw.text.trim(qid or ""):upper() |
|||
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then return end |
|||
local prop17 = mw.wikibase.getBestStatements(qid, "P17")[1] |
|||
if not prop17 or prop17.mainsnak.snaktype ~= "value" then return end |
|||
local qid17 = prop17.mainsnak.datavalue.value.id |
|||
local prop37 = mw.wikibase.getBestStatements(qid17, "P37")[1] |
|||
if not prop37 or prop37.mainsnak.snaktype ~= "value" then return end |
|||
local qid37 = prop37.mainsnak.datavalue.value.id |
|||
local prop424 = mw.wikibase.getBestStatements(qid37, "P424")[1] |
|||
if not prop424 or prop424.mainsnak.snaktype ~= "value" then return end |
|||
return prop424.mainsnak.datavalue.value |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- roundto takes a number (x) |
|||
-- and returns it rounded to (sf) significant figures |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local roundto = function(x, sf) |
|||
if x == 0 then return 0 end |
|||
local s = 1 |
|||
if x < 0 then |
|||
x = -x |
|||
s = -1 |
|||
end |
end |
||
arguments.list = getArgument(frame, i18n['argument-list']) |
|||
if sf < 1 then sf = 1 end |
|||
if arguments.list and arguments.list ~= "" and tonumber(arguments.list) ~= 0 then |
|||
local p = 10 ^ (math.floor(math.log10(x)) - sf + 1) |
|||
arguments.list = tonumber(arguments.list) |
|||
x = math.floor(x / p + 0.5) * p * s |
|||
else |
|||
-- if it's integral, cast to an integer: |
|||
arguments.list = nil |
|||
if x == math.floor(x) then x = math.floor(x) end |
|||
return x |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- decimalToDMS takes a decimal degrees (x) with precision (p) |
|||
-- and returns degrees/minutes/seconds according to the precision |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local decimalToDMS = function(x, p) |
|||
-- if p is not supplied, use a precision around 0.1 seconds |
|||
if not tonumber(p) then p = 1e-4 end |
|||
local d = math.floor(x) |
|||
local ms = (x - d) * 60 |
|||
if p > 0.5 then -- precision is > 1/2 a degree |
|||
if ms > 30 then d = d + 1 end |
|||
ms = 0 |
|||
end |
end |
||
arguments.date = getArgument(frame, i18n['argument-date']) |
|||
local m = math.floor(ms) |
|||
arguments.wiki_value = getArgument(frame, i18n['argument-value']) |
|||
local s = (ms - m) * 60 |
|||
arguments.edit = getArgument(frame, i18n['argument-edit']) |
|||
if p > 0.008 then -- precision is > 1/2 a minute |
|||
if arguments.edit and arguments.edit == "1" and not arguments.wiki_value then |
|||
if s > 30 then m = m +1 end |
|||
arguments.edit = false |
|||
else |
|||
elseif p > 0.00014 then -- precision is > 1/2 a second |
|||
arguments.edit = true |
|||
s = math.floor(s + 0.5) |
|||
elseif p > 0.000014 then -- precision is > 1/20 second |
|||
s = math.floor(10 * s + 0.5) / 10 |
|||
elseif p > 0.0000014 then -- precision is > 1/200 second |
|||
s = math.floor(100 * s + 0.5) / 100 |
|||
else -- cap it at 3 dec places for now |
|||
s = math.floor(1000 * s + 0.5) / 1000 |
|||
end |
end |
||
arguments.fallback = getArgument(frame, i18n['argument-fallback']) |
|||
return d, m, s |
|||
if arguments.fallback and arguments.fallback ~= "" then |
|||
end |
|||
arguments.fallback = true |
|||
else |
|||
arguments.fallback = false |
|||
------------------------------------------------------------------------------- |
|||
-- decimalPrecision takes a decimal (x) with precision (p) |
|||
-- and returns x rounded approximately to the given precision |
|||
-- precision should be between 1 and 1e-6, preferably a power of 10. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local decimalPrecision = function(x, p) |
|||
local s = 1 |
|||
if x < 0 then |
|||
x = -x |
|||
s = -1 |
|||
end |
end |
||
arguments.usesuffix = getArgument(frame, i18n['argument-suffix']) |
|||
-- if p is not supplied, pick an arbitrary precision |
|||
arguments.suffix_from_wiki = getArgument(frame, i18n['argument-suffix-label']) |
|||
if not tonumber(p) then p = 1e-4 |
|||
arguments.label = getArgument(frame, i18n['argument-label']) |
|||
elseif p > 1 then p = 1 |
|||
arguments.usebounds = getArgument(frame, i18n['argument-bounds']) |
|||
elseif p < 1e-6 then p = 1e-6 |
|||
else p = 10 ^ math.floor(math.log10(p)) |
|||
end |
|||
x = math.floor(x / p + 0.5) * p * s |
|||
-- if it's integral, cast to an integer: |
|||
if x == math.floor(x) then x = math.floor(x) end |
|||
-- if it's less than 1e-4, it will be in exponent form, so return a string with 6dp |
|||
-- 9e-5 becomes 0.000090 |
|||
if math.abs(x) < 1e-4 then x = string.format("%f", x) end |
|||
return x |
|||
end |
end |
||
local function getDate(qualifiers, dateformat, langcode) |
|||
local out = nil |
|||
------------------------------------------------------------------------------- |
|||
if qualifiers then |
|||
-- formatDate takes a datetime of the usual format from mw.wikibase.entity:formatPropertyValues |
|||
local qualifierID = "" |
|||
-- like "1 August 30 BCE" as parameter 1 |
|||
if qualifiers['P585'] then qualifierID='P585' -- point-in-time |
|||
-- and formats it according to the df (date format) and bc parameters |
|||
elseif qualifiers['P580'] then qualifierID='P580' end -- from |
|||
-- df = ["dmy" / "mdy" / "y"] default will be "dmy" |
|||
-- todo: timespans? P582 |
|||
-- bc = ["BC" / "BCE"] default will be "BCE" |
|||
for k, v in pairs(qualifiers[qualifierID]) do |
|||
------------------------------------------------------------------------------- |
|||
if v.snaktype == 'value' then |
|||
-- Dependencies: none |
|||
out = "(" .. mw.language.new(langcode):formatDate(dateformat, v.datavalue.value.time) .. ")" |
|||
------------------------------------------------------------------------------- |
|||
end |
|||
local format_Date = function(datetime, dateformat, bc) |
|||
local datetime = datetime or "1 August 30 BCE" -- in case of nil value |
|||
-- chop off multiple vales and/or any hours, mins, etc. |
|||
-- keep anything before punctuation - we just want a single date: |
|||
local dateval = string.match( datetime, "[%w ]+") |
|||
local dateformat = string.lower(dateformat or "dmy") -- default to dmy |
|||
local bc = string.upper(bc or "") -- can't use nil for bc |
|||
-- we only want to accept two possibilities: BC or default to BCE |
|||
if bc == "BC" then |
|||
bc = " " .. i18n["BC"] -- prepend a non-breaking space. |
|||
else |
|||
bc = " " .. i18n["BCE"] |
|||
end |
|||
local postchrist = true -- start by assuming no BCE |
|||
local dateparts = {} |
|||
for word in string.gmatch(dateval, "%w+") do |
|||
if word == "BCE" or word == "BC" then -- *** internationalise later *** |
|||
postchrist = false |
|||
else |
|||
-- we'll keep the parts that are not 'BCE' in a table |
|||
dateparts[#dateparts + 1] = word |
|||
end |
end |
||
end |
end |
||
return out |
|||
if postchrist then bc = "" end -- set AD dates to no suffix *** internationalise later *** |
|||
local sep = " " -- separator is nbsp |
|||
local fdate = table.concat(dateparts, sep) -- set formatted date to same order as input |
|||
-- if we have day month year, check dateformat |
|||
if #dateparts == 3 then |
|||
if dateformat == "y" then |
|||
fdate = dateparts[3] |
|||
elseif dateformat == "mdy" then |
|||
fdate = dateparts[2] .. sep .. dateparts[1] .. "," .. sep .. dateparts[3] |
|||
end |
|||
elseif #dateparts == 2 and dateformat == "y" then |
|||
fdate = dateparts[2] |
|||
end |
|||
return fdate .. bc |
|||
end |
end |
||
local function getOrder(qualifiers) |
|||
local out = nil |
|||
------------------------------------------------------------------------------- |
|||
if qualifiers then |
|||
-- dateFormat is the handler for properties that are of type "time" |
|||
local qualifierID = "P1545" -- sorting order / rank / series ordinal |
|||
-- It takes timestamp, precision (6 to 11 per mediawiki), dateformat (y/dmy/mdy), BC format (BC/BCE), |
|||
if qualifiers[qualifierID] then |
|||
-- a plaindate switch (yes/no/adj) to en/disable "sourcing cirumstances"/use adjectival form, |
|||
for k, v in pairs(qualifiers[qualifierID]) do |
|||
-- any qualifiers for the property, the language, and any adjective to use like 'before'. |
|||
if v.snaktype == 'value' then |
|||
-- It passes the date through the "complex date" function |
|||
out = v.datavalue.value |
|||
-- and returns a string with the internatonalised date formatted according to preferences. |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: findLang(); cdate(); dp[] |
|||
------------------------------------------------------------------------------- |
|||
local dateFormat = function(timestamp, dprec, df, bcf, pd, qualifiers, lang, adj, model) |
|||
-- A year can be stored like this: "+1872-00-00T00:00:00Z", |
|||
-- which is processed here as if it were the day before "+1872-01-01T00:00:00Z", |
|||
-- and that's the last day of 1871, so the year is wrong. |
|||
-- So fix the month 0, day 0 timestamp to become 1 January instead: |
|||
timestamp = timestamp:gsub("%-00%-00T", "-01-01T") |
|||
-- output formatting according to preferences (y/dmy/mdy) |
|||
df = (df or ""):lower() |
|||
-- just in case date precision is missing |
|||
dprec = dprec or 11 |
|||
-- override more precise dates if required dateformat is year alone: |
|||
if df == "y" and dprec > 9 then dprec = 9 end |
|||
-- complex date only deals with precisions from 6 to 11, so clip range |
|||
dprec = dprec>11 and 11 or dprec |
|||
dprec = dprec<6 and 6 or dprec |
|||
-- BC format is "BC" or "BCE" |
|||
bcf = (bcf or ""):upper() |
|||
-- plaindate only needs the first letter (y/n/a) |
|||
pd = (pd or ""):sub(1,1):lower() |
|||
if pd == "" or pd == "n" or pd == "f" or pd == "0" then pd = false end |
|||
-- in case language isn't passed |
|||
lang = lang or findLang().code |
|||
-- set adj as empty if nil |
|||
adj = adj or "" |
|||
-- extract the day, month, year from the timestamp |
|||
local bc = timestamp:sub(1, 1)=="-" and "BC" or "" |
|||
local year, month, day = timestamp:match("[+-](%d*)-(%d*)-(%d*)T") |
|||
local iso = tonumber(year) -- if year is missing, let it throw an error |
|||
-- this will adjust the date format to be compatible with cdate |
|||
-- possible formats are Y, YY, YYY0, YYYY, YYYY-MM, YYYY-MM-DD |
|||
if dprec == 6 then iso = math.floor( (iso - 1) / 1000 ) + 1 end |
|||
if dprec == 7 then iso = math.floor( (iso - 1) / 100 ) + 1 end |
|||
if dprec == 8 then iso = math.floor( iso / 10 ) .. "0" end |
|||
if dprec == 10 then iso = year .. "-" .. month end |
|||
if dprec == 11 then iso = year .. "-" .. month .. "-" .. day end |
|||
-- add "circa" (Q5727902) from "sourcing circumstances" (P1480) |
|||
local sc = not pd and qualifiers and qualifiers.P1480 |
|||
if sc then |
|||
for k1, v1 in pairs(sc) do |
|||
if v1.datavalue and v1.datavalue.value.id == "Q5727902" then |
|||
adj = "circa" |
|||
break |
|||
end |
end |
||
end |
end |
||
end |
end |
||
return out |
|||
-- deal with Julian dates: |
|||
-- no point in saying that dates before 1582 are Julian - they are by default |
|||
-- doesn't make sense for dates less precise than year |
|||
-- we can supress it by setting |plaindate, e.g. for use in constructing categories. |
|||
local calendarmodel = "" |
|||
if tonumber(year) > 1582 |
|||
and dprec > 8 |
|||
and not pd |
|||
and model == "http://www.wikidata.org/entity/Q1985786" then |
|||
calendarmodel = "julian" |
|||
end |
|||
if not cdate then |
|||
cdate = require("Module:Complex date")._complex_date |
|||
end |
|||
local fdate = cdate(calendarmodel, adj, tostring(iso), dp[dprec], bc, "", "", "", "", lang, 1) |
|||
-- this may have QuickStatements info appended to it in a div, so remove that |
|||
fdate = fdate:gsub(' <div style="display: none;">[^<]*</div>', '') |
|||
-- it may also be returned wrapped in a microformat, so remove that |
|||
fdate = fdate:gsub("<[^>]*>", "") |
|||
-- there may be leading zeros that we should remove |
|||
fdate = fdate:gsub("^0*", "") |
|||
-- if a plain date is required, then remove any links (like BC linked) |
|||
if pd then |
|||
fdate = fdate:gsub("%[%[.*|", ""):gsub("]]", "") |
|||
end |
|||
-- if 'circa', use the abbreviated form *** internationalise later *** |
|||
fdate = fdate:gsub('circa ', '<abbr title="circa">c.</abbr> ') |
|||
-- deal with BC/BCE |
|||
if bcf == "BCE" then |
|||
fdate = fdate:gsub('BC', 'BCE') |
|||
end |
|||
-- deal with mdy format |
|||
if df == "mdy" then |
|||
fdate = fdate:gsub("(%d+) (%w+) (%d+)", "%2 %1, %3") |
|||
end |
|||
-- deal with adjectival form *** internationalise later *** |
|||
if pd == "a" then |
|||
fdate = fdate:gsub(' century', '-century') |
|||
end |
|||
return fdate |
|||
end |
end |
||
local function sortTableRankAndOrder(t, order_descending) |
|||
local retval = {} |
|||
------------------------------------------------------------------------------- |
|||
local function compare(a, b) |
|||
-- parseParam takes a (string) parameter, e.g. from the list of frame arguments, |
|||
if (a.rank and b.rank and rankOrder[a.rank] < rankOrder[b.rank]) then |
|||
-- and makes "false", "no", and "0" into the (boolean) false |
|||
-- it makes the empty string and nil into the (boolean) value passed as default |
|||
-- allowing the parameter to be true or false by default. |
|||
-- It returns a boolean. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local parseParam = function(param, default) |
|||
if type(param) == "boolean" then param = tostring(param) end |
|||
if param and param ~= "" then |
|||
param = param:lower() |
|||
if (param == "false") or (param:sub(1,1) == "n") or (param == "0") then |
|||
return false |
|||
else |
|||
return true |
return true |
||
end |
end |
||
if (a.rank and b.rank and rankOrder[a.rank] == rankOrder[b.rank]) and (a.order and b.order and ((order_descending and a.order < b.order) or (not order_descending and a.order > b.order))) then |
|||
else |
|||
return |
return true |
||
else |
|||
end |
|||
return false |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- _getSitelink takes the qid of a Wikidata entity passed as |qid= |
|||
-- It takes an optional parameter |wiki= to determine which wiki is to be checked for a sitelink |
|||
-- If the parameter is blank, then it uses the local wiki. |
|||
-- If there is a sitelink to an article available, it returns the plain text link to the article |
|||
-- If there is no sitelink, it returns nil. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local _getSitelink = function(qid, wiki) |
|||
qid = (qid or ""):upper() |
|||
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then return nil end |
|||
wiki = wiki or "" |
|||
local sitelink |
|||
if wiki == "" then |
|||
sitelink = mw.wikibase.sitelink(qid) |
|||
else |
|||
sitelink = mw.wikibase.sitelink(qid, wiki) |
|||
end |
|||
return sitelink |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- _getCommonslink takes an optional qid of a Wikidata entity passed as |qid= |
|||
-- It returns one of the following in order of preference: |
|||
-- the Commons sitelink of the Wikidata entity - but not if onlycat=true and it's not a category; |
|||
-- the Commons sitelink of the topic's main category of the Wikidata entity; |
|||
-- the Commons category of the Wikidata entity - unless fallback=false. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getSitelink(); parseParam() |
|||
------------------------------------------------------------------------------- |
|||
local _getCommonslink = function(qid, onlycat, fallback) |
|||
qid = (qid or ""):upper() |
|||
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then return nil end |
|||
onlycat = parseParam(onlycat, false) |
|||
if fallback == "" then fallback = nil end |
|||
local sitelink = _getSitelink(qid, "commonswiki") |
|||
if onlycat and sitelink and sitelink:sub(1,9) ~= "Category:" then sitelink = nil end |
|||
if not sitelink then |
|||
-- check for topic's main category |
|||
local prop910 = mw.wikibase.getBestStatements(qid, "P910")[1] |
|||
if prop910 then |
|||
local tmcid = prop910.mainsnak.datavalue and prop910.mainsnak.datavalue.value.id |
|||
sitelink = _getSitelink(tmcid, "commonswiki") |
|||
end |
|||
if not sitelink then |
|||
-- check for list's main category |
|||
local prop1754 = mw.wikibase.getBestStatements(qid, "P1754")[1] |
|||
if prop1754 then |
|||
local tmcid = prop1754.mainsnak.datavalue and prop1754.mainsnak.datavalue.value.id |
|||
sitelink = _getSitelink(tmcid, "commonswiki") |
|||
end |
|||
end |
end |
||
end |
end |
||
table.sort(t, compare) |
|||
if not sitelink and fallback then |
|||
-- check for Commons category (string value) |
|||
local prop373 = mw.wikibase.getBestStatements(qid, "P373")[1] |
|||
if prop373 then |
|||
sitelink = prop373.mainsnak.datavalue and prop373.mainsnak.datavalue.value |
|||
if sitelink then sitelink = "Category:" .. sitelink end |
|||
end |
|||
end |
|||
return sitelink |
|||
end |
end |
||
local function compareRank(oldrank, newrank) |
|||
if (newrank and not oldrank) or (oldrank and newrank and rankOrder[newrank] < rankOrder[oldrank]) then |
|||
------------------------------------------------------------------------------- |
|||
return newrank |
|||
-- The label in a Wikidata item is subject to vulnerabilities |
|||
-- that an attacker might try to exploit. |
|||
-- It needs to be 'sanitised' by removing any wikitext before use. |
|||
-- If it doesn't exist, return the id for the item |
|||
-- a second (boolean) value is also returned, value is true when the label exists |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local labelOrId = function(id, lang) |
|||
if lang == "default" then lang = findLang().code end |
|||
local label |
|||
if lang then |
|||
label = mw.wikibase.getLabelByLang(id, lang) |
|||
else |
else |
||
return oldrank |
|||
label = mw.wikibase.label(id) |
|||
end |
|||
if label then |
|||
return mw.text.nowiki(label), true |
|||
else |
|||
return id, false |
|||
end |
end |
||
end |
end |
||
local function getQValueLink(qvalue, fallback, fallbacklang, label_from_wiki) |
|||
local sitelink = mw.wikibase.sitelink(qvalue) |
|||
------------------------------------------------------------------------------- |
|||
local label = label_from_wiki |
|||
-- linkedItem takes an entity-id and returns a string, linked if possible. |
|||
if not label then |
|||
-- This is the handler for "wikibase-item". Preferences: |
|||
label = mw.wikibase.label(qvalue) |
|||
-- 1. Display linked disambiguated sitelink if it exists |
|||
-- 2. Display linked label if it is a redirect |
|||
-- 3. TBA: Display an inter-language link for the label if it exists other than in default language |
|||
-- 4. Display unlinked label if it exists |
|||
-- 5. Display entity-id for now to indicate a label could be provided |
|||
-- dtxt is text to be used instead of label, or nil. |
|||
-- shortname is boolean switch to use P1813 (short name) instead of label if true. |
|||
-- lang is the current language code. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: labelOrId(); donotlink[] |
|||
------------------------------------------------------------------------------- |
|||
local linkedItem = function(id, lprefix, lpostfix, prefix, postfix, dtxt, shortname, lang) |
|||
lprefix = lprefix or "" -- toughen against nil values passed |
|||
lpostfix = lpostfix or "" |
|||
prefix = prefix or "" |
|||
postfix = postfix or "" |
|||
lang = lang or "en" -- fallback to default if missing |
|||
-- see if item might need italics or quotes |
|||
local fmt = "" |
|||
for k, v in ipairs( mw.wikibase.getBestStatements(id, "P31") ) do |
|||
if v.mainsnak.datavalue and formats[v.mainsnak.datavalue.value.id] then |
|||
fmt = formats[v.mainsnak.datavalue.value.id] |
|||
break -- pick the first match |
|||
end |
|||
end |
end |
||
out = nil |
|||
local disp |
|||
if qvalue then |
|||
local sitelink = mw.wikibase.sitelink(id) |
|||
if label == nil then |
|||
-- let's try the fallback-languages |
|||
if dtxt then |
|||
local checkQ = mw.wikibase.getEntityObject(qvalue) |
|||
label, islabel = dtxt, true |
|||
if checkQ then |
|||
local i = 0 |
|||
-- see if there is a shortname in our language, and set label to it |
|||
while i < #fallbacklang do |
|||
for k, v in ipairs( mw.wikibase.getBestStatements(id, "P1813") ) do |
|||
i = i + 1 |
|||
if v.mainsnak.datavalue.value.language == lang then |
|||
label |
label = checkQ:getLabel( fallbacklang[i] ) |
||
if label ~= nil then |
|||
break |
|||
break |
|||
end -- test for language match |
|||
end -- loop through values of short name |
|||
-- if we have no label set, then there was no shortname available |
|||
if not islabel then |
|||
label, islabel = labelOrId(id) |
|||
shortname = false |
|||
end |
|||
else |
|||
label, islabel = labelOrId(id) |
|||
end |
|||
if mw.site.siteName ~= "Wikimedia Commons" then |
|||
if sitelink then |
|||
if not (dtxt or shortname) then |
|||
-- strip any namespace or dab from the sitelink |
|||
local pos = sitelink:find(":") or 0 |
|||
local slink = sitelink |
|||
if pos > 0 then |
|||
local prefix = sitelink:sub(1,pos-1) |
|||
if mw.site.namespaces[prefix] then -- that prefix is a valid namespace, so remove it |
|||
slink = sitelink:sub(pos+1) |
|||
end |
end |
||
end |
end |
||
-- remove stuff after commas or inside parentheses - ie. dabs |
|||
slink = slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "") |
|||
-- use that as label, preserving label case - find("^%u") is true for 1st char uppercase |
|||
if label:find("^%u") then |
|||
label = slink:gsub("^(%l)", string.upper) |
|||
else |
|||
label = slink:gsub("^(%u)", string.lower) |
|||
end |
|||
end |
end |
||
if |
if label == nil then |
||
-- no such luck, fall back to Q-values |
|||
disp = prefix .. fmt .. label .. fmt .. postfix |
|||
label = qvalue |
|||
else |
|||
disp = "[[" .. lprefix .. sitelink .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]" |
|||
end |
end |
||
elseif islabel then |
|||
-- no sitelink, label exists, so check if a redirect with that title exists |
|||
local artitle = mw.title.new(label, 0) |
|||
if artitle and artitle.redirectTarget and not donotlink[label] then |
|||
-- there's a redirect with the same title as the label, so let's link to that |
|||
disp = "[[".. lprefix .. label .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]" |
|||
else |
|||
-- no sitelink, label exists, not redirect (or donotlink) so output plain label |
|||
disp = prefix .. fmt .. label .. fmt .. postfix |
|||
end -- test if article title exists as redirect on current Wiki |
|||
else |
|||
-- no sitelink and no label, so return whatever was returned from labelOrId for now |
|||
-- add tracking category [[Category:Articles with missing Wikidata information]] |
|||
disp = prefix .. label .. postfix .. i18n.missinginfocat |
|||
end |
end |
||
else |
|||
if sitelink and sitelink ~= label then |
|||
local ccat = mw.wikibase.getBestStatements(id, "P373")[1] |
|||
out = "[[" .. sitelink .. "|" .. label .. "]]" |
|||
if ccat and ccat.mainsnak.datavalue then |
|||
elseif sitelink then |
|||
ccat = ccat.mainsnak.datavalue.value |
|||
out = "[[" .. sitelink .. "]]" |
|||
elseif sitelink then |
|||
-- this asumes that if a sitelink exists, then a label also exists |
|||
disp = "[[" .. lprefix .. sitelink .. lpostfix .. "|" .. prefix .. label .. postfix .. "]]" |
|||
else |
else |
||
if fallback then |
|||
-- no sitelink and no Commons cat, so return label from labelOrId for now |
|||
out = "[[:d:Q" .. qvalue .. "|" .. label .. "]]<abbr title='" .. i18n['wiki-article-not-available'] .. "'>[*]</abbr>" |
|||
disp = prefix .. label .. postfix |
|||
else |
|||
out = label |
|||
end |
|||
return disp |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- sourced takes a table representing a statement that may or may not have references |
|||
-- it counts how many references are sourced to something not containing the word "wikipedia" |
|||
-- it returns a boolean = true if there are any sourced references. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local sourced = function(claim) |
|||
if claim.references then |
|||
for kr, vr in pairs(claim.references) do |
|||
local ref = mw.wikibase.renderSnaks(vr.snaks) |
|||
if not ref:find("Wikipedia") then |
|||
return true |
|||
end |
end |
||
end |
end |
||
end |
end |
||
return out |
|||
end |
end |
||
local function roundToDecimalNum(number, decimalPlace) |
|||
local mult = 10^(decimalPlace or 0) |
|||
------------------------------------------------------------------------------- |
|||
return math.floor(number * mult + 0.5) / mult |
|||
-- setRanks takes a flag (parameter passed) that requests the values to return |
|||
-- "b[est]" returns preferred if available, otherwise normal |
|||
-- "p[referred]" returns preferred |
|||
-- "n[ormal]" returns normal |
|||
-- "d[eprecated]" returns deprecated |
|||
-- multiple values are allowed, e.g. "preferred normal" (which is the default) |
|||
-- "best" will override the other flags, and set p and n |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local setRanks = function(rank) |
|||
rank = (rank or ""):lower() |
|||
-- if nothing passed, return preferred and normal |
|||
-- if rank == "" then rank = "p n" end |
|||
local ranks = {} |
|||
for w in string.gmatch(rank, "%a+") do |
|||
w = w:sub(1,1) |
|||
if w == "b" or w == "p" or w == "n" or w == "d" then |
|||
ranks[w] = true |
|||
end |
|||
end |
|||
-- check if "best" is requested or no ranks requested; and if so, set preferred and normal |
|||
if ranks.b or not next(ranks) then |
|||
ranks.p = true |
|||
ranks.n = true |
|||
end |
|||
return ranks |
|||
end |
end |
||
function RoundNumber(num, idp) |
|||
------------------------------------------------------------------------------- |
|||
-- parseInput processes the Q-id , the blacklist and the whitelist |
|||
-- if an input parameter is supplied, it returns that and ends the call. |
|||
-- it returns (1) either the qid or nil indicating whether or not the call should continue |
|||
-- and (2) a table containing all of the statements for the propertyID and relevant Qid |
|||
-- if "best" ranks are requested, it returns those instead of all non-deprecated ranks |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
local parseInput = function(frame, input_parm, property_id) |
|||
-- There may be a local parameter supplied, if it's blank, set it to nil |
|||
input_parm = mw.text.trim(input_parm or "") |
|||
if input_parm == "" then input_parm = nil end |
|||
local args = frame.args |
|||
-- can take a named parameter |qid which is the Wikidata ID for the article. |
|||
-- if it's not supplied, use the id for the current page |
|||
local qid = args.qid or "" |
|||
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
-- if there's no Wikidata item for the current page return nil |
|||
if not qid then return false, input_parm end |
|||
-- The blacklist is passed in named parameter |suppressfields |
|||
local blacklist = args.suppressfields or args.spf |
|||
-- The whitelist is passed in named parameter |fetchwikidata |
|||
local whitelist = args.fetchwikidata or args.fwd |
|||
if not whitelist or whitelist == "" then whitelist = "NONE" end |
|||
-- The name of the field that this function is called from is passed in named parameter |name |
|||
local fieldname = args.name or "" |
|||
if blacklist then |
|||
-- The name is compulsory when blacklist is used, so return nil if it is not supplied |
|||
if not fieldname or fieldname == "" then return false, nil end |
|||
-- If this field is on the blacklist, then return nil |
|||
if blacklist:find(fieldname) then return false, nil end |
|||
end |
|||
-- If we got this far then we're not on the blacklist |
|||
-- The blacklist overrides any locally supplied parameter as well |
|||
-- If a non-blank input parameter was supplied return it |
|||
if input_parm then return false, input_parm end |
|||
-- We can filter out non-valid properties |
|||
if property_id:sub(1,1):upper() ~="P" or property_id == "P0" then return false, nil end |
|||
-- Otherwise see if this field is on the whitelist: |
|||
-- needs a bit more logic because find will return its second value = 0 if fieldname is "" |
|||
-- but nil if fieldname not found on whitelist |
|||
local _, found = whitelist:find(fieldname) |
|||
found = ((found or 0) > 0) |
|||
if whitelist ~= 'ALL' and (whitelist:upper() == "NONE" or not found) then |
|||
return false, nil |
|||
end |
|||
-- See what's on Wikidata (the call always returns a table, but it may be empty): |
|||
local props = {} |
|||
if args.reqranks.b then |
|||
props = mw.wikibase.getBestStatements(qid, property_id) |
|||
else |
|||
props = mw.wikibase.getAllStatements(qid, property_id) |
|||
end |
|||
if props[1] then |
|||
return qid, props |
|||
end |
|||
-- no property on Wikidata |
|||
return false, nil |
|||
end |
end |
||
local function findNumberOfDecimals(number) |
|||
-- first, let's make it a string |
|||
------------------------------------------------------------------------------- |
|||
local numStr = tostring(tonumber(number)) |
|||
-- createicon assembles the "Edit at Wikidata" pen icon. |
|||
-- now let's get the decimals |
|||
-- It returns a wikitext string. |
|||
local integers,decimals = numStr:match('(%d+)%.(%d+)') |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: i18n[]; |
|||
return #decimals |
|||
------------------------------------------------------------------------------- |
|||
local createicon = function(langcode, entityID, propertyID) |
|||
local icon = " [[" .. i18n["filespace"] |
|||
icon = icon .. ":OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt=" |
|||
icon = icon .. i18n["editonwikidata"] |
|||
icon = icon .. "|link=https://www.wikidata.org/wiki/" .. entityID |
|||
icon = icon .. "?uselang=" .. langcode |
|||
if propertyID then icon = icon .. "#" .. propertyID end |
|||
icon = icon .. "|" .. i18n["editonwikidata"] .. "]]" |
|||
return icon |
|||
end |
end |
||
-- This is used to get a value |
|||
------------------------------------------------------------------------------- |
|||
-- if the boolean "list" is set, it will concatenate all available values in a comma-separated list |
|||
-- assembleoutput takes the sequence table containing the property values |
|||
-- if "dateformat" is set, it will look for qualifier-dates (P585, P580) and include in parathensis and format accordingly to the dateformat |
|||
-- and formats it according to switches given. It returns a string or nil. |
|||
local function getValue(propertyID, list, dateformat, edit, fallback, usesuffix, suffix_label, usebounds, value_from_wiki) |
|||
-- It needs the entityID and propertyID to create a link in the pen icon. |
|||
if value_from_wiki and #value_from_wiki and value_from_wiki ~= "" then |
|||
------------------------------------------------------------------------------- |
|||
return value_from_wiki |
|||
-- Dependencies: parseParam(); |
|||
------------------------------------------------------------------------------- |
|||
local assembleoutput = function(out, args, entityID, propertyID) |
|||
-- sorted is a boolean passed to enable sorting of the values returned |
|||
-- if nothing or an empty string is passed set it false |
|||
-- if "false" or "no" or "0" is passed set it false |
|||
local sorted = parseParam(args.sorted, false) |
|||
-- noicon is a boolean passed to suppress the trailing "edit at Wikidata" icon |
|||
-- for use when the value is processed further by the infobox |
|||
-- if nothing or an empty string is passed set it false |
|||
-- if "false" or "no" or "0" is passed set it false |
|||
local noic = parseParam(args.noicon, false) |
|||
-- list is the name of a template that a list of multiple values is passed through |
|||
-- examples include "hlist" and "ubl" |
|||
-- setting it to "prose" produces something like "1, 2, 3, and 4" |
|||
local list = args.list or "" |
|||
-- sep is a string that is used to separate multiple returned values |
|||
-- if nothing or an empty string is passed set it to the default |
|||
-- any double-quotes " are stripped out, so that spaces may be passed |
|||
-- e.g. |sep=" - " |
|||
local sepdefault = i18n["list separator"] |
|||
local separator = args.sep or "" |
|||
separator = string.gsub(separator, '"', '') |
|||
if separator == "" then |
|||
separator = sepdefault |
|||
end |
|||
-- collapse is a number that determines the maximum number of returned values |
|||
-- before the output is collapsed. |
|||
-- Zero or not a number result in no collapsing (default becomes 0). |
|||
local collapse = tonumber(args.collapse) or 0 |
|||
-- if there's anything to return, then return a list |
|||
-- comma-separated by default, but may be specified by the sep parameter |
|||
-- optionally specify a hlist or ubl or a prose list, etc. |
|||
local strout |
|||
if #out > 0 then |
|||
if sorted then table.sort(out) end |
|||
-- if a pen icon is wanted add it the end of the last value |
|||
if not noic then |
|||
out[#out] = out[#out] .. createicon(args.langobj.code, entityID, propertyID) |
|||
end |
|||
if list == "" then |
|||
strout = table.concat(out, separator) |
|||
elseif list:lower() == "prose" then |
|||
strout = mw.text.listToText( out ) |
|||
else |
|||
strout = mw.getCurrentFrame():expandTemplate{title = list, args = out} |
|||
end |
|||
if collapse >0 and #out > collapse then |
|||
strout = collapsediv .. strout .. "</div>" |
|||
end |
|||
else |
else |
||
local lang = mw.language.getContentLanguage() |
|||
strout = nil -- no items had valid reference |
|||
local fallbacklang = mw.language.getFallbacksFor( lang.code ) |
|||
end |
|||
local entity = mw.wikibase.getEntityObject() |
|||
return strout |
|||
local claims |
|||
end |
|||
if entity and entity.claims then |
|||
claims = entity.claims[propertyID] |
|||
------------------------------------------------------------------------------- |
|||
-- rendersnak takes a table (propval) containing the information stored on one property value |
|||
-- and returns the value as a string and its language if monolingual text. |
|||
-- It handles data of type: |
|||
-- wikibase-item |
|||
-- time |
|||
-- string, url, commonsMedia, external-id |
|||
-- quantity |
|||
-- globe-coordinate |
|||
-- monolingualtext |
|||
-- It also requires linked, the link/pre/postfixes, uabbr, and the arguments passed from frame. |
|||
-- The optional filter parameter allows quantities to be be filtered by unit Qid. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam(); labelOrId(); i18n[]; dateFormat(); |
|||
-- roundto(); decimalPrecision(); decimalToDMS(); linkedItem(); |
|||
------------------------------------------------------------------------------- |
|||
local rendersnak = function(propval, args, linked, lpre, lpost, pre, post, uabbr, filter) |
|||
lpre = lpre or "" |
|||
lpost = lpost or "" |
|||
pre = pre or "" |
|||
post = post or "" |
|||
args.lang = args.lang or findLang().code |
|||
-- allow values to display a fixed text instead of label |
|||
local dtxt = args.displaytext or args.dt |
|||
if dtxt == "" then dtxt = nil end |
|||
-- switch to use display of short name (P1813) instead of label |
|||
local shortname = args.shortname or args.sn |
|||
shortname = parseParam(shortname, false) |
|||
local snak = propval.mainsnak or propval |
|||
local dtype = snak.datatype |
|||
local dv = snak.datavalue |
|||
dv = dv and dv.value |
|||
-- value and monolingual text language code returned |
|||
local val, mlt |
|||
if propval.rank and not args.reqranks[propval.rank:sub(1, 1)] then |
|||
-- val is nil: value has a rank that isn't requested |
|||
------------------------------------ |
|||
elseif snak.snaktype == "somevalue" then -- value is unknown |
|||
val = i18n["Unknown"] |
|||
------------------------------------ |
|||
elseif snak.snaktype == "novalue" then -- value is none |
|||
-- val = "No value" -- don't return anything |
|||
------------------------------------ |
|||
elseif dtype == "wikibase-item" then -- data type is a wikibase item: |
|||
-- it's wiki-linked value, so output as link if enabled and possible |
|||
local qnumber = dv.id |
|||
if linked then |
|||
val = linkedItem(qnumber, lpre, lpost, pre, post, dtxt, shortname, args.lang) |
|||
else -- no link wanted so check for display-text, otherwise test for lang code |
|||
local label, islabel |
|||
if dtxt then |
|||
label = dtxt |
|||
else |
|||
label, islabel = labelOrId(qnumber) |
|||
local langlabel = mw.wikibase.getLabelByLang(qnumber, args.lang) |
|||
if langlabel then |
|||
label = mw.text.nowiki( langlabel ) |
|||
end |
|||
end |
|||
val = pre .. label .. post |
|||
end -- test for link required |
|||
------------------------------------ |
|||
elseif dtype == "time" then -- data type is time: |
|||
-- time is in timestamp format |
|||
-- date precision is integer per mediawiki |
|||
-- output formatting according to preferences (y/dmy/mdy) |
|||
-- BC format as BC or BCE |
|||
-- plaindate is passed to disable looking for "sourcing cirumstances" |
|||
-- or to set the adjectival form |
|||
-- qualifiers (if any) is a nested table or nil |
|||
-- lang is given, or user language, or site language |
|||
-- |
|||
-- Here we can check whether args.df has a value |
|||
-- If not, use code from Module:Sandbox/RexxS/Getdateformat to set it from templates like {{Use mdy dates}} |
|||
val = dateFormat(dv.time, dv.precision, args.df, args.bc, args.pd, propval.qualifiers, args.lang, "", dv.calendarmodel) |
|||
------------------------------------ |
|||
-- data types which are strings: |
|||
elseif dtype == "commonsMedia" or dtype == "external-id" or dtype == "string" or dtype == "url" then |
|||
-- commonsMedia or external-id or string or url |
|||
-- all have mainsnak.datavalue.value as string |
|||
if (lpre == "" or lpre == ":") and lpost == "" then |
|||
-- don't link if no linkpre/postfix or linkprefix is just ":" |
|||
val = pre .. dv .. post |
|||
elseif dtype == "external-id" then |
|||
val = "[" .. lpre .. dv .. lpost .. " " .. pre .. dv .. post .. "]" |
|||
else |
|||
val = "[[" .. lpre .. dv .. lpost .. "|" .. pre .. dv .. post .. "]]" |
|||
end -- check for link requested (i.e. either linkprefix or linkpostfix exists) |
|||
------------------------------------ |
|||
-- data types which are quantities: |
|||
elseif dtype == "quantity" then |
|||
-- quantities have mainsnak.datavalue.value.amount and mainsnak.datavalue.value.unit |
|||
-- the unit is of the form http://www.wikidata.org/entity/Q829073 |
|||
-- |
|||
-- implement a switch to turn on/off numerical formatting later |
|||
local fnum = true |
|||
-- |
|||
-- a switch to turn on/off conversions - only for en-wiki |
|||
local conv = parseParam(args.conv or args.convert, false) |
|||
-- if we have conversions, we won't have formatted numbers or scales |
|||
if conv then |
|||
uabbr = true |
|||
fnum = false |
|||
args.scale = "0" |
|||
end |
end |
||
local out = {} |
|||
-- |
|||
local highestrank = nil |
|||
-- a switch to turn on/off showing units, default is true |
|||
if claims then |
|||
local showunits = parseParam(args.su or args.showunits, true) |
|||
if (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == "wikibase-entityid") then |
|||
-- |
|||
-- if wiki-linked value output as link if possible |
|||
-- convert amount to a number |
|||
for k, v in pairs(claims) do |
|||
local amount = tonumber(dv.amount) or i18n["NaN"] |
|||
if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then |
|||
-- |
|||
out[#out + 1] = { output = getQValueLink("Q" .. v.mainsnak.datavalue.value["numeric-id"], fallback, fallbacklang) } |
|||
-- scale factor for millions, billions, etc. |
|||
-- now let's check for a suffix |
|||
local sc = tostring(args.scale or ""):sub(1,1):lower() |
|||
if usesuffix and v.mainsnak.datavalue.value.unit then |
|||
local scale |
|||
-- find Q-value |
|||
if sc == "a" then |
|||
local qval = "" |
|||
-- automatic scaling |
|||
_, _, qval = string.find(v.mainsnak.datavalue.value.unit, "^https*://www.wikidata.org/entity/(Q%d+)$") |
|||
if amount > 1e15 then |
|||
if qval and qval ~= "" then |
|||
local suffix = getQValueLink(qval, fallback, fallbacklang, suffix_label) |
|||
elseif amount > 1e12 then |
|||
if suffix then |
|||
out[#out].output = out[#out].output .. " " .. suffix |
|||
elseif amount > 1e9 then |
|||
end |
|||
end |
|||
elseif amount > 1e6 then |
|||
scale = 3 |
|||
else |
|||
scale = 0 |
|||
end |
|||
else |
|||
scale = tonumber(args.scale) or 0 |
|||
if scale < 0 or scale > 12 then scale = 0 end |
|||
scale = math.floor(scale/3) * 3 |
|||
end |
|||
local factor = 10^scale |
|||
amount = amount / factor |
|||
-- ranges: |
|||
local range = "" |
|||
-- check if upper and/or lower bounds are given and significant |
|||
local upb = tonumber(dv.upperBound) |
|||
local lowb = tonumber(dv.lowerBound) |
|||
if upb and lowb then |
|||
-- differences rounded to 2 sig fig: |
|||
local posdif = roundto(upb - amount, 2) / factor |
|||
local negdif = roundto(amount - lowb, 2) / factor |
|||
upb, lowb = amount + posdif, amount - negdif |
|||
-- round scaled numbers to integers or 4 sig fig |
|||
if (scale > 0 or sc == "a") then |
|||
if amount < 1e4 then |
|||
amount = roundto(amount, 4) |
|||
else |
|||
amount = math.floor(amount + 0.5) |
|||
end |
|||
end |
|||
if fnum then amount = args.langobj:formatNum( amount ) end |
|||
if posdif ~= negdif then |
|||
-- non-symmetrical |
|||
range = " +" .. posdif .. " -" .. negdif |
|||
elseif posdif ~= 0 then |
|||
-- symmetrical and non-zero |
|||
range = " ±" .. posdif |
|||
else |
|||
-- otherwise range is zero, so leave it as "" |
|||
end |
|||
else |
|||
-- round scaled numbers to integers or 4 sig fig |
|||
if (scale > 0 or sc == "a") then |
|||
if amount < 1e4 then |
|||
amount = roundto(amount, 4) |
|||
else |
|||
amount = math.floor(amount + 0.5) |
|||
end |
|||
end |
|||
if fnum then amount = args.langobj:formatNum( amount ) end |
|||
end |
|||
-- unit names and symbols: |
|||
-- extract the qid in the form 'Qnnn' from the value.unit url |
|||
-- and then fetch the label from that - or symbol if unitabbr is true |
|||
local unit = "" |
|||
local usep = "" |
|||
local usym = "" |
|||
local unitqid = string.match( dv.unit, "(Q%d+)" ) |
|||
if filter and unitqid ~= filter then return nil end |
|||
if unitqid and showunits then |
|||
local uname = mw.wikibase.getLabelByLang(unitqid, args.lang) or "" |
|||
if uname ~= "" then usep, unit = " ", uname end |
|||
if uabbr then |
|||
-- see if there's a unit symbol (P5061) |
|||
local unitsymbols = mw.wikibase.getAllStatements(unitqid, "P5061") |
|||
-- construct fallback table |
|||
local fbtbl = mw.language.getFallbacksFor( args.lang ) |
|||
table.insert( fbtbl, 1, args.lang ) |
|||
local found = false |
|||
for idx1, us in ipairs(unitsymbols) do |
|||
for idx2, fblang in ipairs(fbtbl) do |
|||
if us.mainsnak.datavalue.value.language == fblang then |
|||
usym = us.mainsnak.datavalue.value.text |
|||
found = true |
|||
break |
|||
end |
end |
||
if |
if dateformat then |
||
local date = getDate(v.qualifiers, dateformat, lang.code) |
|||
end -- loop through fallback table |
|||
if date then |
|||
end -- loop through values of P5061 |
|||
out[#out].output = out[#out].output .. " " .. date |
|||
if found then usep, unit = " ", usym end |
|||
end |
end |
||
end |
end |
||
out[#out].rank = v.rank |
|||
-- format display: |
|||
out[#out].order = getOrder(v.qualifiers) |
|||
if conv then |
|||
highestrank = compareRank(highestrank, v.rank) |
|||
if range == "" then |
|||
val = mw.getCurrentFrame():expandTemplate{title = "cvt", args = {amount, unit}} |
|||
else |
|||
val = mw.getCurrentFrame():expandTemplate{title = "cvt", args = {lowb, "to", upb, unit}} |
|||
end |
|||
elseif unit == "$" or unit == "£" then |
|||
val = unit .. amount .. range .. i18n.multipliers[scale] |
|||
else |
|||
val = amount .. range .. i18n.multipliers[scale] .. usep .. unit |
|||
end |
|||
------------------------------------ |
|||
-- datatypes which are global coordinates: |
|||
elseif dtype == "globe-coordinate" then |
|||
-- 'display' parameter defaults to "inline, title" *** unused for now *** |
|||
-- local disp = args.display or "" |
|||
-- if disp == "" then disp = "inline, title" end |
|||
-- |
|||
-- format parameter switches from deg/min/sec to decimal degrees |
|||
-- default is deg/min/sec -- decimal degrees needs |format = dec |
|||
local form = (args.format or ""):lower():sub(1,3) |
|||
if form ~= "dec" then form = "dms" end -- not needed for now |
|||
-- |
|||
-- show parameter allows just the latitude, or just the longitude, or both |
|||
-- to be returned as a signed decimal, ignoring the format parameter. |
|||
local show = (args.show or ""):lower() |
|||
if show ~= "longlat" then show = show:sub(1,3) end |
|||
-- |
|||
local lat, long, prec = dv.latitude, dv.longitude, dv.precision |
|||
if show == "lat" then |
|||
val = decimalPrecision(lat, prec) |
|||
elseif show == "lon" then |
|||
val = decimalPrecision(long, prec) |
|||
elseif show == "longlat" then |
|||
val = decimalPrecision(long, prec) .. ", " .. decimalPrecision(lat, prec) |
|||
else |
|||
local ns = "N" |
|||
local ew = "E" |
|||
if lat < 0 then |
|||
ns = "S" |
|||
lat = - lat |
|||
end |
|||
if long < 0 then |
|||
ew = "W" |
|||
long = - long |
|||
end |
|||
if form == "dec" then |
|||
lat = decimalPrecision(lat, prec) |
|||
long = decimalPrecision(long, prec) |
|||
val = lat .. "°" .. ns .. " " .. long .. "°" .. ew |
|||
else |
|||
local latdeg, latmin, latsec = decimalToDMS(lat, prec) |
|||
local longdeg, longmin, longsec = decimalToDMS(long, prec) |
|||
if latsec == 0 and longsec == 0 then |
|||
if latmin == 0 and longmin == 0 then |
|||
val = latdeg .. "°" .. ns .. " " .. longdeg .. "°" .. ew |
|||
else |
|||
val = latdeg .. "°" .. latmin .. "′" .. ns .. " " |
|||
val = val .. longdeg .. "°".. longmin .. "′" .. ew |
|||
end |
end |
||
else |
|||
val = latdeg .. "°" .. latmin .. "′" .. latsec .. "″" .. ns .. " " |
|||
val = val .. longdeg .. "°" .. longmin .. "′" .. longsec .. "″" .. ew |
|||
end |
end |
||
elseif (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == 'quantity') then |
|||
end |
|||
-- this is a quantity, output as value |
|||
end |
|||
for k, v in pairs(claims) do |
|||
------------------------------------ |
|||
if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then |
|||
elseif dtype == "monolingualtext" then -- data type is Monolingual text: |
|||
if v.mainsnak.datavalue.value['amount'] then |
|||
out[#out + 1] = { output = lang:formatNum(tonumber(v.mainsnak.datavalue.value['amount'])) } |
|||
-- collect all the values in 'out' and languages in 'mlt' and process them later |
|||
end |
|||
val = pre .. dv.text .. post |
|||
-- check for bounds |
|||
mlt = dv.language |
|||
if usebounds and v.mainsnak.datavalue.value['lowerBound'] and v.mainsnak.datavalue.value['upperBound'] then |
|||
------------------------------------ |
|||
local lowdiff = tonumber(v.mainsnak.datavalue.value['amount']) - tonumber(v.mainsnak.datavalue.value['lowerBound']) |
|||
else |
|||
local upperdiff = tonumber(v.mainsnak.datavalue.value['upperBound']) - tonumber(v.mainsnak.datavalue.value['amount']) |
|||
-- some other data type so write a specific handler |
|||
local numDec = findNumberOfDecimals(v.mainsnak.datavalue.value['amount']) |
|||
val = "unknown data type: " .. dtype |
|||
out[#out].output = out[#out].output .. " ±" .. tostring(roundToDecimalNum(lowdiff, numDec)) |
|||
end -- of datatype/unknown value/sourced check |
|||
end |
|||
return val, mlt |
|||
-- now let's check for a suffix |
|||
end |
|||
if usesuffix and v.mainsnak.datavalue.value.unit then |
|||
-- find Q-value |
|||
local qval = "" |
|||
------------------------------------------------------------------------------- |
|||
_, _, qval = string.find(v.mainsnak.datavalue.value.unit, "^https*://www.wikidata.org/entity/(Q%d+)$") |
|||
-- propertyvalueandquals takes a property object, the arguments passed from frame, |
|||
if qval and qval ~= "" then |
|||
-- and a qualifier propertyID. |
|||
local suffix = getQValueLink(qval, fallback, fallbacklang, suffix_label) |
|||
-- It returns a sequence (table) of values representing the values of that property |
|||
if suffix then |
|||
-- and qualifiers that match the qualifierID if supplied. |
|||
out[#out].output = out[#out].output .. " " .. suffix |
|||
------------------------------------------------------------------------------- |
|||
end |
|||
-- Dependencies: parseParam(); sourced(); labelOrId(); i18n.latestdatequalifier(); format_Date(); |
|||
-- makeOrdinal(); roundto(); decimalPrecision(); decimalToDMS(); assembleoutput(); |
|||
------------------------------------------------------------------------------- |
|||
local function propertyvalueandquals(objproperty, args, qualID) |
|||
-- needs this style of declaration because it's re-entrant |
|||
-- onlysourced is a boolean passed to return only values sourced to other than Wikipedia |
|||
-- if nothing or an empty string is passed set it true |
|||
local onlysrc = parseParam(args.onlysourced or args.osd, true) |
|||
-- linked is a a boolean that enables the link to a local page via sitelink |
|||
-- if nothing or an empty string is passed set it true |
|||
local linked = parseParam(args.linked, true) |
|||
-- prefix is a string that may be nil, empty (""), or a string of characters |
|||
-- this is prefixed to each value |
|||
-- useful when when multiple values are returned |
|||
-- any double-quotes " are stripped out, so that spaces may be passed |
|||
local prefix = (args.prefix or ""):gsub('"', '') |
|||
-- postfix is a string that may be nil, empty (""), or a string of characters |
|||
-- this is postfixed to each value |
|||
-- useful when when multiple values are returned |
|||
-- any double-quotes " are stripped out, so that spaces may be passed |
|||
local postfix = (args.postfix or ""):gsub('"', '') |
|||
-- linkprefix is a string that may be nil, empty (""), or a string of characters |
|||
-- this creates a link and is then prefixed to each value |
|||
-- useful when when multiple values are returned and indirect links are needed |
|||
-- any double-quotes " are stripped out, so that spaces may be passed |
|||
local lprefix = (args.linkprefix or args.lp or ""):gsub('"', '') |
|||
-- linkpostfix is a string that may be nil, empty (""), or a string of characters |
|||
-- this is postfixed to each value when linking is enabled with lprefix |
|||
-- useful when when multiple values are returned |
|||
-- any double-quotes " are stripped out, so that spaces may be passed |
|||
local lpostfix = (args.linkpostfix or ""):gsub('"', '') |
|||
-- wdlinks is a boolean passed to enable links to Wikidata when no article exists |
|||
-- if nothing or an empty string is passed set it false |
|||
local wdl = parseParam(args.wdlinks or args.wdl, false) |
|||
-- unitabbr is a boolean passed to enable unit abbreviations for common units |
|||
-- if nothing or an empty string is passed set it false |
|||
local uabbr = parseParam(args.unitabbr or args.uabbr, false) |
|||
-- qualsonly is a boolean passed to return just the qualifiers |
|||
-- if nothing or an empty string is passed set it false |
|||
local qualsonly = parseParam(args.qualsonly or args.qo, false) |
|||
-- maxvals is a string that may be nil, empty (""), or a number |
|||
-- this determines how many items may be returned when multiple values are available |
|||
-- setting it = 1 is useful where the returned string is used within another call, e.g. image |
|||
local maxvals = tonumber(args.maxvals) or 0 |
|||
-- pd (plain date) is a string: yes/true/1 | no/false/0 | adj |
|||
-- to disable/enable "sourcing cirumstances" or use adjectival form for the plain date |
|||
local pd = args.plaindate or args.pd or "no" |
|||
args.pd = pd |
|||
-- allow qualifiers to have a different date format; default to year |
|||
args.qdf = args.qdf or args.qualifierdateformat or args.df or "y" |
|||
local lang = args.lang or findlang().code |
|||
-- all proper values of a Wikidata property will be the same type as the first |
|||
-- qualifiers don't have a mainsnak, properties do |
|||
local datatype = objproperty[1].datatype or objproperty[1].mainsnak.datatype |
|||
-- out[] holds the values for this property |
|||
-- mlt[] holds the language code if the datatype is monolingual text |
|||
local out = {} |
|||
local mlt = {} |
|||
for k, v in ipairs(objproperty) do |
|||
local hasvalue = true |
|||
if (onlysrc and not sourced(v)) then |
|||
-- no value: it isn't sourced when onlysourced=true |
|||
hasvalue = false |
|||
else |
|||
local val, lcode = rendersnak(v, args, linked, lprefix, lpostfix, prefix, postfix, uabbr) |
|||
if not val then |
|||
hasvalue = false -- rank doesn't match |
|||
elseif qualsonly and qualID then |
|||
-- suppress value returned: only qualifiers are requested |
|||
else |
|||
out[#out+1], mlt[#out+1] = val, lcode |
|||
end |
|||
end |
|||
-- See if qualifiers are to be returned: |
|||
local snak = v.mainsnak or v |
|||
if hasvalue and v.qualifiers and qualID and snak.snaktype~="novalue" then |
|||
local qsep = (args.qsep or ""):gsub('"', '') |
|||
local qargs = { |
|||
["osd"] = "false", |
|||
["linked"] = tostring(linked), |
|||
["prefix"] = args.qprefix, |
|||
["postfix"] = args.qpostfix, |
|||
["linkprefix"] = args.qlinkprefix or args.qlp, |
|||
["linkpostfix"] = args.qlinkpostfix, |
|||
["wdl"] = "false", |
|||
["unitabbr"] = tostring(uabbr), |
|||
["maxvals"] = 0, |
|||
["sorted"] = tostring(args.qsorted), |
|||
["noicon"] = "true", |
|||
["list"] = args.qlist, |
|||
["sep"] = qsep, |
|||
["langobj"] = args.langobj, |
|||
["lang"] = args.langobj.code, |
|||
["df"] = args.qdf |
|||
} |
|||
local qlist = {} |
|||
local t1, t2 = "", "" |
|||
-- see if we want all qualifiers |
|||
if qualID == "ALL" then |
|||
if v["qualifiers-order"] then |
|||
-- the values in the order table are the keys for the qualifiers table: |
|||
for k1, v1 in ipairs(v["qualifiers-order"]) do |
|||
if v1 == "P1326" then |
|||
local ts = v.qualifiers[v1][1].datavalue.value.time |
|||
local dp = v.qualifiers[v1][1].datavalue.value.precision |
|||
qlist[#qlist + 1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "before") |
|||
elseif v1 == "P1319" then |
|||
local ts = v.qualifiers[v1][1].datavalue.value.time |
|||
local dp = v.qualifiers[v1][1].datavalue.value.precision |
|||
qlist[#qlist + 1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "after") |
|||
else |
|||
local q = assembleoutput(propertyvalueandquals(v.qualifiers[v1], qargs), qargs) |
|||
-- we already deal with circa via 'sourcing circumstances' |
|||
-- either linked or unlinked *** internationalise later *** |
|||
if q ~= "circa" and not (type(q) == "string" and q:find("circa]]")) then |
|||
qlist[#qlist + 1] = q |
|||
end |
end |
||
end |
end |
||
if dateformat then |
|||
local date = getDate(v.qualifiers, dateformat, lang.code) |
|||
else |
|||
if date then |
|||
-- are there cases where qualifiers-order doesn't exist? |
|||
out[#out].output = out[#out].output .. " " .. date |
|||
local ql = propertyvalueandquals(v.qualifiers, qargs) |
|||
end |
|||
for k1, v1 in ipairs(ql) do |
|||
-- we already deal with circa via 'sourcing circumstances' |
|||
-- either linked or unlinked *** internationalise later *** |
|||
if v1 ~= "circa" and not (type(v1) == "string" and v1:find("circa]]")) then |
|||
qlist[#qlist + 1] = v1 |
|||
end |
end |
||
out[#out].rank = v.rank |
|||
out[#out].order = getOrder(v.qualifiers) |
|||
highestrank = compareRank(highestrank, v.rank) |
|||
end |
end |
||
end |
end |
||
elseif (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == 'time') then |
|||
-- see if we want date/range |
|||
-- this is a quantity, output as value |
|||
elseif qualID == "DATES" then |
|||
for k, v in pairs(claims) do |
|||
qargs.maxvals = 1 |
|||
if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then |
|||
for k1, v1 in pairs(v.qualifiers) do |
|||
if v.mainsnak.datavalue.value['time'] then |
|||
if k1 == "P580" then -- P580 is "start time" |
|||
local timeformat = dateformat |
|||
t1 = propertyvalueandquals(v1, qargs)[1] or "" |
|||
if not timeformat or timeformat == "" then |
|||
timeformat = i18n['standard-timeformat'] |
|||
t2 = propertyvalueandquals(v1, qargs)[1] or "" |
|||
end |
|||
end |
|||
-- otherwise process qualID as a list of qualifiers |
|||
else |
|||
for q in mw.text.gsplit(qualID, "%p") do -- split at punctuation and iterate |
|||
q = mw.text.trim(q):upper() -- remove whitespace and capitalise |
|||
if q == "P1326" then |
|||
-- latest date, so supply 'before' as well. Assume one date value. |
|||
for k1, v1 in pairs(v.qualifiers) do |
|||
if k1 == "P1326" then |
|||
local ts = v1[1].datavalue.value.time |
|||
local dp = v1[1].datavalue.value.precision |
|||
qlist[#qlist + 1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "before") |
|||
end |
end |
||
out[#out + 1] = { output = mw.language.new(lang.code):formatDate(timeformat, v.mainsnak.datavalue.value.time) } |
|||
end |
end |
||
-- now let's check for a suffix |
|||
else |
|||
if usesuffix and v.mainsnak.datavalue.value.unit then |
|||
for k1, v1 in pairs(v.qualifiers) do |
|||
-- find Q-value |
|||
local qval = "" |
|||
_, _, qval = string.find(v.mainsnak.datavalue.value.unit, "^https*://www.wikidata.org/entity/(Q%d+)$") |
|||
for k2, v2 in ipairs(ql) do |
|||
if qval and qval ~= "" then |
|||
local suffix = getQValueLink(qval, fallback, fallbacklang, suffix_label) |
|||
if suffix then |
|||
out[#out].output = out[#out].output .. " " .. suffix |
|||
end |
end |
||
end |
end |
||
end |
end |
||
if dateformat then |
|||
local date = getDate(v.qualifiers, dateformat, lang.code) |
|||
if date then |
|||
end -- of testing for what qualID is |
|||
out[#out].output = out[#out].output .. " " .. date |
|||
local t = t1 .. t2 |
|||
-- *** internationalise date separators later *** |
|||
local dsep = "–" |
|||
if t:find("%s") or t:find(" ") then dsep = " – " end |
|||
if #qlist > 0 then |
|||
local qstr = assembleoutput(qlist, qargs) |
|||
if qualsonly then |
|||
out[#out+1] = qstr |
|||
else |
|||
out[#out] = out[#out] .. " (" .. qstr .. ")" |
|||
end |
|||
elseif t > "" then |
|||
if qualsonly then |
|||
out[#out+1] = t1 .. dsep .. t2 |
|||
else |
|||
out[#out] = out[#out] .. " (" .. t1 .. dsep .. t2 .. ")" |
|||
end |
|||
end |
|||
end -- of test for qualifiers wanted |
|||
if maxvals > 0 and #out >= maxvals then break end |
|||
end -- of for each value loop |
|||
-- we need to pick one value to return if the datatype was "monolingualtext" |
|||
-- if there's only one value, use that |
|||
-- otherwise look through the fallback languages for a match |
|||
if datatype == "monolingualtext" and #out >1 then |
|||
lang = mw.text.split( lang, '-', true )[1] |
|||
local fbtbl = mw.language.getFallbacksFor( lang ) |
|||
table.insert( fbtbl, 1, lang ) |
|||
local bestval = "" |
|||
local found = false |
|||
for idx1, lang1 in ipairs(fbtbl) do |
|||
for idx2, lang2 in ipairs(mlt) do |
|||
if (lang1 == lang2) and not found then |
|||
bestval = out[idx2] |
|||
found = true |
|||
break |
|||
end |
|||
end -- loop through values of property |
|||
end -- loop through fallback languages |
|||
if found then |
|||
-- replace output table with a table containing the best value |
|||
out = { bestval } |
|||
else |
|||
-- more than one value and none of them on the list of fallback languages |
|||
-- sod it, just give them the first one |
|||
out = { out[1] } |
|||
end |
|||
end |
|||
return out |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- Common code for p.getValueByQual and p.getValueByLang |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
local _getvaluebyqual = function(frame, qualID, checkvalue) |
|||
-- The property ID that will have a qualifier is the first unnamed parameter |
|||
local propertyID = mw.text.trim(frame.args[1] or "") |
|||
if propertyID == "" then return "no property supplied" end |
|||
if qualID == "" then return "no qualifier supplied" end |
|||
-- onlysourced is a boolean passed to return property values |
|||
-- only when property values are sourced to something other than Wikipedia |
|||
-- if nothing or an empty string is passed set it true |
|||
-- if "false" or "no" or 0 is passed set it false |
|||
local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true) |
|||
-- set the requested ranks flags |
|||
frame.args.reqranks = setRanks(frame.args.rank) |
|||
-- set a language object and code in the frame.args table |
|||
frame.args.langobj = findLang(frame.args.lang) |
|||
frame.args.lang = frame.args.langobj.code |
|||
local args = frame.args |
|||
-- check for locally supplied parameter in second unnamed parameter |
|||
-- success means no local parameter and the property exists |
|||
local qid, props = parseInput(frame, args[2], propertyID) |
|||
local linked = parseParam(args.linked, true) |
|||
local lpre = (args.linkprefix or args.lp or ""):gsub('"', '') |
|||
local lpost = (args.linkpostfix or ""):gsub('"', '') |
|||
local pre = (args.prefix or ""):gsub('"', '') |
|||
local post = (args.postfix or ""):gsub('"', '') |
|||
local uabbr = parseParam(args.unitabbr or args.uabbr, false) |
|||
local filter = (args.unit or ""):upper() |
|||
if filter == "" then filter = nil end |
|||
if qid then |
|||
local out = {} |
|||
-- Scan through the values of the property |
|||
-- we want something like property is "pronunciation audio (P443)" in propertyID |
|||
-- with a qualifier like "language of work or name (P407)" in qualID |
|||
-- whose value has the required ID, like "British English (Q7979)", in qval |
|||
for k1, v1 in ipairs(props) do |
|||
if v1.mainsnak.snaktype == "value" then |
|||
-- check if it has the right qualifier |
|||
local v1q = v1.qualifiers |
|||
if v1q and v1q[qualID] then |
|||
if onlysrc == false or sourced(v1) then |
|||
-- if we've got this far, we have a (sourced) claim with qualifiers |
|||
-- so see if matches the required value |
|||
-- We'll only deal with wikibase-items and strings for now |
|||
if v1q[qualID][1].datatype == "wikibase-item" then |
|||
if checkvalue(v1q[qualID][1].datavalue.value.id) then |
|||
out[#out + 1] = rendersnak(v1, args, linked, lpre, lpost, pre, post, uabbr, filter) |
|||
end |
|||
elseif v1q[qualID][1].datatype == "string" then |
|||
if checkvalue(v1q[qualID][1].datavalue.value) then |
|||
out[#out + 1] = rendersnak(v1, args, linked, lpre, lpost, pre, post, uabbr, filter) |
|||
end |
end |
||
end |
end |
||
out[#out].rank = v.rank |
|||
end -- of check for sourced |
|||
out[#out].order = getOrder(v.qualifiers) |
|||
end -- of check for matching required value and has qualifiers |
|||
highestrank = compareRank(highestrank, v.rank) |
|||
else |
|||
return nil |
|||
end -- of check for string |
|||
end -- of loop through values of propertyID |
|||
return assembleoutput(out, frame.args, qid, propertyID) |
|||
else |
|||
return props -- either local parameter or nothing |
|||
end -- of test for success |
|||
return nil |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- _location takes Q-id and follows P276 (location) |
|||
-- or P131 (located in the administrative territorial entity) or P706 (located on terrain feature) |
|||
-- from the initial item to higher level territories/locations until it reaches the highest. |
|||
-- An optional boolean, 'first', determines whether the first item is returned (default: false). |
|||
-- An optional boolean 'skip' toggles the display to skip to the last item (default: false). |
|||
-- It returns a table containing the locations - linked where possible, except for the highest. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: findLang(); labelOrId(); linkedItem |
|||
------------------------------------------------------------------------------- |
|||
local _location = function(qid, first, skip) |
|||
first = parseParam(first, false) |
|||
skip = parseParam(skip, false) |
|||
local locs = {"P276", "P131", "P706"} |
|||
local out = {} |
|||
local langcode = findLang():getCode() |
|||
local finished = false |
|||
local count = 0 |
|||
local prevqid = "Q0" |
|||
repeat |
|||
local prop |
|||
for i1, v1 in ipairs(locs) do |
|||
local proptbl = mw.wikibase.getBestStatements(qid, v1) |
|||
if #proptbl > 1 then |
|||
-- there is more than one higher location |
|||
local prevP131, prevP131id |
|||
if prevqid ~= "Q0" then |
|||
prevP131 = mw.wikibase.getBestStatements(prevqid, "P131")[1] |
|||
prevP131id = prevP131 |
|||
and prevP131.mainsnak.datavalue |
|||
and prevP131.mainsnak.datavalue.value.id |
|||
end |
|||
for i2, v2 in ipairs(proptbl) do |
|||
parttbl = v2.qualifiers and v2.qualifiers.P518 |
|||
if parttbl then |
|||
-- this higher location has qualifier 'applies to part' (P518) |
|||
for i3, v3 in ipairs(parttbl) do |
|||
if v3.snaktype == "value" and v3.datavalue.value.id == prevqid then |
|||
-- it has a value equal to the previous location |
|||
prop = proptbl[i2] |
|||
break |
|||
end -- of test for matching last location |
|||
end -- of loop through values of 'applies to part' |
|||
else |
|||
-- there's no qualifier 'applies to part' (P518) |
|||
-- so check if the previous location had a P131 that matches this alternate |
|||
if qid == prevP131id then |
|||
prop = proptbl[i2] |
|||
break |
|||
end -- of test for matching previous P131 |
|||
end |
end |
||
end -- of loop through parent locations |
|||
-- fallback to second value if match not found |
|||
prop = prop or proptbl[2] |
|||
elseif #proptbl > 0 then |
|||
prop = proptbl[1] |
|||
end |
|||
if prop then break end |
|||
end |
|||
-- check if it's an instance of (P31) a country (Q6256) and terminate the chain if it is |
|||
local inst = mw.wikibase.getAllStatements(qid, "P31") |
|||
if #inst > 0 then |
|||
for k, v in ipairs(inst) do |
|||
local instid = v.mainsnak.datavalue.value.id |
|||
-- stop if it's a country (or a country within the United Kingdom if skip is true) |
|||
if instid == "Q6256" or (skip and instid == "Q3336843") then |
|||
prop = nil -- this will ensure this is treated as top-level location |
|||
break |
|||
end |
end |
||
elseif (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == 'string') then |
|||
end |
|||
-- this is a string |
|||
end |
|||
for k, v in pairs(claims) do |
|||
if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then |
|||
-- get the name of this location and update qid to point to the parent location |
|||
if |
if v.mainsnak.datavalue.value then |
||
out[#out + 1] = { output = v.mainsnak.datavalue.value } |
|||
if not skip or count == 0 then |
|||
out[#out+1] = linkedItem(qid, ":", "", "", "") -- get a linked value if we can |
|||
end |
|||
qid, prevqid = prop.mainsnak.datavalue.value.id, qid |
|||
else |
|||
-- This is top-level location, so get short name except when this is the first item |
|||
-- Use full label if there's no short name or this is the first item |
|||
local prop1813 = mw.wikibase.getAllStatements(qid, "P1813") |
|||
-- if there's a short name and this isn't the only item |
|||
if prop1813[1] and (#out > 0)then |
|||
local shortname |
|||
-- short name is monolingual text, so look for match to the local language |
|||
-- choose the shortest 'short name' in that language |
|||
for k, v in pairs(prop1813) do |
|||
if v.mainsnak.datavalue.value.language == langcode then |
|||
local name = v.mainsnak.datavalue.value.text |
|||
if (not shortname) or (#name < #shortname) then |
|||
shortname = name |
|||
end |
end |
||
if dateformat then |
|||
local date = getDate(v.qualifiers, dateformat, lang.code) |
|||
if date then |
|||
out[#out].output = out[#out].output .. " " .. date |
|||
end |
|||
end |
|||
out[#out].rank = v.rank |
|||
out[#out].order = getOrder(v.qualifiers) |
|||
highestrank = compareRank(highestrank, v.rank) |
|||
end |
end |
||
end |
|||
-- add the shortname if one is found, fallback to the label |
|||
-- but skip it if it's "USA" |
|||
if shortname ~= "USA" then |
|||
out[#out+1] = shortname or labelOrId(qid) |
|||
else |
|||
if skip then out[#out+1] = "US" end |
|||
end |
end |
||
else |
else |
||
-- Unknown type |
|||
-- no shortname, so just add the label |
|||
out[#out + 1] = { output = 'unknown type ' .. claims[1].mainsnak.datavalue.type } |
|||
local loc = labelOrId(qid) |
|||
-- exceptions go here: |
|||
if loc == "United States of America" then |
|||
out[#out+1] = "United States" |
|||
else |
|||
out[#out+1] = loc |
|||
end |
|||
end |
end |
||
finished = true |
|||
end |
end |
||
-- Now we'll have to sort the table according to rank and order |
|||
count = count + 1 |
|||
sortTableRankAndOrder(out) |
|||
until finished or count >= 10 -- limit to 10 levels to avoid infinite loops |
|||
-- Now we'll make the output |
|||
local i = 0 |
|||
-- remove the first location if not quired |
|||
local ret = {} |
|||
if not first then table.remove(out, 1) end |
|||
while i < #out do |
|||
i = i + 1 |
|||
-- we might have duplicate text for consecutive locations, so remove them |
|||
-- check if the rank is within the highestrank |
|||
if #out > 2 then |
|||
if out[i].rank == highestrank then |
|||
local plain = {} |
|||
if list then |
|||
for i, v in ipairs(out) do |
|||
list = list - 1 |
|||
plain[i] = v:gsub("^%[%[[^|]*|", ""):gsub("]]$", "") |
|||
end |
|||
local idx = 2 |
|||
repeat |
|||
if plain[idx] == plain[idx-1] then |
|||
-- duplicate found |
|||
local removeidx = 0 |
|||
if (plain[idx] ~= out[idx]) and (plain[idx-1] == out[idx-1]) then |
|||
-- only second one is linked, so drop the first |
|||
removeidx = idx - 1 |
|||
elseif (plain[idx] == out[idx]) and (plain[idx-1] ~= out[idx-1]) then |
|||
-- only first one is linked, so drop the second |
|||
removeidx = idx |
|||
else |
|||
-- pick one |
|||
removeidx = idx - (os.time()%2) |
|||
end |
end |
||
table.remove(out, removeidx) |
|||
ret[#ret + 1] = out[i].output |
|||
table.remove(plain, removeidx) |
|||
if not list or list < 0 then |
|||
else |
|||
if i < #out then |
|||
-- We still have entries, show it |
|||
end |
|||
ret[#ret + 1] = '<abbr title="' .. i18n['wikidata-more-results-exists'] .. '>…</abbr>' |
|||
until idx >= #out |
|||
break |
|||
end |
|||
end |
|||
return out |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- _getsumofparts scans the property 'has part' (P527) for values matching a list. |
|||
-- The list (args.vlist) consists of a string of Qids separated by spaces or any usual punctuation. |
|||
-- If the matched values have a qualifer 'quantity' (P1114), those quantites are summed. |
|||
-- The sum is returned as a number (i.e. 0 if none) |
|||
-- a table of arguments is supplied implementing the usual parameters. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: setRanks; parseParam; parseInput; sourced; assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
local _getsumofparts = function(args) |
|||
local vallist = (args.vlist or ""):upper() |
|||
if vallist == "" then return end |
|||
args.reqranks = setRanks(args.rank) |
|||
local f = {} |
|||
f.args = args |
|||
local qid, props = parseInput(f, "", "P527") |
|||
if not qid then return 0 end |
|||
local onlysrc = parseParam(args.onlysourced or args.osd, true) |
|||
local sum = 0 |
|||
for k1, v1 in ipairs(props) do |
|||
if (onlysrc == false or sourced(v1)) |
|||
and v1.mainsnak.snaktype == "value" |
|||
and v1.mainsnak.datavalue.type == "wikibase-entityid" |
|||
and vallist:match( v1.mainsnak.datavalue.value.id ) |
|||
and v1.qualifiers |
|||
then |
|||
local quals = v1.qualifiers["P1114"] |
|||
if quals then |
|||
for k2, v2 in ipairs(quals) do |
|||
sum = sum + v2.datavalue.value.amount |
|||
end |
end |
||
end |
end |
||
end |
end |
||
return table.concat(ret, ", ") |
|||
end |
end |
||
return sum |
|||
end |
end |
||
-- This is used to get the name of the property with upper first case |
|||
local function getProperty(propertyID, propertyname_from_wiki) |
|||
------------------------------------------------------------------------------- |
|||
if propertyname_from_wiki and #propertyname_from_wiki then |
|||
------------------------------------------------------------------------------- |
|||
return propertyname_from_wiki |
|||
-- Public functions |
|||
------------------------------------------------------------------------------- |
|||
------------------------------------------------------------------------------- |
|||
-- _getValue makes the functionality of getValue available to other modules |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced; |
|||
-- labelOrId; i18n.latestdatequalifier; format_Date; makeOrdinal; roundto; decimalPrecision; decimalToDMS; |
|||
------------------------------------------------------------------------------- |
|||
p._getValue = function(args) |
|||
-- parameter sets for commonly used groups of parameters |
|||
local paraset = tonumber(args.ps or args.parameterset or 0) |
|||
if paraset == 1 then |
|||
-- a common setting |
|||
args.rank = "best" |
|||
args.fetchwikidata = "ALL" |
|||
args.onlysourced = "no" |
|||
args.noicon = "true" |
|||
elseif paraset == 2 then |
|||
-- equivalent to raw |
|||
args.rank = "best" |
|||
args.fetchwikidata = "ALL" |
|||
args.onlysourced = "no" |
|||
args.noicon = "true" |
|||
args.linked = "no" |
|||
args.pd = "true" |
|||
elseif paraset == 3 then |
|||
-- third set goes here |
|||
end |
|||
-- implement eid parameter |
|||
local eid = args.eid |
|||
if eid == "" then |
|||
return nil |
|||
elseif eid then |
|||
args.qid = eid |
|||
end |
|||
local propertyID = mw.text.trim(args[1] or "") |
|||
args.reqranks = setRanks(args.rank) |
|||
local f = {} |
|||
f.args = args |
|||
local entityid, props = parseInput(f, f.args[2], propertyID) |
|||
if not entityid then |
|||
return props -- either the input parameter or nothing |
|||
end |
|||
-- qual is a string containing the property ID of the qualifier(s) to be returned |
|||
-- if qual == "ALL" then all qualifiers returned |
|||
-- if qual == "DATES" then qualifiers P580 (start time) and P582 (end time) returned |
|||
-- if nothing or an empty string is passed set it nil -> no qualifiers returned |
|||
local qualID = mw.text.trim(args.qual or ""):upper() |
|||
if qualID == "" then qualID = nil end |
|||
-- set a language object and code in the args table |
|||
args.langobj = findLang(args.lang) |
|||
args.lang = args.langobj.code |
|||
-- table 'out' stores the return value(s): |
|||
local out = propertyvalueandquals(props, args, qualID) |
|||
-- format the table of values and return it as a string: |
|||
return assembleoutput(out, args, entityid, propertyID) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getValue is used to get the value(s) of a property |
|||
-- The property ID is passed as the first unnamed parameter and is required. |
|||
-- A locally supplied parameter may optionaly be supplied as the second unnamed parameter. |
|||
-- The function will now also return qualifiers if parameter qual is supplied |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced; |
|||
-- labelOrId; i18n.latestdatequalifier; format_Date; makeOrdinal; roundto; decimalPrecision; decimalToDMS; |
|||
------------------------------------------------------------------------------- |
|||
p.getValue = function(frame) |
|||
local args= frame.args |
|||
if not args[1] then |
|||
args = frame:getParent().args |
|||
if not args[1] then return i18n.errors["No property supplied"] end |
|||
end |
|||
return p._getValue(args) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getPreferredValue is used to get a value, |
|||
-- (or a comma separated list of them if multiple values exist). |
|||
-- If preferred ranks are set, it will return those values, otherwise values with normal ranks |
|||
-- now redundant to getValue with |rank=best |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: p.getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; |
|||
-- parseParam; sourced; labelOrId; i18n.latestdatequalifier; format_Date; |
|||
-- makeOrdinal; roundto; decimalPrecision; decimalToDMS; |
|||
------------------------------------------------------------------------------- |
|||
p.getPreferredValue = function(frame) |
|||
frame.args.rank = "best" |
|||
return p.getValue(frame) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getCoords is used to get coordinates for display in an infobox |
|||
-- whitelist and blacklist are implemented |
|||
-- optional 'display' parameter is allowed, defaults to "inline, title" |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: setRanks(); parseInput(); decimalPrecision(); |
|||
------------------------------------------------------------------------------- |
|||
p.getCoords = function(frame) |
|||
local propertyID = "P625" |
|||
-- if there is a 'display' parameter supplied, use it |
|||
-- otherwise default to "inline, title" |
|||
local disp = frame.args.display or "" |
|||
if disp == "" then |
|||
disp = "inline, title" |
|||
end |
|||
-- there may be a format parameter to switch from deg/min/sec to decimal degrees |
|||
-- default is deg/min/sec |
|||
-- decimal degrees needs |format = dec |
|||
local form = (frame.args.format or ""):lower():sub(1,3) |
|||
if form ~= "dec" then |
|||
form = "dms" |
|||
end |
|||
-- just deal with best values |
|||
frame.args.reqranks = setRanks("best") |
|||
local qid, props = parseInput(frame, frame.args[1], propertyID) |
|||
if not qid then |
|||
return props -- either local parameter or nothing |
|||
else |
else |
||
local |
local lang = mw.language.getContentLanguage() |
||
local out = mw.wikibase.label(propertyID) |
|||
local lat, long, prec = dv.latitude, dv.longitude, dv.precision |
|||
return lang:ucfirst(out) |
|||
lat = decimalPrecision(lat, prec) |
|||
long = decimalPrecision(long, prec) |
|||
local lat_long = { lat, long } |
|||
lat_long["display"] = disp |
|||
lat_long["format"] = form |
|||
-- invoke template Coord with the values stored in the table |
|||
return frame:expandTemplate{title = 'coord', args = lat_long} |
|||
end |
end |
||
end |
end |
||
-- This is used to get the type of the property |
|||
local function getUnitType(propertyID, value_from_wiki) |
|||
------------------------------------------------------------------------------- |
|||
if value_from_wiki and #value_from_wiki and value_from_wiki ~= "" then |
|||
-- getQualifierValue is used to get a formatted value of a qualifier |
|||
return value_from_wiki |
|||
-- |
|||
-- The call needs: a property (the unnamed parameter or 1=) |
|||
-- a target value for that property (pval=) |
|||
-- a qualifier for that target value (qual=) |
|||
-- The usual whitelisting and blacklisting of the property is implemented |
|||
-- The boolean onlysourced= parameter can be set to return nothing |
|||
-- when the property is unsourced (or only sourced to Wikipedia) |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam(); setRanks(); parseInput(); sourced(); |
|||
-- propertyvalueandquals(); assembleoutput(); |
|||
-- labelOrId(); i18n.latestdatequalifier(); format_Date(); |
|||
-- findLang(); makeOrdinal(); roundto(); decimalPrecision(); decimalToDMS(); |
|||
------------------------------------------------------------------------------- |
|||
p.getQualifierValue = function(frame) |
|||
-- The property ID that will have a qualifier is the first unnamed parameter |
|||
local propertyID = mw.text.trim(frame.args[1] or "") |
|||
-- The value of the property we want to match whose qualifier value is to be returned |
|||
-- is passed in named parameter |pval= |
|||
local propvalue = frame.args.pval |
|||
-- The property ID of the qualifier |
|||
-- whose value is to be returned is passed in named parameter |qual= |
|||
local qualifierID = frame.args.qual |
|||
-- onlysourced is a boolean passed to return qualifiers |
|||
-- only when property values are sourced to something other than Wikipedia |
|||
-- if nothing or an empty string is passed set it true |
|||
-- if "false" or "no" or 0 is passed set it false |
|||
local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true) |
|||
-- set a language object and language code in the frame.args table |
|||
frame.args.langobj = findLang(frame.args.lang) |
|||
frame.args.lang = frame.args.langobj.code |
|||
-- set the requested ranks flags |
|||
frame.args.reqranks = setRanks(frame.args.rank) |
|||
-- check for locally supplied parameter in second unnamed parameter |
|||
-- success means no local parameter and the property exists |
|||
local qid, props = parseInput(frame, frame.args[2], propertyID) |
|||
if qid then |
|||
local out = {} |
|||
-- Scan through the values of the property |
|||
-- we want something like property is P793, significant event (in propertyID) |
|||
-- whose value is something like Q385378, construction (in propvalue) |
|||
-- then we can return the value(s) of a qualifier such as P580, start time (in qualifierID) |
|||
for k1, v1 in pairs(props) do |
|||
if v1.mainsnak.snaktype == "value" and v1.mainsnak.datavalue.type == "wikibase-entityid" then |
|||
-- It's a wiki-linked value, so check if it's the target (in propvalue) |
|||
-- and if it has qualifiers |
|||
if v1.mainsnak.datavalue.value.id == propvalue and v1.qualifiers then |
|||
if onlysrc == false or sourced(v1) then |
|||
-- if we've got this far, we have a (sourced) claim with qualifiers |
|||
-- which matches the target, so find the value(s) of the qualifier we want |
|||
local quals = v1.qualifiers[qualifierID] |
|||
if quals then |
|||
-- can't reference qualifer, so set onlysourced = "no" (not boolean) |
|||
local qargs = frame.args |
|||
qargs.onlysourced = "no" |
|||
local vals = propertyvalueandquals(quals, qargs, qid) |
|||
for k, v in ipairs(vals) do |
|||
out[#out + 1] = v |
|||
end |
|||
end |
|||
end -- of check for sourced |
|||
end -- of check for matching required value and has qualifiers |
|||
end -- of check for wikibase entity |
|||
end -- of loop through values of propertyID |
|||
return assembleoutput(out, frame.args, qid, propertyID) |
|||
else |
else |
||
local lang = mw.language.getContentLanguage() |
|||
return props -- either local parameter or nothing |
|||
local fallbacklang = mw.language.getFallbacksFor( lang.code ) |
|||
end -- of test for success |
|||
local entity = mw.wikibase.getEntityObject(propertyID) |
|||
return nil |
|||
local claims |
|||
end |
|||
if entity and entity.claims then |
|||
claims = entity.claims['P2237'] |
|||
------------------------------------------------------------------------------- |
|||
-- getSumOfParts scans the property 'has part' (P527) for values matching a list. |
|||
-- The list is passed in parameter vlist. |
|||
-- It consists of a string of Qids separated by spaces or any usual punctuation. |
|||
-- If the matched values have a qualifier 'quantity' (P1114), those quantities are summed. |
|||
-- The sum is returned as a number or nothing if zero. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getsumofparts; |
|||
------------------------------------------------------------------------------- |
|||
p.getSumOfParts = function(frame) |
|||
local sum = _getsumofparts(frame.args) |
|||
if sum == 0 then return end |
|||
return sum |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getValueByQual gets the value of a property which has a qualifier with a given entity value |
|||
-- The call needs: |
|||
-- a property ID (the unnamed parameter or 1=Pxxx) |
|||
-- the ID of a qualifier for that property (qualID=Pyyy) |
|||
-- either the Wikibase-entity ID of a value for that qualifier (qvalue=Qzzz) |
|||
-- or a string value for that qualifier (qvalue=abc123) |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getvaluebyqual; parseParam; setRanks; parseInput; sourced; |
|||
-- assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getValueByQual = function(frame) |
|||
local qualID = frame.args.qualID |
|||
-- The Q-id of the value for the qualifier we want to match is in named parameter |qvalue= |
|||
local qval = frame.args.qvalue or "" |
|||
if qval == "" then return "no qualifier value supplied" end |
|||
local function checkQID(id) |
|||
return id == qval |
|||
end |
|||
return _getvaluebyqual(frame, qualID, checkQID) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getValueByLang gets the value of a property which has a qualifier P407 |
|||
-- ("language of work or name") whose value has the given language code |
|||
-- The call needs: |
|||
-- a property ID (the unnamed parameter or 1=Pxxx) |
|||
-- the MediaWiki language code to match the language (lang=xx[-yy]) |
|||
-- (if no code is supplied, it uses the default language) |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getvaluebyqual; parseParam; setRanks; parseInput; sourced; assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getValueByLang = function(frame) |
|||
-- The language code for the qualifier we want to match is in named parameter |lang= |
|||
local langcode = findLang(frame.args.lang).code |
|||
local function checkLanguage(id) |
|||
-- id should represent a language like "British English (Q7979)" |
|||
-- it should have string property "Wikimedia language code (P424)" |
|||
-- qlcode will be a table: |
|||
local qlcode = mw.wikibase.getBestStatements(id, "P424") |
|||
if (#qlcode > 0) and (qlcode[1].mainsnak.datavalue.value == langcode) then |
|||
return true |
|||
end |
end |
||
end |
|||
return _getvaluebyqual(frame, "P407", checkLanguage) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getValueByRefSource gets the value of a property which has a reference "stated in" (P248) |
|||
-- whose value has the given entity-ID. |
|||
-- The call needs: |
|||
-- a property ID (the unnamed parameter or 1=Pxxx) |
|||
-- the entity ID of a value to match where the reference is stated in (match=Qzzz) |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getValueByRefSource = function(frame) |
|||
-- The property ID that we want to check is the first unnamed parameter |
|||
local propertyID = mw.text.trim(frame.args[1] or ""):upper() |
|||
if propertyID == "" then return "no property supplied" end |
|||
-- The Q-id of the value we want to match is in named parameter |qvalue= |
|||
local qval = (frame.args.match or ""):upper() |
|||
if qval == "" then qval = "Q21540096" end |
|||
local unit = (frame.args.unit or ""):upper() |
|||
if unit == "" then unit = "Q4917" end |
|||
local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true) |
|||
-- set the requested ranks flags |
|||
frame.args.reqranks = setRanks(frame.args.rank) |
|||
-- set a language object and code in the frame.args table |
|||
frame.args.langobj = findLang(frame.args.lang) |
|||
frame.args.lang = frame.args.langobj.code |
|||
local linked = parseParam(frame.args.linked, true) |
|||
local uabbr = parseParam(frame.args.uabbr or frame.args.unitabbr, false) |
|||
-- qid not nil means no local parameter and the property exists |
|||
local qid, props = parseInput(frame, frame.args[2], propertyID) |
|||
if qid then |
|||
local out = {} |
local out = {} |
||
local |
local highestrank = nil |
||
if claims then |
|||
for k1, v1 in ipairs(props) do |
|||
if (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == "wikibase-entityid") then |
|||
if onlysrc == false or sourced(v1) then |
|||
-- if wiki-linked value output as link if possible |
|||
if v1.references then |
|||
for k, v in pairs(claims) do |
|||
if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then |
|||
local sitelink = mw.wikibase.sitelink("Q" .. v.mainsnak.datavalue.value["numeric-id"]) |
|||
for k3, v3 in ipairs(v2.snaks.P248) do |
|||
local label = mw.wikibase.label("Q" .. v.mainsnak.datavalue.value["numeric-id"]) |
|||
if label == nil then |
|||
out[#out+1], mlt[#out+1] = rendersnak(v1, frame.args, linked, "", "", "", "", uabbr, unit) |
|||
-- let's try the fallback-languages |
|||
if not mlt[#out] then |
|||
local checkQ = mw.wikibase.getEntityObject("Q" .. v.mainsnak.datavalue.value["numeric-id"]) |
|||
-- we only need one match per property value |
|||
if checkQ then |
|||
-- unless datatype was monolingual text |
|||
local i = 0 |
|||
while i < #fallbacklang do |
|||
i = i + 1 |
|||
label = checkQ:getLabel( fallbacklang[i] ) |
|||
if label ~= nil then |
|||
break |
break |
||
end |
end |
||
end |
end |
||
end -- of loop through values "stated in" |
|||
end |
|||
end -- of test that "stated in" exists |
|||
if label == nil then |
|||
-- no such luck, fall back to Q-values |
|||
label = "Q" .. v.mainsnak.datavalue.value["numeric-id"] |
|||
end -- of test for sourced |
|||
end -- of loop through values of propertyID |
|||
if #mlt > 0 then |
|||
local langcode = frame.args.lang |
|||
langcode = mw.text.split( langcode, '-', true )[1] |
|||
local fbtbl = mw.language.getFallbacksFor( langcode ) |
|||
table.insert( fbtbl, 1, langcode ) |
|||
local bestval = "" |
|||
local found = false |
|||
for idx1, lang1 in ipairs(fbtbl) do |
|||
for idx2, lang2 in ipairs(mlt) do |
|||
if (lang1 == lang2) and not found then |
|||
bestval = out[idx2] |
|||
found = true |
|||
break |
|||
end |
|||
end -- loop through values of property |
|||
end -- loop through fallback languages |
|||
if found then |
|||
-- replace output table with a table containing the best value |
|||
out = { bestval } |
|||
else |
|||
-- more than one value and none of them on the list of fallback languages |
|||
-- sod it, just give them the first one |
|||
out = { out[1] } |
|||
end |
|||
end |
|||
return assembleoutput(out, frame.args, qid, propertyID) |
|||
else |
|||
return props -- no property or local parameter supplied |
|||
end -- of test for success |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getPropertyIDs takes most of the usual parameters. |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented. |
|||
-- It returns the Entity-IDs (Qids) of the values of a property if it is a Wikibase-Entity. |
|||
-- Otherwise it returns nothing. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getPropertyIDs = function(frame) |
|||
local args = frame.args |
|||
args.reqranks = setRanks(args.rank) |
|||
args.langobj = findLang(args.lang) |
|||
args.lang = args.langobj.code |
|||
-- change default for noicon to true |
|||
args.noicon = tostring(parseParam(args.noicon or "", true)) |
|||
local f = {} |
|||
f.args = args |
|||
local pid = mw.text.trim(args[1] or "") |
|||
-- get the qid and table of claims for the property, or nothing and the local value passed |
|||
local qid, props = parseInput(f, args[2], pid) |
|||
if not qid then return props end |
|||
if not props[1] then return nil end |
|||
local onlysrc = parseParam(args.onlysourced or args.osd, true) |
|||
local maxvals = tonumber(args.maxvals) or 0 |
|||
out = {} |
|||
for i, v in ipairs(props) do |
|||
local snak = v.mainsnak |
|||
if ( snak.datatype == "wikibase-item" ) |
|||
and ( v.rank and args.reqranks[v.rank:sub(1, 1)] ) |
|||
and ( snak.snaktype == "value" ) |
|||
and ( sourced(v) or not onlysrc ) |
|||
then |
|||
out[#out+1] = snak.datavalue.value.id |
|||
end |
|||
if maxvals > 0 and #out >= maxvals then break end |
|||
end |
|||
return assembleoutput(out, args, qid, pid) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getPropOfProp takes two propertyIDs: prop1 and prop2 (as well as the usual parameters) |
|||
-- If the value(s) of prop1 are of type "wikibase-item" then it returns the value(s) of prop2 |
|||
-- of each of those wikibase-items. |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getPropOfProp = function(frame) |
|||
frame.args.reqranks = setRanks(frame.args.rank) |
|||
frame.args.langobj = findLang(frame.args.lang) |
|||
frame.args.lang = frame.args.langobj.code |
|||
local args = frame.args |
|||
local pid1 = args.prop1 or args.pid1 or "" |
|||
local pid2 = args.prop2 or args.pid2 or "" |
|||
local localval = mw.text.trim(args[1] or "") |
|||
if pid1 == "" or pid2 == "" then return nil end |
|||
local qid1, statements1 = parseInput(frame, localval, pid1) |
|||
if not qid1 then return localval end |
|||
local onlysrc = parseParam(args.onlysourced or args.osd, true) |
|||
local maxvals = tonumber(args.maxvals) or 0 |
|||
local qualID = mw.text.trim(args.qual or ""):upper() |
|||
if qualID == "" then qualID = nil end |
|||
local out = {} |
|||
for k, v in ipairs(statements1) do |
|||
if not onlysrc or sourced(v) then |
|||
local snak = v.mainsnak |
|||
if snak.datatype == "wikibase-item" and snak.snaktype == "value" then |
|||
local qid2 = snak.datavalue.value.id |
|||
local statements2 = {} |
|||
if args.reqranks.b then |
|||
statements2 = mw.wikibase.getBestStatements(qid2, pid2) |
|||
else |
|||
statements2 = mw.wikibase.getAllStatements(qid2, pid2) |
|||
end |
|||
if statements2[1] then |
|||
local out2 = propertyvalueandquals(statements2, args, qualID) |
|||
out[#out+1] = assembleoutput(out2, args, qid2, pid2) |
|||
end |
|||
end -- of test for valid property1 value |
|||
end -- of test for sourced |
|||
if maxvals > 0 and #out >= maxvals then break end |
|||
end -- of loop through values of property1 |
|||
return assembleoutput(out, args, qid1, pid1) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getAwardCat takes most of the usual parameters. If the item has values of P166 (award received), |
|||
-- then it examines each of those awards for P2517 (category for recipients of this award). |
|||
-- If it exists, it returns the corresponding category, |
|||
-- with the item's P734 (family name) as sort key, or no sort key if there is no family name. |
|||
-- The sort key may be overridden by the parameter |sortkey (alias |sk). |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getAwardCat = function(frame) |
|||
frame.args.reqranks = setRanks(frame.args.rank) |
|||
frame.args.langobj = findLang(frame.args.lang) |
|||
frame.args.lang = frame.args.langobj.code |
|||
local args = frame.args |
|||
args.sep = " " |
|||
local pid1 = args.prop1 or "P166" |
|||
local pid2 = args.prop2 or "P2517" |
|||
if pid1 == "" or pid2 == "" then return nil end |
|||
-- locally supplied value: |
|||
local localval = mw.text.trim(args[1] or "") |
|||
local qid1, statements1 = parseInput(frame, localval, pid1) |
|||
if not qid1 then return localval end |
|||
-- linkprefix (strip quotes) |
|||
local lp = (args.linkprefix or args.lp or ""):gsub('"', '') |
|||
-- sort key (strip quotes, hyphens and periods): |
|||
local sk = (args.sortkey or args.sk or ""):gsub('["-.]', '') |
|||
-- family name: |
|||
local famname = "" |
|||
if sk == "" then |
|||
local p734 = mw.wikibase.getBestStatements(qid1, "P734")[1] |
|||
local p734id = p734 and p734.mainsnak.snaktype == "value" and p734.mainsnak.datavalue.value.id or "" |
|||
famname = mw.wikibase.sitelink(p734id) or "" |
|||
-- strip namespace and disambigation |
|||
local pos = famname:find(":") or 0 |
|||
famname = famname:sub(pos+1):gsub("%s%(.+%)$", "") |
|||
if famname == "" then |
|||
local lbl = mw.wikibase.label(p734id) |
|||
famname = lbl and mw.text.nowiki(lbl) or "" |
|||
end |
|||
end |
|||
local onlysrc = parseParam(args.onlysourced or args.osd, true) |
|||
local maxvals = tonumber(args.maxvals) or 0 |
|||
local qualID = mw.text.trim(args.qual or ""):upper() |
|||
if qualID == "" then qualID = nil end |
|||
local out = {} |
|||
for k, v in ipairs(statements1) do |
|||
if not onlysrc or sourced(v) then |
|||
local snak = v.mainsnak |
|||
if snak.datatype == "wikibase-item" and snak.snaktype == "value" then |
|||
local qid2 = snak.datavalue.value.id |
|||
local statements2 = {} |
|||
if args.reqranks.b then |
|||
statements2 = mw.wikibase.getBestStatements(qid2, pid2) |
|||
else |
|||
statements2 = mw.wikibase.getAllStatements(qid2, pid2) |
|||
end |
|||
if statements2[1] and statements2[1].mainsnak.snaktype == "value" then |
|||
local qid3 = statements2[1].mainsnak.datavalue.value.id |
|||
local sitelink = mw.wikibase.sitelink(qid3) |
|||
-- if there's no local sitelink, create the sitelink from English label |
|||
if not sitelink then |
|||
local lbl = mw.wikibase.getLabelByLang(qid3, "en") |
|||
if lbl then |
|||
if lbl:sub(1,9) == "Category:" then |
|||
sitelink = mw.text.nowiki(lbl) |
|||
else |
|||
sitelink = "Category:" .. mw.text.nowiki(lbl) |
|||
end |
end |
||
end |
end |
||
if sitelink then |
if sitelink and sitelink ~= label then |
||
out[#out + 1] = { output = "[[" .. sitelink .. "|" .. label .. "]]" } |
|||
if sk ~= "" then |
|||
elseif sitelink then |
|||
out[#out + 1] = { output = "[[" .. sitelink .. "]]" } |
|||
elseif famname ~= "" then |
|||
out[#out+1] = "[[" .. lp .. sitelink .. "|" .. famname .. "]]" |
|||
else |
else |
||
if fallback then |
|||
out[#out+1] = "[[" .. lp .. sitelink .. "]]" |
|||
out[#out + 1] = { output = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]<abbr title='" .. i18n['wiki-article-not-available'] .. "'>[*]</abbr>" } |
|||
end -- of check for sort keys |
|||
end -- of test for sitelink |
|||
end -- of test for category |
|||
end -- of test for wikibase item has a value |
|||
end -- of test for sourced |
|||
if maxvals > 0 and #out >= maxvals then break end |
|||
end -- of loop through values of property1 |
|||
return assembleoutput(out, args, qid1, pid1) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getIntersectCat takes most of the usual parameters. |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented |
|||
-- It takes two properties, |prop1 and |prop2 (e.g. occupation and country of citizenship) |
|||
-- Each property's value is a wiki-base entity |
|||
-- For each value of the first parameter (ranks implemented) it fetches the value's main category |
|||
-- and then each value of the second parameter (possibly substituting a simpler description) |
|||
-- then it returns all of the categories representing the intersection of those properties, |
|||
-- (e.g. Category:Actors from Canada). A joining term may be supplied (e.g. |join=from). |
|||
-- The item's P734 (family name) is the sort key, or no sort key if there is no family name. |
|||
-- The sort key may be overridden by the parameter |sortkey (alias |sk). |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; |
|||
------------------------------------------------------------------------------- |
|||
p.getIntersectCat = function(frame) |
|||
frame.args.reqranks = setRanks(frame.args.rank) |
|||
frame.args.langobj = findLang(frame.args.lang) |
|||
frame.args.lang = frame.args.langobj.code |
|||
local args = frame.args |
|||
args.sep = " " |
|||
args.linked = "no" |
|||
local pid1 = args.prop1 or "P106" |
|||
local pid2 = args.prop2 or "P27" |
|||
if pid1 == "" or pid2 == "" then return nil end |
|||
local qid, statements1 = parseInput(frame, "", pid1) |
|||
if not qid then return nil end |
|||
local qid, statements2 = parseInput(frame, "", pid2) |
|||
if not qid then return nil end |
|||
-- topics like countries may have different names in categories from their label in Wikidata |
|||
local subs_exists, subs = pcall(mw.loadData, "Module:WikidataIB/subs") |
|||
local join = args.join or "" |
|||
local onlysrc = parseParam(args.onlysourced or args.osd, true) |
|||
local maxvals = tonumber(args.maxvals) or 0 |
|||
-- linkprefix (strip quotes) |
|||
local lp = (args.linkprefix or args.lp or ""):gsub('"', '') |
|||
-- sort key (strip quotes, hyphens and periods): |
|||
local sk = (args.sortkey or args.sk or ""):gsub('["-.]', '') |
|||
-- family name: |
|||
local famname = "" |
|||
if sk == "" then |
|||
local p734 = mw.wikibase.getBestStatements(qid, "P734")[1] |
|||
local p734id = p734 and p734.mainsnak.snaktype == "value" and p734.mainsnak.datavalue.value.id or "" |
|||
famname = mw.wikibase.sitelink(p734id) or "" |
|||
-- strip namespace and disambigation |
|||
local pos = famname:find(":") or 0 |
|||
famname = famname:sub(pos+1):gsub("%s%(.+%)$", "") |
|||
if famname == "" then |
|||
local lbl = mw.wikibase.label(p734id) |
|||
famname = lbl and mw.text.nowiki(lbl) or "" |
|||
end |
|||
end |
|||
local cat1 = {} |
|||
for k, v in ipairs(statements1) do |
|||
if not onlysrc or sourced(v) then |
|||
-- get the ID representing the value of the property |
|||
local pvalID = (v.mainsnak.snaktype == "value") and v.mainsnak.datavalue.value.id |
|||
if pvalID then |
|||
-- get the topic's main category (P910) for that entity |
|||
local p910 = mw.wikibase.getBestStatements(pvalID, "P910")[1] |
|||
if p910 and p910.mainsnak.snaktype == "value" then |
|||
local tmcID = p910.mainsnak.datavalue.value.id |
|||
-- use sitelink or the English label for the cat |
|||
local cat = mw.wikibase.sitelink(tmcID) |
|||
if not cat then |
|||
local lbl = mw.wikibase.getLabelByLang(tmcID, "en") |
|||
if lbl then |
|||
if lbl:sub(1,9) == "Category:" then |
|||
cat = mw.text.nowiki(lbl) |
|||
else |
else |
||
out[#out + 1] = { output = label } |
|||
end |
end |
||
end |
end |
||
out[#out].rank = v.rank |
|||
out[#out].order = getOrder(v.qualifiers) |
|||
highestrank = compareRank(highestrank, v.rank) |
|||
end |
end |
||
end |
|||
cat1[#cat1+1] = cat |
|||
end |
|||
end -- of test for topic's main category exists |
|||
end -- of test for property has vaild value |
|||
end -- of test for sourced |
|||
if maxvals > 0 and #cat1 >= maxvals then break end |
|||
end |
|||
local cat2 = {} |
|||
for k, v in ipairs(statements2) do |
|||
if not onlysrc or sourced(v) then |
|||
local cat = rendersnak(v, args) |
|||
if subs[cat] then cat = subs[cat] end |
|||
cat2[#cat2+1] = cat |
|||
end |
end |
||
-- Now we'll have to sort the table according to rank and order |
|||
if maxvals > 0 and #cat2 >= maxvals then break end |
|||
sortTableRankAndOrder(out) |
|||
end |
|||
-- Now we'll make the output |
|||
out = {} |
|||
local i = 0 |
|||
for k1, v1 in ipairs(cat1) do |
|||
local ret = {} |
|||
for k2, v2 in ipairs(cat2) do |
|||
local list = 0 |
|||
while i < #out do |
|||
out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "|" .. sk .. "]]" |
|||
i = i + 1 |
|||
-- check if the rank is within the highestrank |
|||
out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "|" .. famname .. "]]" |
|||
if out[i].rank == highestrank then |
|||
else |
|||
if list then |
|||
out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "]]" |
|||
list = list - 1 |
|||
end -- of check for sort keys |
|||
end |
end |
||
ret[#ret + 1] = out[i].output |
|||
args.noicon = "true" |
|||
if not list or list < 0 then |
|||
return assembleoutput(out, args, qid, pid1) |
|||
if i < #out then |
|||
end |
|||
break |
|||
------------------------------------------------------------------------------- |
|||
-- qualsToTable takes most of the usual parameters. |
|||
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented. |
|||
-- A qid may be given, and the first unnamed parameter is the property ID, which is of type wikibase item. |
|||
-- It takes a list of qualifier property IDs as |quals= |
|||
-- For a given qid and property, it creates the rows of an html table, |
|||
-- each row being a value of the property (optionally only if the property matches the value in |pval= ) |
|||
-- each cell being the first value of the qualifier corresponding to the list in |quals |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam; setRanks; parseInput; sourced; |
|||
------------------------------------------------------------------------------- |
|||
p.qualsToTable = function(frame) |
|||
local args = frame.args |
|||
local quals = args.quals or "" |
|||
if quals == "" then return "" end |
|||
args.reqranks = setRanks(args.rank) |
|||
local propertyID = mw.text.trim(args[1] or "") |
|||
local f = {} |
|||
f.args = args |
|||
local entityid, props = parseInput(f, "", propertyID) |
|||
if not entityid then return "" end |
|||
args.langobj = findLang(args.lang) |
|||
args.lang = args.langobj.code |
|||
local pval = args.pval or "" |
|||
local qplist = mw.text.split(quals, "%p") -- split at punctuation and make a sequential table |
|||
for i, v in ipairs(qplist) do |
|||
qplist[i] = mw.text.trim(v):upper() -- remove whitespace and capitalise |
|||
end |
|||
local col1 = args.firstcol or "" |
|||
if col1 ~= "" then |
|||
col1 = col1 .. "</td><td>" |
|||
end |
|||
local emptycell = args.emptycell or " " |
|||
-- construct a 2-D array of qualifier values in qvals |
|||
local qvals = {} |
|||
for i, v in ipairs(props) do |
|||
local skip = false |
|||
if pval ~= "" then |
|||
local pid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id |
|||
if pid ~= pval then skip = true end |
|||
end |
|||
if not skip then |
|||
local qval = {} |
|||
local vqualifiers = v.qualifiers or {} |
|||
-- go through list of wanted qualifier properties |
|||
for i1, v1 in ipairs(qplist) do |
|||
-- check for that property ID in the statement's qualifiers |
|||
local qv, qtype |
|||
if vqualifiers[v1] then |
|||
qtype = vqualifiers[v1][1].datatype |
|||
if qtype == "time" then |
|||
if vqualifiers[v1][1].snaktype == "value" then |
|||
qv = mw.wikibase.renderSnak(vqualifiers[v1][1]) |
|||
qv = frame:expandTemplate{title="dts", args={qv}} |
|||
else |
|||
qv = "?" |
|||
end |
|||
elseif qtype == "url" then |
|||
qv = mw.wikibase.renderSnak(vqualifiers[v1][1]) |
|||
local display = mw.ustring.match( mw.uri.decode(qv, "WIKI"), "([%w ]+)$" ) |
|||
if display then |
|||
qv = "[" .. qv .. " " .. display .. "]" |
|||
end |
|||
else |
|||
qv = mw.wikibase.formatValue(vqualifiers[v1][1]) |
|||
end |
end |
||
end |
end |
||
end |
|||
-- record either the value or a placeholder |
|||
qval[i1] = qv or emptycell |
|||
end -- of loop through list of qualifiers |
|||
-- add the list of qualifier values as a "row" in the main list |
|||
qvals[#qvals+1] = qval |
|||
end |
end |
||
local ent = mw.wikibase.getEntityObject() |
|||
end -- of for each value loop |
|||
ret[#ret + 1] = dump(ent.claims) |
|||
return table.concat(ret, ", ") |
|||
local out = {} |
|||
for i, v in ipairs(qvals) do |
|||
out[i] = "<tr><td>" .. col1 .. table.concat(qvals[i], "</td><td>") .. "</td></tr>" |
|||
end |
end |
||
return table.concat(out, "\n") |
|||
end |
end |
||
function p.getPropertyUnit(frame) |
|||
getArguments(frame) |
|||
return getUnitType(arguments.property, arguments.wiki_value) |
|||
end |
|||
local function addLinkback(str, property) |
|||
------------------------------------------------------------------------------- |
|||
local id = mw.wikibase.getEntityObject() |
|||
-- getGlobe takes an optional qid of a Wikidata entity passed as |qid= |
|||
if not id then |
|||
-- otherwise it uses the linked item for the current page. |
|||
return str |
|||
-- If returns the Qid of the globe used in P625 (coordinate location), |
|||
-- or nil if there isn't one. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getGlobe = function(frame) |
|||
local qid = frame.args.qid or frame.args[1] or "" |
|||
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
local coords = mw.wikibase.getBestStatements(qid, "P625")[1] |
|||
local globeid |
|||
if coords and coords.mainsnak.snaktype == "value" then |
|||
globeid = coords.mainsnak.datavalue.value.globe:match("(Q%d+)") |
|||
end |
end |
||
if type(id) == 'table' then |
|||
return globeid |
|||
id = id.id |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getCommonsLink takes an optional qid of a Wikidata entity passed as |qid= |
|||
-- It returns one of the following in order of preference: |
|||
-- the Commons sitelink of the linked Wikidata item; |
|||
-- the Commons sitelink of the topic's main category of the linked Wikidata item; |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getCommonslink(); _getSitelink(); parseParam() |
|||
------------------------------------------------------------------------------- |
|||
p.getCommonsLink = function(frame) |
|||
local oc = frame.args.onlycat or frame.args.onlycategories |
|||
local fb = parseParam(frame.args.fallback or frame.args.fb, true) |
|||
return _getCommonslink(frame.args.qid, oc, fb) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getSitelink takes the qid of a Wikidata entity passed as |qid= |
|||
-- It takes an optional parameter |wiki= to determine which wiki is to be checked for a sitelink |
|||
-- If the parameter is blank, then it uses the local wiki. |
|||
-- If there is a sitelink to an article available, it returns the plain text link to the article |
|||
-- If there is no sitelink, it returns nil. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getSiteLink = function(frame) |
|||
return _getSitelink(frame.args.qid, frame.args.wiki or mw.text.trim(frame.args[1] or "")) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getLink has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= |
|||
-- If there is a sitelink to an article on the local Wiki, it returns a link to the article |
|||
-- with the Wikidata label as the displayed text. |
|||
-- If there is no sitelink, it returns the label as plain text. |
|||
-- If there is no label in the local language, it displays the qid instead. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getLink = function(frame) |
|||
local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "") |
|||
if itemID == "" then return end |
|||
local sitelink = mw.wikibase.sitelink(itemID) |
|||
local label = labelOrId(itemID) |
|||
if sitelink then |
|||
return "[[:" .. sitelink .. "|" .. label .. "]]" |
|||
else |
|||
return label |
|||
end |
end |
||
end |
|||
local class = '' |
|||
if property then |
|||
class = 'wd_' .. string.lower(property) |
|||
------------------------------------------------------------------------------- |
|||
-- getLabel has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= |
|||
-- It returns the Wikidata label for the local language as plain text. |
|||
-- If there is no label in the local language, it displays the qid instead. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getLabel = function(frame) |
|||
local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "") |
|||
if itemID == "" then return end |
|||
local lang = frame.args.lang or "" |
|||
if lang == "" then lang = nil end |
|||
local label = labelOrId(itemID, lang) |
|||
return label |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getAT (Article Title) |
|||
-- has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= |
|||
-- If there is a sitelink to an article on the local Wiki, it returns the sitelink as plain text. |
|||
-- If there is no sitelink, it returns nothing. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getAT = function(frame) |
|||
local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "") |
|||
if itemID == "" then return end |
|||
return mw.wikibase.sitelink(itemID) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getDescription has the qid of a Wikidata entity passed as |qid= |
|||
-- (it defaults to the associated qid of the current article if omitted) |
|||
-- and a local parameter passed as the first unnamed parameter. |
|||
-- Any local parameter passed (other than "Wikidata" or "none") becomes the return value. |
|||
-- It returns the article description for the Wikidata entity if the local parameter is "Wikidata". |
|||
-- Nothing is returned if the description doesn't exist or "none" is passed as the local parameter. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getDescription = function(frame) |
|||
local desc = mw.text.trim(frame.args[1] or "") |
|||
local itemID = mw.text.trim(frame.args.qid or "") |
|||
if itemID == "" then itemID = nil end |
|||
if desc:lower() == 'wikidata' then |
|||
return mw.wikibase.description(itemID) |
|||
elseif desc:lower() == 'none' then |
|||
return nil |
|||
else |
|||
return desc |
|||
end |
end |
||
local title = i18n['wikidata-linkback-edit'] |
|||
local icon = '[%s [[File:Blue pencil.svg|%s|10px|baseline|link=]] ]' |
|||
local url = mw.uri.fullUrl('d:' .. id .. '#' .. property, 'uselang=nb') |
|||
url.fragment = property |
|||
url = tostring(url) |
|||
local v = mw.html.create('span') |
|||
:addClass(class) |
|||
:wikitext(str) |
|||
:tag('span') |
|||
:addClass('noprint plainlinks wikidata-linkback') |
|||
:css('padding-left', '.5em') |
|||
:wikitext(icon:format(url, title)) |
|||
:allDone() |
|||
return tostring(v) |
|||
end |
end |
||
-- |
|||
-- Denne funksjonen kalles opp slik: {{#invoke:WikidataIB|rowProperty|P26}} |
|||
------------------------------------------------------------------------------- |
|||
-- den vil da returnere en tekst-streng som er en rad i en infoboks slik: <tr class="rad" valign="top"><th colspan="2">[Property-navn]</th><td colspan="2">[claim]</td></tr> |
|||
-- getAliases has the qid of a Wikidata entity passed as |qid= |
|||
-- property-navn og claim hentes fra wikidata |
|||
-- (it defaults to the associated qid of the current article if omitted) |
|||
-- andre argumenter som kan benyttes: |
|||
-- and a local parameter passed as the first unnamed parameter. |
|||
-- property - angir hvilken property som skal benyttes, alternativ måte å spesifisere på: {{#invoke:WikidataIB|rowProperty|property=P26}} |
|||
-- It implements blacklisting and whitelisting with a field name of "alias" by default. |
|||
-- liste - angir at hvis det er flere verdier under en property skal de listes ut slik: <tr class="rad" valign="top"><th colspan="2">[Property-navn]</th><td colspan="2">[claim1], [claim2], ...</td></tr> |
|||
-- Any local parameter passed becomes the return value. |
|||
-- angis slik: {{#invoke:WikidataIB|rowProperty|P26|liste=1}} |
|||
-- Otherwise it returns the aliases for the Wikidata entity with the usual list options. |
|||
-- dato - angir om verdiene skal legges inn med dato i parantes i etterkant slik: <tr class="rad" valign="top"><th colspan="2">[Property-navn]</th><td colspan="2">[claim] (dato)</td></tr> |
|||
-- Nothing is returned if the aliases do not exist. |
|||
-- angis slik: {{#invoke:WikidataIB|rowProperty|P26|dato=<datoformat>}}, f.eks. {{#invoke:WikidataIB|rowProperty|P26|dato=j. F Y}} vil gi (31. desember 2015) |
|||
------------------------------------------------------------------------------- |
|||
-- denne kan også kombineres med "liste" |
|||
-- Dependencies: findLang(); assembleoutput() |
|||
-- verdi - standardverdi som benyttes dersom wikidata ikke har noen claims/verdier for den angitte egenskapen (property). Må da også spesifiseres sammen med "propertynavn". |
|||
------------------------------------------------------------------------------- |
|||
-- angis slik: {{#invoke:WikidataIB|rowProperty|P26|verdi=Ola Normann}} |
|||
p.getAliases = function(frame) |
|||
-- pnavn - egenskapsnavn som benyttes dersom wikidata ikke har den angitte egenskapen (property). |
|||
local args = frame.args |
|||
-- angis slik: {{#invoke:WikidataIB|rowProperty|P26|pnavn=Ektefelle}} |
|||
-- noedit - angir om en "editeringslink" som peker mot Wikidata IKKE skal legges på raden. Kun tilgjengelig hvis alle data hentes fra Wikidata. |
|||
local fieldname = args.name or "" |
|||
-- angis slik: {{#invoke:WikidataIB|rowProperty|P26|noedit=1}} |
|||
if fieldname == "" then fieldname = "alias" end |
|||
-- fallback - angir om lenker skal opprettes mot wikidata hvis lokal artikkel ikke finnes |
|||
-- angis slik: {{#invoke:WikidataIB|rowProperty|P26|fallback=1}} |
|||
local blacklist = args.suppressfields or args.spf or "" |
|||
-- |
|||
if blacklist:find(fieldname) then return nil end |
|||
function p.rowProperty(frame) |
|||
getArguments(frame) |
|||
local localval = mw.text.trim(args[1] or "") |
|||
local value = getValue(arguments.property, arguments.list, arguments.date, arguments.edit, arguments.fallback, arguments.usesuffix, arguments.suffix_from_wiki, arguments.usebounds, arguments.wiki_value) |
|||
if localval ~= "" then return localval end |
|||
local retval = "" |
|||
if value and value ~= "" then |
|||
local whitelist = args.fetchwikidata or args.fwd or "" |
|||
retval = retval .. '<tr class="rad" valign="top"><th colspan="2">' .. getProperty(arguments.property, arguments.label) .. '</th><td colspan="2"' |
|||
if whitelist == "" then whitelist = "NONE" end |
|||
if arguments.list then |
|||
if not (whitelist == 'ALL' or whitelist:find(fieldname)) then return nil end |
|||
retval = retval .. ' class="reducible"' |
|||
local qid = mw.text.trim(args.qid or "") |
|||
if qid == "" then qid = nil end |
|||
local entity = mw.wikibase.getEntity(qid) |
|||
if not entity then return nil end |
|||
local aliases = entity.aliases |
|||
if not aliases then return nil end |
|||
if not qid then qid= mw.wikibase.getEntityIdForCurrentPage() end |
|||
args.langobj = findLang(args.lang) |
|||
local langcode = args.langobj.code |
|||
args.lang = langcode |
|||
local out = {} |
|||
for k1, v1 in pairs(aliases) do |
|||
if v1[1].language == langcode then |
|||
for k1, v2 in ipairs(v1) do |
|||
out[#out+1] = v2.value |
|||
end |
|||
break |
|||
end |
end |
||
retval = retval .. '>' |
|||
end |
|||
if arguments.edit and (not arguments.wiki_value or arguments.wiki_value == "") then |
|||
retval = retval .. addLinkback(value, arguments.property) |
|||
return assembleoutput(out, args, qid) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- pageId returns the page id (entity ID, Qnnn) of the current page |
|||
-- returns nothing if the page is not connected to Wikidata |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.pageId = function(frame) |
|||
return mw.wikibase.getEntityIdForCurrentPage() |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- formatDate is a wrapper to export the private function format_Date |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: format_Date(); |
|||
------------------------------------------------------------------------------- |
|||
p.formatDate = function(frame) |
|||
return format_Date(frame.args[1], frame.args.df, frame.args.bc) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- location is a wrapper to export the private function _location |
|||
-- it takes the entity-id as qid or the first unnamed parameter |
|||
-- optional boolean parameter first toggles the display of the first item |
|||
-- optional boolean parameter skip toggles the display to skip to the last item |
|||
-- parameter debug=<y/n> (default 'n') adds error msg if not a location |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _location(); |
|||
------------------------------------------------------------------------------- |
|||
p.location = function(frame) |
|||
local debug = (frame.args.debug or ""):sub(1, 1):lower() |
|||
if debug == "" then debug = "n" end |
|||
local qid = mw.text.trim(frame.args.qid or frame.args[1] or ""):upper() |
|||
if qid == "" then qid=mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then |
|||
if debug ~= "n" then |
|||
return i18n.errors["entity-not-found"] |
|||
else |
else |
||
retval = retval .. value |
|||
return nil |
|||
end |
end |
||
retval = retval .. '</td></tr>' |
|||
end |
end |
||
return retval |
|||
local first = mw.text.trim(frame.args.first or "") |
|||
local skip = mw.text.trim(frame.args.skip or "") |
|||
return table.concat( _location(qid, first, skip), ", " ) |
|||
end |
end |
||
function p.getPropertyValue(frame) |
|||
------------------------------------------------------------------------------- |
|||
-- Get argument "property" |
|||
-- checkBlacklist implements a test to check whether a named field is allowed |
|||
getArguments(frame) |
|||
-- returns true if the field is not blacklisted (i.e. allowed) |
|||
local value = getValue(arguments.property, arguments.list, arguments.date, arguments.edit, arguments.fallback, arguments.usesuffix, arguments.suffix_from_wiki, arguments.usebounds, arguments.wiki_value) |
|||
-- returns false if the field is blacklisted (i.e. disallowed) |
|||
local retval = "" |
|||
-- {{#if:{{#invoke:WikidataIB |checkBlacklist |name=Joe |suppressfields=Dave; Joe; Fred}} | not blacklisted | blacklisted}} |
|||
if value and value ~= "" then |
|||
-- displays "blacklisted" |
|||
if arguments.edit and (not arguments.wiki_value or arguments.wiki_value == "") then |
|||
-- {{#if:{{#invoke:WikidataIB |checkBlacklist |name=Jim |suppressfields=Dave; Joe; Fred}} | not blacklisted | blacklisted}} |
|||
retval = addLinkback(value, arguments.property) |
|||
-- displays "not blacklisted" |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.checkBlacklist = function(frame) |
|||
local blacklist = frame.args.suppressfields or frame.args.spf or "" |
|||
local fieldname = frame.args.name or "" |
|||
if blacklist ~= "" and fieldname ~= "" then |
|||
if blacklist:find(fieldname) then |
|||
return false |
|||
else |
else |
||
retval = value |
|||
end |
end |
||
else |
|||
-- one of the fields is missing: let's call that "not on the list" |
|||
return true |
|||
end |
end |
||
return retval |
|||
end |
end |
||
function p.getPropertyLabel(frame) |
|||
getArguments(frame) |
|||
------------------------------------------------------------------------------- |
|||
return getProperty(arguments.property, arguments.label) |
|||
-- emptyor returns nil if its first unnamed argument is just punctuation, whitespace or html tags |
|||
-- otherwise it returns the argument unchanged (including leading/trailing space). |
|||
-- If the argument may contain "=", then it must be called explicitly: |
|||
-- |1=arg |
|||
-- (In that case, leading and trailing spaces are trimmed) |
|||
-- It finds use in infoboxes where it can replace tests like: |
|||
-- {{#if: {{#invoke:WikidatIB |getvalue |P99 |fwd=ALL}} | <span class="xxx">{{#invoke:WikidatIB |getvalue |P99 |fwd=ALL}}</span> | }} |
|||
-- with a form that uses just a single call to Wikidata: |
|||
-- {{#invoke |WikidataIB |emptyor |1= <span class="xxx">{{#invoke:WikidataIB |getvalue |P99 |fwd=ALL}}</span> }} |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.emptyor = function(frame) |
|||
local s = frame.args[1] or "" |
|||
if s == "" then return nil end |
|||
local sx = s:gsub("%s", ""):gsub("<[^>]*>", ""):gsub("%p", "") |
|||
if sx == "" then |
|||
return nil |
|||
else |
|||
return s |
|||
end |
|||
end |
end |
||
function p.dumpProperty(frame) |
|||
getArguments(frame) |
|||
------------------------------------------------------------------------------- |
|||
local entity = mw.wikibase.getEntityObject(arguments.property) |
|||
-- labelorid is a public function to expose the output of labelOrId() |
|||
return dump(entity) |
|||
-- Pass the Q-number as |qid= or as an unnamed parameter. |
|||
-- It returns the Wikidata label for that entity or the qid if no label exists. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: labelOrId |
|||
------------------------------------------------------------------------------- |
|||
p.labelorid = function(frame) |
|||
return labelOrId( frame.args.qid or frame.args[1] ) |
|||
end |
end |
||
function p.dumpClaims(frame) |
|||
getArguments(frame) |
|||
------------------------------------------------------------------------------- |
|||
local entity = mw.wikibase.getEntityObject() |
|||
-- getLang returns the MediaWiki language code of the current content. |
|||
local claims = nil |
|||
-- If optional parameter |style=full, it returns the language name. |
|||
local retval = "" |
|||
------------------------------------------------------------------------------- |
|||
if entity and entity.claims and arguments.property then |
|||
-- Dependencies: none |
|||
claims = entity.claims[arguments.property] |
|||
------------------------------------------------------------------------------- |
|||
elseif entity and entity.claims then |
|||
p.getLang = function(frame) |
|||
claims = entity.claims |
|||
local style = (frame.args.style or ""):lower() |
|||
local langcode = mw.language.getContentLanguage().code |
|||
if style == "full" then |
|||
return mw.language.fetchLanguageName( langcode ) |
|||
end |
end |
||
if claims then |
|||
return langcode |
|||
retval = dump(claims) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getItemLangCode takes a qid parameter (using the current page's qid if blank) |
|||
-- If the item for that qid has property country (P17) it looks at the first preferred value |
|||
-- If the country has an official language (P37), it looks at the first preferred value |
|||
-- If that official language has a language code (P424), it returns the first preferred value |
|||
-- Otherwise it returns nothing. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: _getItemLangCode() |
|||
------------------------------------------------------------------------------- |
|||
p.getItemLangCode = function(frame) |
|||
return _getItemLangCode(frame.args.qid or frame.args[1]) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- findLanguage exports the local findLang() function |
|||
-- It takes an optional language code and returns, in order of preference: |
|||
-- the code if a known language; |
|||
-- the user's language, if set; |
|||
-- the server's content language. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: findLang |
|||
------------------------------------------------------------------------------- |
|||
p.findLanguage = function(frame) |
|||
return findLang(frame.args.lang or frame.args[1]).code |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getQid returns the qid, if supplied |
|||
-- failing that, the Wikidata entity ID of the "category's main topic (P301)", if it exists |
|||
-- failing that, the Wikidata entity ID associated with the current page, if it exists |
|||
-- otherwise, nothing |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getQid = function(frame) |
|||
local qid = (frame.args.qid or ""):upper() |
|||
-- check if a qid was passed; if so, return it: |
|||
if qid ~= "" then return qid end |
|||
-- check if there's a "category's main topic (P301)": |
|||
qid = mw.wikibase.getEntityIdForCurrentPage() |
|||
if qid then |
|||
local prop301 = mw.wikibase.getBestStatements(qid, "P301") |
|||
if prop301[1] then |
|||
local mctid = prop301[1].mainsnak.datavalue.value.id |
|||
if mctid then return mctid end |
|||
end |
|||
end |
end |
||
return retval |
|||
-- otherwise return the page qid (if any) |
|||
return qid |
|||
end |
end |
||
------------------------------------------------------------------------------- |
|||
-- followQid takes three optional parameters: qid, props, and all. |
|||
-- If qid is not given, it uses the qid for the connected page |
|||
-- or returns nil if there isn't one. |
|||
-- props is a list of properties, separated by punctuation. |
|||
-- If props is given, the Wikidata item for the qid is examined for each property in turn. |
|||
-- If that property contains a value that is another Wikibase-item, that item's qid is returned, |
|||
-- and the search terminates, unless |all=y when all of the qids are returned, sparated by spaces. |
|||
-- If props is not given, the qid is returned. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam() |
|||
------------------------------------------------------------------------------- |
|||
p.followQid = function(frame) |
|||
local qid = (frame.args.qid or ""):upper() |
|||
local all = parseParam(frame.args.all, false) |
|||
if qid == "" then |
|||
qid = mw.wikibase.getEntityIdForCurrentPage() |
|||
end |
|||
if not qid then return nil end |
|||
local out = {} |
|||
local props = (frame.args.props or ""):upper() |
|||
if props ~= "" then |
|||
for p in mw.text.gsplit(props, "%p") do -- split at punctuation and iterate |
|||
p = mw.text.trim(p) |
|||
for i, v in ipairs( mw.wikibase.getBestStatements(qid, p) ) do |
|||
local linkedid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id |
|||
if linkedid then |
|||
if all then |
|||
out[#out+1] = linkedid |
|||
else |
|||
return linkedid |
|||
end -- test for all or just the first one found |
|||
end -- test for value exists for that property |
|||
end -- loop through values of property to follow |
|||
end -- loop through list of properties to follow |
|||
end |
|||
if #out > 0 then |
|||
return table.concat(out, " ") |
|||
else |
|||
return qid |
|||
end |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- globalSiteID returns the globalSiteID for the current wiki |
|||
-- e.g. returns "enwiki" for the English Wikipedia, "enwikisource" for English Wikisource, etc. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.globalSiteID = function(frame) |
|||
return mw.wikibase.getGlobalSiteId() |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- siteID returns the root of the globalSiteID |
|||
-- e.g. "en" for "enwiki", "enwikisource", etc. |
|||
-- treats "en-gb" as "en", etc. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.siteID = function(frame) |
|||
local txtlang = frame:preprocess( "{{int:lang}}" ) or "" |
|||
-- This deals with specific exceptions: be-tarask -> be-x-old |
|||
if txtlang == "be-tarask" then |
|||
return "be_x_old" |
|||
end |
|||
local pos = txtlang:find("-") |
|||
local ret = "" |
|||
if pos then |
|||
ret = txtlang:sub(1, pos-1) |
|||
else |
|||
ret = txtlang |
|||
end |
|||
return ret |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- projID returns the code used to link to the reader's language's project |
|||
-- e.g "en" for [[:en:WikidataIB]] |
|||
-- treats "en-gb" as "en", etc. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.projID = function(frame) |
|||
local txtlang = frame:preprocess( "{{int:lang}}" ) or "" |
|||
-- This deals with specific exceptions: be-tarask -> be-x-old |
|||
if txtlang == "be-tarask" then |
|||
return "be-x-old" |
|||
end |
|||
local pos = txtlang:find("-") |
|||
local ret = "" |
|||
if pos then |
|||
ret = txtlang:sub(1, pos-1) |
|||
else |
|||
ret = txtlang |
|||
end |
|||
return ret |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- formatNumber formats a number according to the the supplied language code ("|lang=") |
|||
-- or the default language if not supplied. |
|||
-- The number is the first unnamed parameter or "|num=" |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: findLang() |
|||
------------------------------------------------------------------------------- |
|||
p.formatNumber = function(frame) |
|||
local lang |
|||
local num = tonumber(frame.args[1] or frame.args.num) or 0 |
|||
lang = findLang(frame.args.lang) |
|||
return lang:formatNum( num ) |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- examine dumps the property (the unnamed parameter or pid) |
|||
-- from the item given by the parameter 'qid' (or the other unnamed parameter) |
|||
-- or from the item corresponding to the current page if qid is not supplied. |
|||
-- e.g. {{#invoke:WikidataIB |examine |pid=P26 |qid=Q42}} |
|||
-- or {{#invoke:WikidataIB |examine |P26 |Q42}} or any combination of these |
|||
-- or {{#invoke:WikidataIB |examine |P26}} for the current page. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.examine = function( frame ) |
|||
local args |
|||
if frame.args[1] or frame.args.pid or frame.args.qid then |
|||
args = frame.args |
|||
else |
|||
args = frame:getParent().args |
|||
end |
|||
local par = {} |
|||
local pid = (args.pid or ""):upper() |
|||
local qid = (args.qid or ""):upper() |
|||
par[1] = mw.text.trim( args[1] or "" ):upper() |
|||
par[2] = mw.text.trim( args[2] or "" ):upper() |
|||
table.sort(par) |
|||
if par[2]:sub(1,1) == "P" then par[1], par[2] = par[2], par[1] end |
|||
if pid == "" then pid = par[1] end |
|||
if qid == "" then qid = par[2] end |
|||
if pid:sub(1,1) ~= "P" then return "No property supplied" end |
|||
if qid:sub(1,1) ~= "Q" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then return "No item for this page" end |
|||
return "<pre>" .. mw.dumpObject( mw.wikibase.getAllStatements( qid, pid ) ) .. "</pre>" |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- checkvalue looks for 'val' as a wikibase-item value of a property (the unnamed parameter or pid) |
|||
-- from the item given by the parameter 'qid' |
|||
-- or from the Wikidata item associated with the current page if qid is not supplied. |
|||
-- If property is not supplied, then P31 (instance of) is assumed. |
|||
-- It returns val if found or nothing if not found. |
|||
-- e.g. {{#invoke:WikidataIB |checkvalue |val=Q5 |pid=P31 |qid=Q42}} |
|||
-- or {{#invoke:WikidataIB |checkvalue |val=Q5 |P31 |qid=Q42}} |
|||
-- or {{#invoke:WikidataIB |checkvalue |val=Q5 |qid=Q42}} |
|||
-- or {{#invoke:WikidataIB |checkvalue |val=Q5 |P31}} for the current page. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.checkvalue = function( frame ) |
|||
local args |
|||
if frame.args.val then |
|||
args = frame.args |
|||
else |
|||
args = frame:getParent().args |
|||
end |
|||
local val = args.val |
|||
if not val then return nil end |
|||
local pid = mw.text.trim(args.pid or args[1] or "P31"):upper() |
|||
local qid = (args.qid or ""):upper() |
|||
if pid:sub(1,1) ~= "P" then return nil end |
|||
if qid:sub(1,1) ~= "Q" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then return nil end |
|||
local stats = mw.wikibase.getAllStatements( qid, pid ) |
|||
if not stats[1] then return nil end |
|||
if stats[1].mainsnak.datatype == "wikibase-item" then |
|||
for k, v in pairs( stats ) do |
|||
if v.mainsnak.snaktype == "value" and v.mainsnak.datavalue.value.id == val then |
|||
return val |
|||
end |
|||
end |
|||
end |
|||
return nil |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- url2 takes a parameter url= that is a proper url and formats it for use in an infobox. |
|||
-- If no parameter is supplied, it returns nothing. |
|||
-- This is the equivalent of Template:URL |
|||
-- but it keeps the "edit at Wikidata" pen icon out of the microformat. |
|||
-- Usually it will take its url parameter directly from a Wikidata call: |
|||
-- e.g. {{#invoke:WikidataIB |url2 |url={{wdib |P856 |qid=Q23317 |fwd=ALL |osd=no}} |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.url2 = function(frame) |
|||
local txt = frame.args.url or "" |
|||
if txt == "" then return nil end |
|||
local url, icon = txt:match("(.+) (.+)") |
|||
url = url or txt |
|||
icon = icon or "" |
|||
local prot, addr = url:match("(http[s]*://)(.+)") |
|||
prot = prot or url |
|||
addr = addr or "" |
|||
local disp, n = addr:gsub("%.", "<wbr/>%.") |
|||
return '<span class="url">[' .. prot .. addr .. " " .. disp .. "]</span> " .. icon |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getWebsite fetches the Official website (P856) and formats it for use in an infobox. |
|||
-- This is similar to Template:Official website but with a url displayed, |
|||
-- and it adds the "edit at Wikidata" pen icon beyond the microformat if enabled. |
|||
-- A local value will override the Wikidata value. "NONE" returns nothing. |
|||
-- e.g. {{#invoke:WikidataIB |getWebsite |qid= |noicon= |lang= |url= }} |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: findLang(); parseParam(); |
|||
------------------------------------------------------------------------------- |
|||
p.getWebsite = function(frame) |
|||
local url = frame.args.url or "" |
|||
if url:upper() == "NONE" then return nil end |
|||
local qid = frame.args.qid or "" |
|||
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end |
|||
if not qid then return nil end |
|||
local urls = {} |
|||
local quals = {} |
|||
if url == "" then |
|||
local prop856 = mw.wikibase.getBestStatements(qid, "P856") |
|||
for k, v in pairs(prop856) do |
|||
if v.mainsnak.snaktype == "value" then |
|||
urls[#urls+1] = v.mainsnak.datavalue.value |
|||
if v.qualifiers and v.qualifiers["P1065"] then |
|||
-- just take the first archive url (P1065) |
|||
local au = v.qualifiers["P1065"][1] |
|||
if au.snaktype == "value" then |
|||
quals[#urls] = au.datavalue.value |
|||
end -- test for archive url having a value |
|||
end -- test for qualifers |
|||
end -- test for website having a value |
|||
end -- loop through website(s) |
|||
else |
|||
urls[1] = url |
|||
end |
|||
if #urls == 0 then return nil end |
|||
local out = {} |
|||
for i, u in ipairs(urls) do |
|||
local link = quals[i] or u |
|||
local prot, addr = u:match("(http[s]*://)(.+)") |
|||
addr = addr or u |
|||
local disp, n = addr:gsub("%.", "<wbr/>%.") |
|||
out[#out+1] = '<span class="url">[' .. link .. " " .. disp .. "]</span>" |
|||
end |
|||
local langcode = findLang(frame.args.lang).code |
|||
local noicon = parseParam(frame.args.noicon, false) |
|||
if url == "" and not noicon then |
|||
out[#out] = out[#out] .. createicon(langcode, qid, "P856") |
|||
end |
|||
local ret = "" |
|||
if #out > 1 then |
|||
ret = mw.getCurrentFrame():expandTemplate{title = "ubl", args = out} |
|||
else |
|||
ret = out[1] |
|||
end |
|||
return ret |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getAllLabels fetches the set of labels and formats it for display as wikitext. |
|||
-- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getAllLabels = function(frame) |
|||
local args = frame.args or frame:getParent().args or {} |
|||
local qid = args.qid |
|||
if qid == "" then qid = nil end |
|||
local entity = mw.wikibase.getEntity(qid) |
|||
if not entity then return i18n["entity-not-found"] end |
|||
local labels = entity.labels |
|||
if not labels then return i18n["labels-not-found"] end |
|||
local out = {} |
|||
for k, v in pairs(labels) do |
|||
out[#out+1] = v.value .. " (" .. v.language .. ")" |
|||
end |
|||
return table.concat(out, "; ") |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getAllDescriptions fetches the set of descriptions and formats it for display as wikitext. |
|||
-- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getAllDescriptions = function(frame) |
|||
local args = frame.args or frame:getParent().args or {} |
|||
local qid = args.qid |
|||
if qid == "" then qid = nil end |
|||
local entity = mw.wikibase.getEntity(qid) |
|||
if not entity then return i18n["entity-not-found"] end |
|||
local descriptions = entity.descriptions |
|||
if not descriptions then return i18n["descriptions-not-found"] end |
|||
local out = {} |
|||
for k, v in pairs(descriptions) do |
|||
out[#out+1] = v.value .. " (" .. v.language .. ")" |
|||
end |
|||
return table.concat(out, "; ") |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getAllAliases fetches the set of aliases and formats it for display as wikitext. |
|||
-- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.getAllAliases = function(frame) |
|||
local args = frame.args or frame:getParent().args or {} |
|||
local qid = args.qid |
|||
if qid == "" then qid = nil end |
|||
local entity = mw.wikibase.getEntity(qid) |
|||
if not entity then return i18n["entity-not-found"] end |
|||
local aliases = entity.aliases |
|||
if not aliases then return i18n["aliases-not-found"] end |
|||
local out = {} |
|||
for k1, v1 in pairs(aliases) do |
|||
local lang = v1[1].language |
|||
local val = {} |
|||
for k1, v2 in ipairs(v1) do |
|||
val[#val+1] = v2.value |
|||
end |
|||
out[#out+1] = table.concat(val, ", ") .. " (" .. lang .. ")" |
|||
end |
|||
return table.concat(out, "; ") |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- showNoLinks displays the article titles that should not be linked. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
p.showNoLinks = function(frame) |
|||
local out = {} |
|||
for k, v in pairs(donotlink) do |
|||
out[#out+1] = k |
|||
end |
|||
table.sort( out ) |
|||
return table.concat(out, "; ") |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- checkValidity checks whether the first unnamed parameter represents a valid entity-id, |
|||
-- that is, something like Q1235 or P123. |
|||
-- It returns the strings "true" or "false". |
|||
-- Change false to nil to return "true" or "" (easier to test with #if:). |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: none |
|||
------------------------------------------------------------------------------- |
|||
function p.checkValidity(frame) |
|||
local id = mw.text.trim(frame.args[1] or "") |
|||
if mw.wikibase.isValidEntityId(id) then |
|||
return true |
|||
else |
|||
return false |
|||
end |
|||
end |
|||
------------------------------------------------------------------------------- |
|||
-- getEntityFromTitle returns the Entity-ID (Q-number) for a given title. |
|||
-- Modification of Module:ResolveEntityId |
|||
-- The title is the first unnamed parameter. |
|||
-- The site parameter determines the site/language for the title. Defaults to current wiki. |
|||
-- The showdab parameter determines whether dab pages should return the Q-number or nil. Defaults to true. |
|||
-- Returns the Q-number or nil if it does not exist. |
|||
------------------------------------------------------------------------------- |
|||
-- Dependencies: parseParam |
|||
------------------------------------------------------------------------------- |
|||
function p.getEntityFromTitle(frame) |
|||
local args=frame.args |
|||
if not args[1] then args=frame:getParent().args end |
|||
if not args[1] then return nil end |
|||
local title = mw.text.trim(args[1]) |
|||
local site = args.site or "" |
|||
local showdab = parseParam(args.showdab, true) |
|||
qid = mw.wikibase.getEntityIdForTitle(title, site) |
|||
if qid then |
|||
local prop31 = mw.wikibase.getBestStatements(qid, "P31")[1] |
|||
if not showdab and prop31 and prop31.mainsnak.datavalue.value.id == "Q4167410" then |
|||
return nil |
|||
else |
|||
return qid |
|||
end |
|||
end |
|||
end |
|||
return p |
return p |
||
------------------------------------------------------------------------------- |
|||
-- List of exported functions |
|||
------------------------------------------------------------------------------- |
|||
--[[ |
|||
_getValue |
|||
getValue |
|||
getPreferredValue |
|||
getCoords |
|||
getQualifierValue |
|||
getSumOfParts |
|||
getValueByQual |
|||
getValueByLang |
|||
getValueByRefSource |
|||
getPropertyIDs |
|||
getPropOfProp |
|||
getAwardCat |
|||
getIntersectCat |
|||
getGlobe |
|||
getCommonsLink |
|||
getSiteLink |
|||
getLink |
|||
getLabel |
|||
getAT |
|||
getDescription |
|||
getAliases |
|||
pageId |
|||
formatDate |
|||
location |
|||
checkBlacklist |
|||
emptyor |
|||
labelorid |
|||
getLang |
|||
getItemLangCode |
|||
findLanguage |
|||
getQID |
|||
followQid |
|||
globalSiteID |
|||
siteID |
|||
projID |
|||
formatNumber |
|||
examine |
|||
checkvalue |
|||
url2 |
|||
getWebsite |
|||
getAllLabels |
|||
getAllDescriptions |
|||
getAllAliases |
|||
showNoLinks |
|||
checkValidity |
|||
getEntityFromTitle |
|||
--]] |
|||
------------------------------------------------------------------------------- |
Sideversjonen fra 18. jan. 2020 kl. 01:05
Dokumentasjon for denne modulen kan opprettes på Modul:WikidataIB/dok
local p = {} local rankOrder = { ['truth'] = 1, ['preferred'] = 2, ['normal'] = 3, ['deprecated'] = 4 } local i18n = { ['wikidata-linkback-edit'] = 'Redigere på Wikidata', ['wiki-article-not-available'] = 'Artikkelen er ikke tilgjengelig på denne wikien ennå', ['wikidata-more-results-exists'] = 'Flere verdier er tilgjengelige på wikidata', ['standard-timeformat'] = 'j. F Y', ['argument-property'] = 'property', ['argument-list'] = 'liste', ['argument-date'] = 'dato', ['argument-value'] = 'verdi', ['argument-label'] = 'pnavn', ['argument-noedit'] = 'noedit', ['argument-fallback'] = 'fallback', ['argument-suffix'] = 'suffiks', ['argument-suffix-label'] = 'suffiksnavn', ['argument-bounds'] = 'usikkerhet', ['category-rowproperty-no-arguments'] = '[[Kategori:Artikler med invoke WikidataIB rowProperty uten argumenter]]', ['category-getpropertyvalue-no-arguments'] = '[[Kategori:Artikler med invoke WikidataIB getPropertyValue uten argumenter]]', ['category-getpropertylabel-no-arguments'] = '[[Kategori:Artikler med invoke WikidataIB getPropertyLabel uten argumenter]]' } local arguments = { property = nil, list = nil, date = nil, wiki_value = nil, edit = nil, fallback = nil, usesuffix = nil, suffix_from_wiki = nil, label = nil, usebounds = nil, } local function dump(obj) return "<pre>" .. mw.dumpObject(obj) .. "</pre>" end local function getArgument(frame, argument) local args = frame.args if args[1] == nil then local pFrame = frame:getParent(); args = pFrame.args; for k,v in pairs( frame.args ) do args[k] = v; end end if args[argument] then return args[argument] end return nil end local function getArguments(frame) arguments.property = getArgument(frame, i18n['argument-property']) if not arguments.property then -- No such argument, try getting it as the first argument arguments.property = getArgument(frame, '1') end arguments.list = getArgument(frame, i18n['argument-list']) if arguments.list and arguments.list ~= "" and tonumber(arguments.list) ~= 0 then arguments.list = tonumber(arguments.list) else arguments.list = nil end arguments.date = getArgument(frame, i18n['argument-date']) arguments.wiki_value = getArgument(frame, i18n['argument-value']) arguments.edit = getArgument(frame, i18n['argument-edit']) if arguments.edit and arguments.edit == "1" and not arguments.wiki_value then arguments.edit = false else arguments.edit = true end arguments.fallback = getArgument(frame, i18n['argument-fallback']) if arguments.fallback and arguments.fallback ~= "" then arguments.fallback = true else arguments.fallback = false end arguments.usesuffix = getArgument(frame, i18n['argument-suffix']) arguments.suffix_from_wiki = getArgument(frame, i18n['argument-suffix-label']) arguments.label = getArgument(frame, i18n['argument-label']) arguments.usebounds = getArgument(frame, i18n['argument-bounds']) end local function getDate(qualifiers, dateformat, langcode) local out = nil if qualifiers then local qualifierID = "" if qualifiers['P585'] then qualifierID='P585' -- point-in-time elseif qualifiers['P580'] then qualifierID='P580' end -- from -- todo: timespans? P582 for k, v in pairs(qualifiers[qualifierID]) do if v.snaktype == 'value' then out = "(" .. mw.language.new(langcode):formatDate(dateformat, v.datavalue.value.time) .. ")" end end end return out end local function getOrder(qualifiers) local out = nil if qualifiers then local qualifierID = "P1545" -- sorting order / rank / series ordinal if qualifiers[qualifierID] then for k, v in pairs(qualifiers[qualifierID]) do if v.snaktype == 'value' then out = v.datavalue.value end end end end return out end local function sortTableRankAndOrder(t, order_descending) local retval = {} local function compare(a, b) if (a.rank and b.rank and rankOrder[a.rank] < rankOrder[b.rank]) then return true end if (a.rank and b.rank and rankOrder[a.rank] == rankOrder[b.rank]) and (a.order and b.order and ((order_descending and a.order < b.order) or (not order_descending and a.order > b.order))) then return true else return false end end table.sort(t, compare) end local function compareRank(oldrank, newrank) if (newrank and not oldrank) or (oldrank and newrank and rankOrder[newrank] < rankOrder[oldrank]) then return newrank else return oldrank end end local function getQValueLink(qvalue, fallback, fallbacklang, label_from_wiki) local sitelink = mw.wikibase.sitelink(qvalue) local label = label_from_wiki if not label then label = mw.wikibase.label(qvalue) end out = nil if qvalue then if label == nil then -- let's try the fallback-languages local checkQ = mw.wikibase.getEntityObject(qvalue) if checkQ then local i = 0 while i < #fallbacklang do i = i + 1 label = checkQ:getLabel( fallbacklang[i] ) if label ~= nil then break end end end if label == nil then -- no such luck, fall back to Q-values label = qvalue end end if sitelink and sitelink ~= label then out = "[[" .. sitelink .. "|" .. label .. "]]" elseif sitelink then out = "[[" .. sitelink .. "]]" else if fallback then out = "[[:d:Q" .. qvalue .. "|" .. label .. "]]<abbr title='" .. i18n['wiki-article-not-available'] .. "'>[*]</abbr>" else out = label end end end return out end local function roundToDecimalNum(number, decimalPlace) local mult = 10^(decimalPlace or 0) return math.floor(number * mult + 0.5) / mult end function RoundNumber(num, idp) end local function findNumberOfDecimals(number) -- first, let's make it a string local numStr = tostring(tonumber(number)) -- now let's get the decimals local integers,decimals = numStr:match('(%d+)%.(%d+)') return #decimals end -- This is used to get a value -- if the boolean "list" is set, it will concatenate all available values in a comma-separated list -- if "dateformat" is set, it will look for qualifier-dates (P585, P580) and include in parathensis and format accordingly to the dateformat local function getValue(propertyID, list, dateformat, edit, fallback, usesuffix, suffix_label, usebounds, value_from_wiki) if value_from_wiki and #value_from_wiki and value_from_wiki ~= "" then return value_from_wiki else local lang = mw.language.getContentLanguage() local fallbacklang = mw.language.getFallbacksFor( lang.code ) local entity = mw.wikibase.getEntityObject() local claims if entity and entity.claims then claims = entity.claims[propertyID] end local out = {} local highestrank = nil if claims then if (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == "wikibase-entityid") then -- if wiki-linked value output as link if possible for k, v in pairs(claims) do if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then out[#out + 1] = { output = getQValueLink("Q" .. v.mainsnak.datavalue.value["numeric-id"], fallback, fallbacklang) } -- now let's check for a suffix if usesuffix and v.mainsnak.datavalue.value.unit then -- find Q-value local qval = "" _, _, qval = string.find(v.mainsnak.datavalue.value.unit, "^https*://www.wikidata.org/entity/(Q%d+)$") if qval and qval ~= "" then local suffix = getQValueLink(qval, fallback, fallbacklang, suffix_label) if suffix then out[#out].output = out[#out].output .. " " .. suffix end end end if dateformat then local date = getDate(v.qualifiers, dateformat, lang.code) if date then out[#out].output = out[#out].output .. " " .. date end end out[#out].rank = v.rank out[#out].order = getOrder(v.qualifiers) highestrank = compareRank(highestrank, v.rank) end end elseif (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == 'quantity') then -- this is a quantity, output as value for k, v in pairs(claims) do if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then if v.mainsnak.datavalue.value['amount'] then out[#out + 1] = { output = lang:formatNum(tonumber(v.mainsnak.datavalue.value['amount'])) } end -- check for bounds if usebounds and v.mainsnak.datavalue.value['lowerBound'] and v.mainsnak.datavalue.value['upperBound'] then local lowdiff = tonumber(v.mainsnak.datavalue.value['amount']) - tonumber(v.mainsnak.datavalue.value['lowerBound']) local upperdiff = tonumber(v.mainsnak.datavalue.value['upperBound']) - tonumber(v.mainsnak.datavalue.value['amount']) local numDec = findNumberOfDecimals(v.mainsnak.datavalue.value['amount']) out[#out].output = out[#out].output .. " ±" .. tostring(roundToDecimalNum(lowdiff, numDec)) end -- now let's check for a suffix if usesuffix and v.mainsnak.datavalue.value.unit then -- find Q-value local qval = "" _, _, qval = string.find(v.mainsnak.datavalue.value.unit, "^https*://www.wikidata.org/entity/(Q%d+)$") if qval and qval ~= "" then local suffix = getQValueLink(qval, fallback, fallbacklang, suffix_label) if suffix then out[#out].output = out[#out].output .. " " .. suffix end end end if dateformat then local date = getDate(v.qualifiers, dateformat, lang.code) if date then out[#out].output = out[#out].output .. " " .. date end end out[#out].rank = v.rank out[#out].order = getOrder(v.qualifiers) highestrank = compareRank(highestrank, v.rank) end end elseif (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == 'time') then -- this is a quantity, output as value for k, v in pairs(claims) do if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then if v.mainsnak.datavalue.value['time'] then local timeformat = dateformat if not timeformat or timeformat == "" then timeformat = i18n['standard-timeformat'] end out[#out + 1] = { output = mw.language.new(lang.code):formatDate(timeformat, v.mainsnak.datavalue.value.time) } end -- now let's check for a suffix if usesuffix and v.mainsnak.datavalue.value.unit then -- find Q-value local qval = "" _, _, qval = string.find(v.mainsnak.datavalue.value.unit, "^https*://www.wikidata.org/entity/(Q%d+)$") if qval and qval ~= "" then local suffix = getQValueLink(qval, fallback, fallbacklang, suffix_label) if suffix then out[#out].output = out[#out].output .. " " .. suffix end end end if dateformat then local date = getDate(v.qualifiers, dateformat, lang.code) if date then out[#out].output = out[#out].output .. " " .. date end end out[#out].rank = v.rank out[#out].order = getOrder(v.qualifiers) highestrank = compareRank(highestrank, v.rank) end end elseif (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == 'string') then -- this is a string for k, v in pairs(claims) do if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then if v.mainsnak.datavalue.value then out[#out + 1] = { output = v.mainsnak.datavalue.value } end if dateformat then local date = getDate(v.qualifiers, dateformat, lang.code) if date then out[#out].output = out[#out].output .. " " .. date end end out[#out].rank = v.rank out[#out].order = getOrder(v.qualifiers) highestrank = compareRank(highestrank, v.rank) end end else -- Unknown type out[#out + 1] = { output = 'unknown type ' .. claims[1].mainsnak.datavalue.type } end end -- Now we'll have to sort the table according to rank and order sortTableRankAndOrder(out) -- Now we'll make the output local i = 0 local ret = {} while i < #out do i = i + 1 -- check if the rank is within the highestrank if out[i].rank == highestrank then if list then list = list - 1 end ret[#ret + 1] = out[i].output if not list or list < 0 then if i < #out then -- We still have entries, show it ret[#ret + 1] = '<abbr title="' .. i18n['wikidata-more-results-exists'] .. '>…</abbr>' break end end end end return table.concat(ret, ", ") end end -- This is used to get the name of the property with upper first case local function getProperty(propertyID, propertyname_from_wiki) if propertyname_from_wiki and #propertyname_from_wiki then return propertyname_from_wiki else local lang = mw.language.getContentLanguage() local out = mw.wikibase.label(propertyID) return lang:ucfirst(out) end end -- This is used to get the type of the property local function getUnitType(propertyID, value_from_wiki) if value_from_wiki and #value_from_wiki and value_from_wiki ~= "" then return value_from_wiki else local lang = mw.language.getContentLanguage() local fallbacklang = mw.language.getFallbacksFor( lang.code ) local entity = mw.wikibase.getEntityObject(propertyID) local claims if entity and entity.claims then claims = entity.claims['P2237'] end local out = {} local highestrank = nil if claims then if (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == "wikibase-entityid") then -- if wiki-linked value output as link if possible for k, v in pairs(claims) do if v.rank ~= mw.wikibase.entity.claimRanks.RANK_DEPRECATED then local sitelink = mw.wikibase.sitelink("Q" .. v.mainsnak.datavalue.value["numeric-id"]) local label = mw.wikibase.label("Q" .. v.mainsnak.datavalue.value["numeric-id"]) if label == nil then -- let's try the fallback-languages local checkQ = mw.wikibase.getEntityObject("Q" .. v.mainsnak.datavalue.value["numeric-id"]) if checkQ then local i = 0 while i < #fallbacklang do i = i + 1 label = checkQ:getLabel( fallbacklang[i] ) if label ~= nil then break end end end if label == nil then -- no such luck, fall back to Q-values label = "Q" .. v.mainsnak.datavalue.value["numeric-id"] end end if sitelink and sitelink ~= label then out[#out + 1] = { output = "[[" .. sitelink .. "|" .. label .. "]]" } elseif sitelink then out[#out + 1] = { output = "[[" .. sitelink .. "]]" } else if fallback then out[#out + 1] = { output = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]<abbr title='" .. i18n['wiki-article-not-available'] .. "'>[*]</abbr>" } else out[#out + 1] = { output = label } end end out[#out].rank = v.rank out[#out].order = getOrder(v.qualifiers) highestrank = compareRank(highestrank, v.rank) end end end end -- Now we'll have to sort the table according to rank and order sortTableRankAndOrder(out) -- Now we'll make the output local i = 0 local ret = {} local list = 0 while i < #out do i = i + 1 -- check if the rank is within the highestrank if out[i].rank == highestrank then if list then list = list - 1 end ret[#ret + 1] = out[i].output if not list or list < 0 then if i < #out then break end end end end local ent = mw.wikibase.getEntityObject() ret[#ret + 1] = dump(ent.claims) return table.concat(ret, ", ") end end function p.getPropertyUnit(frame) getArguments(frame) return getUnitType(arguments.property, arguments.wiki_value) end local function addLinkback(str, property) local id = mw.wikibase.getEntityObject() if not id then return str end if type(id) == 'table' then id = id.id end local class = '' if property then class = 'wd_' .. string.lower(property) end local title = i18n['wikidata-linkback-edit'] local icon = '[%s [[File:Blue pencil.svg|%s|10px|baseline|link=]] ]' local url = mw.uri.fullUrl('d:' .. id .. '#' .. property, 'uselang=nb') url.fragment = property url = tostring(url) local v = mw.html.create('span') :addClass(class) :wikitext(str) :tag('span') :addClass('noprint plainlinks wikidata-linkback') :css('padding-left', '.5em') :wikitext(icon:format(url, title)) :allDone() return tostring(v) end -- -- Denne funksjonen kalles opp slik: {{#invoke:WikidataIB|rowProperty|P26}} -- den vil da returnere en tekst-streng som er en rad i en infoboks slik: <tr class="rad" valign="top"><th colspan="2">[Property-navn]</th><td colspan="2">[claim]</td></tr> -- property-navn og claim hentes fra wikidata -- andre argumenter som kan benyttes: -- property - angir hvilken property som skal benyttes, alternativ måte å spesifisere på: {{#invoke:WikidataIB|rowProperty|property=P26}} -- liste - angir at hvis det er flere verdier under en property skal de listes ut slik: <tr class="rad" valign="top"><th colspan="2">[Property-navn]</th><td colspan="2">[claim1], [claim2], ...</td></tr> -- angis slik: {{#invoke:WikidataIB|rowProperty|P26|liste=1}} -- dato - angir om verdiene skal legges inn med dato i parantes i etterkant slik: <tr class="rad" valign="top"><th colspan="2">[Property-navn]</th><td colspan="2">[claim] (dato)</td></tr> -- angis slik: {{#invoke:WikidataIB|rowProperty|P26|dato=<datoformat>}}, f.eks. {{#invoke:WikidataIB|rowProperty|P26|dato=j. F Y}} vil gi (31. desember 2015) -- denne kan også kombineres med "liste" -- verdi - standardverdi som benyttes dersom wikidata ikke har noen claims/verdier for den angitte egenskapen (property). Må da også spesifiseres sammen med "propertynavn". -- angis slik: {{#invoke:WikidataIB|rowProperty|P26|verdi=Ola Normann}} -- pnavn - egenskapsnavn som benyttes dersom wikidata ikke har den angitte egenskapen (property). -- angis slik: {{#invoke:WikidataIB|rowProperty|P26|pnavn=Ektefelle}} -- noedit - angir om en "editeringslink" som peker mot Wikidata IKKE skal legges på raden. Kun tilgjengelig hvis alle data hentes fra Wikidata. -- angis slik: {{#invoke:WikidataIB|rowProperty|P26|noedit=1}} -- fallback - angir om lenker skal opprettes mot wikidata hvis lokal artikkel ikke finnes -- angis slik: {{#invoke:WikidataIB|rowProperty|P26|fallback=1}} -- function p.rowProperty(frame) getArguments(frame) local value = getValue(arguments.property, arguments.list, arguments.date, arguments.edit, arguments.fallback, arguments.usesuffix, arguments.suffix_from_wiki, arguments.usebounds, arguments.wiki_value) local retval = "" if value and value ~= "" then retval = retval .. '<tr class="rad" valign="top"><th colspan="2">' .. getProperty(arguments.property, arguments.label) .. '</th><td colspan="2"' if arguments.list then retval = retval .. ' class="reducible"' end retval = retval .. '>' if arguments.edit and (not arguments.wiki_value or arguments.wiki_value == "") then retval = retval .. addLinkback(value, arguments.property) else retval = retval .. value end retval = retval .. '</td></tr>' end return retval end function p.getPropertyValue(frame) -- Get argument "property" getArguments(frame) local value = getValue(arguments.property, arguments.list, arguments.date, arguments.edit, arguments.fallback, arguments.usesuffix, arguments.suffix_from_wiki, arguments.usebounds, arguments.wiki_value) local retval = "" if value and value ~= "" then if arguments.edit and (not arguments.wiki_value or arguments.wiki_value == "") then retval = addLinkback(value, arguments.property) else retval = value end end return retval end function p.getPropertyLabel(frame) getArguments(frame) return getProperty(arguments.property, arguments.label) end function p.dumpProperty(frame) getArguments(frame) local entity = mw.wikibase.getEntityObject(arguments.property) return dump(entity) end function p.dumpClaims(frame) getArguments(frame) local entity = mw.wikibase.getEntityObject() local claims = nil local retval = "" if entity and entity.claims and arguments.property then claims = entity.claims[arguments.property] elseif entity and entity.claims then claims = entity.claims end if claims then retval = dump(claims) end return retval end return p