الفرق بين المراجعتين ل"وحدة:Wd"
اذهب إلى التنقل
اذهب إلى البحث
Ahmad A Najar (نقاش | مساهمات) |
Ahmad A Najar (نقاش | مساهمات) |
||
| سطر 355: | سطر 355: | ||
return out | return out | ||
| + | end | ||
| + | |||
| + | local function parseWikidataURL(url) | ||
| + | local id | ||
| + | |||
| + | if url:match('^http[s]?://') then | ||
| + | id = split(url, "Q") | ||
| + | |||
| + | if id[2] then | ||
| + | return "Q" .. id[2] | ||
| + | end | ||
| + | end | ||
| + | |||
| + | return nil | ||
| + | end | ||
| + | |||
| + | function parseDate(dateStr, precision) | ||
| + | precision = precision or "d" | ||
| + | |||
| + | local i, j, index, ptr | ||
| + | local parts = {nil, nil, nil} | ||
| + | |||
| + | if dateStr == nil then | ||
| + | return parts[1], parts[2], parts[3] -- year, month, day | ||
| + | end | ||
| + | |||
| + | -- 'T' for snak values, '/' for outputs with '/Julian' attached | ||
| + | i, j = dateStr:find("[T/]") | ||
| + | |||
| + | if i then | ||
| + | dateStr = dateStr:sub(1, i-1) | ||
| + | end | ||
| + | |||
| + | local from = 1 | ||
| + | |||
| + | if dateStr:sub(1,1) == "-" then | ||
| + | -- this is a negative number, look further ahead | ||
| + | from = 2 | ||
| + | end | ||
| + | |||
| + | index = 1 | ||
| + | ptr = 1 | ||
| + | |||
| + | i, j = dateStr:find("-", from) | ||
| + | |||
| + | if i then | ||
| + | -- year | ||
| + | parts[index] = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10) -- remove '+' sign (explicitly give base 10 to prevent error) | ||
| + | |||
| + | if parts[index] == -0 then | ||
| + | parts[index] = tonumber("0") -- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string instead | ||
| + | end | ||
| + | |||
| + | if precision == "y" then | ||
| + | -- we're done | ||
| + | return parts[1], parts[2], parts[3] -- year, month, day | ||
| + | end | ||
| + | |||
| + | index = index + 1 | ||
| + | ptr = i + 1 | ||
| + | |||
| + | i, j = dateStr:find("-", ptr) | ||
| + | |||
| + | if i then | ||
| + | -- month | ||
| + | parts[index] = tonumber(dateStr:sub(ptr, i-1), 10) | ||
| + | |||
| + | if precision == "m" then | ||
| + | -- we're done | ||
| + | return parts[1], parts[2], parts[3] -- year, month, day | ||
| + | end | ||
| + | |||
| + | index = index + 1 | ||
| + | ptr = i + 1 | ||
| + | end | ||
| + | end | ||
| + | |||
| + | if dateStr:sub(ptr) ~= "" then | ||
| + | -- day if we have month, month if we have year, or year | ||
| + | parts[index] = tonumber(dateStr:sub(ptr), 10) | ||
| + | end | ||
| + | |||
| + | return parts[1], parts[2], parts[3] -- year, month, day | ||
| + | end | ||
| + | |||
| + | local function datePrecedesDate(aY, aM, aD, bY, bM, bD) | ||
| + | if aY == nil or bY == nil then | ||
| + | return nil | ||
| + | end | ||
| + | aM = aM or 1 | ||
| + | aD = aD or 1 | ||
| + | bM = bM or 1 | ||
| + | bD = bD or 1 | ||
| + | |||
| + | if aY < bY then | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | if aY > bY then | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | if aM < bM then | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | if aM > bM then | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | if aD < bD then | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | return false | ||
| + | end | ||
| + | |||
| + | local function getHookName(param, index) | ||
| + | if hookNames[param] then | ||
| + | return hookNames[param][index] | ||
| + | elseif param:len() > 2 then | ||
| + | return hookNames[param:sub(1, 2).."\\d"][index] | ||
| + | else | ||
| + | return nil | ||
| + | end | ||
| + | end | ||
| + | |||
| + | local function alwaysTrue() | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | -- The following function parses a format string. | ||
| + | -- | ||
| + | -- The example below shows how a parsed string is structured in memory. | ||
| + | -- Variables other than 'str' and 'child' are left out for clarity's sake. | ||
| + | -- | ||
| + | -- Example: | ||
| + | -- "A %p B [%s[%q1]] C [%r] D" | ||
| + | -- | ||
| + | -- Structure: | ||
| + | -- [ | ||
| + | -- { | ||
| + | -- str = "A " | ||
| + | -- }, | ||
| + | -- { | ||
| + | -- str = "%p" | ||
| + | -- }, | ||
| + | -- { | ||
| + | -- str = " B ", | ||
| + | -- child = | ||
| + | -- [ | ||
| + | -- { | ||
| + | -- str = "%s", | ||
| + | -- child = | ||
| + | -- [ | ||
| + | -- { | ||
| + | -- str = "%q1" | ||
| + | -- } | ||
| + | -- ] | ||
| + | -- } | ||
| + | -- ] | ||
| + | -- }, | ||
| + | -- { | ||
| + | -- str = " C ", | ||
| + | -- child = | ||
| + | -- [ | ||
| + | -- { | ||
| + | -- str = "%r" | ||
| + | -- } | ||
| + | -- ] | ||
| + | -- }, | ||
| + | -- { | ||
| + | -- str = " D" | ||
| + | -- } | ||
| + | -- ] | ||
| + | -- | ||
| + | local function parseFormat(str) | ||
| + | local chr, esc, param, root, cur, prev, new | ||
| + | local params = {} | ||
| + | |||
| + | local function newObject(array) | ||
| + | local obj = {} -- new object | ||
| + | obj.str = "" | ||
| + | |||
| + | array[#array + 1] = obj -- array{object} | ||
| + | obj.parent = array | ||
| + | |||
| + | return obj | ||
| + | end | ||
| + | |||
| + | local function endParam() | ||
| + | if param > 0 then | ||
| + | if cur.str ~= "" then | ||
| + | cur.str = "%"..cur.str | ||
| + | cur.param = true | ||
| + | params[cur.str] = true | ||
| + | cur.parent.req[cur.str] = true | ||
| + | prev = cur | ||
| + | cur = newObject(cur.parent) | ||
| + | end | ||
| + | param = 0 | ||
| + | end | ||
| + | end | ||
| + | |||
| + | root = {} -- array | ||
| + | root.req = {} | ||
| + | cur = newObject(root) | ||
| + | prev = nil | ||
| + | |||
| + | esc = false | ||
| + | param = 0 | ||
| + | |||
| + | for i = 1, #str do | ||
| + | chr = str:sub(i,i) | ||
| + | |||
| + | if not esc then | ||
| + | if chr == '\\' then | ||
| + | endParam() | ||
| + | esc = true | ||
| + | elseif chr == '%' then | ||
| + | endParam() | ||
| + | if cur.str ~= "" then | ||
| + | cur = newObject(cur.parent) | ||
| + | end | ||
| + | param = 2 | ||
| + | elseif chr == '[' then | ||
| + | endParam() | ||
| + | if prev and cur.str == "" then | ||
| + | table.remove(cur.parent) | ||
| + | cur = prev | ||
| + | end | ||
| + | cur.child = {} -- new array | ||
| + | cur.child.req = {} | ||
| + | cur.child.parent = cur | ||
| + | cur = newObject(cur.child) | ||
| + | elseif chr == ']' then | ||
| + | endParam() | ||
| + | if cur.parent.parent then | ||
| + | new = newObject(cur.parent.parent.parent) | ||
| + | if cur.str == "" then | ||
| + | table.remove(cur.parent) | ||
| + | end | ||
| + | cur = new | ||
| + | end | ||
| + | else | ||
| + | if param > 1 then | ||
| + | param = param - 1 | ||
| + | elseif param == 1 then | ||
| + | if not chr:match('%d') then | ||
| + | endParam() | ||
| + | end | ||
| + | end | ||
| + | |||
| + | cur.str = cur.str .. replaceSpecialChar(chr) | ||
| + | end | ||
| + | else | ||
| + | cur.str = cur.str .. chr | ||
| + | esc = false | ||
| + | end | ||
| + | |||
| + | prev = nil | ||
| + | end | ||
| + | |||
| + | endParam() | ||
| + | |||
| + | -- make sure that at least one required parameter has been defined | ||
| + | if not next(root.req) then | ||
| + | throwError("missing-required-parameter") | ||
| + | end | ||
| + | |||
| + | -- make sure that the separator parameter "%s" is not amongst the required parameters | ||
| + | if root.req[parameters.separator] then | ||
| + | throwError("extra-required-parameter", parameters.separator) | ||
| + | end | ||
| + | |||
| + | return root, params | ||
| + | end | ||
| + | |||
| + | local function sortOnRank(claims) | ||
| + | local rankPos | ||
| + | local ranks = {{}, {}, {}, {}} -- preferred, normal, deprecated, (default) | ||
| + | local sorted = {} | ||
| + | |||
| + | for _, v in ipairs(claims) do | ||
| + | rankPos = rankTable[v.rank] or 4 | ||
| + | ranks[rankPos][#ranks[rankPos] + 1] = v | ||
| + | end | ||
| + | |||
| + | sorted = ranks[1] | ||
| + | sorted = mergeArrays(sorted, ranks[2]) | ||
| + | sorted = mergeArrays(sorted, ranks[3]) | ||
| + | |||
| + | return sorted | ||
| + | end | ||
| + | |||
| + | -- if id == nil then item connected to current page is used | ||
| + | function Config:getLabel(id, raw, link, short) | ||
| + | local label = nil | ||
| + | local title = nil | ||
| + | local prefix= "" | ||
| + | |||
| + | if not id then | ||
| + | id = mw.wikibase.getEntityIdForCurrentPage() | ||
| + | |||
| + | if not id then | ||
| + | return "" | ||
| + | end | ||
| + | end | ||
| + | |||
| + | id = id:upper() -- just to be sure | ||
| + | |||
| + | if raw then | ||
| + | -- check if given id actually exists | ||
| + | if mw.wikibase.isValidEntityId(id) and mw.wikibase.entityExists(id) then | ||
| + | label = id | ||
| + | |||
| + | if id:sub(1,1) == "P" then | ||
| + | prefix = "Property:" | ||
| + | end | ||
| + | end | ||
| + | |||
| + | prefix = "d:" .. prefix | ||
| + | |||
| + | title = label -- may be nil | ||
| + | else | ||
| + | -- try short name first if requested | ||
| + | if short then | ||
| + | label = p._property{aliasesP.shortName, [p.args.eid] = id} -- get short name | ||
| + | |||
| + | if label == "" then | ||
| + | label = nil | ||
| + | end | ||
| + | end | ||
| + | |||
| + | -- get label | ||
| + | if not label then | ||
| + | label = mw.wikibase.getLabelByLang(id, self.langCode) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | if not label then | ||
| + | label = "" | ||
| + | elseif link then | ||
| + | -- build a link if requested | ||
| + | if not title then | ||
| + | if id:sub(1,1) == "Q" then | ||
| + | title = mw.wikibase.getSitelink(id) | ||
| + | elseif id:sub(1,1) == "P" then | ||
| + | -- properties have no sitelink, link to Wikidata instead | ||
| + | title = id | ||
| + | prefix = "d:Property:" | ||
| + | end | ||
| + | end | ||
| + | |||
| + | if title then | ||
| + | label = buildWikilink(prefix .. title, label) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | return label | ||
| + | end | ||
| + | |||
| + | function Config:getEditIcon() | ||
| + | local value = "" | ||
| + | local prefix = "" | ||
| + | local front = " " | ||
| + | local back = "" | ||
| + | |||
| + | if self.entityID:sub(1,1) == "P" then | ||
| + | prefix = "Property:" | ||
| + | end | ||
| + | |||
| + | if self.editAtEnd then | ||
| + | front = '<span style="float:' | ||
| + | |||
| + | if self.langObj:isRTL() then | ||
| + | front = front .. 'left' | ||
| + | else | ||
| + | front = front .. 'right' | ||
| + | end | ||
| + | |||
| + | front = front .. '">' | ||
| + | back = '</span>' | ||
| + | end | ||
| + | |||
| + | value = "[[File:OOjs UI icon edit-ltr-progressive.svg|frameless|text-top|10px|alt=" .. i18n['info']['edit-on-wikidata'] .. "|link=https://www.wikidata.org/wiki/" .. prefix .. self.entityID .. "?uselang=" .. self.langCode | ||
| + | |||
| + | if self.propertyID then | ||
| + | value = value .. "#" .. self.propertyID | ||
| + | elseif self.inSitelinks then | ||
| + | value = value .. "#sitelinks-wikipedia" | ||
| + | end | ||
| + | |||
| + | value = value .. "|" .. i18n['info']['edit-on-wikidata'] .. "]]" | ||
| + | |||
| + | return front .. value .. back | ||
| + | end | ||
| + | |||
| + | -- used to create the final output string when it's all done, so that for references the | ||
| + | -- function extensionTag("ref", ...) is only called when they really ended up in the final output | ||
| + | function Config:concatValues(valuesArray) | ||
| + | local outString = "" | ||
| + | local j, skip | ||
| + | |||
| + | for i = 1, #valuesArray do | ||
| + | -- check if this is a reference | ||
| + | if valuesArray[i].refHash then | ||
| + | j = i - 1 | ||
| + | skip = false | ||
| + | |||
| + | -- skip this reference if it is part of a continuous row of references that already contains the exact same reference | ||
| + | while valuesArray[j] and valuesArray[j].refHash do | ||
| + | if valuesArray[i].refHash == valuesArray[j].refHash then | ||
| + | skip = true | ||
| + | break | ||
| + | end | ||
| + | j = j - 1 | ||
| + | end | ||
| + | |||
| + | if not skip then | ||
| + | -- add <ref> tag with the reference's hash as its name (to deduplicate references) | ||
| + | outString = outString .. mw.getCurrentFrame():extensionTag("ref", valuesArray[i][1], {name = valuesArray[i].refHash}) | ||
| + | end | ||
| + | else | ||
| + | outString = outString .. valuesArray[i][1] | ||
| + | end | ||
| + | end | ||
| + | |||
| + | return outString | ||
end | end | ||
return p | return p | ||
مراجعة 05:16، 7 مايو 2021
يمكن إنشاء صفحة توثيق الوحدة في وحدة:Wd/شرح
-- Original module located at [[:en:Module:Wd]] and [[:en:Module:Wd/i18n]].
local p = {}
local arg = ...
local i18n
local function loadI18n(aliasesP, frame)
local title
if frame then
-- current module invoked by page/template, get its title from frame
title = frame:getTitle()
else
-- current module included by other module, get its title from ...
title = arg
end
if not i18n then
i18n = require(title .. "/i18n").init(aliasesP)
end
end
p.claimCommands = {
property = "property",
properties = "properties",
qualifier = "qualifier",
qualifiers = "qualifiers",
reference = "reference",
references = "references"
}
p.generalCommands = {
label = "label",
title = "title",
description = "description",
alias = "alias",
aliases = "aliases",
badge = "badge",
badges = "badges"
}
p.flags = {
linked = "linked",
short = "short",
raw = "raw",
multilanguage = "multilanguage",
unit = "unit",
-------------
preferred = "preferred",
normal = "normal",
deprecated = "deprecated",
best = "best",
future = "future",
current = "current",
former = "former",
edit = "edit",
editAtEnd = "edit@end",
mdy = "mdy",
single = "single",
sourced = "sourced"
}
p.args = {
eid = "eid",
page = "page",
date = "date"
}
local aliasesP = {
coord = "P625",
-----------------------
image = "P18",
author = "P50",
publisher = "P123",
importedFrom = "P143",
statedIn = "P248",
pages = "P304",
language = "P407",
hasPart = "P527",
publicationDate = "P577",
startTime = "P580",
endTime = "P582",
chapter = "P792",
retrieved = "P813",
referenceURL = "P854",
sectionVerseOrParagraph = "P958",
archiveURL = "P1065",
title = "P1476",
formatterURL = "P1630",
quote = "P1683",
shortName = "P1813",
definingFormula = "P2534",
archiveDate = "P2960",
inferredFrom = "P3452",
typeOfReference = "P3865",
column = "P3903"
}
local aliasesQ = {
percentage = "Q11229",
prolepticJulianCalendar = "Q1985786",
citeWeb = "Q5637226",
citeQ = "Q22321052"
}
local parameters = {
property = "%p",
qualifier = "%q",
reference = "%r",
alias = "%a",
badge = "%b",
separator = "%s",
general = "%x"
}
local formats = {
property = "%p[%s][%r]",
qualifier = "%q[%s][%r]",
reference = "%r",
propertyWithQualifier = "%p[ <span style=\"font-size:85\\%\">(%q)</span>][%s][%r]",
alias = "%a[%s]",
badge = "%b[%s]"
}
local hookNames = { -- {level_1, level_2}
[parameters.property] = {"getProperty"},
[parameters.reference] = {"getReferences", "getReference"},
[parameters.qualifier] = {"getAllQualifiers"},
[parameters.qualifier.."\\d"] = {"getQualifiers", "getQualifier"},
[parameters.alias] = {"getAlias"},
[parameters.badge] = {"getBadge"}
}
-- default value objects, should NOT be mutated but instead copied
local defaultSeparators = {
["sep"] = {" "},
["sep%s"] = {","},
["sep%q"] = {"; "},
["sep%q\\d"] = {", "},
["sep%r"] = nil, -- none
["punc"] = nil -- none
}
local rankTable = {
["preferred"] = 1,
["normal"] = 2,
["deprecated"] = 3
}
local Config = {}
-- allows for recursive calls
function Config:new()
local cfg = {}
setmetatable(cfg, self)
self.__index = self
cfg.separators = {
-- single value objects wrapped in arrays so that we can pass by reference
["sep"] = {copyTable(defaultSeparators["sep"])},
["sep%s"] = {copyTable(defaultSeparators["sep%s"])},
["sep%q"] = {copyTable(defaultSeparators["sep%q"])},
["sep%r"] = {copyTable(defaultSeparators["sep%r"])},
["punc"] = {copyTable(defaultSeparators["punc"])}
}
cfg.entity = nil
cfg.entityID = nil
cfg.propertyID = nil
cfg.propertyValue = nil
cfg.qualifierIDs = {}
cfg.qualifierIDsAndValues = {}
cfg.bestRank = true
cfg.ranks = {true, true, false} -- preferred = true, normal = true, deprecated = false
cfg.foundRank = #cfg.ranks
cfg.flagBest = false
cfg.flagRank = false
cfg.periods = {true, true, true} -- future = true, current = true, former = true
cfg.flagPeriod = false
cfg.atDate = {parseDate(os.date('!%Y-%m-%d'))} -- today as {year, month, day}
cfg.mdyDate = false
cfg.singleClaim = false
cfg.sourcedOnly = false
cfg.editable = false
cfg.editAtEnd = false
cfg.inSitelinks = false
cfg.langCode = mw.language.getContentLanguage().code
cfg.langName = mw.language.fetchLanguageName(cfg.langCode, cfg.langCode)
cfg.langObj = mw.language.new(cfg.langCode)
cfg.siteID = mw.wikibase.getGlobalSiteId()
cfg.states = {}
cfg.states.qualifiersCount = 0
cfg.curState = nil
cfg.prefetchedRefs = nil
return cfg
end
local State = {}
function State:new(cfg, type)
local stt = {}
setmetatable(stt, self)
self.__index = self
stt.conf = cfg
stt.type = type
stt.results = {}
stt.parsedFormat = {}
stt.separator = {}
stt.movSeparator = {}
stt.puncMark = {}
stt.linked = false
stt.rawValue = false
stt.shortName = false
stt.anyLanguage = false
stt.unitOnly = false
stt.singleValue = false
return stt
end
local function replaceAlias(id)
if aliasesP[id] then
id = aliasesP[id]
end
return id
end
local function errorText(code, param)
local text = i18n["errors"][code]
if param then text = mw.ustring.gsub(text, "$1", param) end
return text
end
local function throwError(errorMessage, param)
error(errorText(errorMessage, param))
end
local function replaceDecimalMark(num)
return mw.ustring.gsub(num, "[.]", i18n['numeric']['decimal-mark'], 1)
end
local function padZeros(num, numDigits)
local numZeros
local negative = false
if num < 0 then
negative = true
num = num * -1
end
num = tostring(num)
numZeros = numDigits - num:len()
for _ = 1, numZeros do
num = "0"..num
end
if negative then
num = "-"..num
end
return num
end
local function replaceSpecialChar(chr)
if chr == '_' then
-- replace underscores with spaces
return ' '
else
return chr
end
end
local function replaceSpecialChars(str)
local chr
local esc = false
local strOut = ""
for i = 1, #str do
chr = str:sub(i,i)
if not esc then
if chr == '\\' then
esc = true
else
strOut = strOut .. replaceSpecialChar(chr)
end
else
strOut = strOut .. chr
esc = false
end
end
return strOut
end
local function buildWikilink(target, label)
if not label or target == label then
return "[[" .. target .. "]]"
else
return "[[" .. target .. "|" .. label .. "]]"
end
end
-- used to make frame.args mutable, to replace #frame.args (which is always 0)
-- with the actual amount and to simply copy tables
function copyTable(tIn)
if not tIn then
return nil
end
local tOut = {}
for i, v in pairs(tIn) do
tOut[i] = v
end
return tOut
end
-- used to merge output arrays together;
-- note that it currently mutates the first input array
local function mergeArrays(a1, a2)
for i = 1, #a2 do
a1[#a1 + 1] = a2[i]
end
return a1
end
local function split(str, del)
local out = {}
local i, j = str:find(del)
if i and j then
out[1] = str:sub(1, i - 1)
out[2] = str:sub(j + 1)
else
out[1] = str
end
return out
end
local function parseWikidataURL(url)
local id
if url:match('^http[s]?://') then
id = split(url, "Q")
if id[2] then
return "Q" .. id[2]
end
end
return nil
end
function parseDate(dateStr, precision)
precision = precision or "d"
local i, j, index, ptr
local parts = {nil, nil, nil}
if dateStr == nil then
return parts[1], parts[2], parts[3] -- year, month, day
end
-- 'T' for snak values, '/' for outputs with '/Julian' attached
i, j = dateStr:find("[T/]")
if i then
dateStr = dateStr:sub(1, i-1)
end
local from = 1
if dateStr:sub(1,1) == "-" then
-- this is a negative number, look further ahead
from = 2
end
index = 1
ptr = 1
i, j = dateStr:find("-", from)
if i then
-- year
parts[index] = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10) -- remove '+' sign (explicitly give base 10 to prevent error)
if parts[index] == -0 then
parts[index] = tonumber("0") -- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string instead
end
if precision == "y" then
-- we're done
return parts[1], parts[2], parts[3] -- year, month, day
end
index = index + 1
ptr = i + 1
i, j = dateStr:find("-", ptr)
if i then
-- month
parts[index] = tonumber(dateStr:sub(ptr, i-1), 10)
if precision == "m" then
-- we're done
return parts[1], parts[2], parts[3] -- year, month, day
end
index = index + 1
ptr = i + 1
end
end
if dateStr:sub(ptr) ~= "" then
-- day if we have month, month if we have year, or year
parts[index] = tonumber(dateStr:sub(ptr), 10)
end
return parts[1], parts[2], parts[3] -- year, month, day
end
local function datePrecedesDate(aY, aM, aD, bY, bM, bD)
if aY == nil or bY == nil then
return nil
end
aM = aM or 1
aD = aD or 1
bM = bM or 1
bD = bD or 1
if aY < bY then
return true
end
if aY > bY then
return false
end
if aM < bM then
return true
end
if aM > bM then
return false
end
if aD < bD then
return true
end
return false
end
local function getHookName(param, index)
if hookNames[param] then
return hookNames[param][index]
elseif param:len() > 2 then
return hookNames[param:sub(1, 2).."\\d"][index]
else
return nil
end
end
local function alwaysTrue()
return true
end
-- The following function parses a format string.
--
-- The example below shows how a parsed string is structured in memory.
-- Variables other than 'str' and 'child' are left out for clarity's sake.
--
-- Example:
-- "A %p B [%s[%q1]] C [%r] D"
--
-- Structure:
-- [
-- {
-- str = "A "
-- },
-- {
-- str = "%p"
-- },
-- {
-- str = " B ",
-- child =
-- [
-- {
-- str = "%s",
-- child =
-- [
-- {
-- str = "%q1"
-- }
-- ]
-- }
-- ]
-- },
-- {
-- str = " C ",
-- child =
-- [
-- {
-- str = "%r"
-- }
-- ]
-- },
-- {
-- str = " D"
-- }
-- ]
--
local function parseFormat(str)
local chr, esc, param, root, cur, prev, new
local params = {}
local function newObject(array)
local obj = {} -- new object
obj.str = ""
array[#array + 1] = obj -- array{object}
obj.parent = array
return obj
end
local function endParam()
if param > 0 then
if cur.str ~= "" then
cur.str = "%"..cur.str
cur.param = true
params[cur.str] = true
cur.parent.req[cur.str] = true
prev = cur
cur = newObject(cur.parent)
end
param = 0
end
end
root = {} -- array
root.req = {}
cur = newObject(root)
prev = nil
esc = false
param = 0
for i = 1, #str do
chr = str:sub(i,i)
if not esc then
if chr == '\\' then
endParam()
esc = true
elseif chr == '%' then
endParam()
if cur.str ~= "" then
cur = newObject(cur.parent)
end
param = 2
elseif chr == '[' then
endParam()
if prev and cur.str == "" then
table.remove(cur.parent)
cur = prev
end
cur.child = {} -- new array
cur.child.req = {}
cur.child.parent = cur
cur = newObject(cur.child)
elseif chr == ']' then
endParam()
if cur.parent.parent then
new = newObject(cur.parent.parent.parent)
if cur.str == "" then
table.remove(cur.parent)
end
cur = new
end
else
if param > 1 then
param = param - 1
elseif param == 1 then
if not chr:match('%d') then
endParam()
end
end
cur.str = cur.str .. replaceSpecialChar(chr)
end
else
cur.str = cur.str .. chr
esc = false
end
prev = nil
end
endParam()
-- make sure that at least one required parameter has been defined
if not next(root.req) then
throwError("missing-required-parameter")
end
-- make sure that the separator parameter "%s" is not amongst the required parameters
if root.req[parameters.separator] then
throwError("extra-required-parameter", parameters.separator)
end
return root, params
end
local function sortOnRank(claims)
local rankPos
local ranks = {{}, {}, {}, {}} -- preferred, normal, deprecated, (default)
local sorted = {}
for _, v in ipairs(claims) do
rankPos = rankTable[v.rank] or 4
ranks[rankPos][#ranks[rankPos] + 1] = v
end
sorted = ranks[1]
sorted = mergeArrays(sorted, ranks[2])
sorted = mergeArrays(sorted, ranks[3])
return sorted
end
-- if id == nil then item connected to current page is used
function Config:getLabel(id, raw, link, short)
local label = nil
local title = nil
local prefix= ""
if not id then
id = mw.wikibase.getEntityIdForCurrentPage()
if not id then
return ""
end
end
id = id:upper() -- just to be sure
if raw then
-- check if given id actually exists
if mw.wikibase.isValidEntityId(id) and mw.wikibase.entityExists(id) then
label = id
if id:sub(1,1) == "P" then
prefix = "Property:"
end
end
prefix = "d:" .. prefix
title = label -- may be nil
else
-- try short name first if requested
if short then
label = p._property{aliasesP.shortName, [p.args.eid] = id} -- get short name
if label == "" then
label = nil
end
end
-- get label
if not label then
label = mw.wikibase.getLabelByLang(id, self.langCode)
end
end
if not label then
label = ""
elseif link then
-- build a link if requested
if not title then
if id:sub(1,1) == "Q" then
title = mw.wikibase.getSitelink(id)
elseif id:sub(1,1) == "P" then
-- properties have no sitelink, link to Wikidata instead
title = id
prefix = "d:Property:"
end
end
if title then
label = buildWikilink(prefix .. title, label)
end
end
return label
end
function Config:getEditIcon()
local value = ""
local prefix = ""
local front = " "
local back = ""
if self.entityID:sub(1,1) == "P" then
prefix = "Property:"
end
if self.editAtEnd then
front = '<span style="float:'
if self.langObj:isRTL() then
front = front .. 'left'
else
front = front .. 'right'
end
front = front .. '">'
back = '</span>'
end
value = "[[File:OOjs UI icon edit-ltr-progressive.svg|frameless|text-top|10px|alt=" .. i18n['info']['edit-on-wikidata'] .. "|link=https://www.wikidata.org/wiki/" .. prefix .. self.entityID .. "?uselang=" .. self.langCode
if self.propertyID then
value = value .. "#" .. self.propertyID
elseif self.inSitelinks then
value = value .. "#sitelinks-wikipedia"
end
value = value .. "|" .. i18n['info']['edit-on-wikidata'] .. "]]"
return front .. value .. back
end
-- used to create the final output string when it's all done, so that for references the
-- function extensionTag("ref", ...) is only called when they really ended up in the final output
function Config:concatValues(valuesArray)
local outString = ""
local j, skip
for i = 1, #valuesArray do
-- check if this is a reference
if valuesArray[i].refHash then
j = i - 1
skip = false
-- skip this reference if it is part of a continuous row of references that already contains the exact same reference
while valuesArray[j] and valuesArray[j].refHash do
if valuesArray[i].refHash == valuesArray[j].refHash then
skip = true
break
end
j = j - 1
end
if not skip then
-- add <ref> tag with the reference's hash as its name (to deduplicate references)
outString = outString .. mw.getCurrentFrame():extensionTag("ref", valuesArray[i][1], {name = valuesArray[i].refHash})
end
else
outString = outString .. valuesArray[i][1]
end
end
return outString
end
return p