Changes

4,370 bytes added ,  11:51, 5 March 2022
m
KS update 1.2
Line 1: Line 1:  +
-- Version: 2021-02-06
 
-- Module to implement use of a blacklist and whitelist for infobox fields
 
-- 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
 
-- Can take a named parameter |qid which is the Wikidata ID for the article
Line 13: Line 14:     
local cdate -- initialise as nil and only load _complex_date function if needed
 
local cdate -- initialise as nil and only load _complex_date function if needed
-- [[Module:Complex date]] is loaded lazily and has the following dependencies:
+
-- Module:Complex date is loaded lazily and has the following dependencies:
-- Module:I18n/complex date, Module:ISOdate, Module:DateI18n (alternative for Module:Date),
+
-- Module:Calendar
-- Module:Formatnum, Module:I18n/date, Module:Yesno, Module:Linguistic, 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,
 
-- 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.
 
-- is needed to use Module:Complex date which seemingly requires date precision as a string.
Line 564: Line 574:  
-- shortname is boolean switch to use P1813 (short name) instead of label if true.
 
-- shortname is boolean switch to use P1813 (short name) instead of label if true.
 
-- lang is the current language code.
 
-- lang is the current language code.
 +
-- uselbl is boolean switch to force display of the label instead of the sitelink (default: false)
 +
-- linkredir is boolean switch to allow linking to a redirect (default: false)
 +
-- formatvalue is boolean switch to allow formatting as italics or quoted (default: false)
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
-- Dependencies: labelOrId(); donotlink[]
 
-- Dependencies: labelOrId(); donotlink[]
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
local linkedItem = function(id, lprefix, lpostfix, prefix, postfix, dtxt, shortname, lang)
+
local linkedItem = function(id, args)
lprefix = lprefix or "" -- toughen against nil values passed
+
local lprefix = (args.lp or args.lprefix or args.linkprefix or ""):gsub('"', '') -- toughen against nil values passed
lpostfix = lpostfix or ""
+
local lpostfix = (args.lpostfix or ""):gsub('"', '')
prefix = prefix or ""
+
local prefix = (args.prefix or ""):gsub('"', '')
postfix = postfix or ""
+
local postfix = (args.postfix or ""):gsub('"', '')
lang = lang or "en" -- fallback to default if missing
+
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
 
-- see if item might need italics or quotes
 
local fmt = ""
 
local fmt = ""
for k, v in ipairs( mw.wikibase.getBestStatements(id, "P31") ) do
+
if next(formats) and formatvalue then
if v.mainsnak.datavalue and formats[v.mainsnak.datavalue.value.id] then
+
for k, v in ipairs( mw.wikibase.getBestStatements(id, "P31") ) do
fmt = formats[v.mainsnak.datavalue.value.id]
+
if v.mainsnak.datavalue and formats[v.mainsnak.datavalue.value.id] then
break -- pick the first match
+
fmt = formats[v.mainsnak.datavalue.value.id]
 +
break -- pick the first match
 +
end
 
end
 
end
 
end
 
end
Line 605: Line 628:  
if sitelink then
 
if sitelink then
 
if not (dtxt or shortname) then
 
if not (dtxt or shortname) then
-- strip any namespace or dab from the sitelink
+
-- if sitelink and label are the same except for case, no need to process further
local pos = sitelink:find(":") or 0
+
if sitelink:lower() ~= label:lower() then
local slink = sitelink
+
-- strip any namespace or dab from the sitelink
if pos > 0 then
+
local pos = sitelink:find(":") or 0
local prefix = sitelink:sub(1,pos-1)
+
local slink = sitelink
if mw.site.namespaces[prefix] then -- that prefix is a valid namespace, so remove it
+
if pos > 0 then
slink = sitelink:sub(pos+1)
+
local pfx = sitelink:sub(1,pos-1)
 +
if mw.site.namespaces[pfx] then -- that prefix is a valid namespace, so remove it
 +
slink = sitelink:sub(pos+1)
 +
end
 +
end
 +
-- remove stuff after commas or inside parentheses - ie. dabs
 +
slink = slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")
 +
-- if uselbl is false, use sitelink instead of label
 +
if not uselbl then
 +
--  use slink as display, preserving label case - find("^%u") is true for 1st char uppercase
 +
if label:find("^%u") then
 +
label = slink:gsub("^(%l)", string.upper)
 +
else
 +
label = slink:gsub("^(%u)", string.lower)
 +
end
 
end
 
end
end
  −
-- remove stuff after commas or inside parentheses - ie. dabs
  −
slink = slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")
  −
--  use that as label, preserving label case - find("^%u") is true for 1st char uppercase
  −
if label:find("^%u") then
  −
label = slink:gsub("^(%l)", string.upper)
  −
else
  −
label = slink:gsub("^(%u)", string.lower)
   
end
 
end
 
end
 
end
Line 629: Line 658:  
end
 
end
 
elseif islabel then
 
elseif islabel then
-- no sitelink, label exists, so check if a redirect with that title exists
+
-- no sitelink, label exists, so check if a redirect with that title exists, if linkredir is true
local artitle = mw.title.new(label, 0) -- only nil if label has invalid chars
+
-- display plain label by default
if not donotlink[label] and artitle and artitle.redirectTarget then
+
disp = prefix .. fmt .. label .. fmt .. postfix
-- there's a redirect with the same title as the label, so let's link to that
+
if linkredir then
disp = "[[".. lprefix .. label .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]"
+
local artitle = mw.title.new(label, 0) -- only nil if label has invalid chars
else
+
if not donotlink[label] and artitle and artitle.redirectTarget then
-- either (donotlink is true) or (no sitelink, label exists, not redirect)
+
-- there's a redirect with the same title as the label, so let's link to that
-- so output unlinked label with italics or quotes as needed
+
disp = "[[".. lprefix .. label .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]"
disp = prefix .. fmt .. label .. fmt .. postfix
+
end
 
end -- test if article title exists as redirect on current Wiki
 
end -- test if article title exists as redirect on current Wiki
 
else
 
else
Line 794: Line 823:  
-- createicon assembles the "Edit at Wikidata" pen icon.
 
-- createicon assembles the "Edit at Wikidata" pen icon.
 
-- It returns a wikitext string inside a span class="penicon"
 
-- It returns a wikitext string inside a span class="penicon"
 +
-- if entityID is nil or empty, the ID associated with current page is used
 +
-- langcode and propertyID may be nil or empty
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
-- Dependencies: i18n[];
 
-- Dependencies: i18n[];
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
local createicon = function(langcode, entityID, propertyID)
 
local createicon = function(langcode, entityID, propertyID)
local icon = "&nbsp;<span class='penicon'>[["
+
langcode = langcode or ""
 +
if not entityID or entityID == "" then entityID= mw.wikibase.getEntityIdForCurrentPage() end
 +
propertyID = propertyID or ""
 +
local icon = "&nbsp;<span class='penicon autoconfirmed-show'>[["
 
-- "&nbsp;<span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
 
-- "&nbsp;<span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
 
.. i18n["filespace"]
 
.. i18n["filespace"]
Line 804: Line 838:  
.. i18n["editonwikidata"]
 
.. i18n["editonwikidata"]
 
.. "|link=https://www.wikidata.org/wiki/" .. entityID
 
.. "|link=https://www.wikidata.org/wiki/" .. entityID
.. "?uselang=" .. langcode
+
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID then icon = icon .. "#" .. propertyID end
+
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
 
icon = icon .. "|" .. i18n["editonwikidata"] .. "]]</span>"
 
icon = icon .. "|" .. i18n["editonwikidata"] .. "]]</span>"
 
return icon
 
return icon
Line 814: Line 848:  
-- assembleoutput takes the sequence table containing the property values
 
-- assembleoutput takes the sequence table containing the property values
 
-- and formats it according to switches given. It returns a string or nil.
 
-- and formats it according to switches given. It returns a string or nil.
-- It needs the entityID and propertyID to create a link in the pen icon.
+
-- It uses the entityID (and optionally propertyID) to create a link in the pen icon.
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
-- Dependencies: parseParam();
 
-- Dependencies: parseParam();
Line 938: Line 972:  
local qnumber = dv.id
 
local qnumber = dv.id
 
if linked then
 
if linked then
val = linkedItem(qnumber, lpre, lpost, pre, post, dtxt, shortname, args.lang)
+
val = linkedItem(qnumber, args)
 
else -- no link wanted so check for display-text, otherwise test for lang code
 
else -- no link wanted so check for display-text, otherwise test for lang code
 
local label, islabel
 
local label, islabel
Line 1,246: Line 1,280:  
args.pd = pd
 
args.pd = pd
   −
-- allow qualifiers to have a different date format; default to year
+
-- 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 "y"
+
args.qdf = args.qdf or args.qualifierdateformat or args.df or (not qualsonly and "y")
   −
local lang = args.lang or findlang().code
+
local lang = args.lang or findLang().code
    
     -- qualID is a string list of wanted qualifiers or "ALL"
 
     -- qualID is a string list of wanted qualifiers or "ALL"
Line 1,374: Line 1,408:  
elseif t ~= "" then
 
elseif t ~= "" then
 
if qualsonly then
 
if qualsonly then
out[#out+1] = timestart .. dsep .. timeend
+
if timestart == "" then
 +
out[#out+1] = timeend
 +
elseif timeend == "" then
 +
out[#out+1] = timestart
 +
else
 +
out[#out+1] = timestart .. dsep .. timeend
 +
end
 
else
 
else
 
out[#out] = out[#out] .. " (" .. timestart .. dsep .. timeend .. ")"
 
out[#out] = out[#out] .. " (" .. timestart .. dsep .. timeend .. ")"
Line 1,454: Line 1,494:  
local uabbr = parseParam(args.unitabbr or args.uabbr, false)
 
local uabbr = parseParam(args.unitabbr or args.uabbr, false)
 
local filter = (args.unit or ""):upper()
 
local filter = (args.unit or ""):upper()
 +
local maxvals = tonumber(args.maxvals) or 0
 
if filter == "" then filter = nil end
 
if filter == "" then filter = nil end
   Line 1,485: Line 1,526:  
return nil
 
return nil
 
end -- of check for string
 
end -- of check for string
 +
if maxvals > 0 and #out >= maxvals then break end
 
end -- of loop through values of propertyID
 
end -- of loop through values of propertyID
 
return assembleoutput(out, frame.args, qid, propertyID)
 
return assembleoutput(out, frame.args, qid, propertyID)
Line 1,527: Line 1,569:  
end
 
end
 
for i2, v2 in ipairs(proptbl) do
 
for i2, v2 in ipairs(proptbl) do
parttbl = v2.qualifiers and v2.qualifiers.P518
+
local parttbl = v2.qualifiers and v2.qualifiers.P518
 
if parttbl then
 
if parttbl then
 
-- this higher location has qualifier 'applies to part' (P518)
 
-- this higher location has qualifier 'applies to part' (P518)
Line 1,554: Line 1,596:  
end
 
end
   −
-- check if it's an instance of (P31) a country (Q6256) and terminate the chain if it is
+
-- check if it's an instance of (P31) a country (Q6256) or sovereign state (Q3624078)
 +
-- and terminate the chain if it is
 
local inst = mw.wikibase.getAllStatements(qid, "P31")
 
local inst = mw.wikibase.getAllStatements(qid, "P31")
 
if #inst > 0 then
 
if #inst > 0 then
 
for k, v in ipairs(inst) do
 
for k, v in ipairs(inst) do
local instid = v.mainsnak.datavalue.value.id
+
local instid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id
 
-- stop if it's a country (or a country within the United Kingdom if skip is true)
 
-- stop if it's a country (or a country within the United Kingdom if skip is true)
if instid == "Q6256" or (skip and instid == "Q3336843") then
+
if instid == "Q6256" or instid == "Q3624078" or (skip and instid == "Q3336843") then
 
prop = nil -- this will ensure this is treated as top-level location
 
prop = nil -- this will ensure this is treated as top-level location
 
break
 
break
Line 1,570: Line 1,613:  
if prop and prop.mainsnak.datavalue then
 
if prop and prop.mainsnak.datavalue then
 
if not skip or count == 0 then
 
if not skip or count == 0 then
out[#out+1] = linkedItem(qid, ":", "", "", "") -- get a linked value if we can
+
local args = { lprefix = ":" }
 +
out[#out+1] = linkedItem(qid, args) -- get a linked value if we can
 
end
 
end
 
qid, prevqid = prop.mainsnak.datavalue.value.id, qid
 
qid, prevqid = prop.mainsnak.datavalue.value.id, qid
Line 1,802: Line 1,846:  
-- getCoords is used to get coordinates for display in an infobox
 
-- getCoords is used to get coordinates for display in an infobox
 
-- whitelist and blacklist are implemented
 
-- whitelist and blacklist are implemented
-- optional 'display' parameter is allowed, defaults to "inline, title"
+
-- optional 'display' parameter is allowed, defaults to nil - was "inline, title"
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
-- Dependencies: setRanks(); parseInput(); decimalPrecision();
 
-- Dependencies: setRanks(); parseInput(); decimalPrecision();
Line 1,810: Line 1,854:     
-- if there is a 'display' parameter supplied, use it
 
-- if there is a 'display' parameter supplied, use it
-- otherwise default to "inline, title"
+
-- otherwise default to nothing
 
local disp = frame.args.display or ""
 
local disp = frame.args.display or ""
 
if disp == "" then
 
if disp == "" then
disp = "inline, title"
+
disp = nil -- default to not supplying display parameter, was "inline, title"
 
end
 
end
   Line 1,871: Line 1,915:  
-- whose value is to be returned is passed in named parameter |qual=
 
-- whose value is to be returned is passed in named parameter |qual=
 
local qualifierID = frame.args.qual
 
local qualifierID = frame.args.qual
 +
 +
-- A filter can be set like this: filter=P642==Q22674854
 +
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
    
-- onlysourced is a boolean passed to return qualifiers
 
-- onlysourced is a boolean passed to return qualifiers
Line 1,896: Line 1,949:  
for k1, v1 in pairs(props) do
 
for k1, v1 in pairs(props) do
 
if v1.mainsnak.snaktype == "value" and v1.mainsnak.datavalue.type == "wikibase-entityid" then
 
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)
+
-- It's a wiki-linked value, so check if it's the target (in propvalue) and if it has qualifiers
-- and if it has qualifiers
   
if v1.mainsnak.datavalue.value.id == propvalue and v1.qualifiers then
 
if v1.mainsnak.datavalue.value.id == propvalue and v1.qualifiers then
 
if onlysrc == false or sourced(v1) then
 
if onlysrc == false or sourced(v1) then
 
-- if we've got this far, we have a (sourced) claim with qualifiers
 
-- if we've got this far, we have a (sourced) claim with qualifiers
-- which matches the target, so find the value(s) of the qualifier we want
+
-- which matches the target, so apply the filter and find the value(s) of the qualifier we want
local quals = v1.qualifiers[qualifierID]
+
if not filter or (v1.qualifiers[fprop] and v1.qualifiers[fprop][1].datavalue.value.id == fval) then
if quals then
+
local quals = v1.qualifiers[qualifierID]
-- can't reference qualifer, so set onlysourced = "no" (not boolean)
+
if quals then
local qargs = frame.args
+
-- can't reference qualifer, so set onlysourced = "no" (args are strings, not boolean)
qargs.onlysourced = "no"
+
local qargs = frame.args
local vals = propertyvalueandquals(quals, qargs, qid)
+
qargs.onlysourced = "no"
for k, v in ipairs(vals) do
+
local vals = propertyvalueandquals(quals, qargs, qid)
out[#out + 1] = v
+
for k, v in ipairs(vals) do
 +
out[#out + 1] = v
 +
end
 
end
 
end
 
end
 
end
Line 2,092: Line 2,146:  
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
 
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
p.getPropertyIDs = function(frame)
+
p._getPropertyIDs = function(args)
local args = frame.args
   
args.reqranks = setRanks(args.rank)
 
args.reqranks = setRanks(args.rank)
 
args.langobj = findLang(args.lang)
 
args.langobj = findLang(args.lang)
Line 2,110: Line 2,163:  
local maxvals = tonumber(args.maxvals) or 0
 
local maxvals = tonumber(args.maxvals) or 0
   −
out = {}
+
local out = {}
 
for i, v in ipairs(props) do
 
for i, v in ipairs(props) do
 
local snak = v.mainsnak
 
local snak = v.mainsnak
Line 2,124: Line 2,177:     
return assembleoutput(out, args, qid, pid)
 
return assembleoutput(out, args, qid, pid)
 +
end
 +
 +
p.getPropertyIDs = function(frame)
 +
local args = frame.args
 +
return p._getPropertyIDs(args)
 
end
 
end
   Line 2,159: Line 2,217:  
qlist = qlist:gsub("[%p%s]+", " ") .. " "
 
qlist = qlist:gsub("[%p%s]+", " ") .. " "
   −
out = {}
+
local out = {}
 
for i, v in ipairs(props) do
 
for i, v in ipairs(props) do
 
local snak = v.mainsnak
 
local snak = v.mainsnak
Line 2,193: Line 2,251:  
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
 
-- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
p.getPropOfProp = function(frame)
+
p._getPropOfProp = function(args)
frame.args.reqranks = setRanks(frame.args.rank)
+
-- parameter sets for commonly used groups of parameters
frame.args.langobj = findLang(frame.args.lang)
+
local paraset = tonumber(args.ps or args.parameterset or 0)
frame.args.lang = frame.args.langobj.code
+
if paraset == 1 then
local args = frame.args
+
-- a common setting
local pid1 = args.prop1 or args.pid1 or ""
+
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
 +
 
 +
args.reqranks = setRanks(args.rank)
 +
args.langobj = findLang(args.lang)
 +
args.lang = args.langobj.code
 +
local pid1 = args.prop1 or args.pid1 or ""
 
local pid2 = args.prop2 or args.pid2 or ""
 
local pid2 = args.prop2 or args.pid2 or ""
local localval = mw.text.trim(args[1] or "")
   
if pid1 == "" or pid2 == "" then return nil end
 
if pid1 == "" or pid2 == "" then return nil end
local qid1, statements1 = parseInput(frame, localval, pid1)
+
 
if not qid1 then return localval end
+
local f = {}
 +
f.args = args
 +
local qid1, statements1 = parseInput(f, args[1], pid1)
 +
-- parseInput nulls empty args[1] and returns args[1] if nothing on Wikidata
 +
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 onlysrc = parseParam(args.onlysourced or args.osd, true)
 
local maxvals = tonumber(args.maxvals) or 0
 
local maxvals = tonumber(args.maxvals) or 0
Line 2,229: Line 2,310:  
end -- of loop through values of property1
 
end -- of loop through values of property1
 
return assembleoutput(out, args, qid1, pid1)
 
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
 
end
   Line 2,409: Line 2,500:  
if maxvals > 0 and #cat2 >= maxvals then break end
 
if maxvals > 0 and #cat2 >= maxvals then break end
 
end
 
end
out = {}
+
local out = {}
 
for k1, v1 in ipairs(cat1) do
 
for k1, v1 in ipairs(cat1) do
 
for k2, v2 in ipairs(cat2) do
 
for k2, v2 in ipairs(cat2) do
Line 2,493: Line 2,584:  
end
 
end
 
elseif qtype == "url" then
 
elseif qtype == "url" then
qv = mw.wikibase.renderSnak(vqualifiers[v1][1])
+
if vqualifiers[v1][1].snaktype == "value" then
local display = mw.ustring.match( mw.uri.decode(qv, "WIKI"), "([%w ]+)$" )
+
qv = mw.wikibase.renderSnak(vqualifiers[v1][1])
if display then
+
local display = mw.ustring.match( mw.uri.decode(qv, "WIKI"), "([%w ]+)$" )
qv = "[" .. qv .. " " .. display .. "]"
+
if display then
 +
qv = "[" .. qv .. " " .. display .. "]"
 +
end
 
end
 
end
 
else
 
else
Line 2,691: Line 2,784:  
if not (whitelist == 'ALL' or whitelist:find(fieldname)) then return nil end
 
if not (whitelist == 'ALL' or whitelist:find(fieldname)) then return nil end
   −
local qid = mw.text.trim(args.qid or "")
+
local qid = args.qid or ""
if qid == "" then qid = nil end
+
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
 +
if not qid or not mw.wikibase.entityExists(qid) then return nil end
   −
local entity = mw.wikibase.getEntity(qid)
+
local aliases = mw.wikibase.getEntity(qid).aliases
if not entity then return nil end
  −
local aliases = entity.aliases
   
if not aliases then return nil end
 
if not aliases then return nil end
if not qid then qid= mw.wikibase.getEntityIdForCurrentPage() end
      
args.langobj = findLang(args.lang)
 
args.langobj = findLang(args.lang)
Line 2,901: Line 2,992:     
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- followQid takes three optional parameters: qid, props, and all.
+
-- followQid takes four optional parameters: qid, props, list and all.
 
-- If qid is not given, it uses the qid for the connected page
 
-- If qid is not given, it uses the qid for the connected page
 
-- or returns nil if there isn't one.
 
-- or returns nil if there isn't one.
Line 2,907: Line 2,998:  
-- If props is given, the Wikidata item for the qid is examined for each property in turn.
 
-- 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,
 
-- If that property contains a value that is another Wikibase-item, that item's qid is returned,
-- and the search terminates, unless |all=y when all of the qids are returned, sparated by spaces.
+
-- 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.
 
-- If props is not given, the qid is returned.
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
-- Dependencies: parseParam()
 
-- Dependencies: parseParam()
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
p.followQid = function(frame)
+
p._followQid = function(args)
local qid = (frame.args.qid or ""):upper()
+
local qid = (args.qid or ""):upper()
local all = parseParam(frame.args.all, false)
+
local all = parseParam(args.all, false)
 +
local list = args.list or ""
 +
if list == "" then list = nil end
 
if qid == "" then
 
if qid == "" then
 
qid = mw.wikibase.getEntityIdForCurrentPage()
 
qid = mw.wikibase.getEntityIdForCurrentPage()
Line 2,920: Line 3,014:  
if not qid then return nil end
 
if not qid then return nil end
 
local out = {}
 
local out = {}
local props = (frame.args.props or ""):upper()
+
local props = (args.props or ""):upper()
 
if props ~= "" then
 
if props ~= "" then
 
for p in mw.text.gsplit(props, "%p") do -- split at punctuation and iterate
 
for p in mw.text.gsplit(props, "%p") do -- split at punctuation and iterate
Line 2,937: Line 3,031:  
end
 
end
 
if #out > 0 then
 
if #out > 0 then
return table.concat(out, " ")
+
local ret = ""
 +
if list then
 +
ret = mw.getCurrentFrame():expandTemplate{title = list, args = out}
 +
else
 +
ret = table.concat(out, " ")
 +
end
 +
return ret
 
else
 
else
 
return qid
 
return qid
 
end
 
end
 +
end
 +
 +
p.followQid = function(frame)
 +
return p._followQid(frame.args)
 
end
 
end
   Line 3,056: Line 3,160:  
-- from the item given by the parameter 'qid'
 
-- from the item given by the parameter 'qid'
 
-- or from the Wikidata item associated with the current page if qid is not supplied.
 
-- or from the Wikidata item associated with the current page if qid is not supplied.
 +
-- It only checks ranks that are requested (preferred and normal by default)
 
-- If property is not supplied, then P31 (instance of) is assumed.
 
-- If property is not supplied, then P31 (instance of) is assumed.
 
-- It returns val if found or nothing if not found.
 
-- It returns val if found or nothing if not found.
Line 3,079: Line 3,184:  
if qid:sub(1,1) ~= "Q" then qid = mw.wikibase.getEntityIdForCurrentPage() end
 
if qid:sub(1,1) ~= "Q" then qid = mw.wikibase.getEntityIdForCurrentPage() end
 
if not qid then return nil end
 
if not qid then return nil end
local stats = mw.wikibase.getAllStatements( qid, pid )
+
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
 
if not stats[1] then return nil end
 
if not stats[1] then return nil end
 
if stats[1].mainsnak.datatype == "wikibase-item" then
 
if stats[1].mainsnak.datatype == "wikibase-item" then
 
for k, v in pairs( stats ) do
 
for k, v in pairs( stats ) do
if v.mainsnak.snaktype == "value" and v.mainsnak.datavalue.value.id == val then
+
local ms = v.mainsnak
 +
if ranks[v.rank:sub(1,1)] and ms.snaktype == "value" and ms.datavalue.value.id == val then
 
return val
 
return val
 
end
 
end
Line 3,098: Line 3,210:  
-- but it keeps the "edit at Wikidata" pen icon out of the microformat.
 
-- 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:
 
-- 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}}
+
-- e.g. {{#invoke:WikidataIB |url2 |url={{wdib |P856 |qid=Q23317 |fwd=ALL |osd=no}} }}
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
-- Dependencies: none
 
-- Dependencies: none
Line 3,105: Line 3,217:  
local txt = frame.args.url or ""
 
local txt = frame.args.url or ""
 
if txt == "" then return nil end
 
if txt == "" then return nil end
 +
-- extract any icon
 
local url, icon = txt:match("(.+)&nbsp;(.+)")
 
local url, icon = txt:match("(.+)&nbsp;(.+)")
url = url or txt
+
-- make sure there's at least a space at the end
 +
url = (url or txt) .. " "
 
icon = icon or ""
 
icon = icon or ""
local prot, addr = url:match("(http[s]*://)(.+)")
+
-- extract any protocol like https://
prot = prot or url
+
local prot = url:match("(https*://).+[ \"\']")
addr = addr or ""
+
-- extract address
local disp, n = addr:gsub("%.", "<wbr/>%.")
+
local addr = ""
 +
if prot then
 +
addr = url:match("https*://(.+)[ \"\']") or " "
 +
else
 +
prot = "//"
 +
addr = url:match("[^%p%s]+%.(.+)[ \"\']") or " "
 +
end
 +
-- 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>&nbsp;" .. icon
 
return '<span class="url">[' .. prot .. addr .. " " .. disp .. "]</span>&nbsp;" .. icon
 
end
 
end
Line 3,189: Line 3,311:  
local args = frame.args or frame:getParent().args or {}
 
local args = frame.args or frame:getParent().args or {}
   −
local qid = args.qid
+
local qid = args.qid or ""
if qid == "" then qid = nil end
+
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 entity = mw.wikibase.getEntity(qid)
  −
if not entity then return i18n["entity-not-found"] end
     −
local labels = entity.labels
+
local labels = mw.wikibase.getEntity(qid).labels
 
if not labels then return i18n["labels-not-found"] end
 
if not labels then return i18n["labels-not-found"] end
   Line 3,216: Line 3,336:  
local args = frame.args or frame:getParent().args or {}
 
local args = frame.args or frame:getParent().args or {}
   −
local qid = args.qid
+
local qid = args.qid or ""
if qid == "" then qid = nil end
+
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 entity = mw.wikibase.getEntity(qid)
  −
if not entity then return i18n["entity-not-found"] end
     −
local descriptions = entity.descriptions
+
local descriptions = mw.wikibase.getEntity(qid).descriptions
 
if not descriptions then return i18n["descriptions-not-found"] end
 
if not descriptions then return i18n["descriptions-not-found"] end
   Line 3,243: Line 3,361:  
local args = frame.args or frame:getParent().args or {}
 
local args = frame.args or frame:getParent().args or {}
   −
local qid = args.qid
+
local qid = args.qid or ""
if qid == "" then qid = nil end
+
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 entity = mw.wikibase.getEntity(qid)
+
local aliases = mw.wikibase.getEntity(qid).aliases
if not entity then return i18n["entity-not-found"] end
  −
 
  −
local aliases = entity.aliases
   
if not aliases then return i18n["aliases-not-found"] end
 
if not aliases then return i18n["aliases-not-found"] end
   Line 3,316: Line 3,432:  
local site = args.site or ""
 
local site = args.site or ""
 
local showdab = parseParam(args.showdab, true)
 
local showdab = parseParam(args.showdab, true)
qid = mw.wikibase.getEntityIdForTitle(title, site)
+
local qid = mw.wikibase.getEntityIdForTitle(title, site)
 
if qid then
 
if qid then
 
local prop31 = mw.wikibase.getBestStatements(qid, "P31")[1]
 
local prop31 = mw.wikibase.getBestStatements(qid, "P31")[1]
Line 3,326: Line 3,442:  
end
 
end
 
end
 
end
 +
    
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
Line 3,333: Line 3,450:  
-- The meanings are given at https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times
 
-- The meanings are given at https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times
 
-- 0 = 1 billion years .. 6 = millennium, 7 = century, 8 = decade, 9 = year, 10 = month, 11 = day
 
-- 0 = 1 billion years .. 6 = millennium, 7 = century, 8 = decade, 9 = year, 10 = month, 11 = day
-- Returns nil if it does not exist.
+
-- Returns 0 (or the second unnamed parameter) if the Wikidata does not exist.
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- Dependencies: parseParam
+
-- Dependencies: parseParam; sourced;
 
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
 
function p.getDatePrecision(frame)
 
function p.getDatePrecision(frame)
 
local args=frame.args
 
local args=frame.args
 
if not args[1] then args=frame:getParent().args end
 
if not args[1] then args=frame:getParent().args end
 +
local default = tonumber(args[2] or args.default) or 0
 
local prop = mw.text.trim(args[1] or "")
 
local prop = mw.text.trim(args[1] or "")
if prop == "" then return nil end
+
if prop == "" then return default end
 
local qid = args.qid or ""
 
local qid = args.qid or ""
 
if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end
 
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 onlysrc = parseParam(args.onlysourced or args.osd, true)
 
local stat = mw.wikibase.getBestStatements(qid, prop)
 
local stat = mw.wikibase.getBestStatements(qid, prop)
Line 3,353: Line 3,472:  
if prec then return prec end
 
if prec then return prec end
 
end
 
end
 +
return default
 
end
 
end