Modul:Vorlage:Unsigniert
Vorlagenprogrammierung | Diskussionen | Lua | Unterseiten | |||
Modul | Deutsch | English
|
Modul: | Dokumentation |
Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus
local Unsigned = { suite = "Unsigned",
serial = "2019-07-19",
item = 0 }
--[=[
Deal with unsigned contributions on talk pages
]=]
local Failsafe = Unsigned
Unsigned.cnf =
{ cat = "Wikipedia:Vorlagenfehler/Vorlage:Unsigniert",
defaults = { ["1"] = "nicht" },
gsub = { { " Mrz%.", " Mär." } },
parMap = { ["1"] = "User",
["2"] = "Stamp",
["3"] = "2",
ALT = "1",
Datum = "DateTime" },
service = "Unsigniert",
signature = "<small>{''$1 [[Hilfe:Signatur|signierter]] Beitrag'' von $SIGNATURE$2)</small>",
sole = "<small>(ohne [gültigen] Zeitstempel [[Hilfe:Signatur#wie|signierter]] Beitrag)</small>",
stamp = "dmy",
support = "[[Vorlage:Unsigniert]]",
user = { { "Benutzer", "Benutzerin" }, "BD" },
zone = "CES?T"
}
Unsigned.timestamps = {
dmy = { seek = "^[012]%d, [0123]%d. %l%l%l%. 20%d%d %($ZONE%)$",
set = "H:i, j. M Y (T)" } }
local function Fetch( ask, advanced )
-- Fetch module
-- Parameter:
-- ask -- string, with name
-- "DateTime"
-- "Multilingual"
-- "URLutil"
-- Returns table of module
-- error: Module not available
local sign = ask
local r, stem
if sign:sub( 1, 1 ) == "/" then
sign = Unsigned.frame:getTitle() .. sign
else
stem = sign
sign = "Module:" .. stem
end
if Unsigned.extern then
r = Unsigned.extern[ sign ]
else
Unsigned.extern = { }
end
if not r then
local lucky, g = pcall( require, sign )
if type( g ) == "table" then
if stem and type( g[ stem ] ) == "function" then
r = g[ stem ]()
else
r = g
end
Unsigned.extern[ sign ] = r
else
error( string.format( "Fetch(%s) %s", sign, g ) )
end
end
return r
end -- Fetch()
local function Flat( a )
-- Standardize HTML entities (e.g. before substitution)
-- Parameter:
-- a -- string
-- Returns:
-- string
local h = { [34] = "quot",
[38] = "amp",
[39] = "apos",
[60] = "lt",
[62] = "gt",
[160] = "nbsp",
[173] = "shy",
[8194] = "ensp",
[8195] = "emsp",
[8201] = "thinsp",
[8204] = "zwnj",
[8205] = "zwj",
[8206] = "lrm",
[8207] = "rlm" }
local w = { 35, 42, 58, 59, 91, 92, 93, 123, 124, 125 }
local i = 1
local r = a
local k, s, x
while i do
i = r:find( "&#", i, true )
if i then
x, s = r:sub( i + 2 ):match( "^(x?)(%x+);" )
if s then
if x == "x" then
k = 16
else
k = 10
end
k = tonumber( s, k )
s = string.format( "&#%s%s;", x, s )
x = false
if k >= 35 and k <= 125 then
for j = 1, #w do
if k == w[ j ] then
x = true
break -- for j
end
end -- j = 1, #w
elseif k < 32 or k == 8209 or k == 8239 then
x = true
end
if x then
x = string.format( "&#%d;", k )
elseif k >= 0xFFFE then
x = string.format( "&#x%X;", k )
else
x = h[ k ]
if x then
x = string.format( "&%s;", x )
else
x = mw.ustring.char( k )
end
end
r = r:gsub( s, x )
end
i = i + 1
end
end -- while i
return r
end -- Flat()
local function factory()
-- Create signature
-- Returns:
-- string, wikitext
-- error: invalid format
local pLang = mw.language.getContentLanguage()
local female = function( alike, alt )
local g
if type( alt[ 1 ] ) == "string" and
type( alt[ 2 ] ) == "string" and
( type( alt[ 3 ] ) == "string" or
not alt[ 3 ] ) then
g = pLang:gender( alike, alt )
end
return g
end -- female()
local URLutil = Fetch( "URLutil" )
local s = Unsigned.vals.User
local sign = Unsigned.cnf.signature or "$SIGNATURE"
local r, show, space
if URLutil.isIP( s ) then
local special
r = { "Contributions" }
special = Unsigned.frame:callParserFunction( "#special", r )
space = mw.site.namespaces[ 3 ].name
show = mw.message.new( "talkpagelinktext" )
:inLanguage( pLang:getCode() )
:plain()
r = string.format( "[[%s/%s|%s]] [[[%s:%s|%s]]]",
special, s, s, space, s, show )
elseif s:find( "[/@#<>%|%[%]%{%}:]" ) then
local e = mw.html.create( "code" )
:wikitext( mw.text.nowiki( s ) )
local slang = pLang:getCode()
r = mw.message.new( "nosuchusershort" )
:inLanguage( slang )
:params( tostring( e ) )
:plain()
error( r, 0 )
else
local space3
s = s:gsub( "_", " " )
if type( Unsigned.cnf.user ) == "table" then
local e = Unsigned.cnf.user[ 1 ]
if type( e ) == "table" then
space = female( s, e )
elseif type( e ) == "string" then
space = e
end
e = Unsigned.cnf.user[ 2 ]
if type( e ) == "table" then
space3 = female( s, e )
elseif type( e ) == "string" then
space3 = e
end
end
show = mw.message.new( "contribslink" )
:inLanguage( pLang:getCode() )
:plain()
space = space or mw.site.namespaces[ 2 ].name
space3 = space3 or mw.site.namespaces[ 3 ].name
r = string.format( "[[%s:%s|%s]] [[[%s:%s|%s]]]",
space, s, s, space3, s, show )
end
r = sign:gsub( "$SIGNATURE", r )
if r:find( "%$%d" ) then
for i = 1, 9 do
s = tostring( i )
show = Unsigned.vals[ s ] or ""
r = mw.ustring.gsub( r, "$" .. s, show )
end -- for i
end
return Flat( r )
end -- factory()
local function fault( a )
-- Format error message by class=error
-- Parameter:
-- a -- string, error message
-- Returns:
-- string, HTML span
local b = mw.html.create( "div" )
:addClass( "error" )
:css( "background-color", "#FFC0C0" )
:css( "border", "#FF0000 3px solid" )
:css( "margin", "1em" )
:css( "padding", "0.5em" )
local c = mw.html.create( "div" )
:css( "font-family", "monospace" )
:css( "margin-top", "0.5em" )
local p = { }
local r, s
if type( Unsigned.cnf ) ~= "table" then
Unsigned.cnf = { }
end
if type( Unsigned.cnf.support ) == "string" then
s = Unsigned.cnf.support
else
s = Unsigned.self or Unsigned.suite
end
r = string.format( "'''%s''' – %s", s, a or "????" )
b:wikitext( r )
Unsigned.pars = Unsigned.pars or { }
for k, v in pairs( Unsigned.pars ) do
table.insert( p, k )
end -- for k, v
table.sort( p )
if type( Unsigned.cnf.service ) == "string" then
s = Unsigned.cnf.service
else
s = Unsigned.self
end
r = string.format( "{{subst:%s", s )
for i = 1, #p do
s = p[ i ]
r = string.format( "%s |%s=%s", r, s, Unsigned.pars[ s ] )
end -- for i
r = r .. "}}"
p = { [ 1 ] = "nowiki", [ 2 ] = r }
r = Unsigned.frame:callParserFunction( "#tag", p )
c:wikitext( r )
c:newline()
b:newline()
b:node( c )
r = tostring( b )
if type( Unsigned.cnf.cat ) == "string" then
r = string.format( "%s[[category:%s]]",
r, Unsigned.cnf.cat )
end
return Flat( r )
end -- fault()
local function finish( attempt )
-- Postprocess stamp
-- Parameter:
-- attempt -- string, stamp
-- Returns
-- string, improved stamp
local r = attempt
if type( Unsigned.cnf.gsub ) == "table" then
for k, v in pairs( Unsigned.cnf.gsub ) do
if type( v ) == "table" and
type( v[ 1 ] ) == "string" and
type( v[ 2 ] ) == "string" then
r = mw.ustring.gsub( Unsigned.vals.Stamp,
v[ 1 ],
v[ 2 ] )
end
end -- for k, v
end
return r
end -- finish()
local function format( attempt )
-- Make stamp from arbitrary date time
-- Parameter:
-- attempt -- string, date time
-- Returns
-- string, formatted stamp
-- error: invalid format
local DateTime = Fetch( "DateTime" )
local s = attempt
local dt = DateTime( s )
local r
if type( dt ) == "table" then
if not dt.zone then
dt:future( - tonumber( dt:format( "Z" ) ) )
end
s = Unsigned.stamp or "c"
r = dt:format( s )
else
local e = mw.html.create( "code" )
:wikitext( mw.text.nowiki( s ) )
local p = mw.language.getContentLanguage()
local slang = p:getCode()
local stamp = mw.message.new( "blocklist-timestamp" )
:inLanguage( slang )
:plain()
s = mw.message.new( "confirmedit-preview-invalid" )
:inLanguage( slang )
:plain()
s = string.format( "%s %s: %s",
stamp, s, tostring( e ) )
error( s, 0 )
end
return r
end -- format()
local function furnish( arglist )
-- Initialize config and parameters
-- Parameter:
-- arglist -- table, template parameters
-- error: serious problem
local cnf
if type( Unsigned.cnf ) == "table" then
cnf = Unsigned.cnf
else
local lucky
lucky, cnf = pcall( mw.loadData,
Unsigned.self .. "/config" )
if type( cnf ) == "table" then
Unsigned.cnf = cnf
else
error( cnf, 0 )
end
end
if type( cnf.stamp ) == "string" and
type( cnf.parMap ) == "table" then
local strip = mw.ustring.char( 0x5B,
0x22, 0x27, 0x200E, 0x200F,
0x5D )
local timestamp = Unsigned.timestamps[ cnf.stamp ]
local s
if type( timestamp ) == "table" then
if type( timestamp.seek ) == "string" and
type( timestamp.set ) == "string" then
local shift = cnf.zone or "%u%u%u%u?"
Unsigned.seek = timestamp.seek:gsub( "$ZONE", shift )
Unsigned.stamp = timestamp.set
else
error( "INTERNAL: invalid timestamp: " .. cnf.stamp, 0 )
end
else
error( "INTERNAL: missing timestamp: " .. cnf.stamp, 0 )
end
Unsigned.pars = { }
Unsigned.vals = { }
for k, v in pairs( arglist ) do
if type( v ) == "string" then
if type( k ) == "number" then
k = tostring( k )
end
s = cnf.parMap[ k ]
if type( s ) == "string" then
v = mw.ustring.gsub( v, strip, "" )
v = mw.text.trim( v )
if v ~= "" then
Unsigned.vals[ s ] = v
end
-- else UNKNOWN PAR
end
if v ~= "" then
Unsigned.pars[ k ] = v
end
end
end -- for k, v
if type( cnf.defaults ) == "table" then
for k, v in pairs( cnf.defaults ) do
if type( Unsigned.vals[ k ] ) == "nil" then
Unsigned.vals[ k ] = v
end
end -- for k, v
end
else
error( "INTERNAL: missing cnf.parMap / cnf.global", 0 )
end
end -- furnish()
local function f( arglist )
-- Main procedure
-- Parameter:
-- arglist -- table, template parameters
-- Returns
-- string, formatted signature
-- error: serious problem
local r
furnish( arglist )
if Unsigned.vals.DateTime then
Unsigned.vals.Stamp = format( Unsigned.vals.DateTime )
elseif Unsigned.vals.Stamp then
if not mw.ustring.match( Unsigned.vals.Stamp,
Unsigned.seek ) then
Unsigned.vals.Stamp = format( Unsigned.vals.Stamp )
end
end
if Unsigned.vals.User then
r = factory()
elseif Unsigned.vals.Stamp and Unsigned.cnf.sole then
r = Unsigned.cnf.sole
else
r = ""
end
if Unsigned.vals.Stamp then
r = string.format( "%s %s",
r, finish( Unsigned.vals.Stamp ) )
end
if r == "" then
local p = mw.language.getContentLanguage()
local slang = p:getCode()
local r = mw.message.new( "content-json-empty-object" )
:inLanguage( slang )
:plain()
error( r, 0 )
end
return r
end -- f()
Unsigned.main = function ( arglist, frame )
-- Main interface
local lucky, r
Unsigned.frame = frame or mw.getCurrentFrame()
lucky, r = pcall( f, arglist )
if not lucky then
r = fault( r )
end
return r
end -- Unsigned.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
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 vsn = entity:formatPropertyValues( "P348" )
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 )
-- Template call
Unsigned.self = frame:getTitle()
return Unsigned.main( frame:getParent().args, frame )
end -- p.f
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.Unsigned = function ()
-- Module interface
return Unsigned
end
return p