gemeinsam neue Wege der Erkenntnis gehen
Eine freie Initiative von Menschen bei anthrowiki.at anthrowiki.at, anthro.world anthro.world, biodyn.wiki biodyn.wiki und steiner.wiki steiner.wiki
mit online Lesekreisen, Übungsgruppen, Vorträgen ...
Wie Sie die Entwicklung von AnthroWiki durch Ihre Spende unterstützen können, erfahren Sie hier.

Use Google Translate for a raw translation of our pages into more than 100 languages.
Please note that some mistranslations can occur due to machine translation.
Alle Banner auf einen Klick
Grundkurs zur Ausbildung in Biographie-Arbeit
11 Wochenenden in Mannheim
5. April 2025 bis 8. Feb. 2026
Leitung Joop Grün und Walter Seyffer
+49 (0) 6203 84 390 60
www.akademie-biographiearbeit.org
Der neue Glomer Katalog 2024/25 ist da!

Aktuelle Neuerscheinungen und alle lieferbaren Bücher anthroposophischer Verlage
Anthroposophie, Waldorf, Jugend & Kinderbücher, Gesundheit, Lebensphasen, Wissenschaften mit mehr als 7.500 Titeln aus über 80 Verlagen.

Rudolf Steiner: Die Prüfung der Seele
Sonntag, 4. Mai 2025, 20h
Bild 10 - 13, mit Einführung und anschließendem Publikumsgespräch

Livestream: Anmeldung auf https://holiversitaet.de/kultur/

Modul:TemplUtl

Aus AnthroWiki

Die Dokumentation für dieses Modul kann unter Modul:TemplUtl/Doku erstellt werden

local TemplUtl = { suite  = "TemplUtl",
                   serial = "2019-02-20" };



local fiatTitleRegExp = function ( accept )
    -- Create pattern to detect page name
    -- Precondition:
    --     accept  -- string; trimmed title
    -- Postcondition:
    --     Returns string with pattern
    local start = mw.ustring.sub( accept, 1, 1 );
    local r;
    if mw.ustring.match( start, "%a" ) then
        r = string.format( "[%s%s]%s",
                           mw.ustring.lower( start ),
                           mw.ustring.upper( start ),
                           mw.ustring.sub( accept, 2 ) );
    else
        r = accept;
    end
    if r:match( " " ) then
        r = r:gsub( "%", "%%" )
             :gsub( "[%-^.?+*()$]", "%$1" )
             :gsub( "_", " " )
             :gsub( "%s+", "[%s_]+" );
    end
    return r;
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" then
                r = true;
            elseif r == "n"  or  r == "no"  or  r == "false" then
                r = false;
            else
                if not TemplUtl.L10N then
                    local lucky;
                    s = string.format( "Module:%s/local",
                                       TemplUtl.suite );
                    lucky, TemplUtl.L10N = pcall( mw.loadData, s );
                end
                if type( TemplUtl.L10N ) == "table" then
                    local entry;
                    if not TemplUtl.lang then
                        -- TODO: page language
                        TemplUtl.lang =
                              mw.language.getContentLanguage():getCode();
                    end
                    entry = TemplUtl.L10N[ TemplUtl.lang ];
                    if type( entry ) == "table" then
                        s = entry[ r ];
                        if type( s ) == "boolean" then
                            r = s;
                        end
                    end
                else
                    TemplUtl.L10N = true;
                end
                if type( r ) ~= "boolean" then
                    if type( another ) ~= "nil"  then
                        r = TemplUtl.faculty( another );
                    else
                        r = true;
                    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.failsafe = function ( assert )
    local r
    if not assert  or  assert <= TemplUtl.serial then
        r = TemplUtl.serial
    else
        r = false
    end
    return r
end -- TemplUtl.failsafe()



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( "&gt;&gt;&gt;" );
        sign = string.format( "[[#%s|%s]]",  sign,  tostring( btn ) );
        top:wikitext( sign, "&#160;", 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, frame )
    -- Simulation of template transclusion
    -- Precondition:
    --    access  -- string, or nil; page name (template)
    --    frame   -- object, or nil
    local s;
    if type( access ) == "string" then
        s = mw.text.trim( access );
        if s == "" then
            s = false;
        end
    end
    if not s then
        local cnf, lucky;
        s = string.format( "Module:%s/self", TemplUtl.suite );
        lucky, cnf = pcall( mw.loadData, s );
        if type( cnf ) == "table"  and
           cnf.loop == true then
            s = mw.title.getCurrentTitle().text;
        else
            s = false;
        end
    end
    if s then
        local f = function ()
                      framing( frame ):expandTemplate{ title = s };
                  end
        pcall( f );
    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()



TemplUtl.feasible = function ( address )
    -- Does this describe an URL beginning?
    -- Precondition:
    --    address  -- string; what to inspect, URL presumed
    -- Postcondition:
    --     Returns true, if URL beginning
    local start, r = address:match( "^%s*((%a*:?)//)" );
    if start then
        if r == "" then
            r = true;
        elseif r:sub( -1, -1 ) == ":" then
            local schemes = ":ftp:ftps:http:https:";
            r = ":" .. r:lower();
            if schemes:find( r, 1, true ) then
                r = true;
            else
                r = false;
            end
        else
            r = false;
        end
    end
    return r;
end -- TemplUtl.feasible()



TemplUtl.feed = function ( area, ahead, at, after )
    -- Detect next free "|" or "}}"
    -- Precondition:
    --     area   -- string; template transclusion
    --     ahead  -- string; opening element, or false
    --     at     -- number; byte position in area where to start
    --     after  -- true, if only to search for "}}"
    -- Postcondition:
    --     Returns
    --          -- number; byte position in area
    --             -- before "|" or "}}", may be at end
    --             -- to continue search; ahead has been closed
    --          -- true, if to be continued at number
    local j    = at;
    local loop = true;
    local c, k, r, s, seek;
    if after then
        seek = "[{}<]";
    else
        seek = "[%[%]|{}<:]";
    end
    while loop do
        j = area:find( seek, j );
        if j then
            c = area:byte( j, j );
            if c == 123 then    -- {
                k = j + 1;
                if area:byte( k, k ) == 123 then
                    k = k + 1;
                    if area:byte( k, k ) == 123 then
                        j, loop = TemplUtl.feed( area, "{{{", k, after );
                    else
                        k = k - 1;
                        j, loop = TemplUtl.feed( area, "{{", k, after );
                    end
                    if not loop then
                        r = j;
                    end
                end
            elseif c == 125 then    -- }
                k = j + 1;
                if area:byte( k, k ) == 125 then
                    if ahead == "{{" then
                        r = k;
                        break;    -- while loop;
                    elseif ahead == "{{{" then
                        k = k + 1;
                        if area:byte( k, k ) == 125 then
                            r = k;
                            break;    -- while loop;
                        end
                    elseif not ahead then
                        r    = j - 1;
                        loop = false;
                    end
                end
            elseif c == 60 then    -- <
                k = j + 3;
                if area:sub( j, k ) == "<!--" then
                    k = area:find( "-->", k );
                    if k then
                        j = k + 2;
                    end
                else
                    local skip;
                    s    = area:sub( j + 1 ):lower();
                    skip = s:match( "^%s*nowiki%s*>" );
                    if skip then
                        local n = skip:len();
                        n, k = s:find( "<%s*/%s*nowiki%s*>", n );
                        if k then
                            j = j + k;
                        else
                            loop = false;
                        end
                    end
                end
            elseif c == 124 then    -- |
                if not r then
                    r = j - 1;
                end
                if not ahead then
                    loop = false;
                end
            elseif c == 91 then    -- [
                k = j + 1;
                if area:byte( k, k ) == 91 then
                    k = k + 1;
                    j, loop = TemplUtl.feed( area, "[[", k, after );
                elseif TemplUtl.feasible( area:sub( k ) ) then
                    k = k + 3;
                    j, loop = TemplUtl.feed( area, "[", k, after );
                end
                if not loop then
                    r = j;
                end
            elseif c == 93 then    -- ]
                if ahead == "[" then
                    r = j;
                    break;    -- while loop
                elseif ahead == "[[" then
                    k = j + 1;
                    if area:byte( k, k ) == 93 then
                        r = k;
                        break;    -- while loop
                    end
                end
            elseif c == 58 then    -- :
                s = area:sub( j + 1,  j + 2 );
                if s == "//" then
                    s = " " .. area:sub( 1,  j + 2 );
                    s = s:match( "%s(%a+://)$" );
                    if s  and  TemplUtl.feasible( s ) then
                        s = area .. " ";
                        s = s:match( "([^%s|]+)%s", j );
                        if s then
                            k = s:find( "}}" );
                            if k then
                                j = j + k + 1;
                            else
                                j = j + s:len();
                            end
                        end
                    end
                end
            end
            j = j + 1;
        else
            loop = false;
        end
    end -- while loop
    if not r then
        r = area:len();
    end
    return r, loop;
end -- TemplUtl.feed()



TemplUtl.feeder = function ( area, at )
    -- Retrieve all parameters
    -- Precondition:
    --     area   -- string; template transclusion
    --     at     -- optional number; byte position in area of "{{"
    -- Postcondition:
    --     Returns
    --          -- table
    --              [0]       -- template, page, parser function name
    --              [1]       -- unnamed parameter
    --              ["name"]  -- named parameter
    --          -- string; error message, if any, else nil
    local n = 0;
    local j, k, p, r, r2, s, v;
    if type( at ) == "number" then
        j = at + 2;
    else
        j = 3;
    end
    while true do
        k = TemplUtl.feed( area, false, j );
        s = area:sub( j, k );
        s = s:gsub( "<!--.*-->", "" );
        if n == 0 then
            r = { [ 0 ] = s };
            n = 1;
        else
            p, v = s:match( "^([^=]*)=(.*)$" );
            if p then
                if p:match( "^%s*%d+%s*$" )  then
                    p = tonumber( p );
                else
                    p = mw.text.trim( p );
                end
                v = mw.text.trim( v );
            else
                p = n;
                v = s;
                n = n + 1;
            end
            if r[ p ] then
                if r2 then
                    r2 = r2 .. " * ";
                else
                    r2 = "";
                end
                r2 = string.format( "%s%s '%s'",
                                    r2,
                                    "duplicated parameter",
                                    tostring( p ) );
            end
            r[ p ] = v;
        end
        s = area:sub( k + 1,  k + 2 );
        if s == "}}" then
            break;    -- while true
        elseif s == "" then
            r2 = "template not closed";
            break;    -- while true
        end
        j = k + 2;
    end -- while true
    return r, r2;
end -- TemplUtl.feeder()



TemplUtl.fetch = function ( area, ask )
    -- Find assignment of a named template parameter
    -- Precondition:
    --     area  -- string; template transclusion
    --     ask   -- string; parameter name
    -- Postcondition:
    --     Returns string with trimmed parameter value, or nil
    --     Does not return value if template inside
    local r;
    local scan = string.format( "%s%s%s",
                                "|%s*", ask, "%s*=(.+)$" );
    r = mw.ustring.match( area, scan );
    if r then
        local j = TemplUtl.feed( r, false, 1 );
        r = r:sub( 1, j );
        if r then
            r = mw.text.trim( r );
            if r == "" then
                r = nil;
            end
        end
    end
    return r;
end -- TemplUtl.fetch()



TemplUtl.find = function ( area, access, at, alter )
    -- Find next occurrence of a template
    -- Precondition:
    --     area    -- string; where to search
    --     access  -- string; trimmed (template) title
    --     at      -- optional number; ustring position in area, if not 1
    --     alter   -- optional string; lowercase namespace pattern
    --                                 "" for article
    --                                 no colon (:)
    -- Postcondition:
    --     Returns ustring position of "{{" in area, or false
    -- Requires:
    --     fiatTitleRegExp()
    local scan = string.format( "{{%s%s%s",
                                "([%w_%s:]*)%s*",
                                fiatTitleRegExp( access ),
                                "%s*([|}<]!?)" );
    local r, space, start, suffix;
    if type( at ) == "number" then
        r = at;
    else
        r = 1;
    end
    while true do
        r = mw.ustring.find( area, scan, r );
        if r then
            start, suffix = mw.ustring.match( area, scan, r );
            if start then
                start = mw.text.trim( start );
                if start == "" then
                    break; -- while true
                elseif alter then
                    if not space then
                        space = string.format( "^:?%s:$", alter );
                    end
                    start = mw.ustring.lower( start );
                    if mw.ustring.match( start, space ) then
                        break; -- while true
                    end
                else
                    start = start:match( "^:?(.+):$" );
                    if start then
                        start = mw.ustring.lower( start );
                        if start == "template" then
                            break; -- while true
                        else
                            if not space then
                                space = mw.site.namespaces[ 10 ].name;
                                space = mw.ustring.lower( space );
                            end
                            start = start:gsub( "_", " " )
                                         :gsub( "%s+", " " );
                            if start == space then
                                break; -- while true
                            end
                        end
                    end
                end
            else
                break; -- while true
            end
            r = r + 2;
        else
            r = false;
            break; -- while true
        end
    end -- while true
    return r;
end -- TemplUtl.find()


-- finder()
--      1 page name
--      2 template title / page name
--      3 4 5 6
--        more like 2



TemplUtl.flat = function ( area )
    -- Remove syntax elements that hide effective syntax only
    -- Precondition:
    --     area  -- string; wikitext to be reduced
    -- Postcondition:
    --     Returns cleared wikitext
    local delimiters = { { "<%s*NOWIKI%s*>", "<%s*/%s*NOWIKI%s*>" },
                         { "<!--", "-->", true },
                         { "<%s*PRE%s*>", "<%s*/%s*PRE%s*>" },
                         { "<%s*SYNTAXHIGHLIGHT[^<>]*>",
                           "<%s*/%s*SYNTAXHIGHLIGHT%s*>" } };
    local i          = 1;
    local r          = area;
    local k, m, n;
    if not TemplUtl.Delimiters then
        local c, sD, sP;
        TemplUtl.Delimiters = { };
        for j = 1, #delimiters do
            table.insert( TemplUtl.Delimiters, { } );
            for ji = 1, 2 do
                sD = delimiters[ j ][ ji ];
                sP = "";
                for js = 1, #sD, 1 do
                    c = sD:byte( js, js );
                    if c >= 65  and  c <= 90 then
                        sP = string.format( "%s[%c%c]",
                                            sP,  c,  c + 32 );
                    else
                        sP = sP .. string.char( c );
                    end
                end -- for js
                table.insert( TemplUtl.Delimiters[ j ], sP );
            end -- for ji
        end -- for j
    end
    while ( true ) do
        k = false;
        for j = 1, #delimiters do
            m = r:find( TemplUtl.Delimiters[ j ][ 1 ],
                        i,
                        TemplUtl.Delimiters[ j ][ 3 ] );
            if m  and  ( not k  or  m < k ) then
                k = m;
                n = j;
            end
        end -- for j
        if k then
            local s
            if k > 1 then
                i = k - 1;
                s = r:sub( 1, i );
            else
                s = "";
            end
            j, m  =  r:find( TemplUtl.Delimiters[ n ][ 2 ],
                             k + 1,
                             TemplUtl.Delimiters[ n ][ 3 ] );
            if m then
                r = s  ..  r:sub( m + 1 );
            else
                r = s;
                break; -- while true
            end
        else
            break; -- while true
        end
    end -- while true
    return r;
end -- TemplUtl.flat()



-- Export
local p = { };

function p.faculty( frame )
    return TemplUtl.faculty( frame.args[ 1 ],
                             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.isRedirect()
    return mw.title.getCurrentTitle().isRedirect and "1"  or  "";
end -- p.isRedirect

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 TemplUtl.failsafe( since )  or  ""
end -- p.failsafe()

p.TemplUtl = function ()
    return TemplUtl;
end -- p.TemplUtl()

return p;