|
|
Line 1: |
Line 1: |
− | local TemplateData = { suite = "TemplateData",
| + | {{Navigation}} |
− | serial = "2022-03-10",
| |
− | item = 46997995 }
| |
− | --[==[
| |
− | improve template:TemplateData
| |
− | ]==]
| |
− | local Failsafe = TemplateData
| |
| | | |
| + | * This monster appears in the artwork of "[[Ancient Warriors Saga - Sun-Liu Alliance]]". |
| | | |
− | local Config = {
| + | * This monster is based on [[wikipedia:Zhou Yu|Zhou Yu]] ([[wikipedia:Courtesy name|courtesy name]]: '''Gongjin'''), from the historical novel ''[[wikipedia:Romance of the Three Kingdoms|Romance of the Three Kingdoms]]'', a famed [[wikipedia:Eastern Wu|Wu]] general known for both his wit and beauty serving under [[wikipedia:Sun Quan|Sun Quan]]. He was known for his role during [[wikipedia:Battle of Red Cliffs|Battle of Red Cliffs]], the [[wikipedia:Battle of Jiangling (208)|Battle of Jiangling]] as well as for his many victories which served as the basis of the Wu Kingdom. |
− | -- multiple option names mapped into unique internal fields
| + | ** Additionally, this monster's swan motif and "Graceful" moniker might be a reference to Zhou Yu's popular moniker "Zhou the Beautiful Youth", as swans are symbols of beauty. |
− | basicCnf = { catProblem = "strange",
| |
− | classMultiColumns = "selMultClm",
| |
− | classNoNumTOC = "suppressTOCnum",
| |
− | classTable = "classTable",
| |
− | cssParWrap = "cssTabWrap",
| |
− | cssParams = "cssTable",
| |
− | docpageCreate = "suffix",
| |
− | docpageDetect = "subpage",
| |
− | helpBoolean = "support4boolean",
| |
− | helpContent = "support4content",
| |
− | helpDate = "support4date",
| |
− | helpFile = "support4wiki-file-name",
| |
− | helpFormat = "supportFormat",
| |
− | helpLine = "support4line",
| |
− | helpNumber = "support4number",
| |
− | helpPage = "support4wiki-page-name",
| |
− | helpString = "support4string",
| |
− | helpTemplate = "support4wiki-template-name",
| |
− | helpURL = "support4url",
| |
− | helpUser = "support4wiki-user-name",
| |
− | msgDescMiss = "solo",
| |
− | tStylesTOCnum = "stylesTOCnum",
| |
− | tStylesMultiColumns = "stylesMultClm" },
| |
− | classTable = { "wikitable" }, -- classes for params table
| |
− | debugmultilang = "C0C0C0",
| |
− | loudly = false, -- show exported element, etc.
| |
− | solo = false, -- complaint on missing description
| |
− | strange = false, -- title of maintenance category
| |
− | cssTable = false, -- styles for params table
| |
− | cssTabWrap = false, -- styles for params table wrapper
| |
− | debug = false,
| |
− | subpage = false, -- pattern to identify subpage
| |
− | suffix = false, -- subpage creation scheme
| |
− | suppressTOCnum = false, -- class for TOC number suppression
| |
− | jsonDebug = "json-code-lint" -- class for jsonDebug tool
| |
− | }
| |
− | local Data = {
| |
− | div = false, -- <div class="mw-templatedata-doc-wrap">
| |
− | got = false, -- table, initial templatedata object
| |
− | heirs = false, -- table, params that are inherited
| |
− | jump = false, -- source position at end of "params"
| |
− | less = false, -- main description missing
| |
− | lasting = false, -- old syntax encountered
| |
− | lazy = false, -- doc mode; do not generate effective <templatedata>
| |
− | leading = false, -- show TOC
| |
− | -- low = false, -- 1= mode
| |
− | order = false, -- parameter sequence
| |
− | params = false, -- table, exported parameters
| |
− | scream = false, -- error messages
| |
− | sibling = false, -- TOC juxtaposed
| |
− | slang = nil, -- project/user language code
| |
− | slim = false, -- JSON reduced to plain
| |
− | source = false, -- JSON input
| |
− | strip = false, -- <templatedata> evaluation
| |
− | tag = false, -- table, exported root element
| |
− | title = false, -- page
| |
− | tree = false -- table, rewritten templatedata object
| |
− | }
| |
− | local Permit = {
| |
− | builder = { after = "block",
| |
− | align = "block",
| |
− | block = "block",
| |
− | compressed = "block",
| |
− | dense = "block",
| |
− | grouped = "inline",
| |
− | half = "inline",
| |
− | indent = "block",
| |
− | inline = "inline",
| |
− | last = "block",
| |
− | lead = "block",
| |
− | newlines = "*",
| |
− | spaced = "inline" },
| |
− | colors = { bg = "FFFFFF",
| |
− | fg = "000000",
| |
− | tableheadbg = "B3B7FF",
| |
− | required = "EAF3FF",
| |
− | suggested = "FFFFFF",
| |
− | optional = "EAECF0",
| |
− | deprecated = "FFCBCB" },
| |
− | params = { aliases = "table",
| |
− | autovalue = "string",
| |
− | default = "string table I18N nowiki",
| |
− | deprecated = "boolean string I18N",
| |
− | description = "string table I18N",
| |
− | example = "string table I18N nowiki",
| |
− | label = "string table I18N",
| |
− | inherits = "string",
| |
− | required = "boolean",
| |
− | style = "string table",
| |
− | suggested = "boolean",
| |
− | suggestedvalues = "string table number boolean",
| |
− | type = "string" },
| |
− | root = { description = "string table I18N",
| |
− | format = "string",
| |
− | maps = "table",
| |
− | params = "table",
| |
− | paramOrder = "table",
| |
− | sets = "table" },
| |
− | search = "[{,]%%s*(['\"])%s%%1%%s*:%%s*%%{",
| |
− | types = { boolean = true,
| |
− | content = true,
| |
− | date = true,
| |
− | line = true,
| |
− | number = true,
| |
− | string = true,
| |
− | unknown = true,
| |
− | url = true,
| |
− | ["wiki-file-name"] = true,
| |
− | ["wiki-page-name"] = true,
| |
− | ["wiki-template-name"] = true,
| |
− | ["wiki-user-name"] = true,
| |
− | ["unbalanced-wikitext"] = true,
| |
− | ["string/line"] = "line",
| |
− | ["string/wiki-page-name"] = "wiki-page-name",
| |
− | ["string/wiki-user-name"] = "wiki-user-name" }
| |
− | }
| |
− | | |
− | | |
− | | |
− | local function Fault( alert )
| |
− | -- Memorize error message
| |
− | -- Parameter:
| |
− | -- alert -- string, error message
| |
− | if Data.scream then
| |
− | Data.scream = string.format( "%s *** %s", Data.scream, alert )
| |
− | else
| |
− | Data.scream = alert
| |
− | end
| |
− | end -- Fault()
| |
− | | |
− | | |
− | | |
− | local function Fetch( ask, allow )
| |
− | -- Fetch module
| |
− | -- Parameter:
| |
− | -- ask -- string, with name
| |
− | -- "/global"
| |
− | -- "JSONutil"
| |
− | -- "Multilingual"
| |
− | -- "Text"
| |
− | -- "WLink"
| |
− | -- allow -- true: no error if unavailable
| |
− | -- Returns table of module
| |
− | -- error: Module not available
| |
− | local sign = ask
| |
− | local r, stem
| |
− | if sign:sub( 1, 1 ) == "/" then
| |
− | sign = TemplateData.frame:getTitle() .. sign
| |
− | else
| |
− | stem = sign
| |
− | sign = "Module:" .. stem
| |
− | end
| |
− | if TemplateData.extern then
| |
− | r = TemplateData.extern[ sign ]
| |
− | else
| |
− | TemplateData.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
| |
− | TemplateData.extern[ sign ] = r
| |
− | elseif not allow then
| |
− | error( string.format( "Fetch(%s) %s", sign, g ), 0 )
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- Fetch()
| |
− | | |
− | | |
− | | |
− | local function Foreign()
| |
− | -- Guess human language
| |
− | -- Returns slang, or not
| |
− | if type( Data.slang ) == "nil" then
| |
− | local Multilingual = Fetch( "Multilingual", true )
| |
− | if Multilingual and
| |
− | type( Multilingual.userLangCode ) == "function" then
| |
− | Data.slang = Multilingual.userLangCode()
| |
− | else
| |
− | Data.slang = mw.language.getContentLanguage():getCode()
| |
− | :lower()
| |
− | end
| |
− | end
| |
− | if Data.slang and
| |
− | mw.ustring.codepoint( Data.slang, 1, 1 ) > 122 then
| |
− | Data.slang = false
| |
− | end
| |
− | return Data.slang
| |
− | end -- Foreign()
| |
− | | |
− | | |
− | | |
− | local function facet( ask, at )
| |
− | -- Find physical position of parameter definition in JSON
| |
− | -- Parameter:
| |
− | -- ask -- string, parameter name
| |
− | -- at -- number, physical position within definition
| |
− | -- Returns number, or nil
| |
− | local seek = string.format( Permit.search,
| |
− | ask:gsub( "%%", "%%%%" )
| |
− | :gsub( "([%-.()+*?^$%[%]])",
| |
− | "%%%1" ) )
| |
− | local i, k, r, slice, source
| |
− | if not Data.jump then
| |
− | Data.jump = Data.source:find( "params", 2 )
| |
− | if Data.jump then
| |
− | Data.jump = Data.jump + 7
| |
− | else
| |
− | Data.jump = 1
| |
− | end
| |
− | end
| |
− | i, k = Data.source:find( seek, at + Data.jump )
| |
− | while i and not r do
| |
− | source = Data.source:sub( k + 1 )
| |
− | slice = source:match( "^%s*\"([^\"]+)\"s*:" )
| |
− | if not slice then
| |
− | slice = source:match( "^%s*'([^']+)'%s*:" )
| |
− | end
| |
− | if ( slice and Permit.params[ slice ] ) or
| |
− | source:match( "^%s*%}" ) then
| |
− | r = k
| |
− | else
| |
− | i, k = Data.source:find( seek, k )
| |
− | end
| |
− | end -- while i
| |
− | return r
| |
− | end -- facet()
| |
− | | |
− | | |
− | | |
− | local function facilities( apply )
| |
− | -- Retrieve details of suggestedvalues
| |
− | -- Parameter:
| |
− | -- apply -- table, with plain or enhanced values
| |
− | -- .suggestedvalues -- table|string|number, or more
| |
− | -- Returns
| |
− | -- 1 -- table, with suggestedvalues
| |
− | -- 2 -- table, with CSS map, or not
| |
− | -- 3 -- string, with class, or not
| |
− | -- 4 -- string, with templatestyles, or not
| |
− | local elements = apply.suggestedvalues
| |
− | local s = type( elements )
| |
− | local r1, r2, r3, r4
| |
− | if s == "table" then
| |
− | local values = elements.values
| |
− | if type( values ) == "table" then
| |
− | r1 = values
| |
− | if type( elements.scroll ) == "string" then
| |
− | r2 = r2 or { }
| |
− | r2.height = apply.scroll
| |
− | r2.overflow = "auto"
| |
− | end
| |
− | if type( elements.minwidth ) == "string" then
| |
− | local s = type( elements.maxcolumns )
| |
− | r2 = r2 or { }
| |
− | r2["column-width"] = elements.minwidth
| |
− | if s == "string" or
| |
− | s == "number" then
| |
− | s = tostring( elements.maxcolumns )
| |
− | r2["column-count"] = s
| |
− | end
| |
− | if type( Config.selMultClm ) == "string" then
| |
− | r3 = Config.selMultClm
| |
− | end
| |
− | if type( Config.stylesMultClm ) == "string" then
| |
− | local src = Config.stylesMultClm .. "/styles.css"
| |
− | r4 = TemplateData.frame
| |
− | :extensionTag( "templatestyles",
| |
− | nil,
| |
− | { src = src } )
| |
− | end
| |
− | end
| |
− | elseif elements and elements ~= "" then
| |
− | r1 = elements
| |
− | end
| |
− | elseif s == "string" then
| |
− | s = mw.text.trim( about )
| |
− | if s ~= "" then
| |
− | r1 = { }
| |
− | table.insert( r1,
| |
− | { code = s } )
| |
− | end
| |
− | elseif s == "number" then
| |
− | r1 = { }
| |
− | table.insert( r1,
| |
− | { code = tostring( elements ) } )
| |
− | end
| |
− | return r1, r2, r3, r4
| |
− | end -- facilities()
| |
− | | |
− | | |
− | | |
− | local function factory( adapt )
| |
− | -- Retrieve localized text from system message
| |
− | -- Parameter:
| |
− | -- adapt -- string, message ID after "templatedata-"
| |
− | -- Returns string, with localized text
| |
− | local o = mw.message.new( "templatedata-" .. adapt )
| |
− | if Foreign() then
| |
− | o:inLanguage( Data.slang )
| |
− | end
| |
− | return o:plain()
| |
− | end -- factory()
| |
− | | |
− | | |
− | | |
− | local function faculty( adjust )
| |
− | -- Test template arg for boolean
| |
− | -- adjust -- string or nil
| |
− | -- Returns boolean
| |
− | local s = type( adjust )
| |
− | local r
| |
− | if s == "string" then
| |
− | r = mw.text.trim( adjust )
| |
− | r = ( r ~= "" and r ~= "0" )
| |
− | elseif s == "boolean" then
| |
− | r = adjust
| |
− | else
| |
− | r = false
| |
− | end
| |
− | return r
| |
− | end -- faculty()
| |
− | | |
− | | |
− | | |
− | local function failures()
| |
− | -- Retrieve error collection and category
| |
− | -- Returns string
| |
− | local r
| |
− | if Data.scream then
| |
− | local e = mw.html.create( "span" )
| |
− | :addClass( "error" )
| |
− | :wikitext( Data.scream )
| |
− | r = tostring( e )
| |
− | mw.addWarning( "'''TemplateData'''<br />" .. Data.scream )
| |
− | if Config.strange then
| |
− | r = string.format( "%s[[category:%s]]",
| |
− | r,
| |
− | Config.strange )
| |
− | end
| |
− | else
| |
− | r = ""
| |
− | end
| |
− | return r
| |
− | end -- failures()
| |
− | | |
− | | |
− | | |
− | local function fair( adjust )
| |
− | -- Reduce text to one line of plain text, or noexport wikitext blocks
| |
− | -- adjust -- string
| |
− | -- Returns string, with adjusted text
| |
− | local f = function ( a )
| |
− | return a:gsub( "%s*\n%s*", " " )
| |
− | :gsub( "%s%s+", " " )
| |
− | end
| |
− | local tags = { { start = "<noexport>",
| |
− | stop = "</noexport>" },
| |
− | { start = "<exportonly>",
| |
− | stop = "</exportonly>",
| |
− | l = false }
| |
− | }
| |
− | local r = adjust
| |
− | local i, j, k, s, tag
| |
− | for m = 1, 2 do
| |
− | tag = tags[ m ]
| |
− | if r:find( tag.start, 1, true ) then
| |
− | s = r
| |
− | r = ""
| |
− | i = 1
| |
− | tag.l = true
| |
− | j, k = s:find( tag.start, i, true )
| |
− | while j do
| |
− | if j > 1 then
| |
− | r = r .. f( s:sub( i, j - 1 ) )
| |
− | end
| |
− | i = k + 1
| |
− | j, k = s:find( tag.stop, i, true )
| |
− | if j then
| |
− | if m == 1 then
| |
− | r = r .. s:sub( i, j - 1 )
| |
− | end
| |
− | i = k + 1
| |
− | j, k = s:find( tag.start, i, true )
| |
− | else
| |
− | Fault( "missing " .. tag.stop )
| |
− | end
| |
− | end -- while j
| |
− | r = r .. s:sub( i )
| |
− | elseif m == 1 then
| |
− | r = f( r )
| |
− | end
| |
− | end -- for m
| |
− | if tags[ 2 ].l then
| |
− | r = r:gsub( "<exportonly>.*</exportonly>", "" )
| |
− | end
| |
− | return r
| |
− | end -- fair()
| |
− | | |
− | | |
− | | |
− | local function fancy( advance, alert )
| |
− | -- Present JSON source
| |
− | -- Parameter:
| |
− | -- advance -- true, for nice
| |
− | -- alert -- true, for visible
| |
− | -- Returns string
| |
− | local r
| |
− | if Data.source then
| |
− | local support = Config.jsonDebug
| |
− | local css
| |
− | if advance then
| |
− | css = { height = "6em",
| |
− | resize = "vertical" }
| |
− | r = { [ 1 ] = "syntaxhighlight",
| |
− | [ 2 ] = Data.source,
| |
− | lang = "json",
| |
− | style = table.concat( css, ";" ) }
| |
− | if alert then
| |
− | r.class( support )
| |
− | end
| |
− | r = TemplateData.frame:callParserFunction( "#tag", r )
| |
− | else
| |
− | css = { [ "font-size" ] = "77%",
| |
− | [ "line-height" ] = "1.35" }
| |
− | if alert then
| |
− | css.resize = "vertical"
| |
− | else
| |
− | css.display = "none"
| |
− | end
| |
− | r = mw.html.create( "pre" )
| |
− | :addClass( support )
| |
− | :css( css )
| |
− | :wikitext( mw.text.encode( Data.source ) )
| |
− | r = tostring( r )
| |
− | end
| |
− | r = "\n".. r
| |
− | else
| |
− | r = ""
| |
− | end
| |
− | return r
| |
− | end -- fancy()
| |
− | | |
− | | |
− | | |
− | local function faraway( alternatives )
| |
− | -- Retrieve best language version from multilingual text
| |
− | -- Parameter:
| |
− | -- alternatives -- table, to be evaluated
| |
− | -- Returns
| |
− | -- 1 -- string, with best match
| |
− | -- 2 -- table of other versions, if any
| |
− | local n = 0
| |
− | local variants = { }
| |
− | local r1, r2
| |
− | for k, v in pairs( alternatives ) do
| |
− | if type( v ) == "string" then
| |
− | v = mw.text.trim( v )
| |
− | if v ~= "" and type( k ) == "string" then
| |
− | k = k:lower()
| |
− | variants[ k ] = v
| |
− | n = n + 1
| |
− | end
| |
− | end
| |
− | end -- for k, v
| |
− | if n > 0 then
| |
− | local Multilingual = Fetch( "Multilingual", true )
| |
− | if Multilingual and
| |
− | type( Multilingual.i18n ) == "function" then
| |
− | local show, slang = Multilingual.i18n( variants )
| |
− | if show then
| |
− | r1 = show
| |
− | variants[ slang ] = nil
| |
− | r2 = variants
| |
− | end
| |
− | end
| |
− | if not r1 then
| |
− | Foreign()
| |
− | for k, v in pairs( variants ) do
| |
− | if n == 1 then
| |
− | r1 = v
| |
− | elseif Data.slang == k then
| |
− | variants[ k ] = nil
| |
− | r1 = v
| |
− | r2 = variants
| |
− | end
| |
− | end -- for k, v
| |
− | end
| |
− | if r2 and Multilingual then
| |
− | for k, v in pairs( r2 ) do
| |
− | if v and not Multilingual.isLang( k, true ) then
| |
− | Fault( string.format( "%s <code>lang=%s</code>",
| |
− | "Invalid",
| |
− | k ) )
| |
− | end
| |
− | end -- for k, v
| |
− | end
| |
− | end
| |
− | return r1, r2
| |
− | end -- faraway()
| |
− | | |
− | | |
− | | |
− | local function fashioned( about, asked, assign )
| |
− | -- Create description head
| |
− | -- Parameter:
| |
− | -- about -- table, supposed to contain description
| |
− | -- asked -- true, if mandatory description
| |
− | -- assign -- <block>, if to be equipped
| |
− | -- Returns <block>, with head, or nil
| |
− | local para = assign or mw.html.create( "div" )
| |
− | local plus, r
| |
− | if about and about.description then
| |
− | if type( about.description ) == "string" then
| |
− | para:wikitext( about.description )
| |
− | else
| |
− | para:wikitext( about.description[ 1 ] )
| |
− | plus = mw.html.create( "ul" )
| |
− | plus:css( "text-align", "left" )
| |
− | for k, v in pairs( about.description[ 2 ] ) do
| |
− | plus:node( mw.html.create( "li" )
| |
− | :node( mw.html.create( "code" )
| |
− | :wikitext( k ) )
| |
− | :node( mw.html.create( "br" ) )
| |
− | :wikitext( fair( v ) ) )
| |
− | end -- for k, v
| |
− | if Config.loudly then
| |
− | plus = mw.html.create( "div" )
| |
− | :css( "background-color",
| |
− | "#" .. Config.debugmultilang )
| |
− | :node( plus )
| |
− | else
| |
− | plus:addClass( "templatedata-maintain" )
| |
− | :css( "display", "none" )
| |
− | end
| |
− | end
| |
− | elseif Config.solo and asked then
| |
− | para:addClass( "error" )
| |
− | :wikitext( Config.solo )
| |
− | Data.less = true
| |
− | else
| |
− | para = false
| |
− | end
| |
− | if para then
| |
− | if plus then
| |
− | r = mw.html.create( "div" )
| |
− | :node( para )
| |
− | :node( plus )
| |
− | else
| |
− | r = para
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- fashioned()
| |
− | | |
− | | |
− | | |
− | local function fatten( access )
| |
− | -- Create table row for sub-headline
| |
− | -- Parameter:
| |
− | -- access -- string, with name
| |
− | -- Returns <tr>
| |
− | local param = Data.tree.params[ access ]
| |
− | local sub, sort = access:match( "(=+)%s*(%S.*)$" )
| |
− | local headline = mw.html.create( string.format( "h%d", #sub ) )
| |
− | local r = mw.html.create( "tr" )
| |
− | local td = mw.html.create( "td" )
| |
− | :attr( "colspan", "5" )
| |
− | :attr( "data-sort-value", "!" .. sort )
| |
− | local s
| |
− | if param.style then
| |
− | s = type( param.style )
| |
− | if s == "table" then
| |
− | td:css( param.style )
| |
− | elseif s == "string" then
| |
− | td:cssText( param.style )
| |
− | end
| |
− | end
| |
− | s = fashioned( param, false, headline )
| |
− | if s then
| |
− | headline = s
| |
− | else
| |
− | headline:wikitext( sort )
| |
− | end
| |
− | td:node( headline )
| |
− | r:node( td )
| |
− | return r
| |
− | end -- fatten()
| |
− | | |
− | | |
− | | |
− | local function fathers()
| |
− | -- Merge params with inherited values
| |
− | local n = 0
| |
− | local p = Data.params
| |
− | local t = Data.tree.params
| |
− | local p2, t2
| |
− | for k, v in pairs( Data.heirs ) do
| |
− | n = n + 1
| |
− | end -- for k, v
| |
− | for i = 1, n do
| |
− | if Data.heirs then
| |
− | for k, v in pairs( Data.heirs ) do
| |
− | if v and not Data.heirs[ v ] then
| |
− | n = n - 1
| |
− | t[ k ].inherits = nil
| |
− | Data.heirs[ k ] = nil
| |
− | p2 = { }
| |
− | t2 = { }
| |
− | if p[ v ] then
| |
− | for k2, v2 in pairs( p[ v ] ) do
| |
− | p2[ k2 ] = v2
| |
− | end -- for k2, v2
| |
− | if p[ k ] then
| |
− | for k2, v2 in pairs( p[ k ] ) do
| |
− | if type( v2 ) ~= "nil" then
| |
− | p2[ k2 ] = v2
| |
− | end
| |
− | end -- for k2, v2
| |
− | end
| |
− | p[ k ] = p2
| |
− | for k2, v2 in pairs( t[ v ] ) do
| |
− | t2[ k2 ] = v2
| |
− | end -- for k2, v2
| |
− | for k2, v2 in pairs( t[ k ] ) do
| |
− | if type( v2 ) ~= "nil" then
| |
− | t2[ k2 ] = v2
| |
− | end
| |
− | end -- for k2, v2
| |
− | t[ k ] = t2
| |
− | else
| |
− | Fault( "No params[] inherits " .. v )
| |
− | end
| |
− | end
| |
− | end -- for k, v
| |
− | end
| |
− | end -- i = 1, n
| |
− | if n > 0 then
| |
− | local s
| |
− | for k, v in pairs( Data.heirs ) do
| |
− | if v then
| |
− | if s then
| |
− | s = string.format( "%s | %s", s, k )
| |
− | else
| |
− | s = "Circular inherits: " .. k
| |
− | end
| |
− | end
| |
− | end -- for k, v
| |
− | Fault( s )
| |
− | end
| |
− | end -- fathers()
| |
− | | |
− | | |
− | | |
− | local function favorize()
| |
− | -- Local customization issues
| |
− | local boole = { ["font-size"] = "125%" }
| |
− | local l, cx = pcall( mw.loadData,
| |
− | TemplateData.frame:getTitle() .. "/config" )
| |
− | local scripting, style
| |
− | TemplateData.ltr = not mw.language.getContentLanguage():isRTL()
| |
− | if TemplateData.ltr then
| |
− | scripting = "left"
| |
− | else
| |
− | scripting = "right"
| |
− | end
| |
− | boole[ "margin-" .. scripting ] = "3em"
| |
− | Permit.boole = { [false] = { css = boole,
| |
− | lead = true,
| |
− | show = "☐" },
| |
− | [true] = { css = boole,
| |
− | lead = true,
| |
− | show = "☑" } }
| |
− | Permit.css = { }
| |
− | for k, v in pairs( Permit.colors ) do
| |
− | if k == "tableheadbg" then
| |
− | k = "tablehead"
| |
− | end
| |
− | if k == "fg" then
| |
− | style = "color"
| |
− | else
| |
− | style = "background-color"
| |
− | end
| |
− | Permit.css[ k ] = { }
| |
− | Permit.css[ k ][ style ] = "#" .. v
| |
− | end -- for k, v
| |
− | if type( cx ) == "table" then
| |
− | local c, s
| |
− | if type( cx.permit ) == "table" then
| |
− | if type( cx.permit.boole ) == "table" then
| |
− | if type( cx.permit.boole[ true ] ) == "table" then
| |
− | Permit.boole[ false ] = cx.permit.boole[ false ]
| |
− | end
| |
− | if type( cx.permit.boole[ true ] ) == "table" then
| |
− | Permit.boole[ true ] = cx.permit.boole[ true ]
| |
− | end
| |
− | end
| |
− | if type( cx.permit.css ) == "table" then
| |
− | for k, v in pairs( cx.permit.css ) do
| |
− | if type( v ) == "table" then
| |
− | Permit.css[ k ] = v
| |
− | end
| |
− | end -- for k, v
| |
− | end
| |
− | end
| |
− | for k, v in pairs( Config.basicCnf ) do
| |
− | s = type( cx[ k ] )
| |
− | if s == "string" or s == "table" then
| |
− | Config[ v ] = cx[ k ]
| |
− | end
| |
− | end -- for k, v
| |
− | end
| |
− | if type( Config.subpage ) ~= "string" or
| |
− | type( Config.suffix ) ~= "string" then
| |
− | local got = mw.message.new( "templatedata-doc-subpage" )
| |
− | local suffix
| |
− | if got:isDisabled() then
| |
− | suffix = "doc"
| |
− | else
| |
− | suffix = got:plain()
| |
− | end
| |
− | if type( Config.subpage ) ~= "string" then
| |
− | Config.subpage = string.format( "/%s$", suffix )
| |
− | end
| |
− | if type( Config.suffix ) ~= "string" then
| |
− | Config.suffix = string.format( "%%s/%s", suffix )
| |
− | end
| |
− | end
| |
− | end -- favorize()
| |
− | | |
− | | |
− | | |
− | local function feasible( all, at, about )
| |
− | -- Deal with suggestedvalues within parameter
| |
− | -- Parameter:
| |
− | -- all -- parameter details
| |
− | -- .default
| |
− | -- .type
| |
− | -- at -- string, with parameter name
| |
− | -- about -- suggestedvalues -- table,
| |
− | -- value and possibly description
| |
− | -- table may have elements:
| |
− | -- .code -- mandatory
| |
− | -- .label -- table|string
| |
− | -- .support -- table|string
| |
− | -- .icon -- string
| |
− | -- .class -- table|string
| |
− | -- .css -- table
| |
− | -- .style -- string
| |
− | -- .less -- true: suppress code
| |
− | -- Returns
| |
− | -- 1: mw.html object <ul>
| |
− | -- 2: sequence table with values, or nil
| |
− | local h = { }
| |
− | local e, r1, r2, s, v
| |
− | if #about > 0 then
| |
− | for i = 1, #about do
| |
− | e = about[ i ]
| |
− | s = type( e )
| |
− | if s == "table" then
| |
− | if type( e.code ) == "string" then
| |
− | s = mw.text.trim( e.code )
| |
− | if s == "" then
| |
− | e = nil
| |
− | else
| |
− | e.code = s
| |
− | end
| |
− | else
| |
− | e = nil
| |
− | s = string.format( "params.%s.%s[%d] %s",
| |
− | at,
| |
− | "suggestedvalues",
| |
− | i,
| |
− | "MISSING 'code:'" )
| |
− | end
| |
− | elseif s == "string" then
| |
− | s = mw.text.trim( e )
| |
− | if s == "" then
| |
− | e = nil
| |
− | s = string.format( "params.%s.%s[%d] EMPTY",
| |
− | at, "suggestedvalues", i )
| |
− | Fault( s )
| |
− | else
| |
− | e = { code = s }
| |
− | end
| |
− | elseif s == "number" then
| |
− | e = { code = tostring( e ) }
| |
− | else
| |
− | s = string.format( "params.%s.%s[%d] INVALID",
| |
− | at, "suggestedvalues", i )
| |
− | Fault( s )
| |
− | e = false
| |
− | end
| |
− | if e then
| |
− | v = v or { }
| |
− | table.insert( v, e )
| |
− | if h[ e.code ] then
| |
− | s = string.format( "params.%s.%s REPEATED %s",
| |
− | at,
| |
− | "suggestedvalues",
| |
− | e.code )
| |
− | Fault( s )
| |
− | else
| |
− | h[ e.code ] = true
| |
− | end
| |
− | end
| |
− | end -- for i
| |
− | else
| |
− | Fault( string.format( "params.%s.suggestedvalues %s",
| |
− | at, "NOT AN ARRAY" ) )
| |
− | end
| |
− | if v then
| |
− | local code, d, k, less, story, swift, t, u
| |
− | r1 = mw.html.create( "ul" )
| |
− | r2 = { }
| |
− | for i = 1, #v do
| |
− | u = mw.html.create( "li" )
| |
− | e = v[ i ]
| |
− | table.insert( r2, e.code )
| |
− | story = false
| |
− | less = ( e.less == true )
| |
− | if not less then
| |
− | swift = e.code
| |
− | if e.support then
| |
− | local scream, support
| |
− | s = type( e.support )
| |
− | if s == "string" then
| |
− | support = e.support
| |
− | elseif s == "table" then
| |
− | support = faraway( e.support )
| |
− | else
| |
− | scream = "INVALID"
| |
− | end
| |
− | if support then
| |
− | s = mw.text.trim( support )
| |
− | if s == "" then
| |
− | scream = "EMPTY"
| |
− | elseif s:find( "[%[%]|%<%>]" ) then
| |
− | scream = "BAD PAGE"
| |
− | else
| |
− | support = s
| |
− | end
| |
− | end
| |
− | if scream then
| |
− | s = string.format( "params.%s.%s[%d].support %s",
| |
− | at,
| |
− | "suggestedvalues",
| |
− | i,
| |
− | scream )
| |
− | Fault( s )
| |
− | else
| |
− | swift = string.format( "[[:%s|%s]]",
| |
− | support, swift )
| |
− | end
| |
− | end
| |
− | if all.type:sub( 1, 5 ) == "wiki-" and
| |
− | swift == e.code then
| |
− | local rooms = { file = 6,
| |
− | temp = 10,
| |
− | user = 2 }
| |
− | local ns = rooms[ all.type:sub( 6, 9 ) ] or 0
| |
− | t = mw.title.makeTitle( ns, swift )
| |
− | if t and t.exists then
| |
− | swift = string.format( "[[:%s|%s]]",
| |
− | t.prefixedText, swift )
| |
− | end
| |
− | end
| |
− | if e.code == all.default then
| |
− | k = 800
| |
− | else
| |
− | k = 300
| |
− | end
| |
− | code = mw.html.create( "code" )
| |
− | :css( "font-weight", tostring( k ) )
| |
− | :css( "white-space", "nowrap" )
| |
− | :wikitext( swift )
| |
− | u:node( code )
| |
− | end
| |
− | if e.class then
| |
− | s = type( e.class )
| |
− | if s == "string" then
| |
− | u:addClass( e.class )
| |
− | elseif s == "table" then
| |
− | for k, s in pairs( e.class ) do
| |
− | u:addClass( s )
| |
− | end -- for k, s
| |
− | else
| |
− | s = string.format( "params.%s.%s[%d].class INVALID",
| |
− | at, "suggestedvalues", i )
| |
− | Fault( s )
| |
− | end
| |
− | end
| |
− | if e.css then
| |
− | if type( e.css ) == "table" then
| |
− | u:css( e.css )
| |
− | else
| |
− | s = string.format( "params.%s.%s[%d].css INVALID",
| |
− | at, "suggestedvalues", i )
| |
− | Fault( s )
| |
− | end
| |
− | end
| |
− | if e.style then
| |
− | if type( e.style ) == "string" then
| |
− | u:cssText( e.style )
| |
− | else
| |
− | s = string.format( "params.%s.%s[%d].style INVALID",
| |
− | at, "suggestedvalues", i )
| |
− | Fault( s )
| |
− | end
| |
− | end
| |
− | if all.type == "wiki-file-name" and not e.icon then
| |
− | e.icon = e.code
| |
− | end
| |
− | if e.label then
| |
− | s = type( e.label )
| |
− | if s == "string" then
| |
− | s = mw.text.trim( e.label )
| |
− | if s == "" then
| |
− | s = string.format( "params.%s.%s[%d].label %s",
| |
− | at,
| |
− | "suggestedvalues",
| |
− | i,
| |
− | "EMPTY" )
| |
− | Fault( s )
| |
− | else
| |
− | story = s
| |
− | end
| |
− | elseif s == "table" then
| |
− | story = faraway( e.label )
| |
− | else
| |
− | s = string.format( "params.%s.%s[%d].label INVALID",
| |
− | at, "suggestedvalues", i )
| |
− | Fault( s )
| |
− | end
| |
− | end
| |
− | s = false
| |
− | if type( e.icon ) == "string" then
| |
− | t = mw.title.makeTitle( 6, e.icon )
| |
− | if t and t.file.exists then
| |
− | local g = mw.html.create( "span" )
| |
− | s = string.format( "[[%s|16px]]", t.prefixedText )
| |
− | g:attr( "role", "presentation" )
| |
− | :wikitext( s )
| |
− | s = tostring( g )
| |
− | end
| |
− | end
| |
− | if not s and not less and e.label then
| |
− | s = mw.ustring.char( 0x2013 )
| |
− | end
| |
− | if s then
| |
− | d = mw.html.create( "span" )
| |
− | :wikitext( s )
| |
− | if TemplateData.ltr then
| |
− | if not less then
| |
− | d:css( "margin-left", "0.5em" )
| |
− | end
| |
− | if story then
| |
− | d:css( "margin-right", "0.5em" )
| |
− | end
| |
− | else
| |
− | if not less then
| |
− | d:css( "margin-right", "0.5em" )
| |
− | end
| |
− | if story then
| |
− | d:css( "margin-left", "0.5em" )
| |
− | end
| |
− | end
| |
− | u:node( d )
| |
− | end
| |
− | if story then
| |
− | u:wikitext( story )
| |
− | end
| |
− | r1:newline()
| |
− | :node( u )
| |
− | end -- for i
| |
− | end
| |
− | if not r1 and v ~= false then
| |
− | Fault( string.format( "params.%s.suggestedvalues INVALID", at ) )
| |
− | r1 = mw.html.create( "code" )
| |
− | :addClass( "error" )
| |
− | :wikitext( "INVALID" )
| |
− | end
| |
− | return r1, r2
| |
− | end -- feasible()
| |
− | | |
− | | |
− | | |
− | local function feat()
| |
− | -- Check and store parameter sequence
| |
− | if Data.source then
| |
− | local i = 0
| |
− | local s
| |
− | for k, v in pairs( Data.tree.params ) do
| |
− | if i == 0 then
| |
− | Data.order = { }
| |
− | i = 1
| |
− | s = k
| |
− | else
| |
− | i = 2
| |
− | break -- for k, v
| |
− | end
| |
− | end -- for k, v
| |
− | if i > 1 then
| |
− | local pointers = { }
| |
− | local points = { }
| |
− | local given = { }
| |
− | for k, v in pairs( Data.tree.params ) do
| |
− | i = facet( k, 1 )
| |
− | if type( v ) == "table" then
| |
− | if type( v.label ) == "string" then
| |
− | s = mw.text.trim( v.label )
| |
− | if s == "" then
| |
− | s = k
| |
− | end
| |
− | else
| |
− | s = k
| |
− | end
| |
− | if given[ s ] then
| |
− | if given[ s ] == 1 then
| |
− | local scream = "Parameter label '%s' detected multiple times"
| |
− | Fault( string.format( scream, s ) )
| |
− | given[ s ] = 2
| |
− | end
| |
− | else
| |
− | given[ s ] = 1
| |
− | end
| |
− | end
| |
− | if i then
| |
− | table.insert( points, i )
| |
− | pointers[ i ] = k
| |
− | i = facet( k, i )
| |
− | if i then
| |
− | s = "Parameter '%s' detected twice"
| |
− | Fault( string.format( s, k ) )
| |
− | end
| |
− | else
| |
− | s = "Parameter '%s' not detected"
| |
− | Fault( string.format( s, k ) )
| |
− | end
| |
− | end -- for k, v
| |
− | table.sort( points )
| |
− | for i = 1, #points do
| |
− | table.insert( Data.order, pointers[ points[ i ] ] )
| |
− | end -- i = 1, #points
| |
− | elseif s then
| |
− | table.insert( Data.order, s )
| |
− | end
| |
− | end
| |
− | end -- feat()
| |
− | | |
− | | |
− | | |
− | local function feature( access )
| |
− | -- Create table row for parameter, check and display violations
| |
− | -- Parameter:
| |
− | -- access -- string, with name
| |
− | -- Returns <tr>
| |
− | local mode, s, status
| |
− | local fine = function ( a )
| |
− | s = mw.text.trim( a )
| |
− | return a == s and
| |
− | a ~= "" and
| |
− | not a:find( "%|=\n" ) and
| |
− | not a:find( "%s%s" )
| |
− | end
| |
− | local begin = mw.html.create( "td" )
| |
− | local code = mw.html.create( "code" )
| |
− | local desc = mw.html.create( "td" )
| |
− | local eager = mw.html.create( "td" )
| |
− | local legal = true
| |
− | local param = Data.tree.params[ access ]
| |
− | local ranking = { "required", "suggested", "optional", "deprecated" }
| |
− | local r = mw.html.create( "tr" )
| |
− | local styles = "mw-templatedata-doc-param-"
| |
− | local sort, typed
| |
− | | |
− | for k, v in pairs( param ) do
| |
− | if v == "" then
| |
− | param[ k ] = false
| |
− | end
| |
− | end -- for k, v
| |
− | | |
− | -- label
| |
− | sort = param.label or access
| |
− | if sort:match( "^%d+$" ) then
| |
− | begin:attr( "data-sort-value",
| |
− | string.format( "%05d", tonumber( sort ) ) )
| |
− | end
| |
− | begin:css( "font-weight", "bold" )
| |
− | :wikitext( sort )
| |
− | | |
− | -- name and aliases
| |
− | code:css( "font-size", "92%" )
| |
− | :css( "white-space", "nowrap" )
| |
− | :wikitext( access )
| |
− | if not fine( access ) then
| |
− | code:addClass( "error" )
| |
− | Fault( string.format( "Bad ID params.<code>%s</code>", access ) )
| |
− | legal = false
| |
− | begin:attr( "data-sort-value", " " .. sort )
| |
− | end
| |
− | code = mw.html.create( "td" )
| |
− | :addClass( styles .. "name" )
| |
− | :node( code )
| |
− | if access:match( "^%d+$" ) then
| |
− | code:attr( "data-sort-value",
| |
− | string.format( "%05d", tonumber( access ) ) )
| |
− | end
| |
− | if type( param.aliases ) == "table" then
| |
− | local lapsus, syn
| |
− | for k, v in pairs( param.aliases ) do
| |
− | code:tag( "br" )
| |
− | if type( v ) == "string" then
| |
− | if not fine( v ) then
| |
− | lapsus = true
| |
− | code:node( mw.html.create( "span" )
| |
− | :addClass( "error" )
| |
− | :css( "font-style", "italic" )
| |
− | :wikitext( "string" ) )
| |
− | :wikitext( s )
| |
− | else
| |
− | syn = mw.html.create( "span" )
| |
− | :addClass( styles .. "alias" )
| |
− | :css( "white-space", "nowrap" )
| |
− | :wikitext( s )
| |
− | code:node( syn )
| |
− | end
| |
− | else
| |
− | lapsus = true
| |
− | code:node( mw.html.create( "code" )
| |
− | :addClass( "error" )
| |
− | :wikitext( type( v ) ) )
| |
− | end
| |
− | end -- for k, v
| |
− | if lapsus then
| |
− | s = string.format( "params.<code>%s</code>.aliases", access )
| |
− | Fault( factory( "invalid-value" ):gsub( "$1", s ) )
| |
− | legal = false
| |
− | end
| |
− | end
| |
− | | |
− | -- description etc.
| |
− | s = fashioned( param )
| |
− | if s then
| |
− | desc:node( s )
| |
− | end
| |
− | if param.style then
| |
− | s = type( param.style )
| |
− | if s == "table" then
| |
− | desc:css( param.style )
| |
− | elseif s == "string" then
| |
− | desc:cssText( param.style )
| |
− | end
| |
− | end
| |
− | if param.suggestedvalues or
| |
− | param.default or
| |
− | param.example or
| |
− | param.autovalue then
| |
− | local details = { "suggestedvalues",
| |
− | "default",
| |
− | "example",
| |
− | "autovalue" }
| |
− | local dl = mw.html.create( "dl" )
| |
− | local dd, section, show
| |
− | for i = 1, #details do
| |
− | s = details[ i ]
| |
− | show = param[ s ]
| |
− | if show then
| |
− | dd = mw.html.create( "dd" )
| |
− | section = factory( "doc-param-" .. s )
| |
− | if param.type == "boolean" and
| |
− | ( show == "0" or show == "1" ) then
| |
− | local boole = Permit.boole[ ( show == "1" ) ]
| |
− | if boole.lead == true then
| |
− | dd:node( mw.html.create( "code" )
| |
− | :wikitext( show ) )
| |
− | :wikitext( " " )
| |
− | end
| |
− | if type( boole.show ) == "string" then
| |
− | local v = mw.html.create( "span" )
| |
− | :attr( "aria-hidden", "true" )
| |
− | :wikitext( boole.show )
| |
− | if boole.css then
| |
− | v:css( boole.css )
| |
− | end
| |
− | dd:node( v )
| |
− | end
| |
− | if type( boole.suffix ) == "string" then
| |
− | dd:wikitext( boole.suffix )
| |
− | end
| |
− | if boole.lead == false then
| |
− | dd:wikitext( " " )
| |
− | :node( mw.html.create( "code" )
| |
− | :wikitext( show ) )
| |
− | end
| |
− | elseif s == "suggestedvalues" then
| |
− | local v, css, class, ts = facilities( param )
| |
− | if v then
| |
− | local ul
| |
− | ul, v = feasible( param, access, v )
| |
− | if v then
| |
− | dd:newline()
| |
− | :node( ul )
| |
− | if css then
| |
− | dd:css( css )
| |
− | if class then
| |
− | dd:addClass( class )
| |
− | end
| |
− | if ts then
| |
− | dd:newline()
| |
− | dd:node( ts )
| |
− | end
| |
− | end
| |
− | Data.params[ access ].suggestedvalues = v
| |
− | end
| |
− | end
| |
− | else
| |
− | dd:wikitext( show )
| |
− | end
| |
− | dl:node( mw.html.create( "dt" )
| |
− | :wikitext( section ) )
| |
− | :node( dd )
| |
− | end
| |
− | end -- i = 1, #details
| |
− | desc:node( dl )
| |
− | end
| |
− | | |
− | -- type
| |
− | if type( param.type ) == "string" then
| |
− | param.type = mw.text.trim( param.type )
| |
− | if param.type == "" then
| |
− | param.type = false
| |
− | end
| |
− | end
| |
− | if param.type then
| |
− | s = Permit.types[ param.type ]
| |
− | typed = mw.html.create( "td" )
| |
− | :addClass( styles .. "type" )
| |
− | if s then
| |
− | if s == "string" then
| |
− | Data.params[ access ].type = s
| |
− | typed:wikitext( factory( "doc-param-type-" .. s ) )
| |
− | :tag( "br" )
| |
− | typed:node( mw.html.create( "span" )
| |
− | :addClass( "error" )
| |
− | :wikitext( param.type ) )
| |
− | Data.lasting = true
| |
− | else
| |
− | local support = Config[ "support4" .. param.type ]
| |
− | s = factory( "doc-param-type-" .. param.type )
| |
− | if support then
| |
− | s = string.format( "[[%s|%s]]", support, s )
| |
− | end
| |
− | typed:wikitext( s )
| |
− | end
| |
− | else
| |
− | Data.params[ access ].type = "unknown"
| |
− | typed:addClass( "error" )
| |
− | :wikitext( "INVALID" )
| |
− | s = string.format( "params.<code>%s</code>.type", access )
| |
− | Fault( factory( "invalid-value" ):gsub( "$1", s ) )
| |
− | legal = false
| |
− | end
| |
− | else
| |
− | typed = mw.html.create( "td" )
| |
− | :wikitext( factory( "doc-param-type-unknown" ) )
| |
− | Data.params[ access ].type = "unknown"
| |
− | if param.default then
| |
− | Data.params[ access ].default = nil
| |
− | Fault( "Default value requires <code>type</code>" )
| |
− | legal = false
| |
− | end
| |
− | end
| |
− | typed:addClass( "navigation-not-searchable" )
| |
− | -- status
| |
− | if param.required then
| |
− | mode = 1
| |
− | if param.autovalue then
| |
− | Fault( string.format( "autovalued <code>%s</code> required",
| |
− | access ) )
| |
− | legal = false
| |
− | end
| |
− | if param.default then
| |
− | Fault( string.format( "Defaulted <code>%s</code> required",
| |
− | access ) )
| |
− | legal = false
| |
− | end
| |
− | if param.deprecated then
| |
− | Fault( string.format( "Required deprecated <code>%s</code>",
| |
− | access ) )
| |
− | legal = false
| |
− | end
| |
− | elseif param.deprecated then
| |
− | mode = 4
| |
− | elseif param.suggested then
| |
− | mode = 2
| |
− | else
| |
− | mode = 3
| |
− | end
| |
− | status = ranking[ mode ]
| |
− | ranking = factory( "doc-param-status-" .. status )
| |
− | if mode == 1 or mode == 4 then
| |
− | ranking = mw.html.create( "span" )
| |
− | :css( "font-weight", "bold" )
| |
− | :wikitext( ranking )
| |
− | if type( param.deprecated ) == "string" then
| |
− | ranking:tag( "br" )
| |
− | ranking:wikitext( param.deprecated )
| |
− | end
| |
− | if param.suggested and mode == 4 then
| |
− | s = string.format( "Suggesting deprecated <code>%s</code>",
| |
− | access )
| |
− | Fault( s )
| |
− | legal = false
| |
− | end
| |
− | end
| |
− | eager:attr( "data-sort-value", tostring( mode ) )
| |
− | :node( ranking )
| |
− | :addClass( string.format( "%sstatus-%s %s",
| |
− | styles, status,
| |
− | "navigation-not-searchable" ) )
| |
− | | |
− | -- <tr>
| |
− | r:attr( "id", "templatedata:" .. mw.uri.anchorEncode( access ) )
| |
− | :css( Permit.css[ status ] )
| |
− | :addClass( styles .. status )
| |
− | :node( begin )
| |
− | :node( code )
| |
− | :node( desc )
| |
− | :node( typed )
| |
− | :node( eager )
| |
− | :newline()
| |
− | if not legal then
| |
− | r:css( "border", "#FF0000 3px solid" )
| |
− | end
| |
− | return r
| |
− | end -- feature()
| |
− | | |
− | | |
− | | |
− | local function features()
| |
− | -- Create <table> for parameters
| |
− | -- Returns <table>, or nil
| |
− | local r
| |
− | if Data.tree and Data.tree.params then
| |
− | local tbl = mw.html.create( "table" )
| |
− | local tr = mw.html.create( "tr" )
| |
− | feat()
| |
− | if Data.order and #Data.order > 1 then
| |
− | tbl:addClass( "sortable" )
| |
− | end
| |
− | if type( Config.classTable ) == "table" then
| |
− | for k, v in pairs( Config.classTable ) do
| |
− | tbl:addClass( v )
| |
− | end -- for k, v
| |
− | end
| |
− | if type( Config.cssTable ) == "table" then
| |
− | tbl:css( Config.cssTable )
| |
− | end
| |
− | tr:addClass( "navigation-not-searchable" )
| |
− | :node( mw.html.create( "th" )
| |
− | :attr( "colspan", "2" )
| |
− | :css( Permit.css.tablehead )
| |
− | :wikitext( factory( "doc-param-name" ) ) )
| |
− | :node( mw.html.create( "th" )
| |
− | :css( Permit.css.tablehead )
| |
− | :wikitext( factory( "doc-param-desc" ) ) )
| |
− | :node( mw.html.create( "th" )
| |
− | :css( Permit.css.tablehead )
| |
− | :wikitext( factory( "doc-param-type" ) ) )
| |
− | :node( mw.html.create( "th" )
| |
− | :css( Permit.css.tablehead )
| |
− | :wikitext( factory( "doc-param-status" ) ) )
| |
− | tbl:newline()
| |
− | -- :node( mw.html.create( "thead" )
| |
− | :node( tr )
| |
− | -- )
| |
− | :newline()
| |
− | if Data.order then
| |
− | local leave, s
| |
− | for i = 1, #Data.order do
| |
− | s = Data.order[ i ]
| |
− | if s:sub( 1, 1 ) == "=" then
| |
− | leave = true
| |
− | tbl:node( fatten( s ) )
| |
− | Data.order[ i ] = false
| |
− | elseif s:match( "[=|]" ) then
| |
− | Fault( string.format( "Bad param <code>%s</code>",
| |
− | s ) )
| |
− | else
| |
− | tbl:node( feature( s ) )
| |
− | end
| |
− | end -- for i = 1, #Data.order
| |
− | if leave then
| |
− | for i = #Data.order, 1, -1 do
| |
− | if not Data.order[ i ] then
| |
− | table.remove( Data.order, i )
| |
− | end
| |
− | end -- for i = #Data.order, 1, -1
| |
− | end
| |
− | Data.tag.paramOrder = Data.order
| |
− | end
| |
− | if Config.cssTabWrap or Data.scroll then
| |
− | r = mw.html.create( "div" )
| |
− | if type( Config.cssTabWrap ) == "table" then
| |
− | r:css( Config.cssTabWrap )
| |
− | elseif type( Config.cssTabWrap ) == "string" then
| |
− | -- deprecated
| |
− | r:cssText( Config.cssTabWrap )
| |
− | end
| |
− | if Data.scroll then
| |
− | r:css( "height", Data.scroll )
| |
− | :css( "overflow", "auto" )
| |
− | end
| |
− | r:node( tbl )
| |
− | else
| |
− | r = tbl
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- features()
| |
− | | |
− | | |
− | | |
− | local function fellow( any, assigned, at )
| |
− | -- Check sets[] parameter and issue error message, if necessary
| |
− | -- Parameter:
| |
− | -- any -- should be number
| |
− | -- assigned -- parameter name
| |
− | -- at -- number, of set
| |
− | local s
| |
− | if type( any ) ~= "number" then
| |
− | s = "<code>sets[%d].params[%s]</code>??"
| |
− | Fault( string.format( s,
| |
− | at,
| |
− | mw.text.nowiki( tostring( any ) ) ) )
| |
− | elseif type( assigned ) == "string" then
| |
− | if not Data.got.params[ assigned ] then
| |
− | s = "<code>sets[%d].params %s</code> is undefined"
| |
− | Fault( string.format( s, at, assigned ) )
| |
− | end
| |
− | else
| |
− | s = "<code>sets[%d].params[%d] = %s</code>??"
| |
− | Fault( string.format( s, k, type( assigned ) ) )
| |
− | end
| |
− | end -- fellow()
| |
− | | |
− | | |
− | | |
− | local function fellows()
| |
− | -- Check sets[] and issue error message, if necessary
| |
− | local s
| |
− | if type( Data.got.sets ) == "table" then
| |
− | if type( Data.got.params ) == "table" then
| |
− | for k, v in pairs( Data.got.sets ) do
| |
− | if type( k ) == "number" then
| |
− | if type( v ) == "table" then
| |
− | for ek, ev in pairs( v ) do
| |
− | if ek == "label" then
| |
− | s = type( ev )
| |
− | if s ~= "string" and
| |
− | s ~= "table" then
| |
− | s = "<code>sets[%d].label</code>??"
| |
− | Fault( string.format( s, k ) )
| |
− | end
| |
− | elseif ek == "params" and
| |
− | type( ev ) == "table" then
| |
− | for pk, pv in pairs( ev ) do
| |
− | fellow( pk, pv, k )
| |
− | end -- for pk, pv
| |
− | else
| |
− | ek = mw.text.nowiki( tostring( ek ) )
| |
− | s = "<code>sets[%d][%s]</code>??"
| |
− | Fault( string.format( s, k, ek ) )
| |
− | end
| |
− | end -- for ek, ev
| |
− | else
| |
− | k = mw.text.nowiki( tostring( k ) )
| |
− | v = mw.text.nowiki( tostring( v ) )
| |
− | s = string.format( "<code>sets[%s][%s]</code>??",
| |
− | k, v )
| |
− | Fault( s )
| |
− | end
| |
− | else
| |
− | k = mw.text.nowiki( tostring( k ) )
| |
− | s = string.format( "<code>sets[%s]</code> ?????", k )
| |
− | Fault( s )
| |
− | end
| |
− | end -- for k, v
| |
− | else
| |
− | s = "<code>params</code> required for <code>sets</code>"
| |
− | Fault( s )
| |
− | end
| |
− | else
| |
− | s = "<code>sets</code> needs to be of <code>object</code> type"
| |
− | Fault( s )
| |
− | end
| |
− | end -- fellows()
| |
− | | |
− | | |
− | | |
− | local function finalize( advance )
| |
− | -- Wrap presentation into frame
| |
− | -- Parameter:
| |
− | -- advance -- true, for nice
| |
− | -- Returns string
| |
− | local r, lapsus
| |
− | if Data.div then
| |
− | r = tostring( Data.div )
| |
− | elseif Data.strip then
| |
− | r = Data.strip
| |
− | else
| |
− | lapsus = true
| |
− | r = ""
| |
− | end
| |
− | r = r .. failures()
| |
− | if Data.source then
| |
− | local live = ( advance or lapsus )
| |
− | if not live then
| |
− | live = TemplateData.frame:preprocess( "{{REVISIONID}}" )
| |
− | live = ( live == "" )
| |
− | end
| |
− | if live then
| |
− | r = r .. fancy( advance, lapsus )
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- finalize()
| |
− | | |
− | | |
− | | |
− | local function find()
| |
− | -- Find JSON data within page source (title)
| |
− | -- Returns string, or nil
| |
− | local s = Data.title:getContent()
| |
− | local i, j = s:find( "<templatedata>", 1, true )
| |
− | local r
| |
− | if i then
| |
− | local k = s:find( "</templatedata>", j, true )
| |
− | if k then
| |
− | r = mw.text.trim( s:sub( j + 1, k - 1 ) )
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- find()
| |
− | | |
− | | |
− | | |
− | local function flat( adjust )
| |
− | -- Remove formatting from text string for VE
| |
− | -- Parameter:
| |
− | -- arglist -- string, to be stripped, or nil
| |
− | -- Returns string, or nil
| |
− | local r
| |
− | if adjust then
| |
− | r = adjust:gsub( "\n", " " )
| |
− | if r:find( "<noexport>", 1, true ) then
| |
− | r = r:gsub( "<noexport>.*</noexport>", "" )
| |
− | end
| |
− | if r:find( "<exportonly>", 1, true ) then
| |
− | r = r:gsub( "</?exportonly>", "" )
| |
− | end
| |
− | if r:find( "''", 1, true ) then
| |
− | r = r:gsub( "'''", "" ):gsub( "''", "" )
| |
− | end
| |
− | if r:find( "<", 1, true ) then
| |
− | local Text = Fetch( "Text" )
| |
− | r = Text.getPlain( r:gsub( "<br */?>", "\r\n" ) )
| |
− | end
| |
− | if r:find( "[", 1, true ) then
| |
− | local WLink = Fetch( "WLink" )
| |
− | if WLink.isBracketedURL( r ) then
| |
− | r = r:gsub( "%[([hf]tt?ps?://%S+) [^%]]+%]", "%1" )
| |
− | end
| |
− | r = WLink.getPlain( r )
| |
− | end
| |
− | if r:find( "&", 1, true ) then
| |
− | r = mw.text.decode( r )
| |
− | if r:find( "­", 1, true ) then
| |
− | r = r:gsub( "­", "" )
| |
− | end
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- flat()
| |
− | | |
− | | |
− | | |
− | local function flush()
| |
− | -- JSON encode narrowed input; obey unnamed (numerical) parameters
| |
− | -- Returns <templatedata> JSON string
| |
− | local r
| |
− | if Data.tag then
| |
− | r = mw.text.jsonEncode( Data.tag ):gsub( "%}$", "," )
| |
− | else
| |
− | r = "{"
| |
− | end
| |
− | r = r .. "\n\"params\":{"
| |
− | if Data.order then
| |
− | local sep = ""
| |
− | local s
| |
− | for i = 1, #Data.order do
| |
− | s = Data.order[ i ]
| |
− | r = string.format( "%s%s\n%s:%s",
| |
− | r,
| |
− | sep,
| |
− | mw.text.jsonEncode( s ),
| |
− | mw.text.jsonEncode( Data.params[ s ] ) )
| |
− | sep = ",\n"
| |
− | end -- for i = 1, #Data.order
| |
− | end
| |
− | r = r .. "\n}\n}"
| |
− | return r
| |
− | end -- flush()
| |
− | | |
− | | |
− | | |
− | local function focus( access )
| |
− | -- Check components; focus multilingual description, build trees
| |
− | -- Parameter:
| |
− | -- access -- string, name of parameter, nil for root
| |
− | local f = function ( a, at )
| |
− | local r
| |
− | if at then
| |
− | r = string.format( "<code>params.%s</code>", at )
| |
− | else
| |
− | r = "''root''"
| |
− | end
| |
− | if a then
| |
− | r = string.format( "%s<code>.%s</code>", r, a )
| |
− | end
| |
− | return r
| |
− | end
| |
− | local parent
| |
− | if access then
| |
− | parent = Data.got.params[ access ]
| |
− | else
| |
− | parent = Data.got
| |
− | end
| |
− | if type( parent ) == "table" then
| |
− | local elem, got, permit, s, scope, slot, tag, target
| |
− | if access then
| |
− | permit = Permit.params
| |
− | if type( access ) == "number" then
| |
− | slot = tostring( access )
| |
− | else
| |
− | slot = access
| |
− | end
| |
− | else
| |
− | permit = Permit.root
| |
− | end
| |
− | for k, v in pairs( parent ) do
| |
− | scope = permit[ k ]
| |
− | if scope then
| |
− | s = type( v )
| |
− | if s == "string" and k ~= "format" then
| |
− | v = mw.text.trim( v )
| |
− | end
| |
− | if scope:find( s, 1, true ) then
| |
− | if scope:find( "I18N", 1, true ) then
| |
− | if s == "string" then
| |
− | elem = fair( v )
| |
− | elseif s == "table" then
| |
− | local translated
| |
− | v, translated = faraway( v )
| |
− | if v then
| |
− | if translated and
| |
− | k == "description" then
| |
− | elem = { [ 1 ] = fair( v ),
| |
− | [ 2 ] = translated }
| |
− | else
| |
− | elem = fair( v )
| |
− | end
| |
− | else
| |
− | elem = false
| |
− | end
| |
− | end
| |
− | if type( v ) == "string" then
| |
− | if k == "deprecated" then
| |
− | if v == "1" then
| |
− | v = true
| |
− | elseif v == "0" then
| |
− | v = false
| |
− | end
| |
− | elem = v
| |
− | elseif scope:find( "nowiki", 1, true ) then
| |
− | elem = mw.text.nowiki( v )
| |
− | elem = elem:gsub( " \n", "<br>" )
| |
− | v = v:gsub( string.char( 13 ), "" )
| |
− | else
| |
− | v = flat( v )
| |
− | end
| |
− | elseif s == "boolean" then
| |
− | if scope:find( "boolean", 1, true ) then
| |
− | elem = v
| |
− | else
| |
− | s = "Type <code>boolean</code> bad for "
| |
− | .. f( k, slot )
| |
− | Fault( s )
| |
− | end
| |
− | end
| |
− | else
| |
− | if k == "params" and not access then
| |
− | v = nil
| |
− | elem = nil
| |
− | elseif k == "format" and not access then
| |
− | elem = mw.text.decode( v )
| |
− | v = nil
| |
− | elseif k == "inherits" then
| |
− | elem = v
| |
− | if not Data.heirs then
| |
− | Data.heirs = { }
| |
− | end
| |
− | Data.heirs[ slot ] = v
| |
− | v = nil
| |
− | elseif k == "style" then
| |
− | elem = v
| |
− | v = nil
| |
− | elseif s == "string" then
| |
− | v = mw.text.nowiki( v )
| |
− | elem = v
| |
− | else
| |
− | elem = v
| |
− | end
| |
− | end
| |
− | if type( elem ) ~= "nil" then
| |
− | if not target then
| |
− | if access then
| |
− | if not Data.tree.params then
| |
− | Data.tree.params = { }
| |
− | end
| |
− | Data.tree.params[ slot ] = { }
| |
− | target = Data.tree.params[ slot ]
| |
− | else
| |
− | Data.tree = { }
| |
− | target = Data.tree
| |
− | end
| |
− | end
| |
− | target[ k ] = elem
| |
− | elem = false
| |
− | end
| |
− | if type( v ) ~= "nil" then
| |
− | if not tag then
| |
− | if access then
| |
− | if type( v ) == "string" and
| |
− | v.sub( 1, 1 ) == "=" then
| |
− | v = nil
| |
− | else
| |
− | if not Data.params then
| |
− | Data.params = { }
| |
− | end
| |
− | Data.params[ slot ] = { }
| |
− | tag = Data.params[ slot ]
| |
− | end
| |
− | else
| |
− | Data.tag = { }
| |
− | tag = Data.tag
| |
− | end
| |
− | end
| |
− | if type( v ) ~= "nil" and
| |
− | k ~= "suggestedvalues" then
| |
− | tag[ k ] = v
| |
− | end
| |
− | end
| |
− | else
| |
− | s = string.format( "Type <code>%s</code> bad for %s",
| |
− | scope, f( k, slot ) )
| |
− | Fault( s )
| |
− | end
| |
− | else
| |
− | Fault( "Unknown component " .. f( k, slot ) )
| |
− | end
| |
− | end -- for k, v
| |
− | if not access and Data.got.sets then
| |
− | fellows()
| |
− | end
| |
− | else
| |
− | Fault( f() .. " needs to be of <code>object</code> type" )
| |
− | end
| |
− | end -- focus()
| |
− | | |
− | | |
− | | |
− | local function format()
| |
− | -- Build formatted element
| |
− | -- Returns <inline>
| |
− | local source = Data.tree.format:lower()
| |
− | local r, s
| |
− | if source == "inline" or source == "block" then
| |
− | r = mw.html.create( "i" )
| |
− | :wikitext( source )
| |
− | else
| |
− | local code
| |
− | if source:find( "|", 1, true ) then
| |
− | local scan = "^[\n ]*%{%{[\n _]*|[\n _]*=[\n _]*%}%}[\n ]*$"
| |
− | if source:match( scan ) then
| |
− | code = source:gsub( "\n", "N" )
| |
− | else
| |
− | s = mw.text.nowiki( source ):gsub( "\n", "\n" )
| |
− | s = tostring( mw.html.create( "code" )
| |
− | :wikitext( s ) )
| |
− | Fault( "Invalid format " .. s )
| |
− | source = false
| |
− | end
| |
− | else
| |
− | local words = mw.text.split( source, "%s+" )
| |
− | local show, start, support, unknown
| |
− | for i = 1, #words do
| |
− | s = words[ i ]
| |
− | if i == 1 then
| |
− | start = s
| |
− | end
| |
− | support = Permit.builder[ s ]
| |
− | if support == start or
| |
− | support == "*" then
| |
− | Permit.builder[ s ] = true
| |
− | elseif s:match( "^[1-9]%d?" ) and
| |
− | Permit.builder.align then
| |
− | Permit.builder.align = tonumber( s )
| |
− | else
| |
− | if unknown then
| |
− | unknown = string.format( "%s %s", unknown, s )
| |
− | else
| |
− | unknown = s
| |
− | end
| |
− | end
| |
− | end -- i = 1, #words
| |
− | if unknown then
| |
− | s = tostring( mw.html.create( "code" )
| |
− | :css( "white-space", "nowrap" )
| |
− | :wikitext( s ) )
| |
− | Fault( "Unknown/misplaced format keyword " .. s )
| |
− | source = false
| |
− | start = false
| |
− | end
| |
− | if start == "inline" then
| |
− | if Permit.builder.half == true then
| |
− | show = "inline half"
| |
− | code = "{{_ |_=_}}"
| |
− | elseif Permit.builder.grouped == true then
| |
− | show = "inline grouped"
| |
− | code = "{{_ | _=_}}"
| |
− | elseif Permit.builder.spaced == true then
| |
− | show = "inline spaced"
| |
− | code = "{{_ | _ = _ }}"
| |
− | end
| |
− | if Permit.builder.newlines == true then
| |
− | show = show or "inline"
| |
− | code = code or "{{_|_=_}}"
| |
− | show = show .. " newlines"
| |
− | code = string.format( "N%sN", code )
| |
− | end
| |
− | elseif start == "block" then
| |
− | local space = "" -- amid "|" and name
| |
− | local spaced = " " -- preceding "="
| |
− | local spacer = " " -- following "="
| |
− | local suffix = "N" -- closing "}}" on new line
| |
− | show = "block"
| |
− | if Permit.builder.indent == true then
| |
− | start = " "
| |
− | show = "block indent"
| |
− | else
| |
− | start = ""
| |
− | end
| |
− | if Permit.builder.compressed == true then
| |
− | spaced = ""
| |
− | spacer = ""
| |
− | show = show .. " compressed"
| |
− | if Permit.builder.last == true then
| |
− | show = show .. " last"
| |
− | else
| |
− | suffix = ""
| |
− | end
| |
− | else
| |
− | if Permit.builder.lead == true then
| |
− | show = show .. " lead"
| |
− | space = " "
| |
− | end
| |
− | if type( Permit.builder.align ) ~= "string" then
| |
− | local n
| |
− | s = " align"
| |
− | if Permit.builder.align == true then
| |
− | n = 0
| |
− | if type( Data.got ) == "table" and
| |
− | type( Data.got.params ) == "table" then
| |
− | for k, v in pairs( Data.got.params ) do
| |
− | if type( v ) == "table" and
| |
− | not v.deprecated and
| |
− | type( k ) == "string" then
| |
− | k = mw.ustring.len( k )
| |
− | if k > n then
| |
− | n = k
| |
− | end
| |
− | end
| |
− | end -- for k, v
| |
− | end
| |
− | else
| |
− | n = Permit.builder.align
| |
− | if type( n ) == "number" and n > 1 then
| |
− | s = string.format( "%s %d", s, n )
| |
− | else
| |
− | n = 0 -- How comes?
| |
− | end
| |
− | end
| |
− | if n > 1 then
| |
− | spaced = string.rep( "_", n - 1 ) .. " "
| |
− | end
| |
− | show = show .. s
| |
− | elseif Permit.builder.after == true then
| |
− | spaced = ""
| |
− | show = show .. " after"
| |
− | elseif Permit.builder.dense == true then
| |
− | spaced = ""
| |
− | spacer = ""
| |
− | show = show .. " dense"
| |
− | end
| |
− | if Permit.builder.last == true then
| |
− | suffix = spacer
| |
− | show = show .. " last"
| |
− | end
| |
− | end
| |
− | code = string.format( "N{{_N%s|%s_%s=%s_%s}}N",
| |
− | start,
| |
− | space,
| |
− | spaced,
| |
− | spacer,
| |
− | suffix )
| |
− | if show == "block" then
| |
− | show = "block newlines"
| |
− | end
| |
− | end
| |
− | if show then
| |
− | r = mw.html.create( "span" )
| |
− | :wikitext( show )
| |
− | end
| |
− | end
| |
− | if code then
| |
− | source = code:gsub( "N", "\n" )
| |
− | code = mw.text.nowiki( code ):gsub( "N", "\n" )
| |
− | code = mw.html.create( "code" )
| |
− | :css( "margin-left", "1em" )
| |
− | :css( "margin-right", "1em" )
| |
− | :wikitext( code )
| |
− | if r then
| |
− | r = mw.html.create( "span" )
| |
− | :node( r )
| |
− | :node( code )
| |
− | else
| |
− | r = code
| |
− | end
| |
− | end
| |
− | end
| |
− | if source and Data.tag then
| |
− | Data.tag.format = source
| |
− | end
| |
− | return r
| |
− | end -- format()
| |
− | | |
− | | |
− | | |
− | local function formatter()
| |
− | -- Build presented documentation
| |
− | -- Returns <div>
| |
− | local r = mw.html.create( "div" )
| |
− | local x = fashioned( Data.tree, true, r )
| |
− | local s
| |
− | if x then
| |
− | r = x
| |
− | end
| |
− | if Data.leading then
| |
− | local toc = mw.html.create( "div" )
| |
− | local shift
| |
− | if Config.suppressTOCnum then
| |
− | toc:addClass( Config.suppressTOCnum )
| |
− | if type( Config.stylesTOCnum ) == "string" then
| |
− | local src = Config.stylesTOCnum .. "/styles.css"
| |
− | s = TemplateData.frame:extensionTag( "templatestyles",
| |
− | nil,
| |
− | { src = src } )
| |
− | r:newline()
| |
− | :node( s )
| |
− | end
| |
− | end
| |
− | toc:addClass( "navigation-not-searchable" )
| |
− | :css( "margin-top", "0.5em" )
| |
− | :wikitext( "__TOC__" )
| |
− | if Data.sibling then
| |
− | local block = mw.html.create( "div" )
| |
− | if TemplateData.ltr then
| |
− | shift = "right"
| |
− | else
| |
− | shift = "left"
| |
− | end
| |
− | block:css( "float", shift )
| |
− | :wikitext( Data.sibling )
| |
− | r:newline()
| |
− | :node( block )
| |
− | :newline()
| |
− | end
| |
− | r:newline()
| |
− | :node( toc )
| |
− | :newline()
| |
− | if shift then
| |
− | r:node( mw.html.create( "div" )
| |
− | :css( "clear", shift ) )
| |
− | :newline()
| |
− | end
| |
− | end
| |
− | s = features()
| |
− | if s then
| |
− | if Data.leading then
| |
− | r:node( mw.html.create( "h" .. Config.nested )
| |
− | :wikitext( factory( "doc-params" ) ) )
| |
− | :newline()
| |
− | end
| |
− | r:node( s )
| |
− | end
| |
− | if Data.shared then
| |
− | local global = mw.html.create( "div" )
| |
− | :attr( "id", "templatedata-global" )
| |
− | local shift
| |
− | if TemplateData.ltr then
| |
− | shift = "right"
| |
− | else
| |
− | shift = "left"
| |
− | end
| |
− | global:css( "float", shift )
| |
− | :wikitext( string.format( "[[%s|%s]]",
| |
− | Data.shared, "Global" ) )
| |
− | r:newline()
| |
− | :node( global )
| |
− | end
| |
− | if Data.tree and Data.tree.format then
| |
− | local e = format()
| |
− | if e then
| |
− | local show = "Format"
| |
− | if Config.supportFormat then
| |
− | show = string.format( "[[%s|%s]]",
| |
− | Config.supportFormat, show )
| |
− | end
| |
− | r:node( mw.html.create( "p" )
| |
− | :addClass( "navigation-not-searchable" )
| |
− | :wikitext( show .. ": " )
| |
− | :node( e ) )
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- formatter()
| |
− | | |
− | | |
− | | |
− | local function free()
| |
− | -- Remove JSON comment lines
| |
− | if Data.source:find( "//", 1, true ) then
| |
− | Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([{},\"'])",
| |
− | "%1%3" )
| |
− | end
| |
− | end -- free()
| |
− | | |
− | | |
− | | |
− | local function full()
| |
− | -- Build survey table from JSON data, append invisible <templatedata>
| |
− | Data.div = mw.html.create( "div" )
| |
− | :addClass( "mw-templatedata-doc-wrap" )
| |
− | if Permit.css.bg then
| |
− | Data.div:css( Permit.css.bg )
| |
− | end
| |
− | if Permit.css.fg then
| |
− | Data.div:css( Permit.css.fg )
| |
− | end
| |
− | focus()
| |
− | if Data.tag then
| |
− | if type( Data.got.params ) == "table" then
| |
− | for k, v in pairs( Data.got.params ) do
| |
− | focus( k )
| |
− | end -- for k, v
| |
− | if Data.heirs then
| |
− | fathers()
| |
− | end
| |
− | end
| |
− | end
| |
− | Data.div:node( formatter() )
| |
− | if not Data.lazy then
| |
− | Data.slim = flush()
| |
− | if TemplateData.frame then
| |
− | local div = mw.html.create( "div" )
| |
− | local tdata = { [ 1 ] = "templatedata",
| |
− | [ 2 ] = Data.slim }
| |
− | Data.strip = TemplateData.frame:callParserFunction( "#tag",
| |
− | tdata )
| |
− | div:wikitext( Data.strip )
| |
− | if Config.loudly then
| |
− | Data.div:node( mw.html.create( "hr" )
| |
− | :css( { height = "7ex" } ) )
| |
− | else
| |
− | div:css( "display", "none" )
| |
− | end
| |
− | Data.div:node( div )
| |
− | end
| |
− | end
| |
− | if Data.lasting then
| |
− | Fault( "deprecated type syntax" )
| |
− | end
| |
− | if Data.less then
| |
− | Fault( Config.solo )
| |
− | end
| |
− | end -- full()
| |
− | | |
− | | |
− | | |
− | local function furnish( adapt, arglist )
| |
− | -- Analyze transclusion
| |
− | -- Parameter:
| |
− | -- adapt -- table, #invoke parameters
| |
− | -- arglist -- table, template parameters
| |
− | -- Returns string
| |
− | local source
| |
− | favorize()
| |
− | -- deprecated:
| |
− | for k, v in pairs( Config.basicCnf ) do
| |
− | if adapt[ k ] and adapt[ k ] ~= "" then
| |
− | Config[ v ] = adapt[ k ]
| |
− | end
| |
− | end -- for k, v
| |
− | if arglist.heading and arglist.heading:match( "^[3-6]$" ) then
| |
− | Config.nested = arglist.heading
| |
− | else
| |
− | Config.nested = "2"
| |
− | end
| |
− | Config.loudly = faculty( arglist.debug or adapt.debug )
| |
− | Data.lazy = faculty( arglist.lazy ) and not Config.loudly
| |
− | Data.leading = faculty( arglist.TOC )
| |
− | if Data.leading and arglist.TOCsibling then
| |
− | Data.sibling = mw.text.trim( arglist.TOCsibling )
| |
− | end
| |
− | if arglist.lang then
| |
− | Data.slang = arglist.lang:lower()
| |
− | elseif adapt.lang then
| |
− | Data.slang = adapt.lang:lower()
| |
− | end
| |
− | if arglist.JSON then
| |
− | source = arglist.JSON
| |
− | elseif arglist.Global then
| |
− | source = TemplateData.getGlobalJSON( arglist.Global,
| |
− | arglist.Local )
| |
− | elseif arglist[ 1 ] then
| |
− | local s = mw.text.trim( arglist[ 1 ] )
| |
− | local start = s:sub( 1, 1 )
| |
− | if start == "<" then
| |
− | Data.strip = s
| |
− | elseif start == "{" then
| |
− | source = s
| |
− | elseif mw.ustring.sub( s, 1, 8 ) ==
| |
− | mw.ustring.char( 127, 39, 34, 96, 85, 78, 73, 81 ) then
| |
− | Data.strip = s
| |
− | end
| |
− | end
| |
− | if type( arglist.vertical ) == "string" and
| |
− | arglist.vertical:match( "^%d*%.?%d+[emprx]+$" ) then
| |
− | Data.scroll = arglist.vertical
| |
− | end
| |
− | if not source then
| |
− | Data.title = mw.title.getCurrentTitle()
| |
− | source = find()
| |
− | if not source and
| |
− | not Data.title.text:match( Config.subpage ) then
| |
− | local s = string.format( Config.suffix,
| |
− | Data.title.prefixedText )
| |
− | Data.title = mw.title.new( s )
| |
− | if Data.title.exists then
| |
− | source = find()
| |
− | end
| |
− | end
| |
− | end
| |
− | if not Data.lazy then
| |
− | if not Data.title then
| |
− | Data.title = mw.title.getCurrentTitle()
| |
− | end
| |
− | Data.lazy = Data.title.text:match( Config.subpage )
| |
− | end
| |
− | if type( source ) == "string" then
| |
− | TemplateData.getPlainJSON( source )
| |
− | end
| |
− | return finalize( faculty( arglist.source ) )
| |
− | end -- furnish()
| |
− | | |
− | | |
− | | |
− | 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()
| |
− | | |
− | | |
− | | |
− | TemplateData.getGlobalJSON = function ( access, adapt )
| |
− | -- Retrieve TemplateData from a global repository (JSON)
| |
− | -- Parameter:
| |
− | -- access -- string, with page specifier (on WikiMedia Commons)
| |
− | -- adapt -- JSON string or table with local overrides
| |
− | -- Returns true, if succeeded
| |
− | local plugin = Fetch( "/global" )
| |
− | local r
| |
− | if type( plugin ) == "table" and
| |
− | type( plugin.fetch ) == "function" then
| |
− | local s, got = plugin.fetch( access, adapt )
| |
− | if got then
| |
− | Data.got = got
| |
− | Data.order = got.paramOrder
| |
− | Data.shared = s
| |
− | r = true
| |
− | full()
| |
− | else
| |
− | Fault( s )
| |
− | end
| |
− | end
| |
− | return r
| |
− | end -- TemplateData.getGlobalJSON()
| |
− | | |
− | | |
− | | |
− | TemplateData.getPlainJSON = function ( adapt )
| |
− | -- Reduce enhanced JSON data to plain text localized JSON
| |
− | -- Parameter:
| |
− | -- adapt -- string, with enhanced JSON
| |
− | -- Returns string, or not
| |
− | if type( adapt ) == "string" then
| |
− | local JSONutil = Fetch( "JSONutil", true )
| |
− | Data.source = adapt
| |
− | free()
| |
− | if JSONutil then
| |
− | local Multilingual = Fetch( "Multilingual", true )
| |
− | local f
| |
− | if Multilingual then
| |
− | f = Multilingual.i18n
| |
− | end
| |
− | Data.got = JSONutil.fetch( Data.source, true, f )
| |
− | else
| |
− | local lucky
| |
− | lucky, Data.got = pcall( mw.text.jsonDecode, Data.source )
| |
− | end
| |
− | if type( Data.got ) == "table" then
| |
− | full()
| |
− | elseif not Data.strip then
| |
− | local scream = type( Data.got )
| |
− | if scream == "string" then
| |
− | scream = Data.got
| |
− | else
| |
− | scream = "Data.got: " .. scream
| |
− | end
| |
− | Fault( "fatal JSON error: " .. scream )
| |
− | end
| |
− | end
| |
− | return Data.slim
| |
− | end -- TemplateData.getPlainJSON()
| |
− | | |
− | | |
− | | |
− | TemplateData.test = function ( adapt, arglist )
| |
− | TemplateData.frame = mw.getCurrentFrame()
| |
− | return furnish( adapt, arglist )
| |
− | end -- TemplateData.test()
| |
− | | |
− | | |
− | | |
− | -- Export
| |
− | local p = { }
| |
− | | |
− | p.f = function ( frame )
| |
− | -- Template call
| |
− | local lucky, r
| |
− | TemplateData.frame = frame
| |
− | lucky, r = pcall( furnish, frame.args, frame:getParent().args )
| |
− | if not lucky then
| |
− | Fault( "INTERNAL: " .. r )
| |
− | r = failures()
| |
− | end
| |
− | return r
| |
− | 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.TemplateData = function ()
| |
− | -- Module interface
| |
− | return TemplateData
| |
− | end
| |
− | | |
− | return p
| |