Editing
Module:PBD
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
local p = {} local arg = ... local i18n local function loadI18n(aliasesP, frame) local title if frame then title = frame:getTitle() else 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 = "P48", ----------------------- image = "P470", author = "P215", publisher = "P218", importedFrom = "P36", statedIn = "P15", pages = "P219", language = "P44", hasPart = "P173", publicationDate = "P19", startTime = "P34", endTime = "P41", chapter = "P221", retrieved = "P17", referenceURL = "P35", sectionVerseOrParagraph = "P223", archiveURL = "P208", title = "P225", formatterURL = "P167", quote = "P226", shortName = "P203", definingFormula = "P232", archiveDate = "P227", inferredFrom = "P71", typeOfReference = "P228", column = "P230" } local aliasesQ = { percentage = "Q224", prolepticJulianCalendar = "Q219", citeWeb = "Q225", citeQ = "Q227" } 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 = { [parameters.property] = {"getProperty"}, [parameters.reference] = {"getReferences", "getReference"}, [parameters.qualifier] = {"getAllQualifiers"}, [parameters.qualifier.."\\d"] = {"getQualifiers", "getQualifier"}, [parameters.alias] = {"getAlias"}, [parameters.badge] = {"getBadge"} } local defaultSeparators = { ["sep"] = {" "}, ["sep%s"] = {","}, ["sep%q"] = {"; "}, ["sep%q\\d"] = {", "}, ["sep%r"] = nil, ["punc"] = nil } local rankTable = { ["preferred"] = 1, ["normal"] = 2, ["deprecated"] = 3 } local Config = {} function Config:new() local cfg = {} setmetatable(cfg, self) self.__index = self cfg.separators = { ["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} cfg.foundRank = #cfg.ranks cfg.flagBest = false cfg.flagRank = false cfg.periods = {true, true, true} cfg.flagPeriod = false cfg.atDate = {parseDate(os.date('!%Y-%m-%d'))} 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 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 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 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 parsePornbasedataURL(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] end i, j = dateStr:find("[T/]") if i then dateStr = dateStr:sub(1, i-1) end local from = 1 if dateStr:sub(1,1) == "-" then from = 2 end index = 1 ptr = 1 i, j = dateStr:find("-", from) if i then parts[index] = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10) if parts[index] == -0 then parts[index] = tonumber("0") end if precision == "y" then return parts[1], parts[2], parts[3] end index = index + 1 ptr = i + 1 i, j = dateStr:find("-", ptr) if i then parts[index] = tonumber(dateStr:sub(ptr, i-1), 10) if precision == "m" then return parts[1], parts[2], parts[3] end index = index + 1 ptr = i + 1 end end if dateStr:sub(ptr) ~= "" then parts[index] = tonumber(dateStr:sub(ptr), 10) end return parts[1], parts[2], parts[3] 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 local function parseFormat(str) local chr, esc, param, root, cur, prev, new local params = {} local function newObject(array) local obj = {} obj.str = "" array[#array + 1] = obj 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() if not next(root.req) then throwError("missing-required-parameter") end 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 = {{}, {}, {}, {}} 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 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() if raw then 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 = "pbd:" .. prefix title = label else 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 if not title then if id:sub(1,1) == "Q" then title = mw.wikibase.getSitelink(id) if not title then title = id prefix = "pbd:Special:EntityPage/" end elseif id:sub(1,1) == "P" then title = id prefix = "pbd:Special:EntityPage/" end end label = mw.text.nowiki(label) if title then label = buildWikilink(prefix .. title, mw.text.nowiki(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-pornbasedata'] .. "|link=https://pornbasedata.com/wiki/" .. prefix .. self.entityID .. "?uselang=" .. self.langCode if self.propertyID then value = value .. "#" .. self.propertyID elseif self.inSitelinks then value = value .. "#sitelinks-pbc" end value = value .. "|" .. i18n['info']['edit-on-pornbasedata'] .. "]]" return front .. value .. back end function Config:concatValues(valuesArray) local outString = "" local j, skip for i = 1, #valuesArray do if valuesArray[i].refHash then j = i - 1 skip = false 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 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 function Config:convertUnit(unit, raw, link, short, unitOnly) local space = " " local label = "" local itemID if unit == "" or unit == "1" then return nil end if unitOnly then space = "" end itemID = parsePornbasedataURL(unit) if itemID then if itemID == aliasesQ.percentage then return "%" else label = self:getLabel(itemID, raw, link, short) if label ~= "" then return space .. label end end end return "" end function State:getValue(snak) return self.conf:getValue(snak, self.rawValue, self.linked, self.shortName, true, self.unitOnly, false, self.type:sub(1,2)) end function Config:getValue(snak, raw, link, short, anyLang, unitOnly, noSpecial, type) if snak.snaktype == 'value' then local datatype = snak.datavalue.type local subtype = snak.datatype local datavalue = snak.datavalue.value if datatype == 'string' then if subtype == 'url' and link then if raw then return "[" .. datavalue .. "]" else return "[" .. datavalue .. " " .. datavalue .. "]" end elseif subtype == 'commonsMedia' then if link then return buildWikilink("pbc:File:" .. datavalue, datavalue) elseif not raw then return "[[File:" .. datavalue .. "]]" else return datavalue end elseif subtype == 'geo-shape' and link then return buildWikilink("pbc:" .. datavalue, datavalue) elseif subtype == 'math' and not raw then local attribute = nil if (type == parameters.property or (type == parameters.qualifier and self.propertyID == aliasesP.hasPart)) and snak.property == aliasesP.definingFormula then attribute = {qid = self.entityID} end return mw.getCurrentFrame():extensionTag("math", datavalue, attribute) elseif subtype == 'external-id' and link then local url = p._property{aliasesP.formatterURL, [p.args.eid] = snak.property} if url ~= "" then url = mw.ustring.gsub(url, "$1", datavalue) return "[" .. url .. " " .. datavalue .. "]" else return datavalue end else return datavalue end elseif datatype == 'monolingualtext' then if anyLang or datavalue['language'] == self.langCode then return datavalue['text'] else return nil end elseif datatype == 'quantity' then local value = "" local unit if not unitOnly then value = mw.ustring.gsub(datavalue['amount'], "^\+(.+)$", "%1") if raw then return value end value = replaceDecimalMark(value) value = i18n.addDelimiters(value) end unit = self:convertUnit(datavalue['unit'], raw, link, short, unitOnly) if unit then value = value .. unit end return value elseif datatype == 'time' then local y, m, d, p, yDiv, yRound, yFull, value, calendarID, dateStr local yFactor = 1 local sign = 1 local prefix = "" local suffix = "" local mayAddCalendar = false local calendar = "" local precision = datavalue['precision'] if precision == 11 then p = "d" elseif precision == 10 then p = "m" else p = "y" yFactor = 10^(9-precision) end y, m, d = parseDate(datavalue['time'], p) if y < 0 then sign = -1 y = y * sign end if precision <= 8 then yDiv = y / yFactor if precision >= 6 then mayAddCalendar = true if precision <= 7 then yRound = math.ceil(yDiv) if not raw then if precision == 6 then suffix = i18n['datetime']['suffixes']['millennium'] else suffix = i18n['datetime']['suffixes']['century'] end suffix = i18n.getOrdinalSuffix(yRound) .. suffix else yRound = (yRound - 1) * yFactor + 1 end else yRound = math.floor(yDiv) * yFactor if not raw then prefix = i18n['datetime']['prefixes']['decade-period'] suffix = i18n['datetime']['suffixes']['decade-period'] end end if raw and sign < 0 then yRound = yRound + yFactor - 1 end else local yReFactor, yReDiv, yReRound yRound = math.floor(yDiv + 0.5) if yRound == 0 then if precision <= 2 and y ~= 0 then yReFactor = 1e6 yReDiv = y / yReFactor yReRound = math.floor(yReDiv + 0.5) if yReDiv == yReRound then precision = 3 yFactor = yReFactor yRound = yReRound end end if yRound == 0 then precision = 5 yFactor = 1 yRound = y mayAddCalendar = true end end if precision >= 1 and y ~= 0 then yFull = yRound * yFactor yReFactor = 1e9 yReDiv = yFull / yReFactor yReRound = math.floor(yReDiv + 0.5) if yReDiv == yReRound then precision = 0 yFactor = yReFactor yRound = yReRound else yReFactor = 1e6 yReDiv = yFull / yReFactor yReRound = math.floor(yReDiv + 0.5) if yReDiv == yReRound then precision = 3 yFactor = yReFactor yRound = yReRound end end end if not raw then if precision == 3 then suffix = i18n['datetime']['suffixes']['million-years'] elseif precision == 0 then suffix = i18n['datetime']['suffixes']['billion-years'] else yRound = yRound * yFactor if yRound == 1 then suffix = i18n['datetime']['suffixes']['year'] else suffix = i18n['datetime']['suffixes']['years'] end end else yRound = yRound * yFactor end end else yRound = y mayAddCalendar = true end if mayAddCalendar then calendarID = parsePornbasedataURL(datavalue['calendarmodel']) if calendarID and calendarID == aliasesQ.prolepticJulianCalendar then if not raw then if link then calendar = " ("..buildWikilink(i18n['datetime']['julian-calendar'], i18n['datetime']['julian'])..")" else calendar = " ("..i18n['datetime']['julian']..")" end else calendar = "/"..i18n['datetime']['julian'] end end end if not raw then local ce = nil if sign < 0 then ce = i18n['datetime']['BCE'] elseif precision <= 5 then ce = i18n['datetime']['CE'] end if ce then if link then ce = buildWikilink(i18n['datetime']['common-era'], ce) end suffix = suffix .. " " .. ce end value = tostring(yRound) if m then dateStr = self.langObj:formatDate("F", "1-"..m.."-1") if d then if self.mdyDate then dateStr = dateStr .. " " .. d .. "," else dateStr = d .. " " .. dateStr end end value = dateStr .. " " .. value end value = prefix .. value .. suffix .. calendar else value = padZeros(yRound * sign, 4) if m then value = value .. "-" .. padZeros(m, 2) if d then value = value .. "-" .. padZeros(d, 2) end end value = value .. calendar end return value elseif datatype == 'wikibase-entityid' then local label local itemID = datavalue['numeric-id'] if subtype == 'wikibase-item' then itemID = "Q" .. itemID elseif subtype == 'wikibase-property' then itemID = "P" .. itemID else return '<strong class="error">' .. errorText('unknown-data-type', subtype) .. '</strong>' end label = self:getLabel(itemID, raw, link, short) if label == "" then label = nil end return label else return '<strong class="error">' .. errorText('unknown-data-type', datatype) .. '</strong>' end elseif snak.snaktype == 'somevalue' and not noSpecial then if raw then return " " else return i18n['values']['unknown'] end elseif snak.snaktype == 'novalue' and not noSpecial then if raw then return "" else return i18n['values']['none'] end else return nil end end function Config:getSingleRawQualifier(claim, qualifierID) local qualifiers if claim.qualifiers then qualifiers = claim.qualifiers[qualifierID] end if qualifiers and qualifiers[1] then return self:getValue(qualifiers[1], true) else return nil end end function Config:snakEqualsValue(snak, value) local snakValue = self:getValue(snak, true) if snakValue and snak.snaktype == 'value' and snak.datavalue.type == 'wikibase-entityid' then value = value:upper() end return snakValue == value end function Config:setRank(rank) local rankPos if rank == p.flags.best then self.bestRank = true self.flagBest = true return end if rank:sub(1,9) == p.flags.preferred then rankPos = 1 elseif rank:sub(1,6) == p.flags.normal then rankPos = 2 elseif rank:sub(1,10) == p.flags.deprecated then rankPos = 3 else return end if not self.flagRank then self.ranks = {false, false, false} self.bestRank = self.flagBest self.flagRank = true end if rank:sub(-1) == "+" then for i = rankPos, 1, -1 do self.ranks[i] = true end elseif rank:sub(-1) == "-" then for i = rankPos, #self.ranks do self.ranks[i] = true end else self.ranks[rankPos] = true end end function Config:setPeriod(period) local periodPos if period == p.flags.future then periodPos = 1 elseif period == p.flags.current then periodPos = 2 elseif period == p.flags.former then periodPos = 3 else return end if not self.flagPeriod then self.periods = {false, false, false} self.flagPeriod = true end self.periods[periodPos] = true end function Config:qualifierMatches(claim, id, value) local qualifiers if claim.qualifiers then qualifiers = claim.qualifiers[id] end if qualifiers then for _, v in pairs(qualifiers) do if self:snakEqualsValue(v, value) then return true end end elseif value == "" then return true end return false end function Config:rankMatches(rankPos) if self.bestRank then return (self.ranks[rankPos] and self.foundRank >= rankPos) else return self.ranks[rankPos] end end function Config:timeMatches(claim) local startTime = nil local startTimeY = nil local startTimeM = nil local startTimeD = nil local endTime = nil local endTimeY = nil local endTimeM = nil local endTimeD = nil if self.periods[1] and self.periods[2] and self.periods[3] then -- any time return true end startTime = self:getSingleRawQualifier(claim, aliasesP.startTime) if startTime and startTime ~= "" and startTime ~= " " then startTimeY, startTimeM, startTimeD = parseDate(startTime) end endTime = self:getSingleRawQualifier(claim, aliasesP.endTime) if endTime and endTime ~= "" and endTime ~= " " then endTimeY, endTimeM, endTimeD = parseDate(endTime) end if startTimeY ~= nil and endTimeY ~= nil and datePrecedesDate(endTimeY, endTimeM, endTimeD, startTimeY, startTimeM, startTimeD) then endTimeY = nil endTimeM = nil endTimeD = nil end if self.periods[1] then if startTimeY and datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], startTimeY, startTimeM, startTimeD) then return true end end if self.periods[2] then if (startTimeY == nil or not datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], startTimeY, startTimeM, startTimeD)) and (endTimeY == nil or datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], endTimeY, endTimeM, endTimeD)) then return true end end if self.periods[3] then if endTimeY and not datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], endTimeY, endTimeM, endTimeD) then return true end end return false end function Config:processFlag(flag) if not flag then return false end if flag == p.flags.linked then self.curState.linked = true return true elseif flag == p.flags.raw then self.curState.rawValue = true if self.curState == self.states[parameters.reference] then self.separators["sep%r"][1] = {" "} end return true elseif flag == p.flags.short then self.curState.shortName = true return true elseif flag == p.flags.multilanguage then self.curState.anyLanguage = true return true elseif flag == p.flags.unit then self.curState.unitOnly = true return true elseif flag == p.flags.mdy then self.mdyDate = true return true elseif flag == p.flags.single then self.singleClaim = true return true elseif flag == p.flags.sourced then self.sourcedOnly = true return true elseif flag == p.flags.edit then self.editable = true return true elseif flag == p.flags.editAtEnd then self.editable = true self.editAtEnd = true return true elseif flag == p.flags.best or flag:match('^'..p.flags.preferred..'[+-]?$') or flag:match('^'..p.flags.normal..'[+-]?$') or flag:match('^'..p.flags.deprecated..'[+-]?$') then self:setRank(flag) return true elseif flag == p.flags.future or flag == p.flags.current or flag == p.flags.former then self:setPeriod(flag) return true elseif flag == "" then return true else return false end end function Config:processFlagOrCommand(flag) local param = "" if not flag then return false end if flag == p.claimCommands.property or flag == p.claimCommands.properties then param = parameters.property elseif flag == p.claimCommands.qualifier or flag == p.claimCommands.qualifiers then self.states.qualifiersCount = self.states.qualifiersCount + 1 param = parameters.qualifier .. self.states.qualifiersCount self.separators["sep"..param] = {copyTable(defaultSeparators["sep%q\\d"])} elseif flag == p.claimCommands.reference or flag == p.claimCommands.references then param = parameters.reference else return self:processFlag(flag) end if self.states[param] then return false end self.states[param] = State:new(self, param) self.states[param].parsedFormat = parseFormat(parameters.general) self.states[param].separator = self.separators["sep"..param] if flag == p.claimCommands.property or flag == p.claimCommands.qualifier or flag == p.claimCommands.reference then self.states[param].singleValue = true end self.curState = self.states[param] return true end function Config:processSeparators(args) local sep for i, v in pairs(self.separators) do if args[i] then sep = replaceSpecialChars(args[i]) if sep ~= "" then self.separators[i][1] = {sep} else self.separators[i][1] = nil end end end end function Config:setFormatAndSeparators(state, parsedFormat) state.parsedFormat = parsedFormat state.separator = self.separators["sep"] state.movSeparator = self.separators["sep"..parameters.separator] state.puncMark = self.separators["punc"] end function State:isSourced(claim) self.conf.prefetchedRefs = self:getReferences(claim) return (#self.conf.prefetchedRefs > 0) end function State:resetCaches() self.conf.prefetchedRefs = nil end function State:claimMatches(claim) local matches, rankPos self:resetCaches() if self.conf.propertyValue then matches = self.conf:snakEqualsValue(claim.mainsnak, self.conf.propertyValue) else matches = true end for i, v in pairs(self.conf.qualifierIDsAndValues) do matches = (matches and self.conf:qualifierMatches(claim, i, v)) end rankPos = rankTable[claim.rank] or 4 matches = (matches and self.conf:rankMatches(rankPos) and self.conf:timeMatches(claim)) if self.conf.sourcedOnly then matches = (matches and self:isSourced(claim)) end return matches, rankPos end function State:out() local result local valuesArray local sep = nil local out = {} local function walk(formatTable, result) local valuesArray = {} for i, v in pairs(formatTable.req) do if not result[i] or not result[i][1] then return {} end end for _, v in ipairs(formatTable) do if v.param then valuesArray = mergeArrays(valuesArray, result[v.str]) elseif v.str ~= "" then valuesArray[#valuesArray + 1] = {v.str} end if v.child then valuesArray = mergeArrays(valuesArray, walk(v.child, result)) end end return valuesArray end for i = #self.results, 1, -1 do result = self.results[i] if #out > 0 then sep = self.separator[1] result[parameters.separator] = {self.movSeparator[1]} else sep = nil result[parameters.separator] = {self.puncMark[1]} end valuesArray = walk(self.parsedFormat, result) if #valuesArray > 0 then if sep then valuesArray[#valuesArray + 1] = sep end out = mergeArrays(valuesArray, out) end end self.results = {} return out end function State:getProperty(claim) local value = {self:getValue(claim.mainsnak)} if #value > 0 then return {value} else return {} end end function State:getQualifiers(claim, param) local qualifiers if claim.qualifiers then qualifiers = claim.qualifiers[self.conf.qualifierIDs[param]] end if qualifiers then return self.conf.states[param]:iterate(qualifiers, {[parameters.general] = hookNames[parameters.qualifier.."\\d"][2], count = 1}) else return {} end end function State:getQualifier(snak) local value = {self:getValue(snak)} if #value > 0 then return {value} else return {} end end function State:getAllQualifiers(claim, param, result, hooks) local out = {} local sep = self.conf.separators["sep"..parameters.qualifier][1] for i = 1, self.conf.states.qualifiersCount do if not result[parameters.qualifier..i] then self:callHook(parameters.qualifier..i, hooks, claim, result) end if result[parameters.qualifier..i] and result[parameters.qualifier..i][1] then if #out > 0 and sep then out[#out + 1] = sep end out = mergeArrays(out, result[parameters.qualifier..i]) end end return out end function State:getReferences(claim) if self.conf.prefetchedRefs then return self.conf.prefetchedRefs end if claim.references then return self.conf.states[parameters.reference]:iterate(claim.references, {[parameters.general] = hookNames[parameters.reference][2], count = 1}) else return {} end end function State:getReference(statement) local key, citeWeb, citeQ, label local params = {} local citeParams = {['web'] = {}, ['q'] = {}} local citeMismatch = {} local useCite = nil local useParams = nil local value = "" local ref = {} local version = 1 if statement.snaks then if statement.snaks[aliasesP.importedFrom] then statement.snaks[aliasesP.importedFrom] = nil end if statement.snaks[aliasesP.inferredFrom] then statement.snaks[aliasesP.inferredFrom] = nil end if statement.snaks[aliasesP.typeOfReference] then statement.snaks[aliasesP.typeOfReference] = nil end if statement.snaks[aliasesP.image] then statement.snaks[aliasesP.image] = nil end if self:getReferenceDetail(statement.snaks, aliasesP.language) == self.conf.langName then statement.snaks[aliasesP.language] = nil end for i in pairs(statement.snaks) do label = "" if i == aliasesP.author then params[i] = self:getReferenceDetails(statement.snaks, i, false, self.linked, true) else params[i] = {self:getReferenceDetail(statement.snaks, i, false, (self.linked or (i == aliasesP.statedIn)) and (statement.snaks[i][1].datatype ~= 'url'), true)} end if #params[i] == 0 then params[i] = nil else if statement.snaks[i][1].datatype == 'external-id' then key = "external-id" label = self.conf:getLabel(i) if label ~= "" then label = label .. " " end else key = i end for j in pairs(citeParams) do if not citeMismatch[j] then if i18n['cite'][j][key] then if i18n['cite'][j][key] ~= "" then citeParams[j][i18n['cite'][j][key]] = label .. params[i][1] for k=2, #params[i] do citeParams[j][i18n['cite'][j][key]..k] = label .. params[i][k] end end else citeMismatch[j] = true end end end end end citeWeb = split(mw.wikibase.getSitelink(aliasesQ.citeWeb) or "", ":")[2] citeQ = split(mw.wikibase.getSitelink(aliasesQ.citeQ) or "", ":")[2] if citeWeb and not citeMismatch['web'] and citeParams['web'][i18n['cite']['web'][aliasesP.referenceURL]] and citeParams['web'][i18n['cite']['web'][aliasesP.title]] then useCite = citeWeb useParams = citeParams['web'] elseif citeQ and not citeMismatch['q'] and citeParams['q'][i18n['cite']['q'][aliasesP.statedIn]] then citeParams['q'][i18n['cite']['q'][aliasesP.statedIn]] = self:getReferenceDetail(statement.snaks, aliasesP.statedIn, true) useCite = citeQ useParams = citeParams['q'] end if useCite and useParams then if mw.isSubsting() then for i, v in pairs(useParams) do value = value .. "|" .. i .. "=" .. v end value = "{{" .. useCite .. value .. "}}" else value = mw.getCurrentFrame():expandTemplate{title=useCite, args=useParams} end elseif params[aliasesP.statedIn] or params[aliasesP.referenceURL] or params[aliasesP.title] then citeParams['default'] = {} if params[aliasesP.author] and #params[aliasesP.author] > 0 then citeParams['default'][#citeParams['default'] + 1] = table.concat(params[aliasesP.author], " & ") end if params[aliasesP.referenceURL] and params[aliasesP.title] then citeParams['default'][#citeParams['default'] + 1] = '[' .. params[aliasesP.referenceURL][1] .. ' "' .. params[aliasesP.title][1] .. '"]' elseif params[aliasesP.referenceURL] then citeParams['default'][#citeParams['default'] + 1] = params[aliasesP.referenceURL][1] elseif params[aliasesP.title] then citeParams['default'][#citeParams['default'] + 1] = '"' .. params[aliasesP.title][1] .. '"' end if params[aliasesP.statedIn] then citeParams['default'][#citeParams['default'] + 1] = "''" .. params[aliasesP.statedIn][1] .. "''" end params[aliasesP.author] = nil params[aliasesP.referenceURL] = nil params[aliasesP.title] = nil params[aliasesP.statedIn] = nil for i, v in pairs(params) do i = self.conf:getLabel(i) if i ~= "" then citeParams['default'][#citeParams['default'] + 1] = i .. ": " .. v[1] end end value = table.concat(citeParams['default'], "; ") if value ~= "" then value = value .. "." end end if value ~= "" then value = {value} if not self.rawValue then value.refHash = "pornbasedata-" .. statement.hash .. "-v" .. (tonumber(i18n['cite']['version']) + version) end ref = {value} end end return ref end function State:getReferenceDetail(snaks, dType, raw, link, anyLang) local switchLang = anyLang local value = nil if not snaks[dType] then return nil end repeat for _, v in ipairs(snaks[dType]) do value = self.conf:getValue(v, raw, link, false, anyLang and not switchLang, false, true) -- noSpecial = true if value then break end end if value or not anyLang then break end switchLang = not switchLang until anyLang and switchLang return value end function State:getReferenceDetails(snaks, dType, raw, link, anyLang) local values = {} if not snaks[dType] then return {} end for _, v in ipairs(snaks[dType]) do values[#values + 1] = self.conf:getValue(v, raw, link, false, anyLang, false, true) end return values end function State:getAlias(object) local value = object.value local title = nil if value and self.linked then if self.conf.entityID:sub(1,1) == "Q" then title = mw.wikibase.getSitelink(self.conf.entityID) elseif self.conf.entityID:sub(1,1) == "P" then title = "pbd:Property:" .. self.conf.entityID end if title then value = buildWikilink(title, value) end end value = {value} if #value > 0 then return {value} else return {} end end function State:getBadge(value) value = self.conf:getLabel(value, self.rawValue, self.linked, self.shortName) if value == "" then value = nil end value = {value} if #value > 0 then return {value} else return {} end end function State:callHook(param, hooks, statement, result) local valuesArray, refHash if not result[param] and hooks[param] then valuesArray = self[hooks[param]](self, statement, param, result, hooks) if #valuesArray > 0 then result[param] = valuesArray result.count = result.count + 1 else result[param] = {} return true end end return false end function State:iterate(statements, hooks, matchHook) matchHook = matchHook or alwaysTrue local matches = false local rankPos = nil local result, gotRequired for _, v in ipairs(statements) do matches, rankPos = matchHook(self, v) if matches then result = {count = 0} local function walk(formatTable) local miss for i2, v2 in pairs(formatTable.req) do miss = self:callHook(i2, hooks, v, result) if miss then return false end if result.count == hooks.count then return true end end for _, v2 in ipairs(formatTable) do if result.count == hooks.count then return true end if v2.child then walk(v2.child) end end return true end gotRequired = walk(self.parsedFormat) if gotRequired then if rankPos and self.conf.foundRank > rankPos then self.conf.foundRank = rankPos end self.results[#self.results + 1] = result if self.singleValue then break end end end end return self:out() end local function getEntityId(arg, eid, page, allowOmitPropPrefix) local id = nil local prop = nil if arg then if arg:sub(1,1) == ":" then page = arg eid = nil elseif arg:sub(1,1):upper() == "Q" or arg:sub(1,9):lower() == "property:" or allowOmitPropPrefix then eid = arg page = nil else prop = arg end end if eid then if eid:sub(1,9):lower() == "property:" then id = replaceAlias(mw.text.trim(eid:sub(10))) if id:sub(1,1):upper() ~= "P" then id = "" end else id = replaceAlias(eid) end elseif page then if page:sub(1,1) == ":" then page = mw.text.trim(page:sub(2)) end id = mw.wikibase.getEntityIdForTitle(page) or "" end if not id then id = mw.wikibase.getEntityIdForCurrentPage() or "" end id = id:upper() if not mw.wikibase.isValidEntityId(id) then id = "" end return id, prop end local function nextArg(args) local arg = args[args.pointer] if arg then args.pointer = args.pointer + 1 return mw.text.trim(arg) else return nil end end local function claimCommand(args, funcName) local cfg = Config:new() cfg:processFlagOrCommand(funcName) local lastArg, parsedFormat, formatParams, claims, value local hooks = {count = 0} if args[p.args.date] then cfg.atDate = {parseDate(args[p.args.date])} cfg.periods = {false, true, false} end repeat lastArg = nextArg(args) until not cfg:processFlagOrCommand(lastArg) cfg.entityID, cfg.propertyID = getEntityId(lastArg, args[p.args.eid], args[p.args.page]) if cfg.entityID == "" then return "" end cfg.entity = mw.wikibase.getEntity(cfg.entityID) if not cfg.propertyID then cfg.propertyID = nextArg(args) end cfg.propertyID = replaceAlias(cfg.propertyID) if not cfg.entity or not cfg.propertyID then return "" end cfg.propertyID = cfg.propertyID:upper() if not cfg.entity.claims or not cfg.entity.claims[cfg.propertyID] then return "" end claims = cfg.entity.claims[cfg.propertyID] if cfg.states.qualifiersCount > 0 then if #args - args.pointer + 1 > cfg.states.qualifiersCount then cfg.propertyValue = nextArg(args) end for i = 1, cfg.states.qualifiersCount do cfg.qualifierIDs[parameters.qualifier..i] = replaceAlias(nextArg(args) or ""):upper() end elseif cfg.states[parameters.reference] then cfg.propertyValue = nextArg(args) end if cfg.propertyValue then cfg.propertyValue = replaceSpecialChars(cfg.propertyValue) if cfg.propertyValue ~= "" and mw.text.trim(cfg.propertyValue) == "" then cfg.propertyValue = " " else cfg.propertyValue = mw.text.trim(cfg.propertyValue) end end if args["format"] then parsedFormat, formatParams = parseFormat(args["format"]) elseif cfg.states.qualifiersCount > 0 then if cfg.states[parameters.property] then parsedFormat, formatParams = parseFormat(formats.propertyWithQualifier) else parsedFormat, formatParams = parseFormat(formats.qualifier) end elseif cfg.states[parameters.property] then parsedFormat, formatParams = parseFormat(formats.property) else parsedFormat, formatParams = parseFormat(formats.reference) end if cfg.states.qualifiersCount > 0 and not cfg.states[parameters.property] then cfg.separators["sep"..parameters.separator][1] = {";"} end if cfg.states[parameters.reference] and not cfg.states[parameters.property] and cfg.states.qualifiersCount == 0 and not cfg.states[parameters.reference].rawValue then cfg.separators["sep"][1] = nil end if cfg.states.qualifiersCount == 1 then cfg.separators["sep"..parameters.qualifier] = cfg.separators["sep"..parameters.qualifier.."1"] end cfg:processSeparators(args) for i, v in pairs(cfg.states) do if formatParams[i] or formatParams[i:sub(1, 2)] then hooks[i] = getHookName(i, 1) hooks.count = hooks.count + 1 end end if formatParams[parameters.qualifier] and cfg.states.qualifiersCount > 0 then hooks[parameters.qualifier] = getHookName(parameters.qualifier, 1) hooks.count = hooks.count + 1 end if not cfg.states[parameters.property] then cfg.states[parameters.property] = State:new(cfg, parameters.property) if cfg.singleClaim then cfg.states[parameters.property].singleValue = true end end if cfg.sourcedOnly and not cfg.states[parameters.reference] then cfg:processFlagOrCommand(p.claimCommands.reference) end cfg:setFormatAndSeparators(cfg.states[parameters.property], parsedFormat) for i, v in pairs(args) do i = tostring(i) if i:match('^[Pp]%d+$') or aliasesP[i] then v = replaceSpecialChars(v) if v ~= "" and mw.text.trim(v) == "" then v = " " end cfg.qualifierIDsAndValues[replaceAlias(i):upper()] = v end end claims = sortOnRank(claims) value = cfg:concatValues(cfg.states[parameters.property]:iterate(claims, hooks, State.claimMatches)) if cfg.editable and value ~= "" then value = value .. cfg:getEditIcon() end return value end local function generalCommand(args, funcName) local cfg = Config:new() cfg.curState = State:new(cfg) local lastArg local value = nil repeat lastArg = nextArg(args) until not cfg:processFlag(lastArg) cfg.entityID = getEntityId(lastArg, args[p.args.eid], args[p.args.page], true) if cfg.entityID == "" or not mw.wikibase.entityExists(cfg.entityID) then return "" end if funcName == p.generalCommands.label then value = cfg:getLabel(cfg.entityID, cfg.curState.rawValue, cfg.curState.linked, cfg.curState.shortName) elseif funcName == p.generalCommands.title then cfg.inSitelinks = true if cfg.entityID:sub(1,1) == "Q" then value = mw.wikibase.getSitelink(cfg.entityID) end if cfg.curState.linked and value then value = buildWikilink(value) end elseif funcName == p.generalCommands.description then value = mw.wikibase.getDescription(cfg.entityID) else local parsedFormat, formatParams local hooks = {count = 0} cfg.entity = mw.wikibase.getEntity(cfg.entityID) if funcName == p.generalCommands.alias or funcName == p.generalCommands.badge then cfg.curState.singleValue = true end if funcName == p.generalCommands.alias or funcName == p.generalCommands.aliases then if not cfg.entity.aliases or not cfg.entity.aliases[cfg.langCode] then return "" end local aliases = cfg.entity.aliases[cfg.langCode] if args["format"] then parsedFormat, formatParams = parseFormat(args["format"]) else parsedFormat, formatParams = parseFormat(formats.alias) end cfg:processSeparators(args) if formatParams[parameters.alias] then hooks[parameters.alias] = getHookName(parameters.alias, 1) hooks.count = hooks.count + 1 end cfg:setFormatAndSeparators(cfg.curState, parsedFormat) value = cfg:concatValues(cfg.curState:iterate(aliases, hooks)) elseif funcName == p.generalCommands.badge or funcName == p.generalCommands.badges then if not cfg.entity.sitelinks or not cfg.entity.sitelinks[cfg.siteID] or not cfg.entity.sitelinks[cfg.siteID].badges then return "" end local badges = cfg.entity.sitelinks[cfg.siteID].badges cfg.inSitelinks = true if args["format"] then parsedFormat, formatParams = parseFormat(args["format"]) else parsedFormat, formatParams = parseFormat(formats.badge) end cfg:processSeparators(args) if formatParams[parameters.badge] then hooks[parameters.badge] = getHookName(parameters.badge, 1) hooks.count = hooks.count + 1 end cfg:setFormatAndSeparators(cfg.curState, parsedFormat) value = cfg:concatValues(cfg.curState:iterate(badges, hooks)) end end value = value or "" if cfg.editable and value ~= "" then value = value .. cfg:getEditIcon() end return value end local function establishCommands(commandList, commandFunc) for _, commandName in pairs(commandList) do local function wikitextWrapper(frame) local args = copyTable(frame.args) args.pointer = 1 loadI18n(aliasesP, frame) return commandFunc(args, commandName) end p[commandName] = wikitextWrapper local function luaWrapper(args) args = copyTable(args) args.pointer = 1 loadI18n(aliasesP) return commandFunc(args, commandName) end p["_" .. commandName] = luaWrapper end end establishCommands(p.claimCommands, claimCommand) establishCommands(p.generalCommands, generalCommand) function p.main(frame) if not mw.wikibase then return nil end local f, args loadI18n(aliasesP, frame) frame = frame:getParent() or frame if not frame.args[1] then throwError("no-function-specified") end f = mw.text.trim(frame.args[1]) if f == "main" then throwError("main-called-twice") end assert(p["_"..f], errorText('no-such-function', f)) args = copyTable(frame.args) table.remove(args, 1) return p["_"..f](args) end return p
Summary:
Please note that all contributions to Porn Base Central may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Porn Base Central:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Preview page with this template
Template used on this page:
Module:PBD/doc
(
view source
)
Navigation menu
Personal tools
English
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Module
Discussion
English
Views
Read
Edit source
View history
More
Search
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Tools
What links here
Related changes
Upload file
Special pages
Page information