Modul:TemplatePar: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
c/p aus https://de.wikipedia.beta.wmflabs.org/w/index.php?title=Modul:TemplatePar&action=edit&oldid=22559 (Spezial:PermaLink/179745316#1× C&P Modul mit 700.000 Einbindungen)
K (21 Versionen importiert: Lua) |
(c/p aus https://de.wikipedia.beta.wmflabs.org/w/index.php?title=Modul:TemplatePar&action=edit&oldid=22559 (Spezial:PermaLink/179745316#1× C&P Modul mit 700.000 Einbindungen)) |
||
Zeile 1: | Zeile 1: | ||
-- | local TemplatePar = { serial = "2018-08-04", | ||
suite = "TemplatePar", | |||
item = 15393417, | |||
extern = { }, | |||
frame = false } | |||
--[=[ | |||
Template parameter utility | Template parameter utility | ||
* assert | * assert | ||
Zeile 6: | Zeile 11: | ||
* countNotEmpty | * countNotEmpty | ||
* downcase() | * downcase() | ||
* duplicates | |||
* match | * match | ||
* valid | * valid | ||
* verify() | * verify() | ||
* TemplatePar() | * TemplatePar() | ||
* failsafe() | |||
]=] | ]=] | ||
Zeile 15: | Zeile 22: | ||
-- Module globals | -- Module globals | ||
local MessagePrefix = "lua-module-TemplatePar-" | local MessagePrefix = "lua-module-TemplatePar-" | ||
local L10nDef = {} | local L10nDef = {} | ||
Zeile 36: | Zeile 42: | ||
unknown = "Error in template * unknown parameter name", | unknown = "Error in template * unknown parameter name", | ||
unknownRule = "#invoke:TemplatePar unknown rule" | unknownRule = "#invoke:TemplatePar unknown rule" | ||
} | } | ||
local Patterns = { | local Patterns = { | ||
Zeile 90: | Zeile 78: | ||
[ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$", | [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$", | ||
1, 31, 127 ), | 1, 31, 127 ), | ||
[ "ref" ] = string.format( "%c'%c`UNIQ%s%sref%s%s%sQINU`%c'%c", | |||
127, 34, "%-", "%-", "%-", "%d+", | |||
"%-", 34, 127 ), | |||
[ "+" ] = "%S" | [ "+" ] = "%S" | ||
} | } | ||
Zeile 137: | Zeile 128: | ||
-- Return error keyword, or false | -- Return error keyword, or false | ||
-- Uses: | -- Uses: | ||
-- >< TemplatePar.extern.FileMedia | |||
-- Module:FileMedia | -- Module:FileMedia | ||
-- FileMedia.isType() | -- FileMedia.isType() | ||
local r | local r | ||
if attempt and attempt ~= "" then | if attempt and attempt ~= "" then | ||
local lucky, FileMedia = pcall( require, "Module:FileMedia" ) | local FileMedia | ||
if TemplatePar.extern.FileMedia then | |||
FileMedia = TemplatePar.extern.FileMedia | |||
else | |||
local lucky | |||
lucky, FileMedia = pcall( require, "Module:FileMedia" ) | |||
if type( FileMedia ) == "table" then | |||
FileMedia = FileMedia.FileMedia() | |||
TemplatePar.extern.FileMedia = FileMedia | |||
end | |||
end | |||
if type( FileMedia ) == "table" then | if type( FileMedia ) == "table" then | ||
local s, live = accept:match( "^([a-z]+)(:?)%+?$" ) | local s, live = accept:match( "^([a-z]+)(:?)%+?$" ) | ||
if live then | if live then | ||
Zeile 190: | Zeile 191: | ||
local l10n = L10nDef[ c ] | local l10n = L10nDef[ c ] | ||
if not l10n then | if not l10n then | ||
l10n = L10nDef[ "en | local lucky | ||
lucky, l10n = pcall( mw.loadData, | |||
string.format( "Module:%s/%s", | |||
TemplatePar.suite, c ) ) | |||
if type( l10n ) == "table" then | |||
L10nDef[ c ] = l10n | |||
end | |||
end | |||
if type( l10n ) ~= "table" then | |||
l10n = L10nDef.en | |||
end | end | ||
r = l10n[ say ] | r = l10n[ say ] | ||
if not r then | |||
r = L10nDef.en[ say ] | |||
end | |||
else | else | ||
m:inLanguage( c ) | m:inLanguage( c ) | ||
Zeile 202: | Zeile 215: | ||
return r | return r | ||
end -- factory() | end -- factory() | ||
Zeile 243: | Zeile 242: | ||
return r | return r | ||
end -- failure() | end -- failure() | ||
local function fair( story, scan ) | |||
-- Test for match (possibly user-defined with syntax error) | |||
-- Precondition: | |||
-- story -- string; parameter value | |||
-- scan -- string; pattern | |||
-- Postcondition: | |||
-- Return nil, if not matching, else non-nil | |||
-- Uses: | |||
-- mw.ustring.match() | |||
return mw.ustring.match( story, scan ) | |||
end -- fair() | |||
local function familiar( accept, attempt ) | |||
-- Check string as possible language name or list | |||
-- Precondition: | |||
-- accept -- string; requirement | |||
-- lang | |||
-- langs | |||
-- langW | |||
-- langsW | |||
-- lang+ | |||
-- langs+ | |||
-- langW+ | |||
-- langsW+ | |||
-- attempt -- string; to be tested | |||
-- Postcondition: | |||
-- Return error keyword, or false | |||
-- Uses: | |||
-- >< TemplatePar.extern.Multilingual | |||
-- Module:Multilingual | |||
-- Multilingual.isType() | |||
local r | |||
mw.log("familiar()",accept,attempt) | |||
if attempt and attempt ~= "" then | |||
local Multilingual | |||
if TemplatePar.extern.Multilingual then | |||
Multilingual = TemplatePar.extern.Multilingual | |||
else | |||
local lucky | |||
lucky, Multilingual = pcall( require, "Module:Multilingual" ) | |||
if type( Multilingual ) == "table" then | |||
Multilingual = Multilingual.Multilingual() | |||
TemplatePar.extern.Multilingual = Multilingual | |||
end | |||
end | |||
if type( Multilingual ) == "table" then | |||
local lazy = accept:find( "W", 1, true ) | |||
if accept:find( "s", 1, true ) then | |||
local group = mw.text.split( attempt, "%s+" ) | |||
r = false | |||
for i = 1, #group do | |||
if not Multilingual.isLang( group[ i ], lazy ) then | |||
r = "invalid" | |||
break -- for i | |||
end | |||
end -- for i | |||
elseif Multilingual.isLang( attempt, lazy ) then | |||
r = false | |||
else | |||
r = "invalid" | |||
end | |||
else | |||
r = "missing" | |||
end | |||
elseif accept:find( "+", 1, true ) then | |||
r = "empty" | |||
else | |||
r = false | |||
end | |||
return r | |||
end -- familiar() | |||
local function far( accept, attempt ) | |||
-- Check string as possible URL | |||
-- Precondition: | |||
-- accept -- string; requirement | |||
-- url | |||
-- url+ | |||
-- attempt -- string; to be tested | |||
-- Postcondition: | |||
-- Return error keyword, or false | |||
-- Uses: | |||
-- >< TemplatePar.extern.Multilingual | |||
-- Module:Multilingual | |||
-- Multilingual.isType() | |||
local r | |||
if attempt and attempt ~= "" then | |||
local URLutil | |||
if TemplatePar.extern.URLutil then | |||
URLutil = TemplatePar.extern.URLutil | |||
else | |||
local lucky | |||
lucky, URLutil = pcall( require, "Module:URLutil" ) | |||
if type( URLutil ) == "table" then | |||
URLutil = URLutil.URLutil() | |||
TemplatePar.extern.URLutil = URLutil | |||
end | |||
end | |||
if type( URLutil ) == "table" then | |||
if URLutil.isWebURL( attempt ) then | |||
r = false | |||
else | |||
r = "invalid" | |||
end | |||
else | |||
r = "missing" | |||
end | |||
elseif accept:find( "+", 1, true ) then | |||
r = "empty" | |||
else | |||
r = false | |||
end | |||
return r | |||
end -- far() | |||
Zeile 287: | Zeile 407: | ||
-- mw.text.trim() | -- mw.text.trim() | ||
-- facility() | -- facility() | ||
-- | -- fair() | ||
-- containsCJK() | -- containsCJK() | ||
local r = false | local r = false | ||
Zeile 356: | Zeile 476: | ||
r = facility( s, analyze ) | r = facility( s, analyze ) | ||
n = true | n = true | ||
elseif s:match( " | elseif s:match( "langs?W?%+?" ) then | ||
n = " | r = familiar( s, analyze ) | ||
n = true | |||
elseif s:match( "url%+?" ) then | |||
r = far( s, analyze ) | |||
n = true | |||
end | end | ||
-- datetime+ | |||
-- iso8631+ | |||
-- line+ | |||
if not n and not r then | if not n and not r then | ||
r = "unknownRule" | r = "unknownRule" | ||
Zeile 379: | Zeile 504: | ||
end | end | ||
if scan then | if scan then | ||
local legal, got = pcall( | local legal, got = pcall( fair, analyze, scan ) | ||
if legal then | if legal then | ||
if not got then | if not got then | ||
Zeile 414: | Zeile 539: | ||
-- Postcondition: | -- Postcondition: | ||
-- Return true iff found | -- Return true iff found | ||
local k, v | local k, v, r | ||
for k, v in pairs( haystack ) do | for k, v in pairs( haystack ) do | ||
if k == needle then | if k == needle then | ||
r = true | |||
end | end | ||
end -- for k, v | end -- for k, v | ||
return false | return r or false | ||
end -- fed() | end -- fed() | ||
Zeile 442: | Zeile 567: | ||
g = TemplatePar.downcase( options ) | g = TemplatePar.downcase( options ) | ||
else | else | ||
TemplatePar.frame = mw.getCurrentFrame() | |||
g = TemplatePar.frame | |||
if light then | if light then | ||
g = g:getParent() | g = g:getParent() | ||
Zeile 486: | Zeile 612: | ||
if type( sub ) == "string" then | if type( sub ) == "string" then | ||
sub = sub:gsub( "%%!", "|" ) | sub = sub:gsub( "%%!", "|" ) | ||
:gsub( "%%%(%(", "{{" ) | |||
:gsub( "%%%)%)", "}}" ) | |||
:gsub( "\\n", string.char( 10 ) ) | |||
options.pattern = sub | options.pattern = sub | ||
options.key = nil | options.key = nil | ||
Zeile 526: | Zeile 653: | ||
local function finalize( submit, options | local function finalize( submit, options ) | ||
-- Finalize message | -- Finalize message | ||
-- Precondition: | -- Precondition: | ||
Zeile 535: | Zeile 662: | ||
-- options.cat | -- options.cat | ||
-- options.template | -- options.template | ||
-- Postcondition: | -- Postcondition: | ||
-- Return string or false | -- Return string or false | ||
Zeile 542: | Zeile 668: | ||
local r = false | local r = false | ||
if submit then | if submit then | ||
local lazy = false | |||
local learn = false | |||
local show = false | |||
local opt, s | local opt, s | ||
if type( options ) == "table" then | if type( options ) == "table" then | ||
opt = options | opt = options | ||
Zeile 551: | Zeile 678: | ||
s = opt.preview | s = opt.preview | ||
if type( s ) == "string" and | if type( s ) == "string" and | ||
s ~= "" and s ~= "0" and s ~= "-" then | |||
local sniffer = "{{REVISIONID}}" | |||
if lazy then | if lazy then | ||
show = "" | show = "" | ||
lazy = false | lazy = false | ||
end | end | ||
if not frame then | if not TemplatePar.frame then | ||
frame = mw.getCurrentFrame() | TemplatePar.frame = mw.getCurrentFrame() | ||
end | end | ||
if frame:preprocess( | if TemplatePar.frame:preprocess( sniffer ) == "" then | ||
if s == "1" then | if s == "1" then | ||
show = "*" | show = "*" | ||
Zeile 565: | Zeile 693: | ||
show = s | show = s | ||
end | end | ||
learn = true | |||
end | end | ||
end | end | ||
Zeile 581: | Zeile 710: | ||
local i | local i | ||
if not show or show == "*" then | if not show or show == "*" then | ||
local e = mw.html.create( "span" ) | |||
:attr( "class", "error" ) | |||
:wikitext( "@@@" ) | |||
if learn then | |||
local max = 1000000000 | |||
local id = math.floor( os.clock() * max ) | |||
local sign = string.format( "error_%d", id ) | |||
local btn = mw.html.create( "span" ) | |||
local top = mw.html.create( "div" ) | |||
e:attr( "id", sign ) | |||
btn:css( { ["background"] = "#FFFF00", | |||
["border"] = "#FF0000 3px solid", | |||
["font-weight"] = "bold", | |||
["padding"] = "2px", | |||
["text-decoration"] = "none" } ) | |||
:wikitext( ">>>" ) | |||
sign = string.format( "[[#%s|%s]]", | |||
sign, tostring( btn ) ) | |||
top:wikitext( sign, " ", submit ) | |||
mw.addWarning( tostring( top ) ) | |||
end | |||
show = tostring( e ) | |||
end | end | ||
i = show:find( "@@@", 1, true ) | i = show:find( "@@@", 1, true ) | ||
Zeile 593: | Zeile 743: | ||
r = show | r = show | ||
end | end | ||
end | |||
if learn and r then | |||
-- r = fatal( r ) | |||
end | end | ||
s = opt.cat | s = opt.cat | ||
if type( s ) == "string" then | if type( s ) == "string" then | ||
local link | |||
if opt.errNS then | if opt.errNS then | ||
local ns = mw.title.getCurrentTitle().namespace | local ns = mw.title.getCurrentTitle().namespace | ||
Zeile 603: | Zeile 757: | ||
local spaces = string.format( " %s ", opt.errNS ) | local spaces = string.format( " %s ", opt.errNS ) | ||
if spaces:match( space ) then | if spaces:match( space ) then | ||
link = true | |||
end | end | ||
elseif st == "table" then | elseif st == "table" then | ||
for i = 1, #opt.errNS do | for i = 1, #opt.errNS do | ||
if opt.errNS[ i ] == ns then | if opt.errNS[ i ] == ns then | ||
link = true | |||
break -- for i | break -- for i | ||
end | end | ||
end -- for i | end -- for i | ||
end | end | ||
else | |||
link = true | |||
end | end | ||
if | if link then | ||
local cats, i | |||
if not r then | if not r then | ||
r = "" | r = "" | ||
Zeile 625: | Zeile 780: | ||
end | end | ||
end | end | ||
cats = mw.text.split( s, "%s*#%s*" ) | |||
for i = 1, #cats do | for i = 1, #cats do | ||
s = mw.text.trim( cats[ i ] ) | s = mw.text.trim( cats[ i ] ) | ||
Zeile 804: | Zeile 958: | ||
-- options.mandatory | -- options.mandatory | ||
-- options.optional | -- options.optional | ||
-- frame -- object, or false | -- frame -- object; #invoke environment, or false | ||
-- Postcondition: | -- Postcondition: | ||
-- Return string with error message as configured; | -- Return string with error message as configured; | ||
-- false if valid | -- false if valid | ||
-- Uses: | -- Uses: | ||
-- < TemplatePar.frame | |||
-- fold() | -- fold() | ||
-- fetch() | -- fetch() | ||
Zeile 814: | Zeile 969: | ||
-- finalize() | -- finalize() | ||
local duty, r | local duty, r | ||
if frame then | |||
TemplatePar.frame = frame | |||
else | |||
TemplatePar.frame = mw.getCurrentFrame() | |||
end | |||
if type( options ) == "table" then | if type( options ) == "table" then | ||
if type( options.mandatory ) ~= "table" then | if type( options.mandatory ) ~= "table" then | ||
Zeile 836: | Zeile 996: | ||
end | end | ||
end | end | ||
return finalize( r, options | return finalize( r, options ) | ||
end -- form() | end -- form() | ||
Zeile 907: | Zeile 1.067: | ||
-- false if valid or no answer permitted | -- false if valid or no answer permitted | ||
-- Uses: | -- Uses: | ||
-- mw.text.trim() | -- mw.text.trim() | ||
-- format() | -- format() | ||
-- failure() | -- failure() | ||
Zeile 914: | Zeile 1.074: | ||
local story = assignment.args[ access ] or "" | local story = assignment.args[ access ] or "" | ||
if type( access ) == "number" then | if type( access ) == "number" then | ||
story = mw.text.trim( story ) | story = mw.text.trim( story ) | ||
end | end | ||
if type( options ) ~= "table" then | if type( options ) ~= "table" then | ||
Zeile 986: | Zeile 1.146: | ||
end | end | ||
if r then | if r then | ||
r = finalize( r, options | r = finalize( r, options ) | ||
else | else | ||
s = frame.args[ 1 ] or "" | s = frame.args[ 1 ] or "" | ||
Zeile 994: | Zeile 1.154: | ||
end | end | ||
if action == "valid" then | if action == "valid" then | ||
r = TemplatePar.valid( s, options | r = TemplatePar.valid( s, options ) | ||
elseif action == "assert" then | elseif action == "assert" then | ||
r = TemplatePar.assert( s, "", options ) | r = TemplatePar.assert( s, "", options ) | ||
Zeile 1.104: | Zeile 1.264: | ||
TemplatePar.valid = function ( access, options | TemplatePar.failsafe = function ( assert ) | ||
-- Retrieve versioning and check for compliance | |||
-- Precondition: | |||
-- assert -- string, with required version or "wikidata", | |||
-- or false | |||
-- Postcondition: | |||
-- Returns string with appropriate version, or false | |||
local r | |||
if since == "wikidata" then | |||
local item = TemplatePar.item | |||
since = false | |||
if type( item ) == "number" and item > 0 then | |||
local ent = mw.wikibase.getEntity( string.format( "Q%d", | |||
item ) ) | |||
if type( ent ) == "table" then | |||
local vsn = ent: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 <= TemplatePar.serial then | |||
r = TemplatePar.serial | |||
else | |||
r = false | |||
end | |||
end | |||
return r | |||
end -- TemplatePar.failsafe() | |||
TemplatePar.valid = function ( access, options ) | |||
-- Check validity of one particular template parameter | -- Check validity of one particular template parameter | ||
-- Precondition: | -- Precondition: | ||
Zeile 1.110: | Zeile 1.306: | ||
-- string or number | -- string or number | ||
-- options -- table or nil; optional details | -- options -- table or nil; optional details | ||
-- Postcondition: | -- Postcondition: | ||
-- Return string with error message as configured; | -- Return string with error message as configured; | ||
-- false if valid or no answer permitted | -- false if valid or no answer permitted | ||
-- Uses: | -- Uses: | ||
-- >< TemplatePar.frame | |||
-- mw.text.trim() | -- mw.text.trim() | ||
-- TemplatePar.downcase() | -- TemplatePar.downcase() | ||
Zeile 1.140: | Zeile 1.336: | ||
params = TemplatePar.downcase( options ) | params = TemplatePar.downcase( options ) | ||
else | else | ||
params = frame:getParent() | if not TemplatePar.frame then | ||
TemplatePar.frame = mw.getCurrentFrame() | |||
end | |||
params = TemplatePar.frame:getParent() | |||
end | end | ||
r = formatted( params, access, options ) | r = formatted( params, access, options ) | ||
Zeile 1.179: | Zeile 1.378: | ||
-- furnish() | -- furnish() | ||
return furnish( frame, "assert" ) | return furnish( frame, "assert" ) | ||
end -- .assert() | end -- p.assert() | ||
Zeile 1.216: | Zeile 1.415: | ||
end | end | ||
return r or "" | return r or "" | ||
end -- .check() | end -- p.check() | ||
Zeile 1.227: | Zeile 1.426: | ||
-- TemplatePar.count() | -- TemplatePar.count() | ||
return tostring( TemplatePar.count() ) | return tostring( TemplatePar.count() ) | ||
end -- .count() | end -- p.count() | ||
Zeile 1.238: | Zeile 1.437: | ||
-- TemplatePar.countNotEmpty() | -- TemplatePar.countNotEmpty() | ||
return tostring( TemplatePar.countNotEmpty() ) | return tostring( TemplatePar.countNotEmpty() ) | ||
end -- .countNotEmpty() | end -- p.countNotEmpty() | ||
Zeile 1.244: | Zeile 1.443: | ||
function p.match( frame ) | function p.match( frame ) | ||
-- Combined analysis of parameters and their values | -- Combined analysis of parameters and their values | ||
-- Precondition: | |||
-- frame -- object; #invoke environment | |||
-- Postcondition: | -- Postcondition: | ||
-- Return string with error message or "" | -- Return string with error message or "" | ||
-- Uses: | -- Uses: | ||
-- < TemplatePar.frame | |||
-- mw.text.trim() | -- mw.text.trim() | ||
-- mw.ustring.lower() | -- mw.ustring.lower() | ||
Zeile 1.266: | Zeile 1.468: | ||
local k, v, s | local k, v, s | ||
local params = { } | local params = { } | ||
TemplatePar.frame = frame | |||
for k, v in pairs( frame.args ) do | for k, v in pairs( frame.args ) do | ||
if type( k ) == "number" then | if type( k ) == "number" then | ||
Zeile 1.349: | Zeile 1.552: | ||
r = failure( "invalid", errValues, options ) | r = failure( "invalid", errValues, options ) | ||
end | end | ||
r = finalize( r, options | r = finalize( r, options ) | ||
end | end | ||
end | end | ||
return r or "" | return r or "" | ||
end -- .match() | end -- p.match() | ||
Zeile 1.366: | Zeile 1.569: | ||
-- furnish() | -- furnish() | ||
return furnish( frame, "valid" ) | return furnish( frame, "valid" ) | ||
end -- .valid() | end -- p.valid() | ||
p.failsafe = function ( frame ) | |||
-- Check or retrieve version information | |||
-- Precondition: | |||
-- frame -- object; #invoke environment | |||
-- Postcondition: | |||
-- Return string with error message or "" | |||
-- Uses: | |||
-- TemplatePar.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 TemplatePar.failsafe( since ) or "" | |||
end -- p.failsafe() | |||
Zeile 1.375: | Zeile 1.604: | ||
-- Return table with functions | -- Return table with functions | ||
return TemplatePar | return TemplatePar | ||
end -- .TemplatePar() | end -- p.TemplatePar() | ||
return p | return p |