Dokumentation für das Modul Hilfe:VisualEditor[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]
Das Modul dient der Gestaltung der Hilfeartikel zum VisualEditor
Hinweise
local HelpVisualEditor = { suite  = "HelpVisualEditor",                            serial = "2019-05-16",                            item   = 63383133 } --[=[ Unterstützung für Vorlagen/Hilfeseiten Hilfe:VisualEditor/*** ]=]    local lucky, Data = pcall( mw.loadData,                            "Module:Hilfe:VisualEditor/config" ) if type( Data ) ~= "table" then     error( "[[Module:Hilfe:VisualEditor/config]] fehlt" ) end local Config  = Data.config local Widgets = { } local Frame local Title local Tree    local function facet( activate )     return activate:gsub( "%.svg$", "-progressive.svg" ) end -- facet()    local function factory( ancestor, array, all )     -- Clone a table     -- Parameter:     --     ancestor  -- table, to be copied     --     array     -- true, if sequence; number: copy first elements     --     all       -- true, if deep elements to be copied also     -- Returns:     --     new table     local r = { }     if array then         local n         if type( array ) == "number" then             n = array         else             n = table.maxn( ancestor )             if n == 0 then                 for k, v in pairs( ancestor ) do                     n = n + 1                 end -- for k, v             end         end         for i = 1, n do             table.insert( r,  ancestor[ i ] )         end -- for i         if all then             local e             for i = 1, n do                 e = r[ i ]                 if type( e ) == "table" then                     r[ i ] = factory( e, false, true )                 end             end -- for i         end     else         for k, v in pairs( ancestor ) do             r[ k ] = v         end -- for k, v         if all then             local e             for k, v in pairs( r ) do                 e = r[ k ]                 if type( e ) == "table" then                     r[ k ] = factory( e, false, true )                 end             end -- for k, v         end     end     return r 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 fallback( ask )     -- Create similar item     --     ask  -- string, with ID     -- Returns table     local insertFew = 4     local kurzSchrift = 4     local r     if ask:sub( 1, 10 ) == "CodeMirror"  and  #ask > 10 then         r = { menu    = 3,               show    = Tree.CodeMirror.show,               slot    = Tree.CodeMirror.slot,               icon    = Tree.CodeMirror.icon,               start   = Tree.CodeMirror.start,               lowered = false }         if ask == "CodeMirrorAktiv" then             r.icon = facet( r.icon )         end     elseif ask == "InsertFew" then         r = { menu  = -2,               show  = Tree.InsertAll.show,               slot  = Tree.InsertAll.slot,               icon  = Tree.InsertAll.icon,               start = Tree.InsertAll.start,               entries = factory( Tree.InsertAll.entries, insertFew ) }         r.entries[ insertFew ] = "Mehr"     elseif ask:sub( 1, 7 ) == "Schrift" then         local entries, k         if ask:sub( 1, 11 ) == "SchriftKurz" then             k = kurzSchrift         else             k = true         end         entries = factory( Tree.SchriftAlle.entries, k )         r = { menu    = -2,               icon    = Tree.SchriftAlle.icon,               slot    = Tree.SchriftAlle.slot,               entries = entries }         if k == kurzSchrift then             r.entries[ kurzSchrift ] = "Mehr"             if ask == "SchriftKurz" then                 r.entries[ kurzSchrift - 1 ] = "Gestaltlos"             else                 r.entries[ kurzSchrift - 1 ] = "GestaltlosNix"             end         else             r.entries[ #r.entries - 1 ] = "GestaltlosNix"         end     elseif ask:sub( 1, 14 ) == "Seitenoptionen"  and  #ask > 14 then         local sub         r = factory( Tree.Seitenoptionen, false, true )         for i = 2, #r.entries do             sub = r.entries[ i ]             if i <= 5 then                 Tree[ sub ] = factory( Tree[ sub ] )                 Tree[ sub ].lowered = true             elseif sub == "CodeMirror" then                 if ask:sub( 20 ) == "" then                     r.entries[ i ] = "CodeMirrorInaktiv"                 else                     r.entries[ i ] = sub .. ask:sub( 20 )                 end                 break    -- for i             end         end -- for i     end     return r end -- fallback()    local function fault( a )     -- Formatiere Fehler mit class=error     -- Parameter:     --     a  -- string, mit Fehlermeldung     -- Rückgabewert:     --     string, mit HTML-Element     local e = mw.html.create( "span" )     e:addClass( "error" )      :wikitext( "FEHLER * " .. a )     return tostring( e ) end -- fault()    local function fetch( access )     -- Retrieve static tree entry; else on the fly     -- Parameter:     --     access  -- string, mit ID     -- Rückgabewert:     --     tree entry     local r = Tree[ access ]     if not r then         r = fallback( access )     end     return r end -- fetch()    local function fill( apply, assume )     -- Beschriftung ermitteln     -- Parameter:     --     apply   -- table     --     assume  -- string, mit Rückfallwert     -- Rückgabewert:     --     string     local r     if apply.slot then         r = mw.message.new( apply.slot:gsub( "^@", "visualeditor-" ) )         if not r:exists() then             r = false         end     end     if r then         r = r:plain()     elseif apply.show then         r = apply.show     else         r = assume     end     return r end -- fill()    local function flat( a )     -- Eingabewert trimmen; leeren Wert ignorieren     -- Parameter:     --     a  -- string oder nil     -- Rückgabewert:     --     string oder nil oder false     local r     if a then         r = mw.text.trim( a )         if r == "" then             r = false         end     end     return r end -- flat()    Widgets.dropdown2 = function ( all, accessed, aim, above, active, align )     local r     if all.entries then         local cssT  = { "background-color:#FFFFFF",                         "border-collapse:collapse",                         "margin-left:.5em",                         "margin-bottom:.5em" }         local high  = { }         local low   = ( all.menu < 0 )         local e, entry, launch, show, short, sign, space, strong, style         if aim then             e = mw.text.split( aim, "+", true )             for k, v in pairs( e ) do                 high[ v ] = true             end -- for k, v         end         if above then             if type( above ) == "string" then                 table.insert( cssT,  "min-width:" .. above )             end         else             table.insert( cssT, "width:100%" )         end         style = table.concat( cssT, ";" )         r     = "\n{|"         if above then             local pars  = { background = "#" .. Config.bgMainSel,                             div = true }             local sep   = "style='border%%s: #%s 1px solid;%%s'"             sep   = string.format( sep, Config.borderDd )             style = style .. ";box-shadow: 0 2px 2px 0 rgba(0,0,0,0.25)"             r     = string.format( "%s %s\n|%s|%s",                                    r,                                    string.format( sep, "", style ),                                    string.format( sep, "-bottom", "" ),                                    Widgets.toolItem( accessed, pars ) )         else           cssT  = { style,                       "font-size:90%" }             r = string.format( "%s style='%s'",                                r,                                table.concat( cssT, ";" ) )         end         space = false         for k, v in pairs( all.entries ) do             entry  = fetch( v )             launch = high[ v ]             if not entry then                 return fault( "dropdown: Bad entry " .. v )             end             if launch then                 if low  or  Config.itemSel == 1 then                     strong = "background-color: #" .. Config.bgItemSel                 else                     strong = "border: 2px solid #" .. Config.borderSel                 end                 high[ v ] = false             elseif entry.lowered then                 strong = "opacity:0.5"             else                 strong = ""             end             if strong ~= "" then                 strong = string.format( "style='%s'|", strong )             end             if entry.icon then                 sign = entry.icon                 if launch  and  not entry.lock   and                    sign:match( "^OOjs UI .+%.svg$" ) then                     sign = facet( sign )                 end             elseif launch and all.leader then                 sign = "OOjs UI icon check-progressive.svg"             else                 sign = false             end             if sign then                 sign = string.format( "[[File:%s|%dpx|icon]]",                                       sign,                                       entry.px or Config.icon )             else                 if not space then                     space = string.format( "%dpx", Config.icon )                     e     = mw.html.create( "span" )                     e:css( { ["display"] = "inline-block",                              ["width"]   = space } )                      :wikitext( "&#160;" )                     space = tostring( e )                 end                 sign = space             end             show = fill( entry, v )             if active and entry.smart then                 local s                 e = mw.html.create( "span" )                 if launch then                     s = "#3366CC"                 else                     s = "#444444"                 end                 e:css( "color", s )                  :wikitext( show )                 show = string.format( "[[#%s|%s]]",                                       entry.smart,                                       tostring( e ) )                 launch = false             end             if entry.style or launch then                 e = mw.html.create( "span" )                 if entry.style then                     e:cssText( entry.style )                 end                 if launch then                     e:css( "color", "#3366CC" )                 end                 e:wikitext( show )                 show = tostring( e )             end             e = mw.html.create( "div" )             e:css( { ["float"]         = "left",                      ["padding-right"] = "3px",                      ["white-space"]   = "pre" } )              :wikitext(  string.format( "%s %s", sign, show )  )             show = tostring( e )             if entry.shortcut then                 if not Title then                     Title = mw.title.getCurrentTitle()                 end                 if Title.text == Config.single then                     short = "#VEshortcuts"                 else                     short = string.format( "%s:%s",                                            mw.site.namespaces[12].name,                                            Config.shortcut )                 end                 e = mw.html.create( "div" )                 e:css( { ["float"]        = "right",                          ["opacity"]      = "0.5",                          ["margin-left"]  = "0.8em",                          ["margin-right"] = "0.3em",                          ["white-space"]  = "nowrap" } )                  :wikitext( string.format( "[[%s|%s]]",                                            short,                                            entry.shortcut ) )                 short = tostring( e )             elseif entry.iconRight then                 e = mw.html.create( "div" )                 e:css( { ["float"]        = "right",                          ["margin-left"]  = "0.8em",                          ["margin-right"] = "0.3em" } )                  :wikitext( string.format( "[[File:%s|%dpx]]",                                            entry.iconRight,                                            entry.pxR or Config.icon ) )                 short = tostring( e )             else                 short = ""             end             r = string.format( "%s\n|-\n|%s %s %s",                                r, strong, show, short )         end -- for k, v         r = r .. "\n|}"         if aim then             show = false             for k, v in pairs( e ) do                 if high[ v ] then                     if show then                         show = string.format( "%s+%s", show, k )                     else                         show = k                     end                 end             end -- for k, v             if show then                 r = r .. fault( "dropdown: Auswahl fehlt: " .. show )             end         end     else         r = fault( "dropdown: Keine .entries" )     end     return r end -- Widgets.dropdown2()    Widgets.progressive = function ( about, adjust )     local e    = mw.html.create( "span" )     local size = "1em"     local r     if adjust.div  or  adjust.mini then         size = "0.8em"         e:css( { ["border-radius"] = "0",                  ["font-size"] = "75%" } )     end     e:addClass( "mw-ui-button mw-ui-progressive" )      :css( { ["color"]       = "#FFFFFF",              ["line-height"] = size,              ["min-width"]   = "none" } )      :wikitext( about )     r = tostring( e )     if Config.tstyleUI then         r = Frame:extensionTag( "templatestyles",                                 nil,                                 { src = Config.tstyleUI } )             .. r     end     return r end -- Widgets.progressive()    Widgets.toolbar = function ( ahead, after )     local div      = { div = true,                        ["line-height"] = "1em" }     local element  = mw.html.create( "div" )     local entries  = factory( Tree.TOOLBAR.entries, true )     local n        = #entries     local surround = "1px solid #" .. Config.borderBar     local entry, s     element:css( { ["background"] = "#FFFFFF",                    ["border"]     = surround,                    ["float"]      = "left",                    ["margin"]     = "0" } )     if ahead >= 1  and  after >= 1 then         element:css( { ["width"] = "100%" } )     end     if after > 0 then         local rechts = mw.html.create( "div" )         rechts:css( { ["float"]       = "right",                       ["margin-left"] = "1em",                       ["white-space"] = "nowrap" } )         if ahead > 0 then             rechts:css( { ["border-left"] = surround } )         end         for i = 5, n do             s     = entries[ i ]             entry = Tree[ s ]             if entry.rechts then                 rechts:wikitext( Widgets.toolItem( s, div ) )             end         end -- for i         element:wikitext( tostring( rechts ) )     end     if ahead > 0 then         for i = 1, n do             s     = entries[ i ]             entry = Tree[ s ]             if entry.links  and  ahead >= entry.links then                 element:wikitext( Widgets.toolItem( s, div ) )             end         end -- for i     end     entry = mw.html.create( "div" )     entry:css( { ["clear"] = "both" } )     element:wikitext( tostring( entry ) )     return tostring( element ) end -- Widgets.toolbar()    Widgets.toolItem = function ( access, adjust )     local details = factory( fetch( access ),  false )     local element, low, r, shift, show, smart     if adjust then         for k, v in pairs( adjust ) do             details[ k ] = v         end -- for k, v     end     low = ( details.border  or  details.menu ~= 2 )           and   not details.div     if low then         element = "span"     else         element = "div"     end     element = mw.html.create( element )     if details.border and details.icon then         show = ""     else         show = fill( details, access )         if not low then             local height = adjust["line-height"]             element:css( { ["float"] = "left" } )             if height then                 element:css( { ["line-height"] = height } )             end         end         if not Title then             Title = mw.title.getCurrentTitle()         end         if Title.text == Config.single then             if details.swift then                 shift = "#" .. details.swift             end         elseif details.start then             shift = string.format( "%s:%s",                                    mw.site.namespaces[12].name,                                    details.start )             if shift == Title.prefixedText then                 shift = false             end         end         if details.progressive then             show = Widgets.progressive( show, details )         end         if shift then             show = string.format( "[[%s|%s]]", shift, show )         end     end     if details.smart then         smart = details.smart         if details.shortcut then             smart = string.format( "%s %s %s",                                    smart,                                    mw.ustring.char( 8211 ),                                    details.shortcut )         end     elseif details.shortcut then         smart = details.shortcut     end     element:css( { ["white-space"] = "nowrap" } )     if not details.progressive then         local graphics = details.icon or details.before         if details.border then             element:css( { ["border"]  = "1px solid #"                                          .. Config.borderBar,                            ["padding"] = "2px 5px" } )         else             element:css( { ["padding"] = "0 5px" } )             if type( details.borderR ) ~= "boolean" then                 details.borderR = true             end             if details.background then                 element:css( { ["background"] = details.background } )             end             if details.borderR then                 element:css( { ["border-right"] = "1px solid #"                                                   .. Config.borderBar } )             end         end         if graphics then             local k, s             if type( graphics ) == "table" then                 details.px  = graphics.px                 details.top = graphics.top                 graphics    = graphics.img  or  "example.svg"             else                 show = ""             end             if type( details.px ) == "number" then                 k = details.px             else                 k = Config.mainPX             end --          if details.align == "right" then --              s = "|right" --          end             if details.top then                 s = "|top"             end             show = string.format( "[[File:%s|%dpx%s|link=%s|%s]]%s",                                   graphics,                                   k,                                   s     or "",                                   shift or "",                                   smart or "icon",                                   show )         end         if details.div  and  not details.icon then             element:css( { ["padding-bottom"] = "3px",                            ["padding-top"]    = "2px" } )         end         if details.entries  and  not details.less then             show = string.format( "%s [[File:%s|%dpx|link=|%s]]",                                   show,                                   Config.openDown.src,                                   Config.openDown.px,                                   smart or "Dropdown-Menü" )         end     end     if smart then         element:attr( "title", smart )     end     element:wikitext( show )     if details.name then         show = fill( details, access )         if math.abs( details.name ) > 1 then             show = string.format( "'''%s'''", show )         end         if details.name > 0 then             r = string.format( "%s %s", tostring( element ), show )         else             r = string.format( "%s %s", show, tostring( element ) )         end     else         r = tostring( element )     end     return r end -- Widgets.toolItem()    Tree = factory( Data.tree )    HelpVisualEditor.failsafe = function ( atleast )     -- Retrieve versioning and check for compliance     -- Precondition:     --     atleast  -- string, with required version or "wikidata",     --                or false     -- Postcondition:     --     Returns  string with appropriate version, or false     local since = atleast     local r     if since == "wikidata" then         local item = HelpVisualEditor.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 vsn = entity:formatPropertyValues( "P348" )                 if type( vsn ) == "table"  and                    type( vsn.value ) == "string" and                    vsn.value ~= "" then                     r = vsn.value                 end             end         end     end     if not r then         if not since  or  since <= HelpVisualEditor.serial then             r = HelpVisualEditor.serial         else             r = false         end     end     return r end -- HelpVisualEditor.failsafe()    -- Export local p = { }  p.dropdown = function ( frame )     -- Tropfrunter     local params = frame:getParent().args     local scope  = flat( params[ 1 ] )     local r     if scope then         local path = fetch( scope )         if path then             local leader = not faculty( params.nohead )                            or  faculty( params.head )             local link   = faculty( params.link )             local widget = string.format( "dropdown%d",                                           math.abs( path.menu ) )             Frame = frame             if leader and params.head and                params.head:match( "^%d+%l+$" ) then                 leader = params.head             end             r = Widgets[ widget ]( path,                                    scope,                                    flat( params[ 2 ] ),                                    leader,                                    link,                                    flat( params.float ) )         else             r = fault( "dropdown * Menü unbekannt: " .. scope )         end     else         r = fault( "dropdown: Kein Menü" )     end     return r end -- p.dropdown()    p.headline = function ( frame )     -- Dynamische Überschrift     local pages  = { }     local params = frame:getParent().args     local parts  = { }     local e, m, s, show     Title = mw.title.getCurrentTitle()     for k, v in pairs( params ) do         s = type( k )         if s == "number" then             if k == 1 then                 if v:match( "^%s*[1-6]%s*$" ) then                     m = tonumber( v )                 else                     show = fault( "h-Zahl ungültig:" .. v )                 end             elseif k == 2  and not show then                 v = mw.text.trim( v )                 if v ~= "" then                     show = v                 end             end         elseif s == "string" then             if k == "Gesamt" then                 k = Config.single             end             if k:find( "/", 2, true ) then                 pages[ k:gsub( "^%./", "" ) ] = v             elseif k:sub( 1, 5 ) == "Anker" then                 if v ~= "" then                     table.insert( parts, v )                 end             end         end     end -- for k, v     if not m then         m = 2     end     if not pages[ Config.single ] then         pages[ Config.single ] = tostring( m + 1 )     end     if Title.namespace == 12 then         s = pages[ Title.text ]         if s then             if s:match( "^[1-6]$" ) then                 m = tonumber( s )             else                 show = fault( "h-Zahl ungültig:" .. s )             end         end     end     if not show then         show = fault( "Überschrift fehlt" )     end     e = mw.html.create( string.format( "h%d",  m ) )     m = table.maxn( parts )     if m > 0 then         e:attr( "id",  mw.uri.anchorEncode( parts[ 1 ] ) )         if m > 1 then             local el             for i = 2, m do                 el = mw.html.create( "span" )                 el:attr( "id",  mw.uri.anchorEncode( parts[ i ] ) )                 show = tostring( el ) .. show             end    -- for i         end     end     e:wikitext( show )     return tostring( e ) end -- p.headline()    p.icon = function ( frame )     -- Icon per ID     local params = frame:getParent().args     local sketch = flat( params[ 1 ] )     local r     if sketch then         local entry = Tree[ sketch ]         if entry then             r = entry.icon             if r then                 local icon = flat( params[ 2 ] )                 if icon then                     icon = tonumber( icon ) or 1                 else                     icon = Config.icon                 end                 if icon > 7 then                     r = string.format( "[[File:%s|%dpx|icon]]",                                        r, icon )                 else                     r = fault( "icon * zu klein: " .. tostring( icon ) )                 end             else                 r = fault( "icon * unbebildert: " .. sketch )             end         else             r = fault( "icon * unbekannt: " .. sketch )         end     else         r = fault( "icon: Keine ID" )     end     return r end -- p.icon()    p.progressive = function ( frame )     -- Button auf blau     local params  = frame:getParent().args     Frame = frame     return Widgets.progressive( params[ 1 ] or "??????????????",                                 { mini = faculty( params.mini ) } ) end -- p.progressive()    p.toolbar = function ( frame )     -- Hauptmenü     local params = frame:getParent().args     local links  = flat( params.links )   or  1     local rechts = flat( params.rechts )  or  1     local r     if links == "½" then         links = 0.5     elseif links == "¾" then         links = 0.75     elseif links == mw.ustring.char( 8540 ) then    --  3/8         links = 0.375     else         links = tonumber( links )  or  0     end     rechts = tonumber( rechts )  or  0     if links > 0  or  rechts > 0 then         Frame = frame         r     = Widgets.toolbar( links, rechts )     else         r = fault( "toolbar: links und rechts 0" )     end     return r end -- p.toolbar()    p.toolitem = function ( frame )     -- Hauptmenü-Element     local params = frame:getParent().args     local scope  = flat( params[ 1 ] )     local r     if scope then         local branch = Tree[ scope ]         if branch then             local name = params.name             local pars = { }             if branch.menu == 2 then                 pars.border = true             else                 pars.borderR = false             end             if name  and  name:match( "^[-+]?[12]$" ) then                 pars.name = tonumber( name )             end             Frame = frame             r     = Widgets.toolItem( scope, pars )         else             r = fault( "toolitem * Item unbekannt: " .. scope )         end     else         r = fault( "toolitem: Kein Item" )     end     return r end -- p.toolitem()    p.failsafe = function ( frame )     -- Check or retrieve version information     -- Precondition:     --     frame  -- object; #invoke environment     -- Postcondition:     --     Return string with error message or ""     -- Uses:     --     HelpVisualEditor.failsafe()     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 HelpVisualEditor.failsafe( since )  or  "" end -- p.failsafe()  p.HelpVisualEditor = function ()     -- Module interface     return HelpVisualEditor end  return p