Modul:Sort/cellNum
Erscheinungsbild
Vorlagenprogrammierung | Diskussionen | Lua | Test | Unterseiten | |||
Modul | Deutsch | English
|
Modul: | Dokumentation |
Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus
Dies ist die (produktive) Mutterversion eines global benutzten Lua-Moduls.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Versionsbezeichnung auf WikiData:
2024-06-01
Updating notwendig
(lokal:2020-03-15
)local Sort = { suite = "Sort",
sub = "cellNum",
serial = "2020-03-15",
item = 0,
globals = { FormatNum = 15709679 } }
--[=[
Sort/cellNum -- support table cells with numerical content
]=]
local Failsafe = Sort
local GlobalMod = Sort
local Cell
Sort.mpz = -0.5
if mw.site.server:find( ".beta.wmflabs.org", 4, true ) then
require( "Module:No Globals" )
end
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
-- 2019-10-29
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, 0 )
end
end
return r
end -- foreignModule()
local face = function ( attribute, assign )
-- Store preceding attribute
-- Precondition:
-- attribute -- string, attribute name
-- assign -- string|nil, for value
-- Postcondition:
-- attributes extended
if type( assign ) == "string" then
local s = mw.text.trim( assign )
if s ~= "" then
Cell = Cell or { }
Cell[ attribute ] = s
end
end
end -- face()
local facing = function ( append )
-- Prepend preceding attributes
-- Precondition:
-- append -- string|html, thing to be extended
-- Postcondition:
-- Returns string, if append is a string
-- otherwise html is extended
local r = append
if Cell then
if type( append ) == "string" then
if Cell.css then
local s = ""
for k, v in pairs( Cell.css ) do
if type( k ) == "string" and
type( v ) == "string" then
v = mw.text.trim( v )
k = mw.text.trim( k )
if v ~= "" and
k ~= "" then
s = string.format( "%s;%s:%s", s, k, v )
end
end
end -- for k, v
if s ~= "" then
face( "style", s:sub( 2 ) )
end
Cell.css = nil
end
r = "| " .. r
for k, v in pairs( Cell ) do
r = string.format( " %s=\"%s\"%s", k, v, r )
end -- for k, v
r = r:sub( 2 )
else
for k, v in pairs( Cell ) do
if k == "class" then
append:addClass( v )
elseif k == "css" then
append:css( v )
else
append:attr( k, v )
end
end -- for k, v
end
end
return r
end -- facing()
local factory = function ( ask )
-- Ensure config data
-- Precondition:
-- assign -- string|nil, particular query
-- Postcondition:
-- config data available
if not ask then
Sort.minus = Sort.minus or mw.ustring.char( 8722 )
elseif ask == "sep" then
if not Sort.sepDec then
Sort.contLang = Sort.contLang or
mw.language.getContentLanguage()
Sort.sepGroup, Sort.sepDec =
mw.ustring.match( Sort.contLang:formatNum( 1234.5 ),
"1(%p?)234(%p)5" )
Sort.sepDec = Sort.sepDec or "."
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 == "*" then
if not Sort.spanMult then
local e = mw.html.create( "span" )
:addClass( "numericFormat-multiply" )
:wikitext( "*" )
Sort.spanMult = tostring( e )
end
elseif ask == "1000" then
if not Sort.span1000 then
local e = mw.html.create( "span" )
:addClass( "numericFormat-1000" )
:wikitext( "@@@" )
Sort.span1000 = tostring( e )
end
elseif ask == "10sup" then
if not Sort.span10sup then
local e = mw.html.create( "span" )
:addClass( "numericFormat-10sup" )
:wikitext( "@@@" )
Sort.span10sup = tostring( e )
end
end
end -- factory()
local features = function ( assign )
-- Parse CSS string
-- Precondition:
-- assign -- string, CSS to be parsed
-- Postcondition:
-- Cell.css
local css = mw.text.split( assign, ";" )
-- Problem: URL; not expected
local pair, s
for i = 1, #css do
pair = mw.text.split( css[ i ], ":" )
-- Problem: URL; not expected
if #pair == 2 then
s = mw.text.trim( pair[ 1 ] )
if s ~= "" then
Cell = Cell or { }
Cell.css = Cell.css or { }
Cell.css[ s ] = pair[ 2 ]
end
end
end -- i = 1, #css
end -- features()
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 ( all, ahead, assist, adjacent )
-- Equip number with styled special characters
-- Precondition:
-- all -- string, formatted entire presentation
-- ahead -- boolean, heading minus
-- assist -- boolean, grouping possible
-- adjacent -- boolean, decimal
-- Postcondition:
-- Returns updated entire presentation
local r = all
if ahead and mw.ustring.codepoint( r, 1, 1 ) == 8722 then
factory( "minus" )
r = Sort.spanMinus .. mw.ustring.sub( r, 2 )
end
if adjacent then
factory( "sep" )
factory( "dec" )
if Sort.spanDec then
r = mw.ustring.gsub( r, Sort.seekDec, Sort.spanDec )
end
end
if assist then
factory( "sep" )
if Sort.seekGroup then
local s
Sort.seek1000 = Sort.seek1000 or
"(%d?%d?%d)" .. Sort.seekGroup
factory( "1000" )
repeat
s = mw.ustring.match( r, Sort.seek1000 )
if s then
r = mw.ustring.gsub( r,
s .. Sort.seekGroup,
Sort.span1000:gsub( "@@@", s ) )
end
until not s
end
end
return feeder( "cssNum" ) .. r
end -- fine()
local fined = function ( all, assign )
-- Append styled number
-- Precondition:
-- all -- string, formatted entire presentation
-- assign -- number, integer
-- Postcondition:
-- Returns
-- 1. string, updated entire presentation
-- 2. string, styled number
local r1 = all
local r2
if assign < 0 then
r2 = tostring( -1 * assign )
if Sort.cssNum then
factory( "minus" )
r2 = Sort.spanMinus .. r2
r1 = feeder( "cssNum" ) .. r1
else
factory()
r2 = Sort.minus .. r2
end
else
r2 = tostring( assign )
end
return r1, r2
end -- fined()
local finest = function ( all, assign )
-- Append styled decimal power
-- Precondition:
-- all -- string, formatted presentation
-- assign -- number, exponent
-- Postcondition:
-- Returns expanded presentation
local r = string.format( "%s%s%s",
feeder( "cssNum" ),
feeder( "cssNumExp" ),
all )
local s
factory( "*" )
factory( "10sup" )
r, s = fined( r, assign )
r = string.format( "%s%s%s",
r,
Sort.spanMult:gsub( ">%*<", ">E<" ),
Sort.span10sup:gsub( "@@@", s ) )
return r
end -- finest()
local flat = function ( assign, after )
-- Parse decimal number
-- Precondition:
-- assign -- string, number to be parsed
-- after -- boolean, decimal separator expected
-- Postcondition:
-- Returns number, or false
local r = mw.text.trim( assign )
if r:find( "%d" ) then
if mw.ustring.codepoint( r, 1, 1 ) == 8722 then
r = "-" .. mw.ustring.sub( r, 2 )
end
if after then
local i, k
factory( "sep" )
i = mw.ustring.find( r, Sort.sepGroup, 1, true )
if i and Sort.separated and
mw.ustring.match( r, Sort.separated ) then
r = mw.ustring.gsub( r, Sort.seekGroup, "" )
i = false
end
k = mw.ustring.find( r, Sort.sepDec, 1, true )
if i and k and i < k then
r = mw.ustring.gsub( r, Sort.seekGroup, "" )
i = false
end
if k and Sort.sepDec ~= "." then
r = mw.ustring.gsub( r, Sort.seekDec, "." )
end
end
r = tonumber( r )
else
r = false
end
return r
end -- flat()
local fore = function ( amount, above )
-- Create and merge sort attribute
-- Precondition:
-- amount -- number, for base
-- above -- number|nil, for exponent
-- Postcondition:
-- attributes extended
local s = tostring( amount )
local i = s:find( ".", 1, true )
if i then
factory( "sep" )
if Sort.sepDec ~= "." then
s = string.format( "%s%s%s",
s:sub( 1, i - 1 ),
Sort.sepDec,
s:sub( i + 1 ) )
end
end
if above and above ~= 0 then
s = string.format( "%sE%d", s, above )
end
face( "data-sort-value", s )
end -- fore()
local format = function ( args )
-- Format visible number
-- Precondition:
-- args -- table, parameters
-- .pad -- number, for padding
-- .pre -- string, for prefix
-- .lead -- boolean, for plus sign
-- .n -- number, for base
-- .exp -- number, for exponent
-- .post -- string, for postfix
-- .round -- number, for rounding
-- .cell -- boolean, enfoce sort value
-- Postcondition:
-- Returns string
local low = ( args.n < 0 )
local e, i, less, long, move, n, r, s, shift
if low then
n = -1 * args.n
else
n = args.n
end
less = ( n > math.floor( n ) )
long = ( n >= 1000 )
if low or less or long then
factory()
r = Sort.contLang:formatNum( n )
if low then
r = Sort.minus .. r
elseif args.lead then
r = "+" .. r
end
else
r = tostring( n )
end
if args.pad and args.pad < 0 then
move = args.pad
if less then
factory( "sep" )
i = mw.ustring.find( r, Sort.sepDec, 1, true )
if not i then
i = #r
end
move = move + i
end
if move < 0 then
move = move + 1
end
end
if args.pre and move then
move = move + mw.ustring.len( args.pre ) + 1
end
if move then
if move < 0 then
move = Sort.mpz * move
Cell = Cell or { }
Cell.css = Cell.css or { }
if not Sort.shift then
Sort.contLang = Sort.contLang or
mw.language.getContentLanguage()
if Sort.contLang:isRTL() then
Sort.shift = "right"
else
Sort.shift = "left"
end
Sort.shift = "padding-" .. Sort.shift
end
Cell.css[ Sort.shift ] = string.format( "%.2fem", move )
end
elseif args.pad then
factory( "sep" )
i = mw.ustring.find( r, Sort.sepDec, 1, true )
if i then
i = #r - i
shift = ""
else
i = 0
shift = Sort.sepDec
end
i = args.pad - i
if args.post then
i = i - mw.ustring.len( args.post ) - 1
end
if i > 0 then
shift = shift .. string.rep( "0", i )
e = mw.html.create( "span" )
:css( "visibility", "hidden" )
:wikitext( shift )
shift = tostring( e )
end
end
if Sort.cssNum then
if low or long or less then
r = fine( r, low, long, less )
end
end
if args.exp then
if Sort.cssNumExp then
r = finest( r, args.exp )
else
r, s = fined( r, args.exp )
e = mw.html.create( "sup" )
:wikitext( s )
r = string.format( "%s%c10%s", r, 183, tostring( e ) )
end
end
if args.pre or args.post 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 )
r = tostring( e )
end
if shift then
r = r .. shift
end
if args.pad or
args.pre or
( args.cell and
( args.lead or
low or
less or
long or
args.exp ) ) then
fore( args.n, args.exp )
end
return r
end -- format()
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
-- .exp -- number|string, for exponent
-- .post -- string, for postfix
-- .round -- number|string, for rounding
-- .cell -- string|boolean|table, enforce sort
-- .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
-- .frame -- table, if present
-- Postcondition:
-- Returns string, or expands .cell
local r
Cell = false
if type( args ) == "table" then
local present = { }
local s = type( args.n )
if type( args.frame ) == "table" then
Sort.frame = args.frame
end
if s == "string" then
present.n = flat( args.n, true )
elseif s == "number" then
present.n = args.n
end
if present.n then
s = type( args.exp )
if s == "string" then
present.exp = flat( args.exp )
elseif s == "number" then
present.exp = args.exp
end
s = type( args.style )
if s == "string" then
features( args.style )
elseif s == "table" then
Cell = { }
Cell.css = args.style
end
face( "class", args.class )
face( "id", args.id )
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
if type( args.pre ) == "string" then
s = mw.text.trim( args.pre )
if s ~= "" then
present.pre = s
end
end
if type( args.post ) == "string" then
s = mw.text.trim( args.post )
if s ~= "" then
present.post = s
end
end
s = type( args.cell )
if s == "string" then
present.cell = ( args.cell == "1" )
elseif s == "boolean" or s == "table" then
present.cell = args.cell
end
s = type( args.plus )
if s == "string" then
present.lead = ( args.plus == "1" or args.plus == "+" )
elseif s == "boolean" then
present.lead = args.plus
end
if present.lead and present.n < 0 then
present.lead = false
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 )
if Cell then
s = type( present.cell )
if s == "boolean" then
r = facing( r )
elseif s == "table" then
facing( present.cell )
present.cell:wikitext( r )
else
local e = mw.html.create( "span" )
:wikitext( r )
facing( e )
r = tostring( e )
end
elseif type( present.cell ) == "table" then
present.cell:wikitext( r )
end
else
local e = mw.html.create( "span" )
:addClass( "error" )
:wikitext( "???" )
r = tostring( e )
if type( present.cell ) == "table" then
present.cell:wikitext( r )
end
end
end
return r
end -- Sort.f()
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.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