395
Bearbeitungen
(2016-02-28) |
K (21 Versionen importiert: Doku-Vorlage) |
||
(18 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
local TemplUtl = { suite = "TemplUtl", | local TemplUtl = { suite = "TemplUtl", | ||
serial = " | serial = "2019-11-20", | ||
local | item = 52364930 }; | ||
local Failsafe = TemplUtl; | |||
local fallible = function ( adjust, ahead ) | |||
-- Check for leading character disturbing syntax | |||
-- Precondition: | |||
-- adjust -- string; trimmed wikitext | |||
-- ahead -- true, if leading syntax shall start on new line | |||
-- Postcondition: | |||
-- Returns string, modified if necessary | |||
local r = adjust; | |||
local c = r:byte( 1, 1 ); | |||
if c <= 59 and | |||
( c==35 or c==42 or c==58 or c==59 ) then | |||
if ahead then | |||
r = "\n" .. r; | |||
else | |||
r = mw.text.nowiki( r:sub( 1, 1 ) ) .. r:sub( 2 ); | |||
end | |||
elseif ahead then | |||
local c2 = r:byte( 2, 1 ); | |||
if ( c==123 and c2==124 ) or | |||
( c==124 and c2==45 ) then | |||
r = "\n" .. r; | |||
end | |||
end | |||
return r; | |||
end -- fallible() | |||
Zeile 10: | Zeile 39: | ||
-- accept -- string; trimmed title | -- accept -- string; trimmed title | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns string with pattern | ||
local start = mw.ustring.sub( accept, 1, 1 ); | local start = mw.ustring.sub( accept, 1, 1 ); | ||
local r; | local r; | ||
Zeile 23: | Zeile 52: | ||
if r:match( " " ) then | if r:match( " " ) then | ||
r = r:gsub( "%", "%%" ) | r = r:gsub( "%", "%%" ) | ||
:gsub( "[^.?+*()$] | :gsub( "[%-^.?+*()$]", "%$1" ) | ||
:gsub( "_", " " ) | :gsub( "_", " " ) | ||
:gsub( "%s+", "[%s_]+" ); | :gsub( "%s+", "[%s_]+" ); | ||
Zeile 29: | Zeile 58: | ||
return r; | return r; | ||
end -- fiatTitleRegExp() | end -- fiatTitleRegExp() | ||
local framing = function ( frame ) | |||
if not TemplUtl.frame then | |||
if type( frame ) == "table" then | |||
TemplUtl.frame = frame; | |||
else | |||
TemplUtl.frame = mw.getCurrentFrame(); | |||
end | |||
end | |||
return TemplUtl.frame; | |||
end -- framing() | |||
TemplUtl.faculty = function ( analyze, another ) | |||
-- Test template arg for boolean | |||
-- analyze -- string, boolean, number or nil | |||
-- another -- fallback: string, boolean, or nil | |||
-- Returns boolean | |||
local s = type( analyze ); | |||
local r; | |||
if s == "string" then | |||
r = mw.text.trim( analyze ); | |||
if r == "" then | |||
r = TemplUtl.faculty( another, nil ); | |||
elseif r:find( "1", 1, true ) and | |||
r:match( "^[0%-]*1[01%-]*$") then | |||
r = true; | |||
elseif r:match( "^[0%-]+$") then | |||
r = false; | |||
else | |||
r = r:lower(); | |||
if r == "y" or | |||
r == "yes" or | |||
r == "true" or | |||
r == "on" then | |||
r = true; | |||
elseif r == "n" or | |||
r == "no" or | |||
r == "false" or | |||
r == "off" then | |||
r = false; | |||
else | |||
if not TemplUtl.boolang then | |||
-- TODO: page language | |||
local l, d = pcall( mw.ext.data.get, "i18n/01.tab" ); | |||
if type( d ) == "table" and | |||
type( d.data ) == "table" then | |||
local f = function ( at ) | |||
local e = d.data[ at ]; | |||
l = e[ 1 ]; | |||
s = e[ 2 ]; | |||
if type( l ) == "boolean" and | |||
type( s ) == "string" then | |||
s = mw.text.split( s, "|" ); | |||
for i = 1, #s do | |||
TemplUtl.boolang[ s[ i ] ] = l; | |||
end -- for i | |||
end | |||
end | |||
TemplUtl.boolang = { }; | |||
f( 1 ); | |||
f( 2 ); | |||
else | |||
TemplUtl.boolang = true; | |||
end | |||
end | |||
if type( TemplUtl.boolang ) == "table" then | |||
s = TemplUtl.boolang[ r ]; | |||
if type( s ) == "boolean" then | |||
r = s; | |||
end | |||
end | |||
if type( r ) ~= "boolean" then | |||
s = type( another ); | |||
if s == "nil" then | |||
r = true; | |||
elseif s == "boolean" then | |||
r = another; | |||
else | |||
r = TemplUtl.faculty( another ); | |||
end | |||
end | |||
end | |||
end | |||
elseif s == "boolean" then | |||
r = analyze; | |||
elseif s == "number" then | |||
r = ( analyze ~= 0 ); | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- TemplUtl.faculty() | |||
TemplUtl.failure = function ( alert, always, addClass, frame ) | |||
-- Format error message, mostly hidden | |||
-- alert -- string: message | |||
-- always -- boolean, or nil: do not hide | |||
-- addClass -- string, or nil: add classes to element | |||
-- frame -- object, or nil | |||
-- Returns string | |||
local err = mw.html.create( "span" ) | |||
:addClass( "error" ) | |||
:wikitext( alert ); | |||
local live = ( framing( frame ):preprocess( "{{REVISIONID}}" ) | |||
== "" ); | |||
if type( addClass ) == "string" then | |||
err:addClass( addClass ) | |||
end | |||
if live then | |||
local max = 1000000000; | |||
local id = math.floor( os.clock() * max ); | |||
local sign = string.format( "error_%d", id ); | |||
local btn = mw.html.create( "span" ); | |||
local top = mw.html.create( "div" ); | |||
err:attr( "id", sign ); | |||
-- TODO: LTR | |||
btn:css( { ["background"] = "#FFFF00", | |||
["border"] = "#FF0000 3px solid", | |||
["font-weight"] = "bold", | |||
["padding"] = "2px", | |||
["text-decoration"] = "none" } ) | |||
:wikitext( ">>>" ); | |||
sign = string.format( "[[#%s|%s]]", sign, tostring( btn ) ); | |||
top:wikitext( sign, " ", alert ); | |||
mw.addWarning( tostring( top:attr( "role", "alert" ) ) ); | |||
elseif not always then | |||
err:css( { ["display"] = "none" } ); | |||
-- err:css( { ["display"] = "inline-block", | |||
-- ["line-height"] = "0", | |||
-- ["max-height"] = "0", | |||
-- ["max-width"] = "0", | |||
-- ["visibility"] = "hidden" } ); | |||
end | |||
return tostring( err ); | |||
end -- TemplUtl.failure() | |||
TemplUtl.fake = function ( access ) | |||
-- Simulation of template transclusion | |||
-- Precondition: | |||
-- access -- string; page name (template) | |||
if type( access ) == "string" then | |||
local s = mw.text.trim( access ); | |||
if s ~= "" then | |||
local t = mw.title.new( s, 10 ); | |||
if not mw.title.equals( mw.title.getCurrentTitle(), t ) and | |||
t.exists then | |||
t:getContent(); | |||
end | |||
end | |||
end | |||
end -- TemplUtl.fake() | |||
TemplUtl.fakes = function ( array, frame, ahead, answer ) | |||
-- Simulation of template transclusions | |||
-- Precondition: | |||
-- array -- table, with template title strings | |||
-- frame -- object, or nil | |||
-- ahead -- string, or nil, with common prefix | |||
-- answer -- true, or nil, for list creation | |||
-- Postcondition: | |||
-- Returns string, if answer requested | |||
local e = framing( frame ); | |||
local f = function ( a ) | |||
e:expandTemplate{ title = a }; | |||
end | |||
local s = ahead or ""; | |||
local r; | |||
for k, v in pairs( array ) do | |||
if type( k ) == "number" and | |||
type( v ) == "string" then | |||
v = s .. mw.text.trim( v ); | |||
pcall( f, v ); | |||
if answer then | |||
if r then | |||
r = r .. "\n"; | |||
else | |||
r = ""; | |||
end | |||
r = string.format( "%s* [[Template:%s|%s]]", r, v, v ); | |||
end | |||
end | |||
end -- for k, v | |||
return r; | |||
end -- TemplUtl.fakes() | |||
Zeile 37: | Zeile 260: | ||
-- address -- string; what to inspect, URL presumed | -- address -- string; what to inspect, URL presumed | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns true, if URL beginning | ||
local start, r = address:match( "^%s*((%a*:?)//)" ); | local start, r = address:match( "^%s*((%a*:?)//)" ); | ||
if start then | if start then | ||
Zeile 67: | Zeile 290: | ||
-- after -- true, if only to search for "}}" | -- after -- true, if only to search for "}}" | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns | ||
-- -- number; byte position in area | -- -- number; byte position in area | ||
-- -- before "|" or "}}", may be at end | -- -- before "|" or "}}", may be at end | ||
Zeile 204: | Zeile 427: | ||
-- at -- optional number; byte position in area of "{{" | -- at -- optional number; byte position in area of "{{" | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns | ||
-- -- table | -- -- table | ||
-- [0] -- template, page, parser function name | -- [0] -- template, page, parser function name | ||
Zeile 271: | Zeile 494: | ||
-- ask -- string; parameter name | -- ask -- string; parameter name | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns string with trimmed parameter value, or nil | ||
-- Does not return value if template inside | -- Does not return value if template inside | ||
local r; | local r; | ||
Zeile 302: | Zeile 525: | ||
-- no colon (:) | -- no colon (:) | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns ustring position of "{{" in area, or false | ||
-- Requires: | -- Requires: | ||
-- fiatTitleRegExp() | -- fiatTitleRegExp() | ||
Zeile 368: | Zeile 591: | ||
-- 3 4 5 6 | -- 3 4 5 6 | ||
-- more like 2 | -- more like 2 | ||
TemplUtl.firstbreak = function ( adjust ) | |||
-- Precede leading character with newline if specific syntax | |||
-- Precondition: | |||
-- adjust -- string; trimmed wikitext | |||
-- Postcondition: | |||
-- Returns string, modified if necessary | |||
return fallible( adjust, true ); | |||
end -- TemplUtl.firstbreak() | |||
Zeile 374: | Zeile 608: | ||
-- Remove syntax elements that hide effective syntax only | -- Remove syntax elements that hide effective syntax only | ||
-- Precondition: | -- Precondition: | ||
-- area -- string; wikitext to be reduced | -- area -- string; unparsed wikitext to be reduced | ||
-- Postcondition: | -- Postcondition: | ||
-- | -- Returns cleared wikitext | ||
local delimiters = { { "<%s*NOWIKI%s*>", "<%s*/%s*NOWIKI%s*>" }, | local delimiters = { { "<%s*NOWIKI%s*>", "<%s*/%s*NOWIKI%s*>" }, | ||
{ "<!--", "-->", true }, | { "<!--", "-->", true }, | ||
Zeile 385: | Zeile 619: | ||
local r = area; | local r = area; | ||
local k, m, n; | local k, m, n; | ||
if not Delimiters then | if not TemplUtl.Delimiters then | ||
local c, sD, sP; | local c, sD, sP; | ||
Delimiters = { }; | TemplUtl.Delimiters = { }; | ||
for j = 1, #delimiters do | for j = 1, #delimiters do | ||
table.insert( Delimiters, { } ); | table.insert( TemplUtl.Delimiters, { } ); | ||
for ji = 1, 2 do | for ji = 1, 2 do | ||
sD = delimiters[ j ][ ji ]; | sD = delimiters[ j ][ ji ]; | ||
Zeile 402: | Zeile 636: | ||
end | end | ||
end -- for js | end -- for js | ||
table.insert( Delimiters[ j ], sP ); | table.insert( TemplUtl.Delimiters[ j ], sP ); | ||
end -- for ji | end -- for ji | ||
end -- for j | end -- for j | ||
Zeile 409: | Zeile 643: | ||
k = false; | k = false; | ||
for j = 1, #delimiters do | for j = 1, #delimiters do | ||
m = r:find( Delimiters[ j ][ 1 ], | m = r:find( TemplUtl.Delimiters[ j ][ 1 ], | ||
i, | i, | ||
Delimiters[ j ][ 3 ] ); | TemplUtl.Delimiters[ j ][ 3 ] ); | ||
if m and ( not k or m < k ) then | if m and ( not k or m < k ) then | ||
k = m; | k = m; | ||
Zeile 425: | Zeile 659: | ||
s = ""; | s = ""; | ||
end | end | ||
j, m = r:find( Delimiters[ n ][ 2 ], | j, m = r:find( TemplUtl.Delimiters[ n ][ 2 ], | ||
k + 1, | k + 1, | ||
Delimiters[ n ][ 3 ] ); | TemplUtl.Delimiters[ n ][ 3 ] ); | ||
if m then | if m then | ||
r = s .. r:sub( m + 1 ); | r = s .. r:sub( m + 1 ); | ||
Zeile 440: | Zeile 674: | ||
return r; | return r; | ||
end -- TemplUtl.flat() | end -- TemplUtl.flat() | ||
TemplUtl.nowiki1 = function ( adjust ) | |||
-- HTML-escape leading character if disturbing syntax | |||
-- Precondition: | |||
-- adjust -- string; trimmed wikitext | |||
-- Postcondition: | |||
-- Returns string, modified if necessary | |||
return fallible( adjust, false ); | |||
end -- TemplUtl.nowiki1() | |||
Failsafe.failsafe = function ( atleast ) | |||
-- Retrieve versioning and check for compliance | |||
-- Precondition: | |||
-- atleast -- string, with required version or "wikidata" or "~" | |||
-- or false | |||
-- Postcondition: | |||
-- Returns string -- with queried version, also if problem | |||
-- false -- if appropriate | |||
local last = ( atleast == "~" ) | |||
local since = atleast | |||
local r | |||
if last or since == "wikidata" then | |||
local item = Failsafe.item | |||
since = false | |||
if type( item ) == "number" and item > 0 then | |||
local entity = mw.wikibase.getEntity( string.format( "Q%d", | |||
item ) ) | |||
if type( entity ) == "table" then | |||
local seek = Failsafe.serialProperty or "P348" | |||
local vsn = entity:formatPropertyValues( seek ) | |||
if type( vsn ) == "table" and | |||
type( vsn.value ) == "string" and | |||
vsn.value ~= "" then | |||
if last and vsn.value == Failsafe.serial then | |||
r = false | |||
else | |||
r = vsn.value | |||
end | |||
end | |||
end | |||
end | |||
end | |||
if type( r ) == "nil" then | |||
if not since or since <= Failsafe.serial then | |||
r = Failsafe.serial | |||
else | |||
r = false | |||
end | |||
end | |||
return r | |||
end -- Failsafe.failsafe() | |||
Zeile 446: | Zeile 735: | ||
local p = { }; | local p = { }; | ||
function p.failsafe() | function p.faculty( frame ) | ||
return | return TemplUtl.faculty( frame.args[ 1 ], | ||
end | frame.args[ 2 ] ) and "1" | ||
or ""; | |||
end -- p.faculty | |||
function p.failure( frame ) | |||
local scream = mw.text.trim( frame.args[ 1 ] or "" ); | |||
local loud = frame.args[ 2 ]; | |||
local select = frame.args.class; | |||
if scream == "" then | |||
scream = "?????????"; | |||
end | |||
if loud then | |||
loud = TemplUtl.faculty( loud, nil ); | |||
end | |||
return TemplUtl.failure( scream, loud, select, frame ); | |||
end -- p.failure | |||
function p.fake( frame ) | |||
TemplUtl.fake( frame.args[ 1 ] or "", frame ); | |||
return ""; | |||
end -- p.fake | |||
function p.fakes( frame ) | |||
local list = ( frame.args.list == "1" ); | |||
local r = TemplUtl.fakes( frame.args, | |||
frame, | |||
frame.args.prefix, | |||
list ); | |||
return r or ""; | |||
end -- p.fakes | |||
function p.firstbreak( frame ) | |||
local r = ( frame.args[ 1 ] ); | |||
if r then | |||
r = mw.text.trim( r ); | |||
if r ~= "" then | |||
r = TemplUtl.firstbreak( r ); | |||
end | |||
end | |||
return r or ""; | |||
end -- p.firstbreak | |||
function p.from( frame ) | |||
local r = frame:getParent():getTitle(); | |||
if r then | |||
r = string.format( "{{%s}}", r ); | |||
end | |||
return r or ""; | |||
end -- p.from | |||
function p.isRedirect() | |||
return mw.title.getCurrentTitle().isRedirect and "1" or ""; | |||
end -- p.isRedirect | |||
function p.nowiki1( frame ) | |||
local r = ( frame.args[ 1 ] ); | |||
if r then | |||
r = mw.text.trim( r ); | |||
if r ~= "" then | |||
r = TemplUtl.nowiki1( r ); | |||
end | |||
end | |||
return r or ""; | |||
end -- p.nowiki1 | |||
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.TemplUtl = function () | p.TemplUtl = function () | ||
return TemplUtl; | return TemplUtl; | ||
end | end -- p.TemplUtl() | ||
return p; | return p; |