Modul:Utility
Utseende
Dokumentationen för denna modul kan skapas på Modul:Utility/dok
rm = rm or {}
-- Returnerar dagens datum. För att avläsningar som läser av vid ett visst datum ska ha ett datum att utgå ifrån.
rm.now=function()
local currentDateStr = os.date("%Y-%m-%d %H:%M:%S")
return currentDateStr
end
--Returns a tbl with label, sitelink etc.
rm.tblWikilink=function (qid,asofdate,bDoNotCheckPartOf)
local tbl={}
local bHasLabel
if (qid) then
tbl.qid=qid
-- Read label (for specific year if relevant)
local txtLabelThis=getLabelFundamental(qid)
if (asofdate==nil) then
tbl.txtLabel=txtLabelThis
else
tbl.txtLabel=rm.getLabelFromEntityId(qid,asofdate)
end
if not tbl.txtLabel then
tbl.txtLabel=localisation.txtMissing .. '<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]' -- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
bHasLabel=false
else
bHasLabel=true
end
tbl.txtLabel_current=rm.getLabelFromEntityId(qid,rm.now())
if not tbl.txtLabel_current then
tbl.txtLabel_current=localisation.txtMissing .. '<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]' -- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
end
-- Get site link
tbl.txtSitelink=mw.wikibase.getSitelink(qid)
-- If site link exists - use it
if tbl.txtSitelink then
return tbl,true
else
if not(bDoNotCheckPartOf) then
-- if there is no site link, check if the item (organisation) is part of another one (either as 'part of' or 'mother organisation')
-- if so use it
local claimsPartOf = mw.wikibase.getAllStatements(qid, 'P361' ) -- part of
if (claimsPartOf[1]) then
local iPartof=read(claimsPartOf[1],'id')
local mytbl, isokpart
mytbl,isokpart=rm.tblWikilink(iPartof,asofdate)
if (isokpart) then
tbl.txtSitelink=mytbl.txtSitelink -- use sitelink from part of (but label from original organisation)
return tbl,true
end
end
local claimsPartOf2 = mw.wikibase.getAllStatements(qid,'P749' ) -- mother organisation
if (claimsPartOf2[1]) then
local iPartof2=read(claimsPartOf2[1],'id')
local mytbl, isokpart
mytbl,isokpart=rm.tblWikilink(iPartof2,asofdate)
if (isokpart) then
tbl.txtSitelink=mytbl.txtSitelink -- use sitelink from part of (but label from original organisation)
return tbl,true
end
else
-- If no site link at the item or any parent, consider using the label as sitelink
if bHasLabel and not tbl.txtSitelink then
idUsedLabel=mw.wikibase.getEntityIdForTitle(tbl.txtLabel)
if (idUsedLabel) then
tbl.txtSitelink=tbl.txtLabel
return tbl,true
else
if (txtLabelThis==nil) then
tbl.txtSitelink=tbl.txtLabel
return tbl, true
else
tbl.txtSitelink=txtLabelThis
return tbl, true
end
end
else
tbl.txtLabel=localisation.txtMissing .. '<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]' -- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
tbl.txtSitelink=false
return tbl,false -- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
end
end
end
end
end
return tbl,false
end
rm.getLabelFromEntityId=function( qid, asofdate )
if (asofdate==nil) then
return getLabelFundamental(qid)
else
--If available use P2561 (name), prioriticed as it can be edited with greater flexibility
local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P2561',asofdate )
if (not(bFoundName)) then
--If P2561 not available try P1448 (official name)
local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P1448',asofdate )
end
if (bFoundName) then
return txtName
else
return getLabelFundamental(qid)
end
end
end
--Returns a wikilink to the connect page if there is one. Otherwise create to the a page with the name of the label
function txtWikilink(qid,year)
-- Read label (for specific year if relevant)
local txtLabel
local txtLabelThis=getLabelFundamental(qid)
if (year==nil) then
txtLabel=txtLabelThis
else
txtLabel=getLabelFromEntityId(qid,year)
end
-- Get site link
local txtSitelink=mw.wikibase.getSitelink(qid)
-- If site link exists - use it
if (txtSitelink) then
return '[[' .. txtSitelink .. '|' .. txtLabel .. ']]'
else
-- if there is no site link, check if the item (organisation) is part of another one (either as 'part of' or 'mother organisation')
-- if so use it
local claimsPartOf = mw.wikibase.getAllStatements(qid, 'P361' ) -- part of
if (claimsPartOf[1]) then
local iPartof=read(claimsPartOf[1],'id')
local mytxt, isokpart
mytxt,isokpart=txtWikilink(iPartof,year)
if (isokpart) then
return mytxt,true
end
end
local claimsPartOf2 = mw.wikibase.getAllStatements(qid,'P749' ) -- mother organisation
if (claimsPartOf2[1]) then
local iPartof2=read(claimsPartOf2[1],'id')
return txtWikilink(iPartof2,year)
else
-- If no site link at the item or any parent, consider using the label
if (txtLabel) then
idThatLabel=mw.wikibase.getEntityIdForTitle(txtLabel)
if (idThatLabel) then
return txtLabel,true
else
if (txtLabelThis==nil) then
return '[[' .. txtLabel .. ']]',true
else
return '[[' .. txtLabelThis .. '|' .. txtLabel .. ']]',true
end
end
else
return '('..localisation.txtMissing..')<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]',false -- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
end
end
end
end
--Returns a wikilink to the connect page if there is one. Otherwise create to the a page with the name of the label
--Does not try to use the label as a sitelink if there is no sitelink
--Further, it does not try to use any part of or mother organisation relation
function txtWikilinkWOsitelink(qid,year)
-- Read label (for specific year if relevant)
local txtLabel
local txtLabelThis=getLabelFundamental(qid)
if (year==nil) then
txtLabel=txtLabelThis
else
txtLabel=getLabelFromEntityId(qid,year)
end
-- Get site link
txtSitelink=mw.wikibase.getSitelink(qid)
-- If site link exists - use it
if (txtSitelink) then
return '[[' .. txtSitelink .. '|' .. txtLabel .. ']]'
else
if (txtLabel) then
return txtLabel
else
return '('..localisation.txtMissing..')<!--'..qid..'-->' -- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
end
end
end
function emptyifNil(data)
if (data) then
return data
else
return ''
end
end
function getLabelByEntity(qid)
mw.log('getLabelByEntity')
return getLabelFundamental(qid)
end
function getLabelFundamental(qid)
return mw.wikibase.getLabel(qid, localisation.txtLanguageCode ) or mw.wikibase.getLabel(qid, 'mul')
end
function getLabelFromEntityId( qid, year )
if (year==nil) then
return mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
else
--If available use P2561 (name), prioriticed as it can be edited with greater flexibility
local bFoundName,txtName=getLabelFromNamePropertyId(qid,'P2561',year )
if (not(bFoundName)) then
--If P2561 not available try P1448 (official name)
local bFoundName,txtName=getLabelFromNamePropertyId(qid,'P1448',year )
end
if (bFoundName) then
return txtName
else
txtLabelDirect=getLabelFundamental(qid)
if (txtLabelDirect) then
return txtLabelDirect
else
return localisation.txtMissing
end
end
end
end
function getLabelFromNamePropertyId(qid, pid,year )
local claims = mw.wikibase.getBestStatements(qid,pid) -- If the club have had many names, loop through to find the one that was used when the player played at the club
if (next(claims)) then
-- Use label as default (if nothing is found that match year-wise)
local txtName=mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
-- Loop through names
for key, value in pairs( claims ) do
local yearfrom,yearto,datefrom,dateto = years(value)
local lng=read(value,'language')
if ((year >= yearfrom and year <= yearto) or (yearto=='' and year >= yearfrom)) and (not(lang_denylist[lng]==true)) then
if (lng==txtLocalLanguage) then
txtName=read(value,'text')
if (txtName==nil) then
txtName=txtNotLocalLanguage
else --If name exists in local language return straight away, do not continue looping
return true,txtName
end
else --set name for possible later return, but keep looping
txtName=read(value,'text')
end
end
end
--if name property (P1448 or P2561) is set then set name if one was found, otherwise write an error message
return true,txtName
else
--if property was not set just use usual name
return false,nil
end
end
function getLabelFromEntityId2( qid, asofdate )
if (year==nil) then
return mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
else
--If available use P2561 (name), prioriticed as it can be edited with greater flexibility
local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P2561',asofdate )
if (not(bFoundName)) then
--If P2561 not available try P1448 (official name)
local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P1448',asofdate )
end
if (bFoundName) then
return txtName
else
return mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
end
end
end
function getLabelFromNamePropertyId2(qid, pid,asofdate )
local claims = mw.wikibase.getBestStatements(qid,pid) -- If the club have had many names, loop through to find the one that was used when the player played at the club
if (next(claims)) then
-- Use label as default (if nothing is found that match year-wise)
local txtName=mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
-- Loop through names
for key, value in pairs( claims ) do
local yearfrom,yearto,datefrom,dateto = years(value)
local lng=read(value,'language')
if ((asofdate >= datefrom and asofdate <= dateto) or (dateto=='' and asofdate >= datefrom)) and (not(localisation.lang_denylist[lng]==true)) then
if (lng==localisation.txtLanguageCode) then
txtName=read(value,'text')
if (txtName==nil) then
txtName=txtNotLocalLanguage
else --If name exists in local language return straight away, do not continue looping
return true,txtName
end
else --set name for possible later return, but keep looping
txtName=read(value,'text')
end
end
end
--if name property (P1448 or P2561) is set then set name if one was found, otherwise write an error message
return true,txtName
else
--if property was not set just use usual name
return false,nil
end
end
function readFirstStatementId(entityid,txtProperty)
statements=mw.wikibase.getBestStatements(entityid,txtProperty)
if not(next(statements)==nil) then
if not(statements[1]==nil) then
return read(statements[1],'id')
end
end
return nil
end
function readFirstStatement(entityid,txtProperty)
statements=mw.wikibase.getBestStatements(entityid,txtProperty)
if not(next(statements)==nil) then
if not(statements[1]==nil) then
qid=read(statements[1],'id')
if not (qid==nil) then
return mw.wikibase.getLabelByLang(qid,localisation.txtLanguageCode)
end
end
end
return nil
end
function getQualifier(value,txtQualifierId)
if value['qualifiers'] and value['qualifiers'][txtQualifierId] then
txtValue=emptyifNil(mw.wikibase.renderSnak(value['qualifiers'][txtQualifierId][1]))
else
txtValue=nil
end
return txtValue
end
--Replace with (and move content to) getQualifier, which as a more sensible name
function getProperty(value,txtPropertyId)
mw.log("Använder getProperty")
if value['qualifiers'] and value['qualifiers'][txtPropertyId] then
txtValue=emptyifNil(mw.wikibase.renderSnak(value['qualifiers'][txtPropertyId][1]))
else
txtValue=nil
end
return txtValue
end
function getQualifierId(value,txtQualifierId)
if value then
if value['qualifiers'] then
if value['qualifiers'][txtQualifierId] then
txtSnaktype=value['qualifiers'][txtQualifierId][1].snaktype
if (txtSnaktype=="value") then
txtValue=value['qualifiers'][txtQualifierId][1].datavalue.value.id
if (not txtValue) then
txtValue=value['qualifiers'][txtQualifierId][1].datavalue.value.amount
end
else
txtValue="Not Implemented"
end
else
txtValue=nil
end
else
txtValue=nil
end
else
return nil
end
return txtValue
end
--Replace with (and move content to) getQualifierId, which as a more sensible name
function getPropertyId(value,txtPropertyId)
mw.log("Använder getPropertyId")
if value then
if value['qualifiers'] then
if value['qualifiers'][txtPropertyId] then
txtSnaktype=value['qualifiers'][txtPropertyId][1].snaktype
if (txtSnaktype=="value") then
txtValue=value['qualifiers'][txtPropertyId][1].datavalue.value.id
if (not txtValue) then
txtValue=value['qualifiers'][txtPropertyId][1].datavalue.value.amount
end
else
txtValue="Not Implemented"
end
else
txtValue=nil
end
else
txtValue=nil
end
else
return nil
end
return txtValue
end
--Read a value of a property
function read(data,type)
if (data) then
if (data['mainsnak']) then
return readQualifier(data['mainsnak'],type)
else
return nil
end
else
return nil
end
end
--Read a value of a qualifier
function readQualifier(data,type)
if (data['datavalue']) then
return data['datavalue']['value'][type]
else
return nil
end
end
rm.readtext=function(claims, asofdate)
for key, value in pairs( claims ) do
local yearfrom,yearto,datefrom,dateto = years(value)
local lng=read(value,'language')
if ((asofdate >= datefrom and asofdate <= dateto) or (dateto=='' and asofdate >= datefrom)) and (not(localisation.lang_denylist[lng]==true)) then
if (lng==localisation.txtLocalLanguage) then
txtName=read(value,'text')
if (txtName==nil) then
txtName=localisation.txtNotLocalLanguage
else --If name exists in local language return straight away, do not continue looping
return true,txtName
end
else --set name for possible later return, but keep looping
txtName=read(value,'text')
end
end
end
end
rm.readQualifier=function (value,qfid,type)
if (value.qualifiers and value.qualifiers[qfid]) then
return readQualifier(value.qualifiers[qfid][1],type)
else
return nil
end
end
-- Function to split a string by a delimiter (by chatgpt)
function split(inputStr, delimiter)
local result = {}
for match in (inputStr .. delimiter):gmatch("(.-)" .. delimiter) do
table.insert(result, match)
end
return result
end
-- Function to merge two tables
function merge(table1, table2)
local result = {}
-- Insert all key-value pairs from table1 into result
for key, value in pairs(table1) do
result[key] = value
end
-- Insert all key-value pairs from table2 into result
for key, value in pairs(table2) do
result[key] = value
end
return result
end
-- Check if all values of a given property are the same. In such case there is often no need to show something for every individual item
--------------------------------------------------
-- qid qid of the object
-- pid pid of the property
--
-- The function returns a lua table with filename, description, width, height (as well as qid and pid)
function getImage(qid,pid)
img=mw.wikibase.getBestStatements(qid, pid )
bDescription=false -- variable to check if a description has been found
if next(img) then
image={}
image.txtFilename = img[1]['mainsnak']['datavalue']['value']
-- txtFilename = read(img[1],'value')
if img[1].qualifiers and img[1].qualifiers.P2096 then
-- Loop through all descriptions
for key, value in pairs(img[1].qualifiers.P2096) do
-- Only add if has the same language code as the local wikipedia
language=readQualifier(value,'language')
if (language==localisation.txtLanguageCode) then
bDescription=true -- description found!
image.txtDescription=readQualifier(value,'text') -- add description (+ pen to make it easier to edit)
end
end
end
image.width,image.height=getImageSize(image.txtFilename)
image.qid=qid
image.pid=pid
return image
end
return
end
-- Get size of image. Used by the function above,
--------------------------------------------------
-- txtFilename Name of image file
--
-- The function returns a lua table with width and height (if succesful) or error message (if unsuccesful)
function getImageSize(txtFileName)
local title = mw.title.new(txtFileName, 'File')
if not title then
return nil, nil, "Invalid image name"
end
local file = title and title.file
if not file then
return nil, nil, "File not found"
end
return file.width, file.height
end
-- Adds image to lua table (myArgs) that is used to supply arguments to the infobox template
-- Assumes a lua table that has been filled by the getImage function above
function showImage(tblImage)
myArgs[localisation.txtImage]='[[File:' .. tblImage.txtFilename .. '|' .. settings.iWidth_px .. 'px]]'
p.myArgs[localisation.txtImage]='[[File:' .. tblImage.txtFilename .. '|' .. settings.iWidth_px .. 'px]]'
if (tblImage.txtDescription) then
myArgs[localisation.txtCaption]=tblImage.txtDescription..txtEditPen(tblImage.qid,tblImage.pid)
p.myArgs[localisation.txtCaption]=tblImage.txtDescription..txtEditPen(tblImage.qid,tblImage.pid)
else
myArgs[localisation.txtImage]=myArgs[localisation.txtImage]..txtEditPen(tblImage.qid,tblImage.pid)
p.myArgs[localisation.txtImage]=myArgs[localisation.txtImage]..txtEditPen(tblImage.qid,tblImage.pid)
end
end
function datetotext (from,to)
mw.log('in function datetotext')
local txt =''
if not isempty(from) then
txt=from.year
end
if not (isempty(from) and isempty(to)) then
txt=txt..'–'
end
if not isempty(to) then
txt=txt..to.year
end
if from and to and (from.year==to.year) then
txt=from.year
end
return txt
end
p.showdata = function(frame)
p.frame=frame
p=p.data()
require(localisation.txtModule .. ':Debug' )
return tprint(p)
end
p.showpartininfobox=function(txtThisLabel,propertyname,bCheckChildren,runfunc)
local obj=p[propertyname]
if (obj) then
if(obj[1]) then --Safety check to check if obj is an array rather than a structure (since Lua for some reason lacks any built-in functionality to test the difference test for 1 is a quick fix)
obj=nil
end
end
if (obj) then
local txtContent=obj.data
if (obj.unit) then
txtContent=txtContent .. ' ' .. obj.unit
end
txtContent=txtContent .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
if (runfunc) then
txtContent=txtContent .. runfunc()
end
p.addContent(txtThisLabel,txtContent)
-- p.iCounter=p.iCounter+1
-- myArgs[localisation.txtLabel .. p.iCounter]=txtThisLabel
-- myArgs[localisation.txtContent .. p.iCounter]=txt .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
-- if (runfunc) then
-- myArgs[localisation.txtContent .. p.iCounter]=myArgs[localisation.txtContent .. p.iCounter] .. runfunc()
-- end
end
if (bCheckChildren) then
if (p.objectIds) then
for key,value in pairs(p.objectIds) do
obj=p[value][propertyname]
if (obj) then
local txtContent=obj.data
if (obj.unit) then
txtContent=txtContent .. ' ' .. obj.unit
end
txtContent=txtContent .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
if (runfunc) then
txtContent=txtContent .. runfunc()
end
p.addContent(' – ' .. p[value]['label'],txtContent)
-- p.iCounter=p.iCounter+1
-- myArgs[localisation.txtLabel .. p.iCounter]=' – ' .. p[value]['label']
-- myArgs[localisation.txtContent .. p.iCounter]=txt .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
-- if (runfunc) then
-- myArgs[localisation.txtContent .. p.iCounter]=myArgs[localisation.txtContent .. p.iCounter] .. runfunc()
-- end
end
end
end
end
end
p.processoneiteminlist=function(item,func,specificproperties,separator,bHideReferences)
local ret
if (item.from or item.to) then
txtYears=' (' .. datetotext (item.from,item.to) .. ')'
else
txtYears=''
end
if func then
ret = func(item)
else
if not (specificproperties==nil) then
local txtCurrent=item[specificproperties[1]]
for j=2,#specificproperties do
if (item[specificproperties[j]]) then
if not txtCurrent then
txtCurrent=''
end
txtCurrent=txtCurrent .. separator .. item[specificproperties[j]]
end
end
ret = txtCurrent
else
ret= item
end
end
if (bHideReferences) then
return ret .. txtYears
else
return ret .. txtYears .. txtUnpackReference_model(p.frame,item.ref,item.qid,item.pid)
end
end
-- Function: Loopitems
-- Purpose: To fill an infobox row with values based on the content of ,general property, that will contain an array that is looped through
-- Arguments:
-- label - Label for the infobox row
-- generalproperty - Property to read the data from.
-- specificproperties - Subproperties that are used to fill the content of the infobox row.
-- separator - Separator between the different items of the list (except the last one)
-- lastseparator - Separator between the second last and the last item of the list
p.loopitems=function(label,generalproperty,func,specificproperties,separator,lastseparator,bHideReferences)
local listDataitems=p[generalproperty]
local iItems=1
if listDataitems and next(listDataitems) then
iItems=#listDataitems
local txt
if (iItems>0) then
txt=''
for i=1,iItems do
if(i>1) then
if (i==iItems) then
txt=txt..lastseparator
else
txt=txt..separator
end
end
local txtCurrent=p.processoneiteminlist(listDataitems[i],func,specificproperties,", ",bHideReferences)
if (i==1) then
txt=txt..firstToUpper(txtCurrent)
else
txt=txt..txtCurrent
end
end
else
txt=p.processoneiteminlist(listDataitems,func,specificproperties,", ",bHideReferences)
end
local txtLabel
if type(label) == "string" then
txtLabel=label
else
if (iItems>1) then
txtLabel=label[2]
else
txtLabel=label[1]
end
end
p.addContent(txtLabel,txt)
end
end
-- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
-- use these as the second parameter and this function instead of the built-in "pairs" function
-- to iterate over all qualifiers and snaks in the intended order.
local function orderedpairs(array, order)
mw.log('in function orderedpairs')
if not order then return pairs(array) end
-- return iterator function
local i = 0
return function()
i = i + 1
if order[i] then
return order[i], array[order[i]]
end
end
end
function __genOrderedIndex( t )
local orderedIndex = {}
for key in pairs(t) do
table.insert( orderedIndex, key )
end
table.sort( orderedIndex )
return orderedIndex
end
function orderedNext(t, state)
-- mw.log('in function orderedNext')
-- Equivalent of the next function, but returns the keys in the alphabetic
-- order. We use a temporary ordered key table that is stored in the
-- table being iterated.
local key = nil
--print("orderedNext: state = "..tostring(state) )
if state == nil then
-- the first time, generate the index
t.__orderedIndex = __genOrderedIndex( t )
key = t.__orderedIndex[1]
else
-- fetch the next value
for i = 1,table.getn(t.__orderedIndex) do
if t.__orderedIndex[i] == state then
key = t.__orderedIndex[i+1]
end
end
end
if key then
return key, t[key]
end
-- no more value to return, cleanup
t.__orderedIndex = nil
return
end
function orderedPairs(t)
-- mw.log('in function orderedPairs')
-- Equivalent of the pairs() function on tables. Allows to iterate
-- in order
return orderedNext, t, nil
end
function isempty(foo)
return (foo==nil) or (foo=='') or (foo==0)
end
-- from: https://stackoverflow.com/questions/2421695/first-character-uppercase-lua
function firstToUpper(str)
if (str) then
return (str:gsub("^%l", string.upper))
else
return ''
end
end
function inTable(table, val)
for _, value in ipairs(table) do
if value == val then
return true
end
end
return false
end
--Functions to ensure that urls are handled correctly
--from http://lua-users.org/wiki/StringRecipes
function url_encode(str)
if str then
str = str:gsub("\n", "\r\n")
str = str:gsub(" ", "+")
end
return str
end
function url_decode(str)
str = str:gsub("+", " ")
str = str:gsub("%%(%x%x)", function(h)
return string.char(tonumber(h,16))
end)
str = str:gsub("\r\n", "\n")
return str
end