Modul:Sort/cellDate
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-04-04
)local Sort = { suite = "Sort",
sub = "cellDate",
serial = "2020-04-04",
item = 0,
globals = { DateTime = 20652535 } }
--[=[
Sort/cellDate -- support table cells with sortable date and time
]=]
local Failsafe = Sort
local GlobalMod = Sort
local Cell
Sort.mpz = 0.5
Sort.maxYear = 2099
Sort.similar = mw.ustring.char( 8776 ) -- ~~
Sort.supreme = mw.ustring.char( 8734 ) -- infinit
Sort.types = { "date",
"time",
"isoDate",
"usLongDate" }
Sort.weights = { }
Sort.weights.en = {
[true] = Sort.similar .. "abeus",
["before"] = 3,
["begin"] = 4,
["begin of"] = 4,
["beginning"] = 4,
["beginning of"] = 4,
["since"] = 6,
["until"] = 7,
["end of"] = 8,
["after"] = 9,
["about"] = true,
[Sort.similar] = true
}
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 facility = function ()
-- Retrieve page or project language
-- Postcondition:
-- Returns string, downcased
Sort.contLang = Sort.contLang or
mw.language.getContentLanguage()
return Sort.contLang:getCode():lower()
end -- facility()
local facing = function ( append )
-- Prepend preceding attributes
-- Precondition:
-- append -- string|html|nil, thing to be extended
-- Postcondition:
-- Returns string, if append is a string or empty
-- otherwise html is extended
local r
if Cell then
if type( append ) == "table" then
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
else
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
if append then
r = "| " .. append
else
r = "|"
end
for k, v in pairs( Cell ) do
r = string.format( " %s=\"%s\"%s", k, v, r )
end -- for k, v
r = r:sub( 2 )
end
else
r = append
end
return r
end -- facing()
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 fold = function ( access, alien, assign )
-- Retrieve config table
-- Precondition:
-- access -- string, external table
-- alien -- string, language code
-- assign -- string, local table
-- Postcondition:
-- Returns table, or not
local r
Sort[ assign ] = Sort[ assign ] or { }
if type( Sort[ assign ][ alien ] ) == "nil" then
local data = foreignModule( "DateTime", false, "local" )
if data and
type( data[ access ] ) == "table" then
Sort[ assign ][ alien ] = data[ access ][ alien ]
else
Sort[ assign ][ alien ] = false
end
end
if type( Sort[ assign ][ alien ] ) == "table" then
r = Sort[ assign ][ alien ]
end
return r
end -- fold()
local following = function ()
-- Retrieve text order
-- Postcondition:
-- Returns true, if left-to-right
if type( Sort.ltr ) ~= "boolean" then
Sort.contLang = Sort.contLang or
mw.language.getContentLanguage()
Sort.ltr = not Sort.contLang:isRTL()
end
return Sort.ltr
end -- following()
local fore = function ( args )
-- Create and merge sort attribute
-- Precondition:
-- args -- table, parameters
-- .d -- table, with date
-- .infinit -- number|nil, out of ages, +/-1
-- .pre -- string|false, for prefix
-- .type -- string|false, for sorting
-- Postcondition:
-- attributes extended
local d = { lang = args.d.lang }
local latest, least, s
if args.pre then
local weights = fold( "sortWeights", d.lang, "weights" )
local i
if weights then
i = weights[ args.pre ]
if type( i ) == "number" then
if i < 7 then
least = true
else
latest = true
end
end
end
end
if args.type == "time" then
if args.d.hour then
d.hour = args.d.hour
elseif least then
d.hour = 0
elseif latest then
d.hour = 24
else
d.hour = 12
end
if args.d.min then
d.min = args.d.min
elseif least then
d.min = 0
elseif latest then
d.min = 59
else
d.min = 30
end
if args.d.sec then
d.sec = args.d.sec
elseif least then
d.sec = 0
elseif latest then
d.sec = 59
else
d.sec = 30
end
else
d.year = args.d.year or 0
if args.d.bc and args.type == "isoDate" then
d.year = 0
else
d.year = args.d.year or 0
end
if args.d.month then
d.month = args.d.month
elseif least then
d.month = 1
elseif latest then
d.month = 12
else
d.month = 6
end
if args.d.dom then
d.dom = args.d.dom
elseif least then
d.dom = 1
else
d.dom = tonumber( Sort.DateTime( d ):format( "t" ) )
if not latest then
d.dom = math.floor( 0.5 * d.dom )
end
end
end
d = Sort.DateTime( d )
if args.type == "isoDate" then
s = "c"
elseif args.type == "time" then
s = "H:i:s"
elseif args.type == "usLongDate" then
d.lang = "en"
s = "F j, Y H:i:s"
else
s = "j M Y"
end
if args.d.bc then
s = s:gsub( "Y", "-Y" )
end
s = d:format( s )
if args.infinit then
s = s:gsub( tostring( Sort.maxYear ), "9999" )
end
face( "data-sort-value", s )
end -- fore()
local format = function ( args )
-- Format visible date
-- Precondition:
-- args -- table, parameters
-- .d -- table, with date
-- .pattern -- string, with format
-- .pad -- boolean, for padding
-- .pre -- string, for prefix
-- .post -- string, for postfix
-- .type -- string, for sorting
-- Postcondition:
-- Returns string
local r, templates
if not args.d.lang then
args.d.lang = facility()
end
if args.pad and not args.pre then
local scheme = args.pattern
if scheme then
local templates = fold( "templates",
facility(),
"templates" )
if templates and
type( templates[ scheme ] ) == "table" and
type( templates[ scheme ].spec ) == "string" then
scheme = templates[ scheme ].spec
end
end
if scheme then
local lift
if args.type == "time" then
lift = ( scheme:sub( 1, 1 ) == "G" and
args.d.hour and
args.d.hour < 10 )
else
lift = ( scheme:sub( 1, 1 ) == "j" and
args.d.dom and
args.d.dom < 10 )
end
if lift then
Cell = Cell or { }
Cell.css = Cell.css or { }
if not Sort.shift then
if following() then
Sort.shift = "left"
else
Sort.shift = "right"
end
Sort.shift = "padding-" .. Sort.shift
end
Cell.css[ Sort.shift ] = string.format( "%.2fem",
Sort.mpz )
end
end
end
r = args.d:format( args.pattern or "*" )
if args.pre or args.post then
local e
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
return r
end -- format()
Sort.f = function ( args )
-- Create table cell start
-- Parameter:
-- args -- table, parameters
-- .d -- string|table, with date
-- .pattern -- string, with format
-- .lang -- string, for formatting
-- .pad -- boolean, for padding
-- .pre -- string, for prefix
-- .post -- string, for postfix
-- .cell -- table|nil, sort environment
-- .type -- string, for sorting mode
-- .class -- string, for cell attribute
-- .style -- string|table, for cell attribute
-- .id -- string, for cell attribute
-- .cat -- string|nil, for error category
-- .frame -- object, if present
-- Postcondition:
-- Returns string, or expands .cell
local r
Cell = false
if type( Sort.DateTime ) == "nil" then
local bib = foreignModule( "DateTime",
true,
false,
Sort.globals.DateTime )
if bib and type( bib.DateTime ) == "function" then
Sort.DateTime = bib.DateTime()
else
Sort.DateTime = false
end
end
if type( args ) == "table" and Sort.DateTime then
local present = { }
local s
if type( args.lang ) == "string" then
present.lang = mw.text.trim( args.lang )
else
present.lang = facility()
end
if type( args.d ) == "string" and
mw.ustring.find( args.d, Sort.supreme, 1, true ) then
s = mw.text.trim( args.d )
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 present.infinit then
present.d = { year = Sort.maxYear,
lang = present.lang }
if present.infinit > 0 then
present.d.month = 12
present.d.dom = 31
else
present.d.bc = true
present.d.month = 1
present.d.dom = 1
end
present.d = Sort.DateTime( present.d )
end
end
if not present.infinit then
local slim
if type( args.d ) == "string" then
slim = mw.text.trim( args.d )
if slim ~= "" then
present.d = slim
end
end
if type( args.pre ) == "string" then
slim = mw.text.trim( args.pre )
if slim ~= "" then
present.pre = slim
end
end
s = type( present.d )
if s == "string" and not present.pre then
local weights = fold( "sortWeights",
present.lang,
"weights" )
if weights and weights[ true ] then
local sw = weights[ true ]
if type( sw ) == "string" then
slim = mw.ustring.sub( present.d, 1, 1 )
slim = mw.ustring.lower( slim )
if mw.ustring.find( sw, slim, 1, true ) then
local n
for k, v in pairs( weights ) do
if type( k ) == "string" then
n = mw.ustring.len( k )
slim = mw.ustring.sub( present.d,
1,
n )
if slim == k then
present.pre = k
present.d = mw.text.trim(
mw.ustring.sub( present.d,
n + 1 ) )
break -- for k, v
end
end
end -- for k, v
end
end
end
end
if s == "string" then
if present.d == "" then
s = "now"
else
s = present.d
end
present.d = Sort.DateTime( s, args.lang )
elseif s ~= "table" then
present.d = Sort.DateTime( "now", args.lang )
end
end
if type( present.d ) == "table" then
if type( args.frame ) == "table" then
Sort.frame = Sort.frame or args.frame
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 )
if type( args.type ) == "string" then
local n
s = mw.text.trim( args.type )
n = #s
if n > 0 then
local sort
s = s:lower()
for i = 1, #Sort.types do
sort = Sort.types[ i ]:sub( 1, n ):lower()
if s == sort then
present.type = Sort.types[ i ]
break -- for i
end
end -- i = 1, #Sort.types
end
end
if not present.infinit then
if type( args.pre ) == "string" then
s = mw.text.trim( args.pre )
if s ~= "" then
present.pre = s
end
end
if type( args.pattern ) == "string" then
s = mw.text.trim( args.pattern )
if s ~= "" then
present.pattern = s:gsub( "\\ ", " " )
end
end
s = type( args.pad )
if s == "string" then
present.pad = ( args.pad == "1" )
elseif s == "boolean" then
present.pad = args.pad
end
if type( args.post ) == "string" then
s = mw.text.trim( args.post )
if s ~= "" then
present.post = s
end
end
r = format( present )
end
fore( present )
if type( args.cell ) == "table" then
facing( present.cell )
if not present.infinit then
present.cell:wikitext( r )
end
else
r = facing( r )
end
else
local e = mw.html.create( "span" )
:addClass( "error" )
:wikitext( "????" )
if type( args.cat ) == "string" then
e:wikitext( string.format( "[[Category:%s]]",
args.cat ) )
end
if type( args.cell ) == "table" then
present.cell:node( e )
else
r = tostring( e )
end
end
end
return r
end -- Sort.f()
Sort.furnish = function ()
-- Retrieve list of project prefixes
-- Postcondition:
-- Returns string -- with wikitext list
-- false -- if none
local r, weights
weights = fold( "sortWeights", facility(), "weights" )
if weights and weights[ true ] then
local order = { }
for k, v in pairs( weights ) do
if type( k ) == "string" then
table.insert( order, k )
end
end -- for k, v
table.sort( order )
for i = 1, #order do
if r then
r = r .. "\n"
else
r = ""
end
r = string.format( "%s* %s", r, order[ i ] )
end -- i = 1, #order
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.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.furnish = function ()
return Sort.furnish() or ""
end -- p.f
p.Sort = function ()
-- Module interface
return Sort
end
return p