Nicht angemeldeter Benutzer - Bearbeiten von Seiten ist nur als angemeldeter Benutzer möglich.

Modul:Vorlage:Anker

Aus imedwiki
Zur Navigation springen Zur Suche springen

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

local Anchor = { suite   = "AnchorTemplate",
                 serial  = "2019-12-29",
                 item    = 79414611,
                 globals = { TemplUtl = 52364930 }
               }
--[=[
Template:Anchor   {{Anker}}
]=]
local Failsafe   = Anchor
local GlobalMod  = Anchor



local Config = {
    badPattern     = "[%%#'\"%[%]<>|]",
    globalPage     = { "bodyContent",
                       "catlinks",
                       "centralNotice",
                       "content",
                       "contentSub",
                       "editform",
                       "editpage-copywarn",
                       "firstHeading",
                       "footer",
                       "fundraising",
                       "jump-to-nav",
                       "page-actions",
                       "siteNotice",
                       "siteSub",
                       "toc",
                       "top" },
    globalPatterns = { "^mw%-[%l%-]+$",
                       "^ca%-[%l%-]+$",
                       "^n%-[%l%-]+$",
                       "^pt?%-[%l%-]+$",
                       "^wp%u" },
    errCat         = false,
    errClass       = "error_fragment",
    errHide        = true,
    errNS          = false,
    errInvalid     = { en = "Invalid:",
                       de = "Ungültig:" },
    errModule      = { en = "Library module missing:",
                       de = "Bibliotheksmodul fehlt:" },
    errNoFragments = { en = "No fragments given",
                       de = "Keine Bezeichner angegeben" },
    errUnkown      = { en = "Unkown parameter:",
                       de = "Parameter unbekannt:" }
}



local foreignModule = function ( access, advanced, append, alt, alert )
    -- Fetch global module
    -- Precondition:
    --     access    -- string, with name of base module
    --     advanced  -- true, for require(); else mw.loadData()
    --     append    -- string, with subpage part, if any; or false
    --     alt       -- number, of wikidata item of root; or false
    --     alert     -- true, for throwing error on data problem
    -- Postcondition:
    --     Returns whatever, probably table
    -- 2019-10-29
    local storage = access
    local finer = function ()
                      if append then
                          storage = string.format( "%s/%s",
                                                   storage,
                                                   append )
                      end
                  end
    local fun, lucky, r, suited
    if advanced then
        fun = require
    else
        fun = mw.loadData
    end
    GlobalMod.globalModules = GlobalMod.globalModules or { }
    suited = GlobalMod.globalModules[ access ]
    if not suited then
        finer()
        lucky, r = pcall( fun,  "Module:" .. storage )
    end
    if not lucky then
        if not suited  and
           type( alt ) == "number"  and
           alt > 0 then
            suited = string.format( "Q%d", alt )
            suited = mw.wikibase.getSitelink( suited )
            GlobalMod.globalModules[ access ] = suited or true
        end
        if type( suited ) == "string" then
            storage = suited
            finer()
            lucky, r = pcall( fun, storage )
        end
        if not lucky and alert then
            error( "Missing or invalid page: " .. storage, 0 )
        end
    end
    return r
end -- foreignModule()



local function factory( apply )
    -- Localization of messages
    --     apply  -- string, with message key
    -- Returns message text; at least English
    local entry = Config[ apply ]
    local r
    if entry then
        -- TODO: page language
        r = entry[ mw.language.getContentLanguage():getCode() ]
        if not r then
            r = entry.en
        end
    else
        r = tostring( mw.html.create( "span" )
                        :addClass( "error" )
                        :wikitext( string.format( "????.%s.????",
                                                  apply ) ) )
    end
    return r
end -- factory()



local function faculty( adjust )
    -- Test template arg for boolean
    --     adjust  -- string or nil
    -- Returns boolean
    local r = false
    if adjust then
        r = mw.text.trim( adjust )
        if r ~= ""  and  r ~= "0" then
            r = true
        end
    end
    return r
end -- faculty()



local function fair( assembly )
    -- Create HTML code for anchors
    --     assembly  -- sequence table, with identtifiers
    -- Returns HTML string
    local collection = mw.html.create( "" )
    local f = function ( a )
                  collection:node( mw.html.create( "span" )
                                          :attr( "id", a ) )
              end
    local s, seen, shift
    table.sort( assembly )
    for i = 1, #assembly do
        s = assembly[ i ]
        if s ~= seen then
            if not s:match( "^[%w_]+$" ) then
                shift = mw.uri.encode( s, "WIKI" )
                if shift ~= s then
                    f( shift:gsub( "%%", "." ) )
                end
            end
            f( s )
            seen = s
        end
    end -- i = 1, #assembly
    return tostring( collection )
end -- fair()



local function fault( alert, about )
    -- Format message with class="error" or similar
    --     alert  -- string, with message key
    --     about  -- string, with explanation
    -- Returns message with markup
    local scope = Config.errClass
    local story = factory( alert )
    local TemplUtl = foreignModule( "TemplUtl",
                                    true,
                                    false,
                                    Anchor.globals.TemplUtl )
    local r, scope, style
    if type( TemplUtl ) == "table"  and
       type( TemplUtl.TemplUtl ) == "function" then
        TemplUtl = TemplUtl.TemplUtl()
    else
        TemplUtl = false
    end
    if Config.self then
        story = string.format( "%s * %s", Config.self, story )
    end
    if Config.errClasses then
        if scope then
            scope = string.format( "%s %s",
                                   scope, Config.errClasses )
        else
            scope = Config.errClasses
        end
    end
    if about then
        story = string.format( "%s %s", story, about )
    end
    if TemplUtl then
        r = TemplUtl.failure( story,
                              not Config.errHide,
                              scope,
                              Config.frame )
    else
        r = tostring( mw.html.create( "span" )
                             :addClass( scope )
                             :addClass( "error" )
                             :wikitext( story ) )
    end
    if Config.errCat then
        if Config.errNS then
            local st = type( Config.errNS )
            if st == "number" then
                st = { }
                table.insert( st, Config.errNS )
                Config.errNS = st
            elseif st == "string" then
                Config.errNS = mw.text.split( Config.errNS, "%s+" )
                for i = 1, #Config.errNS do
                    Config.errNS[ i ] = tonumber( Config.errNS[ i ] )
                end -- for i
            end
            if type( Config.errNS ) == "table" then
                local ns = mw.title.getCurrentTitle().namespace
                for i = 1, #Config.errNS do
                    if Config.errNS[ i ] == ns then
                        Config.errNS = false
                        break    -- for i
                    end
                end -- for i
            end
        end
        if not Config.errNS then
            r = string.format( "%s[[Category:%s]]", r, Config.errCat )
        end
    end
    return r
end -- fault()



local function main( argsF, argsT )
    -- Invocation
    --     argsF  -- table, with #invoke parameters, or false
    --     argsT  -- table, with template parameters
    -- Returns appropriate string
    local r
    if argsF then
        Config.errCat     = argsF.errCat
        Config.errClasses = argsF.errClasses
        Config.errHide    = faculty( argsF.errHide )
        Config.errNS      = argsF.errNS
if mw.site.server:find( "de.wikipedia.org", 1, true ) then
    Config.errClasses = "Linkwartung"
    Config.errHide = true
    Config.errNS = 0
end
    end
    if type( argsT ) == "table" then
        local checked = { }
        local tocheck = { }
        local further = function ( add )
                            local s = add:gsub( " +", "_" )
                                         :gsub( "_+", "_" )
                            table.insert( checked,s )
                        end
        local less, s, unknown
        for k, v in pairs( argsT ) do
            if type( k ) == "number" then
                v = mw.text.trim( v )
                if v == "" then
                    v = false
                end
                less = ( k < 0 )
                k = false
            else
                less = k:match( "^[x%-][1-9]%d*" )
                if less then
                    k = false
                end
            end
            if k then
                unknown = unknown  or  { }
                table.insert( unknown, k )
            elseif v then
                if less then
                    further( v )
                else
                    table.insert( tocheck, v )
                end
            end
        end -- for k, v
        if unknown then
            local e = mw.html.create( "code" )
                        :css( "white-space", "nowrap" )
                        :wikitext( table.concat( unknown, " " ) )
            s = string.format( " in [[%s]]",
                               Config.frame:getTitle() )
            e:tag( "span" )
             :wikitext( s )
            r = fault( "errUnkown", tostring( e ) )
        else
            local bad, e
            local flop = function ( a, alter )
                             if not bad then
                                 bad = { }
                             end
                             e = mw.html.create( "code" )
                                        :wikitext( a )
                             if alter then
                                 e:css( "white-space", "nowrap" )
                             end
                             table.insert( bad, tostring( e ) )
                         end
            local legal, s
            for i = 1, #tocheck do
                s = mw.text.unstripNoWiki( tocheck[ i ] )
                if s:match( "^%d" )   or
                   s:sub( 1, 1 ) == "-"   or
                   s:match( Config.badPattern )   or
                   s:match( "&#%w+;" ) then
                    legal = false
                else
                    legal = true
                    for k = 1, #Config.globalPatterns do
                        if s:match( Config.globalPatterns[ k ] ) then
                            legal = false
                            break    -- k = 1, #Config.globalPatterns
                        end
                    end -- k = 1, #Config.globalPatterns
                end
                if not legal then
                    flop( mw.text.encode( s ),  true )
                else
                    further( s )
                end
            end -- i = 1, #tocheck
            for i = 1, #checked do
                s = checked[ i ]
                for k = 1, #Config.globalPage do
                    if s == Config.globalPage[ k ] then
                        flop( s )
                        break    -- k = 1, #Config.globalPage
                    end
                end -- k = 1, #Config.globalPage
            end -- i = 1, #checked
            if bad then
                s = string.format( "%s in [[%s]]",
                                   table.concat( bad, ", " ),
                                   Config.frame:getParent():getTitle() )
                r = fault( "errInvalid", s )
            elseif #checked == 0 then
                r = fault( "errNoFragments" )
            else
                r = fair( checked )
            end
        end
    end
    return r or ""
end -- main()



Failsafe.failsafe = function ( atleast )
    -- Retrieve versioning and check for compliance
    -- Precondition:
    --     atleast  -- string, with required version or "wikidata" or "~"
    --                 or false
    -- Postcondition:
    --     Returns  string  -- with queried version, also if problem
    --              false   -- if appropriate
    -- 2019-10-15
    local last  = ( atleast == "~" )
    local since = atleast
    local r
    if last  or  since == "wikidata" then
        local item = Failsafe.item
        since = false
        if type( item ) == "number"  and  item > 0 then
            local entity = mw.wikibase.getEntity( string.format( "Q%d",
                                                                 item ) )
            if type( entity ) == "table" then
                local seek = Failsafe.serialProperty or "P348"
                local vsn  = entity:formatPropertyValues( seek )
                if type( vsn ) == "table"  and
                   type( vsn.value ) == "string"  and
                   vsn.value ~= "" then
                    if last  and  vsn.value == Failsafe.serial then
                        r = false
                    else
                        r = vsn.value
                    end
                end
            end
        end
    end
    if type( r ) == "nil" then
        if not since  or  since <= Failsafe.serial then
            r = Failsafe.serial
        else
            r = false
        end
    end
    return r
end -- Failsafe.failsafe()



-- Export
local p = { }

p.f = function ( frame )
    local lucky, r
    Config.frame = frame
    lucky, r = pcall( main, frame.args, frame:getParent().args )
    if not lucky then
        r = tostring( mw.html.create( "span" )
                        :addClass( "error" )
                        :wikitext( string.format( "%s * %s",
                                                  frame:getTitle(),
                                                  r ) ) )
    end
    return r
end -- p.f()

p.flops = function ( frame )
    local r   = ""
    local sep = ""
    local e
    for k = 1, #Config.globalPage do
        e   = mw.html.create( "code" )
                     :css( "white-space", "nowrap" )
                     :wikitext( Config.globalPage[ k ] )
        r   = string.format( "%s%s%s", r, sep, tostring( e ) )
        sep = ", "
    end -- k = 1, #Config.globalPage
    return r
end -- p.flops()

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()

return p