Modul:TemplateData: Unterschied zwischen den Versionen
w>PerfektesChaos (2018-02-13) |
K (73 Versionen von wikivoyage:Modul:TemplateData importiert) |
||
(41 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
local TemplateData = { suite = "TemplateData", | local TemplateData = { suite = "TemplateData", | ||
serial = " | serial = "2021-07-05", | ||
item = 46997995 } | item = 46997995 } | ||
--[=[ | --[==[ | ||
improve template:TemplateData | improve template:TemplateData | ||
]=] | ]==] | ||
local Failsafe = TemplateData | |||
Zeile 12: | Zeile 13: | ||
basicCnf = { catProblem = "strange", | basicCnf = { catProblem = "strange", | ||
classNoNumTOC = "suppressTOCnum", | classNoNumTOC = "suppressTOCnum", | ||
classTable = "classTable", | |||
cssParWrap = "cssTabWrap", | cssParWrap = "cssTabWrap", | ||
cssParams = "cssTable", | cssParams = "cssTable", | ||
Zeile 28: | Zeile 30: | ||
helpURL = "support4url", | helpURL = "support4url", | ||
helpUser = "support4wiki-user-name", | helpUser = "support4wiki-user-name", | ||
msgDescMiss = "solo" | msgDescMiss = "solo", | ||
tStylesTOCnum = "stylesTOCnum" }, | |||
classTable = { "wikitable" }, -- classes for params table | |||
debugmultilang = "C0C0C0", | |||
loudly = false, -- show exported element, etc. | loudly = false, -- show exported element, etc. | ||
solo = false, -- complaint on missing description | solo = false, -- complaint on missing description | ||
Zeile 39: | Zeile 42: | ||
subpage = false, -- pattern to identify subpage | subpage = false, -- pattern to identify subpage | ||
suffix = false, -- subpage creation scheme | suffix = false, -- subpage creation scheme | ||
suppressTOCnum = false | suppressTOCnum = false, -- class for TOC number suppression | ||
jsonDebug = "json-code-lint" -- class for jsonDebug tool | |||
} | } | ||
local Data = { | local Data = { | ||
Zeile 45: | Zeile 49: | ||
got = false, -- table, initial templatedata object | got = false, -- table, initial templatedata object | ||
heirs = false, -- table, params that are inherited | heirs = false, -- table, params that are inherited | ||
jump = false, -- source position at end of "params" | |||
less = false, -- main description missing | less = false, -- main description missing | ||
lasting = false, -- old syntax encountered | lasting = false, -- old syntax encountered | ||
Zeile 53: | Zeile 58: | ||
params = false, -- table, exported parameters | params = false, -- table, exported parameters | ||
scream = false, -- error messages | scream = false, -- error messages | ||
slang = | sibling = false, -- TOC juxtaposed | ||
slang = nil, -- project/user language code | |||
slim = false, -- JSON reduced to plain | slim = false, -- JSON reduced to plain | ||
source = false, -- JSON input | source = false, -- JSON input | ||
Zeile 62: | Zeile 68: | ||
} | } | ||
local Permit = { | local Permit = { | ||
builder = { align | builder = { after = "block", | ||
block | align = "block", | ||
compressed = "block", | block = "block", | ||
dense | compressed = "block", | ||
grouped | dense = "block", | ||
half | grouped = "inline", | ||
indent | half = "inline", | ||
inline | indent = "block", | ||
last | inline = "inline", | ||
lead | last = "block", | ||
newlines | lead = "block", | ||
spaced | newlines = "*", | ||
spaced = "inline" }, | |||
colors = { tableheadbg = "B3B7FF", | colors = { tableheadbg = "B3B7FF", | ||
required = "EAF3FF", | required = "EAF3FF", | ||
Zeile 79: | Zeile 86: | ||
optional = "EAECF0", | optional = "EAECF0", | ||
deprecated = "FFCBCB" }, | deprecated = "FFCBCB" }, | ||
params = { aliases | params = { aliases = "table", | ||
autovalue | autovalue = "string", | ||
default | default = "string table I18N nowiki", | ||
deprecated | deprecated = "boolean string I18N", | ||
description = "string table I18N", | description = "string table I18N", | ||
example | example = "string table I18N nowiki", | ||
label | label = "string table I18N", | ||
inherits | inherits = "string", | ||
required | required = "boolean", | ||
suggested | style = "string table", | ||
type | suggested = "boolean", | ||
suggestedvalues = "string table number", | |||
type = "string" }, | |||
root = { description = "string table I18N", | root = { description = "string table I18N", | ||
format = "string", | format = "string", | ||
Zeile 130: | Zeile 139: | ||
local function Fetch( ask ) | local function Fetch( ask, allow ) | ||
-- Fetch module | -- Fetch module | ||
-- Parameter: | -- Parameter: | ||
-- ask | -- ask -- string, with name | ||
-- | -- "/global" | ||
-- | -- "JSONutil" | ||
-- | -- "Multilingual" | ||
-- "Text" | |||
-- "WLink" | |||
-- allow -- true: no error if unavailable | |||
-- Returns table of module | -- Returns table of module | ||
-- error: Module not available | -- error: Module not available | ||
local r | local sign = ask | ||
local r, stem | |||
if sign:sub( 1, 1 ) == "/" then | |||
sign = TemplateData.frame:getTitle() .. sign | |||
else | |||
stem = sign | |||
sign = "Module:" .. stem | |||
end | |||
if TemplateData.extern then | if TemplateData.extern then | ||
r = TemplateData.extern[ | r = TemplateData.extern[ sign ] | ||
else | else | ||
TemplateData.extern = { } | TemplateData.extern = { } | ||
end | end | ||
if not r then | if not r then | ||
local lucky, g = pcall( require, | local lucky, g = pcall( require, sign ) | ||
if type( g ) == "table" then | if type( g ) == "table" then | ||
r = g[ | if stem and type( g[ stem ] ) == "function" then | ||
TemplateData.extern[ | r = g[ stem ]() | ||
else | |||
error( string.format( "Fetch(%s) %s", | r = g | ||
end | |||
TemplateData.extern[ sign ] = r | |||
elseif not allow then | |||
error( string.format( "Fetch(%s) %s", sign, g ), 0 ) | |||
end | end | ||
end | end | ||
return r | return r | ||
end -- Fetch() | end -- Fetch() | ||
local function Foreign() | |||
-- Guess human language | |||
-- Returns slang, or not | |||
if type( Data.slang ) == "nil" then | |||
local Multilingual = Fetch( "Multilingual", true ) | |||
if Multilingual and | |||
type( Multilingual.userLangCode ) == "function" then | |||
Data.slang = Multilingual.userLangCode() | |||
else | |||
Data.slang = mw.language.getContentLanguage():getCode() | |||
:lower() | |||
end | |||
end | |||
if Data.slang and | |||
mw.ustring.codepoint( Data.slang, 1, 1 ) > 122 then | |||
Data.slang = false | |||
end | |||
return Data.slang | |||
end -- Foreign() | |||
Zeile 169: | Zeile 214: | ||
:gsub( "([%-.()+*?^$%[%]])", | :gsub( "([%-.()+*?^$%[%]])", | ||
"%%%1" ) ) | "%%%1" ) ) | ||
local i, k = Data.source:find( | local i, k, r, slice, source | ||
if not Data.jump then | |||
Data.jump = Data.source:find( "params", 2 ) | |||
if Data.jump then | |||
Data.jump = Data.jump + 7 | |||
else | |||
Data.jump = 1 | |||
end | |||
end | |||
i, k = Data.source:find( seek, at + Data.jump ) | |||
while i and not r do | while i and not r do | ||
source = Data.source:sub( k + 1 ) | source = Data.source:sub( k + 1 ) | ||
Zeile 181: | Zeile 234: | ||
r = k | r = k | ||
else | else | ||
i, k = Data.source:find( seek, k ) | i, k = Data.source:find( seek, k ) | ||
end | end | ||
end -- while i | end -- while i | ||
Zeile 194: | Zeile 247: | ||
-- adapt -- string, message ID after "templatedata-" | -- adapt -- string, message ID after "templatedata-" | ||
-- Returns string, with localized text | -- Returns string, with localized text | ||
local o = mw.message.new( "templatedata-" .. adapt ) | |||
if Foreign() then | |||
o:inLanguage( Data.slang ) | |||
end | |||
return o:plain() | |||
end -- factory() | end -- factory() | ||
Zeile 245: | Zeile 302: | ||
-- adjust -- string | -- adjust -- string | ||
-- Returns string, with adjusted text | -- Returns string, with adjusted text | ||
local f = function ( a ) | local f = function ( a ) | ||
return a:gsub( "%s*\n%s*", " " ) | |||
:gsub( "%s%s+", " " ) | |||
end | |||
local tags = { { start = "<noexport>", | |||
stop = "</noexport>" }, | |||
{ start = "<exportonly>", | |||
stop = "</exportonly>", | |||
l = false } | |||
} | |||
local r = adjust | |||
local i, j, k, s, tag | |||
for m = 1, 2 do | |||
tag = tags[ m ] | |||
if r:find( tag.start, 1, true ) then | |||
s = r | |||
r = "" | |||
i = 1 | |||
tag.l = true | |||
j, k = s:find( tag.start, i, true ) | |||
while j do | |||
if j > 1 then | |||
r = r .. f( s:sub( i, j - 1 ) ) | |||
end | |||
i = k + 1 | |||
j, k = s:find( tag.stop, i, true ) | |||
if j then | |||
if m == 1 then | |||
r = r .. s:sub( i, j - 1 ) | |||
end | |||
i = k + 1 | |||
j, k = s:find( tag.start, i, true ) | |||
else | |||
Fault( "missing " .. tag.stop ) | |||
end | |||
end -- while j | |||
r = r .. s:sub( i ) | |||
elseif m == 1 then | |||
r = f( r ) | |||
end | |||
end -- for m | |||
if tags[ 2 ].l then | |||
r = r:gsub( "<exportonly>.*</exportonly>", "" ) | |||
end | |||
return r | |||
end -- fair() | |||
local function fancy( advance, alert ) | |||
-- Present JSON source | |||
-- Parameter: | |||
-- advance -- true, for nice | |||
-- alert -- true, for visible | |||
-- Returns string | |||
local r | local r | ||
if | if Data.source then | ||
local | local support = Config.jsonDebug | ||
local | local css | ||
if advance then | |||
css = { height = "6em", | |||
if | resize = "vertical" } | ||
r = { [ 1 ] = "syntaxhighlight", | |||
[ 2 ] = Data.source, | |||
lang = "json", | |||
style = table.concat( css, ";" ) } | |||
if alert then | |||
r.class( support ) | |||
end | end | ||
r = TemplateData.frame:callParserFunction( "#tag", r ) | |||
else | |||
css = { [ "font-size" ] = "77%", | |||
[ "line-height" ] = "1.35" } | |||
if alert then | |||
css.resize = "vertical" | |||
else | else | ||
css.display = "none" | |||
end | end | ||
end | r = mw.html.create( "pre" ) | ||
r = | :addClass( support ) | ||
:css( css ) | |||
:wikitext( mw.text.encode( Data.source ) ) | |||
r = tostring( r ) | |||
end | |||
r = "\n".. r | |||
else | else | ||
r = | r = "" | ||
end | end | ||
return r | return r | ||
end -- | end -- fancy() | ||
local function faraway( alternatives ) | local function faraway( alternatives ) | ||
-- Retrieve | -- Retrieve best language version from multilingual text | ||
-- Parameter: | -- Parameter: | ||
-- alternatives -- table, to be evaluated | -- alternatives -- table, to be evaluated | ||
Zeile 287: | Zeile 405: | ||
local variants = { } | local variants = { } | ||
local r1, r2 | local r1, r2 | ||
for k, v in pairs( alternatives ) do | for k, v in pairs( alternatives ) do | ||
if type( v ) == "string" then | if type( v ) == "string" then | ||
v = mw.text.trim( v ) | v = mw.text.trim( v ) | ||
if v ~= "" then | if v ~= "" and type( k ) == "string" then | ||
k = k:lower() | |||
variants[ k ] = v | variants[ k ] = v | ||
n = n + 1 | n = n + 1 | ||
Zeile 300: | Zeile 416: | ||
end -- for k, v | end -- for k, v | ||
if n > 0 then | if n > 0 then | ||
local Multilingual = Fetch( "Multilingual", true ) | |||
if | if Multilingual and | ||
type( Multilingual.i18n ) == "function" then | |||
local show, slang = Multilingual.i18n( variants ) | |||
if show then | |||
r1 = show | |||
variants[ slang ] = nil | |||
r2 = variants | |||
end | end | ||
end | end | ||
if not r1 then | if not r1 then | ||
Foreign() | |||
for k, v in pairs( variants ) do | for k, v in pairs( variants ) do | ||
if v | if n == 1 then | ||
r1 = v | |||
elseif Data.slang == k then | |||
variants[ k ] = nil | variants[ k ] = nil | ||
r1 = v | r1 = v | ||
r2 = variants | r2 = variants | ||
end | end | ||
end -- for k, v | end -- for k, v | ||
end | end | ||
if r2 then | if r2 and Multilingual then | ||
for k, v in pairs( r2 ) do | for k, v in pairs( r2 ) do | ||
if v and not Multilingual.isLang( k ) then | if v and not Multilingual.isLang( k, true ) then | ||
Fault( string.format( " | Fault( string.format( "%s <code>lang=%s</code>", | ||
"Invalid", | |||
k ) ) | k ) ) | ||
end | end | ||
Zeile 358: | Zeile 450: | ||
return r1, r2 | return r1, r2 | ||
end -- faraway() | end -- faraway() | ||
local function fashioned( about, asked, assign ) | |||
-- Create description head | |||
-- Parameter: | |||
-- about -- table, supposed to contain description | |||
-- asked -- true, if mandatory description | |||
-- assign -- <block>, if to be equipped | |||
-- Returns <block>, with head, or nil | |||
local para = assign or mw.html.create( "div" ) | |||
local plus, r | |||
if about and about.description then | |||
if type( about.description ) == "string" then | |||
para:wikitext( about.description ) | |||
else | |||
para:wikitext( about.description[ 1 ] ) | |||
plus = mw.html.create( "ul" ) | |||
plus:css( "text-align", "left" ) | |||
for k, v in pairs( about.description[ 2 ] ) do | |||
plus:node( mw.html.create( "li" ) | |||
:node( mw.html.create( "code" ) | |||
:wikitext( k ) ) | |||
:node( mw.html.create( "br" ) ) | |||
:wikitext( fair( v ) ) ) | |||
end -- for k, v | |||
if Config.loudly then | |||
plus = mw.html.create( "div" ) | |||
:css( "background-color", | |||
"#" .. Config.debugmultilang ) | |||
:node( plus ) | |||
else | |||
plus:addClass( "templatedata-maintain" ) | |||
:css( "display", "none" ) | |||
end | |||
end | |||
elseif Config.solo and asked then | |||
para:addClass( "error" ) | |||
:wikitext( Config.solo ) | |||
Data.less = true | |||
else | |||
para = false | |||
end | |||
if para then | |||
if plus then | |||
r = mw.html.create( "div" ) | |||
:node( para ) | |||
:node( plus ) | |||
else | |||
r = para | |||
end | |||
end | |||
return r | |||
end -- fashioned() | |||
local function fatten( access ) | |||
-- Create table row for sub-headline | |||
-- Parameter: | |||
-- access -- string, with name | |||
-- Returns <tr> | |||
local param = Data.tree.params[ access ] | |||
local sub, sort = access:match( "(=+)%s*(%S.*)$" ) | |||
local headline = mw.html.create( string.format( "h%d", #sub ) ) | |||
local r = mw.html.create( "tr" ) | |||
local td = mw.html.create( "td" ) | |||
:attr( "colspan", "5" ) | |||
:attr( "data-sort-value", "!" .. sort ) | |||
local s | |||
if param.style then | |||
s = type( param.style ) | |||
if s == "table" then | |||
td:css( param.style ) | |||
elseif s == "string" then | |||
td:cssText( param.style ) | |||
end | |||
end | |||
s = fashioned( param, false, headline ) | |||
if s then | |||
headline = s | |||
else | |||
headline:wikitext( sort ) | |||
end | |||
td:node( headline ) | |||
r:node( td ) | |||
return r | |||
end -- fatten() | |||
Zeile 371: | Zeile 551: | ||
end -- for k, v | end -- for k, v | ||
for i = 1, n do | for i = 1, n do | ||
for k, v in pairs( Data.heirs ) do | if Data.heirs then | ||
for k, v in pairs( Data.heirs ) do | |||
if v and not Data.heirs[ v ] then | |||
n = n - 1 | |||
t[ k ].inherits = nil | |||
Data.heirs[ k ] = nil | |||
p2 = { } | |||
t2 = { } | |||
if p[ v ] then | |||
for k2, v2 in pairs( p[ v ] ) do | |||
p2[ k2 ] = v2 | p2[ k2 ] = v2 | ||
end -- for k2, v2 | |||
if p[ k ] then | |||
for k2, v2 in pairs( p[ k ] ) do | |||
if type( v2 ) ~= "nil" then | |||
p2[ k2 ] = v2 | |||
end | |||
end -- for k2, v2 | |||
end | end | ||
p[ k ] = p2 | |||
for k2, v2 in pairs( t[ v ] ) do | |||
t2[ k2 ] = v2 | |||
end -- for k2, v2 | |||
for k2, v2 in pairs( t[ k ] ) do | |||
if type( v2 ) ~= "nil" then | |||
t2[ k2 ] = v2 | |||
end | |||
end -- for k2, v2 | |||
t[ k ] = t2 | |||
else | |||
Fault( "No params[] inherits " .. v ) | |||
end | |||
end | end | ||
end -- for k, v | |||
end | |||
end | |||
end -- i = 1, n | end -- i = 1, n | ||
if n > 0 then | if n > 0 then | ||
Zeile 469: | Zeile 655: | ||
end | end | ||
end -- for k, v | end -- for k, v | ||
end | |||
if type( Config.subpage ) ~= "string" or | |||
type( Config.suffix ) ~= "string" then | |||
local got = mw.message.new( "templatedata-doc-subpage" ) | |||
local suffix | |||
if got:isDisabled() then | |||
suffix = "doc" | |||
else | |||
suffix = got:plain() | |||
end | |||
if type( Config.subpage ) ~= "string" then | |||
Config.subpage = string.format( "/%s$", suffix ) | |||
end | |||
if type( Config.suffix ) ~= "string" then | |||
Config.suffix = string.format( "%%s/%s", suffix ) | |||
end | |||
end | end | ||
end -- favorize() | end -- favorize() | ||
Zeile 474: | Zeile 676: | ||
local function feasible( about, | local function feasible( about, at ) | ||
-- | -- Deal with suggestedvalues within parameter | ||
-- Parameter: | -- Parameter: | ||
-- about -- table, | -- about -- parameter details | ||
-- | -- .suggestedvalues -- table|string|number, | ||
-- Returns | -- value and possibly description | ||
local | -- .code -- mandatory | ||
local | -- .label -- table|string | ||
if | -- .icon -- string | ||
if type( | -- .class -- table|string | ||
-- .css -- table | |||
-- .style -- string | |||
-- .less -- true: suppress code | |||
-- .type | |||
-- at -- string, with parameter name | |||
-- Returns | |||
-- 1: mw.html object | |||
-- 2: sequence table with values, or nil | |||
local p = about.suggestedvalues | |||
local s = type( p ) | |||
local e, r1, r2, v | |||
if s == "table" then | |||
if #p > 0 then | |||
for i = 1, #p do | |||
e = p[ i ] | |||
s = type( e ) | |||
if s == "table" then | |||
if type( e.code ) == "string" then | |||
s = mw.text.trim( e.code ) | |||
if s == "" then | |||
e = nil | |||
else | |||
e.code = s | |||
end | |||
else | |||
e = nil | |||
s = string.format( "params.%s.%s[%d] %s", | |||
at, | |||
"suggestedvalues", | |||
i, | |||
"MISSING 'code:'" ) | |||
end | |||
elseif s == "string" then | |||
s = mw.text.trim( e ) | |||
if s == "" then | |||
e = nil | |||
s = string.format( "params.%s.%s[%d] EMPTY", | |||
at, "suggestedvalues", i ) | |||
Fault( s ) | |||
else | |||
e = { code = s } | |||
end | |||
elseif s == "number" then | |||
e = { code = tostring( e ) } | |||
else | |||
s = string.format( "params.%s.%s[%d] INVALID", | |||
at, "suggestedvalues", i ) | |||
Fault( s ) | |||
e = false | |||
end | |||
if e then | |||
v = v or { } | |||
table.insert( v, e ) | |||
end | |||
end -- for i | |||
else | else | ||
Fault( string.format( "params.%s.suggestedvalues %s", | |||
at, "NOT AN ARRAY" ) ) | |||
if not | end | ||
elseif s == "string" then | |||
:css( " | s = mw.text.trim( p ) | ||
if s ~= "" then | |||
v = { } | |||
table.insert( v, | |||
{ code = s } ) | |||
end | |||
elseif s == "number" then | |||
v = { } | |||
table.insert( v, | |||
{ code = tostring( p ) } ) | |||
end | |||
if v then | |||
local d, less, story, swift, t, u | |||
r1 = mw.html.create( "ul" ) | |||
r2 = { } | |||
for i = 1, #v do | |||
u = mw.html.create( "li" ) | |||
e = v[ i ] | |||
table.insert( r2, e.code ) | |||
story = false | |||
less = ( e.less == true ) | |||
if not less then | |||
swift = e.code | |||
if e.support then | |||
local scream, support | |||
s = type( e.support ) | |||
if s == "string" then | |||
support = e.support | |||
elseif s == "table" then | |||
support = faraway( e.support ) | |||
else | |||
scream = "INVALID" | |||
end | |||
if support then | |||
s = mw.text.trim( support ) | |||
if s == "" then | |||
scream = "EMPTY" | |||
elseif s:find( "[%[%]|%<%>]" ) then | |||
scream = "BAD PAGE" | |||
else | |||
support = s | |||
end | |||
end | |||
if scream then | |||
s = string.format( "params.%s.%s[%d].support %s", | |||
at, | |||
"suggestedvalues", | |||
i, | |||
scream ) | |||
Fault( s ) | |||
else | |||
swift = string.format( "[[:%s|%s]]", | |||
support, swift ) | |||
end | |||
end | |||
if about.type:sub( 1, 5 ) == "wiki-" and | |||
swift == e.code then | |||
local rooms = { file = 6, | |||
temp = 10, | |||
user = 2 } | |||
local ns = rooms[ about.type:sub( 6, 9 ) ] or 0 | |||
t = mw.title.makeTitle( ns, swift ) | |||
if t and t.exists then | |||
swift = string.format( "[[:%s|%s]]", | |||
t.prefixedText, swift ) | |||
end | |||
end | |||
u:node( mw.html.create( "code" ) | |||
:css( "white-space", "nowrap" ) | |||
:wikitext( swift ) ) | |||
end | |||
if e.class then | |||
s = type( e.class ) | |||
if s == "string" then | |||
u:addClass( e.class ) | |||
elseif s == "table" then | |||
for k, s in pairs( e.class ) do | |||
u:addClass( s ) | |||
end -- for k, s | |||
else | |||
s = string.format( "params.%s.%s[%d].class INVALID", | |||
at, "suggestedvalues", i ) | |||
Fault( s ) | |||
end | |||
end | |||
if e.css then | |||
if type( e.css ) == "table" then | |||
u:css( e.css ) | |||
else | |||
s = string.format( "params.%s.%s[%d].css INVALID", | |||
at, "suggestedvalues", i ) | |||
Fault( s ) | |||
end | |||
end | |||
if e.style then | |||
if type( e.style ) == "string" then | |||
u:cssText( e.style ) | |||
else | |||
s = string.format( "params.%s.%s[%d].style INVALID", | |||
at, "suggestedvalues", i ) | |||
Fault( s ) | |||
end | |||
end | |||
if about.type == "wiki-file-name" and not e.icon then | |||
e.icon = e.code | |||
end | |||
if e.label then | |||
s = type( e.label ) | |||
if s == "string" then | |||
s = mw.text.trim( e.label ) | |||
if s == "" then | |||
s = string.format( "params.%s.%s[%d].label %s", | |||
at, | |||
"suggestedvalues", | |||
i, | |||
"EMPTY" ) | |||
Fault( s ) | |||
else | |||
story = s | |||
end | |||
elseif s == "table" then | |||
story = faraway( e.label ) | |||
else | |||
s = string.format( "params.%s.%s[%d].label INVALID", | |||
at, "suggestedvalues", i ) | |||
Fault( s ) | |||
end | |||
end | |||
s = false | |||
if type( e.icon ) == "string" then | |||
t = mw.title.makeTitle( 6, e.icon ) | |||
if t and t.file.exists then | |||
local g = mw.html.create( "span" ) | |||
s = string.format( "[[%s|16px]]", t.prefixedText ) | |||
g:attr( "role", "presentation" ) | |||
:wikitext( s ) | |||
s = tostring( g ) | |||
end | |||
end | |||
if not s and not less and e.label then | |||
s = mw.ustring.char( 0x2013 ) | |||
end | |||
if s then | |||
d = mw.html.create( "span" ) | |||
:wikitext( s ) | |||
if TemplateData.ltr then | |||
if not less then | |||
d:css( "margin-left", "0.5em" ) | |||
end | |||
if story then | |||
d:css( "margin-right", "0.5em" ) | |||
end | |||
else | |||
if not less then | |||
d:css( "margin-right", "0.5em" ) | |||
end | |||
if story then | |||
d:css( "margin-left", "0.5em" ) | |||
end | |||
end | |||
u:node( d ) | |||
end | |||
if story then | |||
u:wikitext( story ) | |||
end | end | ||
r1:newline() | |||
:node( u ) | |||
end -- for i | |||
end | end | ||
if | if not r1 then | ||
Fault( string.format( "params.%s.suggestedvalues INVALID", at ) ) | |||
r1 = mw.html.create( "code" ) | |||
:addClass( "error" ) | |||
:wikitext( "INVALID" ) | |||
end | end | ||
return | return r1, r2 | ||
end -- feasible() | end -- feasible() | ||
Zeile 539: | Zeile 944: | ||
local pointers = { } | local pointers = { } | ||
local points = { } | local points = { } | ||
local given = { } | |||
for k, v in pairs( Data.tree.params ) do | for k, v in pairs( Data.tree.params ) do | ||
i = facet( k, 1 ) | i = facet( k, 1 ) | ||
if type( v ) == "table" then | |||
if type( v.label ) == "string" then | |||
s = mw.text.trim( v.label ) | |||
if s == "" then | |||
s = k | |||
end | |||
else | |||
s = k | |||
end | |||
if given[ s ] then | |||
if given[ s ] == 1 then | |||
local scream = "Parameter label '%s' detected multiple times" | |||
Fault( string.format( scream, s ) ) | |||
given[ s ] = 2 | |||
end | |||
else | |||
given[ s ] = 1 | |||
end | |||
end | |||
if i then | if i then | ||
table.insert( points, i ) | table.insert( points, i ) | ||
Zeile 582: | Zeile 1.007: | ||
local code = mw.html.create( "code" ) | local code = mw.html.create( "code" ) | ||
local desc = mw.html.create( "td" ) | local desc = mw.html.create( "td" ) | ||
local eager = mw.html.create( "td" ) | |||
local legal = true | local legal = true | ||
local param = Data.tree.params[ access ] | local param = Data.tree.params[ access ] | ||
local ranking = { "required", "suggested", "optional", "deprecated" } | local ranking = { "required", "suggested", "optional", "deprecated" } | ||
local r = mw.html.create( "tr" ) | local r = mw.html.create( "tr" ) | ||
local styles = "mw-templatedata-doc-param-" | |||
local sort, typed | local sort, typed | ||
Zeile 614: | Zeile 1.041: | ||
end | end | ||
code = mw.html.create( "td" ) | code = mw.html.create( "td" ) | ||
:addClass( styles .. "name" ) | |||
:node( code ) | :node( code ) | ||
if access:match( "^%d+$" ) then | if access:match( "^%d+$" ) then | ||
Zeile 620: | Zeile 1.048: | ||
end | end | ||
if type( param.aliases ) == "table" then | if type( param.aliases ) == "table" then | ||
local lapsus | local lapsus, syn | ||
for k, v in pairs( param.aliases ) do | for k, v in pairs( param.aliases ) do | ||
code:tag( "br" ) | code:tag( "br" ) | ||
Zeile 630: | Zeile 1.058: | ||
:css( "font-style", "italic" ) | :css( "font-style", "italic" ) | ||
:wikitext( "string" ) ) | :wikitext( "string" ) ) | ||
:wikitext( s ) | |||
else | |||
syn = mw.html.create( "span" ) | |||
:addClass( styles .. "alias" ) | |||
:css( "white-space", "nowrap" ) | |||
:wikitext( s ) | |||
code:node( syn ) | |||
end | end | ||
else | else | ||
lapsus = true | lapsus = true | ||
Zeile 647: | Zeile 1.081: | ||
-- description etc. | -- description etc. | ||
s = | s = fashioned( param ) | ||
if s then | if s then | ||
desc:node( s ) | desc:node( s ) | ||
end | end | ||
if param.default or param.example or param.autovalue then | if param.style then | ||
local details = { "default", "example", "autovalue" } | s = type( param.style ) | ||
if s == "table" then | |||
desc:css( param.style ) | |||
elseif s == "string" then | |||
desc:cssText( param.style ) | |||
end | |||
end | |||
if param.suggestedvalues or | |||
param.default or | |||
param.example or | |||
param.autovalue then | |||
local details = { "suggestedvalues", | |||
"default", | |||
"example", | |||
"autovalue" } | |||
local dl = mw.html.create( "dl" ) | local dl = mw.html.create( "dl" ) | ||
local dd, section, show | local dd, section, show | ||
Zeile 671: | Zeile 1.119: | ||
if type( boole.show ) == "string" then | if type( boole.show ) == "string" then | ||
local v = mw.html.create( "span" ) | local v = mw.html.create( "span" ) | ||
:attr( "aria-hidden", "true" ) | |||
:wikitext( boole.show ) | :wikitext( boole.show ) | ||
if boole.css then | if boole.css then | ||
Zeile 685: | Zeile 1.134: | ||
:wikitext( show ) ) | :wikitext( show ) ) | ||
end | end | ||
elseif s == "suggestedvalues" then | |||
local html, values = feasible( param, access ) | |||
dd:newline() | |||
:node( html ) | |||
Data.params[ access ].suggestedvalues = values | |||
else | else | ||
dd:wikitext( show ) | dd:wikitext( show ) | ||
Zeile 697: | Zeile 1.151: | ||
-- type | -- type | ||
if type( param.type ) == "string" then | |||
param.type = mw.text.trim( param.type ) | |||
if param.type == "" then | |||
param.type = false | |||
end | |||
end | |||
if param.type then | if param.type then | ||
s = Permit.types[ param.type ] | s = Permit.types[ param.type ] | ||
typed = mw.html.create( "td" ) | typed = mw.html.create( "td" ) | ||
:addClass( styles .. "type" ) | |||
if s then | if s then | ||
if s == "string" then | if s == "string" then | ||
Zeile 728: | Zeile 1.189: | ||
typed = mw.html.create( "td" ) | typed = mw.html.create( "td" ) | ||
:wikitext( factory( "doc-param-type-unknown" ) ) | :wikitext( factory( "doc-param-type-unknown" ) ) | ||
Data.params[ access ].type = "unknown" | |||
if param.default then | |||
Data.params[ access ].default = nil | |||
Fault( "Default value requires <code>type</code>" ) | |||
legal = false | |||
end | |||
end | end | ||
-- status | -- status | ||
if param.required then | if param.required then | ||
mode = 1 | mode = 1 | ||
if param.autovalue then | |||
Fault( string.format( "autovalued <code>%s</code> required", | |||
access ) ) | |||
legal = false | |||
end | |||
if param.default then | |||
Fault( string.format( "Defaulted <code>%s</code> required", | |||
access ) ) | |||
legal = false | |||
end | |||
if param.deprecated then | if param.deprecated then | ||
Fault( string.format( "Required deprecated <code>%s</code>", | Fault( string.format( "Required deprecated <code>%s</code>", | ||
Zeile 754: | Zeile 1.230: | ||
ranking:tag( "br" ) | ranking:tag( "br" ) | ||
ranking:wikitext( param.deprecated ) | ranking:wikitext( param.deprecated ) | ||
end | |||
if param.suggested and mode == 4 then | |||
s = string.format( "Suggesting deprecated <code>%s</code>", | |||
access ) | |||
Fault( s ) | |||
legal = false | |||
end | end | ||
end | end | ||
eager:attr( "data-sort-value", tostring( mode ) ) | |||
:node( ranking ) | |||
:addClass( string.format( "%sstatus-%s", | |||
styles, status ) ) | |||
-- <tr> | -- <tr> | ||
r:attr( "id", "templatedata:" .. mw.uri.anchorEncode( access ) ) | r:attr( "id", "templatedata:" .. mw.uri.anchorEncode( access ) ) | ||
:css( Permit.css[ status ] ) | :css( Permit.css[ status ] ) | ||
:addClass( styles .. status ) | |||
:node( begin ) | :node( begin ) | ||
:node( code ) | :node( code ) | ||
:node( desc ) | :node( desc ) | ||
:node( typed ) | :node( typed ) | ||
:node( | :node( eager ) | ||
:newline() | :newline() | ||
if not legal then | if not legal then | ||
Zeile 781: | Zeile 1.266: | ||
local r | local r | ||
if Data.tree and Data.tree.params then | if Data.tree and Data.tree.params then | ||
local tbl | local tbl = mw.html.create( "table" ) | ||
local tr = mw.html.create( "tr" ) | |||
local tr | |||
feat() | feat() | ||
if Data.order and #Data.order > 1 then | if Data.order and #Data.order > 1 then | ||
tbl:addClass( "sortable" ) | tbl:addClass( "sortable" ) | ||
end | end | ||
if type( Config.classTable ) == "table" then | |||
for k, v in pairs( Config.classTable ) do | |||
tbl:addClass( v ) | |||
end -- for k, v | |||
end | |||
tbl: | if type( Config.cssTable ) == "table" then | ||
tbl:css( Config.cssTable ) | |||
end | end | ||
tr:node( mw.html.create( "th" ) | tr:node( mw.html.create( "th" ) | ||
Zeile 818: | Zeile 1.299: | ||
:newline() | :newline() | ||
if Data.order then | if Data.order then | ||
local leave, s | |||
for i = 1, #Data.order do | for i = 1, #Data.order do | ||
tbl:node( | s = Data.order[ i ] | ||
if s:sub( 1, 1 ) == "=" then | |||
leave = true | |||
tbl:node( fatten( s ) ) | |||
Data.order[ i ] = false | |||
elseif s:match( "[=|]" ) then | |||
Fault( string.format( "Bad param <code>%s</code>", | |||
s ) ) | |||
else | |||
tbl:node( feature( s ) ) | |||
end | |||
end -- for i = 1, #Data.order | end -- for i = 1, #Data.order | ||
if leave then | |||
for i = #Data.order, 1, -1 do | |||
if not Data.order[ i ] then | |||
table.remove( Data.order, i ) | |||
end | |||
end -- for i = #Data.order, 1, -1 | |||
end | |||
Data.tag.paramOrder = Data.order | |||
end | end | ||
if Config.cssTabWrap then | if Config.cssTabWrap or Data.scroll then | ||
r = mw.html.create( "div" ) | r = mw.html.create( "div" ) | ||
if type( Config.cssTabWrap ) == "table" then | if type( Config.cssTabWrap ) == "table" then | ||
Zeile 829: | Zeile 1.329: | ||
-- deprecated | -- deprecated | ||
r:cssText( Config.cssTabWrap ) | r:cssText( Config.cssTabWrap ) | ||
end | |||
if Data.scroll then | |||
r:css( "height", Data.scroll ) | |||
:css( "overflow", "auto" ) | |||
end | end | ||
r:node( tbl ) | r:node( tbl ) | ||
Zeile 840: | Zeile 1.344: | ||
local function finalize() | local function fellow( any, assigned, at ) | ||
-- Check sets[] parameter and issue error message, if necessary | |||
-- Parameter: | |||
-- any -- should be number | |||
-- assigned -- parameter name | |||
-- at -- number, of set | |||
local s | |||
if type( any ) ~= "number" then | |||
s = "<code>sets[%d].params[%s]</code>??" | |||
Fault( string.format( s, | |||
at, | |||
mw.text.nowiki( tostring( any ) ) ) ) | |||
elseif type( assigned ) == "string" then | |||
if not Data.got.params[ assigned ] then | |||
s = "<code>sets[%d].params %s</code> is undefined" | |||
Fault( string.format( s, at, assigned ) ) | |||
end | |||
else | |||
s = "<code>sets[%d].params[%d] = %s</code>??" | |||
Fault( string.format( s, k, type( assigned ) ) ) | |||
end | |||
end -- fellow() | |||
local function fellows() | |||
-- Check sets[] and issue error message, if necessary | |||
local s | |||
if type( Data.got.sets ) == "table" then | |||
if type( Data.got.params ) == "table" then | |||
for k, v in pairs( Data.got.sets ) do | |||
if type( k ) == "number" then | |||
if type( v ) == "table" then | |||
for ek, ev in pairs( v ) do | |||
if ek == "label" then | |||
s = type( ev ) | |||
if s ~= "string" and | |||
s ~= "table" then | |||
s = "<code>sets[%d].label</code>??" | |||
Fault( string.format( s, k ) ) | |||
end | |||
elseif ek == "params" and | |||
type( ev ) == "table" then | |||
for pk, pv in pairs( ev ) do | |||
fellow( pk, pv, k ) | |||
end -- for pk, pv | |||
else | |||
ek = mw.text.nowiki( tostring( ek ) ) | |||
s = "<code>sets[%d][%s]</code>??" | |||
Fault( string.format( s, k, ek ) ) | |||
end | |||
end -- for ek, ev | |||
else | |||
k = mw.text.nowiki( tostring( k ) ) | |||
v = mw.text.nowiki( tostring( v ) ) | |||
s = string.format( "<code>sets[%s][%s]</code>??", | |||
k, v ) | |||
Fault( s ) | |||
end | |||
else | |||
k = mw.text.nowiki( tostring( k ) ) | |||
s = string.format( "<code>sets[%s]</code> ?????", k ) | |||
Fault( s ) | |||
end | |||
end -- for k, v | |||
else | |||
s = "<code>params</code> required for <code>sets</code>" | |||
Fault( s ) | |||
end | |||
else | |||
s = "<code>sets</code> needs to be of <code>object</code> type" | |||
Fault( s ) | |||
end | |||
end -- fellows() | |||
local function finalize( advance ) | |||
-- Wrap presentation into frame | -- Wrap presentation into frame | ||
-- Parameter: | |||
-- advance -- true, for nice | |||
-- Returns string | -- Returns string | ||
local r | local r, lapsus | ||
if Data.div then | if Data.div then | ||
r = tostring( Data.div ) | r = tostring( Data.div ) | ||
Zeile 849: | Zeile 1.432: | ||
r = Data.strip | r = Data.strip | ||
else | else | ||
r = "" | lapsus = true | ||
r = "" | |||
end | |||
r = r .. failures() | |||
if Data.source then | |||
local live = ( advance or lapsus ) | |||
if not live then | |||
live = TemplateData.frame:preprocess( "{{REVISIONID}}" ) | |||
live = ( live == "" ) | |||
end | |||
if live then | |||
r = r .. fancy( advance, lapsus ) | |||
end | |||
end | end | ||
return r | return r | ||
end -- finalize() | end -- finalize() | ||
Zeile 874: | Zeile 1.469: | ||
local function flat( adjust ) | local function flat( adjust ) | ||
-- Remove formatting from text string | -- Remove formatting from text string for VE | ||
-- Parameter: | -- Parameter: | ||
-- arglist -- string, to be stripped, or nil | -- arglist -- string, to be stripped, or nil | ||
Zeile 882: | Zeile 1.477: | ||
r = adjust:gsub( "\n", " " ) | r = adjust:gsub( "\n", " " ) | ||
if r:find( "<noexport>", 1, true ) then | if r:find( "<noexport>", 1, true ) then | ||
r = r:gsub( "<noexport> | r = r:gsub( "<noexport>.*</noexport>", "" ) | ||
end | |||
if r:find( "<exportonly>", 1, true ) then | |||
r = r:gsub( "</?exportonly>", "" ) | |||
end | end | ||
if r:find( "''", 1, true ) then | if r:find( "''", 1, true ) then | ||
Zeile 889: | Zeile 1.487: | ||
if r:find( "<", 1, true ) then | if r:find( "<", 1, true ) then | ||
local Text = Fetch( "Text" ) | local Text = Fetch( "Text" ) | ||
r = Text.getPlain( r ) | r = Text.getPlain( r:gsub( "<br */?>", "\r\n" ) ) | ||
end | end | ||
if r:find( "[", 1, true ) then | if r:find( "[", 1, true ) then | ||
Zeile 900: | Zeile 1.498: | ||
if r:find( "&", 1, true ) then | if r:find( "&", 1, true ) then | ||
r = mw.text.decode( r ) | r = mw.text.decode( r ) | ||
if r:find( "­", 1, true ) then | |||
r = r:gsub( "­", "" ) | |||
end | |||
end | end | ||
end | end | ||
Zeile 981: | Zeile 1.582: | ||
if s == "string" then | if s == "string" then | ||
elem = fair( v ) | elem = fair( v ) | ||
elseif s == "table" then | |||
local translated | local translated | ||
v, translated = faraway( v ) | v, translated = faraway( v ) | ||
Zeile 996: | Zeile 1.597: | ||
end | end | ||
end | end | ||
if v then | if type( v ) == "string" then | ||
if scope:find( "nowiki", 1, true ) then | if k == "deprecated" then | ||
if v == "1" then | |||
v = true | |||
elseif v == "0" then | |||
v = false | |||
end | |||
elem = v | |||
elseif scope:find( "nowiki", 1, true ) then | |||
elem = mw.text.nowiki( v ) | elem = mw.text.nowiki( v ) | ||
elem = elem:gsub( " \n", "<br>" ) | |||
v = v:gsub( string.char( 13 ), "" ) | |||
else | else | ||
v = flat( v ) | v = flat( v ) | ||
end | |||
elseif s == "boolean" then | |||
if scope:find( "boolean", 1, true ) then | |||
elem = v | |||
else | |||
s = "Type <code>boolean</code> bad for " | |||
.. f( k, slot ) | |||
Fault( s ) | |||
end | end | ||
end | end | ||
Zeile 1.017: | Zeile 1.635: | ||
Data.heirs[ slot ] = v | Data.heirs[ slot ] = v | ||
v = nil | v = nil | ||
elseif k == "style" then | |||
elem = v | |||
v = nil | |||
elseif s == "string" then | elseif s == "string" then | ||
v = mw.text.nowiki( v ) | v = mw.text.nowiki( v ) | ||
Zeile 1.026: | Zeile 1.647: | ||
if type( elem ) ~= "nil" then | if type( elem ) ~= "nil" then | ||
if not target then | if not target then | ||
if access then | |||
if not Data.tree.params then | |||
Data.tree.params = { } | |||
end | |||
Data.tree.params[ slot ] = { } | |||
target = Data.tree.params[ slot ] | |||
else | |||
Data.tree = { } | |||
target = Data.tree | |||
end | |||
end | end | ||
target[ k ] = elem | target[ k ] = elem | ||
Zeile 1.043: | Zeile 1.664: | ||
if not tag then | if not tag then | ||
if access then | if access then | ||
if not Data.params then | if type( v ) == "string" and | ||
Data.params = { } | v.sub( 1, 1 ) == "=" then | ||
v = nil | |||
else | |||
if not Data.params then | |||
Data.params = { } | |||
end | |||
Data.params[ slot ] = { } | |||
tag = Data.params[ slot ] | |||
end | end | ||
else | else | ||
Data.tag = { } | Data.tag = { } | ||
Zeile 1.053: | Zeile 1.679: | ||
end | end | ||
end | end | ||
tag[ k ] = v | if type( v ) ~= "nil" and | ||
k ~= "suggestedvalues" then | |||
tag[ k ] = v | |||
end | |||
end | end | ||
else | else | ||
Zeile 1.064: | Zeile 1.693: | ||
end | end | ||
end -- for k, v | end -- for k, v | ||
if not access and Data.got.sets then | |||
fellows() | |||
end | |||
else | else | ||
Fault( f() .. " needs to be of <code>object</code> type" ) | Fault( f() .. " needs to be of <code>object</code> type" ) | ||
Zeile 1.083: | Zeile 1.715: | ||
if source:find( "|", 1, true ) then | if source:find( "|", 1, true ) then | ||
local scan = "^[\n ]*%{%{[\n _]*|[\n _]*=[\n _]*%}%}[\n ]*$" | local scan = "^[\n ]*%{%{[\n _]*|[\n _]*=[\n _]*%}%}[\n ]*$" | ||
if source:match( scan | if source:match( scan ) then | ||
code = source:gsub( "\n", "N" ) | code = source:gsub( "\n", "N" ) | ||
else | else | ||
Zeile 1.094: | Zeile 1.726: | ||
else | else | ||
local words = mw.text.split( source, "%s+" ) | local words = mw.text.split( source, "%s+" ) | ||
local show, start, unknown | local show, start, support, unknown | ||
for i = 1, #words do | for i = 1, #words do | ||
s = words[ i ] | s = words[ i ] | ||
Zeile 1.100: | Zeile 1.732: | ||
start = s | start = s | ||
end | end | ||
support = Permit.builder[ s ] | |||
if support == start or | |||
support == "*" then | |||
Permit.builder[ s ] = true | Permit.builder[ s ] = true | ||
elseif s:match( "^[1-9]%d?" ) and | |||
Permit.builder.align then | |||
Permit.builder.align = tonumber( s ) | |||
else | else | ||
if unknown then | if unknown then | ||
Zeile 1.128: | Zeile 1.765: | ||
show = "inline spaced" | show = "inline spaced" | ||
code = "{{_ | _ = _ }}" | code = "{{_ | _ = _ }}" | ||
end | |||
if Permit.builder.newlines == true then | |||
show = show or "inline" | |||
code = code or "{{_|_=_}}" | |||
show = show .. " newlines" | |||
code = string.format( "N%sN", code ) | |||
end | end | ||
elseif start == "block" then | elseif start == "block" then | ||
Zeile 1.155: | Zeile 1.798: | ||
space = " " | space = " " | ||
end | end | ||
if Permit.builder.align == true then | if type( Permit.builder.align ) ~= "string" then | ||
local n | |||
s = " align" | |||
if Permit.builder.align == true then | |||
n = 0 | |||
if type( Data.got ) == "table" and | |||
type( Data.got.params ) == "table" then | |||
for k, v in pairs( Data.got.params ) do | |||
if type( v ) == "table" and | |||
not v.deprecated and | |||
type( k ) == "string" then | |||
k = mw.ustring.len( k ) | |||
if n > 1 then | if k > n then | ||
n = k | |||
end | |||
end | |||
end -- for k, v | |||
end | |||
else | |||
n = Permit.builder.align | |||
if type( n ) == "number" and n > 1 then | |||
s = string.format( "%s %d", s, n ) | |||
else | |||
n = 0 -- How comes? | |||
end | end | ||
end | end | ||
show = show .. | if n > 1 then | ||
spaced = string.rep( "_", n - 1 ) .. " " | |||
end | |||
show = show .. s | |||
elseif Permit.builder.after == true then | elseif Permit.builder.after == true then | ||
spaced = "" | spaced = "" | ||
Zeile 1.191: | Zeile 1.847: | ||
spacer, | spacer, | ||
suffix ) | suffix ) | ||
if show == "block" then | |||
show = "block newlines" | |||
end | |||
end | end | ||
if show then | if show then | ||
Zeile 1.201: | Zeile 1.860: | ||
code = mw.text.nowiki( code ):gsub( "N", "\n" ) | code = mw.text.nowiki( code ):gsub( "N", "\n" ) | ||
code = mw.html.create( "code" ) | code = mw.html.create( "code" ) | ||
:css( "margin-left", "1em" ) | |||
:css( "margin-right", "1em" ) | |||
:wikitext( code ) | :wikitext( code ) | ||
if r then | if r then | ||
Zeile 1.211: | Zeile 1.872: | ||
end | end | ||
end | end | ||
if source then | if source and Data.tag then | ||
Data.tag.format | Data.tag.format = source | ||
end | end | ||
return r | return r | ||
Zeile 1.223: | Zeile 1.884: | ||
-- Returns <div> | -- Returns <div> | ||
local r = mw.html.create( "div" ) | local r = mw.html.create( "div" ) | ||
local | local x = fashioned( Data.tree, true, r ) | ||
if | local s | ||
r | if x then | ||
r = x | |||
end | end | ||
if Data.leading then | if Data.leading then | ||
local toc = mw.html.create( "div" ) | local toc = mw.html.create( "div" ) | ||
local shift | |||
if Config.suppressTOCnum then | if Config.suppressTOCnum then | ||
toc:addClass( Config.suppressTOCnum ) | toc:addClass( Config.suppressTOCnum ) | ||
if type( Config.stylesTOCnum ) == "string" then | |||
local src = Config.stylesTOCnum .. "/styles.css" | |||
s = TemplateData.frame:extensionTag( "templatestyles", | |||
nil, | |||
{ src = src } ) | |||
r:newline() | |||
:node( s ) | |||
end | |||
end | end | ||
toc:css( "margin-top", "0.5em" ) | toc:css( "margin-top", "0.5em" ) | ||
:wikitext( "__TOC__" ) | :wikitext( "__TOC__" ) | ||
if Data.sibling then | |||
local block = mw.html.create( "div" ) | |||
if TemplateData.ltr then | |||
shift = "right" | |||
else | |||
shift = "left" | |||
end | |||
block:css( "float", shift ) | |||
:wikitext( Data.sibling ) | |||
r:newline() | |||
:node( block ) | |||
:newline() | |||
end | |||
r:newline() | r:newline() | ||
:node( toc ) | :node( toc ) | ||
:newline() | :newline() | ||
if shift then | |||
r:node( mw.html.create( "div" ) | |||
:css( "clear", shift ) ) | |||
:newline() | |||
end | |||
end | end | ||
s = features() | s = features() | ||
if s then | if s then | ||
if Data.leading then | if Data.leading then | ||
r:node( mw.html.create( " | r:node( mw.html.create( "h" .. Config.nested ) | ||
:wikitext( factory( "doc-params" ) ) ) | :wikitext( factory( "doc-params" ) ) ) | ||
:newline() | :newline() | ||
end | end | ||
r:node( s ) | r:node( s ) | ||
end | |||
if Data.shared then | |||
local global = mw.html.create( "div" ) | |||
:attr( "id", "templatedata-global" ) | |||
local shift | |||
if TemplateData.ltr then | |||
shift = "right" | |||
else | |||
shift = "left" | |||
end | |||
global:css( "float", shift ) | |||
:wikitext( string.format( "[[%s|%s]]", | |||
Data.shared, "Global" ) ) | |||
r:newline() | |||
:node( global ) | |||
end | end | ||
if Data.tree and Data.tree.format then | if Data.tree and Data.tree.format then | ||
Zeile 1.267: | Zeile 1.971: | ||
local function free() | local function free() | ||
-- Remove JSON comment lines | -- Remove JSON comment lines | ||
Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([},\"'])", | if Data.source:find( "//", 1, true ) then | ||
Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([{},\"'])", | |||
"%1%3" ) | |||
end | |||
end -- free() | end -- free() | ||
Zeile 1.299: | Zeile 2.005: | ||
div:wikitext( Data.strip ) | div:wikitext( Data.strip ) | ||
if Config.loudly then | if Config.loudly then | ||
Data.div:node( mw.html.create( "hr" ) ) | Data.div:node( mw.html.create( "hr" ) | ||
:css( { height = "7ex" } ) ) | |||
else | else | ||
div:css( "display", "none" ) | div:css( "display", "none" ) | ||
Zeile 1.305: | Zeile 2.012: | ||
Data.div:node( div ) | Data.div:node( div ) | ||
end | end | ||
end | |||
if Data.lasting then | |||
Fault( "deprecated type syntax" ) | |||
end | |||
if Data.less then | |||
Fault( Config.solo ) | |||
end | end | ||
end -- full() | end -- full() | ||
Zeile 1.316: | Zeile 2.029: | ||
-- arglist -- table, template parameters | -- arglist -- table, template parameters | ||
-- Returns string | -- Returns string | ||
local source | local source | ||
favorize() | favorize() | ||
Zeile 1.325: | Zeile 2.037: | ||
end | end | ||
end -- for k, v | end -- for k, v | ||
if arglist.heading and arglist.heading:match( "^[3-6]$" ) then | |||
Config.nested = arglist.heading | |||
else | |||
Config.nested = "2" | |||
end | |||
Config.loudly = faculty( arglist.debug or adapt.debug ) | Config.loudly = faculty( arglist.debug or adapt.debug ) | ||
Data.lazy = faculty( arglist.lazy ) and not Config.loudly | Data.lazy = faculty( arglist.lazy ) and not Config.loudly | ||
Data.leading = faculty( arglist.TOC ) | Data.leading = faculty( arglist.TOC ) | ||
if Data.leading and arglist.TOCsibling then | |||
Data.sibling = mw.text.trim( arglist.TOCsibling ) | |||
end | |||
if arglist.lang then | |||
Data.slang = arglist.lang:lower() | |||
elseif adapt.lang then | |||
Data.slang = adapt.lang:lower() | |||
end | |||
if arglist.JSON then | if arglist.JSON then | ||
source = arglist.JSON | source = arglist.JSON | ||
elseif arglist.Global then | |||
source = TemplateData.getGlobalJSON( arglist.Global, | |||
arglist.Local ) | |||
elseif arglist[ 1 ] then | elseif arglist[ 1 ] then | ||
local s = mw.text.trim( arglist[ 1 ] ) | local s = mw.text.trim( arglist[ 1 ] ) | ||
Zeile 1.344: | Zeile 2.069: | ||
Data.strip = s | Data.strip = s | ||
end | end | ||
end | |||
if type( arglist.vertical ) == "string" and | |||
arglist.vertical:match( "^%d*%.?%d+[emprx]+$" ) then | |||
Data.scroll = arglist.vertical | |||
end | end | ||
if not source then | if not source then | ||
Zeile 1.349: | Zeile 2.078: | ||
source = find() | source = find() | ||
if not source and | if not source and | ||
not Data.title.text:match( Config.subpage ) then | not Data.title.text:match( Config.subpage ) then | ||
local s = string.format( Config.suffix, | local s = string.format( Config.suffix, | ||
Zeile 1.358: | Zeile 2.086: | ||
end | end | ||
end | end | ||
end | end | ||
if not Data.lazy | if not Data.lazy then | ||
if not Data.title then | if not Data.title then | ||
Data.title = mw.title.getCurrentTitle() | Data.title = mw.title.getCurrentTitle() | ||
Zeile 1.371: | Zeile 2.093: | ||
Data.lazy = Data.title.text:match( Config.subpage ) | Data.lazy = Data.title.text:match( Config.subpage ) | ||
end | end | ||
TemplateData.getPlainJSON( source ) | if type( source ) == "string" then | ||
return finalize() | TemplateData.getPlainJSON( source ) | ||
end | |||
return finalize( faculty( arglist.source ) ) | |||
end -- furnish() | end -- furnish() | ||
Failsafe.failsafe = function ( atleast ) | |||
-- Retrieve versioning and check for compliance | -- Retrieve versioning and check for compliance | ||
-- Precondition: | -- Precondition: | ||
-- | -- atleast -- string, with required version | ||
-- | -- or wikidata|item|~|@ or false | ||
-- Postcondition: | -- Postcondition: | ||
-- Returns string with | -- Returns string -- with queried version/item, also if problem | ||
local since = | -- false -- if appropriate | ||
-- 2020-08-17 | |||
local since = atleast | |||
local last = ( since == "~" ) | |||
local linked = ( since == "@" ) | |||
local link = ( since == "item" ) | |||
local r | local r | ||
if since == "wikidata" then | if last or link or linked or since == "wikidata" then | ||
local item = | local item = Failsafe.item | ||
since = false | since = false | ||
if type( item ) == "number" and item > 0 then | if type( item ) == "number" and item > 0 then | ||
local | local suited = string.format( "Q%d", item ) | ||
if link then | |||
r = suited | |||
else | |||
local entity = mw.wikibase.getEntity( suited ) | |||
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 | |||
elseif linked then | |||
if mw.title.getCurrentTitle().prefixedText | |||
== mw.wikibase.getSitelink( suited ) then | |||
r = false | |||
else | |||
r = suited | |||
end | |||
else | |||
r = vsn.value | |||
end | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
if | if type( r ) == "nil" then | ||
if not since or since <= | if not since or since <= Failsafe.serial then | ||
r = | r = Failsafe.serial | ||
else | else | ||
r = false | r = false | ||
Zeile 1.411: | Zeile 2.155: | ||
end | end | ||
return r | return r | ||
end -- TemplateData. | end -- Failsafe.failsafe() | ||
TemplateData.getGlobalJSON = function ( access, adapt ) | |||
-- Retrieve TemplateData from a global repository (JSON) | |||
-- Parameter: | |||
-- access -- string, with page specifier (on WikiMedia Commons) | |||
-- adapt -- JSON string or table with local overrides | |||
-- Returns true, if succeeded | |||
local plugin = Fetch( "/global" ) | |||
local r | |||
if type( plugin ) == "table" and | |||
type( plugin.fetch ) == "function" then | |||
local s, got = plugin.fetch( access, adapt ) | |||
if got then | |||
Data.got = got | |||
Data.order = got.paramOrder | |||
Data.shared = s | |||
r = true | |||
full() | |||
else | |||
Fault( s ) | |||
end | |||
end | |||
return r | |||
end -- TemplateData.getGlobalJSON() | |||
Zeile 1.421: | Zeile 2.191: | ||
-- Returns string, or not | -- Returns string, or not | ||
if type( adapt ) == "string" then | if type( adapt ) == "string" then | ||
local JSONutil = Fetch( "JSONutil", true ) | |||
Data.source = adapt | Data.source = adapt | ||
free() | free() | ||
Data.got = mw.text.jsonDecode | if JSONutil then | ||
if Data.got then | local Multilingual = Fetch( "Multilingual", true ) | ||
local f | |||
if Multilingual then | |||
f = Multilingual.i18n | |||
end | |||
Data.got = JSONutil.fetch( Data.source, true, f ) | |||
else | |||
local lucky | |||
lucky, Data.got = pcall( mw.text.jsonDecode, Data.source ) | |||
end | |||
if type( Data.got ) == "table" then | |||
full() | full() | ||
if Data. | elseif not Data.strip then | ||
local scream = type( Data.got ) | |||
if scream == "string" then | |||
scream = Data.got | |||
else | |||
scream = "Data.got: " .. scream | |||
end | end | ||
Fault( "fatal JSON error: " .. scream ) | |||
Fault( "fatal JSON error" ) | |||
end | end | ||
end | end | ||
Zeile 1.461: | Zeile 2.242: | ||
end | end | ||
return r | return r | ||
end -- p.f | end -- p.f | ||
p.failsafe = function ( frame ) | p.failsafe = function ( frame ) | ||
Zeile 1.478: | Zeile 2.259: | ||
end | end | ||
end | end | ||
return | return Failsafe.failsafe( since ) or "" | ||
end -- p.failsafe | end -- p.failsafe | ||
p.TemplateData = function () | p.TemplateData = function () |
Aktuelle Version vom 27. Januar 2023, 13:51 Uhr
Dieses Modul wurde von der deutschsprachigen Wikipedia importiert und leicht modifiziert. Es dient der erweiterten Darstellung der TemplateData zur Nutzung im VisualEditor.
Eine erweitere Dokumentation ist auf der deutschsprachigen Wikipedia verfügbar.
Versionsbezeichnung auf Wikidata: keine Version verfügbar.
Das Modul wird von der Vorlage {{TemplateData}} aufgerufen.
Benötigte weitere Module
Dieses Modul benötigt folgende weitere Module: Arguments • JSONutil • Multilingual • Namespace detect • TemplateData/config • Text • WLink • Yesno}}
local TemplateData = { suite = "TemplateData", serial = "2021-07-05", item = 46997995 } --[==[ improve template:TemplateData ]==] local Failsafe = TemplateData local Config = { -- multiple option names mapped into unique internal fields basicCnf = { catProblem = "strange", classNoNumTOC = "suppressTOCnum", classTable = "classTable", cssParWrap = "cssTabWrap", cssParams = "cssTable", docpageCreate = "suffix", docpageDetect = "subpage", helpBoolean = "support4boolean", helpContent = "support4content", helpDate = "support4date", helpFile = "support4wiki-file-name", helpFormat = "supportFormat", helpLine = "support4line", helpNumber = "support4number", helpPage = "support4wiki-page-name", helpString = "support4string", helpTemplate = "support4wiki-template-name", helpURL = "support4url", helpUser = "support4wiki-user-name", msgDescMiss = "solo", tStylesTOCnum = "stylesTOCnum" }, classTable = { "wikitable" }, -- classes for params table debugmultilang = "C0C0C0", loudly = false, -- show exported element, etc. solo = false, -- complaint on missing description strange = false, -- title of maintenance category cssTable = false, -- styles for params table cssTabWrap = false, -- styles for params table wrapper debug = false, subpage = false, -- pattern to identify subpage suffix = false, -- subpage creation scheme suppressTOCnum = false, -- class for TOC number suppression jsonDebug = "json-code-lint" -- class for jsonDebug tool } local Data = { div = false, -- <div class="mw-templatedata-doc-wrap"> got = false, -- table, initial templatedata object heirs = false, -- table, params that are inherited jump = false, -- source position at end of "params" less = false, -- main description missing lasting = false, -- old syntax encountered lazy = false, -- doc mode; do not generate effective <templatedata> leading = false, -- show TOC -- low = false, -- 1= mode order = false, -- parameter sequence params = false, -- table, exported parameters scream = false, -- error messages sibling = false, -- TOC juxtaposed slang = nil, -- project/user language code slim = false, -- JSON reduced to plain source = false, -- JSON input strip = false, -- <templatedata> evaluation tag = false, -- table, exported root element title = false, -- page tree = false -- table, rewritten templatedata object } local Permit = { builder = { after = "block", align = "block", block = "block", compressed = "block", dense = "block", grouped = "inline", half = "inline", indent = "block", inline = "inline", last = "block", lead = "block", newlines = "*", spaced = "inline" }, colors = { tableheadbg = "B3B7FF", required = "EAF3FF", suggested = "FFFFFF", optional = "EAECF0", deprecated = "FFCBCB" }, params = { aliases = "table", autovalue = "string", default = "string table I18N nowiki", deprecated = "boolean string I18N", description = "string table I18N", example = "string table I18N nowiki", label = "string table I18N", inherits = "string", required = "boolean", style = "string table", suggested = "boolean", suggestedvalues = "string table number", type = "string" }, root = { description = "string table I18N", format = "string", maps = "table", params = "table", paramOrder = "table", sets = "table" }, search = "[{,]%%s*(['\"])%s%%1%%s*:%%s*%%{", types = { boolean = true, content = true, date = true, line = true, number = true, string = true, unknown = true, url = true, ["wiki-file-name"] = true, ["wiki-page-name"] = true, ["wiki-template-name"] = true, ["wiki-user-name"] = true, ["unbalanced-wikitext"] = true, ["string/line"] = "line", ["string/wiki-page-name"] = "wiki-page-name", ["string/wiki-user-name"] = "wiki-user-name" } } local function Fault( alert ) -- Memorize error message -- Parameter: -- alert -- string, error message if Data.scream then Data.scream = string.format( "%s *** %s", Data.scream, alert ) else Data.scream = alert end end -- Fault() local function Fetch( ask, allow ) -- Fetch module -- Parameter: -- ask -- string, with name -- "/global" -- "JSONutil" -- "Multilingual" -- "Text" -- "WLink" -- allow -- true: no error if unavailable -- Returns table of module -- error: Module not available local sign = ask local r, stem if sign:sub( 1, 1 ) == "/" then sign = TemplateData.frame:getTitle() .. sign else stem = sign sign = "Module:" .. stem end if TemplateData.extern then r = TemplateData.extern[ sign ] else TemplateData.extern = { } end if not r then local lucky, g = pcall( require, sign ) if type( g ) == "table" then if stem and type( g[ stem ] ) == "function" then r = g[ stem ]() else r = g end TemplateData.extern[ sign ] = r elseif not allow then error( string.format( "Fetch(%s) %s", sign, g ), 0 ) end end return r end -- Fetch() local function Foreign() -- Guess human language -- Returns slang, or not if type( Data.slang ) == "nil" then local Multilingual = Fetch( "Multilingual", true ) if Multilingual and type( Multilingual.userLangCode ) == "function" then Data.slang = Multilingual.userLangCode() else Data.slang = mw.language.getContentLanguage():getCode() :lower() end end if Data.slang and mw.ustring.codepoint( Data.slang, 1, 1 ) > 122 then Data.slang = false end return Data.slang end -- Foreign() local function facet( ask, at ) -- Find physical position of parameter definition in JSON -- Parameter: -- ask -- string, parameter name -- at -- number, physical position within definition -- Returns number, or nil local seek = string.format( Permit.search, ask:gsub( "%%", "%%%%" ) :gsub( "([%-.()+*?^$%[%]])", "%%%1" ) ) local i, k, r, slice, source if not Data.jump then Data.jump = Data.source:find( "params", 2 ) if Data.jump then Data.jump = Data.jump + 7 else Data.jump = 1 end end i, k = Data.source:find( seek, at + Data.jump ) while i and not r do source = Data.source:sub( k + 1 ) slice = source:match( "^%s*\"([^\"]+)\"s*:" ) if not slice then slice = source:match( "^%s*'([^']+)'%s*:" ) end if ( slice and Permit.params[ slice ] ) or source:match( "^%s*%}" ) then r = k else i, k = Data.source:find( seek, k ) end end -- while i return r end -- facet() local function factory( adapt ) -- Retrieve localized text from system message -- Parameter: -- adapt -- string, message ID after "templatedata-" -- Returns string, with localized text local o = mw.message.new( "templatedata-" .. adapt ) if Foreign() then o:inLanguage( Data.slang ) end return o:plain() end -- factory() local function faculty( adjust ) -- Test template arg for boolean -- adjust -- string or nil -- Returns boolean local s = type( adjust ) local r if s == "string" then r = mw.text.trim( adjust ) r = ( r ~= "" and r ~= "0" ) elseif s == "boolean" then r = adjust else r = false end return r end -- faculty() local function failures() -- Retrieve error collection and category -- Returns string local r if Data.scream then local e = mw.html.create( "span" ) :addClass( "error" ) :wikitext( Data.scream ) r = tostring( e ) mw.addWarning( "'''TemplateData'''<br />" .. Data.scream ) if Config.strange then r = string.format( "%s[[category:%s]]", r, Config.strange ) end else r = "" end return r end -- failures() local function fair( adjust ) -- Reduce text to one line of plain text, or noexport wikitext blocks -- adjust -- string -- Returns string, with adjusted text local f = function ( a ) return a:gsub( "%s*\n%s*", " " ) :gsub( "%s%s+", " " ) end local tags = { { start = "<noexport>", stop = "</noexport>" }, { start = "<exportonly>", stop = "</exportonly>", l = false } } local r = adjust local i, j, k, s, tag for m = 1, 2 do tag = tags[ m ] if r:find( tag.start, 1, true ) then s = r r = "" i = 1 tag.l = true j, k = s:find( tag.start, i, true ) while j do if j > 1 then r = r .. f( s:sub( i, j - 1 ) ) end i = k + 1 j, k = s:find( tag.stop, i, true ) if j then if m == 1 then r = r .. s:sub( i, j - 1 ) end i = k + 1 j, k = s:find( tag.start, i, true ) else Fault( "missing " .. tag.stop ) end end -- while j r = r .. s:sub( i ) elseif m == 1 then r = f( r ) end end -- for m if tags[ 2 ].l then r = r:gsub( "<exportonly>.*</exportonly>", "" ) end return r end -- fair() local function fancy( advance, alert ) -- Present JSON source -- Parameter: -- advance -- true, for nice -- alert -- true, for visible -- Returns string local r if Data.source then local support = Config.jsonDebug local css if advance then css = { height = "6em", resize = "vertical" } r = { [ 1 ] = "syntaxhighlight", [ 2 ] = Data.source, lang = "json", style = table.concat( css, ";" ) } if alert then r.class( support ) end r = TemplateData.frame:callParserFunction( "#tag", r ) else css = { [ "font-size" ] = "77%", [ "line-height" ] = "1.35" } if alert then css.resize = "vertical" else css.display = "none" end r = mw.html.create( "pre" ) :addClass( support ) :css( css ) :wikitext( mw.text.encode( Data.source ) ) r = tostring( r ) end r = "\n".. r else r = "" end return r end -- fancy() local function faraway( alternatives ) -- Retrieve best language version from multilingual text -- Parameter: -- alternatives -- table, to be evaluated -- Returns -- 1 -- string, with best match -- 2 -- table of other versions, if any local n = 0 local variants = { } local r1, r2 for k, v in pairs( alternatives ) do if type( v ) == "string" then v = mw.text.trim( v ) if v ~= "" and type( k ) == "string" then k = k:lower() variants[ k ] = v n = n + 1 end end end -- for k, v if n > 0 then local Multilingual = Fetch( "Multilingual", true ) if Multilingual and type( Multilingual.i18n ) == "function" then local show, slang = Multilingual.i18n( variants ) if show then r1 = show variants[ slang ] = nil r2 = variants end end if not r1 then Foreign() for k, v in pairs( variants ) do if n == 1 then r1 = v elseif Data.slang == k then variants[ k ] = nil r1 = v r2 = variants end end -- for k, v end if r2 and Multilingual then for k, v in pairs( r2 ) do if v and not Multilingual.isLang( k, true ) then Fault( string.format( "%s <code>lang=%s</code>", "Invalid", k ) ) end end -- for k, v end end return r1, r2 end -- faraway() local function fashioned( about, asked, assign ) -- Create description head -- Parameter: -- about -- table, supposed to contain description -- asked -- true, if mandatory description -- assign -- <block>, if to be equipped -- Returns <block>, with head, or nil local para = assign or mw.html.create( "div" ) local plus, r if about and about.description then if type( about.description ) == "string" then para:wikitext( about.description ) else para:wikitext( about.description[ 1 ] ) plus = mw.html.create( "ul" ) plus:css( "text-align", "left" ) for k, v in pairs( about.description[ 2 ] ) do plus:node( mw.html.create( "li" ) :node( mw.html.create( "code" ) :wikitext( k ) ) :node( mw.html.create( "br" ) ) :wikitext( fair( v ) ) ) end -- for k, v if Config.loudly then plus = mw.html.create( "div" ) :css( "background-color", "#" .. Config.debugmultilang ) :node( plus ) else plus:addClass( "templatedata-maintain" ) :css( "display", "none" ) end end elseif Config.solo and asked then para:addClass( "error" ) :wikitext( Config.solo ) Data.less = true else para = false end if para then if plus then r = mw.html.create( "div" ) :node( para ) :node( plus ) else r = para end end return r end -- fashioned() local function fatten( access ) -- Create table row for sub-headline -- Parameter: -- access -- string, with name -- Returns <tr> local param = Data.tree.params[ access ] local sub, sort = access:match( "(=+)%s*(%S.*)$" ) local headline = mw.html.create( string.format( "h%d", #sub ) ) local r = mw.html.create( "tr" ) local td = mw.html.create( "td" ) :attr( "colspan", "5" ) :attr( "data-sort-value", "!" .. sort ) local s if param.style then s = type( param.style ) if s == "table" then td:css( param.style ) elseif s == "string" then td:cssText( param.style ) end end s = fashioned( param, false, headline ) if s then headline = s else headline:wikitext( sort ) end td:node( headline ) r:node( td ) return r end -- fatten() local function fathers() -- Merge params with inherited values local n = 0 local p = Data.params local t = Data.tree.params local p2, t2 for k, v in pairs( Data.heirs ) do n = n + 1 end -- for k, v for i = 1, n do if Data.heirs then for k, v in pairs( Data.heirs ) do if v and not Data.heirs[ v ] then n = n - 1 t[ k ].inherits = nil Data.heirs[ k ] = nil p2 = { } t2 = { } if p[ v ] then for k2, v2 in pairs( p[ v ] ) do p2[ k2 ] = v2 end -- for k2, v2 if p[ k ] then for k2, v2 in pairs( p[ k ] ) do if type( v2 ) ~= "nil" then p2[ k2 ] = v2 end end -- for k2, v2 end p[ k ] = p2 for k2, v2 in pairs( t[ v ] ) do t2[ k2 ] = v2 end -- for k2, v2 for k2, v2 in pairs( t[ k ] ) do if type( v2 ) ~= "nil" then t2[ k2 ] = v2 end end -- for k2, v2 t[ k ] = t2 else Fault( "No params[] inherits " .. v ) end end end -- for k, v end end -- i = 1, n if n > 0 then local s for k, v in pairs( Data.heirs ) do if v then if s then s = string.format( "%s | %s", s, k ) else s = "Circular inherits: " .. k end end end -- for k, v Fault( s ) end end -- fathers() local function favorize() -- Local customization issues local boole = { ["font-size"] = "125%" } local l, cx = pcall( mw.loadData, TemplateData.frame:getTitle() .. "/config" ) local scripting TemplateData.ltr = not mw.language.getContentLanguage():isRTL() if TemplateData.ltr then scripting = "left" else scripting = "right" end boole[ "margin-" .. scripting ] = "3em" Permit.boole = { [false] = { css = boole, lead = true, show = "☐" }, [true] = { css = boole, lead = true, show = "☑" } } Permit.css = { } for k, v in pairs( Permit.colors ) do if k == "tableheadbg" then k = "tablehead" end Permit.css[ k ] = { ["background-color"] = "#" .. v } end -- for k, v if type( cx ) == "table" then local c, s if type( cx.permit ) == "table" then if type( cx.permit.boole ) == "table" then if type( cx.permit.boole[ true ] ) == "table" then Permit.boole[ false ] = cx.permit.boole[ false ] end if type( cx.permit.boole[ true ] ) == "table" then Permit.boole[ true ] = cx.permit.boole[ true ] end end if type( cx.permit.css ) == "table" then for k, v in pairs( cx.permit.css ) do if type( v ) == "table" then Permit.css[ k ] = v end end -- for k, v end end for k, v in pairs( Config.basicCnf ) do s = type( cx[ k ] ) if s == "string" or s == "table" then Config[ v ] = cx[ k ] end end -- for k, v end if type( Config.subpage ) ~= "string" or type( Config.suffix ) ~= "string" then local got = mw.message.new( "templatedata-doc-subpage" ) local suffix if got:isDisabled() then suffix = "doc" else suffix = got:plain() end if type( Config.subpage ) ~= "string" then Config.subpage = string.format( "/%s$", suffix ) end if type( Config.suffix ) ~= "string" then Config.suffix = string.format( "%%s/%s", suffix ) end end end -- favorize() local function feasible( about, at ) -- Deal with suggestedvalues within parameter -- Parameter: -- about -- parameter details -- .suggestedvalues -- table|string|number, -- value and possibly description -- .code -- mandatory -- .label -- table|string -- .icon -- string -- .class -- table|string -- .css -- table -- .style -- string -- .less -- true: suppress code -- .type -- at -- string, with parameter name -- Returns -- 1: mw.html object -- 2: sequence table with values, or nil local p = about.suggestedvalues local s = type( p ) local e, r1, r2, v if s == "table" then if #p > 0 then for i = 1, #p do e = p[ i ] s = type( e ) if s == "table" then if type( e.code ) == "string" then s = mw.text.trim( e.code ) if s == "" then e = nil else e.code = s end else e = nil s = string.format( "params.%s.%s[%d] %s", at, "suggestedvalues", i, "MISSING 'code:'" ) end elseif s == "string" then s = mw.text.trim( e ) if s == "" then e = nil s = string.format( "params.%s.%s[%d] EMPTY", at, "suggestedvalues", i ) Fault( s ) else e = { code = s } end elseif s == "number" then e = { code = tostring( e ) } else s = string.format( "params.%s.%s[%d] INVALID", at, "suggestedvalues", i ) Fault( s ) e = false end if e then v = v or { } table.insert( v, e ) end end -- for i else Fault( string.format( "params.%s.suggestedvalues %s", at, "NOT AN ARRAY" ) ) end elseif s == "string" then s = mw.text.trim( p ) if s ~= "" then v = { } table.insert( v, { code = s } ) end elseif s == "number" then v = { } table.insert( v, { code = tostring( p ) } ) end if v then local d, less, story, swift, t, u r1 = mw.html.create( "ul" ) r2 = { } for i = 1, #v do u = mw.html.create( "li" ) e = v[ i ] table.insert( r2, e.code ) story = false less = ( e.less == true ) if not less then swift = e.code if e.support then local scream, support s = type( e.support ) if s == "string" then support = e.support elseif s == "table" then support = faraway( e.support ) else scream = "INVALID" end if support then s = mw.text.trim( support ) if s == "" then scream = "EMPTY" elseif s:find( "[%[%]|%<%>]" ) then scream = "BAD PAGE" else support = s end end if scream then s = string.format( "params.%s.%s[%d].support %s", at, "suggestedvalues", i, scream ) Fault( s ) else swift = string.format( "[[:%s|%s]]", support, swift ) end end if about.type:sub( 1, 5 ) == "wiki-" and swift == e.code then local rooms = { file = 6, temp = 10, user = 2 } local ns = rooms[ about.type:sub( 6, 9 ) ] or 0 t = mw.title.makeTitle( ns, swift ) if t and t.exists then swift = string.format( "[[:%s|%s]]", t.prefixedText, swift ) end end u:node( mw.html.create( "code" ) :css( "white-space", "nowrap" ) :wikitext( swift ) ) end if e.class then s = type( e.class ) if s == "string" then u:addClass( e.class ) elseif s == "table" then for k, s in pairs( e.class ) do u:addClass( s ) end -- for k, s else s = string.format( "params.%s.%s[%d].class INVALID", at, "suggestedvalues", i ) Fault( s ) end end if e.css then if type( e.css ) == "table" then u:css( e.css ) else s = string.format( "params.%s.%s[%d].css INVALID", at, "suggestedvalues", i ) Fault( s ) end end if e.style then if type( e.style ) == "string" then u:cssText( e.style ) else s = string.format( "params.%s.%s[%d].style INVALID", at, "suggestedvalues", i ) Fault( s ) end end if about.type == "wiki-file-name" and not e.icon then e.icon = e.code end if e.label then s = type( e.label ) if s == "string" then s = mw.text.trim( e.label ) if s == "" then s = string.format( "params.%s.%s[%d].label %s", at, "suggestedvalues", i, "EMPTY" ) Fault( s ) else story = s end elseif s == "table" then story = faraway( e.label ) else s = string.format( "params.%s.%s[%d].label INVALID", at, "suggestedvalues", i ) Fault( s ) end end s = false if type( e.icon ) == "string" then t = mw.title.makeTitle( 6, e.icon ) if t and t.file.exists then local g = mw.html.create( "span" ) s = string.format( "[[%s|16px]]", t.prefixedText ) g:attr( "role", "presentation" ) :wikitext( s ) s = tostring( g ) end end if not s and not less and e.label then s = mw.ustring.char( 0x2013 ) end if s then d = mw.html.create( "span" ) :wikitext( s ) if TemplateData.ltr then if not less then d:css( "margin-left", "0.5em" ) end if story then d:css( "margin-right", "0.5em" ) end else if not less then d:css( "margin-right", "0.5em" ) end if story then d:css( "margin-left", "0.5em" ) end end u:node( d ) end if story then u:wikitext( story ) end r1:newline() :node( u ) end -- for i end if not r1 then Fault( string.format( "params.%s.suggestedvalues INVALID", at ) ) r1 = mw.html.create( "code" ) :addClass( "error" ) :wikitext( "INVALID" ) end return r1, r2 end -- feasible() local function feat() -- Check and store parameter sequence if Data.source then local i = 0 local s for k, v in pairs( Data.tree.params ) do if i == 0 then Data.order = { } i = 1 s = k else i = 2 break -- for k, v end end -- for k, v if i > 1 then local pointers = { } local points = { } local given = { } for k, v in pairs( Data.tree.params ) do i = facet( k, 1 ) if type( v ) == "table" then if type( v.label ) == "string" then s = mw.text.trim( v.label ) if s == "" then s = k end else s = k end if given[ s ] then if given[ s ] == 1 then local scream = "Parameter label '%s' detected multiple times" Fault( string.format( scream, s ) ) given[ s ] = 2 end else given[ s ] = 1 end end if i then table.insert( points, i ) pointers[ i ] = k i = facet( k, i ) if i then s = "Parameter '%s' detected twice" Fault( string.format( s, k ) ) end else s = "Parameter '%s' not detected" Fault( string.format( s, k ) ) end end -- for k, v table.sort( points ) for i = 1, #points do table.insert( Data.order, pointers[ points[ i ] ] ) end -- i = 1, #points elseif s then table.insert( Data.order, s ) end end end -- feat() local function feature( access ) -- Create table row for parameter, check and display violations -- Parameter: -- access -- string, with name -- Returns <tr> local mode, s, status local fine = function ( a ) s = mw.text.trim( a ) return a == s and a ~= "" and not a:find( "%|=\n" ) and not a:find( "%s%s" ) end local begin = mw.html.create( "td" ) local code = mw.html.create( "code" ) local desc = mw.html.create( "td" ) local eager = mw.html.create( "td" ) local legal = true local param = Data.tree.params[ access ] local ranking = { "required", "suggested", "optional", "deprecated" } local r = mw.html.create( "tr" ) local styles = "mw-templatedata-doc-param-" local sort, typed for k, v in pairs( param ) do if v == "" then param[ k ] = false end end -- for k, v -- label sort = param.label or access if sort:match( "^%d+$" ) then begin:attr( "data-sort-value", string.format( "%05d", tonumber( sort ) ) ) end begin:css( "font-weight", "bold" ) :wikitext( sort ) -- name and aliases code:css( "font-size", "92%" ) :css( "white-space", "nowrap" ) :wikitext( access ) if not fine( access ) then code:addClass( "error" ) Fault( string.format( "Bad ID params.<code>%s</code>", access ) ) legal = false begin:attr( "data-sort-value", " " .. sort ) end code = mw.html.create( "td" ) :addClass( styles .. "name" ) :node( code ) if access:match( "^%d+$" ) then code:attr( "data-sort-value", string.format( "%05d", tonumber( access ) ) ) end if type( param.aliases ) == "table" then local lapsus, syn for k, v in pairs( param.aliases ) do code:tag( "br" ) if type( v ) == "string" then if not fine( v ) then lapsus = true code:node( mw.html.create( "span" ) :addClass( "error" ) :css( "font-style", "italic" ) :wikitext( "string" ) ) :wikitext( s ) else syn = mw.html.create( "span" ) :addClass( styles .. "alias" ) :css( "white-space", "nowrap" ) :wikitext( s ) code:node( syn ) end else lapsus = true code:node( mw.html.create( "code" ) :addClass( "error" ) :wikitext( type( v ) ) ) end end -- for k, v if lapsus then s = string.format( "params.<code>%s</code>.aliases", access ) Fault( factory( "invalid-value" ):gsub( "$1", s ) ) legal = false end end -- description etc. s = fashioned( param ) if s then desc:node( s ) end if param.style then s = type( param.style ) if s == "table" then desc:css( param.style ) elseif s == "string" then desc:cssText( param.style ) end end if param.suggestedvalues or param.default or param.example or param.autovalue then local details = { "suggestedvalues", "default", "example", "autovalue" } local dl = mw.html.create( "dl" ) local dd, section, show for i = 1, #details do s = details[ i ] show = param[ s ] if show then dd = mw.html.create( "dd" ) section = factory( "doc-param-" .. s ) if param.type == "boolean" and ( show == "0" or show == "1" ) then local boole = Permit.boole[ ( show == "1" ) ] if boole.lead == true then dd:node( mw.html.create( "code" ) :wikitext( show ) ) :wikitext( " " ) end if type( boole.show ) == "string" then local v = mw.html.create( "span" ) :attr( "aria-hidden", "true" ) :wikitext( boole.show ) if boole.css then v:css( boole.css ) end dd:node( v ) end if type( boole.suffix ) == "string" then dd:wikitext( boole.suffix ) end if boole.lead == false then dd:wikitext( " " ) :node( mw.html.create( "code" ) :wikitext( show ) ) end elseif s == "suggestedvalues" then local html, values = feasible( param, access ) dd:newline() :node( html ) Data.params[ access ].suggestedvalues = values else dd:wikitext( show ) end dl:node( mw.html.create( "dt" ) :wikitext( section ) ) :node( dd ) end end -- i = 1, #details desc:node( dl ) end -- type if type( param.type ) == "string" then param.type = mw.text.trim( param.type ) if param.type == "" then param.type = false end end if param.type then s = Permit.types[ param.type ] typed = mw.html.create( "td" ) :addClass( styles .. "type" ) if s then if s == "string" then Data.params[ access ].type = s typed:wikitext( factory( "doc-param-type-" .. s ) ) :tag( "br" ) typed:node( mw.html.create( "span" ) :addClass( "error" ) :wikitext( param.type ) ) Data.lasting = true else local support = Config[ "support4" .. param.type ] s = factory( "doc-param-type-" .. param.type ) if support then s = string.format( "[[%s|%s]]", support, s ) end typed:wikitext( s ) end else Data.params[ access ].type = "unknown" typed:addClass( "error" ) :wikitext( "INVALID" ) s = string.format( "params.<code>%s</code>.type", access ) Fault( factory( "invalid-value" ):gsub( "$1", s ) ) legal = false end else typed = mw.html.create( "td" ) :wikitext( factory( "doc-param-type-unknown" ) ) Data.params[ access ].type = "unknown" if param.default then Data.params[ access ].default = nil Fault( "Default value requires <code>type</code>" ) legal = false end end -- status if param.required then mode = 1 if param.autovalue then Fault( string.format( "autovalued <code>%s</code> required", access ) ) legal = false end if param.default then Fault( string.format( "Defaulted <code>%s</code> required", access ) ) legal = false end if param.deprecated then Fault( string.format( "Required deprecated <code>%s</code>", access ) ) legal = false end elseif param.deprecated then mode = 4 elseif param.suggested then mode = 2 else mode = 3 end status = ranking[ mode ] ranking = factory( "doc-param-status-" .. status ) if mode == 1 or mode == 4 then ranking = mw.html.create( "span" ) :css( "font-weight", "bold" ) :wikitext( ranking ) if type( param.deprecated ) == "string" then ranking:tag( "br" ) ranking:wikitext( param.deprecated ) end if param.suggested and mode == 4 then s = string.format( "Suggesting deprecated <code>%s</code>", access ) Fault( s ) legal = false end end eager:attr( "data-sort-value", tostring( mode ) ) :node( ranking ) :addClass( string.format( "%sstatus-%s", styles, status ) ) -- <tr> r:attr( "id", "templatedata:" .. mw.uri.anchorEncode( access ) ) :css( Permit.css[ status ] ) :addClass( styles .. status ) :node( begin ) :node( code ) :node( desc ) :node( typed ) :node( eager ) :newline() if not legal then r:css( "border", "#FF0000 3px solid" ) end return r end -- feature() local function features() -- Create <table> for parameters -- Returns <table>, or nil local r if Data.tree and Data.tree.params then local tbl = mw.html.create( "table" ) local tr = mw.html.create( "tr" ) feat() if Data.order and #Data.order > 1 then tbl:addClass( "sortable" ) end if type( Config.classTable ) == "table" then for k, v in pairs( Config.classTable ) do tbl:addClass( v ) end -- for k, v end if type( Config.cssTable ) == "table" then tbl:css( Config.cssTable ) end tr:node( mw.html.create( "th" ) :attr( "colspan", "2" ) :css( Permit.css.tablehead ) :wikitext( factory( "doc-param-name" ) ) ) :node( mw.html.create( "th" ) :css( Permit.css.tablehead ) :wikitext( factory( "doc-param-desc" ) ) ) :node( mw.html.create( "th" ) :css( Permit.css.tablehead ) :wikitext( factory( "doc-param-type" ) ) ) :node( mw.html.create( "th" ) :css( Permit.css.tablehead ) :wikitext( factory( "doc-param-status" ) ) ) tbl:newline() -- :node( mw.html.create( "thead" ) :node( tr ) -- ) :newline() if Data.order then local leave, s for i = 1, #Data.order do s = Data.order[ i ] if s:sub( 1, 1 ) == "=" then leave = true tbl:node( fatten( s ) ) Data.order[ i ] = false elseif s:match( "[=|]" ) then Fault( string.format( "Bad param <code>%s</code>", s ) ) else tbl:node( feature( s ) ) end end -- for i = 1, #Data.order if leave then for i = #Data.order, 1, -1 do if not Data.order[ i ] then table.remove( Data.order, i ) end end -- for i = #Data.order, 1, -1 end Data.tag.paramOrder = Data.order end if Config.cssTabWrap or Data.scroll then r = mw.html.create( "div" ) if type( Config.cssTabWrap ) == "table" then r:css( Config.cssTabWrap ) elseif type( Config.cssTabWrap ) == "string" then -- deprecated r:cssText( Config.cssTabWrap ) end if Data.scroll then r:css( "height", Data.scroll ) :css( "overflow", "auto" ) end r:node( tbl ) else r = tbl end end return r end -- features() local function fellow( any, assigned, at ) -- Check sets[] parameter and issue error message, if necessary -- Parameter: -- any -- should be number -- assigned -- parameter name -- at -- number, of set local s if type( any ) ~= "number" then s = "<code>sets[%d].params[%s]</code>??" Fault( string.format( s, at, mw.text.nowiki( tostring( any ) ) ) ) elseif type( assigned ) == "string" then if not Data.got.params[ assigned ] then s = "<code>sets[%d].params %s</code> is undefined" Fault( string.format( s, at, assigned ) ) end else s = "<code>sets[%d].params[%d] = %s</code>??" Fault( string.format( s, k, type( assigned ) ) ) end end -- fellow() local function fellows() -- Check sets[] and issue error message, if necessary local s if type( Data.got.sets ) == "table" then if type( Data.got.params ) == "table" then for k, v in pairs( Data.got.sets ) do if type( k ) == "number" then if type( v ) == "table" then for ek, ev in pairs( v ) do if ek == "label" then s = type( ev ) if s ~= "string" and s ~= "table" then s = "<code>sets[%d].label</code>??" Fault( string.format( s, k ) ) end elseif ek == "params" and type( ev ) == "table" then for pk, pv in pairs( ev ) do fellow( pk, pv, k ) end -- for pk, pv else ek = mw.text.nowiki( tostring( ek ) ) s = "<code>sets[%d][%s]</code>??" Fault( string.format( s, k, ek ) ) end end -- for ek, ev else k = mw.text.nowiki( tostring( k ) ) v = mw.text.nowiki( tostring( v ) ) s = string.format( "<code>sets[%s][%s]</code>??", k, v ) Fault( s ) end else k = mw.text.nowiki( tostring( k ) ) s = string.format( "<code>sets[%s]</code> ?????", k ) Fault( s ) end end -- for k, v else s = "<code>params</code> required for <code>sets</code>" Fault( s ) end else s = "<code>sets</code> needs to be of <code>object</code> type" Fault( s ) end end -- fellows() local function finalize( advance ) -- Wrap presentation into frame -- Parameter: -- advance -- true, for nice -- Returns string local r, lapsus if Data.div then r = tostring( Data.div ) elseif Data.strip then r = Data.strip else lapsus = true r = "" end r = r .. failures() if Data.source then local live = ( advance or lapsus ) if not live then live = TemplateData.frame:preprocess( "{{REVISIONID}}" ) live = ( live == "" ) end if live then r = r .. fancy( advance, lapsus ) end end return r end -- finalize() local function find() -- Find JSON data within page source (title) -- Returns string, or nil local s = Data.title:getContent() local i, j = s:find( "<templatedata>", 1, true ) local r if i then local k = s:find( "</templatedata>", j, true ) if k then r = mw.text.trim( s:sub( j + 1, k - 1 ) ) end end return r end -- find() local function flat( adjust ) -- Remove formatting from text string for VE -- Parameter: -- arglist -- string, to be stripped, or nil -- Returns string, or nil local r if adjust then r = adjust:gsub( "\n", " " ) if r:find( "<noexport>", 1, true ) then r = r:gsub( "<noexport>.*</noexport>", "" ) end if r:find( "<exportonly>", 1, true ) then r = r:gsub( "</?exportonly>", "" ) end if r:find( "''", 1, true ) then r = r:gsub( "'''", "" ):gsub( "''", "" ) end if r:find( "<", 1, true ) then local Text = Fetch( "Text" ) r = Text.getPlain( r:gsub( "<br */?>", "\r\n" ) ) end if r:find( "[", 1, true ) then local WLink = Fetch( "WLink" ) if WLink.isBracketedURL( r ) then r = r:gsub( "%[([hf]tt?ps?://%S+) [^%]]+%]", "%1" ) end r = WLink.getPlain( r ) end if r:find( "&", 1, true ) then r = mw.text.decode( r ) if r:find( "­", 1, true ) then r = r:gsub( "­", "" ) end end end return r end -- flat() local function flush() -- JSON encode narrowed input; obey unnamed (numerical) parameters -- Returns <templatedata> JSON string local r if Data.tag then r = mw.text.jsonEncode( Data.tag ):gsub( "%}$", "," ) else r = "{" end r = r .. "\n\"params\":{" if Data.order then local sep = "" local s for i = 1, #Data.order do s = Data.order[ i ] r = string.format( "%s%s\n%s:%s", r, sep, mw.text.jsonEncode( s ), mw.text.jsonEncode( Data.params[ s ] ) ) sep = ",\n" end -- for i = 1, #Data.order end r = r .. "\n}\n}" return r end -- flush() local function focus( access ) -- Check components; focus multilingual description, build trees -- Parameter: -- access -- string, name of parameter, nil for root local f = function ( a, at ) local r if at then r = string.format( "<code>params.%s</code>", at ) else r = "''root''" end if a then r = string.format( "%s<code>.%s</code>", r, a ) end return r end local parent if access then parent = Data.got.params[ access ] else parent = Data.got end if type( parent ) == "table" then local elem, got, permit, s, scope, slot, tag, target if access then permit = Permit.params if type( access ) == "number" then slot = tostring( access ) else slot = access end else permit = Permit.root end for k, v in pairs( parent ) do scope = permit[ k ] if scope then s = type( v ) if s == "string" and k ~= "format" then v = mw.text.trim( v ) end if scope:find( s, 1, true ) then if scope:find( "I18N", 1, true ) then if s == "string" then elem = fair( v ) elseif s == "table" then local translated v, translated = faraway( v ) if v then if translated and k == "description" then elem = { [ 1 ] = fair( v ), [ 2 ] = translated } else elem = fair( v ) end else elem = false end end if type( v ) == "string" then if k == "deprecated" then if v == "1" then v = true elseif v == "0" then v = false end elem = v elseif scope:find( "nowiki", 1, true ) then elem = mw.text.nowiki( v ) elem = elem:gsub( " \n", "<br>" ) v = v:gsub( string.char( 13 ), "" ) else v = flat( v ) end elseif s == "boolean" then if scope:find( "boolean", 1, true ) then elem = v else s = "Type <code>boolean</code> bad for " .. f( k, slot ) Fault( s ) end end else if k == "params" and not access then v = nil elem = nil elseif k == "format" and not access then elem = mw.text.decode( v ) v = nil elseif k == "inherits" then elem = v if not Data.heirs then Data.heirs = { } end Data.heirs[ slot ] = v v = nil elseif k == "style" then elem = v v = nil elseif s == "string" then v = mw.text.nowiki( v ) elem = v else elem = v end end if type( elem ) ~= "nil" then if not target then if access then if not Data.tree.params then Data.tree.params = { } end Data.tree.params[ slot ] = { } target = Data.tree.params[ slot ] else Data.tree = { } target = Data.tree end end target[ k ] = elem elem = false end if type( v ) ~= "nil" then if not tag then if access then if type( v ) == "string" and v.sub( 1, 1 ) == "=" then v = nil else if not Data.params then Data.params = { } end Data.params[ slot ] = { } tag = Data.params[ slot ] end else Data.tag = { } tag = Data.tag end end if type( v ) ~= "nil" and k ~= "suggestedvalues" then tag[ k ] = v end end else s = string.format( "Type <code>%s</code> bad for %s", scope, f( k, slot ) ) Fault( s ) end else Fault( "Unknown component " .. f( k, slot ) ) end end -- for k, v if not access and Data.got.sets then fellows() end else Fault( f() .. " needs to be of <code>object</code> type" ) end end -- focus() local function format() -- Build formatted element -- Returns <inline> local source = Data.tree.format:lower() local r, s if source == "inline" or source == "block" then r = mw.html.create( "i" ) :wikitext( source ) else local code if source:find( "|", 1, true ) then local scan = "^[\n ]*%{%{[\n _]*|[\n _]*=[\n _]*%}%}[\n ]*$" if source:match( scan ) then code = source:gsub( "\n", "N" ) else s = mw.text.nowiki( source ):gsub( "\n", "\n" ) s = tostring( mw.html.create( "code" ) :wikitext( s ) ) Fault( "Invalid format " .. s ) source = false end else local words = mw.text.split( source, "%s+" ) local show, start, support, unknown for i = 1, #words do s = words[ i ] if i == 1 then start = s end support = Permit.builder[ s ] if support == start or support == "*" then Permit.builder[ s ] = true elseif s:match( "^[1-9]%d?" ) and Permit.builder.align then Permit.builder.align = tonumber( s ) else if unknown then unknown = string.format( "%s %s", unknown, s ) else unknown = s end end end -- i = 1, #words if unknown then s = tostring( mw.html.create( "code" ) :css( "white-space", "nowrap" ) :wikitext( s ) ) Fault( "Unknown/misplaced format keyword " .. s ) source = false start = false end if start == "inline" then if Permit.builder.half == true then show = "inline half" code = "{{_ |_=_}}" elseif Permit.builder.grouped == true then show = "inline grouped" code = "{{_ | _=_}}" elseif Permit.builder.spaced == true then show = "inline spaced" code = "{{_ | _ = _ }}" end if Permit.builder.newlines == true then show = show or "inline" code = code or "{{_|_=_}}" show = show .. " newlines" code = string.format( "N%sN", code ) end elseif start == "block" then local space = "" -- amid "|" and name local spaced = " " -- preceding "=" local spacer = " " -- following "=" local suffix = "N" -- closing "}}" on new line show = "block" if Permit.builder.indent == true then start = " " show = "block indent" else start = "" end if Permit.builder.compressed == true then spaced = "" spacer = "" show = show .. " compressed" if Permit.builder.last == true then show = show .. " last" else suffix = "" end else if Permit.builder.lead == true then show = show .. " lead" space = " " end if type( Permit.builder.align ) ~= "string" then local n s = " align" if Permit.builder.align == true then n = 0 if type( Data.got ) == "table" and type( Data.got.params ) == "table" then for k, v in pairs( Data.got.params ) do if type( v ) == "table" and not v.deprecated and type( k ) == "string" then k = mw.ustring.len( k ) if k > n then n = k end end end -- for k, v end else n = Permit.builder.align if type( n ) == "number" and n > 1 then s = string.format( "%s %d", s, n ) else n = 0 -- How comes? end end if n > 1 then spaced = string.rep( "_", n - 1 ) .. " " end show = show .. s elseif Permit.builder.after == true then spaced = "" show = show .. " after" elseif Permit.builder.dense == true then spaced = "" spacer = "" show = show .. " dense" end if Permit.builder.last == true then suffix = spacer show = show .. " last" end end code = string.format( "N{{_N%s|%s_%s=%s_%s}}N", start, space, spaced, spacer, suffix ) if show == "block" then show = "block newlines" end end if show then r = mw.html.create( "span" ) :wikitext( show ) end end if code then source = code:gsub( "N", "\n" ) code = mw.text.nowiki( code ):gsub( "N", "\n" ) code = mw.html.create( "code" ) :css( "margin-left", "1em" ) :css( "margin-right", "1em" ) :wikitext( code ) if r then r = mw.html.create( "span" ) :node( r ) :node( code ) else r = code end end end if source and Data.tag then Data.tag.format = source end return r end -- format() local function formatter() -- Build presented documentation -- Returns <div> local r = mw.html.create( "div" ) local x = fashioned( Data.tree, true, r ) local s if x then r = x end if Data.leading then local toc = mw.html.create( "div" ) local shift if Config.suppressTOCnum then toc:addClass( Config.suppressTOCnum ) if type( Config.stylesTOCnum ) == "string" then local src = Config.stylesTOCnum .. "/styles.css" s = TemplateData.frame:extensionTag( "templatestyles", nil, { src = src } ) r:newline() :node( s ) end end toc:css( "margin-top", "0.5em" ) :wikitext( "__TOC__" ) if Data.sibling then local block = mw.html.create( "div" ) if TemplateData.ltr then shift = "right" else shift = "left" end block:css( "float", shift ) :wikitext( Data.sibling ) r:newline() :node( block ) :newline() end r:newline() :node( toc ) :newline() if shift then r:node( mw.html.create( "div" ) :css( "clear", shift ) ) :newline() end end s = features() if s then if Data.leading then r:node( mw.html.create( "h" .. Config.nested ) :wikitext( factory( "doc-params" ) ) ) :newline() end r:node( s ) end if Data.shared then local global = mw.html.create( "div" ) :attr( "id", "templatedata-global" ) local shift if TemplateData.ltr then shift = "right" else shift = "left" end global:css( "float", shift ) :wikitext( string.format( "[[%s|%s]]", Data.shared, "Global" ) ) r:newline() :node( global ) end if Data.tree and Data.tree.format then local e = format() if e then local show = "Format" if Config.supportFormat then show = string.format( "[[%s|%s]]", Config.supportFormat, show ) end r:node( mw.html.create( "p" ) :wikitext( show .. ": " ) :node( e ) ) end end return r end -- formatter() local function free() -- Remove JSON comment lines if Data.source:find( "//", 1, true ) then Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([{},\"'])", "%1%3" ) end end -- free() local function full() -- Build survey table from JSON data, append invisible <templatedata> Data.div = mw.html.create( "div" ) :addClass( "mw-templatedata-doc-wrap" ) focus() if Data.tag then if type( Data.got.params ) == "table" then for k, v in pairs( Data.got.params ) do focus( k ) end -- for k, v if Data.heirs then fathers() end end end Data.div:node( formatter() ) if not Data.lazy then Data.slim = flush() if TemplateData.frame then local div = mw.html.create( "div" ) local tdata = { [ 1 ] = "templatedata", [ 2 ] = Data.slim } Data.strip = TemplateData.frame:callParserFunction( "#tag", tdata ) div:wikitext( Data.strip ) if Config.loudly then Data.div:node( mw.html.create( "hr" ) :css( { height = "7ex" } ) ) else div:css( "display", "none" ) end Data.div:node( div ) end end if Data.lasting then Fault( "deprecated type syntax" ) end if Data.less then Fault( Config.solo ) end end -- full() local function furnish( adapt, arglist ) -- Analyze transclusion -- Parameter: -- adapt -- table, #invoke parameters -- arglist -- table, template parameters -- Returns string local source favorize() -- deprecated: for k, v in pairs( Config.basicCnf ) do if adapt[ k ] and adapt[ k ] ~= "" then Config[ v ] = adapt[ k ] end end -- for k, v if arglist.heading and arglist.heading:match( "^[3-6]$" ) then Config.nested = arglist.heading else Config.nested = "2" end Config.loudly = faculty( arglist.debug or adapt.debug ) Data.lazy = faculty( arglist.lazy ) and not Config.loudly Data.leading = faculty( arglist.TOC ) if Data.leading and arglist.TOCsibling then Data.sibling = mw.text.trim( arglist.TOCsibling ) end if arglist.lang then Data.slang = arglist.lang:lower() elseif adapt.lang then Data.slang = adapt.lang:lower() end if arglist.JSON then source = arglist.JSON elseif arglist.Global then source = TemplateData.getGlobalJSON( arglist.Global, arglist.Local ) elseif arglist[ 1 ] then local s = mw.text.trim( arglist[ 1 ] ) local start = s:sub( 1, 1 ) if start == "<" then Data.strip = s elseif start == "{" then source = s elseif mw.ustring.sub( s, 1, 8 ) == mw.ustring.char( 127, 39, 34, 96, 85, 78, 73, 81 ) then Data.strip = s end end if type( arglist.vertical ) == "string" and arglist.vertical:match( "^%d*%.?%d+[emprx]+$" ) then Data.scroll = arglist.vertical end if not source then Data.title = mw.title.getCurrentTitle() source = find() if not source and not Data.title.text:match( Config.subpage ) then local s = string.format( Config.suffix, Data.title.prefixedText ) Data.title = mw.title.new( s ) if Data.title.exists then source = find() end end end if not Data.lazy then if not Data.title then Data.title = mw.title.getCurrentTitle() end Data.lazy = Data.title.text:match( Config.subpage ) end if type( source ) == "string" then TemplateData.getPlainJSON( source ) end return finalize( faculty( arglist.source ) ) end -- furnish() Failsafe.failsafe = function ( atleast ) -- Retrieve versioning and check for compliance -- Precondition: -- atleast -- string, with required version -- or wikidata|item|~|@ or false -- Postcondition: -- Returns string -- with queried version/item, also if problem -- false -- if appropriate -- 2020-08-17 local since = atleast local last = ( since == "~" ) local linked = ( since == "@" ) local link = ( since == "item" ) local r if last or link or linked or since == "wikidata" then local item = Failsafe.item since = false if type( item ) == "number" and item > 0 then local suited = string.format( "Q%d", item ) if link then r = suited else local entity = mw.wikibase.getEntity( suited ) 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 elseif linked then if mw.title.getCurrentTitle().prefixedText == mw.wikibase.getSitelink( suited ) then r = false else r = suited end else r = vsn.value end 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() TemplateData.getGlobalJSON = function ( access, adapt ) -- Retrieve TemplateData from a global repository (JSON) -- Parameter: -- access -- string, with page specifier (on WikiMedia Commons) -- adapt -- JSON string or table with local overrides -- Returns true, if succeeded local plugin = Fetch( "/global" ) local r if type( plugin ) == "table" and type( plugin.fetch ) == "function" then local s, got = plugin.fetch( access, adapt ) if got then Data.got = got Data.order = got.paramOrder Data.shared = s r = true full() else Fault( s ) end end return r end -- TemplateData.getGlobalJSON() TemplateData.getPlainJSON = function ( adapt ) -- Reduce enhanced JSON data to plain text localized JSON -- Parameter: -- adapt -- string, with enhanced JSON -- Returns string, or not if type( adapt ) == "string" then local JSONutil = Fetch( "JSONutil", true ) Data.source = adapt free() if JSONutil then local Multilingual = Fetch( "Multilingual", true ) local f if Multilingual then f = Multilingual.i18n end Data.got = JSONutil.fetch( Data.source, true, f ) else local lucky lucky, Data.got = pcall( mw.text.jsonDecode, Data.source ) end if type( Data.got ) == "table" then full() elseif not Data.strip then local scream = type( Data.got ) if scream == "string" then scream = Data.got else scream = "Data.got: " .. scream end Fault( "fatal JSON error: " .. scream ) end end return Data.slim end -- TemplateData.getPlainJSON() TemplateData.test = function ( adapt, arglist ) TemplateData.frame = mw.getCurrentFrame() return furnish( adapt, arglist ) end -- TemplateData.test() -- Export local p = { } p.f = function ( frame ) -- Template call local lucky, r TemplateData.frame = frame lucky, r = pcall( furnish, frame.args, frame:getParent().args ) if not lucky then Fault( "INTERNAL: " .. r ) r = failures() end return r end -- p.f 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.TemplateData = function () -- Module interface return TemplateData end return p
Kategorien:
- Modul benötigt das Modul Arguments
- Modul benötigt das Modul JSONutil
- Modul benötigt das Modul Multilingual
- Modul benötigt das Modul Namespace detect
- Modul benötigt das Modul TemplateData/config
- Modul benötigt das Modul Text
- Modul benötigt das Modul WLink
- Modul benötigt das Modul Yesno
- Vorlagen:Formatierungshilfe