Modul:PageUtil: Unterschied zwischen den Versionen
Erscheinungsbild
Admin (Diskussion | Beiträge) Die Seite wurde neu angelegt: „local PageUtil = { suite = "PageUtil", serial = "2018-10-19", item = 0 } --[=[ PageUtil ]=] PageUtil.maxPages = 200 local function fault( alert, frame ) -- Format message with class="error" -- alert -- string, with message -- frame -- object, if known -- Returns message with markup local scream = alert if frame then scream = string.format( "%s * %s", frame:getTitle(),…“ |
Philip (Diskussion | Beiträge) K 1 Version importiert |
||
(Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
local PageUtil = { suite = "PageUtil", | local PageUtil = { suite = "PageUtil", | ||
serial = " | serial = "2024-08-20", | ||
item = | item = 89064539 } | ||
--[=[ | --[=[ | ||
PageUtil | PageUtil | ||
]=] | ]=] | ||
local Failsafe = PageUtil | |||
Zeile 25: | Zeile 26: | ||
:wikitext( scream ) ) | :wikitext( scream ) ) | ||
end -- fault() | end -- fault() | ||
local function find( area, ask ) | |||
-- Check for local page existence without traces | |||
-- area -- number, with namespace number >= 0 | |||
-- ask -- string, with title | |||
-- Returns boolean | |||
local r = false | |||
if mw.title.makeTitle( area, ask ).protectionLevels.edit then | |||
r = true | |||
end | |||
return r | |||
end -- find() | |||
Zeile 129: | Zeile 144: | ||
PageUtil. | PageUtil.exists = function ( area, ask, apply, alert ) | ||
-- | -- Check for existence | ||
-- | -- area -- number or string, with namespace specification | ||
-- | -- -- number >= 0 of local namespace | ||
-- or | -- -- "media" -- files including commons | ||
-- | -- -- "msg" -- system messages | ||
-- Returns | -- -- "data" -- commons:Data:*.tab | ||
-- ask -- table, with list of titles | |||
local r | -- apply -- table or not, with 0, 1, 2 elements | ||
if | -- -- [true]: category list on existence | ||
-- -- [false]: category list on non-existence | |||
-- -- category titles, multiple separated by \n | |||
if type( | -- alert -- table or not, with 0, 1, 2 elements | ||
-- -- [true]: return value on existence | |||
-- -- [false]: return value on non-existence | |||
if type( | -- -- if string then followed by apply categories | ||
-- Returns string, with content, or other element of alert | |||
local got, leg, r | |||
if type( area ) == "number" and | |||
area >= 0 and | |||
math.floor( area ) == area then | |||
for k, v in pairs( ask ) do | |||
if type( v ) == "string" then | |||
got = got or { } | |||
leg = find( area, v ) | |||
got[ leg ] = got[ leg ] or { } | |||
table.insert( got[ leg ], v ) | |||
end | |||
end -- for k, v | |||
elseif area == "media" then | |||
for k, v in pairs( ask ) do | |||
if type( v ) == "string" then | |||
got = got or { } | |||
leg = find( 6, v ) | |||
if not leg then | |||
leg = mw.title.makeTitle( 6, v ).exists | |||
end | |||
got[ leg ] = got[ leg ] or { } | |||
table.insert( got[ leg ], v ) | |||
end | |||
end -- for k, v | |||
elseif area == "msg" then | |||
for k, v in pairs( ask ) do | |||
if type( v ) == "string" then | |||
got = got or { } | |||
leg = mw.message.new( v ):exists() | |||
got[ leg ] = got[ leg ] or { } | |||
table.insert( got[ leg ], v ) | |||
end | |||
end -- for k, v | |||
elseif area == "data" then | |||
local suffix = "tab" | |||
local data, j, lucky | |||
for k, v in pairs( ask ) do | |||
if type( v ) == "string" then | |||
got = got or { } | |||
if not v:find( ".", 2, true ) then | |||
j = -1 - #suffix | |||
if v:sub( j ) ~= "." .. suffix then | |||
v = string.format( "%s.%s", v, suffix ) | |||
end | |||
end | |||
lucky, data = pcall( mw.ext.data.get, v ) | |||
if lucky then | |||
leg = true | |||
else | |||
leg = false | |||
end | end | ||
got[ leg ] = got[ leg ] or { } | |||
table.insert( got[ leg ], v ) | |||
end | end | ||
end | end -- for k, v | ||
else | |||
r = tostring( mw.html.create( "span" ) | |||
:addClass( "error" ) | |||
:wikitext( "exists@PageUtil space error" ) ) | |||
end | end | ||
if | if got then | ||
local b = { false, true } | |||
local bg, ea, sa, sr | |||
for bk, bv in pairs( b ) do | |||
bg = got[ bv ] | |||
end | if bg then | ||
sr = type( r ) | |||
ea = alert[ bv ] | |||
if ea then | |||
sa = type( ea ) | |||
if sr == "string" and | |||
sa == "string" then | |||
r = r .. ea | |||
elseif sr == "nil" then | |||
r = ea | |||
sr = sa | |||
end | |||
if sr == "string" and | |||
r:find( "@@@", 1, true ) then | |||
local space | |||
if type( area ) == "number" then | |||
space = area | |||
elseif area == "media" then | |||
space = 6 | |||
elseif area == "msg" then | |||
space = 8 | |||
elseif area == "data" then | |||
space = "commons:Data" | |||
end | |||
if type( space ) == "number" then | |||
sa = mw.site.namespaces[ space ].name | |||
if space == 6 or space == 14 then | |||
space = ":" .. sa | |||
else | |||
space = sa | |||
end | |||
end | |||
sa = "" | |||
for k, v in pairs( bg ) do | |||
sa = string.format( "%s [[%s:%s]]", | |||
sa, space, v ) | |||
end -- for k, v | |||
r = r:gsub( "@@@", sa ) | |||
end | |||
end | |||
ea = apply[ bv ] | |||
if ea then | |||
if sr == "nil" then | |||
r = "" | |||
sr = "string" | |||
end | |||
if sr == "string" then | |||
sa = type( ea ) | |||
if sa == "string" then | |||
r = string.format( "%s[[Category:%s]]", | |||
r, sa ) | |||
elseif sa == "table" then | |||
for k, v in pairs( ea ) do | |||
r = string.format( "%s[[Category:%s]]", | |||
r, v ) | |||
end -- for k, v | |||
end | |||
end | |||
end | |||
end | |||
end -- for bk, bv | |||
end | end | ||
return r | return r | ||
end -- PageUtil. | end -- PageUtil.exists() | ||
Zeile 260: | Zeile 387: | ||
return r | return r | ||
end -- .merge() | end -- .merge() | ||
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 | |||
-- 2024-03-01 | |||
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 | |||
elseif link then | |||
r = false | |||
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() | |||
Zeile 265: | Zeile 452: | ||
-- Export | -- Export | ||
local p = { } | local p = { } | ||
p.exists = function ( frame ) | |||
local pars = frame:getParent().args | |||
local ns, r | |||
if not pars.ns then | |||
elseif pars.ns:find( "^%d+$" ) then | |||
ns = tonumber( pars.ns ) | |||
elseif pars.ns:find( "^%a+$" ) then | |||
ns = pars.ns:lower() | |||
end | |||
if ns then | |||
local coll, t | |||
for k, v in pairs( pars ) do | |||
t = type( k ) | |||
if t == "string" then | |||
if t:match( "^%d+$" ) then | |||
k = tonumber( k ) | |||
else | |||
k = false | |||
end | |||
end | |||
if k then | |||
v = mw.text.trim( v ) | |||
if v ~= "" then | |||
coll = coll or { } | |||
table.insert( coll, v ) | |||
end | |||
end | |||
end -- for k, v | |||
if coll then | |||
local loss = ( pars.loss == "1" ) | |||
local cat, err | |||
if pars.cat then | |||
t = mw.text.split( pars.cat, "%s*\n%s*" ) | |||
if #t > 0 then | |||
cat = { [ loss ] = t } | |||
end | |||
end | |||
if pars.err and pars.err ~= "" then | |||
err = { [ loss ] = pars.err } | |||
end | |||
r = PageUtil.exists( ns, coll, cat, err ) | |||
end | |||
end | |||
return r or "" | |||
end -- p.exists | |||
p.getCategories = function ( frame ) | |||
local r = "" | |||
local s = frame.args[ 1 ] | |||
local c, t | |||
if s then | |||
s = mw.text.trim( s ) | |||
if s == "" then | |||
s = false | |||
end | |||
end | |||
if s then | |||
t = mw.title.new( s ) | |||
else | |||
t = mw.title.getCurrentTitle() | |||
end | |||
c = t.categories | |||
if c then | |||
local n = #c | |||
if n > 0 then | |||
for i = 1, n do | |||
if r ~= "" then | |||
r = r .. "|" | |||
end | |||
r = r .. c[ i ] | |||
end -- for i | |||
end | |||
end | |||
return r | |||
end -- p.getCategories | |||
p.getProtection = function ( frame ) | p.getProtection = function ( frame ) | ||
Zeile 275: | Zeile 538: | ||
end -- p.getProtection | end -- p.getProtection | ||
p.isRedirect = function () | |||
return mw.title.getCurrentTitle().isRedirect and "1" or "" | return mw.title.getCurrentTitle().isRedirect and "1" or "" | ||
end -- p.isRedirect | end -- p.isRedirect | ||
Zeile 302: | Zeile 565: | ||
end | end | ||
end | end | ||
return | return Failsafe.failsafe( since ) or "" | ||
end -- p.failsafe() | end -- p.failsafe() | ||
Zeile 308: | Zeile 571: | ||
return PageUtil | return PageUtil | ||
end | end | ||
setmetatable( p, { __call = function ( func, ... ) | |||
setmetatable( p, nil ) | |||
return Failsafe | |||
end } ) | |||
return p | return p |
Aktuelle Version vom 5. Februar 2025, 09:57 Uhr
Die Dokumentation für dieses Modul kann unter Modul:PageUtil/Doku erstellt werden
local PageUtil = { suite = "PageUtil",
serial = "2024-08-20",
item = 89064539 }
--[=[
PageUtil
]=]
local Failsafe = PageUtil
PageUtil.maxPages = 200
local function fault( alert, frame )
-- Format message with class="error"
-- alert -- string, with message
-- frame -- object, if known
-- Returns message with markup
local scream = alert
if frame then
scream = string.format( "%s * %s", frame:getTitle(), scream )
end
return tostring( mw.html.create( "span" )
:addClass( "error" )
:wikitext( scream ) )
end -- fault()
local function find( area, ask )
-- Check for local page existence without traces
-- area -- number, with namespace number >= 0
-- ask -- string, with title
-- Returns boolean
local r = false
if mw.title.makeTitle( area, ask ).protectionLevels.edit then
r = true
end
return r
end -- find()
local function flat( adjust, assembly )
-- Replace links to pages by inner links
-- adjust -- string, with text
-- assembly -- table, with page infos
-- Returns adjusted string
local r = adjust
local seek, shift, source, subst
for k, v in pairs( assembly ) do
source = v[ 1 ]
shift = v[ 2 ]
source = ":?" .. source:gsub( " ", "[_ ]+" )
:gsub( "[%.%(%)%*%?%+%-]", "%1" )
.. "%s*"
seek = "%[%[%s*" .. source .. "(#[^%]]*%]%])"
subst = "[[%1"
r = r:gsub( seek, subst )
seek = "%[%[%s*" .. source .. "(%|[^%]]*%]%])"
subst = "[[#" .. shift .. "%1"
r = r:gsub( seek, subst )
seek = "%[%[%s*(" .. source .. "%]%])"
subst = "[[#" .. shift .. "|%1"
r = r:gsub( seek, subst )
end -- for k, v
return r
end -- flat()
local function fraction( access, frame )
-- Retrieve text from section
-- access -- string, with request
-- frame -- object
-- Returns content, or false
-- Uses:
-- mw.title.new() .exists
local r
local seek = "^(#lstx?):%s*%[%[([^%[|%]\n]+)%]%]%s*(%S.*)%s*$"
local scope, source, section = access:match( seek )
if source then
local page = mw.title.new( source )
source = page.prefixedText
if page.exists then
section = mw.text.trim( section )
if section ~= "" then
r = frame:callParserFunction{ name = scope,
args = { source,
section } }
end
else
r = tostring( mw.html.create( "div" )
:addClass( "error" )
:wikitext( source ) )
end
end
return r
end -- fraction()
local function full( access, frame, alias, assembly )
-- Retrieve text from page
-- access -- string, with page name
-- frame -- object
-- alias -- number, unique
-- assembly -- table, with page infos
-- Returns string with content, or nil
-- Uses:
-- mw.title.new() .exists
local page = mw.title.new( access )
local r
if page then
if page.exists then
local source = page.prefixedText
local segment = string.format( "PageUtilMerge-%d", alias )
local seed
if page.namespace == 0 then
seed = ":" .. source
else
seed = source
end
r = string.format( "%s\n%s",
tostring( mw.html.create( "span" )
:attr( "id", segment ) ),
frame:expandTemplate( { title = seed } ) )
table.insert( assembly, { source, segment } )
else
r = tostring( mw.html.create( "div" )
:addClass( "error" )
:wikitext( page.prefixedText ) )
end
else
r = string.format( "%s '%s'", "Unknown page", access )
r = tostring( mw.html.create( "div" )
:addClass( "error" )
:wikitext( r ) )
end
return r
end -- full()
PageUtil.exists = function ( area, ask, apply, alert )
-- Check for existence
-- area -- number or string, with namespace specification
-- -- number >= 0 of local namespace
-- -- "media" -- files including commons
-- -- "msg" -- system messages
-- -- "data" -- commons:Data:*.tab
-- ask -- table, with list of titles
-- apply -- table or not, with 0, 1, 2 elements
-- -- [true]: category list on existence
-- -- [false]: category list on non-existence
-- -- category titles, multiple separated by \n
-- alert -- table or not, with 0, 1, 2 elements
-- -- [true]: return value on existence
-- -- [false]: return value on non-existence
-- -- if string then followed by apply categories
-- Returns string, with content, or other element of alert
local got, leg, r
if type( area ) == "number" and
area >= 0 and
math.floor( area ) == area then
for k, v in pairs( ask ) do
if type( v ) == "string" then
got = got or { }
leg = find( area, v )
got[ leg ] = got[ leg ] or { }
table.insert( got[ leg ], v )
end
end -- for k, v
elseif area == "media" then
for k, v in pairs( ask ) do
if type( v ) == "string" then
got = got or { }
leg = find( 6, v )
if not leg then
leg = mw.title.makeTitle( 6, v ).exists
end
got[ leg ] = got[ leg ] or { }
table.insert( got[ leg ], v )
end
end -- for k, v
elseif area == "msg" then
for k, v in pairs( ask ) do
if type( v ) == "string" then
got = got or { }
leg = mw.message.new( v ):exists()
got[ leg ] = got[ leg ] or { }
table.insert( got[ leg ], v )
end
end -- for k, v
elseif area == "data" then
local suffix = "tab"
local data, j, lucky
for k, v in pairs( ask ) do
if type( v ) == "string" then
got = got or { }
if not v:find( ".", 2, true ) then
j = -1 - #suffix
if v:sub( j ) ~= "." .. suffix then
v = string.format( "%s.%s", v, suffix )
end
end
lucky, data = pcall( mw.ext.data.get, v )
if lucky then
leg = true
else
leg = false
end
got[ leg ] = got[ leg ] or { }
table.insert( got[ leg ], v )
end
end -- for k, v
else
r = tostring( mw.html.create( "span" )
:addClass( "error" )
:wikitext( "exists@PageUtil space error" ) )
end
if got then
local b = { false, true }
local bg, ea, sa, sr
for bk, bv in pairs( b ) do
bg = got[ bv ]
if bg then
sr = type( r )
ea = alert[ bv ]
if ea then
sa = type( ea )
if sr == "string" and
sa == "string" then
r = r .. ea
elseif sr == "nil" then
r = ea
sr = sa
end
if sr == "string" and
r:find( "@@@", 1, true ) then
local space
if type( area ) == "number" then
space = area
elseif area == "media" then
space = 6
elseif area == "msg" then
space = 8
elseif area == "data" then
space = "commons:Data"
end
if type( space ) == "number" then
sa = mw.site.namespaces[ space ].name
if space == 6 or space == 14 then
space = ":" .. sa
else
space = sa
end
end
sa = ""
for k, v in pairs( bg ) do
sa = string.format( "%s [[%s:%s]]",
sa, space, v )
end -- for k, v
r = r:gsub( "@@@", sa )
end
end
ea = apply[ bv ]
if ea then
if sr == "nil" then
r = ""
sr = "string"
end
if sr == "string" then
sa = type( ea )
if sa == "string" then
r = string.format( "%s[[Category:%s]]",
r, sa )
elseif sa == "table" then
for k, v in pairs( ea ) do
r = string.format( "%s[[Category:%s]]",
r, v )
end -- for k, v
end
end
end
end
end -- for bk, bv
end
return r
end -- PageUtil.exists()
PageUtil.getProtection = function ( access, action )
-- Retrieve protection
-- access -- string or title or nil, with page, default: current
-- action -- string or nil, with action, default: edit
-- Returns number: One of: 0, 0.5, 0.75, 1
local t = type( access )
local r = 0
local p
if t == "string" then
t = mw.title.new( access )
elseif t == "table" then
t = access
else
t = mw.title.getCurrentTitle()
end
p = t.protectionLevels
if type( p ) == "table" then
local s
if type( action ) == "string" then
s = mw.text.trim( action )
if s == "" then
s = false
end
end
p = p[ s or "edit" ]
if type( p ) == "table" then
for k, v in pairs( p ) do
if v == "autoconfirmed" then
r = 0.5
elseif v == "editeditorprotected" then
r = 0.75
elseif v == "sysop" then
r = 1
end
end -- for k, v
end
end
return r
end -- PageUtil.getProtection()
PageUtil.merge = function ( args, frame )
-- Retrieve text
-- args -- table, with request
-- frame -- object, if available
-- Returns string, with content
local max = 0
local r = ""
for k, v in pairs( args ) do
if type( k ) == "number" and
k > max then
max = k
end
end -- for k, v
if max > 0 then
local n = 0
local pages = { { mw.title.getCurrentTitle().prefixedText,
"" } }
local mode, s, section, swallow
if not frame then
frame = mw.getCurrentFrame()
end
for i = 1, max do
s = args[ i ]
if s then
swallow = s:match( "^%s*(#lstx?:[^\n]*%S)%s*$" )
if swallow then
s = fraction( swallow, frame )
n = n + 1
else
swallow = s:match( "^%s*%[%[([^%[|%]\n]+)%]%]%s*$" )
if swallow then
s = full( swallow, frame, i, pages )
n = n + 1
end
end
if s then
r = r .. mw.text.trim( s )
end
if n > PageUtil.maxPages then
s = string.format( "'''Too many pages (max. %d)'''",
PageUtil.maxPages )
r = string.format( "%s\n\n%s",
r,
fault( s, frame ) )
break -- for i
end
end
end -- for i
r = flat( r, pages )
end
return r
end -- .merge()
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
-- 2024-03-01
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
elseif link then
r = false
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.exists = function ( frame )
local pars = frame:getParent().args
local ns, r
if not pars.ns then
elseif pars.ns:find( "^%d+$" ) then
ns = tonumber( pars.ns )
elseif pars.ns:find( "^%a+$" ) then
ns = pars.ns:lower()
end
if ns then
local coll, t
for k, v in pairs( pars ) do
t = type( k )
if t == "string" then
if t:match( "^%d+$" ) then
k = tonumber( k )
else
k = false
end
end
if k then
v = mw.text.trim( v )
if v ~= "" then
coll = coll or { }
table.insert( coll, v )
end
end
end -- for k, v
if coll then
local loss = ( pars.loss == "1" )
local cat, err
if pars.cat then
t = mw.text.split( pars.cat, "%s*\n%s*" )
if #t > 0 then
cat = { [ loss ] = t }
end
end
if pars.err and pars.err ~= "" then
err = { [ loss ] = pars.err }
end
r = PageUtil.exists( ns, coll, cat, err )
end
end
return r or ""
end -- p.exists
p.getCategories = function ( frame )
local r = ""
local s = frame.args[ 1 ]
local c, t
if s then
s = mw.text.trim( s )
if s == "" then
s = false
end
end
if s then
t = mw.title.new( s )
else
t = mw.title.getCurrentTitle()
end
c = t.categories
if c then
local n = #c
if n > 0 then
for i = 1, n do
if r ~= "" then
r = r .. "|"
end
r = r .. c[ i ]
end -- for i
end
end
return r
end -- p.getCategories
p.getProtection = function ( frame )
local n = PageUtil.getProtection( frame.args[ 1 ], frame.args[ 2 ] )
local t = { [ 0 ] = "",
[ 0.5 ] = mw.ustring.char( 189 ),
[ 0.75 ] = mw.ustring.char( 190 ),
[ 1 ] = "1" }
return t[ n ]
end -- p.getProtection
p.isRedirect = function ()
return mw.title.getCurrentTitle().isRedirect and "1" or ""
end -- p.isRedirect
p.merge = function ( frame )
local lucky, r = pcall( PageUtil.merge, frame.args, frame )
if not lucky then
r = fault( r, frame )
end
return r
end -- p.merge
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()
function p.PageUtil()
return PageUtil
end
setmetatable( p, { __call = function ( func, ... )
setmetatable( p, nil )
return Failsafe
end } )
return p