Nicht angemeldeter Benutzer - Bearbeiten von Seiten ist nur als angemeldeter Benutzer möglich.
Modul:Shortcuts
Version vom 7. Juni 2014, 16:43 Uhr von wikipedia-de>PerfektesChaos (update)
Die Dokumentation für dieses Modul kann unter Modul:Shortcuts/Doku erstellt werden
--[=[ 2014-06-03
Module:Shortcuts
]=]
-- local globals
local Config
local Current = { }
local Errors = false
local Sort = false
local function faces( any )
-- Retrieve single shortcut names
-- any -- string, with shortcut name list
-- Returns table with shortcut page names
local s = any:gsub( "<[^>]+>", "," )
:gsub( "%[%[", "" )
:gsub( "%]%]", "" )
local r = mw.text.split( s, "%s*,%s*" )
for k, v in pairs( r ) do
if mw.text.trim( v ) == "" then
r[ k ] = nil
end
end -- for k, v
return r
end -- faces()
local function facet( area, assign, assigned )
-- Create mapping shortcut->target
-- area -- string, with target namespace name and colon
-- assign -- string, with target page name
-- assigned -- string, with shortcut page name
-- Returns table with entry
-- .shift -- string, with target page name
-- .shortcut -- string, with shortcut page name
-- .nsn -- number, of shortcut namespace
-- .sort -- string, with sortable shortcut page title
local space, subject = assigned:match( "^([^:]+):(.+)$" )
local r = { }
r.shift = area .. assign
r.shortcut = assigned
if space then
local o = mw.site.namespaces[ space ]
if o then
r.nsn = o.id
end
end
if not r.nsn then
r.nsn = 0
subject = assigned
end
if Sort then
subject = Sort.lex( subject, "latin", false )
end
r.sort = string.upper( subject )
return r
end -- facet()
local function factory( account, alone, assembly )
-- Retrieve mappings shortcut->target for entire target namespace
-- account -- string, with module name
-- alone -- number, of namespace
-- assembly -- table, collecting assignments
-- Extending assembly
local space = mw.site.namespaces[ alone ]
if space then
local got
local sub = string.format( "%s/%d", account, alone )
local l, t = pcall( mw.loadData, sub )
if type( t ) == "table" then
if space.id == 0 then
space = ""
else
space = space.name .. ":"
end
for k, v in pairs( t ) do
got = faces( v )
for i, s in pairs( got ) do
table.insert( assembly, facet( space, k, s ) )
end -- for i, s
end -- for k, v
end
end
end -- factory()
local function fair( above )
-- Convert shortcut list namespaces into talk pages
-- alert -- string, with shortcuts
-- Returns converted shortcuts
local r = " " .. above
if type( Config.talks ) == "table" then
local seek, shift
for k, v in pairs( Config.talks ) do
seek = string.format( "(%%A?)(%s):", k )
shift = string.format( "%%1%s:", v )
r = r:gsub( seek, shift )
end -- for k, v
end
return mw.text.trim( r )
end -- fair()
local function fault( alert, absent )
-- Format message with class="error"; add Config (category etc.)
-- alert -- string, with message
-- absent -- boolean, hide message, trigger category
-- Returns message with markup
local r = string.format( "<span class=\"error\">%s</span>", alert )
if absent and type( Config ) == "table" then
local s = Config.suppress
if type( s ) == "string" and s:find( "%s", 1, true ) then
r = string.format( s, r )
end
if type( Config.scream ) == "string" then
r = string.format( "%s[[Category:%s]]", r, Config.scream )
end
end
return r
end -- fault()
local function failure( assigned, about )
-- Add one message to Errors
-- assigned -- string, with shortcut page name
-- about -- string, with error keyword
if type( Errors ) ~= "table" then
Errors = { }
end
Errors[ assigned ] = about
end -- failure()
local function fiat( ahead, after )
-- Format table row
-- ahead -- string, with first cell
-- after -- string or false, with second cell
-- Returns table row markup
local r = string.format( "\n|-\n|%s", ahead )
if after then
r = string.format( "%s||%s", r, after )
end
return r
end -- fiat()
local function first( a1, a2 )
-- Compare a1 with a2 in reverse title order
-- a1 -- table, with assignment
-- a2 -- table, with assignment
-- Returns true if a1 < a2
local r
if a1.shortcut == a2.shortcut then
r = ( string.upper( a1.shift ) > string.upper( a2.shift ) )
elseif a1.sort == a2.sort then
r = ( a1.nsn > a2.nsn )
else
r = ( a1.sort > a2.sort )
end
return r
end -- first()
local function flag( arglist, alone, achieved )
-- Analyze one shortcut
-- arglist -- table, with parameters
-- .nsn -- number, of current namespace
-- .nsns -- number, of subject namespace
-- alone -- string, with shortcut page name
-- achieved -- table, with title objects; will be extended
-- Adds error message to collection
local page = mw.title.new( alone )
if page.exists then
if page.isRedirect then
local story = page:getContent()
local shift = story:match( "^#[^%[]+%[%[([^%]\n]+)%]%]" )
local redirect = mw.title.new( shift )
if mw.title.equals( Current.page, redirect ) then
for k, v in pairs( achieved ) do
if mw.title.equals( page, v ) then
failure( alone, "duplicated" )
page = false
break -- for k, v
end
end -- for k, v
if page then
table.insert( achieved, page )
end
if arglist.nsn == arglist.nsns
and Config.signature
and not story:find( Config.signature, 15, true ) then
local say
if type( Config.signal ) == "string" then
say = Config.signal
else
say = ".signature (category) missing"
end
failure( alone, say )
end
else
failure( alone, "wrong target" )
end
else
failure( alone, "regular page" )
end
else
failure( alone, "missing" )
end
end -- flag()
local function flash( account, alone )
-- Create all item table body with two columns; shortcut and target
-- account -- string, with module name
-- alone -- number or false, with namespace limitation
-- Returns table rows until end
local r = "\n|}"
local collect = { }
if type( alone ) == "number" then
factory( account, alone, collect )
elseif type( Config.rooms ) == "table" then
for k, v in pairs( Config.rooms ) do
factory( account, v, collect )
end -- for k, v
else
r = r .. "'Config.rooms' not found"
collect = false
end
if collect then
local second, shortcut
if not Sort then
local l, t = pcall( require, "Module:Sort" )
if type( t ) == "table" then
Sort = t.Sort()
end
end
table.sort( collect, first )
for k, v in pairs( collect ) do
shortcut = string.format( "[[%s]]", v.shortcut )
second = string.format( "[[:%s]]", v.shift )
r = fiat( shortcut, second ) .. r
end -- for k, v
end
return r
end -- flash()
local function folder( arglist )
-- Present table row
-- arglist -- table, with parameters
-- .self -- string, target page
-- .story -- string or nil, append to target page link
-- .suffix -- string or nil, append to shortcut list
-- Returns table row markup
local l, nsn, shortcuts, t
local space, subject = arglist.self:match( "^([^:]+):(.+)$" )
if space then
local o = mw.site.namespaces[ space ]
if o then
nsn = o.id
else
nsn = 0
end
else
nsn = 0
end
t = string.format( "%s/%d", arglist.suite, nsn )
l, t = pcall( mw.loadData, t )
if type( t ) == "table" then
shortcuts = t[ subject ]
end
subject = string.format( "[[:%s]]", arglist.self )
if type( arglist.story ) == "string" then
subject = subject .. arglist.story
end
if type( shortcuts ) == "string" then
if shortcuts:sub( 1, 2 ) ~= "[[" then
local got = faces( shortcuts )
shortcuts = ""
for k, v in pairs( got ) do
shortcuts = string.format( "%s, [[%s]]", shortcuts, v )
end -- for k, v
shortcuts = shortcuts:sub( 3 )
end
if type( arglist.suffix ) == "string" then
shortcuts = shortcuts .. arglist.suffix
end
else
shortcuts = fault( "no shortcuts", false )
end
return fiat( subject, shortcuts )
end -- folder()
local function follow( arglist )
-- Analyze list of shortcuts in single page context
-- arglist -- table, with parameters
-- .shortcuts -- string, comma separated list of shortcuts
-- .leave -- true, if dummy entry
-- Throws error with message, else returns string with text
local style = Config.style
local r
if type( style ) == "string" and style:find( "%s", 1, true ) then
local pages = { }
local got = faces( arglist.shortcuts )
r = string.format( style, arglist.shortcuts )
for k, v in pairs( got ) do
if not arglist.leave then
flag( arglist, v, pages )
end
end -- for k, v
if Errors then
local s = ""
for k, v in pairs( Errors ) do
s = string.format( "%s [[%s]]: %s", s, k, v )
end -- for k, v
r = r .. fault( s, true )
end
else
error( "/config 'style' invalid" )
end
return r
end -- follow()
local function forward( args )
-- Perform task
-- args -- table, with parameters
-- .self -- string, target page
-- .shortcuts -- string, comma separated list of shortcuts
-- Throws error with message, else returns string with text
local l, t, sub
local lucky = false
local r = false
if type( args.suite ) == "string" then
sub = args.suite .. "/config"
l, t = pcall( mw.loadData, sub )
if type( t ) == "table" then
Config = t
else
r = string.format( "'%s' invalid", sub )
end
else
r = "bad .suite"
end
if Config then
if args.self then
Current.self = args.self
Current.page = mw.title.new( args.self )
if not Current.page.exists then
Current.page = false
r = string.format( "'%s' not found",
args.self )
end
elseif args.service == "trow" then
r = "'1=' missing"
elseif args.service == "total" then
Current.page = false
lucky = true
else
Current.page = mw.title.getCurrentTitle()
Current.self = Current.page.prefixedText
args.self = Current.self -- OBSOLETING
end
if Current.page then
Current.nsn = Current.page.namespace
args.nsn = Current.nsn -- OBSOLETING
if args.nsn % 2 == 0 then
args.nsns = args.nsn
args.nsnt = args.nsn + 1
else
args.nsnt = args.nsn
args.nsns = args.nsn - 1
end
sub = string.format( "%s/%d", args.suite, args.nsns )
l, t = pcall( mw.loadData, sub )
if type( t ) == "table" then
sub = Current.page.text
if type( t[ sub ] ) == "string" then
if args.shortcuts and not Config.locally then
args.shortcuts = false
r = "'1=' not permitted"
else
args.shortcuts = t[ sub ]
if args.nsn == args.nsnt then
args.shortcuts = fair( args.shortcuts )
end
end
end
end
if args.service == "template" then
if type( args.shortcuts ) == "string" then
args.shortcuts = mw.text.trim( args.shortcuts )
if args.shortcuts == "" then
r = "no shortcuts"
else
lucky = true
end
elseif Current.page.prefixedText == Config.skip then
args.shortcuts = "NS:PT"
args.leave = true
lucky = true
elseif Config.locally then
r = "Shortcuts template '1=' missing"
end
elseif args.service == "trow" or
args.service == "total" then
lucky = true
else
r = "bad .service"
end
end
if lucky then
if args.service == "template" then
r = follow( args )
elseif args.service == "trow" then
r = folder( args )
elseif args.service == "total" then
r = flash( args.suite, args.nsn )
end
end
end
if not lucky then
r = fault( r, true )
if args.service == "trow" then
r = fiat( r, false )
end
end
return r
end -- forward()
local function framed( frame, action )
-- #invoke call in template environment
-- action -- string, with keyword
-- Returns markup
local lucky, r
local params = { service = action,
suite = frame:getTitle() }
local pars = frame:getParent().args
if params.service == "template" then
params.shortcuts = pars[ 1 ]
elseif params.service == "trow" then
params.self = pars[ 1 ]
params.story = pars.story
params.suffix = pars.suffix
elseif params.service == "total" then
params.nsn = pars[ 1 ]
if params.nsn and
params.nsn:match( "^(%d+)$" ) then
params.nsn = tonumber( params.nsn )
else
params.nsn = false
end
end
lucky, r = pcall( forward, params )
return r
end -- framed()
-- Export
local p = { }
function p.template( frame )
return framed( frame, "template" )
end -- p.template
function p.total( frame )
return framed( frame, "total" )
end -- p.total
function p.trow( frame )
return framed( frame, "trow" )
end -- p.trow
function p.twoletters( frame )
return framed( frame, "twoletters" )
end -- p.twoletters
function p.test( args )
-- Debugging
-- args -- table, with arguments; mandatory:
-- .suite -- Module path
-- .service -- action mode, like "template"
-- .shortcuts -- list
-- .self -- (target) page name
local lucky, r = pcall( forward, args )
return r
end -- p.test()
return p