Modul:Pinging
Die Dokumentation für dieses Modul kann unter Modul:Pinging/Doku erstellt werden
local Pinging = { suite = "Pinging",
serial = "2022-11-14",
item = 108829575,
maxEcho = 50, -- currently permitted number of recipients
maxName = 99, -- length of a user name
start = "@",
suffix = ":" }
--[==[
Support templates for pings and user lists
]==]
local Failsafe = Pinging
if mw.site.server:find( ".beta.wmflabs.org", 4, true ) then
require( "strict" )
end
local function fair( analyse, add )
-- Create link target or link title
-- Parameter:
-- analyse -- string with page name or nick
-- add -- true, if user namespace to be added
-- false, if user namespace to be stripped
-- Returns:
-- string
local ns = false
local r = analyse
local space, spec = r:match( "^([^:]+):(.+)$" )
if space then
local tns = mw.site.namespaces[ space ]
if type( tns ) == "table" then
ns = tns.id
end
end
if add then
if not ns then
r = string.format( "%s:%s", mw.site.namespaces.User.name, r )
end
elseif ns then
if ns == 2 or ns == 3 then
r = spec
end
end
return r
end -- fair()
local function fault( alert )
-- Format error message by class=error
-- Parameter:
-- alert -- string, error message
-- Returns:
-- string, HTML span
local e = mw.html.create( "span" )
:addClass( "error" )
:css( "white-space", "nowrap" )
:wikitext( alert )
return tostring( e )
end -- fault()
local function fetch( analyse, alt )
-- Retrieve target table
-- Parameter:
-- analyse -- string with page content
-- alt -- string with additional nick pattern, or not
-- Returns:
-- sequence of targets, might be empty
local i = 1
local loop = true
local r = { }
local s = analyse
local j, k
while ( loop ) do
loop = false
j = s:find( "<!--", i, true )
if j then
k = s:find( "-->", j + 4, true )
if k then
loop = true
s = s:sub( 1, j ) .. s:sub( k + 3 )
i = j
end
end
end -- while loop
i = 1
loop = true
while ( loop ) do
loop = false
j = s:find( "{{#target:", i, true )
if j then
j = j + 10
k = s:find( "}}", j, true )
if k then
loop = true
table.insert( r, s:sub( j, k - 1 ) )
i = k + 1
end
end
end -- while loop
if alt then
local n, sn, sns, st, sub, tns
i = 1
loop = true
while ( loop ) do
j, i = mw.ustring.find( s, alt, i )
if j then
loop = true
sub = mw.ustring.sub( s, j, i )
st, sn = mw.ustring.match( sub, alt )
if st then
st = mw.text.trim( st )
if st == "" then
st = false
end
end
if st then
n = 2
if sn then
sn = mw.text.trim( sn )
if sn == "-" then
n = false
elseif sn ~= "" then
sns = sn:match( "^(%d+)$" )
if sns then
n = tonumber( sns )
else
tns = mw.site.namespaces[ sns ]
if tns then
n = tns.id
end
end
end
end
if n then
st = string.format( "%s:%s",
mw.site.namespaces[ n ].name,
st )
end
table.insert( r, st )
end
else
loop = false
end
end -- while loop
end
return r
end -- fetch()
local function friend( assign, abroad, area, another, alter )
-- Format single link
-- Parameter:
-- assign -- user or page name
-- abroad -- page names came from #target
-- area -- true: always wide area = URL
-- another -- display alternative link title
-- alter -- link is hidden
-- Returns:
-- 1. string or false,
-- 2. true: string is internal
-- 3. true: error occurred
local long = area
local r = assign
local site = false
local lapsus
if abroad then
local s
s, site = assign:match( "^%s*(.+)%s*|%s*(.*)%s*$" )
if s then
site = mw.text.trim( site )
if site == "" then
site = false
else
long = true
end
r = s
end
end
if r then
r = mw.text.trim( r )
if r == "" then
r = false
end
end
if r then
local live = not alter
local show
if r:find( "[#<>%[%]%{%}]" ) or
( not abroad and
( r:find( "[/@]" ) or
mw.ustring.len( r ) > Pinging.maxName ) ) then
lapsus = true
end
if not lapsus then
if another then
show = mw.text.trim( another )
if show == "" then
show = false
end
elseif live then
show = fair( r, false )
end
end
if not show then
show = r
end
if abroad then
if site then
show = string.format( "%s@%s", show, site )
end
else
r = fair( r, true )
end
if show:find( "%s" ) and live then
show = mw.text.trim( show )
if show:find( "%s" ) then
local e = mw.html.create( "span" )
:css( "white-space", "nowrap" )
:wikitext( show )
show = tostring( e )
end
end
if lapsus then
r = fault( show )
long = true
elseif long then
if site then
r = string.format( "//%s/wiki/%s",
site,
mw.uri.encode( r, "WIKI" ) )
else
r = tostring( mw.uri.canonicalUrl( r ) )
end
r = string.format( "[%s %s]", r, show )
if live then
local e = mw.html.create( "span" )
:addClass( "plainlinks" )
:wikitext( r )
r = tostring( e )
end
elseif alter or r == show then
r = string.format( "[[%s]]", r )
else
r = string.format( "[[%s|%s]]", r, show )
end
end
return r, not long, lapsus
end -- friend()
local function friends( assigned, abroad, area, assume, active, alter )
-- Make list of entries
-- Parameter:
-- assigned -- table with pages or users
-- abroad -- true: page names came from #target
-- area -- true: always wide area = URL
-- assume -- table with default options
-- active -- table with current options
-- alter -- string: hide result, show this
-- Returns:
-- string
local limit = ( not area and
active.max ~= "0" and assume.max ~= "0" )
local max = Pinging.maxEcho
local n = 0
local lapsus, light, lost, r, s, stick
if alter then
stick = " "
elseif active[ "/" ] then
stick = active[ "/" ]
elseif assume[ "/" ] then
stick = assume[ "/" ]
else
if Pinging.stick then
stick = Pinging.stick
else
local ltr = not mw.language.getContentLanguage():isRTL()
local e = mw.html.create( "span" )
:wikitext( "|" )
local s
if ltr then
s = "left"
else
s = "right"
end
e:css( "margin-" .. s, "0.5em" )
stick = tostring( e ) .. " "
Pinging.stick = stick
end
end
if limit and ( active.max or assume.max ) then
if tonumber( assume.max ) then
max = tonumber( assume.max )
end
if tonumber( active.max ) then
max = tonumber( active.max )
end
end
stick = stick:gsub( "^_", " " )
:gsub( "_$", " " )
for k, v in pairs( assigned ) do
if type( k ) == "number" then
s = assigned[ "label" .. tostring( k ) ]
s, light, lost = friend( v, abroad, area, s, alter )
if s then
if r then
r = r .. stick
else
r = ""
end
if lost then
lapsus = true
elseif limit and light then
n = n + 1
if n > max then
local scream = "Echo-notification-count"
local tell = mw.message.new( scream )
if tell:exists() then
scream = tell:numParams( max ):plain()
else
scream = string.format( "count %d > %d",
n, max )
end
scream = string.format( " !! %s !! ",
scream )
r = r .. fault( scream )
lapsus = true
limit = false
end
end
r = r .. s
end
end
end -- for k
if r then
local start = Pinging.start
local suffix = Pinging.suffix
if active[ "@" ] then
start = active[ "@" ]
elseif assume[ "@" ] then
start = assume[ "@" ]
elseif active.a then
start = active.a
end
if active[ ":" ] then
suffix = active[ ":" ]
elseif active.p then
suffix = active.p
elseif assume[ ":" ] then
suffix = assume[ ":" ]
end
start = start:gsub( "^_", " " )
:gsub( "_$", " " )
suffix = suffix:gsub( "^_", " " )
:gsub( "_$", " " )
if alter and not lapsus then
local e = mw.html.create( "span" )
:css( "display", "none" )
:wikitext( r )
r = tostring( e ) .. alter
end
r = string.format( "%s%s%s", start, r, suffix )
else
r = fault( "? . ? . ? . ?" )
end
return r
end -- friends()
local function massmessage( assume, active )
-- Create text from massmessage distribution page
-- Parameter:
-- assume -- table with default options
-- [ 1 ] -- page specification
-- [ 2 ] -- title; none for "_", list if omitted
-- active -- table with current options
-- Returns:
-- string
local source = assume[ 1 ]
local page, r, targets
if source then
local id, story
id = source:match( "^%s*#(%d+)%s*$" )
if id then
page = tonumber( id )
else
page = source
end
page = mw.title.new( page )
if page then
story = page:getContent()
end
if story then
targets = fetch( story, assume.pattern )
else
r = fault( source )
end
end
if targets then
-- if =0
local show = assume[ 2 ]
if show then
show = mw.text.trim( show )
if show == "" then
show = false
end
end
if show == "_" then
show = ""
elseif show then
show = string.format( "[[%s|%s]]", page.prefixedText, show )
end
r = friends( targets, true, false, assume, active, show )
elseif not r then
r = fault( source or "massmessage|namespace:title" )
end
if assume.subst and not mw.isSubsting() then
local s = string.format( "{{subst:%s}}",
assume.subst )
r = fault( s )
end
return r
end -- massmessage()
local function userlist( assume, active, area )
-- Create text from template transclusion
-- Parameter:
-- assume -- table with default options
-- active -- table with current options
-- area -- true: always wide area = URL
-- Returns:
-- string
return friends( active, false, area, assume, active, false )
end -- userlist()
Pinging.f = function ( assigned, area, assume, active )
-- Make list of entries
-- Parameter:
-- assigned -- table with pages or users
-- area -- true: always wide area = URL
-- assume -- table with default options
-- active -- table with current options
-- Returns:
-- string
local defaults = assume or { }
local current = active or { }
local r
if type( assigned ) == "table" and
type( defaults ) == "table" and
type( current ) == "table" then
r = friends( assigned, false, area, defaults, current, false )
else
local s
if type( assigned ) ~= "table" then
s = "assigned"
end
if type( defaults ) ~= "table" then
if s then
s = s .. ", assume"
else
s = "assume"
end
end
if type( current ) ~= "table" then
if s then
s = s .. ", active"
else
s = "active"
end
end
s = s .. " not 'table'"
r = fault( s )
end
return r
end -- Pinging.f()
Failsafe.failsafe = function ( atleast )
-- Retrieve versioning and check for compliance
-- Precondition:
-- atleast -- string, with required version
-- or wikidata|item|~|@ or false
-- Postcondition:
-- Returns string -- with queried version/item, also if problem
-- false -- if appropriate
-- 2020-08-17
local since = atleast
local last = ( since == "~" )
local linked = ( since == "@" )
local link = ( since == "item" )
local r
if last or link or linked or since == "wikidata" then
local item = Failsafe.item
since = false
if type( item ) == "number" and item > 0 then
local suited = string.format( "Q%d", item )
if link then
r = suited
else
local entity = mw.wikibase.getEntity( suited )
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
elseif linked then
if mw.title.getCurrentTitle().prefixedText
== mw.wikibase.getSitelink( suited ) then
r = false
else
r = suited
end
else
r = vsn.value
end
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 = { }
function p.massmessage( a1, a2 )
local r
if type( a1 ) == "table" then
local p1, p2
if type( a1.getParent ) == "function" then
-- a1 is supposed to be a frame
p1 = a1.args
p2 = a1:getParent().args
else
p1 = a1
if type( a2 ) == "table" then
p2 = a2
else
p2 = { }
end
end
r = massmessage( p1, p2 )
else
r = fault( "Pinging::massmessage()" )
end
return r
end
function p.maxecho()
return tostring( Pinging.maxEcho )
end
function p.noping( frame )
return userlist( frame.args, frame:getParent().args, true )
end
function p.ping( frame )
return userlist( frame.args, frame:getParent().args, false )
end
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
setmetatable( p, { __call = function ( func, ... )
setmetatable( p, nil )
return Failsafe
end } )
return p