Modul:External links: Forskjell mellom sideversjoner
Hopp til navigering
Hopp til søk
+test for short_links |
m 102 sideversjoner ble importert |
||
| (57 mellomliggende versjoner av 11 brukere er ikke vist) | |||
| Linje 1: | Linje 1: | ||
require(' | require('strict') | ||
local genitiv = require(' | local genitiv = require('Module:Genitiv')._genitiv | ||
local contLang = mw.language.getContentLanguage() | local contLang = mw.language.getContentLanguage() | ||
local cmodule = {} | local cmodule = {} | ||
local conf = require 'Module:External links/conf'(contLang:getCode()) | local conf = require 'Module:External links/conf'(contLang:getCode()) | ||
local hasdatafromwikidata = false | |||
local hasdatafromlocal = false | |||
local haswikidatalink = true -- we assume it's connected | |||
local themainentity = mw.wikibase.getEntity() | |||
local linktarget = 'https://www.wikidata.org/wiki/%s?uselang=%s#%s' | |||
local p = {} | local p = {} | ||
| Linje 15: | Linje 21: | ||
label = mw.wikibase.label(entity.id) or mw.title.getCurrentTitle().text | label = mw.wikibase.label(entity.id) or mw.title.getCurrentTitle().text | ||
end | end | ||
return use_genitiv and genitiv(label) or label | return use_genitiv and genitiv(label, 'sitt') or label | ||
end | end | ||
| Linje 31: | Linje 37: | ||
end | end | ||
local | local pval = {} | ||
pval.P1793 = { -- format as a regular expression | |||
types = { | types = { | ||
snaktype = 'value', | snaktype = 'value', | ||
| Linje 38: | Linje 44: | ||
}, | }, | ||
} | } | ||
-- | pval.P407 = { -- language of work or name | ||
types = { | |||
snaktype = 'value', | |||
datatype = 'wikibase-item', | |||
datavalue = { | |||
type = 'wikibase-entityid', | |||
} | |||
}, | |||
} | |||
pval.P364 = { -- original language of work | pval.P364 = { -- original language of work | ||
types = { | types = { | ||
| Linje 62: | Linje 65: | ||
} | } | ||
pval.P218 = { -- ISO 639-1 language | pval.P218 = { -- ISO 639-1 language | ||
types = { | types = { | ||
| Linje 84: | Linje 75: | ||
} | } | ||
pval.P305 = { -- IETF language tag | |||
types = { | |||
snaktype = 'value', | |||
datatype = 'external-id', | |||
datavalue = { | |||
type = 'string', | |||
} | |||
}, | |||
} | |||
pval.P582 = { -- end time | |||
types = { | |||
snaktype = 'value', | |||
datatype = 'time', | |||
datavalue = { | |||
type = 'string', | |||
} | |||
}, | |||
} | |||
-- This is a really makeshift crappy converter, but it'll do some basic | -- This is a really makeshift crappy converter, but it'll do some basic | ||
-- conversion from PCRE to Lua-style patterns (note that this only | -- conversion from PCRE to Lua-style patterns (note that this only works | ||
-- in very few cases) | -- in very few cases) | ||
local function regexConverter( regex ) | local function regexConverter( regex ) | ||
| Linje 104: | Linje 113: | ||
end | end | ||
function string.urlEncode( str ) | |||
if ( str ) then | |||
str = string.gsub( str, "\n", "\r\n" ) | |||
str = string.gsub( str, "([^-%w/ ])", | |||
function (c) return string.format( "%%%02X", string.byte(c) ) end ) | |||
str = string.gsub( str, " ", "+" ) | |||
end | |||
return str | |||
end | |||
local function getFormatterUrl( prop, value ) | local function getFormatterUrl( prop, value ) | ||
| Linje 114: | Linje 132: | ||
end | end | ||
-- get the claims for this entity | -- get the claims for this entity | ||
local statements = entity.claims['P1630'] | local statements = entity.claims['P1630'] -- formatter URL | ||
-- to avoid deep tests | -- to avoid deep tests | ||
if not statements then | if not statements then | ||
| Linje 130: | Linje 148: | ||
if valid then | if valid then | ||
local mainsnak = claim.mainsnak or {} | local mainsnak = claim.mainsnak or {} | ||
local preferred = claim['rank'] == 'preferred' | local preferred = claim['rank'] == 'preferred' | ||
-- get any qualifiers for this claim (we are interested in P1793 for | -- get any qualifiers for this claim (we are interested in P1793 for | ||
-- indication of which claim is correct) | -- indication of which claim is correct) | ||
local qualifiers = claim.qualifiers or {} | local qualifiers = claim.qualifiers or {} | ||
-- now | -- now let's check the qualifier we are interested in | ||
-- | local qualid = 'P1793' -- format as a regular expression | ||
-- if the claim has this qualifier | |||
if qualifiers[qualid] then | |||
-- it's here, let's check it out! | |||
local items = {} | |||
-- traverse all snaks in this qualifier | |||
for _, qualsnak in ipairs( qualifiers[qualid] ) do | |||
if qualsnak and pval[qualid] then | |||
--mw.log("qualsnak = " .. dump(qualsnak)) | |||
-- check if the snak is of the correct snaktype and datatype | |||
local valid = qualsnak.snaktype == pval[qualid].types.snaktype | |||
and qualsnak.datatype == pval[qualid].types.datatype | |||
if valid then | |||
-- we'll have to convert the regex to Lua-style | |||
local regex = regexConverter(qualsnak.datavalue.value) | |||
local test = string.match( value, '^'..regex..'$' ) | |||
if test then | |||
-- it matched, this is correct and overrides any other. | |||
if preferred then | |||
head = mainsnak.datavalue.value | |||
else | |||
tail = mainsnak.datavalue.value | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
else | end | ||
else | |||
-- we don't have any qualifier, is it preferred? | |||
if mainsnak.datavalue and (head == '' and preferred) or (tail == '' and not preferred) then | |||
-- if we don't have any other, use this one | |||
if preferred and head == '' then | |||
head = mainsnak.datavalue.value | |||
elseif not preferred and tail == '' then | |||
tail = mainsnak.datavalue.value | |||
end | end | ||
end | end | ||
| Linje 184: | Linje 193: | ||
end | end | ||
end | end | ||
return head ~= '' and head or tail | return head ~= '' and head or tail | ||
| Linje 190: | Linje 198: | ||
local function | |||
local | local function getLanguageData(prop, qid) | ||
local head = {} | |||
local tail = {} | |||
-- mw.log("getLanguageData, prop="..dump(prop).." qid="..dump(qid)) | |||
-- get the entity we are checking | -- get the entity we are checking | ||
local entity = mw.wikibase.getEntityObject() | local entity = mw.wikibase.getEntityObject(qid) | ||
-- to avoid deep tests | -- to avoid deep tests | ||
if not entity then | if not entity then | ||
| Linje 199: | Linje 210: | ||
end | end | ||
if not entity.claims then | if not entity.claims then | ||
return | return {} | ||
end | |||
-- get the claims for this entity | |||
local statements = entity.claims[prop] | |||
-- to avoid deep tests | |||
if not statements then | |||
return {} | |||
end | |||
-- mw.log("getLanguageData going through claims="..dump(statements)) | |||
-- let's go through the claims | |||
for _, claim in ipairs( statements ) do | |||
-- to avoid deep tests | |||
if not claim then | |||
claim = {} | |||
end | |||
local valid = claim['type'] == 'statement' | |||
and claim['rank'] ~= 'deprecated' | |||
if valid then | |||
local mainsnak = claim.mainsnak or {} | |||
local preferred = claim['rank'] == 'preferred' | |||
-- verify the item is what we expect | |||
local valid = mainsnak.snaktype == pval[prop].types.snaktype | |||
and mainsnak.datatype == pval[prop].types.datatype | |||
and mainsnak.datavalue.type == pval[prop].types.datavalue.type | |||
if valid then | |||
-- mw.log("getLanguageData claim is valid="..dump(claim)) | |||
-- if this is the correct P-value, dive into it and get P218 (ISO 639-1) | |||
if mainsnak.property == 'P364' then -- original language of work | |||
if preferred then | |||
head[#head+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator')) | |||
else | |||
tail[#tail+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator')) | |||
end | |||
elseif mainsnak.property == 'P218' or mainsnak.property == 'P305' then -- ISO 639-1 code or IETF language tag | |||
if preferred then | |||
head[#head+1] = stringFormatter(mainsnak.datavalue) | |||
else | |||
tail[#tail+1] = stringFormatter(mainsnak.datavalue) | |||
end | |||
end | |||
end | |||
end | |||
end | |||
-- mw.log("getLanguageData returning head="..dump(head).." tail="..dump(tail)) | |||
return #head>0 and head or tail | |||
end | |||
local langqvalorder = {'P407','P364'} | |||
local otherqvalorder = {'P582'} | |||
local function getValuesFromWikidata(props) | |||
local head = {} | |||
local tail = {} | |||
-- mw.log("getValuesFromWikidata, props="..dump(props)) | |||
-- get the entity we are checking | |||
local entity = themainentity | |||
-- to avoid deep tests | |||
if not entity then | |||
--mw.log("getValuesFromWikidata no entity") | |||
return nil | |||
end | |||
if not entity.claims or not props or not props.prop or props.prop == '' then | |||
--mw.log("getValuesFromWikidata no claims or no props") | |||
return {} | |||
end | end | ||
-- get the claims for this entity | -- get the claims for this entity | ||
| Linje 205: | Linje 279: | ||
-- to avoid deep tests | -- to avoid deep tests | ||
if not statements then | if not statements then | ||
return | return {} | ||
end | end | ||
-- let's go through the claims | -- let's go through the claims | ||
| Linje 216: | Linje 290: | ||
and claim['rank'] ~= 'deprecated' | and claim['rank'] ~= 'deprecated' | ||
if valid then | if valid then | ||
-- mw.log("getValuesFromWikidata valid claim="..dump(claim)) | |||
local mainsnak = claim.mainsnak or {} | local mainsnak = claim.mainsnak or {} | ||
local preferred = claim['rank'] == 'preferred' | local preferred = claim['rank'] == 'preferred' | ||
-- get the content of the claim (the identifier) | -- get the content of the claim (the identifier) | ||
local | local langcode = props.langcode | ||
local | local checklangcode = nil | ||
if props. | if props.langcode and props.langcode ~= '' then | ||
-- | checklangcode = string.find(langcode, "([pP]%d+)") | ||
-- | end | ||
if checklangcode and checklangcode ~= "" then | |||
-- this is a P-value for language-code, so we'll check qualifiers for languagedata | |||
-- first get any qualifiers | |||
local qualifiers = claim.qualifiers or {} | |||
for _, qualid in ipairs( langqvalorder ) do | |||
-- if the claim has this qualifier | |||
if qualifiers[qualid] then | |||
-- it's here, let's check it out! | |||
local items = {} | |||
-- traverse all snaks in this qualifier | |||
for _, qualsnak in ipairs( qualifiers[qualid] ) do | |||
if qualsnak and pval[qualid] then | |||
-- mw.log("qualsnak = " .. dump(qualsnak)) | |||
-- check if the snak is of the correct snaktype and datatype | |||
local valid = qualsnak.snaktype == pval[qualid].types.snaktype | |||
and qualsnak.datatype == pval[qualid].types.datatype | |||
if valid then | |||
-- now get the actual data | |||
langcode = table.concat(getLanguageData('P305', 'Q'..qualsnak.datavalue.value['numeric-id']), '') | |||
end | |||
end | |||
end | |||
end | |||
-- mw.log("langcode is now="..dump(langcode)) | |||
end | |||
if string.find(langcode, "([pP]%d+)") then | |||
-- we still don't have any langcode, so we default to "en" | |||
langcode = nil | |||
end | |||
end | |||
local stillvalid = true | |||
-- we should check a couple of other qualifiers as well | |||
-- first get any qualifiers | |||
local qualifiers = claim.qualifiers or {} | |||
for _, qualid in ipairs( otherqvalorder ) do | |||
-- if the claim has this qualifier | |||
if qualifiers[qualid] then | |||
-- it's here, let's check it out! | |||
local items = {} | |||
-- traverse all snaks in this qualifier | |||
for _, qualsnak in ipairs( qualifiers[qualid] ) do | |||
if qualsnak and pval[qualid] then | |||
-- mw.log("qualsnak = " .. dump(qualsnak)) | |||
-- check if the snak is of the correct snaktype and datatype | |||
local valid = qualsnak.snaktype == pval[qualid].types.snaktype | |||
and qualsnak.datatype == pval[qualid].types.datatype | |||
if not valid then | |||
-- sorry, this is not correct | |||
mw.log("qualsnak = INCORRECT") | |||
stillvalid = false | |||
end | |||
end | |||
end | |||
end | end | ||
-- mw.log("langcode is now="..dump(langcode)) | |||
end | end | ||
if stillvalid then | |||
if | if preferred then | ||
head[#head+1] = { value=stringFormatter(mainsnak.datavalue) } | |||
if | if langcode and langcode ~= '' then | ||
head[#head]['langcode'] = langcode | |||
end | |||
else | else | ||
tail[#tail+1] = { value=stringFormatter(mainsnak.datavalue) } | |||
if langcode and langcode ~= '' then | |||
if | tail[#tail]['langcode'] = langcode | ||
end | end | ||
end | end | ||
end | |||
if url | end | ||
output[#output+1] = | end | ||
output[#output].langcode = props. | -- mw.log("getValuesFromWikidata returning head="..dump(head).." tail="..dump(tail)) | ||
return #head>0 and head or tail | |||
end | |||
local function findMainLinksOnWikidata(props, pagetitle, short_links) | |||
local output = {} | |||
local pid = nil | |||
-- get the entity we are checking | |||
local entity = themainentity | |||
-- to avoid deep tests | |||
if not entity then | |||
return nil | |||
end | |||
local values = getValuesFromWikidata(props) | |||
for _, value in ipairs( values ) do | |||
local verified_value = nil | |||
if props.regex then | |||
-- we have a local defined regex, so this will have to pass first | |||
-- maybe we'll have to convert the regex to Lua-style | |||
local regex = regexConverter(props.regex) | |||
local test = string.match( value.value, '^'..regex..'$' ) | |||
-- mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id) | |||
if test then | |||
-- it matched, this is correct and overrides any other. | |||
verified_value = value.value | |||
end | |||
else | |||
verified_value = value.value | |||
end | |||
if verified_value then | |||
local url = '' | |||
output[#output+1] = {} | |||
output[#output].langcode = value.langcode | |||
output[#output].category = {} | |||
if props.url_f then | |||
-- we have a local defined url-formatter function, use it as first priority | |||
url = props.url_f(verified_value) | |||
if props.track and not string.find(props.langcode, "([pP]%d+)") then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain() | |||
elseif props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain() | |||
end | |||
elseif props.url then | |||
-- we have a local defined url-formatter string, use it as second priority | |||
url = mw.message.newRawMessage(props.url, string.urlEncode(verified_value)):plain() | |||
if props.track and not string.find(props.langcode, "([pP]%d+)") then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain() | |||
elseif props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain() | |||
end | |||
else | |||
-- get the formatvalue from the property, if it exists | |||
local formatterUrl = getFormatterUrl(props.prop, verified_value) | |||
if formatterUrl ~= '' then | |||
url = mw.message.newRawMessage(formatterUrl, string.urlEncode(verified_value)):plain() | |||
if props.track then | if props.track then | ||
output[#output].category = mw.message.newRawMessage(cmodule:getMessage(contLang: | output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain() | ||
end | end | ||
end | |||
end | |||
if url ~= '' then | |||
local this_wiki = mw.getContentLanguage() | |||
local this_wiki_code = this_wiki:getCode() | |||
local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or "" | |||
if short_links and props.short then | |||
output[#output].text = | |||
mw.message.newRawMessage(props.short, | |||
getLabel(entity, props.genitiv, pagetitle), | |||
url, | |||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | |||
else | |||
output[#output].text = | |||
mw.message.newRawMessage(props.message, | |||
getLabel(entity, props.genitiv, pagetitle), | |||
url, | |||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | |||
end | |||
end | |||
end | |||
end | |||
--mw.log("findMainLinksOnWikidata returning="..dump(output)) | |||
return output | |||
end | |||
local function getSitelinksFromWikidata(props, entity) | |||
local output = {} | |||
--mw.log("getSitelinksFromWikidata, props="..dump(props)) | |||
-- to avoid deep tests | |||
if not entity then | |||
entity = themainentity | |||
if not entity then | |||
--mw.log("getSitelinksFromWikidata no entity") | |||
return nil | |||
end | |||
end | |||
local requested_sitelink = string.match(props.prop, "SL(%l+)") | |||
local sitelinks = entity:getSitelink(requested_sitelink) | |||
if sitelinks and sitelinks ~= '' then | |||
output[#output+1] = { value = sitelinks } | |||
end | |||
--mw.log("getSitelinksFromWikidata returning output="..dump(output)) | |||
return output | |||
end | |||
local function findSiteLinksOnWikidata(props, pagetitle, short_links) | |||
local output = {} | |||
local pid = nil | |||
-- get the entity we are checking | |||
local entity = themainentity | |||
-- to avoid deep tests | |||
if not entity then | |||
return nil | |||
end | |||
local values = getSitelinksFromWikidata(props) | |||
for _, value in ipairs( values ) do | |||
local verified_value = nil | |||
if props.regex then | |||
-- we have a local defined regex, so this will have to pass first | |||
-- maybe we'll have to convert the regex to Lua-style | |||
local regex = regexConverter(props.regex) | |||
local test = string.match( value.value, '^'..regex..'$' ) | |||
--mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id) | |||
if test then | |||
-- it matched, this is correct and overrides any other. | |||
verified_value = value.value | |||
end | |||
else | |||
verified_value = value.value | |||
end | |||
if verified_value then | |||
--mw.log("it's verified..") | |||
local url = '' | |||
output[#output+1] = {} | |||
output[#output].langcode = value.langcode | |||
output[#output].category = {} | |||
if props.url_f then | |||
-- we have a local defined url-formatter function, use it as first priority | |||
url = props.url_f(verified_value) | |||
if props.track and not string.find(props.langcode, "(SL%l+)") then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain() | |||
elseif props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain() | |||
end | |||
elseif props.url then | |||
-- we have a local defined url-formatter string, use it as second priority | |||
url = mw.message.newRawMessage(props.url, verified_value):plain() | |||
if props.track and not string.find(props.langcode, "(SL%l+)") then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain() | |||
elseif props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain() | |||
end | |||
else | |||
url = verified_value:gsub(' ','_') | |||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain() | |||
end | |||
end | |||
if url ~= '' then | |||
local this_wiki = mw.getContentLanguage() | |||
local this_wiki_code = this_wiki:getCode() | |||
local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or "" | |||
if short_links and props.short then | |||
output[#output].text = | |||
mw.message.newRawMessage(props.short, | |||
getLabel(entity, props.genitiv, pagetitle), | |||
url, | |||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | |||
else | |||
output[#output].text = | |||
mw.message.newRawMessage(props.message, | |||
getLabel(entity, props.genitiv, pagetitle), | |||
url, | |||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
--mw.log("returning | --mw.log("findSiteLinksOnWikidata returning="..dump(output)) | ||
return output | return output | ||
end | end | ||
local function findMainLinksLocal(props, pagetitle, short_links, | local function findMainLinksLocal(props, pagetitle, short_links, local_value) | ||
local output = {} | local output = {} | ||
-- to avoid deep tests | -- to avoid deep tests | ||
| Linje 286: | Linje 571: | ||
return nil | return nil | ||
end | end | ||
if not | if not (local_value or local_value == '') then | ||
-- bail out if no value is present | |||
return output | return output | ||
end | end | ||
-- get the formatvalue from the property | -- get the formatvalue from the property | ||
local | local verified_value = local_value | ||
if props.regex then | if props.regex and props.regex ~= '' then | ||
-- let's verify the id | -- let's verify the id | ||
-- maybe we'll have to convert the regex to Lua-style | -- maybe we'll have to convert the regex to Lua-style | ||
local regex = regexConverter(props.regex) | local regex = regexConverter(props.regex) | ||
local test = string.match( | local test = string.match( local_value, '^'..regex..'$' ) | ||
if test then | if test then | ||
-- it matched, this is correct | -- it matched, this is correct | ||
verified_value = local_value | |||
else | |||
verified_value = nil | |||
end | end | ||
end | end | ||
if not | if not verified_value then | ||
return output | return output | ||
end | end | ||
if (props.url and props.url ~= '') or (props.url_f) then | local wikidata_property = string.find(props.prop, "([pP]%d+)") | ||
local wikidata_values = {} | |||
if wikidata_property then | |||
-- get any wikidata values to see if they are equal to local values | |||
wikidata_values = getValuesFromWikidata(props) | |||
end | |||
if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then | |||
output[#output+1] = {} | output[#output+1] = {} | ||
output[#output].langcode = props.langcode | output[#output].langcode = string.find(props.langcode, "([pP]%d+)") and "" or props.langcode | ||
if props.track then | --mw.log("findMainLinksLocal - props="..dump(props).." langcode="..output[#output].langcode) | ||
output[#output].category = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), ' | output[#output].category = {} | ||
local url = '' | |||
if props.track and wikidata_property and wikidata_values and #wikidata_values then | |||
local local_value_in_wikidata = false | |||
for _,value in ipairs( wikidata_values ) do | |||
if value.value == verified_value then | |||
local_value_in_wikidata = true | |||
end | |||
end | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain() | |||
end | |||
if wikidata_property and wikidata_values and #wikidata_values then | |||
hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim | |||
end | end | ||
if props.url_f then | if props.url_f then | ||
-- we have a local defined url-formatter function, use it as first priority | -- we have a local defined url-formatter function, use it as first priority | ||
url = props.url_f( | url = props.url_f(verified_value) | ||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain() | |||
end | |||
elseif props.url then | elseif props.url then | ||
-- we have a local defined url-formatter string, use it as second priority | -- we have a local defined url-formatter string, use it as second priority | ||
url = mw.message.newRawMessage(props.url, | url = mw.message.newRawMessage(props.url, string.urlEncode(verified_value)):plain() | ||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain() | |||
end | |||
elseif wikidata_property then | |||
-- get the formatvalue from the property, if it exists | |||
local formatterUrl = getFormatterUrl(props.prop, string.urlEncode(verified_value)) | |||
if formatterUrl ~= '' then | |||
url = mw.message.newRawMessage(formatterUrl, verified_value):plain() | |||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain() | |||
end | |||
end | |||
else | else | ||
-- no | -- no other choice, bail out | ||
return {} | return {} | ||
end | end | ||
local this_wiki = mw.getContentLanguage() | |||
local this_wiki_code = this_wiki:getCode() | |||
local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or "" | |||
if short_links and props.short then | if short_links and props.short then | ||
output[#output].text = | output[#output].text = | ||
mw.message.newRawMessage(props.short, | mw.message.newRawMessage(props.short, | ||
getLabel(nil, props.genitiv, pagetitle), | getLabel(nil, props.genitiv, pagetitle), | ||
url) | url, | ||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | :plain() | ||
else | else | ||
| Linje 335: | Linje 658: | ||
mw.message.newRawMessage(props.message, | mw.message.newRawMessage(props.message, | ||
getLabel(nil, props.genitiv, pagetitle), | getLabel(nil, props.genitiv, pagetitle), | ||
url) | url, | ||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | :plain() | ||
end | end | ||
end | end | ||
-- mw.log("returning | --mw.log("findMainLinksLocal returning="..dump(output)) | ||
return output | return output | ||
end | end | ||
local function findSiteLinksLocal(props, pagetitle, short_links, local_value) | |||
local function | |||
local output = {} | local output = {} | ||
-- to avoid deep tests | -- to avoid deep tests | ||
if not | if not props.prop then | ||
return nil | return nil | ||
end | end | ||
if not | if not (local_value or local_value == '') then | ||
-- bail out if no value is present | |||
return output | return output | ||
end | end | ||
-- get the | -- get the formatvalue from the property | ||
local | local verified_value = local_value | ||
if props.regex and props.regex ~= '' then | |||
if not | -- let's verify the id | ||
-- maybe we'll have to convert the regex to Lua-style | |||
local regex = regexConverter(props.regex) | |||
local test = string.match( local_value, '^'..regex..'$' ) | |||
if test then | |||
-- it matched, this is correct | |||
verified_value = local_value | |||
else | |||
verified_value = nil | |||
end | |||
end | |||
if not verified_value then | |||
return output | return output | ||
end | end | ||
-- | local wikidata_property = string.find(props.prop, "(SL.+)") | ||
local wikidata_values = {} | |||
if wikidata_property then | |||
if | -- get any wikidata values to see if they are equal to local values | ||
claim | wikidata_values = getSitelinksFromWikidata(props) | ||
end | |||
if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then | |||
output[#output+1] = {} | |||
output[#output].langcode = string.find(props.langcode, "(SL.+)") and "" or props.langcode | |||
--mw.log("findSiteLinksLocal - props="..dump(props).." langcode="..output[#output].langcode .." wikidata_values="..dump(wikidata_values)) | |||
output[#output].category = {} | |||
local url = '' | |||
if props.track and wikidata_property and wikidata_values and #wikidata_values then | |||
local local_value_in_wikidata = false | |||
for _,value in ipairs( wikidata_values ) do | |||
if value.value == verified_value then | |||
local_value_in_wikidata = true | |||
end | |||
end | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain() | |||
end | |||
if wikidata_property and wikidata_values and #wikidata_values then | |||
hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim | |||
end | end | ||
if props.url_f then | |||
-- we have a local defined url-formatter function, use it as first priority | |||
if | url = props.url_f(verified_value) | ||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain() | |||
-- | end | ||
elseif props.url then | |||
-- we have a local defined url-formatter string, use it as second priority | |||
url = mw.message.newRawMessage(props.url, verified_value):plain() | |||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain() | |||
end | |||
elseif wikidata_property then | |||
url = verified_value:gsub(' ','_') | |||
if props.track then | |||
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain() | |||
end | end | ||
else | |||
-- no other choice, bail out | |||
return {} | |||
end | |||
local this_wiki = mw.getContentLanguage() | |||
local this_wiki_code = this_wiki:getCode() | |||
local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or "" | |||
if short_links and props.short then | |||
output[#output].text = | |||
mw.message.newRawMessage(props.short, | |||
getLabel(nil, props.genitiv, pagetitle), | |||
url, | |||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | |||
else | |||
output[#output].text = | |||
mw.message.newRawMessage(props.message, | |||
getLabel(nil, props.genitiv, pagetitle), | |||
url, | |||
langlink, | |||
verified_value, | |||
mw.uri.encode(verified_value, 'PATH')) | |||
:plain() | |||
end | end | ||
end | end | ||
--mw.log(" | --mw.log("findSiteLinksLocal returning="..dump(output)) | ||
return output | return output | ||
end | end | ||
| Linje 392: | Linje 771: | ||
local function addLinkback(str, property) | local function addLinkback(str, property) | ||
local id = | local id = themainentity | ||
if not id then | if not id then | ||
return str | return str | ||
| Linje 400: | Linje 779: | ||
end | end | ||
if not property then | |||
return str | |||
if property then | |||
end | end | ||
local | local cls = string.format( 'wd_%s', string.lower( property ) ) | ||
local | local lnk = string.format( linktarget, id, contLang:getCode(), property ) | ||
local lbe = conf:g('wikidata-linkback-edit') | |||
local | local txt = '[[File:OOjs UI icon edit-ltr-progressive.svg' | ||
.. '|frameless|text-top|10px' | |||
.. '|alt=' .. mw.text.nowiki( lbe ) | |||
.. '|link=' .. mw.text.nowiki( lnk ) | |||
.. '|' .. mw.text.nowiki( lbe ) | |||
.. ']]' | |||
local html = mw.html.create( 'span' ) | |||
return tostring( | :addClass('noprint plainlinks wikidata-linkback ' .. cls ) | ||
-- @todo add back with correct definition | |||
-- :attr( 'data-bridge-edit-flow', 'single-best-value' ) | |||
:wikitext( txt ) | |||
return str .. ' ' .. tostring( html ) | |||
end | end | ||
local function getArgument(frame, argument) | local function getArgument(frame, argument) | ||
| Linje 438: | Linje 817: | ||
return nil | return nil | ||
end | end | ||
local function removeEntry(conf_claims, identifier, property) | local function removeEntry(conf_claims, identifier, property) | ||
for i, props in ipairs(conf_claims) do | for i, props in ipairs(conf_claims) do | ||
if props[identifier] == property then | if props[identifier] == property then | ||
| Linje 446: | Linje 825: | ||
end | end | ||
end | end | ||
return conf_claims | return conf_claims | ||
end | end | ||
| Linje 464: | Linje 842: | ||
local links_shown = getArgument(frame, conf:a('arg-maxlink')) | local links_shown = getArgument(frame, conf:a('arg-maxlink')) | ||
local pagetitle = getArgument(frame, conf:a('arg-title')) | local pagetitle = getArgument(frame, conf:a('arg-title')) | ||
-- get a list of tracked properties from the article itself | |||
local requested_tracking = getArgument(frame, conf:a('arg-track')) | |||
if requested_tracking and requested_tracking ~= '' then | |||
-- the properties should be written as P1234, P2345 and other | |||
-- version corresponding to the applicable property-identifiers in the config | |||
for track_prop in string.gmatch(requested_tracking,"([^ ,;:]+)") do | |||
-- get the requested properties and be able to access them | |||
-- like req_prop['P345'] to verify if it was requested | |||
local remove_track = string.match(track_prop, "^-(.*)") | |||
for i,claim in ipairs ( conf_claims ) do | |||
if remove_track == claim.prop or remove_track == conf:a('mod-filter-all') then | |||
-- if a property starts with "-", then we'll simply remove that | |||
-- property from the conf_claims | |||
conf_claims[i]['track'] = false | |||
elseif track_prop == claim.prop or track_prop == conf:a('mod-filter-all') then | |||
conf_claims[i]['track'] = true | |||
end | |||
end | |||
end | |||
end | |||
-- get a list of "approved" properties from the article itself | -- get a list of "approved" properties from the article itself | ||
local requested_properties = getArgument(frame, conf:a('arg-properties')) | local requested_properties = getArgument(frame, conf:a('arg-properties')) | ||
--mw.log("requested_properties="..dump(requested_properties)) | |||
-- assume all properties are allowed | -- assume all properties are allowed | ||
local req_prop = {} | local req_prop = {} | ||
| Linje 482: | Linje 881: | ||
no_req_prop = true | no_req_prop = true | ||
end | end | ||
local remove_prop = string.match(i, "^ | local remove_prop = string.match(i, "^-(.*)") | ||
if remove_prop then | if remove_prop then | ||
-- if a property starts with "-", then we'll simply remove that | -- if a property starts with "-", then we'll simply remove that | ||
| Linje 495: | Linje 894: | ||
end | end | ||
local requested_langs = getArgument(frame, conf:a('arg-languages')) | local requested_langs = getArgument(frame, conf:a('arg-languages')) | ||
--mw.log("requested_langs="..dump(requested_langs)) | |||
-- assume all languages are allowed | -- assume all languages are allowed | ||
local req_lang = {} | local req_lang = {} | ||
local no_req_lang = false -- we'll allow languages to be filtered for now | local no_req_lang = false -- we'll allow languages to be filtered for now | ||
if requested_langs and requested_langs ~= '' then | if requested_langs and requested_langs ~= '' then | ||
-- the languages should be written as langcodes as used in the conf_claims | -- the languages should be written as langcodes as used in the conf_claims | ||
| Linje 510: | Linje 910: | ||
end | end | ||
-- like req_lang['en'] to verify if it was requested | -- like req_lang['en'] to verify if it was requested | ||
local remove_lang = string.match(i, "^ | local remove_lang = string.match(i, "^-(.*)") | ||
if remove_lang then | if remove_lang then | ||
-- if a language starts with "-", then we'll simply remove that | -- if a language starts with "-", then we'll simply remove that | ||
| Linje 527: | Linje 927: | ||
else | else | ||
short_links = false | short_links = false | ||
end | |||
local showinline = getArgument(frame, conf:a('arg-inline')) | |||
if showinline and showinline ~= '' then | |||
showinline = true | |||
else | |||
showinline = false | |||
end | end | ||
if not links_shown or links_shown == '' then | if not links_shown or links_shown == '' then | ||
| Linje 533: | Linje 939: | ||
links_shown = tonumber(links_shown) | links_shown = tonumber(links_shown) | ||
end | end | ||
local somedataonwikidata = (short_links and false or true) | local somedataonwikidata = (short_links and false or true) | ||
--mw.log("conf_claims="..dump(conf_claims)) | |||
--mw.log("req_prop="..dump(req_prop)) | |||
--mw.log("req_lang="..dump(req_lang)) | |||
--mw.log("short_links="..dump(short_links)) | |||
for _, props in ipairs(conf_claims) do | for _, props in ipairs(conf_claims) do | ||
-- if we're called with a list of approved properties or languages, check if this one is "approved" | -- if we're called with a list of approved properties or languages, check if this one is "approved" | ||
if (#req_prop==0 or req_prop[props.prop]) and (#req_lang==0 or req_lang[props.langcode]) then | if (#req_prop==0 or req_prop[props.prop]) and (#req_lang==0 or req_lang[props.langcode] or string.find(props.langcode, "([pP]%d+)")) then | ||
--mw.log("checking claim="..dump(props)) | |||
local links = {} | local links = {} | ||
local checkedonwikidata = false | local checkedonwikidata = false | ||
if string.find(props.prop, "([pP]%d+)") then | -- get the any local overriding value from the call | ||
local wikivalue = getArgument(frame, props.prop) | |||
--mw.log("wikivalue="..dump(wikivalue)) | |||
if (not wikivalue or wikivalue == "") and string.find(props.prop, "([pP]%d+)") then | |||
-- the property is a Pnnn type, and therefore on Wikidata | -- the property is a Pnnn type, and therefore on Wikidata | ||
links = findMainLinksOnWikidata(props, pagetitle, short_links) | links = findMainLinksOnWikidata(props, pagetitle, short_links) | ||
| Linje 553: | Linje 963: | ||
checkedonwikidata = true | checkedonwikidata = true | ||
end | end | ||
else | elseif (not wikivalue or wikivalue == "") and string.find(props.prop, "(SL%l+)") then | ||
-- this is a sitelink-type (SLspecieswiki) | |||
--mw.log("finding sitelinks..") | |||
links = findSiteLinksOnWikidata(props, pagetitle, short_links) | |||
if links == nil then | |||
-- a nil-value indicated no wikidata-link | |||
haswikidatalink = false | |||
links = {} | |||
else | |||
checkedonwikidata = true | |||
end | |||
elseif (wikivalue and wikivalue ~= "") and string.find(props.prop, "(SL%l+)") then | |||
-- this is a sitelink-type (SLspecieswiki) | |||
links = findSiteLinksLocal(props, pagetitle, short_links, wikivalue) | |||
elseif wikivalue and wikivalue ~= '' then | |||
-- the property is of another annotation, and therefore a local construct | -- the property is of another annotation, and therefore a local construct | ||
links = findMainLinksLocal(props, pagetitle, short_links, wikivalue) | |||
end | end | ||
for _,v in ipairs(links) do | for _,v in ipairs(links) do | ||
if checkedonwikidata and not hasdatafromwikidata then | -- we'll have to check langcodes again as they may have come from wikidata | ||
if (#req_lang==0 or req_lang[v.langcode]) then | |||
if checkedonwikidata and not hasdatafromwikidata then | |||
-- add a general tracking category for articles with data from wikidata | |||
hasdatafromwikidata = true | |||
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-data-cat') | |||
elseif not checkedonwikidata and not hasdatafromlocal then | |||
-- add a general tracking category for articles with data from template-calls in local articles | |||
hasdatafromlocal = true | |||
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-local-cat') | |||
end | |||
if #output== | if short_links and props.short and v.text and v.text ~= '' then | ||
-- if short links were requested, and a short definition exists for this property, let's use it | |||
if #output==0 then | |||
output[#output+1] = v.text | |||
else | |||
output[#output] = output[#output] .. cmodule:getMessage(contLang:getCode(),'short-list-separator') .. v.text | |||
end | |||
somedataonwikidata = true | |||
elseif not short_links and not showinline and v.text and v.text ~= '' then | |||
-- only if short links were not requested | |||
output[#output+1] = (#output>=1 and conf:g('msg-ul-prepend') or '') -- if this is the first link, we won't output a list-element (msg-ul-prepend) | |||
.. (checkedonwikidata and addLinkback(v.text, props.prop) or v.text) -- if the link comes from wikidata, also output a linkback. | |||
elseif not short_links and showinline and v.text and v.text ~= '' then | |||
-- only if short links were not requested | |||
output[#output+1] = v.text | output[#output+1] = v.text | ||
end | |||
if props.track and v.category and #v.category then | |||
-- add category if tracking is on for this property and a category exists in the link-result. | |||
for _,cats in ipairs( v.category ) do | |||
category[#category+1] = cats | |||
end | |||
end | |||
if links_shown>0 then | |||
links_shown = links_shown - 1 | |||
else | else | ||
break | |||
end | end | ||
end | end | ||
end | end | ||
| Linje 602: | Linje 1 027: | ||
end | end | ||
end | end | ||
if short_links and #output then | local outtext = "" | ||
if short_links and #output>0 then | |||
-- if these are short links, output the whole thing with linkback to wikidata | -- if these are short links, output the whole thing with linkback to wikidata | ||
output = (somedataonwikidata and addLinkback(output | --mw.log("somedataonwikidata="..dump(somedataonwikidata).." and output="..dump(output).." and #output="..dump(#output)) | ||
elseif not short_links and #output then | outtext = (somedataonwikidata | ||
and addLinkback(table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')), nil) | |||
or table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator'))) | |||
elseif not short_links and not showinline and #output>0 then | |||
outtext = table.concat(output,"\n") | |||
elseif not short_links and showinline and #output>0 then | |||
outtext = table.concat(output,conf:g('msg-inline-separator')) | |||
end | end | ||
if not hasdatafromwikidata then | if not hasdatafromwikidata then | ||
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-data-cat') | category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-data-cat') | ||
if not hasdatafromlocal and not short_links then | if not hasdatafromlocal and not short_links then | ||
outtext = cmodule:getMessage(contLang:getCode(), 'no-data-text') | |||
end | end | ||
end | end | ||
| Linje 617: | Linje 1 048: | ||
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-wikilink-cat') | category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-wikilink-cat') | ||
if not hasdatafromlocal and not short_links then | if not hasdatafromlocal and not short_links then | ||
outtext = cmodule:getMessage(contLang:getCode(), 'no-wikilink') | |||
end | end | ||
end | end | ||
local nocategory = getArgument(frame, conf:a('arg-no-categories')) | |||
category = #category>0 and "\n" .. table.concat(category,"\n") or "" | |||
--mw.log("nocategory="..dump(nocategory).." and outtext="..dump(outtext).." and category="..dump(category)) | |||
outtext = outtext .. (nocategory and '' or category) | |||
return outtext | |||
end | end | ||
| Linje 626: | Linje 1 061: | ||
local prop = getArgument(frame, conf:a('arg-properties')) | local prop = getArgument(frame, conf:a('arg-properties')) | ||
local output = getLanguageData(prop) | local output = getLanguageData(prop) | ||
return table.concat(output, conf:a('mod-filter-separator')) | if output and #output>0 then | ||
return table.concat(output, conf:a('mod-filter-separator')) | |||
end | |||
end | end | ||
return p | return p | ||
Siste sideversjon per 22. apr. 2026 kl. 01:08
Modulen "External links" inneholder følgende metoder som er ment brukt via maler
- getLinks
- Henter eksterne lenker fra Wikidata i henhold til en konfigurasjonsfil
- Funksjonen har noen få felles standard-parametre som kan benyttes
conf- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=...}} - Den vil da returnere en rekke formaterte lenker til eksterne sider i henhold til en konfigurasjon som ligger som undersider av denne modulen.
- Følgende konfigurasjoner er tilgjengelige
-
Arter- Artslenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Arter}}. Se {{Artslenker}} for eksempel på bruk.Astronomi- Astronomi, Kalles opp slik:{{#invoke:External links|getLinks|conf=Astronomi}}. Se {{Astronomilenker}} for eksempel på bruk.Autoritetsdata- Autoritetsdata, Kalles opp slik:{{#invoke:External links|getLinks|conf=Autoritetsdata}}. Se {{Autoritetsdata}} for eksempel på bruk.Bryggeri- Bryggerilenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Bryggeri}}. Se {{Bryggerilenker}} for eksempel på bruk.Film- Filmlenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Film}}. Se {{Filmlenker}} for eksempel på bruk.Filmperson- Filmpersonlenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Filmperson}}. Se {{Filmperson}} for eksempel på bruk.Musikk- Musikklenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Musikk}}. Se {{Musikklenker}} for eksempel på bruk.Offisielle lenker- Offisielle lenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Offisielle lenker}}. Se {{Offisielle lenker}} for eksempel på bruk.Politiker- Politiker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Politiker}}. Se {{Politiker}} for eksempel på bruk.Some- Sosiale medie-lenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Some}}. Se {{Somelenker}} for eksempel på bruk.Spill- Spill-lenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Spill}}. Se {{Spill-lenker}} for eksempel på bruk.Sport- Sportslenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Sport}}. Se {{Sportslenker}} for eksempel på bruk.Skip- Skipslenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Skip}}. Se {{Skipslenker}} for eksempel på bruk.Forsker- Forskerlenker, Kalles opp slik:{{#invoke:External links|getLinks|conf=Forsker}}. Se {{Forskerlenker}} for eksempel på bruk.Test- For testing av nye typer og utvikling, Kalles opp slik:{{#invoke:External links|getLinks|conf=Test}}. Skal ikke benyttes i produksjon.
- Funksjonen kalles opp slik:
tittel- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|tittel=...}} - Denne parameteren kan overstyre artikkelnavnet som benyttes videre i modulen. Hvis dette ikke er satt, vil den som standard bruke sidenavnet til artikkelen.
- Funksjonen kalles opp slik:
maxlink- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|maxlink=...}} - Denne parameteren setter maksimum antall lenker som vises frem. Standardverdien er satt til 10.
- Funksjonen kalles opp slik:
prop- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|prop=<egenskap>,<egenskap2>,...}} - Denne parameteren setter en begrensning på hvilke egenskaper som skal vises frem. De skilles av med et komma, mellomrom, semikolon eller kolon. Dersom egenskapen starter med et minus-tegn (
-), f.eks.-P345, så vil alle egenskaper, unntatt den som er angitt forsøkes vist frem. Det er mulig å legge inn flere av disse.
- Funksjonen kalles opp slik:
kort- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|kort=1}} - Denne parameteren bestemmer om kort-versjonen av lenkene skal benyttes.
- Funksjonen kalles opp slik:
inline- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|inline=1}} - Denne parameteren bestemmer om lenkene skal legges på en linje med en separator i mellom seg. Linjen vil ikke prefikses med noen bullet eller lignenden. Se definisjonen av separatoren i Module:External links/conf under
['msg-inline-separator']. Denne funksjonaliteten er ment brukt i tilfeller hvor man ønsker å benytte lenkene i referanser eller lignende.
- Funksjonen kalles opp slik:
språk- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|språk=<langcode1>,<langcode2>...}} - Denne parameteren setter en begrensning på hvilke språk som skal vises frem. De skilles av med et komma, mellomrom, semikolon eller kolon. Dersom språkkoden starter med et minus-tegn (
-), f.eks.-fr, så vil alle språkkoder, unntatt den vises frem. Det er mulig å legge inn flere av disse. Spesial-verdienalleoverstyrer og tillater alle språk.
- Funksjonen kalles opp slik:
track- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|track=<egenskap1>,<egenskap2>...}} - Denne parameteren styrer individuelle sporingskategorier for hver egenskap. De skilles av med et komma, mellomrom, semikolon eller kolon. Dersom egenskapen starter med et minus-tegn (
-), f.eks.-P345, så vil den ikke spores (i tilfelle den er konfigurert til å spores i felleskonfigurasjonen). Det er mulig å legge inn flere av disse, og spesial-kodenallevil slå på sporing på alle.
- Funksjonen kalles opp slik:
<egenskapsnavn>- Funksjonen kalles opp slik:
{{#invoke:External links|getLinks|conf=<konfigurasjon ihht. ovenfor>|<egenskapsnavn>=<verdi>}} - Dette er en generell måte å sette verdien til en egenskap manuelt fra artikler/maler. Dette er ment brukt for tilfeller hvor man bruker en lokalt definert egenskap og trenger å gi den en verdi fra artikkelen. F.eks.
bbfc=46443vil gi ID-en til Blue Thunder i BBFc sin database, og den manuelle definisjonen avbbfci Module:External links/conf/Film vil da benyttes sammen med den ID-en for å bygge den eksterne lenken.
- Funksjonen kalles opp slik:
Se også
- Kategori:External links-kategorier - Kategori som samler forskjellige automatiske kategorier fra dette rammeverket
require('strict')
local genitiv = require('Module:Genitiv')._genitiv
local contLang = mw.language.getContentLanguage()
local cmodule = {}
local conf = require 'Module:External links/conf'(contLang:getCode())
local hasdatafromwikidata = false
local hasdatafromlocal = false
local haswikidatalink = true -- we assume it's connected
local themainentity = mw.wikibase.getEntity()
local linktarget = 'https://www.wikidata.org/wiki/%s?uselang=%s#%s'
local p = {}
local function getLabel(entity, use_genitiv, pagetitle)
local label = (pagetitle and pagetitle ~= '') and pagetitle or nil
if not label and not entity then
label = mw.title.getCurrentTitle().text
elseif not label then
label = mw.wikibase.label(entity.id) or mw.title.getCurrentTitle().text
end
return use_genitiv and genitiv(label, 'sitt') or label
end
-- @todo cleanup, this is in production, use the console
local function dump(obj)
return "<pre>" .. mw.dumpObject(obj) .. "</pre>"
end
local function stringFormatter( datavalue )
if datavalue == nil or datavalue['type'] ~= 'string' then
return nil
end
return datavalue.value
end
local pval = {}
pval.P1793 = { -- format as a regular expression
types = {
snaktype = 'value',
datatype = 'string',
},
}
pval.P407 = { -- language of work or name
types = {
snaktype = 'value',
datatype = 'wikibase-item',
datavalue = {
type = 'wikibase-entityid',
}
},
}
pval.P364 = { -- original language of work
types = {
snaktype = 'value',
datatype = 'wikibase-item',
datavalue = {
type = 'wikibase-entityid',
}
},
}
pval.P218 = { -- ISO 639-1 language
types = {
snaktype = 'value',
datatype = 'external-id',
datavalue = {
type = 'string',
}
},
}
pval.P305 = { -- IETF language tag
types = {
snaktype = 'value',
datatype = 'external-id',
datavalue = {
type = 'string',
}
},
}
pval.P582 = { -- end time
types = {
snaktype = 'value',
datatype = 'time',
datavalue = {
type = 'string',
}
},
}
-- This is a really makeshift crappy converter, but it'll do some basic
-- conversion from PCRE to Lua-style patterns (note that this only works
-- in very few cases)
local function regexConverter( regex )
local output = regex
output = string.gsub(output, "\\d{2}", "%%d%%d")
output = string.gsub(output, "\\d{3}", "%%d%%d%%d")
output = string.gsub(output, "\\d{4}", "%%d%%d%%d%%d")
output = string.gsub(output, "\\d{5}", "%%d%%d%%d%%d%%d")
output = string.gsub(output, "\\d{6}", "%%d%%d%%d%%d%%d%%d")
output = string.gsub(output, "\\d{7}", "%%d%%d%%d%%d%%d%%d%%d")
output = string.gsub(output, "\\d{8}", "%%d%%d%%d%%d%%d%%d%%d%%d")
output = string.gsub(output, "\\d", "%%d")
return output
end
function string.urlEncode( str )
if ( str ) then
str = string.gsub( str, "\n", "\r\n" )
str = string.gsub( str, "([^-%w/ ])",
function (c) return string.format( "%%%02X", string.byte(c) ) end )
str = string.gsub( str, " ", "+" )
end
return str
end
local function getFormatterUrl( prop, value )
local head = ""
local tail = ""
local entity = mw.wikibase.getEntity(prop)
-- to avoid deep tests
if not entity or not entity.claims then
return head
end
-- get the claims for this entity
local statements = entity.claims['P1630'] -- formatter URL
-- to avoid deep tests
if not statements then
return head
end
local formatters = {}
-- let's go through the claims
for _, claim in ipairs( statements ) do
-- to avoid deep tests
if not claim then
claim = {}
end
local valid = claim['type'] == 'statement'
and claim['rank'] ~= 'deprecated'
if valid then
local mainsnak = claim.mainsnak or {}
local preferred = claim['rank'] == 'preferred'
-- get any qualifiers for this claim (we are interested in P1793 for
-- indication of which claim is correct)
local qualifiers = claim.qualifiers or {}
-- now let's check the qualifier we are interested in
local qualid = 'P1793' -- format as a regular expression
-- if the claim has this qualifier
if qualifiers[qualid] then
-- it's here, let's check it out!
local items = {}
-- traverse all snaks in this qualifier
for _, qualsnak in ipairs( qualifiers[qualid] ) do
if qualsnak and pval[qualid] then
--mw.log("qualsnak = " .. dump(qualsnak))
-- check if the snak is of the correct snaktype and datatype
local valid = qualsnak.snaktype == pval[qualid].types.snaktype
and qualsnak.datatype == pval[qualid].types.datatype
if valid then
-- we'll have to convert the regex to Lua-style
local regex = regexConverter(qualsnak.datavalue.value)
local test = string.match( value, '^'..regex..'$' )
if test then
-- it matched, this is correct and overrides any other.
if preferred then
head = mainsnak.datavalue.value
else
tail = mainsnak.datavalue.value
end
end
end
end
end
else
-- we don't have any qualifier, is it preferred?
if mainsnak.datavalue and (head == '' and preferred) or (tail == '' and not preferred) then
-- if we don't have any other, use this one
if preferred and head == '' then
head = mainsnak.datavalue.value
elseif not preferred and tail == '' then
tail = mainsnak.datavalue.value
end
end
end
end
end
return head ~= '' and head or tail
end
local function getLanguageData(prop, qid)
local head = {}
local tail = {}
-- mw.log("getLanguageData, prop="..dump(prop).." qid="..dump(qid))
-- get the entity we are checking
local entity = mw.wikibase.getEntityObject(qid)
-- to avoid deep tests
if not entity then
return nil
end
if not entity.claims then
return {}
end
-- get the claims for this entity
local statements = entity.claims[prop]
-- to avoid deep tests
if not statements then
return {}
end
-- mw.log("getLanguageData going through claims="..dump(statements))
-- let's go through the claims
for _, claim in ipairs( statements ) do
-- to avoid deep tests
if not claim then
claim = {}
end
local valid = claim['type'] == 'statement'
and claim['rank'] ~= 'deprecated'
if valid then
local mainsnak = claim.mainsnak or {}
local preferred = claim['rank'] == 'preferred'
-- verify the item is what we expect
local valid = mainsnak.snaktype == pval[prop].types.snaktype
and mainsnak.datatype == pval[prop].types.datatype
and mainsnak.datavalue.type == pval[prop].types.datavalue.type
if valid then
-- mw.log("getLanguageData claim is valid="..dump(claim))
-- if this is the correct P-value, dive into it and get P218 (ISO 639-1)
if mainsnak.property == 'P364' then -- original language of work
if preferred then
head[#head+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator'))
else
tail[#tail+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator'))
end
elseif mainsnak.property == 'P218' or mainsnak.property == 'P305' then -- ISO 639-1 code or IETF language tag
if preferred then
head[#head+1] = stringFormatter(mainsnak.datavalue)
else
tail[#tail+1] = stringFormatter(mainsnak.datavalue)
end
end
end
end
end
-- mw.log("getLanguageData returning head="..dump(head).." tail="..dump(tail))
return #head>0 and head or tail
end
local langqvalorder = {'P407','P364'}
local otherqvalorder = {'P582'}
local function getValuesFromWikidata(props)
local head = {}
local tail = {}
-- mw.log("getValuesFromWikidata, props="..dump(props))
-- get the entity we are checking
local entity = themainentity
-- to avoid deep tests
if not entity then
--mw.log("getValuesFromWikidata no entity")
return nil
end
if not entity.claims or not props or not props.prop or props.prop == '' then
--mw.log("getValuesFromWikidata no claims or no props")
return {}
end
-- get the claims for this entity
local statements = entity.claims[props.prop]
-- to avoid deep tests
if not statements then
return {}
end
-- let's go through the claims
for _, claim in ipairs( statements ) do
-- to avoid deep tests
if not claim then
claim = {}
end
local valid = claim['type'] == 'statement'
and claim['rank'] ~= 'deprecated'
if valid then
-- mw.log("getValuesFromWikidata valid claim="..dump(claim))
local mainsnak = claim.mainsnak or {}
local preferred = claim['rank'] == 'preferred'
-- get the content of the claim (the identifier)
local langcode = props.langcode
local checklangcode = nil
if props.langcode and props.langcode ~= '' then
checklangcode = string.find(langcode, "([pP]%d+)")
end
if checklangcode and checklangcode ~= "" then
-- this is a P-value for language-code, so we'll check qualifiers for languagedata
-- first get any qualifiers
local qualifiers = claim.qualifiers or {}
for _, qualid in ipairs( langqvalorder ) do
-- if the claim has this qualifier
if qualifiers[qualid] then
-- it's here, let's check it out!
local items = {}
-- traverse all snaks in this qualifier
for _, qualsnak in ipairs( qualifiers[qualid] ) do
if qualsnak and pval[qualid] then
-- mw.log("qualsnak = " .. dump(qualsnak))
-- check if the snak is of the correct snaktype and datatype
local valid = qualsnak.snaktype == pval[qualid].types.snaktype
and qualsnak.datatype == pval[qualid].types.datatype
if valid then
-- now get the actual data
langcode = table.concat(getLanguageData('P305', 'Q'..qualsnak.datavalue.value['numeric-id']), '')
end
end
end
end
-- mw.log("langcode is now="..dump(langcode))
end
if string.find(langcode, "([pP]%d+)") then
-- we still don't have any langcode, so we default to "en"
langcode = nil
end
end
local stillvalid = true
-- we should check a couple of other qualifiers as well
-- first get any qualifiers
local qualifiers = claim.qualifiers or {}
for _, qualid in ipairs( otherqvalorder ) do
-- if the claim has this qualifier
if qualifiers[qualid] then
-- it's here, let's check it out!
local items = {}
-- traverse all snaks in this qualifier
for _, qualsnak in ipairs( qualifiers[qualid] ) do
if qualsnak and pval[qualid] then
-- mw.log("qualsnak = " .. dump(qualsnak))
-- check if the snak is of the correct snaktype and datatype
local valid = qualsnak.snaktype == pval[qualid].types.snaktype
and qualsnak.datatype == pval[qualid].types.datatype
if not valid then
-- sorry, this is not correct
mw.log("qualsnak = INCORRECT")
stillvalid = false
end
end
end
end
-- mw.log("langcode is now="..dump(langcode))
end
if stillvalid then
if preferred then
head[#head+1] = { value=stringFormatter(mainsnak.datavalue) }
if langcode and langcode ~= '' then
head[#head]['langcode'] = langcode
end
else
tail[#tail+1] = { value=stringFormatter(mainsnak.datavalue) }
if langcode and langcode ~= '' then
tail[#tail]['langcode'] = langcode
end
end
end
end
end
-- mw.log("getValuesFromWikidata returning head="..dump(head).." tail="..dump(tail))
return #head>0 and head or tail
end
local function findMainLinksOnWikidata(props, pagetitle, short_links)
local output = {}
local pid = nil
-- get the entity we are checking
local entity = themainentity
-- to avoid deep tests
if not entity then
return nil
end
local values = getValuesFromWikidata(props)
for _, value in ipairs( values ) do
local verified_value = nil
if props.regex then
-- we have a local defined regex, so this will have to pass first
-- maybe we'll have to convert the regex to Lua-style
local regex = regexConverter(props.regex)
local test = string.match( value.value, '^'..regex..'$' )
-- mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id)
if test then
-- it matched, this is correct and overrides any other.
verified_value = value.value
end
else
verified_value = value.value
end
if verified_value then
local url = ''
output[#output+1] = {}
output[#output].langcode = value.langcode
output[#output].category = {}
if props.url_f then
-- we have a local defined url-formatter function, use it as first priority
url = props.url_f(verified_value)
if props.track and not string.find(props.langcode, "([pP]%d+)") then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
elseif props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
end
elseif props.url then
-- we have a local defined url-formatter string, use it as second priority
url = mw.message.newRawMessage(props.url, string.urlEncode(verified_value)):plain()
if props.track and not string.find(props.langcode, "([pP]%d+)") then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
elseif props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
end
else
-- get the formatvalue from the property, if it exists
local formatterUrl = getFormatterUrl(props.prop, verified_value)
if formatterUrl ~= '' then
url = mw.message.newRawMessage(formatterUrl, string.urlEncode(verified_value)):plain()
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
end
end
end
if url ~= '' then
local this_wiki = mw.getContentLanguage()
local this_wiki_code = this_wiki:getCode()
local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or ""
if short_links and props.short then
output[#output].text =
mw.message.newRawMessage(props.short,
getLabel(entity, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
else
output[#output].text =
mw.message.newRawMessage(props.message,
getLabel(entity, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
end
end
end
end
--mw.log("findMainLinksOnWikidata returning="..dump(output))
return output
end
local function getSitelinksFromWikidata(props, entity)
local output = {}
--mw.log("getSitelinksFromWikidata, props="..dump(props))
-- to avoid deep tests
if not entity then
entity = themainentity
if not entity then
--mw.log("getSitelinksFromWikidata no entity")
return nil
end
end
local requested_sitelink = string.match(props.prop, "SL(%l+)")
local sitelinks = entity:getSitelink(requested_sitelink)
if sitelinks and sitelinks ~= '' then
output[#output+1] = { value = sitelinks }
end
--mw.log("getSitelinksFromWikidata returning output="..dump(output))
return output
end
local function findSiteLinksOnWikidata(props, pagetitle, short_links)
local output = {}
local pid = nil
-- get the entity we are checking
local entity = themainentity
-- to avoid deep tests
if not entity then
return nil
end
local values = getSitelinksFromWikidata(props)
for _, value in ipairs( values ) do
local verified_value = nil
if props.regex then
-- we have a local defined regex, so this will have to pass first
-- maybe we'll have to convert the regex to Lua-style
local regex = regexConverter(props.regex)
local test = string.match( value.value, '^'..regex..'$' )
--mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id)
if test then
-- it matched, this is correct and overrides any other.
verified_value = value.value
end
else
verified_value = value.value
end
if verified_value then
--mw.log("it's verified..")
local url = ''
output[#output+1] = {}
output[#output].langcode = value.langcode
output[#output].category = {}
if props.url_f then
-- we have a local defined url-formatter function, use it as first priority
url = props.url_f(verified_value)
if props.track and not string.find(props.langcode, "(SL%l+)") then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
elseif props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
end
elseif props.url then
-- we have a local defined url-formatter string, use it as second priority
url = mw.message.newRawMessage(props.url, verified_value):plain()
if props.track and not string.find(props.langcode, "(SL%l+)") then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()
elseif props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
end
else
url = verified_value:gsub(' ','_')
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()
end
end
if url ~= '' then
local this_wiki = mw.getContentLanguage()
local this_wiki_code = this_wiki:getCode()
local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or ""
if short_links and props.short then
output[#output].text =
mw.message.newRawMessage(props.short,
getLabel(entity, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
else
output[#output].text =
mw.message.newRawMessage(props.message,
getLabel(entity, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
end
end
end
end
--mw.log("findSiteLinksOnWikidata returning="..dump(output))
return output
end
local function findMainLinksLocal(props, pagetitle, short_links, local_value)
local output = {}
-- to avoid deep tests
if not props.prop then
return nil
end
if not (local_value or local_value == '') then
-- bail out if no value is present
return output
end
-- get the formatvalue from the property
local verified_value = local_value
if props.regex and props.regex ~= '' then
-- let's verify the id
-- maybe we'll have to convert the regex to Lua-style
local regex = regexConverter(props.regex)
local test = string.match( local_value, '^'..regex..'$' )
if test then
-- it matched, this is correct
verified_value = local_value
else
verified_value = nil
end
end
if not verified_value then
return output
end
local wikidata_property = string.find(props.prop, "([pP]%d+)")
local wikidata_values = {}
if wikidata_property then
-- get any wikidata values to see if they are equal to local values
wikidata_values = getValuesFromWikidata(props)
end
if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then
output[#output+1] = {}
output[#output].langcode = string.find(props.langcode, "([pP]%d+)") and "" or props.langcode
--mw.log("findMainLinksLocal - props="..dump(props).." langcode="..output[#output].langcode)
output[#output].category = {}
local url = ''
if props.track and wikidata_property and wikidata_values and #wikidata_values then
local local_value_in_wikidata = false
for _,value in ipairs( wikidata_values ) do
if value.value == verified_value then
local_value_in_wikidata = true
end
end
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain()
end
if wikidata_property and wikidata_values and #wikidata_values then
hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim
end
if props.url_f then
-- we have a local defined url-formatter function, use it as first priority
url = props.url_f(verified_value)
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
end
elseif props.url then
-- we have a local defined url-formatter string, use it as second priority
url = mw.message.newRawMessage(props.url, string.urlEncode(verified_value)):plain()
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
end
elseif wikidata_property then
-- get the formatvalue from the property, if it exists
local formatterUrl = getFormatterUrl(props.prop, string.urlEncode(verified_value))
if formatterUrl ~= '' then
url = mw.message.newRawMessage(formatterUrl, verified_value):plain()
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain()
end
end
else
-- no other choice, bail out
return {}
end
local this_wiki = mw.getContentLanguage()
local this_wiki_code = this_wiki:getCode()
local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or ""
if short_links and props.short then
output[#output].text =
mw.message.newRawMessage(props.short,
getLabel(nil, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
else
output[#output].text =
mw.message.newRawMessage(props.message,
getLabel(nil, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
end
end
--mw.log("findMainLinksLocal returning="..dump(output))
return output
end
local function findSiteLinksLocal(props, pagetitle, short_links, local_value)
local output = {}
-- to avoid deep tests
if not props.prop then
return nil
end
if not (local_value or local_value == '') then
-- bail out if no value is present
return output
end
-- get the formatvalue from the property
local verified_value = local_value
if props.regex and props.regex ~= '' then
-- let's verify the id
-- maybe we'll have to convert the regex to Lua-style
local regex = regexConverter(props.regex)
local test = string.match( local_value, '^'..regex..'$' )
if test then
-- it matched, this is correct
verified_value = local_value
else
verified_value = nil
end
end
if not verified_value then
return output
end
local wikidata_property = string.find(props.prop, "(SL.+)")
local wikidata_values = {}
if wikidata_property then
-- get any wikidata values to see if they are equal to local values
wikidata_values = getSitelinksFromWikidata(props)
end
if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then
output[#output+1] = {}
output[#output].langcode = string.find(props.langcode, "(SL.+)") and "" or props.langcode
--mw.log("findSiteLinksLocal - props="..dump(props).." langcode="..output[#output].langcode .." wikidata_values="..dump(wikidata_values))
output[#output].category = {}
local url = ''
if props.track and wikidata_property and wikidata_values and #wikidata_values then
local local_value_in_wikidata = false
for _,value in ipairs( wikidata_values ) do
if value.value == verified_value then
local_value_in_wikidata = true
end
end
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain()
end
if wikidata_property and wikidata_values and #wikidata_values then
hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim
end
if props.url_f then
-- we have a local defined url-formatter function, use it as first priority
url = props.url_f(verified_value)
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
end
elseif props.url then
-- we have a local defined url-formatter string, use it as second priority
url = mw.message.newRawMessage(props.url, verified_value):plain()
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()
end
elseif wikidata_property then
url = verified_value:gsub(' ','_')
if props.track then
output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain()
end
else
-- no other choice, bail out
return {}
end
local this_wiki = mw.getContentLanguage()
local this_wiki_code = this_wiki:getCode()
local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or ""
if short_links and props.short then
output[#output].text =
mw.message.newRawMessage(props.short,
getLabel(nil, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
else
output[#output].text =
mw.message.newRawMessage(props.message,
getLabel(nil, props.genitiv, pagetitle),
url,
langlink,
verified_value,
mw.uri.encode(verified_value, 'PATH'))
:plain()
end
end
--mw.log("findSiteLinksLocal returning="..dump(output))
return output
end
local function addLinkback(str, property)
local id = themainentity
if not id then
return str
end
if type(id) == 'table' then
id = id.id
end
if not property then
return str
end
local cls = string.format( 'wd_%s', string.lower( property ) )
local lnk = string.format( linktarget, id, contLang:getCode(), property )
local lbe = conf:g('wikidata-linkback-edit')
local txt = '[[File:OOjs UI icon edit-ltr-progressive.svg'
.. '|frameless|text-top|10px'
.. '|alt=' .. mw.text.nowiki( lbe )
.. '|link=' .. mw.text.nowiki( lnk )
.. '|' .. mw.text.nowiki( lbe )
.. ']]'
local html = mw.html.create( 'span' )
:addClass('noprint plainlinks wikidata-linkback ' .. cls )
-- @todo add back with correct definition
-- :attr( 'data-bridge-edit-flow', 'single-best-value' )
:wikitext( txt )
return str .. ' ' .. tostring( html )
end
local function getArgument(frame, argument)
local args = frame.args
if args[1] == nil then
local pFrame = frame:getParent();
args = pFrame.args;
for k,v in pairs( frame.args ) do
args[k] = v;
end
end
if args[argument] then
return args[argument]
end
return nil
end
local function removeEntry(conf_claims, identifier, property)
for i, props in ipairs(conf_claims) do
if props[identifier] == property then
table.remove(conf_claims, i)
end
end
return conf_claims
end
function p.getLinks(frame)
local configured_conf = getArgument(frame, conf:a('arg-conf'))
if configured_conf then
cmodule = require ('Module:External_links/conf/'..configured_conf)
else
error(mw.message.newRawMessage(conf:g('missing-conf'), configured_conf):plain())
end
local output = {}
local category = {}
local conf_claims = cmodule:getConfiguredClaims(contLang:getCode())
local limits = cmodule:getLimits()
assert(limits, mw.message.newRawMessage(conf:g('missing-limits'), configured_conf):plain())
local links_shown = getArgument(frame, conf:a('arg-maxlink'))
local pagetitle = getArgument(frame, conf:a('arg-title'))
-- get a list of tracked properties from the article itself
local requested_tracking = getArgument(frame, conf:a('arg-track'))
if requested_tracking and requested_tracking ~= '' then
-- the properties should be written as P1234, P2345 and other
-- version corresponding to the applicable property-identifiers in the config
for track_prop in string.gmatch(requested_tracking,"([^ ,;:]+)") do
-- get the requested properties and be able to access them
-- like req_prop['P345'] to verify if it was requested
local remove_track = string.match(track_prop, "^-(.*)")
for i,claim in ipairs ( conf_claims ) do
if remove_track == claim.prop or remove_track == conf:a('mod-filter-all') then
-- if a property starts with "-", then we'll simply remove that
-- property from the conf_claims
conf_claims[i]['track'] = false
elseif track_prop == claim.prop or track_prop == conf:a('mod-filter-all') then
conf_claims[i]['track'] = true
end
end
end
end
-- get a list of "approved" properties from the article itself
local requested_properties = getArgument(frame, conf:a('arg-properties'))
--mw.log("requested_properties="..dump(requested_properties))
-- assume all properties are allowed
local req_prop = {}
local no_req_prop = false -- we'll allow properties to be filtered for now
if requested_properties and requested_properties ~= '' then
-- the properties should be written as P1234, P2345 and other
-- version corresponding to the applicable property-identifiers in the config
for i in string.gmatch(requested_properties,"([^ ,;:]+)") do
-- get the requested properties and be able to access them
-- like req_prop['P345'] to verify if it was requested
if i == conf:a('mod-filter-all') then
-- this is a special modifier, saying we should ignore
-- all previous and future positive filters and remove the
-- filter (with exception of negative filters)
req_prop = {}
no_req_prop = true
end
local remove_prop = string.match(i, "^-(.*)")
if remove_prop then
-- if a property starts with "-", then we'll simply remove that
-- property from the conf_claims
conf_claims = removeEntry(conf_claims, 'prop', remove_prop)
elseif not no_req_prop then -- only if we are allowing properties to be filtered
req_prop[i] = 1
-- cheat to make #req_prop indicate populated table
req_prop[1] = 1
end
end
end
local requested_langs = getArgument(frame, conf:a('arg-languages'))
--mw.log("requested_langs="..dump(requested_langs))
-- assume all languages are allowed
local req_lang = {}
local no_req_lang = false -- we'll allow languages to be filtered for now
if requested_langs and requested_langs ~= '' then
-- the languages should be written as langcodes as used in the conf_claims
for i in string.gmatch(requested_langs,"([^ ,;:]+)") do
-- get the requested languages and be able to access them
if i == conf:a('mod-filter-all') then
-- this is a special modifier, saying we should ignore
-- all previous and future positive filters and remove the
-- filter (with exception of negative filters)
req_lang = {}
no_req_lang = true
end
-- like req_lang['en'] to verify if it was requested
local remove_lang = string.match(i, "^-(.*)")
if remove_lang then
-- if a language starts with "-", then we'll simply remove that
-- language from the conf_claims
conf_claims = removeEntry(conf_claims, 'langcode', remove_lang)
elseif not no_req_lang then -- only if we are allowing languages to be filtered
req_lang[i] = 1
-- cheat to make #req_lang indicate populated table
req_lang[1] = 1
end
end
end
local short_links = getArgument(frame, conf:a('arg-short'))
if short_links and short_links ~= '' then
short_links = true
else
short_links = false
end
local showinline = getArgument(frame, conf:a('arg-inline'))
if showinline and showinline ~= '' then
showinline = true
else
showinline = false
end
if not links_shown or links_shown == '' then
links_shown = limits['links-shown'] and limits['links-shown'] or 10
else
links_shown = tonumber(links_shown)
end
local somedataonwikidata = (short_links and false or true)
--mw.log("conf_claims="..dump(conf_claims))
--mw.log("req_prop="..dump(req_prop))
--mw.log("req_lang="..dump(req_lang))
--mw.log("short_links="..dump(short_links))
for _, props in ipairs(conf_claims) do
-- if we're called with a list of approved properties or languages, check if this one is "approved"
if (#req_prop==0 or req_prop[props.prop]) and (#req_lang==0 or req_lang[props.langcode] or string.find(props.langcode, "([pP]%d+)")) then
--mw.log("checking claim="..dump(props))
local links = {}
local checkedonwikidata = false
-- get the any local overriding value from the call
local wikivalue = getArgument(frame, props.prop)
--mw.log("wikivalue="..dump(wikivalue))
if (not wikivalue or wikivalue == "") and string.find(props.prop, "([pP]%d+)") then
-- the property is a Pnnn type, and therefore on Wikidata
links = findMainLinksOnWikidata(props, pagetitle, short_links)
if links == nil then
-- a nil-value indicated no wikidata-link
haswikidatalink = false
links = {}
else
checkedonwikidata = true
end
elseif (not wikivalue or wikivalue == "") and string.find(props.prop, "(SL%l+)") then
-- this is a sitelink-type (SLspecieswiki)
--mw.log("finding sitelinks..")
links = findSiteLinksOnWikidata(props, pagetitle, short_links)
if links == nil then
-- a nil-value indicated no wikidata-link
haswikidatalink = false
links = {}
else
checkedonwikidata = true
end
elseif (wikivalue and wikivalue ~= "") and string.find(props.prop, "(SL%l+)") then
-- this is a sitelink-type (SLspecieswiki)
links = findSiteLinksLocal(props, pagetitle, short_links, wikivalue)
elseif wikivalue and wikivalue ~= '' then
-- the property is of another annotation, and therefore a local construct
links = findMainLinksLocal(props, pagetitle, short_links, wikivalue)
end
for _,v in ipairs(links) do
-- we'll have to check langcodes again as they may have come from wikidata
if (#req_lang==0 or req_lang[v.langcode]) then
if checkedonwikidata and not hasdatafromwikidata then
-- add a general tracking category for articles with data from wikidata
hasdatafromwikidata = true
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-data-cat')
elseif not checkedonwikidata and not hasdatafromlocal then
-- add a general tracking category for articles with data from template-calls in local articles
hasdatafromlocal = true
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-local-cat')
end
if short_links and props.short and v.text and v.text ~= '' then
-- if short links were requested, and a short definition exists for this property, let's use it
if #output==0 then
output[#output+1] = v.text
else
output[#output] = output[#output] .. cmodule:getMessage(contLang:getCode(),'short-list-separator') .. v.text
end
somedataonwikidata = true
elseif not short_links and not showinline and v.text and v.text ~= '' then
-- only if short links were not requested
output[#output+1] = (#output>=1 and conf:g('msg-ul-prepend') or '') -- if this is the first link, we won't output a list-element (msg-ul-prepend)
.. (checkedonwikidata and addLinkback(v.text, props.prop) or v.text) -- if the link comes from wikidata, also output a linkback.
elseif not short_links and showinline and v.text and v.text ~= '' then
-- only if short links were not requested
output[#output+1] = v.text
end
if props.track and v.category and #v.category then
-- add category if tracking is on for this property and a category exists in the link-result.
for _,cats in ipairs( v.category ) do
category[#category+1] = cats
end
end
if links_shown>0 then
links_shown = links_shown - 1
else
break
end
end
end
if links_shown==0 then
break
end
end
end
local outtext = ""
if short_links and #output>0 then
-- if these are short links, output the whole thing with linkback to wikidata
--mw.log("somedataonwikidata="..dump(somedataonwikidata).." and output="..dump(output).." and #output="..dump(#output))
outtext = (somedataonwikidata
and addLinkback(table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')), nil)
or table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')))
elseif not short_links and not showinline and #output>0 then
outtext = table.concat(output,"\n")
elseif not short_links and showinline and #output>0 then
outtext = table.concat(output,conf:g('msg-inline-separator'))
end
if not hasdatafromwikidata then
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-data-cat')
if not hasdatafromlocal and not short_links then
outtext = cmodule:getMessage(contLang:getCode(), 'no-data-text')
end
end
if not haswikidatalink then
category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-wikilink-cat')
if not hasdatafromlocal and not short_links then
outtext = cmodule:getMessage(contLang:getCode(), 'no-wikilink')
end
end
local nocategory = getArgument(frame, conf:a('arg-no-categories'))
category = #category>0 and "\n" .. table.concat(category,"\n") or ""
--mw.log("nocategory="..dump(nocategory).." and outtext="..dump(outtext).." and category="..dump(category))
outtext = outtext .. (nocategory and '' or category)
return outtext
end
function p.getLanguageCode(frame)
local prop = getArgument(frame, conf:a('arg-properties'))
local output = getLanguageData(prop)
if output and #output>0 then
return table.concat(output, conf:a('mod-filter-separator'))
end
end
return p