Module:Sort/cellNum
Appearance
local Sort = { suite = "Sort",
sub = "cellNum",
serial = "2020-05-14",
item = 88370026,
globals = { Cell = 90144855,
FormatNum = 15709679 } }
--[=[
Sort/cellNum
support table cells with numerical content and number formatting
]=]
local Failsafe = Sort
local GlobalMod = Sort
Sort.digits = { { 0x30 },
{ 0x0660, "Arab" },
{ 0x06F0, "Arab" },
{ 0x07C0, "Nkoo" },
{ 0x0966, "Deva" },
{ 0x09E6, "Beng" },
{ 0x0A66, "Guru" },
{ 0x0AE6, "Gujr" },
{ 0x0B66, "Orya" },
{ 0x0BE6, "Taml" },
{ 0x0C66, "Telu" },
{ 0x0CE6, "Knda" },
{ 0x0D66, "Mlym" },
{ 0x0DE6, "Sinh" },
{ 0x0E50, "Thai" },
{ 0x0ED0, "Laoo" },
{ 0x0F20, "Tibt" },
{ 0x1040, "Mymr" },
{ 0x1369, "Ethi" },
{ 0x17E0, "Khmr" },
{ 0x1810, "Mong" },
{ 0x1946, "Limb" },
{ 0x19D0, "Talu" },
{ 0x1A80, "Lana" },
{ 0x1A90, "Lana" },
{ 0x1B50, "Bali" },
{ 0x1BB0, "Sund" },
{ 0x1C40, "Lepc" },
{ 0x1C50, "Olck" },
{ 0xA620, "Vaii" },
{ 0xA8D0, "Saur" },
{ 0xA900, "Kali" },
{ 0xA9D0, "Java" },
--{ 0xA9F0, "" }, MYANMAR TAI LAING
{ 0xAA50, "Cham" },
{ 0xABF0, "Mtei" },
{ 0x102E, "Copt" },
{ 0x1104A, "Osma" },
{ 0x110D3, "Rohg" },
--{ 0x110E6, "" }, RUMI
{ 0x11106, "Brah" },
{ 0x1110F, "Sora" },
{ 0x11113, "Cakm" },
{ 0x1111D, "Shrd" },
{ 0x1112F, "Sind" },
{ 0x11145, "Newa" },
{ 0x1114D, "Tirh" },
{ 0x11165, "Modi" },
{ 0x1116C, "Takr" },
{ 0x11173, "Ahom" },
{ 0x1118E, "Wara" },
{ 0x111C5, "Bhks" },
{ 0x111D5, "Gonm" },
{ 0x111DA, "Gong" },
{ 0x116A6, "Mroo" },
{ 0x116B5, "Hmng" },
{ 0x116E8, "Medf" },
{ 0x11E14, "Hmnp" },
{ 0x11E2F, "Wcho" },
{ 0x11E8C, "Mend" },
{ 0x11E95, "Adlm" }
}
Sort.heading = { [0x2D] = 45, -- -
[0x2212] = 45, -- -
[0x2B] = 43 -- +
}
Sort.mpz = -0.5
Sort.prefix = { [0x003C] = -5,
[0x003E] = 5,
[0x00B1] = true,
[0x2248] = false,
[0x2264] = -2,
[0x2265] = 2
}
Sort.supreme = mw.ustring.char( 8734 ) -- infinit
local foreignModule = function ( access, advanced, append, alt, alert )
-- Fetch global module
-- Precondition:
-- access -- string, with name of base module
-- advanced -- true, for require(); else mw.loadData()
-- append -- string, with subpage part, if any; or false
-- alt -- number, of wikidata item of root; or false
-- alert -- true, for throwing error on data problem
-- Postcondition:
-- Returns whatever, probably table
-- 2020-01-01
local storage = access
local finer = function ()
if append then
storage = string.format( "%s/%s",
storage,
append )
end
end
local fun, lucky, r, suited
if advanced then
fun = require
else
fun = mw.loadData
end
GlobalMod.globalModules = GlobalMod.globalModules or { }
suited = GlobalMod.globalModules[ access ]
if not suited then
finer()
lucky, r = pcall( fun, "Module:" .. storage )
end
if not lucky then
if not suited and
type( alt ) == "number" and
alt > 0 then
suited = string.format( "Q%d", alt )
suited = mw.wikibase.getSitelink( suited )
GlobalMod.globalModules[ access ] = suited or true
end
if type( suited ) == "string" then
storage = suited
finer()
lucky, r = pcall( fun, storage )
end
if not lucky and alert then
error( "Missing or invalid page: " .. storage )
end
end
return r
end -- foreignModule()
local fetch = function ( access, advanced, append )
-- Fetch global library
-- Precondition:
-- access -- string|false, with name of base module
-- advanced -- true, for require(); else mw.loadData()
-- append -- string, with subpage part, if any; or false
local store, sub, suite
if access then
suite = access
store = access
sub = append
else
suite = Sort.suite
if append then
sub = append:lower()
store = append
else
store = "Sorter"
end
end
if type( Sort[ store ] ) == "nil" then
local bib = foreignModule( suite,
advanced,
sub,
Sort.globals[ store ],
not access )
if bib and type( bib[ suite ] ) == "function" then
Sort[ store ] = bib[ suite ]()
elseif advanced then
error( tostring( bib ) )
else
Sort[ store ] = bib
end
end
return Sort[ store ]
end -- fetch()
local factory = function ( ask )
-- Ensure config data
-- Precondition:
-- assign -- string|nil, particular query
-- Postcondition:
-- config data available
-- Returns elements for "*", 10, 1000, fractpart
local r
if not ask then
Sort.minus = Sort.minus or mw.ustring.char( 0x2212 )
elseif ask == "sep" then
if not Sort.sepDec then
local seek = "%d(%p?)(%d?%d?456)(%p)7"
local s
Sort.contLang = Sort.contLang or
mw.language.getContentLanguage()
s = Sort.contLang:formatNum( 123456.7 )
Sort.sepGroup, s, Sort.sepDec = mw.ustring.match( s, seek )
Sort.sepDec = Sort.sepDec or "."
Sort.keyDec = mw.ustring.codepoint( Sort.sepDec, 1, 1 )
if s then
Sort.nGroup = #s
end
if Sort.sepDec == "." then
Sort.seekDec = "%%."
else
Sort.seekDec = Sort.sepDec
end
if Sort.sepGroup and Sort.sepGroup ~= "" then
if Sort.sepGroup == "." then
Sort.seekGroup = "%."
else
Sort.seekGroup = Sort.sepGroup
end
Sort.separated = string.format( "%s%%d%%d%%d%s",
Sort.seekGroup,
Sort.seekGroup )
end
end
elseif ask == "dec" then
if not Sort.spanDec then
if Sort.sepDec == "." then
Sort.spanDec = "."
else
local e = mw.html.create( "span" )
:addClass( "numericFormat-dec" )
:node( mw.html.create( "span" )
:wikitext( "." ) )
Sort.spanDec = tostring( e )
end
end
elseif ask == "minus" then
if not Sort.spanMinus then
local e = mw.html.create( "span" )
:addClass( "numericFormat-minus" )
:node( mw.html.create( "span" )
:wikitext( "-" ) )
Sort.spanMinus = tostring( e )
end
elseif ask == 1000 then
r = mw.html.create( "span" )
:addClass( "numericFormat-1000" )
elseif ask == "fractpart" then
r = mw.html.create( "span" )
:addClass( "numericFormat-fractpart" )
elseif ask == "*" then
r = mw.html.create( "span" )
:addClass( "numericFormat-multiply" )
elseif ask == 10 then
r = mw.html.create( "span" )
:addClass( "numericFormat-10" )
-- ::before { content: "10"; }
end
return r
end -- factory()
local feeder = function ( access )
-- Retrieve first TemplateStyles transclusion
-- Precondition:
-- access -- string, TemplateStyles ID
local ts = Sort[ access ]
local r
if ts and not ts.loaded then
local s = type( ts.origin )
local src
ts.loaded = true
if s == "string" then
src = ts.origin
elseif s == "table" then
src = ts.origin.prefixedText
end
if src then
Sort.frame = Sort.frame or mw.getCurrentFrame()
r = Sort.frame:extensionTag( "templatestyles",
nil,
{ src = src } )
end
end
return r or ""
end -- feeder()
local fine = function ( about )
-- Equip number with styled special characters
-- Precondition:
-- about -- table, parameters of base number
-- .show -- string, digits
-- .low -- boolean, heading minus
-- .sign -- string, heading sign
-- .sub -- string, decimal fraction
-- .long -- boolean, grouping possible
-- Postcondition:
-- Returns updated entire presentation
local r
if about.long then
factory( "sep" )
local n = mw.ustring.len( about.show )
local k = n - Sort.nGroup + 1
local i, m, e, s
r = mw.ustring.sub( about.show, k )
n = k - Sort.nGroup
for j = n, -1, - Sort.nGroup do
if j > 0 then
i = j
else
i = 1
end
m = j + Sort.nGroup - 1
s = mw.ustring.sub( about.show, i, m )
e = factory( 1000 ):wikitext( s )
r = tostring( e ) .. r
end -- for j
end
r = r or about.show or about.scream
if about.low then
factory( "minus" )
r = Sort.spanMinus .. r
elseif about.sign then
r = about.sign .. r
end
if about.sub then
local s = about.sub
factory( "sep" )
factory( "dec" )
r = r .. Sort.spanDec
if Sort.nGroup then
local n = mw.ustring.len( s )
if n > Sort.nGroup + 2 then
local k = 0
local m = n - Sort.nGroup
local e, sg
for j = 1, m, Sort.nGroup do
sg = mw.ustring.sub( about.sub,
j,
j + Sort.nGroup - 1 )
e = factory( "fractpart" ):wikitext( sg )
r = r .. tostring( e )
k = k + Sort.nGroup
end -- for j
s = s:sub( k + 1, n )
end
end
r = r .. s
end
return feeder( "cssNum" ) .. r
end -- fine()
local fined = function ( all, assign )
-- Append styled number
-- Precondition:
-- all -- string, formatted entire presentation
-- assign -- table, exponent
-- .show -- string, digits
-- .low -- boolean, < 0
-- Postcondition:
-- Returns
-- 1. string, updated entire presentation
-- 2. string, styled number
local r1 = all
local r2 = assign.show
if assign.low then
if Sort.cssNum then
factory( "minus" )
r2 = Sort.spanMinus .. r2
r1 = feeder( "cssNum" ) .. r1
else
factory()
r2 = Sort.minus .. r2
end
end
return r1, r2
end -- fined()
local finest = function ( args, ahead )
-- Append styled decimal power
-- Precondition:
-- args -- table, parameters
-- .exp -- table, exponent
-- ahead -- string, formatted presentation
-- Postcondition:
-- Returns expanded presentation
local r = string.format( "%s%s%s",
feeder( "cssNum" ),
feeder( "cssNumExp" ),
ahead )
local em = factory( "*" )
local ep = factory( 10 )
local s
r, s = fined( r, args.exp )
em:wikitext( "e" )
ep:node( mw.html.create( "sup" )
:wikitext( s ) )
s = Sort.Cell.feature( args, "color" ) or "#000000"
em:css( "background-color", s )
r = string.format( "%s%s%s",
r,
tostring( em ),
tostring( ep ) )
return r
end -- finest()
local flat = function ( assign, after, adjust )
-- Parse decimal number
-- Precondition:
-- assign -- string, number to be parsed
-- after -- boolean, decimal separator expected
-- adjust -- number|boolean|nil, cheat sort figure
-- Postcondition:
-- Returns table, with analysis
-- .long -- >= 1000 etc.
-- .low -- < 0
-- .sign -- minus, plus
-- .show -- leading digits, scripting
-- .sub -- decimal fragment digits, scripting
-- .sort -- signed ASCII sort text
-- .script -- script code
-- .scream -- error text
local r = { }
local s = assign
local k, init
local face = function ()
local j
if init == 45 then
j = 8722
else
j = init
end
return mw.ustring.char( j )
end -- face()
factory( "sep" )
if s:find( "&", 1, true ) then
s = mw.text.decode( s )
:gsub( " ", mw.ustring.char( 0x2009 ) )
end
s = mw.ustring.gsub( s, "%s", "" )
k = mw.ustring.codepoint( s, 1, 1 )
if k then
init = Sort.heading[ k ]
if init then
if mw.ustring.len( s ) > 1 then
s = mw.ustring.sub( s, 2 )
k = mw.ustring.codepoint( s, 1, 1 )
r.low = ( init == 45 )
else
k = 0x30
s = "0"
end
end
else
k = 0x30
s = "0"
end
if after then
local m = mw.ustring.find( s, Sort.sepGroup, 1, true )
local dig, j0, j9, n
if m and
Sort.separated and
mw.ustring.match( s, Sort.separated ) then
s = mw.ustring.gsub( s, Sort.seekGroup, "" )
end
for i = 1, #Sort.digits do
dig = Sort.digits[ i ]
j0 = dig[ 1 ]
j9 = j0 + 9
if k >= j0 and k <= j9 then
r.script = dig[ 2 ]
n = mw.ustring.len( s )
break -- for i
elseif k < j0 then
break -- for i
end
end -- for i
if n then
m = 0
for i = 1, n do
if k == j0 then
m = i
if i < n then
k = mw.ustring.codepoint( s, i + 1, i + 1 )
end
else
break -- for i
end
end -- for i
if m > 0 then
s = mw.ustring.sub( s, m + 1 )
n = n - m
end
m = 0
for i = 1, n do
if k == Sort.keyDec or k == 46 then
k = false
break -- for i
elseif k >= j0 and k <= j9 then
r.sort = string.format( "%s%c",
r.sort or "",
k - j0 + 48 )
if i < n then
k = mw.ustring.codepoint( s, i + 1, i + 1 )
end
m = i
end
end -- for i
if m > 0 then
r.long = ( m > Sort.nGroup )
r.sort = r.sort or "0"
r.show = mw.ustring.sub( s, 1, m )
if not k then
m = m + 1
s = mw.ustring.sub( s, m + 1 )
end
n = n - m
else
r.show = mw.ustring.char( j0 )
r.sort = "0"
if not k then
s = mw.ustring.sub( s, 2 )
n = n - 1
end
end
if r.low and r.sort ~= "0" then
r.sort = "-" .. r.sort
end
if n > 0 then
if k then
r.scream = s
else
r.sort = r.sort .. Sort.sepDec
k = mw.ustring.codepoint( s, 1, 1 )
for i = 1, n do
if k and k >= j0 and k <= j9 then
r.sort = string.format( "%s%c",
r.sort,
k - j0 + 48 )
if i < n then
k = mw.ustring.codepoint( s,
i + 1,
i + 1 )
end
else
k = false
end
end -- for i
if k then
r.sub = s
else
r.scream = s
r.show = false
end
end
end
if adjust then
if adjust == true then
-- plus/minus
r.sort = "0"
elseif r.sort then
k = tonumber( r.sort )
if k then
local m = k * 0.0000000001
if m < 0 then
m = -m
end
k = k + m * adjust
r.sort = tostring( k )
end
end
end
else
r.scream = assign
end
if init and not r.scream then
r.sign = face()
end
else
k = tonumber( s )
if k and k >= 0 then
k = math.floor( k )
r.show = tostring( k )
r.sort = r.show
if init then
r.sign = face()
if init == 45 then
r.sort = "-" .. r.sort
end
end
else
r.scream = assign
end
end
return r
end -- flat()
local fore = function ( args )
-- Create and merge sort attribute
-- Precondition:
-- args -- table, parameters
-- .n -- table, for base number
-- .sort -- string|nil
-- .exp -- table|nil, for exponent
-- amount -- number, for base
-- Postcondition:
-- attributes extended
local s = args.n.sort or "0"
if args.exp and args.exp.sort then
s = string.format( "%sE%s", s, args.exp.sort )
end
Sort.Cell.faced( args, s )
end -- fore()
local format = function ( args )
-- Format visible number
-- Precondition:
-- args -- table, parameters
-- .pad -- number|false, for padding
-- .pre -- string|false, for prefix
-- .n -- table, for base
-- .low -- boolean, < 0
-- .sign -- minus, plus
-- .show -- leading digits
-- .sub -- decimal fragment digits
-- .script -- script code
-- .suffix -- string|false, extending base
-- .exp -- table|false, for exponent
-- .post -- string|false, for postfix
-- .round -- number|false, for rounding
-- .cell -- boolean, enfoce sort value
-- Postcondition:
-- Returns string
local r = args.n.show or args.n.scream
local e, move, s, shift
if args.pad and args.pad < 0 then
move = args.pad + mw.ustring.len( args.n.show )
if args.n.sign then
move = move + 1
end
if move < 0 then
move = move + 1
end
if args.pre and move then
move = move + mw.ustring.len( args.pre ) + 1
end
end
if move then
if move < 0 then
if not Sort.shift then
if Sort.Cell.following() then
Sort.shift = "left"
else
Sort.shift = "right"
end
Sort.shift = "padding-" .. Sort.shift
end
Sort.Cell.feature( args,
Sort.shift,
string.format( "%.2fem",
Sort.mpz * move ) )
end
elseif args.pad then
move = args.pad
if args.n.sub then
move = move - mw.ustring.len( args.n.sub ) - 1
if args.suffix then
move = move - mw.ustring.len( args.suffix )
end
else
move = move + 0.5
end
if args.post then
move = move - mw.ustring.len( args.post ) - 1
end
if move > 0 then
shift = string.rep( "0", move )
e = mw.html.create( "span" )
:css( "visibility", "hidden" )
:wikitext( shift )
shift = tostring( e )
end
end
if args.n.low or args.n.long or args.n.sub then
r = fine( args.n )
end
if args.suffix then
r = r .. args.suffix
end
if args.exp then
if Sort.cssNumExp then
r = finest( args, r )
else
Sort.stick = Sort.stick or mw.ustring.char( 0xB7 )
r, s = fined( r, args.exp )
e = mw.html.create( "sup" )
:wikitext( s )
r = string.format( "%s%s10%s",
r,
Sort.stick,
tostring( e ) )
end
end
if args.pre or
args.n.long or
args.n.sub or
args.exp and args.exp.low or
args.post or
args.n.script then
if args.pre then
r = string.format( "%s %s", args.pre, r )
end
if args.post then
r = string.format( "%s %s", r, args.post )
end
e = mw.html.create( "span" )
:css( "white-space", "nowrap" )
:wikitext( r )
if ( args.pre or args.post ) and
not Sort.Cell.following() then
e:attr( "dir", "ltr" )
end
if args.n.script then
e:attr( "lang", "und-" .. args.n.script )
end
r = tostring( e )
end
if shift then
r = r .. shift
end
if args.pad or
args.pre or
( args.cell and
( args.n.low or
args.n.sign or
args.n.sub or
args.n.long or
args.suffix or
args.exp or
args.n.script ) ) then
fore( args )
end
return r
end -- format()
local front = function ( analyse )
-- Interprete heading text in front of number
-- Parameter:
-- analyse -- string, with probably prefixed number
-- Postcondition:
-- Returns
-- 1. string|nil -- prefix
-- 2. string|nil -- remaining text, hopefully number
-- 3. number|nil -- weight, cheat sort figure
local i, r1, r2, r3
local s = analyse
if s:find( "&", 1, true ) then
s = mw.text.decode( s )
if s:find( "&", 1, true ) then
local html = { lt = 0x003C,
gt = 0x003E,
plusmn = 0x00B1,
asymp = 0x2248,
le = 0x2264,
ge = 0x2265 }
for k, v in pairs( html ) do
s = s:gsub( string.format( "&%s;", k ),
mw.ustring.char( v ) )
end -- for k, v
end
end
i = mw.ustring.codepoint( s, 1, 1 )
for k, v in pairs( Sort.prefix ) do
if k == i then
r1 = mw.ustring.char( k )
r2 = mw.text.trim( mw.ustring.sub( s, 2 ) )
r3 = v
break -- for k, v
end
end -- for k, v
if not r1 then
local Value = fetch( "Text", false, "value" )
if Value and type( Value.prefix ) == "table" then
for k, v in pairs( Value.prefix ) do
i = mw.ustring.len( k )
if k == mw.ustring.sub( s, 1, i ) then
r1 = k
r2 = mw.text.trim( mw.ustring.sub( s, i + 1 ) )
r3 = v
break -- for k, v
end
end -- for k, v
end
end
return r1, r2, r3
end -- front()
local furnish = function ( args )
-- Execute task
-- Parameter:
-- args -- table, parameters
-- Postcondition:
-- Returns string, or expands .cell
-- Throws error on failure
local r
fetch( false, true, "Cell" )
if type( args ) == "table" then
local present = Sort.Cell.first( args )
local s = type( args.exp )
if s == "string" then
Sort.Cell.fair( args, "exp", present )
elseif s == "number" then
present.exp = args.exp
end
Sort.Cell.fair( args, "pre", present )
s = type( args.n )
if s == "string" then
s = mw.text.trim( args.n )
if s == Sort.supreme then
present.infinit = 1
elseif mw.ustring.len( s ) == 2 and
mw.ustring.codepoint( s, 2, 2 ) == 8734 then
local m = mw.ustring.codepoint( s, 1, 1 )
if m == 45 or m == 8722 then
present.infinit = -1
elseif m == 43 then
present.infinit = 1
end
end
if not present.infinit then
if not present.exp then
local i = s:find( "%d[.,]?[eE]%-?%d+$" )
if i then
local split = s:sub( i + 2 ):upper()
if split:sub( 1, 1 ) == "E" then
split = split:sub( 2 )
end
present.exp = split
s = s:sub( 1, i )
end
end
present.n = flat( s, true )
if present.n.scream and not present.pre then
local move
present.pre, s, move = front( s )
if present.pre then
present.n = flat( s, true, move )
end
end
end
elseif s == "number" then
local k = args.n
present.n = { low = ( k < 0 ),
sort = tostring( k ) }
present.n.show = present.n.sort
if present.n.low then
present.n.show = present.n.show:sub( 2 )
end
k = present.n.show:find( ".", 1, true )
if k then
present.n.sub = present.n.show:sub( k + 1 )
k = k - 1
present.n.show = present.n.show:sub( 1, k )
else
k = mw.ustring.len( present.n.show )
end
present.n.long = ( k > Sort.nGroup )
end
if present.n or present.infinit then
if present.n then
local lazy
s = type( present.exp )
if s == "string" then
present.exp = flat( present.exp )
elseif s == "number" then
local k = present.exp
present.exp = { low = ( k < 0 ) }
if present.exp.low then
k = -1 * k
end
k = math.floor( k )
present.exp.show = tostring( k )
if k > 0 then
present.exp.sort = present.exp.show
if present.exp.low then
present.exp.sort = "-" .. present.exp.sort
end
end
end
s = type( args.lazy )
if s == "string" then
lazy = ( args.lazy == "1" )
elseif s == "" then
lazy = args.lazy
end
if lazy then
fore( present )
else
Sort.Cell.fair( args, "suffix", present )
s = type( args.pad )
if s == "string" then
present.pad = tonumber( args.pad )
elseif s == "number" then
present.pad = args.pad
end
if present.pad and present.pad == 0 then
present.pad = false
end
Sort.Cell.fair( args, "post", present )
if not present.n.low then
s = type( args.plus )
if s == "string" then
if args.plus == "1" or
args.plus == "+" then
present.n.sign = "+"
end
elseif s == "boolean" then
present.n.sign = "+"
end
end
if args.cssNum and not Sort.cssNum then
Sort.cssNum = { }
Sort.cssNum.origin = args.cssNum
end
if args.cssNumExp and not Sort.cssNumExp then
Sort.cssNumExp = { }
Sort.cssNumExp.origin = args.cssNumExp
end
r = format( present )
end
else
present.n = { sort = "9999999" }
if present.infinit < 0 then
present.n.sort = "-" .. present.n.sort
end
present.exp = { sort = "301" }
fore( present )
end
r = Sort.Cell.finalize( present, r )
else
Sort.Cell.fault( "???", args )
end
else
error( "'args' is not a table" )
end
return r
end -- furnish()
Sort.f = function ( args )
-- Create table cell start
-- Parameter:
-- args -- table, parameters
-- .pad -- number|string, for padding
-- .pre -- string, for prefix
-- .plus -- boolean|string, for plus sign
-- .n -- number|string, for base
-- .suffix -- string, extending base
-- .exp -- number|string, for exponent
-- .post -- string, for postfix
-- .round -- number|string, for rounding
-- .lazy -- string|boolean, mute
-- .cell -- string|boolean|table, enforce sort
-- .rowspan -- number|string, for cell attribute
-- .colspan -- number|string, for cell attribute
-- .class -- string, for cell attribute
-- .style -- string|table, for cell attribute
-- .id -- string, for cell attribute
-- .cssNum -- string|title, for templatestyles
-- .cssNumExp -- string|title, for templatestyles
-- .cat -- string|nil, for error category
-- .frame -- table, if present
-- Postcondition:
-- Returns string, or expands .cell, or nil
local lucky, r = pcall( furnish, args )
if not lucky then
local e = mw.html.create( "span" )
:addClass( "error" )
:wikitext( "Module:Sort/cell * " .. r )
if type( args.cell ) == "table" and
type( args.cell.wikitext ) == "function" then
args.cell:node( e )
else
r = tostring( e )
end
end
return r
end -- Sort.f()
Sort.furnish = function ()
-- Retrieve list of project prefixes
-- Postcondition:
-- Returns string -- with wikitext list
local r, Value
for k, v in pairs( Sort.prefix ) do
if r then
r = r .. "\n"
else
r = ""
end
r = string.format( "%s* %s", r, mw.ustring.char( k ) )
end -- for k, v
Value = fetch( "Text", false, "value" )
if Value and type( Value.prefix ) == "table" then
for k, v in pairs( Value.prefix ) do
r = string.format( "%s\n* %s", r, k )
end -- for k, v
end
return r
end -- Sort.furnish()
Failsafe.failsafe = function ( atleast )
-- Retrieve versioning and check for compliance
-- Precondition:
-- atleast -- string, with required version or "wikidata" or "~"
-- or false
-- Postcondition:
-- Returns string -- with queried version, also if problem
-- false -- if appropriate
-- 2019-10-15
local last = ( atleast == "~" )
local since = atleast
local r
if last or since == "wikidata" then
local item = Failsafe.item
since = false
if type( item ) == "number" and item > 0 then
local entity = mw.wikibase.getEntity( string.format( "Q%d",
item ) )
if type( entity ) == "table" then
local 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
else
r = vsn.value
end
end
end
end
end
if type( r ) == "nil" then
if not since or since <= Failsafe.serial then
r = Failsafe.serial
else
r = false
end
end
return r
end -- Failsafe.failsafe()
-- Export
local p = { }
p.f = function ( frame )
-- Template call
Sort.frame = frame
return Sort.f( frame.args ) or ""
end -- p.f
p.furnish = function ()
return Sort.furnish()
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.Sort = function ()
-- Module interface
return Sort
end
return p