--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
-- Version: 2021-02-06
-- 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 pwd = {}
-- creation of a subobject to store comparison functions, used for sorting claims
local cdate -- initialise as nil and only load _complex_date function if needed
-- to be able to build more complex sorts like topological sorts
-- Module:Complex date is loaded lazily and has the following dependencies:
-- Module:Calendar
-- Module:ISOdate
-- Module:DateI18n
-- Module:No globals
-- Module:I18n/complex date
-- Module:Ordinal
-- Module:I18n/ordinal
-- Module:Yesno
-- Module:Formatnum
-- Module:Linguistic
--
-- 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",
}
wd.compare = {}
local i18n =
{
["errors"] =
{
["property-not-found"] = "Property not found.",
["No property supplied"] = "No property supplied",
["entity-not-found"] = "Wikidata entity not found.",
["unknown-claim-type"] = "Unknown claim type.",
["unknown-entity-type"] = "Unknown entity type.",
["qualifier-not-found"] = "Qualifier not found.",
["site-not-found"] = "Wikimedia project not found.",
["labels-not-found"] = "No labels found.",
["descriptions-not-found"] = "No descriptions found.",
["aliases-not-found"] = "No aliases found.",
["unknown-datetime-format"] = "Unknown datetime format.",
["local-article-not-found"] = "Article is available on Wikidata, but not on Wikipedia",
["dab-page"] = " (dab)",
},
["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 modules = { }
-- This piece of html implements a collapsible container. Check the classes exist on your wiki.
local modulesNames = {
local collapsediv = '<div class="mw-collapsible mw-collapsed" style="width:100%; overflow:auto;" data-expandtext="{{int:show}}" data-collapsetext="{{int:hide}}">'
reference = 'Module:Wikidata/Références',
i18n = 'Module:Wikidata/I18n',
globes = 'Module:Wikidata/Globes',
langhierarchy = 'Module:Wikidata/Hiérarchie des langues',
langcodes = 'Module:Dictionnaire Wikidata/Codes langue', -- big, infrequently useda
invertedlangcodes = 'Module:Dictionnaire Wikidata/Codes langue/inversé',
linguistic = 'Module:Linguistique',
-- Some items should not be linked.
datemodule = 'Module:Date',
-- Each wiki can create a list of those in Module:WikidataIB/nolinks
formatDate = 'Module:Date complexe',
-- It should return a table called itemsindex, containing true for each item not to be linked
formatNum = 'Module:Conversion',
local donotlink = {}
langmodule = 'Module:Langue',
local nolinks_exists, nolinks = pcall(mw.loadData, "Module:WikidataIB/nolinks")
cite = 'Module:Biblio',
if nolinks_exists then
weblink = 'Module:Weblink'
donotlink = nolinks.itemsindex
}
end
local function loadModule( t, key )
-- To satisfy Wikipedia:Manual of Style/Titles, certain types of items are italicised, and others are quoted.
if modulesNames[key] then
-- The submodule [[Module:WikidataIB/titleformats]] lists the entity-ids used in 'instance of' (P31),
local m = require( modulesNames[key] )
-- which allows this module to identify the values that should be formatted.
t[key] = m
-- WikidataIB/titleformats exports a table p.formats, which is indexed by entity-id, and contains the value " or ''
return m
local formats = {}
end
local titleformats_exists, titleformats = pcall(mw.loadData, "Module:Sandbox/AdrianoRutzWikidataIB/titleformats")
if titleformats_exists then
formats = titleformats.formats
end
setmetatable( modules, { __index = loadModule } )
local datequalifiers = {'P585', 'P571', 'P580', 'P582', 'P1319', 'P1326'}
-------------------------------------------------------------------------------
-- Private functions
-- === I18n ===
-------------------------------------------------------------------------------
local defaultlang = mw.getContentLanguage():getCode()
--
-------------------------------------------------------------------------------
function wd.translate(str, rep1, rep2)
-- makeOrdinal needs to be internationalised along with the above:
str = modules.i18n[str] or str
-- takes cardinal number as a numeric and returns the ordinal as a string
if rep1 and (type (rep1) == 'string') then
-- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc.
str = str:gsub('$1', rep1)
-------------------------------------------------------------------------------
-- 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
if rep2 and (type (rep2) == 'string')then
-- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th'
str = str:gsub('$2', rep2)
-- 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) .. ordsuffixstr
end
local function addCat(cat, sortkey)
if sortkey then
-------------------------------------------------------------------------------
return '[[Category:' .. cat .. '|' .. sortkey .. ']]'
-- 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
return langobj'[[Category:' .. cat .. ']]'
end
local function formatError( key , category, debug)
if debug then
return error(modules.i18n[key] or key)
end
if category then
return addCat(category, key)
else
return addCat('cat-unsorted-issue', key)
end
end
--
function wd.isSpecial(snak)
-------------------------------------------------------------------------------
return (snak.snaktype ~= 'value')
-- _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: 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
function wd.getId(snak)
if (snak.snaktype == 'value') then
return 'Q' .. snak.datavalue.value['numeric-id']
end
end
function wd.getNumericId(snak)
-------------------------------------------------------------------------------
if (snak.snaktype == 'value') then
-- roundto takes a number (x)
return snak.datavalue.value['numeric-id']
-- 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
if sf < 1 then sf = 1 end
local p = 10 ^ (math.floor(math.log10(x)) - sf + 1)
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
return x
end
function wd.getMainId(claim)
return wd.getId(claim.mainsnak)
end
function wd.entityId(entity)
-------------------------------------------------------------------------------
if type(entity) == 'string' then
-- decimalToDMS takes a decimal degrees (x) with precision (p)
return entity
-- and returns degrees/minutes/seconds according to the precision
elseif type(entity) == 'table' then
-------------------------------------------------------------------------------
return entity.id
-- 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
local m = math.floor(ms)
local s = (ms - m) * 60
if p > 0.008 then -- precision is > 1/2 a minute
if s > 30 then m = m +1 end
s = 0
elseif p > 0.00014 then -- precision is > 1/2 a second
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
return d, m, s
end
function wd.getEntityIdForCurrentPage()
return mw.wikibase.getEntityIdForCurrentPage()
end
-- function that returns true if the "qid" parameter is the qid
-- of the item that is linked to the calling page
function wd.isPageOfQId(qid)
local self_id = mw.wikibase.getEntityIdForCurrentPage()
return self_id ~= nil and qid == self_id
end
function wd.getEntity( val )
-------------------------------------------------------------------------------
if type(val) == 'table' then
-- decimalPrecision takes a decimal (x) with precision (p)
return val
-- 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
if val == '-' then
-- if p is not supplied, pick an arbitrary precision
return nil
if not tonumber(p) then p = 1e-4
elseif p > 1 then p = 1
elseif p < 1e-6 then p = 1e-6
else p = 10 ^ math.floor(math.log10(p))
end
if val == '' then
x = math.floor(x / p + 0.5) * p * s
val = nil
-- if it's integral, cast to an integer:
end
if x == math.floor(x) then x = math.floor(x) end
return mw.wikibase.getEntity(val)
-- 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
function wd.splitStr(val) -- transforme en table les chaînes venant du Wikitexte qui utilisent des virgules de séparation
if type(val) == 'string' then
-------------------------------------------------------------------------------
val = mw.text.split(val, ",")
-- formatDate takes a datetime of the usual format from mw.wikibase.entity:formatPropertyValues
-- like "1 August 30 BCE" as parameter 1
-- and formats it according to the df (date format) and bc parameters
-- df = ["dmy" / "mdy" / "y"] default will be "dmy"
-- bc = ["BC" / "BCE"] default will be "BCE"
-------------------------------------------------------------------------------
-- Dependencies: none
-------------------------------------------------------------------------------
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
return val
end
function wd.isHere(searchset, val)
local postchrist = true -- start by assuming no BCE
for i, j in pairs(searchset) do
local dateparts = {}
if val == j then
for word in string.gmatch(dateval, "%w+") do
return true
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
return false
if postchrist then bc = "" end -- set AD dates to no suffix *** internationalise later ***
end
local sep = " " -- separator is nbsp
local fdate = table.concat(dateparts, sep) -- set formatted date to same order as input
local function wikidataLink(entity)
-- if we have day month year, check dateformat
local name =':d:'
if #dateparts == 3 then
if dateformat == "y" then
if type(entity) == 'string' then
fdate = dateparts[3]
if entity:match("P[0-9+]") then
elseif dateformat == "mdy" then
entity = "Property:" .. entity
fdate = dateparts[2] .. sep .. dateparts[1] .. "," .. sep .. dateparts[3]
end
return name .. entity
elseif #dateparts == 2 and dateformat == "y" then
elseif type(entity) == 'table' then
fdate = dateparts[2]
if entity["type"] == "property" then
name = ":d:Property:"
end
return name .. entity.id
elseif type(entity) == nil then
return formatError('entity-not-found')
end
return fdate .. bc
end
function wd.siteLink(entity, project, lang)
-- returns 3 values: a sitelink (with the relevant prefix) a project name and a language
-------------------------------------------------------------------------------
lang = lang or defaultlang
-- dateFormat is the handler for properties that are of type "time"
if (type(project) ~= 'string') then
-- It takes timestamp, precision (6 to 11 per mediawiki), dateformat (y/dmy/mdy), BC format (BC/BCE),
project = 'wiki'
-- a plaindate switch (yes/no/adj) to en/disable "sourcing circumstances"/use adjectival form,
-- any qualifiers for the property, the language, and any adjective to use like 'before'.
-- It passes the date through the "complex date" function
-- and returns a string with the internatonalised date formatted according to preferences.
-------------------------------------------------------------------------------
-- Dependencies: findLang(); cdate(); dp[]
-------------------------------------------------------------------------------
local dateFormat = function(timestamp, dprec, df, bcf, pd, qualifiers, lang, adj, model)
-- output formatting according to preferences (y/dmy/mdy/ymd)
df = (df or ""):lower()
-- if ymd is required, return the part of the timestamp in YYYY-MM-DD form
-- but apply Year zero#Astronomers fix: 1 BC = 0000; 2 BC = -0001; etc.
if df == "ymd" then
if timestamp:sub(1,1) == "+" then
return timestamp:sub(2,11)
else
local yr = tonumber(timestamp:sub(2,5)) - 1
yr = ("000" .. yr):sub(-4)
if yr ~= "0000" then yr = "-" .. yr end
return yr .. timestamp:sub(6,11)
end
end
project = project:lower()
-- A year can be stored like this: "+1872-00-00T00:00:00Z",
if project == 'wikipedia' then
-- which is processed here as if it were the day before "+1872-01-01T00:00:00Z",
project = 'wiki'
-- and that's the last day of 1871, so the year is wrong.
end
-- So fix the month 0, day 0 timestamp to become 1 January instead:
if type(entity) == 'string' and (project == 'wiki') and ( (not lang or lang == defaultlang) ) then -- évite de charger l'élément entier
timestamp = timestamp:gsub("%-00%-00T", "-01-01T")
return mw.wikibase.sitelink(entity), 'wiki', defaultlang
-- just in case date precision is missing
end
dprec = dprec or 11
if project == 'wikidata' then
-- override more precise dates if required dateformat is year alone:
return wikidataLink(entity), 'wikidata'
if df == "y" and dprec > 9 then dprec = 9 end
end
-- complex date only deals with precisions from 6 to 11, so clip range
local projects = {
dprec = dprec>11 and 11 or dprec
-- nom = {préfixe sur Wikidata, préfix pour les liens sur Wikipédia, ajouter préfixe de langue}
dprec = dprec<6 and 6 or dprec
wiki = {'wiki', nil, true}, -- wikipedia
-- BC format is "BC" or "BCE"
commons = {'commonswiki', 'commons', false},
bcf = (bcf or ""):upper()
commonswiki = {'commonswiki', 'commons', false},
-- plaindate only needs the first letter (y/n/a)
wikiquote = {'wikiquote', 'q', true},
pd = (pd or ""):sub(1,1):lower()
wikivoyage = {'wikivoyage', 'voy', true},
if pd == "" or pd == "n" or pd == "f" or pd == "0" then pd = false end
wikibooks = {'wikibooks', 'b', true},
-- in case language isn't passed
wikinews = {'wikinews', 'n', true},
lang = lang or findLang().code
wikiversity = {'wikiversity', 'v', true},
-- set adj as empty if nil
wikisource = {'wikisource', 's', true},
adj = adj or ""
wiktionary = {'wiktionary', 'wikt', true},
-- extract the day, month, year from the timestamp
specieswiki = {'specieswiki', 'species', false},
local bc = timestamp:sub(1, 1)=="-" and "BC" or ""
metawiki = {'metawiki', 'm', false},
local year, month, day = timestamp:match("[+-](%d*)-(%d*)-(%d*)T")
incubator = {'incubator', 'incubator', false},
local iso = tonumber(year) -- if year is missing, let it throw an error
outreach = {'outreach', 'outreach', false},
-- this will adjust the date format to be compatible with cdate
mediawiki = {'mediawiki', 'mw', false}
-- 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
local entityid = entity.id or entity
if dprec == 8 then iso = math.floor( iso / 10 ) .. "0" end
if dprec == 10 then iso = year .. "-" .. month end
local projectdata = projects[project:lower()]
if dprec == 11 then iso = year .. "-" .. month .. "-" .. day end
if not projectdata then -- defaultlink might be in the form "dewiki" rather than "project: 'wiki', lang: 'de' "
-- add "circa" (Q5727902) from "sourcing circumstances" (P1480)
for k, v in pairs(projects) do
local sc = not pd and qualifiers and qualifiers.P1480
if project:match( k .. '$' )
if sc then
and mw.language.isKnownLanguageTag(project:sub(1, #project-#k))
for k1, v1 in pairs(sc) do
then
if v1.datavalue and v1.datavalue.value.id == "Q5727902" then
lang = project:sub(1, #project-#k)
adj = "circa"
project = project:sub(#lang + 1, #project)
projectdata = projects[project]
break
end
end
if not mw.language.isKnownLanguageTag(lang) then
return --formatError('invalid-project-code', projet or 'nil')
end
end
if not projectdata then
-- deal with Julian dates:
return -- formatError('invalid-project-code', projet or 'nil')
-- 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 suppress 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
local linkcode = projectdata[1]
cdate = require("Module:Complex date")._complex_date
local prefix = projectdata[2]
local multiversion = projectdata[3]
if multiversion then
linkcode = lang .. linkcode
end
local link = mw.wikibase.getSitelink(entityid, linkcode)
local fdate = cdate(calendarmodel, adj, tostring(iso), dp[dprec], bc, "", "", "", "", lang, 1)
if not link then
-- this may have QuickStatements info appended to it in a div, so remove that
return nil
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 ***
if prefix then
fdate = fdate:gsub('circa ', '<abbr title="circa">c.</abbr> ')
link = prefix .. ':' .. link
-- deal with BC/BCE
if bcf == "BCE" then
fdate = fdate:gsub('BC', 'BCE')
end
if multiversion then
-- deal with mdy format
link = ':' .. lang .. ':' .. link
if df == "mdy" then
fdate = fdate:gsub("(%d+) (%w+) (%d+)", "%2 %1, %3")
end
return link, project, lang
-- deal with adjectival form *** internationalise later ***
if pd == "a" then
fdate = fdate:gsub(' century', '-century')
end
return fdate
end
-- add new values to a list, avoiding duplicates
function wd.addNewValues(olditems, newitems, maxnum, stopval)
-------------------------------------------------------------------------------
if not newitems then
-- parseParam takes a (string) parameter, e.g. from the list of frame arguments,
return olditems
-- and makes "false", "no", and "0" into the (boolean) false
end
-- it makes the empty string and nil into the (boolean) value passed as default
for _, qid in pairs(newitems) do
-- allowing the parameter to be true or false by default.
if stopval and (qid == stopval) then
-- It returns a boolean.
table.insert(olditems, qid)
-------------------------------------------------------------------------------
return olditems
-- Dependencies: none
end
-------------------------------------------------------------------------------
if maxnum and (#olditems >= maxnum) then
local parseParam = function(param, default)
return olditems
if type(param) == "boolean" then param = tostring(param) end
end
if param and param ~= "" then
if not wd.isHere(olditems, qid) then
param = param:lower()
table.insert(olditems, qid)
if (param == "false") or (param:sub(1,1) == "n") or (param == "0") then
return false
else
return true
end
else
return default
end
return olditems
end
--=== FILTER CLAIMS ACCORDING TO VARIOUS CRITERIA : FUNCTION GETCLAIMS et alii ===
local function notSpecial(claim)
-------------------------------------------------------------------------------
local type
-- _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 claim.mainsnak ~= nil then
-- If the parameter is blank, then it uses the local wiki.
type = claim.mainsnak.snaktype
-- 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.getSitelink(qid)
else
-- condition respectée quand showonlyqualifier est un paramètre renseigné
sitelink = mw.wikibase.getSitelink(qid, wiki)
-- dans ce cas, claim n'est pas une déclaration entière, mais UNE snak qualifiée du main snak
type = claim.snaktype
end
return sitelink
return type == 'value'
end
local function hasTargetValue(claim, targets) -- retourne true si la valeur est dans la liste des target, ou si c'est une valeur spéciale filtrée séparément par excludespecial
local id = wd.getMainId(claim)
local targets = wd.splitStr(targets)
return wd.isHere(targets, id) or wd.isSpecial(claim.mainsnak)
end
local function excludeValues(claim, values) -- true si la valeur n'est pas dans la liste, ou si c'est une valeur spéciale (filtrée à part par excludespecial)
-------------------------------------------------------------------------------
return wd.isSpecial(claim.mainsnak) or not ( hasTargetValue(claim, values) )
-- _getCommonslink takes an optional qid of a Wikidata entity passed as |qid=
end
-- 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;
local function bestRanked(claims)
-- the Commons sitelink of the topic's main category of the Wikidata entity;
if not claims then
-- the Commons category of the Wikidata entity - unless fallback=false.
return nil
-------------------------------------------------------------------------------
-- 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
local preferred, normal = {}, {}
if not sitelink and fallback then
for i, j in pairs(claims) do
-- check for Commons category (string value)
if j.rank == 'preferred' then
local prop373 = mw.wikibase.getBestStatements(qid, "P373")[1]
table.insert(preferred, j)
if prop373 then
elseif j.rank == 'normal' then
sitelink = prop373.mainsnak.datavalue and prop373.mainsnak.datavalue.value
table.insert(normal, j)
if sitelink then sitelink = "Category:" .. sitelink end
end
end
if #preferred > 0 then
return sitelink
return preferred
else
return normal
end
end
local function withRank(claims, target)
if target == 'best' then
-------------------------------------------------------------------------------
return bestRanked(claims)
-- 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
label = mw.wikibase.getLabel(id)
end
local newclaims = {}
if label then
for pos, claim in pairs(claims) do
return mw.text.nowiki(label), true
if target == 'valid' then
else
if claim.rank ~= 'deprecated' then
return id, false
table.insert(newclaims, claim)
end
elseif claim.rank == target then
table.insert(newclaims, claim)
end
end
return newclaims
end
function wd.hasQualifier(claim, acceptedqualifs, acceptedvals, excludequalifiervalues)
local claimqualifs = claim.qualifiers
if (not claimqualifs) then
return false
end
acceptedqualifs = wd.splitStr(acceptedqualifs)
-------------------------------------------------------------------------------
acceptedvals = wd.splitStr( acceptedvals)
-- linkedItem takes an entity-id and returns a string, linked if possible.
-- This is the handler for "wikibase-item". Preferences:
-- 1. Display linked disambiguated sitelink if it exists
local function ok(qualif) -- vérification pour un qualificatif individuel
-- 2. Display linked label if it is a redirect
if not claimqualifs[qualif] then
-- 3. TBA: Display an inter-language link for the label if it exists other than in default language
return false
-- 4. Display unlinked label if it exists
end
-- 5. Display entity-id for now to indicate a label could be provided
if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK
-- dtxt is text to be used instead of label, or nil.
return true
-- shortname is boolean switch to use P1813 (short name) instead of label if true.
end
-- lang is the current language code.
for i, wanted in pairs(acceptedvals) do
-- uselbl is boolean switch to force display of the label instead of the sitelink (default: false)
for j, actual in pairs(claimqualifs[qualif]) do
-- linkredir is boolean switch to allow linking to a redirect (default: false)
if wd.getId(actual) == wanted then
-- formatvalue is boolean switch to allow formatting as italics or quoted (default: false)
return true
-------------------------------------------------------------------------------
end
-- Dependencies: labelOrId(); donotlink[]
-------------------------------------------------------------------------------
local linkedItem = function(id, args)
local lprefix = (args.lp or args.lprefix or args.linkprefix or ""):gsub('"', '') -- toughen against nil values passed
local lpostfix = (args.lpostfix or ""):gsub('"', '')
local prefix = (args.prefix or ""):gsub('"', '')
local postfix = (args.postfix or ""):gsub('"', '')
local dtxt = args.dtxt
local shortname = args.shortname
local lang = args.lang or "en" -- fallback to default if missing
local uselbl = args.uselabel or args.uselbl
uselbl = parseParam(uselbl, false)
local linkredir = args.linkredir
linkredir = parseParam(linkredir, false)
local formatvalue = args.formatvalue or args.fv
formatvalue = parseParam(formatvalue, false)
-- see if item might need italics or quotes
local fmt = ""
if next(formats) and formatvalue then
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
local disp
for i, qualif in pairs(acceptedqualifs) do
local sitelink = mw.wikibase.getSitelink(id)
if ok(qualif) then
local label, islabel
return true
if dtxt then
label, islabel = dtxt, true
elseif shortname then
-- see if there is a shortname in our language, and set label to it
for k, v in ipairs( mw.wikibase.getBestStatements(id, "P1813") ) do
if v.mainsnak.datavalue.value.language == lang then
label, islabel = v.mainsnak.datavalue.value.text, true
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
return false
if mw.site.siteName ~= "Wikimedia Commons" then
end
if sitelink then
if not (dtxt or shortname) then
function wd.hasQualifierNumber(claim, acceptedqualifs, acceptedvals, excludequalifiervalues)
-- if sitelink and label are the same except for case, no need to process further
local claimqualifs = claim.qualifiers
if sitelink:lower() ~= label:lower() then
-- strip any namespace or dab from the sitelink
if (not claimqualifs) then
local pos = sitelink:find(":") or 0
return false
local slink = sitelink
end
if pos > 0 then
local pfx = sitelink:sub(1,pos-1)
acceptedqualifs = wd.splitStr(acceptedqualifs)
if mw.site.namespaces[pfx] then -- that prefix is a valid namespace, so remove it
acceptedvals = wd.splitStr( acceptedvals)
slink = sitelink:sub(pos+1)
end
end
local function ok(qualif) -- vérification pour un qualificatif individuel
-- remove stuff after commas or inside parentheses - ie. dabs
if not claimqualifs[qualif] then
slink = slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")
return false
-- if uselbl is false, use sitelink instead of label
end
if not uselbl then
if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK
-- use slink as display, preserving label case - find("^%u") is true for 1st char uppercase
return true
if label:find("^%u") then
end
label = slink:gsub("^(%l)", string.upper)
for i, wanted in pairs(acceptedvals) do
else
for j, actual in pairs(claimqualifs[qualif]) do
label = slink:gsub("^(%u)", string.lower)
if mw.wikibase.renderSnak(actual) == wanted then
end
endreturn true
end
end
if donotlink[label] then
disp = prefix .. fmt .. label .. fmt .. postfix
else
disp = "[[" .. lprefix .. sitelink .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]"
end
elseif islabel then
-- no sitelink, label exists, so check if a redirect with that title exists, if linkredir is true
-- display plain label by default
disp = prefix .. fmt .. label .. fmt .. postfix
if linkredir then
local artitle = mw.title.new(label, 0) -- only nil if label has invalid chars
if not donotlink[label] and artitle and artitle.redirectTarget 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 .. "]]"
end
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]]
-- for enwiki, just return the tracking category
if mw.wikibase.getGlobalSiteId() == "enwiki" then
disp = i18n.missinginfocat
else
disp = prefix .. label .. postfix .. i18n.missinginfocat
end
end
end
else
local ccat = mw.wikibase.getBestStatements(id, "P373")[1]
for i, qualif in pairs(acceptedqualifs) do
if ccat and ccat.mainsnak.datavalue then
if ok(qualif) then
ccat = ccat.mainsnak.datavalue.value
return true
disp = "[[" .. lprefix .. "Category:" .. ccat .. lpostfix .. "|" .. prefix .. label .. postfix .. "]]"
elseif sitelink then
-- this asumes that if a sitelink exists, then a label also exists
disp = "[[" .. lprefix .. sitelink .. lpostfix .. "|" .. prefix .. label .. postfix .. "]]"
else
-- no sitelink and no Commons cat, so return label from labelOrId for now
disp = prefix .. label .. postfix
end
end
return dispfalse
end
local function hasSource(claim, targetsource, sourceproperty)
sourceproperty = sourceproperty or 'P248'
-------------------------------------------------------------------------------
if targetsource == "-" then
-- sourced takes a table representing a statement that may or may not have references
return true
-- it looks for a reference sourced to something not containing the word "wikipedia"
end
-- it returns a boolean = true if it finds a sourced reference.
if (not claim.references) then return
-------------------------------------------------------------------------------
false
-- Dependencies: none
end
-------------------------------------------------------------------------------
local candidates = claim.references[1].snaks[sourceproperty] -- les snaks utilisant la propriété demandée
local sourced = function(claim)
if claim.references(not candidates) then
return false
for kr, vr in pairs(claim.references) do
end
local ref = mw.wikibase.renderSnaks(vr.snaks)
if (targetsource == "any") then -- si n'importe quelle valeur est acceptée tant qu'elle utilise en ref la propriété demandée
if not ref:find("Wiki") then
return true
end
targetsource = wd.splitStr(targetsource)
for _, source in pairs(candidates) do
local s = wd.getId(source)
for i, target in pairs(targetsource) do
if s == target then return true end
end
end
return false
end
local function excludeQualifier(claim, qualifier, qualifiervalues)
return not wd.hasQualifier(claim, qualifier, qualifiervalues)
end
function wd.hasDate(claim)
-------------------------------------------------------------------------------
if not claim then
-- setRanks takes a flag (parameter passed) that requests the values to return
return false --error() ?
-- "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
if wd.getDateFromQualif(claim, 'P585') or wd.getDateFromQualif(claim, 'P580') or wd.getDateFromQualif(claim, 'P582') then
-- check if "best" is requested or no ranks requested; and if so, set preferred and normal
return true
if ranks.b or not next(ranks) then
ranks.p = true
ranks.n = true
end
return ranksfalse
end
local function hasLink(claim, site, lang)
if (claim.mainsnak.snaktype ~= 'value') then -- ne pas supprimer les valeurs spéciales, il y a une fonction dédiée pour ça
return true
end
local id = wd.getMainId(claim)
local link = wd.siteLink(id, site, lang)
if link then
return true
end
end
local function isInLanguage(claim, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ?
-------------------------------------------------------------------------------
if type(lang) == 'table' then -- si c'est une table de language séparées par des virgules, on les accepte toutes
-- parseInput processes the Q-id , the blacklist and the whitelist
for i, l in pairs(lang) do
-- if an input parameter is supplied, it returns that and ends the call.
local v = isInLanguage(claim, l)
-- it returns (1) either the qid or nil indicating whether or not the call should continue
if v then
-- and (2) a table containing all of the statements for the propertyID and relevant Qid
return true
-- if "best" ranks are requested, it returns those instead of all non-deprecated ranks
end
-------------------------------------------------------------------------------
end
-- Dependencies: none
end
-------------------------------------------------------------------------------
if type(lang) ~= ('string') then
local parseInput = function(frame, input_parm, property_id)
return --?
-- 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
-- return nil if Wikidata is not available
if not mw.wikibase then return false, input_parm 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 or ""
-- The whitelist is passed in named parameter |fetchwikidata
local whitelist = args.fetchwikidata or args.fwd or ""
if 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 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 (lang == '-') then
-- If we got this far then we're not on the blacklist
return true
-- The blacklist overrides any locally supplied parameter as well
end
-- If a non-blank input parameter was supplied return it
if (lang == 'locallang') then
if input_parm then return false, input_parm end
lang = mw.getContentLanguage():getCode()
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
-- pour les monolingual text
local snak = claim.mainsnak or claim
-- Otherwise see if this field is on the whitelist:
if snak.snaktype == 'value' and snak.datavalue.type == 'monolingualtext' then
-- needs a bit more logic because find will return its second value = 0 if fieldname is ""
if snak.datavalue.value.language == lang then
-- but nil if fieldname not found on whitelist
return true
local _, found = whitelist:find(fieldname)
end
found = ((found or 0) > 0)
return false
if whitelist ~= 'ALL' and (whitelist:upper() == "NONE" or not found) then
return false, nil
end
-- pour les autres types de données : recherche dans les qualificatifs
-- See what's on Wikidata (the call always returns a table, but it may be empty):
if (lang == 'fr') then
local props = {}
lang = 'Q150'
if args.reqranks.b then
elseif (lang == 'en') then
props = mw.wikibase.getBestStatements(qid, property_id)
lang = 'Q1860'
else
lang = invertedlangcodes[lang]
props = mw.wikibase.getAllStatements(qid, property_id)
end
if claim.qualifiers and claim.qualifiers.P407 then
if props[1] then
if wd.hasQualifier(claim, {'P407'}, {lang}) then
return qid, props
return true
else
return false
end
end
-- no property on Wikidata
return true -- si on ne ne sait pas la langue, on condière que c'est bon
return false, nil
end
local function firstVals(claims, numval) -- retourn les numval premières valeurs de la table claims
local numval = tonumber(numval) or 0 -- raise a error if numval is not a positive integer ?
if not claims then
return nil
end
while (#claims > numval) do
table.remove(claims)
end
return claims
end
local function lastVals(claims, numval2) -- retourn les valeurs de la table claims à partir de numval2
-------------------------------------------------------------------------------
local numval2 = tonumber(numval2) or 0 -- raise a error if numval is not a positive integer ?
-- createicon assembles the "Edit at Wikidata" pen icon.
if not claims then
-- It returns a wikitext string inside a span class="penicon"
return nil
-- if entityID is nil or empty, the ID associated with current page is used
end
-- langcode and propertyID may be nil or empty
for i=1,numval2 do
-------------------------------------------------------------------------------
table.remove(claims, 1)
-- Dependencies: i18n[];
end
-------------------------------------------------------------------------------
return claims
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
if not entityID or entityID == "" then entityID= mw.wikibase.getEntityIdForCurrentPage() end
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. i18n["filespace"]
.. ":OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n["editonwikidata"]
.. "|link=https://www.wikidata.org/wiki/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n["editonwikidata"] .. "]]</span>"
return icon
end
-- retourne les valeurs de la table claims à partir de removedupesdate,
-- sans les dates en doublons avec conversion entre les calendrier julien et grégorien,
-------------------------------------------------------------------------------
-- ou uniquement en catégorisant si le paramètre removedupesdate est égale à 'cat'
-- assembleoutput takes the sequence table containing the property values
local function removeDupesDate(claims, removedupesdate)
-- and formats it according to switches given. It returns a string or nil.
if not claims or #claims < 2 then
-- It uses the entityID (and optionally propertyID) to create a link in the pen icon.
return claims, ''
-------------------------------------------------------------------------------
-- 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
local cat = ''
local newClaims = {}
local newIsos = {}
local function findIndex(searchset, val) -- similaire à wd.isHere mais retourne l'index de la valeur trouvée
-- collapse is a number that determines the maximum number of returned values
for i, j in pairs(searchset) do
-- before the output is collapsed.
if val == j then
-- Zero or not a number result in no collapsing (default becomes 0).
return i
local collapse = tonumber(args.collapse) or 0
-- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value
-- this is useful for tracking and debugging
local replacetext = mw.text.trim(args.rt or args.replacetext or "")
-- 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 there's something to display and a pen icon is wanted, add it the end of the last value
local hasdisplay = false
for i, v in ipairs(out) do
if v ~= i18n.missinginfocat then
hasdisplay = true
break
end
end
return -1
if not noic and hasdisplay 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
strout = nil -- no items had valid reference
end
if replacetext ~= "" and strout then strout = replacetext end
return strout
end
for _, claim in ipairs( claims ) do
local snack = claim.mainsnak or claim
-------------------------------------------------------------------------------
if (snack.snaktype == 'value') and (snack.datatype == 'time') and snack.datavalue.value.precision >= 11 then -- s'il s'agit d'un time et que la précision est au moins l'année
-- rendersnak takes a table (propval) containing the information stored on one property value
local iso = snack.datavalue.value.time
-- and returns the value as a string and its language if monolingual text.
_, _, iso = string.find(iso, "(+%d+-%d+-%d+T)")
-- It handles data of type:
local deleteIfDuplicate = false
-- wikibase-item
if snack.datavalue.value.calendarmodel == 'http://www.wikidata.org/entity/Q1985727' then -- si la date est grégorienne
-- time
if modules.formatDate.before('+1582', iso) then -- si avant 1582 on calcule la date julienne
-- string, url, commonsMedia, external-id
_, _, y, m, d = string.find(iso, "+(%d+)-(%d+)-(%d+)T")
-- quantity
y, m , d = modules.datemodule.gregorianToJulian(y, m , d)
-- globe-coordinate
if m < 10 then m = '0' .. m end
-- monolingualtext
if d < 10 then d = '0' .. d end
-- It also requires linked, the link/pre/postfixes, uabbr, and the arguments passed from frame.
iso = '+' .. y .. '-' .. m .. '-' .. d .. 'T'
-- The optional filter parameter allows quantities to be be filtered by unit Qid.
deleteIfDuplicate = true
-------------------------------------------------------------------------------
-- 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, args)
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
local index = findIndex(newIsos, iso)
end
if index >= 0 then -- si la date est déjà présente
val = pre .. label .. post
cat = cat .. '[[Catégorie:Article avec des dates identiques venant de wikidata dans le code de l\'infobox]]'
end -- test for link required
if removedupesdate == "cat" then -- ne faire que catégoriser
------------------------------------
table.insert(newIsos, iso)
elseif dtype == "time" then -- data type is time:
table.insert(newClaims, claim)
-- time is in timestamp format
elseif not deleteIfDuplicate then -- supprimer l'autre date si la date courante n'a pas été convertie
-- date precision is integer per mediawiki
newClaims[index] = claim
-- output formatting according to preferences (y/dmy/mdy)
end -- sinon supprimer la date courante
-- BC format as BC or BCE
else -- pas de doublon
-- plaindate is passed to disable looking for "sourcing cirumstances"
table.insert(newIsos, iso)
-- or to set the adjectival form
table.insert(newClaims, claim)
-- 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
--
-- a switch to turn on/off showing units, default is true
local showunits = parseParam(args.su or args.showunits, true)
--
-- convert amount to a number
local amount = tonumber(dv.amount) or i18n["NaN"]
--
-- scale factor for millions, billions, etc.
local sc = tostring(args.scale or ""):sub(1,1):lower()
local scale
if sc == "a" then
-- automatic scaling
if amount > 1e15 then
scale = 12
elseif amount > 1e12 then
scale = 9
elseif amount > 1e9 then
scale = 6
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
elseif snack.datavalue.value.calendarmodel == 'http://www.wikidata.org/entity/Q1985786' then -- si date julienne
end
if not modules.formatDate.before('+1582', iso) then -- si après 1582 on calcule la date grégorienne
if fnum then amount = args.langobj:formatNum( amount ) end
_, _, y, m, d = string.find(iso, "+(%d+)-(%d+)-(%d+)T")
if posdif ~= negdif then
y, m , d = modules.datemodule.julianToGregorian(y, m , d)
-- non-symmetrical
range if =m "< +"10 ..then posdifm ..= " -"'0' .. negdifm end
elseif if posdifd < 10 then d ~= '0' then.. d end
iso = '+' .. y .. '-' .. m .. '-' .. d .. 'T'
-- symmetrical and non-zero
deleteIfDuplicate = true
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
local index = findIndex(newIsos, iso)
if index >= 0 then -- si date déjà présente
cat = cat .. '[[Catégorie:Article avec des dates identiques venant de wikidata dans le code de l\'infobox]]'
if removedupesdate == "cat" then -- ne faire que catégoriser
table.insert(newIsos, iso)
table.insert(newClaims, claim)
elseif not deleteIfDuplicate then -- supprimer l'autre date si la date courante n'a pas été convertie
newClaims[index] = claim
end -- sinon supprimer la date courante
else -- pas de doublon
table.insert(newIsos, iso)
table.insert(newClaims, claim)
end
else -- autre calendrier
table.insert(newIsos, iso)
table.insert(newClaims, claim)
end
else -- précision insuffisante
if fnum then amount = args.langobj:formatNum( amount ) end
table.insert(newIsos, iso)
end
table.insert(newClaims, claim)
-- 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.getBestStatements(unitqid, "P5061")
-- construct fallback table, add local lang and multiple languages
local fbtbl = mw.language.getFallbacksFor( args.lang )
table.insert( fbtbl, 1, args.lang )
table.insert( fbtbl, 1, "mul" )
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
if found then break end
end -- loop through fallback table
end -- loop through values of P5061
if found then usep, unit = " ", usym end
end
end
end
-- format display:
return newClaims, cat
if conv then
end
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)
local function timeFromQualifs(claim, qualifs)
if latsec == 0 and longsec == 0 then
local claimqualifs = claim.qualifiers
if latmin == 0 and longmin == 0 then
if not claimqualifs then
val = latdeg .. "°" .. ns .. " " .. longdeg .. "°" .. ew
return nil
else
end
val = latdeg .. "°" .. latmin .. "′" .. ns .. " "
for i, qualif in pairs(qualifs or timequalifiers) do
val = val .. longdeg .. "°".. longmin .. "′" .. ew
local vals = claimqualifs[qualif]
end
if vals and (vals[1].snaktype == 'value') then
else
return vals[1].datavalue.value.time, vals[1].datavalue.value.precision
val = latdeg .. "°" .. latmin .. "′" .. latsec .. "″" .. ns .. " "
val = val .. longdeg .. "°" .. longmin .. "′" .. longsec .. "″" .. ew
end
end
end
end
------------------------------------
elseif dtype == "monolingualtext" then -- data type is Monolingual text:
-- has mainsnak.datavalue.value as a table containing language/text pairs
-- collect all the values in 'out' and languages in 'mlt' and process them later
val = pre .. dv.text .. post
mlt = dv.language
------------------------------------
else
-- some other data type so write a specific handler
val = "unknown data type: " .. dtype
end -- of datatype/unknown value/sourced check
return val, mlt
end
local function atDate(claim, mydate)
if mydate == "today" then
mydate = os.date("!%Y-%m-%dT%TZ")
end
-- determines required precision depending on the atdate format
local d = mw.text.split(mydate, "-")
local myprecision
-------------------------------------------------------------------------------
if d[3] then
-- propertyvalueandquals takes a property object, the arguments passed from frame,
myprecision = 11 -- day
-- and a qualifier propertyID.
elseif d[2] then
-- It returns a sequence (table) of values representing the values of that property
myprecision = 10 -- month
-- and qualifiers that match the qualifierID if supplied.
else
-------------------------------------------------------------------------------
myprecision = 9 -- year
-- Dependencies: parseParam(); sourced(); labelOrId(); i18n.latestdatequalifier(); format_Date();
end
-- makeOrdinal(); roundto(); decimalPrecision(); decimalToDMS(); assembleoutput();
-------------------------------------------------------------------------------
local function propertyvalueandquals(objproperty, args, qualID)
-- needs this style of declaration because it's re-entrant
-- with point in time
-- onlysourced is a boolean passed to return only values sourced to other than Wikipedia
local d, storedprecision = timeFromQualifs(claim, {'P585'})
-- if nothing or an empty string is passed set it true
if d then
local onlysrc = parseParam(args.onlysourced or args.osd, true)
return modules.formatDate.equal(mydate, d, math.min(myprecision, storedprecision))
end
-- with start or end date -- TODO: precision
local mindate = timeFromQualifs(claim, {'P580'})
local maxdate = timeFromQualifs(claim, {'P582'})
if modules.formatDate.before(mydate, mindate) and modules.formatDate.before(maxdate, mydate) then
return true
end
return false
end
local function check(claim, condition)
-- linked is a a boolean that enables the link to a local page via sitelink
if type(condition) == 'function' then -- cas standard
-- if nothing or an empty string is passed set it true
return condition(claim)
local linked = parseParam(args.linked, true)
end
return formatError('invalid type', 'function', type(condition))
end
local function minPrecision(claim, minprecision)
-- prefix is a string that may be nil, empty (""), or a string of characters
local snack
-- this is prefixed to each value
if claim.qualifiers then -- si une date est donnée en qualificatif, c'est elle qu'on utilise de préférence au mainsnak
-- useful when when multiple values are returned
for i, j in ipairs(datequalifiers) do
-- any double-quotes " are stripped out, so that spaces may be passed
if claim.qualifiers[j] then
local prefix = (args.prefix or ""):gsub('"', '')
snack = claim.qualifiers[j][1]
break
end
end
end
if not snack then
snack = claim.mainsnak or claim
end
if (snack.snaktype == 'value') and (snack.datatype == 'time') and (snack.datavalue.value.precision < minprecision) then
return false
end
return true
end
function wd.sortClaims(claims, sorttype)
-- postfix is a string that may be nil, empty (""), or a string of characters
if not claims then
-- this is postfixed to each value
return nil
-- useful when when multiple values are returned
end
-- any double-quotes " are stripped out, so that spaces may be passed
if sorttype == 'chronological' then
local postfix = (args.postfix or ""):gsub('"', '')
return wd.chronoSort(claims)
elseif sorttype == 'inverted' then
return wd.chronoSort(claims, true)
elseif sorttype == 'order' then
return wd.chronoSort(claims)
elseif sorttype == 'ascending' then
return wd.quantitySort(claims)
elseif sorttype == 'descending' then
return wd.quantitySort(claims, true)
elseif type(sorttype) == 'function' then
table.sort(claims, sorttype)
return claims
elseif type(sorttype) == 'string' and sorttype:sub(1, 1) == 'P' then
return wd.numericPropertySort(claims, sorttype)
end
return claims
end
function wd.filterClaims(claims, args) --retire de la tables de claims celles qui sont éliminés par un des filters de la table des filters
-- 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('"', '')
local function filter(condition, filterfunction, funargs)
-- linkpostfix is a string that may be nil, empty (""), or a string of characters
if not args[condition] then
-- this is postfixed to each value when linking is enabled with lprefix
return
-- useful when when multiple values are returned
end
-- any double-quotes " are stripped out, so that spaces may be passed
for i = #claims, 1, -1 do
local lpostfix = (args.linkpostfix or ""):gsub('"', '')
if not( filterfunction(claims[i], args[funargs[1]], args[funargs[2]], args[funargs[3]]) ) then
table.remove(claims, i)
end
end
end
filter('isinlang', isInLanguage, {'isinlang'} )
filter('excludespecial', notSpecial, {} )
filter('condition', check, {'condition'} )
if claims[1] and claims[1].mainsnak then
filter('targetvalue', hasTargetValue, {'targetvalue'} )
filter('atdate', atDate, {'atdate'} )
filter('qualifier', wd.hasQualifier, {'qualifier', 'qualifiervalue'} )
filter('qualifiernumber', wd.hasQualifierNumber, {'qualifiernumber', 'qualifiernumbervalue'} )
filter('excludequalifier', excludeQualifier, {'excludequalifier', 'excludequalifiervalue'} )
filter('withsource', hasSource, {'withsource', 'sourceproperty'} )
filter('withdate', wd.hasDate, {} )
filter('excludevalues', excludeValues, {'excludevalues'})
filter('withlink', hasLink, {'withlink', 'linklang'} )
filter('minprecision', minPrecision, {'minprecision'} )
claims = withRank(claims, args.rank or 'best')
end
if #claims == 0 then
return nil
end
if args.sorttype then
claims = wd.sortClaims(claims, args.sorttype)
end
if args.numval2 then
claims = lastVals(claims, args.numval2)
end
if args.numval then
claims = firstVals(claims, args.numval)
end
return claims
end
-- 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)
function wd.loadEntity(entity, cache)
-- unitabbr is a boolean passed to enable unit abbreviations for common units
if type(entity) ~= 'table' then
-- if nothing or an empty string is passed set it false
if cache then
local uabbr = parseParam(args.unitabbr or args.uabbr, false)
if not cache[entity] then
cache[entity] = mw.wikibase.getEntity(entity)
-- qualsonly is a boolean passed to return just the qualifiers
mw.log("cached")
-- if nothing or an empty string is passed set it false
end
local qualsonly = parseParam(args.qualsonly or args.qo, false)
return cache[entity]
else
-- maxvals is a string that may be nil, empty (""), or a number
if entity == '' or (entity == '-') then
-- this determines how many items may be returned when multiple values are available
entity = nil
-- setting it = 1 is useful where the returned string is used within another call, e.g. image
end
local maxvals = tonumber(args.maxvals) or 0
return mw.wikibase.getEntity(entity)
-- 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 unless qualsonly is set
args.qdf = args.qdf or args.qualifierdateformat or args.df or (not qualsonly and "y")
local lang = args.lang or findLang().code
-- qualID is a string list of wanted qualifiers or "ALL"
qualID = qualID or ""
-- capitalise list of wanted qualifiers and substitute "DATES"
qualID = qualID:upper():gsub("DATES", "P580, P582")
local allflag = (qualID == "ALL")
-- create table of wanted qualifiers as key
local qwanted = {}
-- create sequence of wanted qualifiers
local qorder = {}
for q in mw.text.gsplit(qualID, "%p") do -- split at punctuation and iterate
local qtrim = mw.text.trim(q)
if qtrim ~= "" then
qwanted[mw.text.trim(q)] = true
qorder[#qorder+1] = qtrim
end
else
return entity
end
end
-- qsep is the output separator for rendering qualifier list
local qsep = (args.qsep or ""):gsub('"', '')
-- qargs are the arguments to supply to assembleoutput()
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,
["sn"] = parseParam(args.qsn or args.qshortname, false),
}
-- 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
function wd.getClaims( args ) -- returns a table of the claims matching some conditions given in args
-- out[] holds the a list of returned values for this property
if args.claims then -- if claims have already been set, return them
-- mlt[] holds the language code if the datatype is monolingual text
return args.claims
local out = {}
end
local mlt = {}
local properties = args.property
if type(properties) == 'string' then
properties = wd.splitStr(string.upper(args.property))
end
if not properties then
return formatError( 'property-param-not-provided' )
end
--Get entity
for k, v in ipairs(objproperty) do
local hasvalueentity = trueargs.entity
if type(onlysrcentity) and== not sourced(v))'string' then
if entity == '' then
-- no value: it isn't sourced when onlysourced=true
hasvalueentity = falsenil
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
elseif type(entity) == 'table' then
entity = entity.id
end
if (not entity) then
entity = mw.wikibase.getEntityIdForCurrentPage()
end
if (not entity) or (entity == '-') then
return nil
end
local claims = {}
if #properties == 1 then
-- See if qualifiers are to be returned:
claims = mw.wikibase.getAllStatements(entity, properties[1]) -- do not use mw.wikibase.getBestStatements at this stage, as it may remove the best ranked values that match other criteria in the query
local snak = v.mainsnak or v
else
if hasvalue and v.qualifiers and qualID ~= "" and snak.snaktype~="novalue" then
for i, prop in ipairs(properties) do
-- collect all wanted qualifier values returned in qlist, indexed by propertyID
local newclaims = mw.wikibase.getAllStatements(entity, prop)
local qlist = {}
if newclaims and #newclaims > 0 then
local timestart, timeend = "", ""
for j, claim in ipairs(newclaims) do
-- loop through qualifiers
table.insert(claims, claim)
for k1, v1 in pairs(v.qualifiers) do
if allflag or qwanted[k1] then
if k1 == "P1326" then
local ts = v1[1].datavalue.value.time
local dp = v1[1].datavalue.value.precision
qlist[k1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "before")
elseif k1 == "P1319" then
local ts = v1[1].datavalue.value.time
local dp = v1[1].datavalue.value.precision
qlist[k1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "after")
elseif k1 == "P580" then
timestart = propertyvalueandquals(v1, qargs)[1] or "" -- treat only one start time as valid
elseif k1 == "P582" then
timeend = propertyvalueandquals(v1, qargs)[1] or "" -- treat only one end time as valid
else
local q = assembleoutput(propertyvalueandquals(v1, qargs), qargs)
-- we already deal with circa via 'sourcing circumstances' if the datatype was time
-- circa may be either linked or unlinked *** internationalise later ***
if datatype ~= "time" or q ~= "circa" and not (type(q) == "string" and q:find("circa]]")) then
qlist[k1] = q
end
end
end -- of test for wanted
end -- of loop through qualifiers
-- set date separator
local t = timestart .. timeend
-- *** internationalise date separators later ***
local dsep = "–"
if t:find("%s") or t:find(" ") then dsep = " – " end
-- set the order for the list of qualifiers returned; start time and end time go last
if next(qlist) then
local qlistout = {}
if allflag then
for k2, v2 in pairs(qlist) do
qlistout[#qlistout+1] = v2
end
else
for i2, v2 in ipairs(qorder) do
qlistout[#qlistout+1] = qlist[v2]
end
end
if t ~= "" then
qlistout[#qlistout+1] = timestart .. dsep .. timeend
end
local qstr = assembleoutput(qlistout, qargs)
if qualsonly then
out[#out+1] = qstr
else
out[#out] = out[#out] .. " (" .. qstr .. ")"
end
elseif t ~= "" then
if qualsonly then
if timestart == "" then
out[#out+1] = timeend
elseif timeend == "" then
out[#out+1] = timestart
else
out[#out+1] = timestart .. dsep .. timeend
end
else
out[#out] = out[#out] .. " (" .. timestart .. dsep .. timeend .. ")"
end
end
end
end -- of test for qualifiers wanted
end
if maxvals > 0 and #out >= maxvals then break end
end -- of for each value loop
if (not claims) or (#claims == 0) then
-- we need to pick one value to return if the datatype was "monolingualtext"
return nil
-- 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 outwd.filterClaims(claims, args)
end
--=== ENTITY FORMATTING ===
function wd.getLabel(entity, lang1, lang2)
-------------------------------------------------------------------------------
-- Common code for p.getValueByQual and p.getValueByLang
if (not entity) then
-------------------------------------------------------------------------------
return nil -- ou option de gestion des erreurs ?
-- Dependencies: parseParam; setRanks; parseInput; sourced; assembleoutput;
end
-------------------------------------------------------------------------------
entity = entity.id or ( type(entity) == "string" and entity)
local _getvaluebyqual = function(frame, qualID, checkvalue)
if not(type(entity) == 'string') then return nil end
lang1 = lang1 or defaultlang
local str, lang --str : texte rendu, lang : langue de celui-ci
if lang1 == defaultlang then -- le plus économique
str, lang = mw.wikibase.getLabelWithLang(entity) -- le libellé peut être en français ou en anglais
else
str = mw.wikibase.getLabelByLang(entity, lang1)
if str then lang = lang1 end
end
if str and (lang == lang1) then --pas de catégorie "à traduire" si on a obtenu un texte dans la langue désirée (normalement fr)
return str
end
if lang2 then -- langue secondaire, avec catégorie "à traduire"
str2 = mw.wikibase.getLabelByLang(entity, lang2)
if str2 then
lang = lang2
str = str2
end
end
if not str then --si ni lang1, ni lang2 ni l'anglais ne sont présents, parcours de la hiérarchie des langues
for _, trylang in ipairs(modules.langhierarchy.codes) do
str = mw.wikibase.getLabelByLang(entity, trylang)
if str then
lang = trylang
break
end
end
end
if str then
local translationCat = modules.i18n['to translate']
translationCat = translationCat .. (modules.langhierarchy.cattext[lang] or '')
translationCat = addCat(translationCat)
return str, translationCat
end
end
function wd.formatEntity( entity, params )
-- 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 (not entity) then
if qualID == "" then return "no qualifier supplied" end
return nil --formatError('entity-not-found')
end
local id = entity
if type(id) == 'table' then
id = id.id
end
params = params or {}
-- onlysourced is a boolean passed to return property values
local lang = params.lang or defaultlang
-- only when property values are sourced to something other than Wikipedia
local speciallabels = params.speciallabels
-- if nothing or an empty string is passed set it true
local displayformat = params.displayformat
-- if "false" or "no" or 0 is passed set it false
local labelformat = params.labelformat
local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true)
local labelformat2 = params.labelformat2
local defaultlabel = params.defaultlabel or id
local linktype = params.link
local defaultlink = params.defaultlink
local defaultlinkquery = params.defaultlinkquery
if speciallabels and speciallabels[id] then --speciallabels override the standard label + link combination
-- set the requested ranks flags
return speciallabels[id]
frame.args.reqranks = setRanks(frame.args.rank)
end
if params.displayformat == 'raw' then
return id
end
local link, label, translationCat
-- set a language object and code in the frame.args table
frame.args.langobj = findLang(frame.args.lang)
if type(labelformat) == 'function' then -- sert à des cas particuliers
frame.args.lang = frame.args.langobj.code
label, translationCat = labelformat(entity)
end
if not label then label, translationCat = wd.getLabel(entity, lang, params.wikidatalang) end
translationCat = translationCat or "" -- sera toujours ajoutée au résultat mais sera vide si la catégorie de maintenance n'est pas nécessaire
local args = frame.args
if type(labelformat2) == 'function' then -- sert à des cas particuliers
label = labelformat2(label)
end
-- détermination du fait qu'on soit ou non en train de rendre l'élément sur la page de son article
local rendering_entity_on_its_page = wd.isPageOfQId(id)
if not label then
if (defaultlabel == '-') then
return nil
end
link = wd.siteLink(id, 'wikidata')
return '[[' .. link .. '|' .. id .. ']]' .. translationCat
-- si pas de libellé, on met un lien vers Wikidata pour qu'on comprenne à quoi ça fait référence
end
if (linktype == '-') or rendering_entity_on_its_page then
-- check for locally supplied parameter in second unnamed parameter
return label .. translationCat
-- success means no local parameter and the property exists
end
local qid, props = parseInput(frame, args[2], propertyID)
local linkedlink = parseParam(argswd.linkedsiteLink(entity, linktype, truelang)
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()
local maxvals = tonumber(args.maxvals) or 0
if filter == "" then filter = nil end
-- defaultlinkquery will try to link to another page on this Wiki
if qid then
if (not link) and defaultlinkquery then
local out = {}
if type(defaultlinkquery) == 'string' then
-- Scan through the values of the property
defaultlinkquery = {property = defaultlinkquery}
-- 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 -- of check for sourced
end -- of check for matching required value and has qualifiers
else
return nil
end -- of check for string
if maxvals > 0 and #out >= maxvals then break end
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
local 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 -- 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
defaultlinkquery.excludespecial = true
defaultlinkquery.entity = entity
-- check if it's an instance of (P31) a country (Q6256) or sovereign state (Q3624078)
local claims = wd.getClaims(defaultlinkquery)
-- and terminate the chain if it is
if claims then
local inst = mw.wikibase.getAllStatements(qid, "P31")
for i, j in pairs(claims) do
if #inst > 0 then
for local k,id v= in ipairswd.getMainId(instj) do
link = wd.siteLink(id, linktype, lang)
local instid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id
if link then
-- stop if it's a country (or a country within the United Kingdom if skip is true)
if instid == "Q6256" or instid == "Q3624078" or (skip and instid == "Q3336843") then
prop = nil -- this will ensure this is treated as top-level ___location
break
end
end
end
end
if link then
if mw.ustring.sub(link, 1, 9) == "Category:" or mw.ustring.sub(link, 1, 10) == "Catégorie:" then
link = ":" .. link --lier vers une catégorie au lieu de catégoriser
end
return '[[' .. link .. '|' .. label .. ']]' .. translationCat
end
-- if not link, you can use defaultlink: a sidelink to another Wikimedia project
-- get the name of this ___location and update qid to point to the parent ___location
if prop(not and prop.mainsnak.datavaluedefaultlink) then
defaultlink = {'enwiki'}
if not skip or count == 0 then
end
local args = { lprefix = ":" }
if defaultlink and (defaultlink ~= '-') then
out[#out+1] = linkedItem(qid, args) -- get a linked value if we can
local linktype
local sidelink, site, langcode
if type(defaultlink) == 'string' then
defaultlink = {defaultlink}
end
for i, j in ipairs(defaultlink) do
sidelink, site, langcode = wd.siteLink(entity, j, lang)
if sidelink then
break
end
end
qid, prevqid = prop.mainsnak.datavalue.value.id, qid
if not sidelink then
sidelink, site = wd.siteLink(entity, 'wikidata')
end
local icon, class, title = site, nil, nil -- le texte affiché du lien
if site == 'wiki' then
icon, class, title = langcode, "indicateur-langue", wd.translate('see-another-language', mw.language.fetchLanguageName(langcode, defaultlang))
elseif site == 'wikidata' then
icon, class, title = 'd', "indicateur-langue", wd.translate('see-wikidata')
else
title = wd.translate('see-another-project', site)
-- 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
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
else
-- no shortname, so just add the label
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
finished = true
end
local val = '[[' .. sidelink .. '|' .. '<span class = "' .. (class or '').. '" title = "' .. (title or '') .. '">' .. icon .. '</span>]]'
count = count + 1
return label .. ' <small>(' .. val .. ')</small>' .. translationCat
until finished or count >= 10 -- limit to 10 levels to avoid infinite loops
end
return label .. translationCat
end
-- remove the first ___location if not required
if not first then table.remove(out, 1) end
function wd.addTrackingCat(prop, cat) -- doit parfois être appelé par d'autres modules
-- we might have duplicate text for consecutive locations, so remove them
if #outtype(prop) >== 2'table' then
prop = prop[1] -- devrait logiquement toutes les ajouter
local plain = {}
for i, v in ipairs(out) do
-- strip any links
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
table.remove(out, removeidx)
table.remove(plain, removeidx)
else
idx = idx +1
end
until idx >= #out
end
if not prop and not cat then
return out
return formatError("property-param-not-provided")
end
if not cat then
cat = wd.translate('trackingcat', prop or 'P??')
end
return addCat(cat )
end
local function unknownValue(snak, label)
local str = label
if type(str) == "function" then
-------------------------------------------------------------------------------
str = str(snak)
-- _getsumofparts scans the property 'has part' (P527) for values matching a list.
end
-- 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.
if (not str) then
-- The sum is returned as a number (i.e. 0 if none)
if snak.datatype == 'time' then
-- a table of arguments is supplied implementing the usual parameters.
str = wd.translate('sometime')
-------------------------------------------------------------------------------
else
-- Dependencies: setRanks; parseParam; parseInput; sourced; assembleoutput;
str = wd.translate('somevalue')
-------------------------------------------------------------------------------
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
return sum
if type(str) ~= "string" then
return formatError(snak.datatype)
end
return str
end
local function noValue(displayformat)
if not displayformat then
-------------------------------------------------------------------------------
return wd.translate('novalue')
-------------------------------------------------------------------------------
-- 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
if type(displayformat) == 'string' then
return displayformat
end
return formatError()
end
local function getLangCode(entityid)
-- implement eid parameter
return modules.langcodes[tonumber(entityid:sub(2))]
local eid = args.eid
end
if eid == "" then
local function showLang(statement, maxLang) -- retourne le code langue entre paranthèse avant la valeur (par exemple pour les biblios et liens externes)
local mainsnak = statement.mainsnak
if mainsnak.snaktype ~= 'value' then
return nil
elseif eid then
args.qid = eid
end
local langlist = {}
if mainsnak.datavalue.type == 'monolingualtext' then
langlist = {mainsnak.datavalue.value.language}
elseif (not statement.qualifiers) or (not statement.qualifiers.P407) then
return
else
for i, j in pairs( statement.qualifiers.P407 ) do
if j.snaktype == 'value' then
local langentity = wd.getId(j)
local langcode = getLangCode(langentity)
table.insert(langlist, langcode)
end
end
end
if (#langlist > 1) or (#langlist == 1 and langlist[1] ~= defaultlang) then -- si c'est en français, pas besoin de le dire
langlist.maxLang = maxLang
return modules.langmodule.indicationMultilingue(langlist)
end
end
local propertyID = mw.text.trim(args[1] or "")
-- === DATE HANDLING ===
args.reqranks = setRanks(args.rank)
function wd.addStandardQualifs(str, statement)
-- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value
if (not statement) or (not statement.qualifiers) then
-- this is useful for tracking and debugging, so we set fetchwikidata=ALL to fill the whitelist
return str
local replacetext = mw.text.trim(args.rt or args.replacetext or "")
end
if replacetext ~= "" then
if not str then
args.fetchwikidata = "ALL"
return error()-- what's that ?
end
if statement.qualifiers.P1480 then
local f = {}
for i, j in pairs(statement.qualifiers.P1480) do
f.args = args
local v = wd.getId(j)
local entityid, props = parseInput(f, f.args[2], propertyID)
if (v == "Q21818619") then
str = wd.translate('approximate-place', str)
if not entityid then
elseif (v == "Q18122778") or (v == "Q18912752") then
return props -- either the input parameter or nothing
str = wd.translate('uncertain-information', str)
elseif (v == "Q5727902") then
if (statement.mainsnak.datatype == 'time') then
str = modules.formatDate.fuzzydate(str)
else
str = wd.translate('approximate-value', str)
end
end
end
end
return str
-- 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
local function rangeObject(begin, ending, params)
--[[
-------------------------------------------------------------------------------
objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending)
-- getValue is used to get the value(s) of a property
]]--
-- The property ID is passed as the first unnamed parameter and is required.
local timestamp
-- A locally supplied parameter may optionaly be supplied as the second unnamed parameter.
if begin then
-- The function will now also return qualifiers if parameter qual is supplied
timestamp = begin.timestamp
-------------------------------------------------------------------------------
else
-- Dependencies: _getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced;
timestamp = ending.timestamp
-- 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 {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'}
return p._getValue(args)
end
local function dateObject(orig, params)
--[[ transforme un snak en un nouvel objet utilisable par Module:Date complexe
-------------------------------------------------------------------------------
{type = 'dateobject', timestamp = str, era = '+' ou '-', year = number, month = number, day = number, calendar = calendar}
-- getPreferredValue is used to get a value,
]]--
-- (or a comma separated list of them if multiple values exist).
if not params then
-- If preferred ranks are set, it will return those values, otherwise values with normal ranks
params = {}
-- now redundant to getValue with |rank=best
end
-------------------------------------------------------------------------------
-- Dependencies: p.getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput;
local newobj = modules.formatDate.splitDate(orig.time, orig.calendarmodel)
-- parseParam; sourced; labelOrId; i18n.latestdatequalifier; format_Date;
-- makeOrdinal; roundto; decimalPrecision; decimalToDMS;
newobj.precision = params.precision or orig.precision
-------------------------------------------------------------------------------
newobj.type = 'dateobject'
p.getPreferredValue = function(frame)
return newobj
frame.args.rank = "best"
return p.getValue(frame)
end
local function objectToText(obj, params)
if obj.type == 'dateobject' then
-------------------------------------------------------------------------------
return modules.formatDate.simplestring(obj, params)
-- getCoords is used to get coordinates for display in an infobox
elseif obj.type == 'rangeobject' then
-- whitelist and blacklist are implemented
return modules.formatDate.daterange(obj.begin, obj.ending, params)
-- optional 'display' parameter is allowed, defaults to nil - was "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 nothing
local disp = frame.args.display or ""
if disp == "" then
disp = nil -- default to not supplying display parameter, was "inline, title"
end
end
function wd.getDateFromQualif(statement, qualif)
-- there may be a format parameter to switch from deg/min/sec to decimal degrees
if (not statement) or (not statement.qualifiers) or not (statement.qualifiers[qualif]) then
-- default is deg/min/sec
return nil
-- decimal degrees needs |format = dec
local form = (frame.args.format or ""):lower():sub(1,3)
if form ~= "dec" then
form = "dms"
end
local v = statement.qualifiers[qualif][1]
if v.snaktype ~= 'value' then -- que faire dans ce cas ?
return nil
end
return dateObject(v.datavalue.value)
end
function wd.getDate(statement)
-- just deal with best values
local period = wd.getDateFromQualif(statement, 'P585') -- retourne un dateobject
frame.args.reqranks = setRanks("best")
if period then
return period
local qid, props = parseInput(frame, frame.args[1], propertyID)
if not qid then
return props -- either local parameter or nothing
else
local dv = props[1].mainsnak.datavalue.value
local lat, long, prec = dv.latitude, dv.longitude, dv.precision
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
local begin, ending = wd.getDateFromQualif(statement, 'P580'), wd.getDateFromQualif(statement, 'P582')
if begin or ending then
return rangeObject(begin, ending) -- retourne un rangeobject fait de deux dateobject
end
return nil
end
function wd.getFormattedDate(statement, params)
if not statement then
return nil
end
local str
-------------------------------------------------------------------------------
-- getQualifierValue is used to get a formatted value of a qualifier
--
-- 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)
--cherche la date avec les qualifs P580/P582
-- The property ID that will have a qualifier is the first unnamed parameter
local propertyIDdatetable = mwwd.text.trimgetDate(frame.args[1] or ""statement)
if datetable then
str = objectToText(datetable, params)
-- The value of the property we want to match whose qualifier value is to be returned
end
-- is passed in named parameter |pval=
local propvalue = frame.args.pval
-- puis limite intérieur / supérieur
if not str then
local start, ending = wd.getDateFromQualif(statement, 'P1319'), wd.getDateFromQualif(statement, 'P1326')
str = modules.formatDate.between(start, ending, params)
end
-- sinon, le mainsnak, pour les données de type time
-- The property ID of the qualifier
if (not str) and (statement.mainsnak.datatype == 'time') then
-- whose value is to be returned is passed in named parameter |qual=
local qualifierIDmainsnak = framestatement.args.qualmainsnak
if (mainsnak.snaktype == 'value') or (mainsnak.snaktype == 'somevalue') then
str = wd.formatSnak(mainsnak, params)
end
end
if str and params and (params.addstandardqualifs ~= '-') then
-- A filter can be set like this: filter=P642==Q22674854
str = wd.addStandardQualifs(str, statement)
local filter, fprop, fval
local ftable = mw.text.split(frame.args.filter or "", "==")
if ftable[2] then
fprop = mw.text.trim(ftable[1])
fval = mw.text.trim(ftable[2])
filter = true
end
return str
-- 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 apply the filter and find the value(s) of the qualifier we want
if not filter or (v1.qualifiers[fprop] and v1.qualifiers[fprop][1].datavalue.value.id == fval) then
local quals = v1.qualifiers[qualifierID]
if quals then
-- can't reference qualifer, so set onlysourced = "no" (args are strings, 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
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
return props -- either local parameter or nothing
end -- of test for success
return nil
end
wd.compare.by_quantity = function(c1, c2)
local v1 = wd.getDataValue(c1.mainsnak)
-------------------------------------------------------------------------------
local v2 = wd.getDataValue(c2.mainsnak)
-- getSumOfParts scans the property 'has part' (P527) for values matching a list.
if not (v1 and v2) then
-- The list is passed in parameter vlist.
return true
-- It consists of a string of Qids separated by spaces or any usual punctuation.
end
-- If the matched values have a qualifier 'quantity' (P1114), those quantities are summed.
return v1 < v2
-- 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
--[[ tri chronologique générique :
retourne une fonction de tri de liste de déclaration
en fonction d’une fonction qui calcule la clé de tri
et d’une fonction qui compare les clés de tri
paramètres nommés: (appel type wikidata.compare.chrono_key_sort{sortKey="nom clé"})
sortKey (optionnel) : chaine, le nom de la clé utilisée pour un tri
(pour éviter de rentrer en collision avec "dateSortKey"
utilisé par chronoSort au besoin)
snak_key_get_function : fonction qui calcule la valeur de la clé à partir d’un snak ou d’une déclaration,
(obligatoire) le résultat n’est calculé qu’une fois et est stocké en cache dans claim[sortKey]
key_compare_function : fonction de comparaison des clés calculées par snak_key_get_function
(optionnel)
--]]
function wd.chrono_key_sort(arg)
-------------------------------------------------------------------------------
-- getValueByQual gets the value of a property which has a qualifier with a given entity value
local snak_key_get_function = arg.snak_key_get_function
-- The call needs:
local sortKey = arg.sortKey or "dateSortKey"
-- a property ID (the unnamed parameter or 1=Pxxx)
local key_compare_function = arg.key_compare_function or
-- the ID of a qualifier for that property (qualID=Pyyy)
function(c1, c2) return c1 < c2 end
-- either the Wikibase-entity ID of a value for that qualifier (qvalue=Qzzz)
return function(claims)
-- or a string value for that qualifier (qvalue=abc123)
for _, claim in ipairs( claims ) do
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented
if not claim[sortKey] then
-------------------------------------------------------------------------------
local key = snak_key_get_function(claim)
-- Dependencies: _getvaluebyqual; parseParam; setRanks; parseInput; sourced;
if key then
-- assembleoutput;
claim[sortKey] = wd.compare.get_claim_date(key)
-------------------------------------------------------------------------------
else
p.getValueByQual = function(frame)
claim[sortKey] = 0
local qualID = frame.args.qualID
end
-- The Q-id of the value for the qualifier we want to match is in named parameter |qvalue=
end
local qval = frame.args.qvalue or ""
end
if qval == "" then return "no qualifier value supplied" end
table.sort(
local function checkQID(id)
claims,
return id == qval
function(c1, c2)
return key_compare_function(c1[sortKey], c2[sortKey])
end
)
return claims
end
return _getvaluebyqual(frame, qualID, checkQID)
end
function wd.quantitySort(claims, inverted)
-------------------------------------------------------------------------------
local function sort(c1, c2)
-- getValueByLang gets the value of a property which has a qualifier P407
local v1 = wd.getDataValue(c1.mainsnak)
-- ("language of work or name") whose value has the given language code
local v2 = wd.getDataValue(c2.mainsnak)
-- The call needs:
if not (v1 and v2) then
-- a property ID (the unnamed parameter or 1=Pxxx)
return true
-- 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
if inverted then
return v2 < v1
end
return v1 < v2
end
table.sort(claims, sort )
return _getvaluebyqual(frame, "P407", checkLanguage)
return claims
end
function wd.compare.get_claim_date(claim)
local snack = claim.mainsnak or claim
local iso
if (snack.snaktype == 'value') and (snack.datatype == 'time') then
iso = snack.datavalue.value.time
else
iso = timeFromQualifs(claim, datequalifiers) or '0'
end
-- transformation en nombre (indication de la base car gsub retourne deux valeurs)
return tonumber( iso:gsub( '(%d)%D', '%1' ), 10 )
end
function wd.compare.chronoCompare(c1, c2)
-------------------------------------------------------------------------------
return wd.compare.get_claim_date(c1) < wd.compare.get_claim_date(c2)
-- getValueByRefSource gets the value of a property which has a reference "stated in" (P248)
end
-- 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
-- fonction pour renverser l’ordre d’une autre fonction
-- The Q-id of the value we want to match is in named parameter |qvalue=
function wd.compare.rev(comp_criteria)
local qval = (frame.args.match or ""):upper()
return function(c1, c2)
if qval == "" then qval = "Q21540096" end
-- attention les tris en lua attendent des fonctions de comparaison strictement inférieur, on doit
-- vérifier la non égalité quand on inverse l’ordre d’un critère, d’ou "and comp_criteria(c2,c1)"
local unit = (frame.args.unit or ""):upper()
return not(comp_criteria(c1,c2)) and comp_criteria(c2,c1)
if unit == "" then unit = "Q4917" end
end
end
local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true)
-- set the requested ranks flags
frame.args.reqranks = setRanks(frame.args.rank)
-- Fonction qui trie des Claims de type time selon l'ordre chronologique
-- set a language object and code in the frame.args table
-- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim.
frame.args.langobj = findLang(frame.args.lang)
-- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification.
frame.args.lang = frame.args.langobj.code
function wd.chronoSort( claims, inverted )
local linked = parseParam(frame.args.linked, true)
for _, claim in ipairs( claims ) do
if not claim.dateSortKey then
local uabbr = parseParam(frame.args.uabbr or frame.args.unitabbr, false)
claim.dateSortKey = wd.compare.get_claim_date(claim)
end
-- qid not nil means no local parameter and the property exists
end
local qid, props = parseInput(frame, frame.args[2], propertyID)
table.sort(
claims,
if qid then
localfunction out( =c1, {}c2 )
if inverted then
local mlt= {}
return c2.dateSortKey < c1.dateSortKey
for k1, v1 in ipairs(props) do
if onlysrc == false or sourced(v1) then
if v1.references then
for k2, v2 in ipairs(v1.references) do
if v2.snaks.P248 then
for k3, v3 in ipairs(v2.snaks.P248) do
if v3.datavalue.value.id == qval then
out[#out+1], mlt[#out+1] = rendersnak(v1, frame.args, linked, "", "", "", "", uabbr, unit)
if not mlt[#out] then
-- we only need one match per property value
-- unless datatype was monolingual text
break
end
end -- of test for match
end -- of loop through values "stated in"
end -- of test that "stated in" exists
end -- of loop through references
end -- of test that references exist
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
return c1.dateSortKey < c2.dateSortKey
end
)
return assembleoutput(out, frame.args, qid, propertyID)
return claims
else
return props -- no property or local parameter supplied
end -- of test for success
end
local function get_numeric_claim_value(claim, propertySort)
local val
-------------------------------------------------------------------------------
local claimqualifs = claim.qualifiers
-- getPropertyIDs takes most of the usual parameters.
if claimqualifs then
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented.
local vals = claimqualifs[propertySort]
-- It returns the Entity-IDs (Qids) of the values of a property if it is a Wikibase-Entity.
if vals and vals[1].snaktype == 'value' then
-- Otherwise it returns nothing.
val = vals[1].datavalue.value
-------------------------------------------------------------------------------
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
-------------------------------------------------------------------------------
p._getPropertyIDs = function(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 ""):upper()
-- 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
local 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 tonumber(val or 0)
return assembleoutput(out, args, qid, pid)
end
function wd.compare.numeric(propertySort)
p.getPropertyIDs = function(frame)
return function(c1, c2)
local args = frame.args
return get_numeric_claim_value(c1, propertySort) < get_numeric_claim_value(c2, propertySort)
return p._getPropertyIDs(args)
end
end
-- Fonction qui trie des Claims de type value selon l'ordre de la propriété fournit
-- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim.
-- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification.
function wd.numericPropertySort( claims, propertySort )
-------------------------------------------------------------------------------
for _, claim in ipairs( claims ) do
-- getQualifierIDs takes most of the usual parameters.
if not claim.dateSortKey then
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented.
local val = get_numeric_claim_value(claim, propertySort)
-- It takes a property-id as the first unnamed parameter, and an optional parameter qlist
claim.dateSortKey = tonumber(val or 0)
-- which is a list of qualifier property-ids to search for (default is "ALL")
end
-- It returns the Entity-IDs (Qids) of the values of a property if it is a Wikibase-Entity.
end
-- Otherwise it returns nothing.
table.sort(
-------------------------------------------------------------------------------
claims,
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
function ( c1, c2 )
-------------------------------------------------------------------------------
return c1.dateSortKey < c2.dateSortKey
p.getQualifierIDs = function(frame)
end
local args = frame.args
)
args.reqranks = setRanks(args.rank)
return claims
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 ""):upper()
-- 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
-- get the other parameters
local onlysrc = parseParam(args.onlysourced or args.osd, true)
local maxvals = tonumber(args.maxvals) or 0
local qlist = args.qlist or ""
if qlist == "" then qlist = "ALL" end
qlist = qlist:gsub("[%p%s]+", " ") .. " "
local out = {}
for i, v in ipairs(props) do
local snak = v.mainsnak
if ( v.rank and args.reqranks[v.rank:sub(1, 1)] )
and ( snak.snaktype == "value" )
and ( sourced(v) or not onlysrc )
then
if v.qualifiers then
for k1, v1 in pairs(v.qualifiers) do
if qlist == "ALL " or qlist:match(k1 .. " ") then
for i2, v2 in ipairs(v1) do
if v2.datatype == "wikibase-item" and v2.snaktype == "value" then
out[#out+1] = v2.datavalue.value.id
end -- of test that id exists
end -- of loop through qualifier values
end -- of test for kq in qlist
end -- of loop through qualifiers
end -- of test for qualifiers
end -- of test for rank value, sourced, and value exists
if maxvals > 0 and #out >= maxvals then break end
end -- of loop through property values
return assembleoutput(out, args, qid, pid)
end
--[[
test possible en console pour la fonction précédente :
= p.formatStatements{entity = "Q375946", property = 'P50', sorttype = 'P1545', linkback = "true"}
--]]
-- ===================
-------------------------------------------------------------------------------
function wd.getReferences(statement)
-- getPropOfProp takes two propertyIDs: prop1 and prop2 (as well as the usual parameters)
local refdata = statement.references
-- If the value(s) of prop1 are of type "wikibase-item" then it returns the value(s) of prop2
if not refdata then
-- of each of those wikibase-items.
return nil
-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented
-------------------------------------------------------------------------------
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
-------------------------------------------------------------------------------
p._getPropOfProp = 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
local refs = {}
args.reqranks = setRanks(args.rank)
local hashes = {}
args.langobj = findLang(args.lang)
for i, ref in pairs(refdata) do
args.lang = args.langobj.code
local s
local pid1 = args.prop1 or args.pid1 or ""
local function hasValue(prop) -- checks that the prop is here with valid value
local pid2 = args.prop2 or args.pid2 or ""
if ref.snaks[prop] and ref.snaks[prop][1].snaktype == 'value' then
if pid1 == "" or pid2 == "" then return nil end
return true
end
return false
end
if ref.snaks.P248 then -- cas lorsque P248 (affirmé dans) est utilisé
for j, source in pairs(ref.snaks.P248) do
if source.snaktype == 'value' then
local page, accessdate, quotation
if hasValue('P304') then -- page
page = wd.formatSnak(ref.snaks.P304[1])
end
if hasValue('P813') then -- date de consultation
accessdate = wd.formatSnak(ref.snaks.P813[1])
end
if hasValue('P1683') then -- citation
quotation = wd.formatSnak(ref.snaks.P1683[1])
end
local sourceId = wd.getId(source)
s = modules.reference.citeitem(sourceId, {['page'] = page, ['accessdate'] = accessdate, ['citation'] = quotation})
table.insert(refs, s)
table.insert(hashes, ref.hash .. sourceId)
end
end
elseif hasValue('P8091') or hasValue('P854') then -- cas lorsque P8091 (Archival Resource Key) ou P854 (URL de la référence)est utilisé
local arkKey, url, title, author, publisher, accessdate, publishdate, publishlang, quotation, description
if hasValue('P8091') then
local f = {}
arkKey = wd.formatSnak(ref.snaks.P8091[1], {text = "-"})
f.args = args
url = 'https://n2t.net/' .. arkKey
local qid1, statements1 = parseInput(f, args[1], pid1)
if hasValue('P1476') then
-- parseInput nulls empty args[1] and returns args[1] if nothing on Wikidata
title = wd.formatSnak(ref.snaks.P1476[1])
if not qid1 then return statements1 end
-- otherwise it returns the qid and a table for the statement
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
title = arkKey
statements2 = mw.wikibase.getAllStatements(qid2, pid2)
end
ifelseif statements2[1]hasValue('P854') then
url = wd.formatSnak(ref.snaks.P854[1], {text = "-"})
local out2 = propertyvalueandquals(statements2, args, qualID)
if hasValue('P1476') then
out[#out+1] = assembleoutput(out2, args, qid2, pid2)
title = wd.formatSnak(ref.snaks.P1476[1])
else
title = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3')
end
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
p.getPropOfProp = function(frame)
local args= frame.args
if not args.prop1 and not args.pid1 then
args = frame:getParent().args
if not args.prop1 and not args.pid1 then return i18n.errors["No property supplied"] end
end
return p._getPropOfProp(args)
end
--todo : handle multiple values for author, etc.
if hasValue('P1810') then -- sous le nom
description = 'sous le nom ' .. wd.formatSnak(ref.snaks.P1810[1])
end
if hasValue('P813') then -- date de consultation
accessdate = wd.formatSnak(ref.snaks.P813[1])
end
if hasValue('P50') then -- author (item type)
author = wd.formatSnak(ref.snaks.P50[1])
elseif hasValue('P2093') then -- author (string type)
author = wd.formatSnak(ref.snaks.P2093[1])
end
if hasValue('P123') then -- éditeur
publisher = wd.formatSnak(ref.snaks.P123[1])
end
if hasValue('P1683') then -- citation
quotation = wd.formatSnak(ref.snaks.P1683[1])
end
if hasValue('P577') then -- date de publication
publishdate = wd.formatSnak(ref.snaks.P577[1])
end
if hasValue('P407') then -- langue de l'œuvre
local id = wd.getId(ref.snaks.P407[1])
publishlang = getLangCode(id)
end
s = modules.cite.lienWeb{titre = title, url = url, auteur = author, editeur = publisher, langue = publishlang, ['en ligne le'] = publishdate, ['consulté le'] = accessdate, ['citation'] = quotation, ['description'] = description}
table.insert(hashes, ref.hash)
table.insert(refs, s)
elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype == 'value' then
-------------------------------------------------------------------------------
s = wd.formatSnak(ref.snaks.P854[1], {text = "-"})
-- getAwardCat takes most of the usual parameters. If the item has values of P166 (award received),
table.insert(hashes, ref.snaks.P854[1].hash)
-- then it examines each of those awards for P2517 (category for recipients of this award).
table.insert(refs, s)
-- 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.getSitelink(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.getLabel(p734id)
famname = lbl and mw.text.nowiki(lbl) or ""
end
end
if #refs > 0 then
local onlysrc = parseParam(args.onlysourced or args.osd, true)
if #hashes == #refs then
local maxvals = tonumber(args.maxvals) or 0
return refs, hashes
local qualID = mw.text.trim(args.qual or ""):upper()
end
if qualID == "" then qualID = nil end
return refs
local out = {}
end
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.getSitelink(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
if sitelink then
if sk ~= "" then
out[#out+1] = "[[" .. lp .. sitelink .. "|" .. sk .. "]]"
elseif famname ~= "" then
out[#out+1] = "[[" .. lp .. sitelink .. "|" .. famname .. "]]"
else
out[#out+1] = "[[" .. lp .. sitelink .. "]]"
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
function wd.sourceStr(sources, hashes)
if not sources or (#sources == 0) then
-------------------------------------------------------------------------------
return nil
-- 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.getSitelink(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.getLabel(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.getSitelink(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
cat = "Category:" .. mw.text.nowiki(lbl)
end
end
end
cat1[#cat1+1] = cat
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
if maxvals > 0 and #cat2 >= maxvals then break end
end
local outuseHashes = {}hashes and #hashes == #sources
for k1i, v1j in ipairs(cat1sources) do
local refArgs = {name = 'ref', content = j}
for k2, v2 in ipairs(cat2) do
if skuseHashes and hashes[i] ~= ""'-' then
refArgs.args = {name = 'wikidata-' .. hashes[i]}
out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "|" .. sk .. "]]"
elseif famname ~= "" then
out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "|" .. famname .. "]]"
else
out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "]]"
end -- of check for sort keys
end
sources[i] = mw.getCurrentFrame():extensionTag(refArgs)
end
return table.concat(sources, '<sup class="reference cite_virgule">,</sup>')
args.noicon = "true"
return assembleoutput(out, args, qid, pid1)
end
function wd.getDataValue(snak, params)
if not params then
params = {}
end
local speciallabels = params.speciallabels -- parfois on a besoin de faire une liste d'éléments pour lequel le libellé doit être changé, pas très pratique d'utiliser une fonction pour ça
if snak.snaktype ~= 'value' then
-------------------------------------------------------------------------------
return nil
-- qualsToTable takes most of the usual parameters.
end
-- 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 qualsdatatype = argssnak.quals or ""datatype
local value = snak.datavalue.value
if quals == "" then return "" end
local displayformat = params.displayformat
if type(displayformat) == 'function' then
return displayformat(snak, params)
end
if datatype == 'wikibase-item' then
args.reqranks = setRanks(args.rank)
return wd.formatEntity(wd.getId(snak), params)
end
if datatype == 'url' then
local propertyID = mw.text.trim(args[1] or "")
if params.displayformat == 'raw' then
local f = {}
return value
f.args = args
else
local entityid, props = parseInput(f, "", propertyID)
return modules.weblink.makelink(value, params.text)
if not entityid then return "" end
end
end
args.langobj = findLang(args.lang)
args.lang = args.langobj.code
local pval = args.pval or ""
if datatype == 'math' then
local qplist = mw.text.split(quals, "%p") -- split at punctuation and make a sequential table
return mw.getCurrentFrame():extensionTag( "math", value)
for i, v in ipairs(qplist) do
qplist[i] = mw.text.trim(v):upper() -- remove whitespace and capitalise
end
if datatype == 'tabular-data' then
local col1 = args.firstcol or ""
return mw.ustring.sub(value, 6, 100) -- returns the name of the file, without the "Data:" prefix
if col1 ~= "" then
col1 = col1 .. "</td><td>"
end
if (datatype == 'string') or (datatype == 'external-id') or (datatype == 'commonsMedia') then -- toutes les données de type string sauf "math"
local emptycell = args.emptycell or " "
if params.urlpattern then
local urlpattern = params.urlpattern
-- construct a 2-D array of qualifier values in qvals
if type(urlpattern) == 'function' then
local qvals = {}
urlpattern = urlpattern(value)
for i, v in ipairs(props) do
end
local skip = false
-- encodage de l'identifiant qui se retrouve dans le path de l'URL, à l'exception des slashes parfois rencontrés, qui sont des séparateurs à ne pas encoder
if pval ~= "" then
local encodedValue = mw.uri.encode(value, 'PATH'):gsub('%%2F', '/')
local pid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id
-- les parenthèses autour du encodedValue:gsub() sont nécessaires, sinon sa 2e valeur de retour est aussi passée en argument au mw.ustring.gsub() parent
if pid ~= pval then skip = true end
local url = mw.ustring.gsub(urlpattern, '$1', (encodedValue:gsub('%%', '%%%%')))
value = '[' .. url .. ' ' .. (params.text or value) .. ']'
end
return value
if not skip then
end
local qval = {}
local vqualifiers = v.qualifiers or {}
if datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z
-- go through list of wanted qualifier properties
if displayformat == 'raw' then
for i1, v1 in ipairs(qplist) do
return value.time
-- check for that property ID in the statement's qualifiers
else
local qv, qtype
local dateobject = dateObject(value, {precision = params.precision})
if vqualifiers[v1] then
return objectToText(dateobject, params)
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
if vqualifiers[v1][1].snaktype == "value" 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
end
else
qv = mw.wikibase.formatValue(vqualifiers[v1][1])
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
end -- of for each value loop
if datatype == 'globe-coordinate' then
local out = {}
-- retourne une table avec clés latitude, longitude, précision et globe à formater par un autre module (à changer ?)
for i, v in ipairs(qvals) do
if displayformat == 'latitude' then
out[i] = "<tr><td>" .. col1 .. table.concat(qvals[i], "</td><td>") .. "</td></tr>"
return value.latitude
elseif displayformat == 'longitude' then
return value.longitude
else
local coordvalue = mw.clone( value )
coordvalue.globe = modules.globes[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack
return coordvalue -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ?
end
end
return table.concat(out, "\n")
end
if datatype == 'quantity' then -- todo : gérer les paramètres précision
local amount, unit = value.amount, value.unit
if unit then
-------------------------------------------------------------------------------
unit = unit:match('Q%d+')
-- getGlobe takes an optional qid of a Wikidata entity passed as |qid=
end
-- otherwise it uses the linked item for the current page.
-- If returns the Qid of the globe used in P625 (coordinate ___location),
if not unit then
-- or nil if there isn't one.
unit = 'dimensionless'
-------------------------------------------------------------------------------
end
-- Dependencies: none
-------------------------------------------------------------------------------
local raw
p.getGlobe = function(frame)
if displayformat == "raw" then
local qid = frame.args.qid or frame.args[1] or ""
raw = true
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
end
local coords = mw.wikibase.getBestStatements(qid, "P625")[1]
return modules.formatNum.displayvalue(amount, unit,
local globeid
{targetunit = params.targetunit, raw = raw, rounding = params.rounding, showunit = params.showunit or 'short', showlink = params.showlink}
if coords and coords.mainsnak.snaktype == "value" then
)
globeid = coords.mainsnak.datavalue.value.globe:match("(Q%d+)")
end
if datatype == 'monolingualtext' then
return globeid
if value.language == defaultlang then
end
return value.text
else
return modules.langmodule.langue({value.language, value.text, nocat=true})
end
end
return formatError('unknown-datavalue-type' )
-------------------------------------------------------------------------------
-- 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
function wd.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation
local claims = args.claims
local cat = ''
if not claims then
-------------------------------------------------------------------------------
claims = wd.getClaims(args)
-- getSitelink takes the qid of a Wikidata entity passed as |qid=
end
-- It takes an optional parameter |wiki= to determine which wiki is to be checked for a sitelink
if not claims or claims == {} then
-- If the parameter is blank, then it uses the local wiki.
return {}, {}, cat
-- If there is a sitelink to an article available, it returns the plain text link to the article
end
-- If there is no sitelink, it returns nil.
if args.removedupesdate and (args.removedupesdate ~= '-') then
-------------------------------------------------------------------------------
claims, cat = removeDupesDate(claims, args.removedupesdate)
-- Dependencies: none
end
-------------------------------------------------------------------------------
local props = {} -- liste des propriétés associété à chaque string pour catégorisation et linkback
p.getSiteLink = function(frame)
for i, j in pairs(claims) do
return _getSitelink(frame.args.qid, frame.args.wiki or mw.text.trim(frame.args[1] or ""))
claims[i] = wd.formatStatement(j, args)
table.insert(props, j.mainsnak.property)
end
if args.removedupes and (args.removedupes ~= '-') then
claims = wd.addNewValues({}, claims) -- devrait aussi supprimer de props celles qui ne sont pas utilisées
end
return claims, props, cat
end
function wd.getQualifiers(statement, qualifs, params)
if not statement.qualifiers then
-------------------------------------------------------------------------------
return nil
-- 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.getSitelink(itemID)
local label = labelOrId(itemID)
if sitelink then
return "[[:" .. sitelink .. "|" .. label .. "]]"
else
return label
end
local vals = {}
if type(qualifs) == 'string' then
qualifs = wd.splitStr(qualifs)
end
for i, j in pairs(qualifs) do
if statement.qualifiers[j] then
for k, l in pairs(statement.qualifiers[j]) do
table.insert(vals, l)
end
end
end
if #vals == 0 then
return nil
end
return vals
end
function wd.getFormattedQualifiers(statement, qualifs, params)
if not params then params = {} end
-------------------------------------------------------------------------------
local qualiftable = wd.getQualifiers(statement, qualifs)
-- getLabel has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid=
if not qualiftable then
-- It returns the Wikidata label for the local language as plain text.
return nil
-- If there is no label in the local language, it displays the qid instead.
end
-------------------------------------------------------------------------------
qualiftable = wd.filterClaims(qualiftable, params) or {}
-- Dependencies: none
for i, j in pairs(qualiftable) do
-------------------------------------------------------------------------------
qualiftable[i] = wd.formatSnak(j, params)
p.getLabel = function(frame)
end
local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "")
return modules.linguistic.conj(qualiftable, params.conjtype)
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
function wd.showQualifiers(str, statement, args)
local qualifs = args.showqualifiers
-------------------------------------------------------------------------------
if not qualifs then
-- label has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid=
return str -- or error ?
-- if no qid is supplied, it uses the qid associated with the current page.
end
-- It returns the Wikidata label for the local language as plain text.
if type(qualifs) == 'string' then
-- If there is no label in the local language, it returns nil.
qualifs = wd.splitStr(qualifs)
-------------------------------------------------------------------------------
end
-- Dependencies: none
local qualifargs = args.qualifargs or {}
-------------------------------------------------------------------------------
-- formatage des qualificatifs = args commençant par "qualif", ou à défaut, les mêmes que pour la valeur principale
p.label = function(frame)
qualifargs.displayformat = args.qualifdisplayformat or args.displayformat
local qid = mw.text.trim(frame.args[1] or frame.args.qid or "")
qualifargs.labelformat = args.qualiflabelformat or args.labelformat
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
qualifargs.labelformat2 = args.qualiflabelformat2 or args.labelformat2
if not qid then return end
local langqualifargs.link = frame.args.langqualiflink or ""args.link
qualifargs.linktopic = args.qualiflinktopic or args.linktopic
if lang == "" then lang = nil end
qualifargs.conjtype = args.qualifconjtype
local label, success = labelOrId(qid, lang)
qualifargs.precision = args.qualifprecision
if success then return label end
qualifargs.targetunit = args.qualiftargetunit
qualifargs.defaultlink = args.qualifdefaultlink or args.defaultlink
qualifargs.defaultlinkquery = args.qualifdefaultlinkquery or args.defaultlinkquery
local formattedqualifs
if args.qualifformat and type (args.qualifformat) == 'function' then
formattedqualifs = args.qualifformat(statement, qualifs, qualifargs)
else
formattedqualifs = wd.getFormattedQualifiers(statement, qualifs, qualifargs)
end
if formattedqualifs and formattedqualifs ~= "" then
str = str .. " (" .. formattedqualifs .. ")"
end
return str
end
function wd.formatSnak( snak, params )
-------------------------------------------------------------------------------
if not params then params = {} end -- pour faciliter l'appel depuis d'autres modules
-- getAT (Article Title)
if snak.snaktype == 'somevalue' then
-- has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid=
return unknownValue(snak, params.unknownlabel)
-- If there is a sitelink to an article on the local Wiki, it returns the sitelink as plain text.
elseif snak.snaktype == 'novalue' then
-- If there is no sitelink or qid supplied, it returns nothing.
return noValue(params.novaluelabel)
-------------------------------------------------------------------------------
elseif snak.snaktype == 'value' then
-- Dependencies: none
return wd.getDataValue( snak, params)
-------------------------------------------------------------------------------
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.getSitelink(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.getDescription(itemID)
elseif desc:lower() == 'none' then
return nil
else
return descformatError( 'unknown-snak-type' )
end
end
function wd.formatStatement( statement, args ) -- FONCTION A REORGANISER (pas très lisible)
if not args then
args = {}
end
if not statement.type or statement.type ~= 'statement' then
return formatError( 'unknown-claim-type' )
end
local prop = statement.mainsnak.property
local str
-------------------------------------------------------------------------------
-- getAliases 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.
-- It implements blacklisting and whitelisting with a field name of "alias" by default.
-- Any local parameter passed becomes the return value.
-- Otherwise it returns the aliases for the Wikidata entity with the usual list options.
-- Nothing is returned if the aliases do not exist.
-------------------------------------------------------------------------------
-- Dependencies: findLang(); assembleoutput()
-------------------------------------------------------------------------------
p.getAliases = function(frame)
local args = frame.args
-- special displayformat f
local fieldname = args.name or ""
if args.statementformat and (type(args.statementformat) == 'function') then
if fieldname == "" then fieldname = "alias" end
str = args.statementformat(statement, args)
elseif (statement.mainsnak.datatype == 'time') and (statement.mainsnak.dateformat ~= '-') then
if args.displayformat == 'raw' and statement.mainsnak.snaktype == 'value' then
str = statement.mainsnak.datavalue.value.time
else
str = wd.getFormattedDate(statement, args)
end
elseif args.showonlyqualifier and (args.showonlyqualifier ~= '') then
str = wd.getFormattedQualifiers(statement, args.showonlyqualifier, args)
if not str then
return nil
end
if args.addstandardqualifs ~= '-' then
str = wd.addStandardQualifs(str, statement)
end
else
str = wd.formatSnak( statement.mainsnak, args )
if (args.addstandardqualifs ~= '-') and (args.displayformat ~= 'raw') then
str = wd.addStandardQualifs(str, statement)
end
end
-- ajouts divers
local blacklist = args.suppressfields or args.spf or ""
if args.showlang == true then
if blacklist:find(fieldname) then return nil end
local indicateur = showLang(statement, args.maxLang)
if indicateur then
str = indicateur .. ' ' .. str
end
end
if args.showqualifiers then
str = wd.showQualifiers(str, statement, args)
end
if args.showdate then -- when "showdate and chronosort are both set, date retrieval is performed twice
local localval = mw.text.trim(args[1] or "")
local period = wd.getFormattedDate(statement, args, "-") -- 3 arguments indicate the we should not use additional qualifiers, alrady added by wd.formatStatement
if localval ~= "" then return localval end
if period then
str = str .. " <small>(" .. period .. ")</small>"
local whitelist = args.fetchwikidata or args.fwd or ""
end
if whitelist == "" then whitelist = "NONE" end
end
if not (whitelist == 'ALL' or whitelist:find(fieldname)) then return nil end
local qid = args.qid or ""
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
if not qid or not mw.wikibase.entityExists(qid) then return nil end
local aliases = mw.wikibase.getEntity(qid).aliases
if not aliases then return nil end
args.langobj = findLang(args.lang)
local langcode = args.langobj.code
args.lang = langcode
if args.showsource and args.showsource ~= '-' then
local out = {}
local sources, hashes = wd.getReferences(statement)
for k1, v1 in pairs(aliases) do
if v1[1].language == langcodesources then
local source = wd.sourceStr(sources, hashes)
for k1, v2 in ipairs(v1) do
if source then
out[#out+1] = v2.value
str = str .. source
end
break
end
end
return assembleoutput(out, args, qid)str
end
function wd.addLinkBack(str, id, property)
if not id or id == '' then
id = wd.getEntityIdForCurrentPage()
end
if not id then
return str
end
if type(property) == 'table' then
property = property[1]
end
id = wd.entityId(id)
local class = ''
-------------------------------------------------------------------------------
if property then
-- pageId returns the page id (entity ID, Qnnn) of the current page
class = 'wd_' .. string.lower(property)
-- returns nothing if the page is not connected to Wikidata
end
-------------------------------------------------------------------------------
local icon = '[[File:Blue pencil.svg|%s|10px|baseline|class=noviewer|link=%s]]'
-- Dependencies: none
local title = wd.translate('see-wikidata-value')
-------------------------------------------------------------------------------
local url = mw.uri.fullUrl('d:' .. id, 'uselang=fr')
p.pageId = function(frame)
url.fragment = property -- ajoute une #ancre si paramètre "property" défini
return mw.wikibase.getEntityIdForCurrentPage()
url = tostring(url)
local v = mw.html.create('span')
:addClass(class)
:wikitext(str)
:tag('span')
:addClass('noprint wikidata-linkback')
:wikitext(icon:format(title, url))
:allDone()
return tostring(v)
end
function wd.addRefAnchor(str, id)
--[[
-------------------------------------------------------------------------------
Insère une ancre pour une référence générée à partir d'un élément wd.
-- formatDate is a wrapper to export the private function format_Date
L'id Wikidata sert d'identifiant à l'ancre, à utiliser dans les modèles type "harvsp"
-------------------------------------------------------------------------------
--]]
-- Dependencies: format_Date();
return tostring(
-------------------------------------------------------------------------------
mw.html.create('span')
p.formatDate = function(frame)
:attr('id', id)
return format_Date(frame.args[1], frame.args.df, frame.args.bc)
:attr('class', "ouvrage")
:wikitext(str)
)
end
--=== FUNCTIONS USING AN ENTITY AS ARGUMENT ===
local function formatStatementsGrouped(args, type)
-- regroupe les affirmations ayant la même valeur en mainsnak, mais des qualificatifs différents
-- (seulement pour les propriétés de type élément)
local claims = wd.getClaims(args)
-------------------------------------------------------------------------------
if not claims then
-- ___location is a wrapper to export the private function _location
return nil
-- 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
return nil
end
end
local groupedClaims = {}
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
-- regroupe les affirmations par valeur de mainsnak
local function addClaim(claim)
-------------------------------------------------------------------------------
local id = wd.getMainId(claim)
-- checkBlacklist implements a test to check whether a named field is allowed
for i, j in pairs(groupedClaims) do
-- returns true if the field is not blacklisted (i.e. allowed)
if (j.id == id) then
-- returns false if the field is blacklisted (i.e. disallowed)
table.insert(groupedClaims[i].claims, claim)
-- {{#if:{{#invoke:WikidataIB |checkBlacklist |name=Joe |suppressfields=Dave; Joe; Fred}} | not blacklisted | blacklisted}}
return
-- displays "blacklisted"
end
-- {{#if:{{#invoke:WikidataIB |checkBlacklist |name=Jim |suppressfields=Dave; Joe; Fred}} | not blacklisted | blacklisted}}
-- 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
return true
end
table.insert(groupedClaims, {id = id, claims = {claim}})
else
-- one of the fields is missing: let's call that "not on the list"
return true
end
for i, claim in pairs(claims) do
end
addClaim(claim)
-------------------------------------------------------------------------------
-- 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
local stringTable = {}
-- instructions ad hoc pour les paramètres concernant la mise en forme d'une déclaration individuelle
-------------------------------------------------------------------------------
local funs = {
-- labelorid is a public function to expose the output of labelOrId()
{param = "showqualifiers", fun = function(str, claims)
-- Pass the Q-number as |qid= or as an unnamed parameter.
local qualifs = {}
-- It returns the Wikidata label for that entity or the qid if no label exists.
for i, claim in pairs(claims) do
-------------------------------------------------------------------------------
local news = wd.getFormattedQualifiers(claim, args.showqualifiers, args)
-- Dependencies: labelOrId
if news then
-------------------------------------------------------------------------------
table.insert(qualifs, news)
p.labelorid = function(frame)
end
return (labelOrId(frame.args.qid or frame.args[1]))
end
local qualifstr = modules.linguistic.conj(qualifs, wd.translate("qualif-separator"))
if qualifstr and qualifstr ~= "" then
str = str .. " (" .. qualifstr .. ")"
end
return str
end
},
{param = "showdate", fun = function(str, claims)
-- toutes les dates sont regroupées à l'intérieur des mêmes parenthèses ex "médaille d'or (1922, 1924)"
local dates = {}
for i, statement in pairs(claims) do
local s = wd.getFormattedDate(statement, args, true)
if statement then table.insert(dates, s) end
end
local datestr = modules.linguistic.conj(dates)
if datestr and datestr ~= "" then
str = str .. " <small>(" .. datestr .. ")</small>"
end
return str
end
},
{param = "showsource", fun = function(str, claims)
-- les sources sont toutes affichées au même endroit, à la fin
-- si deux affirmations ont la même source, on ne l'affiche qu'une fois
local sources = {}
local hashes = {}
local function dupeRef(old, new)
for i, j in pairs(old) do
if j == new then
return true
end
end
end
for i, claim in pairs(claims) do
local refs, refHashes = wd.getReferences(claim)
if refs then
for i, j in pairs(refs) do
if not dupeRef(sources, j) then
table.insert(sources, j)
local hash = (refHashes and refHashes[i]) or '-'
table.insert(hashes, hash)
end
end
end
end
return str .. (wd.sourceStr(sources, hashes) or "")
end
}
}
for i, group in pairs(groupedClaims) do -- bricolage pour utiliser les arguments de formatStatements
local str = wd.formatEntity(group.id, args)
-------------------------------------------------------------------------------
if not str then
-- getLang returns the MediaWiki language code of the current content.
str = '???' -- pour éviter erreur Lua si formatEntity a retourné nil
-- If optional parameter |style=full, it returns the language name.
end
-------------------------------------------------------------------------------
for i, fun in pairs(funs) do
-- Dependencies: none
if args[fun.param] then
-------------------------------------------------------------------------------
str = fun.fun(str, group.claims, args)
p.getLang = function(frame)
end
local style = (frame.args.style or ""):lower()
end
local langcode = mw.language.getContentLanguage().code
table.insert(stringTable, str)
if style == "full" then
return mw.language.fetchLanguageName( langcode )
end
return langcode
args.valuetable = stringTable
return wd.formatStatements(args)
end
function wd.formatStatements( args )--Format statement and concat them cleanly
-------------------------------------------------------------------------------
-- 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
if args.value == '-' then
return nil
end
-- If a value is already set: use it, except if it's the special value {{WD}} (use wikidata)
-------------------------------------------------------------------------------
if args.value and args.value ~= '' then
-- findLanguage exports the local findLang() function
local valueexpl = wd.translate("activate-query")
-- It takes an optional language code and returns, in order of preference:
if args.value ~= valueexpl then
-- the code if a known language;
return args.value
-- 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
-- There is no value set, and args.expl disables wikidata on empty values
elseif args.expl then
return nil
end
-- otherwise return the page qid (if any)
return qid
end
if args.grouped and args.grouped ~= '' then
args.grouped = false
return formatStatementsGrouped(args)
end
local valuetable = args.valuetable -- dans le cas où les valeurs sont déjà formtées
local props -- les prorpriétés réellement utilisées (dans certainse cas, ce ne sont pas toutes celles de ags.property
local cat = ''
if not valuetable then -- cas le plus courant
valuetable, props, cat = wd.stringTable(args)
end
local str = modules.linguistic.conj(valuetable, args.conjtype)
-------------------------------------------------------------------------------
if not str then
-- followQid takes four optional parameters: qid, props, list and all.
return args.default
-- 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, separated by spaces.
-- If |list= is set to a template, the qids are passed as arguments to the template.
-- If props is not given, the qid is returned.
-------------------------------------------------------------------------------
-- Dependencies: parseParam()
-------------------------------------------------------------------------------
p._followQid = function(args)
local qid = (args.qid or ""):upper()
local all = parseParam(args.all, false)
local list = args.list or ""
if list == "" then list = nil end
if qid == "" then
qid = mw.wikibase.getEntityIdForCurrentPage()
end
if not qidprops then return nil end
props = wd.splitStr(args.property)[1]
local out = {}
local props = (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 #outargs.ucfirst >~= 0'-' then
str = modules.linguistic.ucfirst(str)
local ret = ""
if list then
ret = mw.getCurrentFrame():expandTemplate{title = list, args = out}
else
ret = table.concat(out, " ")
end
return ret
else
return qid
end
end
if args.addcat and (args.addcat ~= '-') then
p.followQid = function(frame)
str = str .. wd.addTrackingCat(props) .. cat
return p._followQid(frame.args)
end
if args.linkback and (args.linkback ~= '-') then
str = wd.addLinkBack(str, args.entity, props)
end
if args.returnnumberofvalues then
return str, #valuetable
end
return str
end
function wd.formatAndCat(args)
if not args then
-------------------------------------------------------------------------------
return nil
-- globalSiteID returns the globalSiteID for the current wiki
end
-- e.g. returns "enwiki" for the English Wikipedia, "enwikisource" for English Wikisource, etc.
args.linkback = args.linkback or true
-------------------------------------------------------------------------------
args.addcat = true
-- Dependencies: none
if args.value then -- do not ignore linkback and addcat, as formatStatements do
-------------------------------------------------------------------------------
if args.value == '-' then
p.globalSiteID = function(frame)
return nil
return mw.wikibase.getGlobalSiteId()
end
local val = args.value .. wd.addTrackingCat(args.property)
val = wd.addLinkBack(val, args.entity, args.property)
return val
end
return wd.formatStatements( args )
end
function wd.getTheDate(args)
local claims = wd.getClaims(args)
-------------------------------------------------------------------------------
if not claims then
-- siteID returns the root of the globalSiteID
return nil
-- 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 posformattedvalues = txtlang:find("-"){}
for i, j in pairs(claims) do
local ret = ""
local v = wd.getFormattedDate(j, args)
if pos then
if v then
ret = txtlang:sub(1, pos-1)
table.insert(formattedvalues, v )
else
end
ret = txtlang
end
local val = modules.linguistic.conj(formattedvalues)
if not val then
return nil
end
if args.addcat == true then
val = val .. wd.addTrackingCat(args.property)
end
val = wd.addLinkBack(val, args.entity, args.property)
return ret
return val
end
function wd.keyDate (event, item, params)
-------------------------------------------------------------------------------
params = params or {}
-- projID returns the code used to link to the reader's language's project
params.entity = item
-- e.g "en" for [[:en:WikidataIB]]
if type(event) == 'table' then
-- treats "en-gb" as "en", etc.
for i, j in pairs(event) do
-------------------------------------------------------------------------------
params.targetvalue = nil -- réinitialisation barbare des paramètres modifiés
-- Dependencies: none
local s = wd.keyDate(j, item, params)
-------------------------------------------------------------------------------
if s then
p.projID = function(frame)
return s
local txtlang = frame:preprocess( "{{int:lang}}" ) or ""
end
-- This deals with specific exceptions: be-tarask -> be-x-old
end
if txtlang == "be-tarask" then
elseif type(event) ~= 'string' then
return "be-x-old"
return formatError('invalid-datatype', type(event), 'string')
end
elseif string.sub(event, 1, 1) == 'Q' then -- on demande un élément utilisé dans P:P793 (événement clé)
local pos = txtlang:find("-")
params.property = 'P793'
local ret = ""
params.targetvalue = event
if pos then
params.addcat = params.addcat or true
ret = txtlang:sub(1, pos-1)
return wd.getTheDate(params)
elseif string.sub(event, 1, 1) == 'P' then -- on demande une propriété
params.property = event
return wd.formatAndCat(params)
else
return formatError('invalid-entity-id', event)
ret = txtlang
end
return ret
end
function wd.mainDate(entity)
-- essaye P580/P582
local args = {entity = entity, addcat = true}
args.property = 'P580'
local startpoint = wd.formatStatements(args)
args.property = 'P582'
local endpoint = wd.formatStatements(args)
local str
-------------------------------------------------------------------------------
if (startpoint or endpoint) then
-- formatNumber formats a number according to the the supplied language code ("|lang=")
str = modules.formatDate.daterange(startpoint, endpoint, params)
-- or the default language if not supplied.
str = wd.addLinkBack(str, entity, 'P582')
-- The number is the first unnamed parameter or "|num="
return str
-------------------------------------------------------------------------------
end
-- Dependencies: findLang()
-------------------------------------------------------------------------------
-- défaut : P585
p.formatNumber = function(frame)
args.property = {'P585', 'P571'}
local lang
args.linkback = true
local num = tonumber(frame.args[1] or frame.args.num) or 0
return wd.formatStatements(args)
lang = findLang(frame.args.lang)
return lang:formatNum( num )
end
-- === FUNCTIONS FOR TRANSITIVE PROPERTIES ===
function wd.getIds(item, query)
-------------------------------------------------------------------------------
query.excludespecial = true
-- examine dumps the property (the unnamed parameter or pid)
query.displayformat = 'raw'
-- from the item given by the parameter 'qid' (or the other unnamed parameter)
query.entity = item
-- or from the item corresponding to the current page if qid is not supplied.
query.addstandardqualifs = '-'
-- e.g. {{#invoke:WikidataIB |examine |pid=P26 |qid=Q42}}
return wd.stringTable(query)
-- 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
local q1 = qid:sub(1,1)
if pid:sub(1,1) ~= "P" then return "No property supplied" end
if q1 ~= "Q" and q1 ~= "M" 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
-- recursively adds a list of qid to an existing list, based on the results of a query
-------------------------------------------------------------------------------
function wd.addVals(list, query, maxdepth, maxnodes, stopval)
-- checkvalue looks for 'val' as a wikibase-item value of a property (the unnamed parameter or pid)
maxdepth = tonumber(maxdepth) or 10
-- from the item given by the parameter 'qid'
maxnodes = tonumber(maxnodes) or 100
-- or from the Wikidata item associated with the current page if qid is not supplied.
if (maxdepth < 0) then
-- It only checks ranks that are requested (preferred and normal by default)
return list
-- 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
if stopval and wd.isHere(list, stopval) then
local val = args.val
if not val then return nil endlist
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 ranks = setRanks(args.rank)
local stats = {}
if ranks.b then
stats = mw.wikibase.getBestStatements(qid, pid)
else
stats = mw.wikibase.getAllStatements( qid, pid )
end
local origsize = #list
if not stats[1] then return nil end
for i = 1, origsize do
if stats[1].mainsnak.datatype == "wikibase-item" then
-- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance
for k, v in pairs( stats ) do
local mscandidates = vwd.mainsnakgetIds(list[i], query)
list = wd.addNewValues(list, candidates, maxnodes, stopval)
if ranks[v.rank:sub(1,1)] and ms.snaktype == "value" and ms.datavalue.value.id == val then
if list[#list] == stopval then
return val
endreturn list
end
if #list >= maxnodes then
return list
end
end
return nil
if (#list == origsize) then
end
return list
-------------------------------------------------------------------------------
-- 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
-- extract any icon
local url, icon = txt:match("(.+) (.+)")
-- make sure there's at least a space at the end
url = (url or txt) .. " "
icon = icon or ""
-- extract any protocol like https://
local prot = url:match("(https*://).+[ \"\']")
-- extract address
local addr = ""
if prot then
addr = url:match("https*://(.+)[ \"\']") or " "
else
prot = "//"
addr = url:match("[^%p%s]+%.(.+)[ \"\']") or " "
end
return wd.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1)
-- strip trailing / from end of ___domain-only url and add <wbr/> before . and /
local disp, n = addr:gsub( "^([^/]+)/$", "%1" ):gsub("%/", "<wbr/>/"):gsub("%.", "<wbr/>.")
return '<span class="url">[' .. prot .. addr .. " " .. disp .. "]</span> " .. icon
end
-- returns a list of items transitively matching a query (orig item is not included in the list)
function wd.transitiveVals(item, query, maxdepth, maxnodes, stopval)
-------------------------------------------------------------------------------
maxdepth = tonumber(maxdepth) or 5
-- getWebsite fetches the Official website (P856) and formats it for use in an infobox.
if type(query) == "string" then
-- This is similar to Template:Official website but with a url displayed,
query = {property = query}
-- 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 urls = {}
local quals = {}
local qid = frame.args.qid or ""
if url and url ~= "" then
urls[1] = url
else
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
if not qid then return nil end
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)
end
if #urls == 0 then return nil end
-- récupération des valeurs
local out = {}
local vals = wd.getIds(item, query)
for i, u in ipairs(urls) do
if not vals then
local link = quals[i] or u
return nil
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 v = wd.addVals(vals, query, maxdepth - 1, maxnodes, stopval)
if not v then
local langcode = findLang(frame.args.lang).code
return nil
local noicon = parseParam(frame.args.noicon, false)
if url == "" and not noicon then
out[#out] = out[#out] .. createicon(langcode, qid, "P856")
end
-- réarrangement des valeurs
local ret = ""
if #outquery.valorder >== 1"inverted" then
local a = {}
ret = mw.getCurrentFrame():expandTemplate{title = "ubl", args = out}
for i = #v, 1, -1 do
else
ret a[#a+1] = outv[1i]
end
v = a
end
return retv
end
-- returns true if an item is the value of a query, transitively
function wd.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes )
-------------------------------------------------------------------------------
local vals = wd.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval )
-- getAllLabels fetches the set of labels and formats it for display as wikitext.
if (not vals) then
-- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page.
return false
-------------------------------------------------------------------------------
-- Dependencies: none
-------------------------------------------------------------------------------
p.getAllLabels = function(frame)
local args = frame.args or frame:getParent().args or {}
local qid = args.qid or ""
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
if not qid or not mw.wikibase.entityExists(qid) then return i18n["entity-not-found"] end
local labels = mw.wikibase.getEntity(qid).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
for _, val in ipairs(vals) do
if (val == searchedval) then
return table.concat(out, "; ")
return true
end
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 or ""
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
if not qid or not mw.wikibase.entityExists(qid) then return i18n["entity-not-found"] end
local descriptions = mw.wikibase.getEntity(qid).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 false
return table.concat(out, "; ")
end
-- returns true if an item is a superclass of another, based on P279
function wd.isSubclass(class, item, maxdepth)
-------------------------------------------------------------------------------
local query = {property = 'P279'}
-- getAllAliases fetches the set of aliases and formats it for display as wikitext.
if class == item then -- item is a subclass of itself iff it is a class
-- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page.
if wd.getIds(item, query) then
-------------------------------------------------------------------------------
return true
-- Dependencies: none
-------------------------------------------------------------------------------
p.getAllAliases = function(frame)
local args = frame.args or frame:getParent().args or {}
local qid = args.qid or ""
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
if not qid or not mw.wikibase.entityExists(qid) then return i18n["entity-not-found"] end
local aliases = mw.wikibase.getEntity(qid).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
return false
out[#out+1] = table.concat(val, ", ") .. " (" .. lang .. ")"
end
return wd.inTransitiveVals(class, item, query, maxdepth )
return table.concat(out, "; ")
end
-- returns true if one of the best ranked P31 values of an item is the target or a subclass of the target
-- rank = 'valid' would seem to make sense, but it would need to check for date qualifiers as some P31 values have begin or end date
-------------------------------------------------------------------------------
function wd.isInstance(targetclass, item, maxdepth)
-- showNoLinks displays the article titles that should not be linked.
maxdepth = maxdepth or 10
-------------------------------------------------------------------------------
local directclasses = wd.transitiveVals(item, {property = 'P31'}, 1)
-- Dependencies: none
if not directclasses then
-------------------------------------------------------------------------------
return false
p.showNoLinks = function(frame)
end
local out = {}
for ki, vclass in pairs(donotlinkdirectclasses) do
if wd.isSubclass(targetclass, class, maxdepth - 1) then
out[#out+1] = k
return true
end
end
return false
table.sort( out )
return table.concat(out, "; ")
end
-- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canada
function wd.findVal(sourceitem, targetclass, query, recursion, instancedepth)
-------------------------------------------------------------------------------
if type(query) == "string" then
-- checkValidity checks whether the first unnamed parameter represents a valid entity-id,
query = {property = query}
-- 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
local candidates = wd.getIds(sourceitem, query)
end
if candidates then
for i, j in pairs(candidates) do
if wd.isInstance(targetclass, j, instancedepth) then
-------------------------------------------------------------------------------
return j
-- getEntityFromTitle returns the Entity-ID (Q-number) for a given title.
end
-- Modification of Module:ResolveEntityId
end
-- The title is the first unnamed parameter.
if not recursion then
-- The site parameter determines the site/language for the title. Defaults to current wiki.
recursion = 3
-- 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)
local 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
recursion = recursion - 1
return qid
end
if recursion < 0 then
return nil
end
for i, candidate in pairs(candidates) do
return wd.findVal(candidate, targetclass, query, recursion, instancedepth)
end
end
-- === VARIA ===
-------------------------------------------------------------------------------
function wd.getDescription(entity, lang)
-- getDatePrecision returns the number representing the precision of the first best date value
lang = lang or defaultlang
-- for the given property.
-- It takes the qid and property ID
local description
-- The meanings are given at https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times
if lang == defaultlang then
-- 0 = 1 billion years .. 6 = millennium, 7 = century, 8 = decade, 9 = year, 10 = month, 11 = day
return mw.wikibase.description(qid)
-- Returns 0 (or the second unnamed parameter) if the Wikidata does not exist.
end
-------------------------------------------------------------------------------
if not entity.descriptions then
-- Dependencies: parseParam; sourced;
return wd.translate('no description')
-------------------------------------------------------------------------------
end
function p.getDatePrecision(frame)
local argsdescriptions =frame entity.argsdescriptions
if not args[1]descriptions then args=frame:getParent().args end
return nil
local default = tonumber(args[2] or args.default) or 0
end
local prop = mw.text.trim(args[1] or "")
if descriptions[lang] then
if prop == "" then return default end
return descriptions[delang].value
local qid = args.qid or ""
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
if not qid then return default end
local onlysrc = parseParam(args.onlysourced or args.osd, true)
local stat = mw.wikibase.getBestStatements(qid, prop)
for i, v in ipairs(stat) do
local prec = (onlysrc == false or sourced(v))
and v.mainsnak.datavalue
and v.mainsnak.datavalue.value
and v.mainsnak.datavalue.value.precision
if prec then return prec end
end
return defaultentity.id
end
function wd.Dump(entity)
entity = wd.getEntity(entity)
if not entity then
return formatError("entity-param-not-provided")
end
return "<pre>"..mw.dumpObject(entity).."</pre>"
end
function wd.frameFun(frame)
return p
local args = frame.args
local funname = args[1]
table.remove(args, 1)
return wd[funname](args)
end
return wd
-------------------------------------------------------------------------------
-- List of exported functions
-------------------------------------------------------------------------------
--[[
_getValue
getValue
getPreferredValue
getCoords
getQualifierValue
getSumOfParts
getValueByQual
getValueByLang
getValueByRefSource
getPropertyIDs
getQualifierIDs
getPropOfProp
getAwardCat
getIntersectCat
getGlobe
getCommonsLink
getSiteLink
getLink
getLabel
label
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
getDatePrecision
--]]
-------------------------------------------------------------------------------
|