ሞድዩል:Authority control
Appearance
Documentation for this module may be created at ሞድዩል:Authority control/doc
require('Module:No globals')
local function cleanLink ( link, style )
-- similar to mw.uri.encode
local wikiLink = link
if style == 'PATH' then
wikiLink = mw.ustring.gsub( wikiLink, ' ', '%%%%20' )
elseif style == 'WIKI' then
wikiLink = mw.ustring.gsub( wikiLink, ' ', '_' )
else -- if style == 'QUERY' then -- default
wikiLink = mw.ustring.gsub( wikiLink, ' ', '+' )
end
wikiLink = mw.ustring.gsub( wikiLink, '%[', '%%5B' )
wikiLink = mw.ustring.gsub( wikiLink, '%]', '%%5D' )
wikiLink = mw.ustring.gsub( wikiLink, '%"', '%%%%22' )
return wikiLink
end
local function generic ( id, link, parameter )
local idlink = cleanLink( id, 'PATH' )
link = mw.ustring.gsub( link, '$1', idlink )
return '[' .. link .. ' ' .. id .. ']'
end
local function noLink ( id, link, parameter )
-- avoid generating an external link together with the identifier
return id
end
local function commonscat ( id, link, parameter )
-- special representation of the link to the Commons categories, to maintain the interwiki link format
local idlink = cleanLink( id, 'WIKI' )
link = mw.ustring.gsub( link, '$1', idlink )
return '<span class="plainlinks">[' .. link .. ' ' .. id .. ']</span>'
end
local function sisterprojects ( id, link, parameter )
-- interproject links
local prefix = {
-- Example: -- enwiki = 'w:en',
commonswiki = 'c',
enwikivoyage = 'voy',
tiwiktionary = 'wikt',
enwikibooks = 'b',
enwikinews = 'n',
enwikiversity = 'v',
enwikiquote = 'q',
enwikisource = 's',
mediawikiwiki = 'mw',
metawiki = 'm',
specieswiki = 'species'
}
if prefix[ parameter ] then
return '[['..prefix[ parameter ]..':'..id..'|'..id..']]'
end
return false
end
function getCommonsValue ( itemId )
local commonslink = ''
local categories = ''
local property = getIdsFromWikidata( itemId, 'P373' )
if property and property[1] then
property = property[1]
commonslink = commonslink .. getLink( 373, property, commonscat )
else
property = ''
end
local sitelink = getIdsFromSitelinks( itemId, 'commonswiki' )
if sitelink and sitelink[1] then
sitelink = sitelink[1]
if sitelink ~= 'Category:' .. property then
if commonslink == '' then
commonslink = commonslink .. sisterprojects( sitelink, nil, 'commonswiki' )
end
end
else
sitelink = ''
end
if property and sitelink then
if sitelink ~= 'Category:' .. property then
-- categories = categories .. '[[መደብ:ዊኪፐድያ:Authority control with non-Commons links]]'
end
elseif sitelink then -- not property
-- categories = categories .. '[[መደብ:ዊኪፐድያ:Authority control without Commonscat]]'
elseif property then -- not sitelink
-- categories = categories .. '[[መደብ:ዊኪፐድያ:Authority control without Commons]]'
else -- not property and not sitelink
-- categories = categories .. '[[መደብ:ዊኪፐድያ:Authority control without any Commons link]]'
end
if commonslink ~= '' then
-- Special:MediaSearch
local mediasearch = 'https://commons.wikimedia.org/wiki/Special:MediaSearch?type=image&search=%22$1%22'
commonslink = commonslink .. ' / ' .. commonscat( itemId, mediasearch )
return { commonslink .. categories }
end
return {}
end
local conf = {}
--In this order: name of the parameter, label, propertyId in Wikidata, formatting function, category id
-- -- name of the parameter: unique name
-- -- label: internal link in wiki format
-- -- propertyId in Wikidata: number without 'P' suffix
-- -- formatting function: one of these four options
-- -- -- local function (like 'generic')
-- -- -- string 'y' (yes), to show a default identifier 'ID'
-- -- -- string 'n' (no), to show the real identifier
-- -- -- any other string, to show this string as identifier ('id', 'url', 'link', ...)
-- -- category id: one of these tree options
-- -- -- number 0, to not add category
-- -- -- number 1, to add a category based on the name of the parameter
-- -- -- any string, to add a category based on this string
conf.databases = {}
conf.databases[1] = {}
conf.databases[1].name = 'Authority control'
conf.databases[1].list = {
{
title = 'ፕሮጀክታት ዊኪሜድያ',
group = {
{ 'Wikidata', '[[ፋይል:Wikidata-logo.svg|20px|link=Wikidata|alt=Wd|Wikidata]] መዋፈሪ ሓበሬታ', 'Wikidata:$1', 'n', 0 },
{ 'Commons', '[[ፋይል:Commons-logo.svg|15px|link=Wikimedia Commons|alt=Commonscat|Commonscat]] ሕብረ-ሜድያዊ', getCommonsValue, 'n', 0 },
{ 'Wikivoyage', '[[ፋይል:Wikivoyage-logo.svg|15px|link=Wikivoyage|alt=Wikivoyage|Wikivoyage]] ሓባሪ ጉዕዞ', 'enwikivoyage', sisterprojects, 0 },
{ 'Wiktionary', '[[ፋይል:Wiktionary-logo.svg|15px|link=Wiktionary|alt=Wiktionary|Wiktionary]] መዝገበ-ቃላት', 'tiwiktionary', sisterprojects, 0 },
{ 'Wikibooks', '[[ፋይል:Wikibooks-logo.svg|15px|link=Wikibooks|alt=Wikibooks|Wikibooks]] መምሃሪ መጻሕፍትን መምርሒታትን', 'enwikibooks', sisterprojects, 0 },
{ 'Wikinews', '[[ፋይል:Wikinews-logo.svg|20px|link=Wikinews|alt=Wikinews|Wikinews]] ዜና', 'enwikinews', sisterprojects, 0 },
{ 'Wikiversity', '[[ፋይል:Wikiversity-logo.svg|15px|link=Wikiversity|alt=Wikiversity|Wikiversity]] መምሃሪ ሃብቲ', 'enwikiversity', sisterprojects, 0 },
{ 'Wikiquote', '[[ፋይል:Wikiquote-logo.svg|15px|link=Wikiquote|alt=Wikiquote|Wikiquote]] ጥርናፈ ጥቕስታት', 'enwikiquote', sisterprojects, 0 },
{ 'Wikisource', '[[ፋይል:Wikisource-logo.svg|15px|link=Wikisource|alt=Wikisource|Wikisource]] ቤተ-መጻሕፍቲ', 'enwikisource', sisterprojects, 0 },
{ 'MediaWiki', '[[ፋይል:MediaWiki-2020-icon.svg|20px|link=MediaWiki|alt=MediaWiki|MediaWiki]] ሜድያዊኪ', 'mediawikiwiki', sisterprojects, 0 },
{ 'Meta-Wiki', '[[ፋይል:Wikimedia Community Logo.svg|15px|link=Wikimedia Meta-Wiki|alt=Meta-Wiki|Meta-Wiki]] ምውህሃድ', 'metawiki', sisterprojects, 0 },
{ 'Wikispecies', '[[ፋይል:Wikispecies-logo.svg|15px|link=Wikispecies|alt=Wikispecies|Wikispecies]] ዓይነታት', 'specieswiki', sisterprojects, 0 },
},
},
}
-- -- Example row: --
-- conf.databases[2] = {}
-- conf.databases[2].name = 'External links'
-- conf.databases[2].list = {
-- {
-- title = '',
-- group = {
-- { 'Website', 'Website', 856, 'n', 0 },
-- },
-- },
-- }
--In this order: alternate name, name of parameter from databases table
conf.aliases = {
{ 'Wd', 'Wikidata' },
{ 'PND', 'GND' },
{ 'Commonscat', 'Commons' },
}
local function getCatForId( parameter, category )
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
if category == 0 then
return ''
elseif category == 1 then
category = parameter
end
if namespace == 0 then
return '[[መደብ:ዊኪፐድያ:Articles with identifiers ' .. category .. ']]\n'
elseif namespace == 2 and not title.isSubpage then
return '[[መደብ:ዊኪፐድያ:User pages with identifiers ' .. category .. ']]\n'
else
return '[[መደብ:ዊኪፐድያ:Miscellaneous pages with identifiers ' .. category .. ']]\n'
end
end
function getIdsFromSitelinks( itemId, property )
local ids = {}
local siteLink = itemId and mw.wikibase.getSitelink( itemId, property )
if siteLink then
table.insert( ids, siteLink )
end
return ids
end
function getIdsFromWikidata( itemId, property )
local ids = {}
local statements = mw.wikibase.getBestStatements(itemId, property)
for _, statement in pairs( statements) do
if statement.mainsnak.datavalue then
table.insert( ids, statement.mainsnak.datavalue.value )
end
end
return ids
end
function getLink( property, val, mask )
local link = ''
if mw.ustring.find( val, '//' ) then
link = val
else
if type(property) == 'number' then
local entityObject = mw.wikibase.getEntityObject('P'..property)
local dataType = entityObject.datatype
if dataType == 'external-id' then
local allStatements = entityObject:getAllStatements('P1630')
if allStatements then
for pos = 1, #allStatements, 1 do
local q = allStatements[pos].qualifiers
if q and q.P407 and q.P407[1].datavalue.value.id == 'Q1321' then
link = allStatements[pos].mainsnak.datavalue.value
end
end
end
if link == '' then
local formatterURL = entityObject:getBestStatements('P1630')[1]
if formatterURL then
link = formatterURL.mainsnak.datavalue.value
else
local formatterURL = entityObject:getBestStatements('P3303')[1]
if formatterURL then link = formatterURL.mainsnak.datavalue.value end
end
end
elseif dataType == 'url' then
local subjectItem = entityObject:getBestStatements('P1629')[1]
if subjectItem then
local officialWebsite = mw.wikibase.getBestStatements(subjectItem.mainsnak.datavalue.value.id, 'P856')[1]
if officialWebsite then
link = officialWebsite.mainsnak.datavalue.value
end
end
elseif dataType == 'string' then
local formatterURL = entityObject:getBestStatements('P1630')[1]
if formatterURL then
link = formatterURL.mainsnak.datavalue.value
else
local formatterURL = entityObject:getBestStatements('P3303')[1]
if formatterURL then
link = formatterURL.mainsnak.datavalue.value
else
local subjectItem = entityObject:getBestStatements('P1629')[1]
if subjectItem then
local officialWebsite = mw.wikibase.getBestStatements(subjectItem.mainsnak.datavalue.value.id,'P856')[1]
if officialWebsite then
link = officialWebsite.mainsnak.datavalue.value
end
end
end
end
end
elseif type(property) == 'string' then
link = property
end
end
link = mw.ustring.gsub(link, '^[Hh][Tt][Tt][Pp]([Ss]?)://', 'http%1://') -- fix wikidata URL
if type(mask) == 'function' then
return mask( val, link, property )
end
link = mw.ustring.gsub(link, '$1', mw.ustring.gsub( mw.ustring.gsub( val, '%%', '%%%%' ), ' ', '%%%%20' ) or val )
if mw.ustring.find( link, '//' ) then
if type(mask) == 'string' then
link = cleanLink( link, 'PATH' )
if mask == 'y' then
return '['..link..' ID]'
elseif mask == 'n' then
return '['..link..' '..val..']'
end
return '['..link..' '..mask..']'
end
elseif link == '' then
return val
else
return '[['..link..'|'..val..']]'
end
end
local function createRow( id, label, rawValue, link, withUid )
if link then
if label and label ~= '' then label = '<span style="white-space:nowrap;">'..label .. ':</span> ' end
if withUid then
return '* ' .. label .. '<span class="uid">' .. link .. '</span>\n'
else
return '* ' .. label .. link .. '\n'
end
else
return '* <span class="error">The ' .. id .. ' id ' .. rawValue .. ' is not valid</span>[[መደብ:ዊኪፐድያ:Pages with authority control issues]]\n'
end
end
local function copyTable(inTable)
if type(inTable) ~= 'table' then return inTable end
local outTable = setmetatable({}, getmetatable(inTable))
for key, value in pairs (inTable) do outTable[copyTable(key)] = copyTable(value) end
return outTable
end
local function splitLccn( id )
if id:match( '^%l%l?%l?%d%d%d%d%d%d%d%d%d?%d?$' ) then
id = id:gsub( '^(%l+)(%d+)(%d%d%d%d%d%d)$', '%1/%2/%3' )
end
if id:match( '^%l%l?%l?/%d%d%d?%d?/%d+$' ) then
return mw.text.split( id, '/' )
end
return false
end
local p = {}
function p.authorityControl( frame )
local pArgs = frame:getParent().args
local parentArgs = copyTable(pArgs)
local stringArgs = false
local fromForCount, itemCount, rowCount = 1, 0, 0
local mobileContent = ''
--Cleanup args
for k, v in pairs( pArgs ) do
if type(k) == 'string' then
--make args case insensitive
local lowerk = mw.ustring.lower(k)
if not parentArgs[lowerk] or parentArgs[lowerk] == '' then
parentArgs[lowerk] = v
parentArgs[k] = nil
end
--remap abc to abc1
if not mw.ustring.find(lowerk, '%d$') then --if no number at end of param
if not parentArgs[lowerk..'1'] or parentArgs[lowerk..'1'] == '' then
parentArgs[lowerk..'1'] = v
parentArgs[lowerk] = nil
end
end
if v and v ~= '' then
--find highest from param
if mw.ustring.sub(lowerk,1,4) == 'from' then
local fromNumber = tonumber(mw.ustring.sub(lowerk,5,-1))
if fromNumber and fromNumber >= fromForCount then fromForCount = fromNumber end
elseif mw.ustring.sub(lowerk,1,3) == 'for' then
local forNumber = tonumber(mw.ustring.sub(lowerk,4,-1))
if forNumber and forNumber >= fromForCount then fromForCount = forNumber end
elseif mw.ustring.lower(v) ~= 'no' and lowerk ~= 'for' then
stringArgs = true
end
end
end
end
--Setup navbox
local navboxParams = {
name = 'Authority control',
bodyclass = 'hlist',
groupstyle = 'width: 12%; text-align:center;',
}
for f = 1, fromForCount, 1 do
local title = {}
--cleanup parameters
if parentArgs['from'..f] == '' then parentArgs['from'..f] = nil end
if parentArgs['for'..f] == '' then parentArgs['for'..f] = nil end
--remap aliases
for _, a in pairs( conf.aliases ) do
local alias, name = mw.ustring.lower(a[1]), mw.ustring.lower(a[2])
if parentArgs[alias..f] and not parentArgs[name..f] then
parentArgs[name..f] = parentArgs[alias..f]
parentArgs[alias..f] = nil
end
end
--Fetch Wikidata item
local itemId = parentArgs['from'..f] or mw.wikibase.getEntityIdForCurrentPage()
local label = itemId and (mw.wikibase.getSitelink(itemId) or mw.wikibase.getLabel(itemId)) or ''
if label and label ~= '' then
title = mw.title.new(label)
if not title then title = mw.title.getCurrentTitle() end
else
title = mw.title.getCurrentTitle()
end
if (not parentArgs['wikidata'..f] or parentArgs['wikidata'..f] == '') and (title.namespace == 0 or title.namespace == 104) then
parentArgs['wikidata'..f] = parentArgs['from'..f] or itemId or ''
end
if title.namespace == 0 or title.namespace == 104 or stringArgs then --Only in the main namespaces or if there are manual overrides
if fromForCount > 1 and #conf.databases > 1 then
if parentArgs['for'..f] and parentArgs['for'..f] ~= '' then
navboxParams['list'..(rowCount + 1)] = "'''" .. parentArgs['for'..f] .. "'''"
else
navboxParams['list'..(rowCount + 1)] = "'''" .. title.text .. "'''"
end
navboxParams['list'..(rowCount + 1)..'style'] = 'background-color: #ddf;'
rowCount = rowCount + 1
end
for _, db in pairs( conf.databases ) do
if db.list and #db.list > 0 then
local listElements = {}
for n, gr in pairs( db.list ) do
local groupElements = {}
if gr.group and #gr.group > 0 then
for _, params in pairs( gr.group ) do
local id = mw.ustring.lower( params[1] )
-- Wikidata fallback if requested
if itemId and params[3] ~= 0 and (not parentArgs[id..f] or parentArgs[id..f] == '') then
local wikidataIds = {}
if type( params[3] ) == 'function' then
wikidataIds = params[3]( itemId )
elseif type( params[3] ) == 'string' then
wikidataIds = getIdsFromSitelinks(itemId, params[3] )
else
wikidataIds = getIdsFromWikidata( itemId, 'P' .. params[3] )
end
if wikidataIds[1] then
parentArgs[id..f] = wikidataIds[1]
end
end
-- Worldcat
if id == 'issn' and parentArgs['worldcatid'..f] and parentArgs['worldcatid'..f] ~= '' then -- 'issn' is the first element following the 'wikidata' item
table.insert( groupElements, createRow( id, '', parentArgs['worldcatid'..f], '[//www.worldcat.org/identities/' .. parentArgs['worldcatid'..f] .. ' WorldCat]', false ) ) --Validation?
elseif id == 'viaf' and parentArgs[id..f] and string.match( parentArgs[id..f], '^%d+$' ) and not parentArgs['worldcatid'..f] then -- Hackishly copy the validation code; this should go away when we move to using P1793 and P1630
table.insert( groupElements, createRow( id, '', parentArgs[id..f], '[//www.worldcat.org/identities/containsVIAFID/' .. parentArgs[id..f] .. ' WorldCat]', false ) )
elseif id == 'lccn' and parentArgs[id..f] and parentArgs[id..f] ~= '' and not parentArgs['viaf'..f] and not parentArgs['worldcatid'..f] then
local lccnParts = splitLccn( parentArgs[id..f] )
if lccnParts and lccnParts[1] ~= 'sh' then
table.insert( groupElements, createRow( id, '', parentArgs[id..f], '[//www.worldcat.org/identities/lccn-' .. lccnParts[1] .. lccnParts[2] .. '-' .. lccnParts[3] .. ' WorldCat]', false ) )
end
end
local val = parentArgs[id..f]
if val and val ~= '' and mw.ustring.lower(val) ~= 'no' and params[3] ~= 0 then
local link
if type( params[3] ) == 'function' then
link = val
else
link = getLink( params[3], val, params[4] )
end
if link and link ~= '' then
table.insert( groupElements, createRow( id, params[2], val, link, true ) .. getCatForId( params[1], params[5] or 0 ) )
itemCount = itemCount + 1
end
end
end
if #groupElements > 0 then
if gr.title and gr.title ~= '' then
table.insert( listElements, "* '''"..gr.title.."'''\n" )
end
table.insert( listElements, table.concat( groupElements ) )
if n == 1 and #groupElements > 1 then
table.insert( listElements, "\n----\n" )
end
-- mobile version
if n == 1 then
mobileContent = table.concat( groupElements )
end
end
end
end
-- Generate navbox title
if #listElements > 0 then
if fromForCount > 1 and #conf.databases == 1 then
if parentArgs['for'..f] and parentArgs['for'..f] ~= '' then
navboxParams['group'..(rowCount + 1)] = "''" .. parentArgs['for'..f] .. "''"
else
navboxParams['group'..(rowCount + 1)] = "''" .. title.text .. "''"
end
else
navboxParams['group'..(rowCount + 1)] = db.name or ''
end
navboxParams['list'..(rowCount + 1)] = table.concat( listElements )
rowCount = rowCount + 1
end
end
end
end
end
if rowCount > 0 then
local Navbox = require('Module:Navbox')
if fromForCount > 1 then
--add missing names
for r = 1, rowCount, 1 do
if navboxParams['group'..r] == '' then
navboxParams['group'..r] = "''" .. mw.wikibase.getEntity(parentArgs['wikidata'..r]):getLabel().."''"
end
end
if fromForCount > 2 then
navboxParams['navbar'] = 'plain'
else
navboxParams['state'] = 'off'
navboxParams['navbar'] = 'off'
end
end
local mainCategories = ''
if stringArgs then
mainCategories = mainCategories .. '[[Category:ዊኪፐድያ:Pages using authority control with parameters]]\n'
end
if itemCount > 13 then
if itemCount > 30 then
itemCount = 'more than 30'
end
mainCategories = mainCategories .. '[[Category:ዊኪፐድያ:Authority control with 3 ' .. itemCount .. ' elements]]\n'
end
navboxParams['style'] = 'width: inherit';
return frame:extensionTag{ name = 'templatestyles', args = { src = 'Template:Authority control/styles.css' } }
.. tostring(
mw.html.create( 'div' )
:addClass( 'mw-authority-control' )
:wikitext( Navbox._navbox( navboxParams ) )
:done()
:tag('div')
:addClass( 'mw-mf-linked-projects' )
:addClass( 'hlist' )
:newline()
:wikitext( mobileContent )
:done()
:done()
)
.. mainCategories
else
return ''
end
end
return p