Modul:WikidataScheme
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-12-16
local WikidataScheme = { suite = "WikidataScheme",
serial = "2019-12-16",
item = 74420405,
globals = { Multilingual = 47541920 } }
--[=[
Pattern for new entities on Wikidata as internationalized guide
]=]
local Failsafe = WikidataScheme
local GlobalMod = WikidataScheme
local Config = { }
local JSONexport = { }
local Resolver = { }
local Table = { }
local Text = { }
Config.coded = { dir = "ltr",
lang = "en" }
Config.colors = { tableheadbg = "B3B7FF",
required = "EAF3FF",
suggested = "FFFFFF",
optional = "EAECF0",
deprecated = "FFCBCB" }
Config.spaces = { L = "Lexeme:",
P = "Property:",
Q = false }
Config.types = { "P", "Q", "L" }
Config.errors = { bag = false }
Config.i18n = { onLabel = "Q461984", -- naming convention
onDesc = "Q1200750", -- description
-- wikibase-newentity-description
onAlias = "wikibase-entitytermsforlanguagelistview-aliases" }
-- Q18616576 Wikidata property
-- Q19798642 Wikidata value
Config.defaults = { err_BadExample = "Invalid property example",
-- ToDo: I18n
err_BadQualifier = "Invalid qualifier definition",
err_InvalidClaim = "Invalid claim",
err_InvalidNameType = "Invalid entity name type",
err_NameBad = "is no assigned entity name",
err_NameEmpty = "entity name empty",
err_NameMissed = "unresolved",
err_NoEntity = "is not an entity",
err_NoNameResolver = "needs",
err_NoProperty = "is not a Property",
err_q_qlist = "Both q and qlist specified",
err_Unguided = "Missing guidance"
}
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 fix = function ( adjust )
-- Escape and trim string
-- Precondition:
-- adjust -- string, with some text
-- Postcondition:
-- Returns string, with some text
return mw.text.trim( adjust ):gsub( "\\", "\\\\" )
:gsub( "\"", "\\\"" )
end -- fix()
Config.feature = function ( area, about, allow )
local r
if Config.options then
end
return r
end -- Config.feature()
Config.field = function ( ask )
-- Retrieve general I18n text
-- Precondition:
-- ask -- string, with text ID, entity ID or system message
-- Postcondition:
-- Returns string, with message
local r
Config.texts = Config.texts or { }
r = Config.texts[ ask ]
if not r then
r = Config.i18n[ ask ]
if type( r ) == "string" then
if r:match( "^Q%d+$" ) then
r = Text.wikibase( r )
else
r = mw.message.new( r ):plain()
end
Config.texts[ ask ] = r
end
end
return r or "??????????"
end -- Config.field()
Config.first = function ()
-- Initialize or reset Config
if not Config.statelist then
Config.css = { }
Config.statelist = { }
for k, v in pairs( Config.colors ) do
if k == "tableheadbg" then
k = "tablehead"
else
Config.statelist[ k ] = true
end
Config.css[ k ] = { ["background-color"] = "#" .. v }
end -- for k, v
end
Config.options = false
-- aus /config neu, mit .Request überschreiben
end -- Config.first()
JSONexport.family = function ( assign, access, align, adjust )
-- Create list of claims or qualifiers
-- Precondition:
-- assign -- table, with definition of element
-- access -- string, with key in assign
-- align -- number, level of alignment
-- adjust -- true, for resolving symbolic IDs
-- Postcondition:
-- Returns string with extended JSON code, or not
local collect = assign[ access ]
local r
if type( collect ) == "table" then
local indent = align + 1
local n = #collect
local shift = string.rep( " ", align )
local list
if align > 1 and type( assign.list ) == "boolean" then
list = assign.list
r = string.format( "%s\"%s\": %s",
shift, tostring( list ) )
else
r = ""
end
if n > 0 then
local sep = ""
if list then
r = string.format( "%s\n%s", r, shift )
end
r = string.format( "%s%s\"%s\": [",
r, shift, access )
for i = 1, n do
r, sep = JSONexport.fiat( collect[ i ],
indent,
r,
sep,
adjust )
end -- for i
r = string.format( "%s\n%s%s ]",
r, shift, string.rep( " ", #access ) )
end
end
return r
end -- JSONexport.family()
JSONexport.favour = function ( all )
-- Create resolve component
-- Precondition:
-- all -- table, with entire request
local r
if type( all.resolve ) == "table" then
local n = 0
local order = { }
local j, coll, s
for k, v in pairs( all.resolve ) do
if type( k ) == "string" and
type( v ) == "table" then
k = mw.text.trim( k )
if k ~= "" then
for i = 1, #Config.types do
s = Config.types[ i ]
j = v[ s ]
if type( j ) == "number" and
j >= 0 and
j == math.floor( j ) then
coll = coll or { }
k = fix( k )
coll[ k ] = string.format( "{ \"%s\": %d }",
s, j )
table.insert( order, k )
j = mw.ustring.len( k )
if j > n then
n = j
end
break -- for i
end
end -- for i
end
end
end -- for k, v
if #order > 0 then
local sep = ""
local k, v
table.sort( order )
r = " \"resolve\": { "
n = n + 1
for i = 1, #order do
k = order[ i ]
v = coll[ k ]
j = mw.ustring.len( k )
s = string.rep( " ", n - mw.ustring.len( k ) )
r = string.format( "%s%s\"%s\": %s%s",
r, sep, k, s, v )
sep = ",\n "
end -- for k, v
r = r .. "\n }"
end
end
return r
end -- JSONexport.favour()
JSONexport.features = function ( assign, align, adjust )
-- Create value element
-- Precondition:
-- assign -- table, with definition of value
-- align -- number, level of alignment
-- adjust -- true, for resolving symbolic IDs
-- Postcondition:
-- Returns string, if not empty
local r
if type( assign ) == "table" then
local indent = align + 1
local shift = string.rep( " ", align )
local f = function ( a )
if a and a ~= "" then
if r then
r = string.format( "%s,\n%s", r, a )
else
r = "\n" .. a
end
end
end -- f()
f( JSONexport.flat( assign, "intro", indent ) )
f( JSONexport.filled( assign, indent, adjust ) )
f( JSONexport.fixed( assign, "q", indent, adjust ) )
f( JSONexport.fixed( assign, "qdefault", indent, adjust ) )
f( JSONexport.fixed( assign, "qqexample", indent, adjust ) )
f( JSONexport.flat( assign, "example", indent ) )
f( JSONexport.family( assign, "qualifiers", indent, adjust ) )
f( JSONexport.flat( assign, "terminate", indent ) )
if r then
r = string.format( "%s {%s\n%s }",
shift, r, shift )
end
end
return r
end -- JSONexport.features()
JSONexport.fetch = function ( access, adjust, alike )
-- Resolve symbolic entity name, if necessary
-- Precondition:
-- access -- string, with entity name or ID
-- adjust -- true, for resolving symbolic IDs
-- alike -- string, if Property or Item required
-- Postcondition:
-- Returns: string, if valid, with quoted thing
local r
if type( access ) == "string" then
local s = mw.text.trim( access )
if s ~= "" then
if adjust then
r = Resolver.fetch( s, alike )
else
r = s
end
if r then
r = string.format( "\"%s\"",
r:gsub( "\"", "" )
:gsub( "\\", "" ) )
end
end
end
return r
end -- JSONexport.fetch()
JSONexport.fiat = function ( assign, align, apply, after, adjust )
-- Create independent entry (in claims or qualifiers) as JSON
-- Precondition:
-- assign -- table, with definition of element
-- align -- number, level of alignment
-- apply -- string, with JSON code to be extended
-- after -- string, with preceding separator
-- adjust -- true, for resolving symbolic IDs
-- Postcondition:
-- Extend apply if element present
-- Returns:
-- 1. string with extended JSON code
-- 2. separator, for next element
local r = apply
local r2 = after
if type( assign ) == "table" then
local s = JSONexport.fetch( assign.subject, adjust, true )
if s then
local shift = string.rep( " ", align )
local indent = align + 1
local f = function ( a )
if a and a ~= "" then
if r then
r = string.format( "%s,\n%s", r, a )
else
r = "\n" .. a
end
end
end -- f()
local state
r = string.format( "%s%s\n%s{ \"subject\": %s",
r, r2, shift, s )
f( JSONexport.flat( assign, "intro", indent ) )
if Config.statelist[ assign.state ] then
state = assign.state
else
state = "optional"
end
r = string.format( "%s,\n%s \"state\": \"%s\"",
r, shift, state )
f( JSONexport.filled( assign, indent, adjust ) )
f( JSONexport.fixed( assign, "q", indent, adjust ) )
f( JSONexport.fixed( assign, "qdefault", indent, adjust ) )
f( JSONexport.fixed( assign, "qqexample", indent, adjust ) )
if type( assign.values ) == "table" then
local vals = { }
local v
for i = 1, #assign.values do
v = JSONexport.features( assign.values[ i ],
indent,
adjust )
if v then
table.insert( vals, v )
end
end -- for i
if #vals then
local sep = ""
r = string.format( "%s,\n%s \"values\": [",
r, shift )
for i = 1, #vals do
r = string.format( "%s%s\n%s %s",
r, sep, shift, vals[ i ] )
sep = ","
end -- for i
r = string.format( "%s\n%s ]", r, shift )
end
end
f( JSONexport.flat( assign, "example", indent ) )
f( JSONexport.flat( assign, "terminate", indent ) )
f( JSONexport.further( assign, "class", indent ) )
f( JSONexport.further( assign, "style", indent ) )
r = string.format( "%s\n%s}", r, shift )
r2 = ","
end
end
return r, r2
end -- JSONexport.fiat()
JSONexport.filled = function ( assign, align, adjust )
-- Create independent JSON list of suggested items (Q), if present
-- Precondition:
-- assign -- table, with definition of element
-- align -- number, level of alignment
-- adjust -- true, for resolving symbolic IDs
-- Postcondition:
-- Returns string with JSON code, or not
local r
if type( assign ) == "table" and
type( assign.qlist ) == "table" then
local n = #assign.qlist
if n > 0 then
local indent = align + 1
local sep = ""
local shift = string.rep( " ", align )
local q, s
r = shift .. "\"qlist\": [ "
for i = 1, n do
q = assign.qlist[ i ]
if type( q ) == "number" then
s = tostring( q )
if s:find( "^[1-9]%d*$" ) then
q = "Q" .. s
end
end
if type( q ) == "string" then
s = JSONexport.fetch( q, adjust, false )
elseif i == n and q == true then
s = "true"
end
if s then
r = string.format( "%s%s%s",
r, sep, s )
sep = ",\n " .. shift
end
end -- for i
r = r .. " ]"
end
end
return r
end -- JSONexport.filled()
JSONexport.fixed = function ( assign, at, align, adjust )
-- Create mandatory/default item (Q), if present
-- Precondition:
-- assign -- table, with definition of element
-- at -- string, with ID within assign
-- "q", "qdefault", "qqexample"
-- align -- number, level of alignment
-- adjust -- true, for resolving symbolic IDs
-- Postcondition:
-- Returns string with JSON code, or not
local r
if type( assign ) == "table" then
local v = assign[ at ]
local s = type( v )
if s == "string" then
s = v
elseif s == "number" then
if v > 0 and
v == math.floor( v ) then
s = string.format( "Q%d", v )
else
s = false
end
elseif s == "table" then
local n = #v
if n == 1 then
s = v[ 1 ]
elseif n > 1 then
local collect = { }
local k
for i = 1, n do
s = JSONexport.fetch( v[ i ], adjust, false )
if s then
table.insert( collect, s )
k = i
end
end -- for i
n = #collect
if at == "qqexample" and n ~= 2 then
n = 0
end
if n == 1 then
s = v[ k ]
else
if n > 1 then
local shift = string.rep( " ", align )
local sep = "\n"
r = string.format( "%s\"%s\": [", shift, at )
for i = 1, n do
r = string.format( "%s%s%s %s",
r,
sep,
shift,
collect[ i ] )
sep = ",\n"
end -- for i
s = string.rep( " ", 2*align + #at + 4 )
r = string.format( "%s\n%s]", r, s )
end
s = false
end
else
s = false
end
else
s = false
end
if s and not r and at ~= "qqexample" then
s = JSONexport.fetch( s, adjust, false )
if s then
local shift = string.rep( " ", align )
r = string.format( "%s\"%s\": %s", shift, at, s )
end
end
end
return r
end -- JSONexport.fixed()
JSONexport.flat = function ( all, at, align )
-- Create JSON for textual element
-- Precondition:
-- all -- table, with request branch
-- at -- string, with ID within { all }
-- align -- number, level of alignment
-- Postcondition:
-- Returns string with extended JSON code
local e = all[ at ]
local o = { }
local s = type( e )
local r, shift, t
if s == "table" then
local parts
for k, v in pairs( e ) do
if type( k ) == "string" and
k:find( "^%l%l" ) then
if type( v ) == "string" then
if k ~= "class" and k ~= "style" then
parts = mw.text.split( k, "-" )
if parts[ 1 ]:find( "^%l%l%l?$" ) then
if #parts >= 2 and
not parts[ 2 ]:find( "^%u%l%l%l$" ) and
not parts[ 2 ]:find( "^%l%l%l" ) and
not parts[ 2 ]:find( "^%u%u$" ) then
k = false
end
else
k = false
end
end
elseif type( v ) ~= "table" or
( k ~= "class" and k ~= "style" ) then
k = false
end
if k then
t = t or { }
t[ k ] = v
if k ~= "class" and k ~= "style" then
table.insert( o, k )
end
end
end
end -- for k, v
if t then
table.sort( o )
if t.class then
table.insert( o, "class" )
end
if t.style then
table.insert( o, "style" )
end
end
elseif s == "string" then
if e:match( "^[PQL]%d+$" ) then
r = string.format( "\"%s\"", e )
else
t = { }
t.und = e
table.insert( o, "und" )
end
end
if r or t then
shift = string.rep( " ", align )
end
if t then
local sep = ""
local data, slang
r = "{\n"
for i = 1, #o do
slang = o[ i ]
data = t[ slang ]
if type( data ) == "string" then
s = fix( data )
else
local sept = ""
s = "{\n"
for k, v in pairs( data ) do
s = string.format( "%s%s%s \"%s\": \"%s\"",
s, sept, shift, k, v )
sept = ",\n"
end -- for k, v
s = string.format( "%s\n%s %s}",
s,
shift,
string.rep( " ", #slang + 4 ) )
end
r = string.format( "%s%s%s \"%s\": \"%s\"",
r, sep, shift, slang, s )
sep = ",\n"
end -- for i
r = string.format( "%s\n%s%s}",
r,
shift,
string.rep( " ", #at + 4 ) )
end
if r then
r = string.format( "%s\"%s\": %s", shift, at, r )
end
return r
end -- JSONexport.flat()
JSONexport.full = function ( all, adjust )
-- Create independent JSON for registration elements
-- Precondition:
-- all -- table, with entire request
-- adjust -- true, for resolving symbolic IDs
-- Postcondition:
-- Returns string with JSON code, or error message
local r = string.format( "{ \"@generated\": \"%s\"",
Config.frame:callParserFunction( "#timel",
"c" ) )
local f = function ( a )
if a and a ~= "" then
r = string.format( "%s,\n%s", r, a )
end
end -- f()
r = string.format( "%s,\n \"@format\": \"%s %s\"",
r, WikidataScheme.suite, WikidataScheme.serial )
f( JSONexport.flat( all, "caption", 1 ) )
f( JSONexport.flat( all, "onLabel", 1 ) )
f( JSONexport.flat( all, "onDesc", 1 ) )
f( JSONexport.flat( all, "onAlias", 1 ) )
f( JSONexport.family( all, "claims", 1, adjust ) )
f( JSONexport.flat( all, "footer", 1 ) )
if not adjust then
f( JSONexport.favour( all ) )
end
f( JSONexport.further( all, "id", 1 ) )
f( JSONexport.further( all, "class", 1 ) )
f( JSONexport.further( all, "style", 1 ) )
f( JSONexport.further( all, "options", 1 ) )
r = r .. "\n}"
return r
end -- JSONexport.full()
JSONexport.further = function ( all, at, align )
-- Create entry for auxilary elements
-- Precondition:
-- all -- table, with entire request
-- at -- string, with ID within { all }
-- align -- number, level of alignment
-- Postcondition:
-- Returns string with JSON code, or not
local permit = { id_string = true,
class_string = true,
class_table = true,
style_string = true,
style_table = true,
options_table = true }
local e = all[ at ]
local s = type( e )
local r
if permit[ string.format( "%s_%s", at, s ) ] then
if s == "string" then
e = mw.text.trim( e )
if e == "" then
e = false
elseif at == "class" then
e = mw.text.split( e, "%s+" )
s = "table"
end
elseif not pairs( e ) then
e = false
end
if e then
local shift = string.rep( " ", align )
if s == "string" then
r = string.format( "%s%s%s \"%s\": \"%s\"",
shift, at, fix( e ) )
else
local sep = ""
r = "{\n"
for k, v in pairs( e ) do
r = string.format( "%s%s%s \"%s\": \"%s\"",
r, sep, shift, k, fix( e ) )
sep = ",\n"
end -- for k, v
r = string.format( "%s\n%s%s}",
r,
shift,
string.rep( " ", #at + 4 ) )
end
end
end
return r
end -- JSONexport.further()
Resolver.fetch = function ( access, alike )
-- Resolve entity name
-- Precondition:
-- access -- string, with entity name or ID
-- alike -- string, if Property or Item required, "P" or "Q"
-- Postcondition:
-- Returns
-- 1. string or not, with entity ID
-- 2. string, with error message
local r1, r2
if type( access ) == "string" then
r2 = mw.text.trim( access )
if r2 == "" then
r2 = Text.flip( "err_NameEmpty" )
else
if r2:find( "^[PQL]%d+$" ) then
r1 = r2
elseif type( WikidataScheme.Request.resolve ) == "table" then
local entry = WikidataScheme.Request.resolve[ r2 ]
if type( entry ) == "table" then
for k, v in pairs( Config.spaces ) do
if type( entry[ k ] ) == "number" then
r1 = string.format( "%s%d", k, entry[ k ] )
break -- for k, v
end
end -- for k, v
if not r1 then
r2 = string.format( "<%s> %s",
r2,
Text.flip( "err_NameBad" )
)
end
else
r2 = string.format( "<%s> %s",
r2,
Text.flip( "err_NameMissed" ) )
end
else
r2 = string.format( "<%s> %s .resolve",
r2,
Text.flip( "err_NoNameResolver" ) )
end
if r1 then
if alike and r1:sub( 1, 1 ) ~= alike then
r2 = string.format( "%s %s",
r1,
Text.flip( "err_InvalidNameType"
) )
elseif not mw.wikibase.isValidEntityId( r1 ) then
r2 = string.format( "%s %s",
r1,
Text.flip( "err_NoEntity" ) )
r1 = false
else
r2 = false
end
end
end
else
r2 = string.format( "%s %s",
Text.flip( "err_InvalidNameType" ),
type( access ) )
end
return r1, r2
end -- Resolver.fetch()
Resolver.fire = function ( all )
-- Create <table> for resolve assignment
-- Precondition:
-- all -- table, with entire request
-- Postcondition:
-- Returns string with entire HTML table, or not
local r
if type( all.resolve ) == "table" then
local order = { }
local j, coll, s
for k, v in pairs( all.resolve ) do
if type( k ) == "string" and
type( v ) == "table" then
k = mw.text.trim( k )
if k ~= "" then
for i = 1, #Config.types do
s = Config.types[ i ]
j = v[ s ]
if type( j ) == "number" and
j >= 0 and
j == math.floor( j ) then
coll = coll or { }
k = fix( k )
coll[ k ] = string.format( "%s%d", s, j )
table.insert( order, k )
break -- for i
end
end -- for i
end
end
end -- for k, v
if #order > 0 then
local tbl = mw.html.create( "table" )
:addClass( "wikitable sortable" )
:addClass( WikidataScheme.suite .. "-resolve" )
local tr = mw.html.create( "tr" )
local e, e2, k, s, td
tr:newline()
:node( mw.html.create( "th" )
:attr( "title", "symbol" )
:css( Config.css.tablehead )
:wikitext( "symbol" ) )
:newline()
:node( mw.html.create( "th" )
:attr( "title", "entity" )
:css( Config.css.tablehead )
:wikitext( "entity" ) )
:newline()
:node( mw.html.create( "th" )
:attr( "title", "label" )
:css( Config.css.tablehead )
:wikitext( "label" ) )
tbl:newline()
table.sort( order )
for i = 1, #order do
k = order[ i ]
tr = mw.html.create( "tr" )
e = mw.html.create( "code" )
:attr( Config.coded )
:wikitext( k )
td = mw.html.create( "td" )
:node( e )
tr:newline()
:node( td )
e, e2 = Table.fetch( coll[ k ], false, true )
td = mw.html.create( "td" )
:node( e )
tr:newline()
:node( td )
td = mw.html.create( "td" )
:node( e2 )
tr:newline()
:node( td )
tbl:newline()
:node( tr )
end -- for k, v
r = tostring( tbl:newline() )
end
end
return r
end -- Resolver.fire()
Text.fashion = function ( at, apply )
-- Assign class and style
-- Precondition:
-- at -- mw.html element
-- apply -- table, or not, may contain components class or style
-- Postcondition:
-- element modified
if type( apply ) == "table" then
local class = apply.class
local css = apply.style
if class then
if type( class ) == "string" then
at:addClass( class )
elseif type( class ) == "table" then
for i = 1, #class do
at:addClass( class[ i ] )
end -- for i
end
end
if css then
if type( css ) == "string" then
at:cssText( css )
elseif type( css ) == "table" then
at:css( css )
end
end
end
end -- Text.fashion()
Text.find = function ( available )
-- Find best match of I18N options
-- Precondition:
-- available -- table, I18N
-- Postcondition:
-- Returns
-- 1. string, with selected message, or not
-- 2. string, with language code, or not
local r, r2
local f = function ()
if type( r ) == "string" then
r = mw.text.trim( r )
if r == "" then
r = false
end
end
end -- f()
if type( available ) == "table" then
if Text.Multilingual then
r, r2 = Text.Multilingual.i18n( available,
false,
Config.frame )
else
Text.foreign()
r = available[ Text.slang ]
f()
if r then
r2 = Text.slang
else
r = available.en
r2 = "en"
end
end
elseif type( available ) == "string" then
r = available
end
f()
if not r then
for k, v in pairs( available ) do
r = v
f()
if r then
r2 = k
break -- for k, v
end
end -- for k, v
end
f()
if not r then
r2 = false
end
return r, r2
end -- Text.find()
Text.flip = function ( about, apply )
-- Retrieve specific module I18n text
-- Precondition:
-- about -- string, with text ID
-- apply -- sequence table, with parameters
-- Postcondition:
-- Returns
-- 1. string, with selected message
-- 2. string, with language code
local r, r2
if type( Config.globals ) == "nil" then
Text.flipper( WikidataScheme.suite )
end
if Config.globals then
r = Config.globals[ about ]
end
if r then
r, r2 = Text.find( r )
end
if not r then
r = Config.defaults[ about ]
if r then
r2 = "en"
else
if type( about ) == "string" then
r = string.format( "???I18N(%s)I18N???", about )
else
r = fault( "Invalid message ID type" )
end
end
end
if apply and
r:find( "$", 1, true ) and
type( apply ) == "table" then
r = mw.message.newRawMessage( r, apply ):plain()
end
return r, r2
end -- Text.flip()
Text.flipper = function ( apply )
-- Retrieve global specific I18N translations
-- Precondition:
-- apply -- string, with package ID
-- Postcondition:
local storage = string.format( "I18n/Module:%s.tab", apply )
local lucky, t = pcall( mw.ext.data.get, storage, "_" )
Config.globals = false
if type( t ) == "table" then
t = t.data
if type( t ) == "table" then
local e
for i = 1, #t do
e = t[ i ]
if type( e ) == "table" and
type( e[ 1 ] ) == "string" and
type( e[ 2 ] ) == "table" then
Config.globals = Config.globals or { }
Config.globals[ e[ 1 ] ] = e[ 2 ]
else
error( storage .. " has unexpected scheme", 0 )
end
end -- for i
else
error( storage .. " corrupted", 0 )
end
end
end -- Text.flipper()
Text.flow = function ( at, alien, applied )
-- Assign differing language and script direction
-- Precondition:
-- at -- mw.html element
-- alien -- string, with language (or script) code, or not
-- applied -- string, with plain text, or not
-- Postcondition:
-- element modified if not matching
-- Returns true if script direction changed
local dir = function ( a )
local r
if a then
r = "ltr"
else
r = "rtl"
end
return r
end -- dir()
local isRTL = function ( a )
local r
if Text.Multilingual then
r = Text.Multilingual.isRTL( a )
else
r = mw.language.new( a ):isRTL()
end
return r
end -- isRTL()
local shift, slang
if not Text.shift then
Text.foreign( true )
if Text.slang then
Text.ltr = not isRTL( Text.slang )
end
if type( Text.ltr ) ~= "boolean" then
Text.ltr = not mw.language.getContentLanguage():isRTL()
end
Text.shift = dir( Text.ltr )
end
if alien then
Text.dirs = Text.dirs or { }
shift = Text.dirs[ alien ]
if not shift then
shift = dir( not isRTL( alien ) )
Text.dirs[ alien ] = shift
end
if applied and shift == "rtl" then
if not Text.Latn then
Text.Latn = string.format( "^[ -%s]*$",
mw.ustring.char( 0x052F ) )
end
if mw.ustring.find( applied, Text.Latn ) then
shift = "ltr"
end
end
if shift == Text.shift then
shift = false
end
if alien ~= Text.slang then
slang = alien
end
else
shift = Text.shift
slang = Text.slang
end
if shift then
at:attr( "dir", shift )
end
if slang then
at:attr( "lang", slang )
end
return true and shift
end -- Text.flow()
Text.foreign = function ( again )
-- Guess human language
-- Precondition:
-- again -- true, for re-evaluation
-- Postcondition:
-- Returns language code, or not
if again or type( Text.slang ) == "nil" then
if Text.Multilingual then
Text.slang = Text.Multilingual.userLangCode()
elseif not Text.slang then
Text.slang = mw.language.getContentLanguage():getCode()
:lower()
end
end
if Text.slang and
mw.ustring.codepoint( Text.slang, 1, 1 ) > 122 then
Text.slang = false
end
return Text.slang
end -- Text.foreign()
Text.html = function ( available, as, alt, alien, across )
-- Create HTML text element
-- Precondition:
-- available -- table, I18N, string: plain text or ID, or not
-- as -- string, HTML tag name
-- alt -- string, with fallback text
-- alien -- string, with language (or script) code, or not
-- across -- number, of columns, for TD
-- Postcondition:
-- Returns mw.html element
local r = type( available )
local show, slang
if r == "table" then
show, slang = Text.find( available )
elseif r == "string" then
if available:find( "^[QPL]%d+$" ) then
local sign = available
if mw.wikibase.isValidEntityId( sign ) then
local s = Config.spaces[ sign:sub( 1, 1 ) ]
if s then
sign = s .. sign
else
sign = sign
end
show, slang = Text.wikibase( sign )
else
show = string.format( "%s %s",
sign,
Text.flip( "err_NoEntity" ) )
end
end
if not show then
show = available
end
slang = slang or alien
else
show = alt
end
if show then
r = mw.html.create( as )
if slang then
local bidi
if as == "code" then
r:attr( Config.coded )
bidi = not Text.ltr
else
bidi = Text.flow( r, slang, show )
end
if bidi and as == "span" then
r = mw.html.create( "bdo" )
:node( r )
Text.flow( r, slang )
end
end
r:wikitext( show )
Text.fashion( r, available )
else
r = mw.html.create( "code" )
:attr( Config.coded )
:wikitext( as )
end
if across and across > 1 then
r:attr( "colspan", tostring( across ) )
end
return r
end -- Text.html()
Text.templatedata = function ( area, about )
-- Retrieve TemplateData system message
-- Precondition:
-- area -- One of: "type", "desc", "status",
-- "example", "default"
-- about -- nil or in case of area=status: "required",
-- "suggested",
-- "optional",
-- "deprecated"
-- Postcondition:
-- Returns string, in general,
-- mw.html span for area=example|default
local s = "templatedata-doc-param-" .. area
local r
if about and area == "status" then
s = string.format( "%s-%s", s, about )
end
Text.templatedataCache = Text.templatedataCache or { }
r = Text.templatedataCache[ s ]
if not r then
local o = mw.message.new( s )
if o:exists() then
if Text.foreign( true ) then
o:inLanguage( Text.slang )
end
r = o:plain()
else
r = string.format( "???(%s)???", s )
end
if area == "example" or area == "default" then
r = mw.html.create( "span" )
:addClass( string.format( "%s-label-%s",
WikidataScheme.suite,
area ) )
:wikitext( r )
end
Text.templatedataCache[ s ] = r
end
return r
end -- Text.templatedata()
Text.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 r, r2
if Text.Multilingual then
r, r2 = Text.Multilingual.wikibase( all,
about,
attempt,
Config.frame )
else
local s = type( all )
local object
if s == "table" then
object = all
elseif s == "string" then
object = mw.wikibase.getEntity( all )
r = 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
r = object[ attempt ].value
r2 = attempt
elseif object.en then
r = object.en.value
r2 = "en"
else
local poly
for k, v in pairs( object ) do
r = v.value
r2 = k
break -- for k, v
end -- for k, v
end
end
end
end
return r or "????????", r2
end -- Text.wikibase()
Table.features = function ( assigned, across, already, asked, above )
-- Describe entry features
-- Precondition:
-- assigned -- table, with definition of one entry
-- across -- number, of columns, or nil on second level
-- already -- true, if first element to be created as TR
-- asked -- true, if first element to be created as TR
-- above -- string, with context property ID
-- Postcondition:
-- Returns sequence table with mw.html objects
-- 1. table, with TD
-- 2. table, with TR, or not
local r1, r2, td
local f = function ( add, also, a )
if add then
if across and across > 1 and not a then
add:attr( "colspan", tostring( across ) )
end
if already or r1 then
local tr
if add or not r2 then
tr = mw.html.create( "tr" )
:node( add )
Table.flag( tr, asked )
if also then
tr:newline()
:node( also )
end
r2 = r2 or { }
table.insert( r2, tr )
else
tr = r2[ #r2 ]
end
else
r1 = { }
table.insert( r1, add )
if also then
table.insert( r1, also )
end
end
end
end -- f()
local f1 = function ( already, add, about )
local ttd = Text.templatedata( about )
local sel = string.format( "%s-%s",
WikidataScheme.suite,
about )
local r = already
local lift
if r then
r:newline()
else
r = mw.html.create( "td" )
lift = true
end
r:node( mw.html.create( "div" )
:node( ttd ) )
:newline()
:node( add:addClass( sel ) )
if lift then
f( r )
end
return r
end -- f1()
local f2 = function ( add, about )
local ttd = Text.templatedata( about )
local sel = string.format( "%s-%s",
WikidataScheme.suite,
about )
local r = already
f( mw.html.create( "td" )
:node( ttd ),
add:addClass( sel ),
true )
end -- f2()
if type( assigned ) == "table" then
f( Table.field( assigned, "intro", 2 ) )
if type( assigned.qlist ) == "table" then
td = mw.html.create( "td" )
if type( assigned.q ) == "nil" then
local ul = Table.filled( assigned.qlist )
if ul then
f( td:node( ul ) )
end
else
f(td:wikitext( fault( Text.flip( "err_q_qlist" ) ) ) )
end
elseif type( assigned.q ) ~= "nil" then
td = mw.html.create( "td" )
f( td:node( Table.fixed( assigned, "q" ) ) )
end
if type( assigned.qdefault ) ~= "nil" then
local q = Table.fixed( assigned, "qdefault" )
if across == 2 then
q = mw.html.create( "td" )
:node( q )
f2( q, "default" )
else
td = f1( td, q, "default" )
end
end
if type( assigned.example ) ~= "nil" then
if across == 2 then
local q = Table.field( assigned, "example" )
f2( q, "example" )
else
local q = Text.html( assigned.example, "div" )
td = f1( td, q, "example" )
end
elseif type( assigned.qqexample ) == "table" then
local qpq = Table.fruit( above, assigned.qqexample )
if across == 2 then
f2( mw.html.create( "td" )
:node( qpq ),
"example" )
else
td = f1( td, qpq, "example" )
end
end
if type( assigned.qualifiers ) == "table" then
if across == 2 then
local hd, q, rows
for i = 1, #assigned.qualifiers do
q = assigned.qualifiers[ i ]
if type( q ) == "table" then
hd, rows = Table.further( q, hd )
if hd then
f( hd[ 1 ], hd[ 2 ], true )
end
if rows then
r2 = r2 or { }
for k = 1, #rows do
table.insert( r2, rows[ k ] )
end -- for k
end
else
q = Text.flip( "err_BadQualifier" )
f( mw.html.create( "td" )
:wikitext( fault( q ) ) )
end
end -- for i
else
td = mw.html.create( "td" )
:wikitext( fault( Text.flip( "err_Nesting" ) ) )
f( td )
end
end
f( Table.field( assigned, "terminate", 2 ) )
end
if not ( r1 ) then
f( mw.html.create( "td" ) )
end
return r1, r2
end -- Table.features()
Table.fetch = function ( access, alike, atom, alone )
-- Describe registration entity
-- Precondition:
-- access -- string, with entity name
-- alike -- string, if Property or Item required, "P" or "Q"
-- atom -- true, if two elements required
-- alone -- true, if combined linked element required
-- Postcondition:
-- Returns
-- 1. string, with entity ID and label, or error message,
-- or mw.html code element for atom
-- 2. mw.html span element for atom
local sign, r1 = Resolver.fetch( access, alike )
local r2
if sign then
local s = Config.spaces[ sign:sub( 1, 1 ) ]
local say, slang
if s then
s = s .. sign
else
s = sign
end
say, slang = Text.wikibase( sign, alike )
r2 = Text.html( say, "span", false, slang )
if alone then
r1 = string.format( "[[d:%s|%s]]", s, tostring( r2 ) )
else
s = string.format( "[[d:%s|%s]]", s, sign )
r1 = Text.html( s, "code", false, "en" )
if not atom then
r1 = string.format( "%s %s",
tostring( r1 ),
tostring( r2 ) )
end
end
elseif r1 then
r1 = fault( r1 )
else
r1 = fault( "Table.fetch()" )
end
return r1, r2
end -- Table.fetch()
Table.fiat = function ( assign )
-- Describe registration claim as major table row
-- Precondition:
-- assign -- table, with definition of one entry
-- Postcondition:
-- Returns sequence table, with mw.html.TR objects
local tr = mw.html.create( "tr" )
local td = mw.html.create( "td" )
local r = { }
if type( assign ) == "table" then
local state = Table.flag( tr, assign.state )
local how, n, rows, v
Text.fashion( tr, assign )
tr:addClass( string.format( "%s-%s",
WikidataScheme.suite, state ) )
v = Table.fetch( assign.subject )
td:wikitext( v )
if type( assign.values ) == "table" then
for i = 1, #assign.values do
how, v = Table.features( assign.values[ i ],
2,
how,
state,
assign.subject )
if v then
rows = rows or { }
for i = 1, #v do
table.insert( rows, v[ i ] )
end -- for i
end
end -- for i
else
how, rows = Table.features( false,
2,
false,
state,
assign.subject )
--[==[ if not ( how or rows ) then
td = mw.html.create( "td" )
:wikitext( fault( Text.flip( "err_Unguided" ) ) )
f( td )
end ]==]
end
if rows then
n = #rows + 1
else
n = 0
end
if n > 1 then
td:attr( "rowspan", tostring( n ) )
end
tr:newline()
:node( td )
if how then
for i = 1, #how do
tr:newline()
:node( how[ i ] )
end -- for i
end
td = mw.html.create( "td" )
:wikitext( Text.templatedata( "status", state ) )
if n > 1 then
td:attr( "rowspan", tostring( n ) )
end
tr:newline()
:node( td )
table.insert( r, tr )
for i = 1, n do
table.insert( r, rows[ i ] )
end -- for i
else
td:attr( "colspan", "3" )
:css( { ["background-color"] = "#FFFF00" } )
:wikitext( fault( Text.flip( "err_InvalidClaim" ) ) )
tr:node( td )
table.insert( r, tr )
end
return r
end -- Table.fiat()
Table.field = function ( all, ask, across )
-- Insert plain text table cell
-- Precondition:
-- all -- table, with request
-- ask -- string, with key in all
-- across -- number, of columns, or not
-- Postcondition:
-- Returns mw.html.TD object, or nothing
local q = all[ ask ]
local r
if q then
local n = across or 1
r = Text.html( q, "td", false, false, n )
end
return r
end -- Table.field()
Table.filled = function ( all )
-- Create unordered list of items
-- Precondition:
-- all -- sequence table, with entity names, and true as last
-- Postcondition:
-- Returns mw.html.UL, or nothing
local q, r, s
for i = 1, #all do
r = r or mw.html.create( "ul" )
q = all[ i ]
if type( q ) == "number" then
s = tostring( q )
if s:find( "^[1-9]%d*$" ) then
q = "Q" .. s
end
end
if type( q ) == "string" then
s = Table.fetch( q )
elseif i == #all and q == true then
s = "…"
else
q = mw.html.create( "code" )
:wikitext( tostring( q ) )
s = Text.flip( "err_InvalidNameType" )
s = string.format( "%s %s", tostring( q ), fault( s ) )
end
r:newline()
:node( mw.html.create( "li" )
:wikitext( s ) )
end -- for i
r:newline()
return r
end -- Table.filled()
Table.fixed = function ( assigned, at )
-- Create mandatory/default item (Q)
-- Precondition:
-- assigned -- string or number or sequence table of strings,
-- with item identifier
-- at -- string, with ID within assign, "q" or "qdefault"
-- -> string or number or sequence table of strings,
-- with item identifier
-- Postcondition:
-- Returns mw.html.span
local v = assigned[ at ]
local s = type( v )
local r
if s == "string" then
s = v
elseif s == "number" then
if v > 0 and
v == math.floor( v ) then
s = string.format( "Q%d", v )
else
s = false
end
elseif s == "table" then
local n = #v
if n == 1 then
r = Table.fixed( v[ 1 ], at )
elseif n > 1 then
r = mw.html.create( "span" )
for i = 1, #n do
if i > 1 then
r:node( mw.html.create( "br" ) )
:newline()
end
r:node( Table.fixed( v[ i ], at ) )
end -- for i
else
s = false
end
else
s = false
end
if not r then
if s then
s = Table.fetch( s )
else
s = fault( Text.flip( "err_NoEntity" ) )
end
r = mw.html.create( "span" )
:wikitext( s )
end
return r
end -- Table.fixed()
Table.flag = function ( adjust, assign )
-- Equip element with state style
-- Precondition:
-- adjust -- mw.html object, to be flagged
-- assign -- state name
-- Postcondition:
-- element modified
-- Returns defined state name
local r = assign
local css
if Config.css[ r ] then
css = Config.css[ r ]
else
r = "optional"
css = { ["background-color"] = "#FFFF00" }
end
adjust:css( css )
css = Config.feature( "css", r, "table string" )
if type( css ) == "string" then
adjust:cssText( css )
elseif type( css ) == "table" then
adjust:css( css )
end
return r
end -- Table.flag()
Table.flat = function ( all, ask, across, append )
-- Insert plain text table row
-- Precondition:
-- all -- table, with request
-- ask -- string, with key in all
-- across -- number, of columns, or not
-- append -- mw.html object, to be added to, or nothing
-- Postcondition:
-- Returns mw.html.TR object, or nothing
local q = all[ ask ]
local r
if q then
local n = across or 1
local s = Config.field( ask )
local td
r = mw.html.create( "tr" )
if s then
td = mw.html.create( "td" )
:wikitext( s )
r:newline()
:node( td )
n = 2
end
td = Text.html( q, "td", false, false, n )
r:newline()
:node( td )
if append then
append:newline()
:node( r )
end
end
return r
end -- Table.flat()
Table.form = function ( all )
-- Create <table> for registration elements
-- Precondition:
-- all -- table, with entire request
-- Postcondition:
-- Returns string with entire HTML table
local tbl = mw.html.create( "table" )
:addClass( "wikitable" )
:addClass( WikidataScheme.suite .. "-table" )
local tr, rows
if type( all.claims ) == "table" then
local got
for i = 1, #all.claims do
got = Table.fiat( all.claims[ i ] )
for k = 1, #got do
rows = rows or { }
table.insert( rows, got[ k ] )
end -- for k
end -- for i
end
if not rows then
rows = { Table.fiat( false ) }
end
if all.caption then
local o = type( all.caption )
if o == "string" or o == "table" then
o = Text.html( all.caption, "caption" )
Text.fashion( caption, all.caption )
tbl:newline()
:node( o )
end
end
Table.flat( all, "onLabel", 2, tbl )
Table.flat( all, "onDesc", 2, tbl )
Table.flat( all, "onAlias", 2, tbl )
Text.shift = false
Text.flow( tbl )
Text.fashion( tbl, all )
if type( all.id ) == "string" then
tbl:attr( "id", all.id )
end
tr = mw.html.create( "tr" )
tr:newline()
:node( mw.html.create( "th" )
:attr( "title", "type" )
:css( Config.css.tablehead )
:wikitext( Text.templatedata( "type" ) ) )
:newline()
:node( mw.html.create( "th" )
:attr( "colspan", "2" )
:css( Config.css.tablehead )
:wikitext( Text.templatedata( "desc" ) ) )
:newline()
:node( mw.html.create( "th" )
:attr( "title", "status" )
:css( Config.css.tablehead )
:wikitext( Text.templatedata( "status" ) ) )
tbl:newline()
-- :node( mw.html.create( "thead" )
:node( tr )
-- )
for i = 1, #rows do
tbl:newline()
:node( rows[ i ] )
end -- for i
if all.footer then
local o = type( all.footer )
if o == "string" or o == "table" then
o = Table.flat( all, "footer", 3 )
Text.fashion( footer, all.footer )
tbl:newline()
:node( o )
end
end
return tostring( tbl:newline() )
end -- Table.form()
Table.fruit = function ( assigned, adjoin )
-- Return content of a qqexample chain
-- Precondition:
-- assigned -- string, with name of P
-- adjoin -- table, with 2 elements as Q names: Item, P-value
-- Postcondition:
local e, r, s
if type( adjoin ) == "table" and #adjoin == 2 then
local p
p, e = Resolver.fetch( assigned, "P" )
if p then
local q1
q1, e = Resolver.fetch( adjoin[ 1 ], "Q" )
if q1 then
local q2
q2, e = Resolver.fetch( adjoin[ 2 ], "Q" )
if q2 then
local x
r = mw.html.create( "span" )
x, p = Table.fetch( p, false, true )
q1 = Table.fetch( q1, false, false, true )
q2 = Table.fetch( q2, false, false, true )
r:wikitext( q1 )
:wikitext( " <" )
:node( p )
:wikitext( "> " )
:wikitext( q2 )
end
end
end
end
if not r then
e = Text.flip( "err_BadExample" )
end
if e then
r = fault( e )
end
return r
end -- Table.fruit()
Table.further = function ( assign, already )
-- Describe one qualifier as middle column table row
-- Precondition:
-- assign -- table, with definition of one qualifier
-- already -- true, if first element to be created as TR
-- Postcondition:
-- Returns sequence tables with mw.html objects, or not
-- 1. TD, if not already
-- 2. TR, if any
local state, r1, r2, tr
local f = function ( add, also )
if add then
if state then
Table.flag( add, state )
if also then
Table.flag( also, state )
end
end
if already or r1 then
tr = mw.html.create( "tr" )
:newline()
:node( add )
if also then
tr:newline()
:node( also )
end
r2 = r2 or { }
table.insert( r2, tr )
else
r1 = { }
table.insert( r1, add )
if also then
table.insert( r1, also )
end
end
end
end -- f()
local td
local how, rows
if Config.statelist[ assign.state ] then
state = assign.state
else
state = "optional"
end
f( Table.flat( assign, "intro", 2 ) )
how, rows = Table.features( assign, 1, r1, state, assign.subject )
r1 = r1 or how
if rows then
r2 = r2 or { }
for i = 1, #rows do
table.insert( r2, rows[ i ] )
end -- for i
end
f( Table.flat( assign, "terminate" ) )
td = mw.html.create( "td" )
:node( Table.fetch( assign.subject, "P" ) )
if r1 then
table.insert( r1, 1, td )
elseif r2 then
r2[ 1 ]:newline()
:node( td )
else
f( td )
end
return r1, r2
end -- Table.further()
WikidataScheme.fetch = function ( about )
-- Retrieve Lua table
-- Precondition:
-- about -- table or JSON string or mw.loadData page name
-- Postcondition:
-- Returns string with error message, or not
-- Makes Lua table available as .Request
local s = type( about )
local r
if s == "string" then
local lucky, d
s = mw.text.trim( about )
if s:sub( 1, 1 ) == "{" and
s:sub( -1 ) == "}" then
lucky, d = pcall( mw.text.jsonDecode, about )
elseif not s:find( "\n", 2, true ) then
lucky, d = pcall( mw.loadData, about )
end
s = type( d )
if s == "table" then
WikidataScheme.Request = d
elseif s == "string" then
r = d
else
r = "Invalid data for WikidataScheme"
end
elseif s == "table" then
WikidataScheme.Request = about
else
r = "Invalid request for WikidataScheme"
end
return r
end -- WikidataScheme.fetch()
WikidataScheme.flat = function ( about, adjust, frame )
-- Export registration description as JSON
-- Precondition:
-- about -- table or JSON string or mw.loadData page name
-- adjust -- true, for resolving symbolic IDs
-- frame -- frame, if available
-- Postcondition:
-- Returns string with JSON or error message
local r = WikidataScheme.fetch( about )
if not r then
Config.frame = Config.frame or frame or mw.getCurrentFrame()
Config.first()
r = JSONexport.full( WikidataScheme.Request, adjust )
r = failures() .. r
end
return r
end -- WikidataScheme.flat()
WikidataScheme.form = function ( about, assigned, frame )
-- Describe registration elements
-- Precondition:
-- about -- table or JSON string or mw.loadData page name
-- assigned -- true, for resolve table only
-- frame -- frame, if available
-- Postcondition:
-- Returns string with entire HTML table
local r
Config.frame = Config.frame or frame or mw.getCurrentFrame()
if not Text.Multilingual and Text.Multilingual ~= false then
local bib = foreignModule( "Multilingual",
true,
false,
WikidataScheme.globals.Multilingual,
true )
if type( bib ) == "table" and
type( bib.Multilingual ) == "function" then
Text.Multilingual = bib.Multilingual()
else
Text.Multilingual = false
end
end
r = WikidataScheme.fetch( about )
if not r then
Config.first()
if assigned then
r = Resolver.fire( WikidataScheme.Request )
else
r = Table.form( WikidataScheme.Request )
end
end
r = failures() .. r
return r
end -- WikidataScheme.form()
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.form = function ( frame )
local s = mw.text.trim( frame.args[ 1 ] or "" )
local r
if s ~= "" then
r = WikidataScheme.form( s, false, frame )
end
return r or ""
end -- p.form
p.format = function ( frame )
local s = mw.text.trim( frame.args[ 1 ] or "" )
local r
if s ~= "" then
r = WikidataScheme.flat( s, false, frame )
end
return r or ""
end -- p.form
p.furnished = function ( frame )
local s = mw.text.trim( frame.args[ 1 ] or "" )
local r
if s ~= "" then
r = WikidataScheme.form( s, true, frame )
end
return r or ""
end -- p.furnished
p.JSON = function ( frame )
local s = mw.text.trim( frame.args[ 1 ] or "" )
local r
if s ~= "" then
r = WikidataScheme.flat( s, true, frame )
end
return r or ""
end -- p.JSON
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.WikidataScheme = function ()
WikidataScheme.Text = Text
return WikidataScheme
end -- p.WikidataScheme
return p