Modul:GlobalSharing
Zur Navigation springen
Zur Suche springen
Vorlagenprogrammierung | Diskussionen | Lua | Unterseiten | |||
Modul | Deutsch | English
|
Modul: | Dokumentation |
Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus
Dies ist die (produktive) Mutterversion eines global benutzten Lua-Moduls.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Versionsbezeichnung auf WikiData:
2019-11-09
local GlobalSharing = { suite = "GlobalSharing",
serial = "2019-11-09",
item = 76292536,
globals = { Multilingual = 47541920,
WikidataScheme = 74420405 } }
--[=[
Support for sharing things in the WMF world
]=]
local Failsafe = GlobalSharing
local GlobalMod = GlobalSharing
local Config = { ltr = true }
local Data = { }
local Present = { }
local Text
Config.spaces = { L = "Lexeme:",
P = "Property:",
Q = false }
Config.pages = { User = 2300,
Template = 10,
Mediawiki = 2300,
Module = 828,
Gadgets = 2300 }
Config.sites = { mediawiki = true,
wikibooks = true,
wikidata = true,
wikimedia = true,
wikinews = true,
wikipedia = true,
wikiquote = true,
wikisource = true,
wikiversity = true,
wikivoyage = true,
wiktionary = true }
Config.icons =
{ npx = 28,
download = { source = "OOjs UI icon download-ltr-progressive.svg",
support = "Update" },
home = { source = "Noun 1580514 3333ff.svg",
support = "Upstream" },
wikidata = { source = "Wikidata-logo.svg",
support = "Wikidata Logo" }
}
Config.css = { ["="] = { ["background-color"] = "#00FF00",
color = "#000000" },
[">"] = { ["background-color"] = "#FF0000",
color = "#FFFF00" },
["?"] = { ["background-color"] = "#FFFF00",
color = "#000000" },
["#"] = { display = "inline-block",
["font-size"] = "120%",
["font-weight"] = "900",
["margin-left"] = "1em",
["margin-right"] = "1em",
["padding-left"] = "1em",
["padding-right"] = "1em"
}
}
Config.errors = { bag = false }
Data.resolve = { source = { P = 1324 },
host = { P = 137 },
version = { P = 348 },
licence = { P = 275 },
usedby = { P = 1535 },
uses = { P = 2283 },
doc = { P = 973 },
doclang = { P = 407 },
iso6391 = { P = 218 },
iso6392 = { P = 219 },
tags = { P = 366 },
linksite = { Q = 677652 },
upgrade = { Q = 920419 },
upstream = { Q = 352213 },
wikidata = { Q = 2013 }
}
local foreignModule = function ( access, advanced, append, alt, alert )
-- Fetch global module
-- Precondition:
-- access -- string, with name of base module
-- advanced -- true, for require(); else mw.loadData()
-- append -- string, with subpage part, if any; or false
-- alt -- number, of wikidata item of root; or false
-- alert -- true, for throwing error on data problem
-- Postcondition:
-- Returns whatever, probably table
-- 2019-10-29
local storage = access
local finer = function ()
if append then
storage = string.format( "%s/%s",
storage,
append )
end
end
local fun, lucky, r, suited
if advanced then
fun = require
else
fun = mw.loadData
end
GlobalMod.globalModules = GlobalMod.globalModules or { }
suited = GlobalMod.globalModules[ access ]
if not suited then
finer()
lucky, r = pcall( fun, "Module:" .. storage )
end
if not lucky then
if not suited and
type( alt ) == "number" and
alt > 0 then
suited = string.format( "Q%d", alt )
suited = mw.wikibase.getSitelink( suited )
GlobalMod.globalModules[ access ] = suited or true
end
if type( suited ) == "string" then
storage = suited
finer()
lucky, r = pcall( fun, storage )
end
if not lucky and alert then
error( "Missing or invalid page: " .. storage, 0 )
end
end
return r
end -- foreignModule()
local failures = function ()
-- Summarize all faults
-- Postcondition:
-- Returns string, hopefully empty
local r
if Config.errors.bag then
local max = 1000000000
local id = math.floor( os.clock() * max )
local show = string.format( "%s * Errors",
WikidataScheme.suite )
local sign = string.format( "error_%d", id )
local errors = mw.html.create( "ul" )
:addClass( "error" )
local e = mw.html.create( "h2" )
:addClass( "error" )
:attr( "id", sign )
:wikitext( show )
for i = 1, #Config.errors.bag do
errors:newline()
:node( mw.html.create( "li" )
:addClass( "error" )
:wikitext( Config.errors.bag[ i ] ) )
end -- for i
r = string.format( "%s\n%s\n",
tostring( e ), tostring( errors ) )
show = string.format( "[[#%s|%s]]", sign, WikidataScheme.suite )
mw.addWarning( show )
end
Config.errors.bag = false
return r or ""
end -- failures()
local fault = function ( alert )
-- Format one error message in HTML
-- Precondition:
-- alert -- string, plain error message
-- Postcondition:
-- Returns string, HTML error message
local e = mw.html.create( "span" )
:addClass( "error" )
:wikitext( alert )
Config.errors.bag = Config.errors.bag or { }
table.insert( Config.errors.bag, alert or "??fault??" )
return tostring( e )
end -- fault()
local first = function ( atleast, actual )
-- Check whether local version is matched
-- Precondition:
-- atleast -- string, with global version, or not
-- actual -- string, with local version, or not
-- Postcondition:
-- Returns
-- "=", if equal
-- ">", if update recommended
-- "<", if local newer than global (may be upstream)
-- "?", if strange data
-- else unknown
local r
if type( atleast ) == "string" and
type( actual ) == "string" then
local sg = mw.text.trim( atleast )
local sl = mw.text.trim( actual )
if sg == sl then
r = "="
elseif sg == "" or sl == "" then
r = "?"
elseif sg:match( "^[0-9.]+$" ) and
sl:match( "^[0-9.]+$" ) then
local f = function ( a )
if not a or a == "" then
return -1
end
return tonumber( a )
end
local vg = mw.text.split( sg, "%.+" )
local vl = mw.text.split( sl, "%.+" )
local kg, kl
r = "?"
for i = 1, #vg do
kg = f( vg[ i ] )
kl = f( vl[ i ] )
if kg < 0 or kl < 0 then
break -- for i
elseif kg > kl then
r = ">"
break -- for i
else
r = "="
end
end -- for i
if r == "=" and #vl > #vg then
r = "?"
end
elseif sg > sl then
r = ">"
else
r = "<"
end
end
return r
end -- first()
local found = function ( at, area )
-- Check whether local source code (copy) is present
-- Precondition:
-- at -- string, with local page name
-- area -- number, of required namespace
-- Postcondition:
-- Returns
-- title object, if appropriate
-- string, if bad page name
-- nil, if not found
local t = mw.title.new( at )
local r
if t and t.exists then
if t.namespace == area or
( area == 10 and t.namespace == 4 ) then
r = t
else
r = at
end
end
return r
end -- found()
Config.fetch = function ( access, at )
-- Retrieve external module
-- Precondition:
-- access -- string, with requested name
-- at -- table, for hosting
if not at[ access ] and at[ access ] ~= false then
local bib = foreignModule( access,
true,
false,
GlobalSharing.globals[ access ],
true )
if type( bib ) == "table" and
type( bib[ access ] ) == "function" then
at[ access ] = bib[ access ]()
else
at[ access ] = false
end
end
end -- Config.fetch()
Config.first = function ()
-- Initialize generally
Config.fetch( "Multilingual", Present )
Config.fetch( "WikidataScheme", GlobalSharing )
if GlobalSharing.WikidataScheme then
Text = GlobalSharing.WikidataScheme.Text
Text.flipper( GlobalSharing.suite )
end
end -- Config.first()
Config.from = function ()
-- Initialize current site
-- Postcondition:
-- Returns string, with normalized site
if not Config.server then
local i
Config.server = mw.site.server
if Config.server:sub( 1, 2 ) == "//" then
Config.server = "https:" .. Config.server
end
i = Config.server:find( "[/.]m%." )
if i and i < 20 then
Config.server = Config.server:sub( 1, i + 1 ) ..
Config.server:sub( i + 4 )
end
if Config.server:sub( -1, 1 ) == "/" then
Config.server = Config.server:sub( 1, #Config.server - 1 )
end
end
return Config.server
end -- Config.from()
Data.father = function ( all )
-- Check whether source matches upstream condition
-- Precondition:
-- all -- item object
-- Postcondition:
-- Returns mw.html object, or not
local source = Data.find( all, "source", 1 )
local r
if source then
local start = Config.from() .. "/wiki/"
if source:find( start ) == 1 then
local i
start = source:sub( #start + 1 )
i = start:find( ":" )
if i > 2 then
local space = start:sub( 1, i - 1 )
if ( Config.pages[ space ] ) then
local t = mw.title.makeTitle( space,
start:sub( i + 1 ) )
if not Config.title then
Config.title = mw.title.getCurrentTitle()
end
r = mw.title.equals( Config.title, t )
end
end
end
end
return r
end -- Data.father()
Data.fetch = function ( access )
-- Resolve entity name
-- Precondition:
-- access -- string, with entity name or ID
-- Postcondition:
-- Returns string or not, with entity ID
local r
if access:find( "^[PQL]%d+$" ) then
r = access
elseif type( Data.resolve[ access ] ) == "table" then
local entry = Data.resolve[ access ]
if type( entry ) == "table" then
for k, v in pairs( Config.spaces ) do
if type( entry[ k ] ) == "number" then
r = string.format( "%s%d", k, entry[ k ] )
break -- for k, v
end
end -- for k, v
end
end
return r
end -- Data.fetch()
Data.final = function ( all )
-- Retrieve upstream source code URL
-- Precondition:
-- all -- item object
-- Postcondition:
-- Returns string, or not
local t = Data.full( 0 )
local r
if t then
r = all.id:match( "^Q(%d+)$" )
r = t[ tonumber( r ) ]
if type( r ) ~= "string" or
r:sub( 1, 8 ) ~= "https://" then
r = false
else
local seek = "^https://[a-z_.]+%.(%l+)%.org/wiki/(%u%l+):"
local site, space = r:match( seek )
if Config.sites[ site ] then
space = Config.pages[ space ]
if space ~= 10 and space ~= 828 then
r = false
end
else
r = false
end
end
end
return r
end -- Data.final()
Data.find = function ( all, assign, at )
-- Retrieve entity value
-- Precondition:
-- all -- item object
-- assign -- string, with entity name
-- at -- number, with value counter, or not
-- Postcondition:
-- Returns
-- 1. value, or not
-- 2. qualifiers, if any
local r1, r2
if type( assign ) == "string" then
local k = at or 1
local s = Data.fetch( assign )
local d = all.claims
if s and
type( d ) == "table" and
type( d[ s ] ) == "table" and
type( d[ s ][ k ] ) == "table" then
d = d[ s ][ k ]
if type( d.mainsnak ) == "table" and
type( d.mainsnak.datavalue ) == "table" then
r1 = d.mainsnak.datavalue.value
if type( d.qualifiers ) == "table" then
r2 = d.qualifiers
end
end
end
end
return r1, r2
end -- Data.find()
Data.full = function ( area )
-- Retrieve one Data.tab element
-- Precondition:
-- area -- number, of collection; 0 for URL, 10, 828, 2300
-- Returns: table, or not
-- 0 -- map, item -> URL
-- else -- sequence of Q
local r
Data.collections = Data.collections or { }
r = Data.collections[ area ]
if type( r ) == "nil" and type( area ) == "number" then
local storage = string.format( "%s/%d.tab",
GlobalSharing.suite, area )
local lucky, data = pcall( mw.ext.data.get, storage )
r = false
if type( data ) == "table" and
type( data.data ) == "table" then
data = data.data
if #data > 0 then
local low = ( area ~= 0 )
local dup = { }
local entry, k
r = { }
for i = 1, #data do
entry = data[ i ]
if type( entry ) == "table" then
k = entry[ 1 ]
if low then
if not dup[ k ] then
table.insert( r, k )
dup[ k ] = true
end
else
r[ k ] = entry[ 2 ]
end
end
end -- for i
if type( k ) ~= "number" or
( low and type( entry[ 2 ] ) ~= "string" ) then
r = false
end
end
end
Data.collections[ area ] = r
end
return r
end -- Data.full()
Present.facet = function ( access )
-- Create decorated Wikidata link
-- Precondition:
-- access -- string, with item ID
-- Postcondition:
-- Returns mw.html object
local r = mw.html.create( "span" )
local s = string.format( "[[d:%s|%s]]", access, access )
r:node( Present.flag( "wikidata" ) )
:newline()
:node( mw.html.create( "code" )
:attr( "dir", "ltr" )
:attr( "lang", "zxx" )
:wikitext( s ) )
return r
end -- Present.facet()
Present.failsafe = function ( about, atleast )
-- Check local version
-- Precondition:
-- about -- mw.title object
-- atleast -- string, with global version
-- Postcondition:
-- Returns mw.html object, or not
local r
if about.namespace == 828 and type( atleast ) == "string" then
local lucky, x = pcall( require, about.prefixedText )
if type( x ) == "table" and x.failsafe then
local s = type( x.failsafe )
if s == "function" then
s = x.failsafe()
elseif s == "string" then
s = x.failsafe
else
s = false
end
if s then
r = first( atleast, s )
if r then
local e, css
if r == ">" or r == "<" then
s = mw.text.nowiki( tostring( s ) )
e = mw.html.create( "code" )
:wikitext( s )
if r == "<" then
r = "?"
end
end
css = Config.css[ r ]
r = mw.html.create( "span" )
:css( Config.css[ "#" ] )
:wikitext( mw.text.nowiki( r ) )
if css then
r:css( css )
end
if e then
r = mw.html.create( "span" )
:node( r )
:node( e )
end
end
end
end
end
return r
end -- Present.failsafe()
Present.father = function ()
-- Create decorated upstream indicator
-- Postcondition:
-- Returns mw.html object
if not Present.upstream then
local e = mw.html.create( "span" )
:attr( { dir = "ltr",
lang = "en",
title = "Upstream" } )
:css( { ["background-color"] = "#B0FFB0" } )
local s = "Upstream"
if Data.resolve.upstream and
Data.resolve.upstream.Q then
local sq = string.format( "Q%d", Data.resolve.upstream.Q )
local sl = mw.wikibase.getSitelink( sq )
if not sl then
sl = mw.wikibase.getSitelink( sq, "enwiki" )
if sl then
sl = "w:en:" .. sl
end
end
if sl then
s = string.format( "[[%s|%s]]", sl, s )
end
end
e:wikitext( s )
Present.upstream = mw.html.create( "span" )
:node( Present.flag( "home" ) )
:newline()
:node( e )
end
return Present.upstream
end -- Present.father()
Present.features = function ( access, adjust )
-- Description term etc. of one item
-- Precondition:
-- access -- number, of item
-- adjust -- table, with options
-- .locally -- local sources only
-- .namespace -- number, of repo resource
-- .wikidata -- show link to item
-- .linksite -- show link to page
-- .source -- show link to local source
-- .host -- show link to global source host
-- Postcondition:
-- Returns
-- 1. table, with sequence of mw.html objects DT, DD, DD, DD
-- or not, if unavailable local source queried
-- 2. string, with sort key
local s = string.format( "Q%d", access )
local e, q, r1, r2, slang, source
if mw.wikibase.isValidEntityId( s ) and
mw.wikibase.entityExists( s ) then
q = mw.wikibase.getEntity( s )
end
if q and adjust.locally then
source = Present.fresh( q, adjust.namespace )
if not source then
q = false
end
end
s = type( q )
if s == "table" then
s, slang = Present.wikibase( q, false )
if s then
r2 = s:lower()
if adjust.linksite then
if q.sitelinks then
Config.site = Config.site or
mw.wikibase.getGlobalSiteId()
e = q.sitelinks[ Config.site ]
if e and e.title then
s = string.format( "[[%s|%s]]", e.title, s )
end
end
else
s = Present.find( q, s )
end
e = Text.html( s, "dt", false, slang )
else
e = mw.html.create( "dt" )
:node( mw.html.create( "code" )
:attr( "dir", "ltr" )
:attr( "lang", "zxx" )
:wikitext( string.format( "Q%d",
access )
) )
end
elseif s == "nil" then
e = mw.html.create( "dt" )
:wikitext( fault( Text.flip( "err_ItemUnknown" ) ) )
:node( mw.html.create( "code" )
:attr( "dir", "ltr" )
:attr( "lang", "und" )
:css( "margin-left", "1em" )
:css( "margin-right", "1em" )
:wikitext( string.format( "Q%d",
access ) ) )
end
if e then
r1 = { }
table.insert( r1, e )
if not r2 then
r2 = string.format( "#%d", access )
end
end
if q then
local f = function ( add, alien, attr )
e = Text.html( tostring( add ),
"dd",
false,
alien )
if attr then
e:attr( attr )
end
table.insert( r1, e )
end
s, slang = Present.wikibase( q, true )
if s then
f( s, slang )
end
if adjust.wikidata then
f( Present.facet( q.id ) )
end
if adjust.source then
Present.from( q, adjust, f )
end
if adjust.version or adjust.locally then
s = Data.find( q, "version", 1 )
if s then
e = mw.html.create( "code" )
:attr( "dir", "ltr" )
:attr( "lang", "zxx" )
:wikitext( s )
if type( source ) == "table" then
s = Present.failsafe( source, s )
if s then
e:newline()
:node( s )
end
end
f( e, "zxx", { dir = "ltr" } )
end
end
end
return r1, r2
end -- Present.features()
Present.final = function ( all, apply )
-- Present link to validated upstream source URL
-- Precondition:
-- all -- item object
-- apply -- string, with protected source URL, or not
-- Postcondition:
-- Returns mw.html object, or not
local r
if type( apply ) == "string" then
local source, q = Data.find( all, "source", 1 )
if source == apply then
local store = string.format( "Q%d", Data.resolve.upgrade.Q )
local show = mw.wikibase.getSitelink( store )
local slang
if show then
if not Config.slang then
Config.slang = mw.language.getContentLanguage()
:getCode()
:lower()
end
slang = Config.slang
else
store = Data.fetch( "host" )
if q[ store ] then
q = q[ store ]
if q[ 1 ] then
store = q[ 1 ].datavalue.value.id
show = Present.wikibase( store )
end
end
end
show = show or "Upgrade"
show = string.format( "[%s %s]", apply, show )
r = Text.html( show, "span", false, slang )
r = mw.html.create( "span" )
:node( Present.flag( "download" ) )
:newline()
:node( r )
end
end
return r
end -- Present.final()
Present.find = function ( all, appear )
-- Try to create doc URL link
-- Precondition:
-- all -- item object
-- appear -- link title
-- Postcondition:
-- Returns string
local r = appear
local i = 1
local url = true
local collection, q, s, s1, s2, slang, store, t
while url do
url, q = Data.find( all, "doc", i )
if url then
collection = collection or { }
slang = false
if q then
store = store or Data.fetch( "doclang" )
if q[ store ] then
q = q[ store ]
for k = 1, #q do
t = q[ k ].datavalue.value
if t and t.id then
s = t.id
s1 = s1 or Data.fetch( "iso6391" )
t = mw.wikibase.getBestStatements( s, s1 )
if t[ 1 ] then
slang = t[ 1 ].mainsnak.datavalue.value
else
s2 = s2 or Data.fetch( "iso6392" )
t = mw.wikibase.getBestStatements( s,
s2 )
slang = t[ 1 ].mainsnak.datavalue.value
end
end
end -- k = 1, #q
end
end
slang = slang or "und"
if not collection[ slang ] then
collection[ slang ] = url
end
end
i = i + 1
end -- while q
if collection then
s = Text.find( collection )
if s then
r = string.format( "[%s %s]", s, r )
end
end
return r
end -- Present.find()
Present.flag = function ( ask )
-- Create icon
-- Postcondition:
-- Returns mw.html object
if not Present[ ask ] then
local c = Config.icons[ ask ]
local e = mw.html.create( "span" )
:attr( { ["aria-hidden"] = "true",
role = "presentation" } )
local s = string.format( "[[File:%s|%dpx|%s|%s]]",
c.source,
Config.icons.npx,
"class=noviewer",
c.support )
e:wikitext( s )
if Config.ltr then
s = "right"
else
s = "left"
end
e:css( "margin-" .. s, "1em" )
Present[ ask ] = e
end
return Present[ ask ]
end -- Present.flag()
Present.focus = function ( all )
-- Present one single item object
-- Precondition:
-- all -- item object
-- Postcondition:
-- Returns mw.html object
local r
if all and all.id then
local f = function ( add )
r:node( mw.html.create( "br" ) )
:newline()
:node( add )
end
local s, slang
r = mw.html.create( "div" )
:addClass( "plainlinks" )
:newline()
:node( Present.facet( all.id ) )
s, slang = Present.wikibase( all, false )
if s then
s = Present.find( all, s )
f( Text.html( s, "span", false, slang ) )
end
s, slang = Present.wikibase( all, true )
if s then
f( Text.html( s, "span", false, slang ) )
end
s = Data.find( all, "version", 1 )
if s then
f( mw.html.create( "code" )
:attr( "dir", "ltr" )
:wikitext( s ) )
end
if Data.father( all ) then
f( Present.father() )
else
s = Present.final( all, Data.final( all ) )
if s then
f( s )
end
end
r:newline()
end
return r
end -- Present.focus()
Present.fresh = function ( all, area )
-- Check whether local source code (copy) is present
-- Precondition:
-- all -- item object
-- area -- number, of namespace
-- Postcondition:
-- Returns
-- title object, if appropriate
-- string, if error message
-- nil, if not found
local r, s
if all.sitelinks then
local wiki
Config.site = Config.site or mw.wikibase.getGlobalSiteId()
wiki = all.sitelinks[ Config.site ]
if wiki and wiki.title then
r = found( wiki.title, area )
if type( r ) == "string" then
s = "err_SourceSitelink"
end
end
end
if not r then
r = Data.find( all, "source", 1 )
if r then
r = r:match( "^https://[^/]+/wiki/(.+:.+)$" )
if r then
r = found( r, area )
s = type( r )
if s == "string" then
s = "err_SourceWikidataBad"
elseif s == "table" then
s = false
else
s = "err_SourceUnregistered"
end
else
s = "err_SourceWikidataInvalid"
end
end
end
if s then
s = fault( Text.flip( s ) )
if type( r ) == "string" then
local e = mw.html.create( "em" )
:attr( "dir", "ltr" )
:attr( "lang", "zxx" )
:wikitext( r:gsub( "//", "//" ) )
r = string.format( "%s %s", s, tostring( e ) )
else
r = s
end
end
return r
end -- Present.fresh()
Present.from = function ( all, adjust, apply )
-- Present link to validated upstream source URL
-- Precondition:
-- all -- item object
-- adjust -- table, with options
-- .host -- show info about global source host
-- apply -- function, to drop result lines
local source, q = Data.find( all, "source", 1 )
if type( source ) == "string" then
local s = Data.final( all )
if s == source then
local seek = "^https://([^/ ]+%.org)/wiki/(%S*)$"
local e, site
site, s = source:match( seek )
if s then
local f = function ()
return mw.html.create( "span" )
:css( { display = "inline-block",
width = "2em" } )
:wikitext( " " )
end
s = string.format( "[%s %s]", source, s )
e = mw.html.create( "span" )
:attr( "dir", "ltr" )
:attr( "lang", "zxx" )
:wikitext( s )
if source:find( Config.from() .. "/wiki/" ) == 1 then
e:newline()
:node( f() )
:newline()
:node( Present.father() )
q = false
end
apply( e )
if q and adjust.host then
local ex, slang
s = string.format( "[https://%s/ %s]", site, site )
e = mw.html.create( "em" )
:attr( "dir", "ltr" )
:attr( "lang", "zxx" )
:wikitext( s )
s = Data.fetch( "host" )
if q[ s ] then
q = q[ s ]
if q[ 1 ] then
ex = q[ 1 ].datavalue.value.id
s, slang = Present.wikibase( ex, true )
if s then
e = mw.html.create( "span" )
:node( e )
:newline()
:node( f() )
:newline()
:node( Text.html( s,
"span",
false,
slang ) )
end
end
end
apply( e )
end
end
end
elseif s then
apply( fault( Text.flip( "err_SourceUnregistered" ) ) )
end
end -- Present.from()
Present.full = function ( array, adjust )
-- Description list of entire area
-- Precondition:
-- array -- table, with non-empty sequence of item numbers
-- adjust -- table, with options
-- Postcondition:
-- Returns mw.html object, or not
local entries = { }
local order = { }
local entry, r, sort
for i = 1, #array do
entry, sort = Present.features( array[ i ], adjust )
if entry then
entries[ sort ] = entry
table.insert( order, sort )
end
end -- for i
if #order then
r = mw.html.create( "dl" )
:addClass( "plainlinks" )
if not adjust.lazy then
table.sort( order )
end
for i = 1, #order do
entry = entries[ order[ i ] ]
for k = 1, #entry do
r:newline()
:node( entry[ k ] )
end -- for k
end -- for i
Text.fashion( r, adjust )
Text.flow( r )
if type( adjust.id ) == "string" then
r:attr( "id", adjust.id )
end
r:newline()
end
return r
end -- Present.full()
Present.wikibase = function ( all, about, attempt )
-- Translation of wikibase component
-- Precondition:
-- all -- string or table, object ID or entity
-- about -- boolean, true "descriptions" or false "labels"
-- attempt -- string or not, code of preferred language
-- Postcondition:
-- Returns
-- 1. string, with selected message, or not
-- 2. string, with language code, or not
local r1, r2
if Present.Multilingual then
r1, r2 = Present.Multilingual.wikibase( all,
about,
attempt,
Config.frame )
else
local s = type( all )
local object
if s == "table" then
object = all
elseif s == "string" then
if mw.wikibase.isValidEntityId( all ) and
mw.wikibase.entityExists( all ) then
object = mw.wikibase.getEntity( all )
end
r1 = all
end
if type( object ) == "table" then
if about then
s = "descriptions"
else
s = "labels"
end
object = object[ s ]
if type( object ) == "table" then
if object[ attempt ] then
r1 = object[ attempt ].value
r2 = attempt
elseif object.en then
r1 = object.en.value
r2 = "en"
else
local poly
for k, v in pairs( object ) do
r1 = v.value
r2 = k
break -- for k, v
end -- for k, v
end
end
end
end
return r1 or "????????", r2
end -- Present.wikibase()
local Collection = function ( action, area, add )
-- Present all registered shared things in one area
-- Precondition:
-- action -- false->"full" or true->"fresh"
-- area -- number, nonzero, of area
-- add -- table, with options, or not
-- Postcondition:
-- Returns string, HTML code
local r
Config.first()
if type( area ) == "number" and area ~= 0 then
local q
if type( add ) == "table" and
type( add.items ) == "string" then
q = mw.text.split( add.items, "%s+" )
for i = 1, #q do
q[ i ] = tonumber( q[ i ] )
end -- for i
else
q = Data.full( area )
end
if q then
local o = { }
if type( add ) == "table" then
for k, v in pairs( add ) do
if v ~= "0" and v ~= "-" then
o[ k ] = v
end
end -- for k, v
end
if action then
o.linksite = true
if area == 10 or area == 828 then
o.locally = true
end
elseif area == 4 then
o.lazy = true
o.linksite = true
o.locally = true
end
o.namespace = area
if o.version or o.source then
o.wikidata = true
end
r = Present.full( q, o )
if r then
r = tostring( r )
end
else
r = fault( Text.flip( "err_CollectionUnknown" ) )
end
else
r = fault( Text.flip( "err_CollectionInvalid" ) )
end
return r or ""
end -- Collection()
GlobalSharing.fetch = function ( access )
-- Retrieve item object
-- Precondition:
-- access -- string, or number, of item
-- Postcondition:
-- Returns table -- with item object
-- string -- with missing item ID
-- false -- if not appropriate
local s = type( access )
local r
if s == "number" and
access > 0 and
math.floor( access ) == access then
r = string.format( "Q%d", access )
elseif s == "string" and
access:match( "^Q[1-9]%d*$" ) then
r = access
end
if r and
mw.wikibase.isValidEntityId( r ) and
mw.wikibase.entityExists( r ) then
r = mw.wikibase.getEntity( r )
end
return r or false
end -- GlobalSharing.fetch()
GlobalSharing.focus = function ( access )
-- Present one single item object
-- Precondition:
-- access -- string, or number, of item
-- Postcondition:
-- Returns table -- with item object
-- false -- if not appropriate
local q = GlobalSharing.fetch( access )
local r
if type( q ) == "table" then
Config.first()
r = Present.focus( q )
end
return r or false
end -- GlobalSharing.focus()
GlobalSharing.fresh = function ( area, add )
-- Present state of local pages of registered transcludes
-- Precondition:
-- area -- number, nonzero, of area
-- add -- table, with options, or not
-- Postcondition:
-- Returns string, HTML code
return Collection( true, area, add )
end -- GlobalSharing.fresh()
GlobalSharing.full = function ( area, add )
-- Present all registered shared things in one area
-- Precondition:
-- area -- number, nonzero, of area
-- add -- table, with options, or not
-- Postcondition:
-- Returns string, HTML code
return Collection( false, area, add )
end -- GlobalSharing.full()
local Template = function ( action, frame )
local params = { }
local f = function ( a )
for k, v in pairs( a.args ) do
if type( v ) == "string" then
v = mw.text.trim( v )
if v ~= "" and v ~= "-" then
if type( k ) == "number" then
k = tostring( k )
end
params[ k ] = v
end
end
end -- for k, v
end
local lucky, plus, r, s
Config.frame = frame
f( frame )
f( frame:getParent() )
s = params[ "1" ]
if action == "focus" then
if s then
if s:match( "^Q[1-9]%d*$" ) then
elseif s:match( "^[1-9]%d*$" ) then
s = "Q" .. s
else
s = false
end
else
s = mw.wikibase.getEntityIdForCurrentPage()
end
lucky = s
elseif s and s:match( "^[1-9]%d*$" ) then
s = tonumber( s )
lucky = s
if action == "full" then
local i, sp
for k, v in pairs( params ) do
if Data.resolve[ k ] then
sp = k
else
i = k:match( "^P?([1-9]%d+)$" )
if i then
i = tonumber( i )
for kk, vv in pairs( Data.resolve ) do
if vv.P == i or vv.Q == i then
sp = kk
break -- for kk, vv
end
end -- for kk, vv
end
end
if sp then
plus = plus or { }
if v ~= "0" then
plus[ sp ] = true
end
sp = false
end
end -- for k, v
-- version=
-- P348=
-- 348=
end
end
if lucky then
lucky, r = pcall( GlobalSharing[ action ], s, plus )
if type( r ) == "table" then
r = tostring( r )
end
if r then
s = params[ "wrap" ]
if s and s:find( "$1", 1, true ) then
r = s:gsub( "$1", r )
end
end
end
return r or ""
end -- Template()
Failsafe.failsafe = function ( atleast )
-- Retrieve versioning and check for compliance
-- Precondition:
-- atleast -- string, with required version or "wikidata" or "~"
-- or false
-- Postcondition:
-- Returns string -- with queried version, also if problem
-- false -- if appropriate
-- 2019-10-15
local last = ( atleast == "~" )
local since = atleast
local r
if last or since == "wikidata" then
local item = Failsafe.item
since = false
if type( item ) == "number" and item > 0 then
local entity = mw.wikibase.getEntity( string.format( "Q%d",
item ) )
if type( entity ) == "table" then
local seek = Failsafe.serialProperty or "P348"
local vsn = entity:formatPropertyValues( seek )
if type( vsn ) == "table" and
type( vsn.value ) == "string" and
vsn.value ~= "" then
if last and vsn.value == Failsafe.serial then
r = false
else
r = vsn.value
end
end
end
end
end
if type( r ) == "nil" then
if not since or since <= Failsafe.serial then
r = Failsafe.serial
else
r = false
end
end
return r
end -- Failsafe.failsafe()
-- Export
local p = { }
p.focus = function ( frame )
return Template( "focus", frame )
end -- p.focus
p.fresh = function ( frame )
return Template( "fresh", frame )
end -- p.fresh
p.full = function ( frame )
return Template( "full", frame )
end -- p.full
p.failsafe = function ( frame )
-- Versioning interface
local s = type( frame )
local since
if s == "table" then
since = frame.args[ 1 ]
elseif s == "string" then
since = frame
end
if since then
since = mw.text.trim( since )
if since == "" then
since = false
end
end
return Failsafe.failsafe( since ) or ""
end -- p.failsafe()
p.GlobalSharing = function ()
return GlobalSharing
end -- p.GlobalSharing
return p