Modul:DateTime/sort
Die Dokumentation für dieses Modul kann unter Modul:DateTime/sort/Doku erstellt werden
--[=[ 2015-08-05
Date and time utilities: Sort
]=]
-- local globals
local DateTime = false
local Invalid = "-199999999999999"
local Templates = { }
local World = { slang = "en",
sortPrefix = { },
sortSep = 46 }
World.sortPrefix.en = {
{ "before", 3 },
{ "begin", 4 },
{ "begin of", 4 },
{ "beginning", 4 },
{ "beginning of", 4 },
{ "since", 6 },
{ "until", 7 },
{ "end of", 8 },
{ "after", 9 },
{ "about", false }
}
local Span0 = "<span style='visibility:hidden;'>0</span>"
local function fault( alert )
-- Format error message by class=error
-- Parameter:
-- alert -- string, with error message
-- Returns:
-- string, with decorated error message
return string.format( "<span class=\"error\">%s</span>", alert )
end -- fault()
local function favorite( arg )
-- Test boolean template argument
-- Parameter:
-- arg -- string, trimmed, with switch, or nil
-- Returns:
-- boolean, true iff requested
local r = false
if arg then
if #arg > 0 then
r = ( arg ~= "0" )
end
end
return r
end -- favorite()
local function feed( alien )
-- Localize, if present
-- Parameter:
-- alien -- string, with language code, or nil
-- Returns:
-- table with sortPrefix, iff inital call
local r = false
if World.localized then
r = World.sortPrefix.en
else
local lucky, data = pcall( mw.loadData, "Module:DateTime/local" )
if lucky then
if alien then
World.slang = alien
elseif data.slang then
World.slang = data.slang
end
if data.sortPrefix and data.sortPrefix[ World.slang ] then
r = data.sortPrefix[ World.slang ]
end
if type(data.sortSep) == "number" then
World.sortSep = data.sortSep
end
end
if not r then
r = World.sortPrefix.en
end
World.localized = true
end
return r
end -- feed()
local function fetch( assign )
-- Retrieve instance
-- Returns:
-- DateTime prototype, or false
-- Throws:
-- error, if main module unavailable
local l, r = pcall( require, "Module:DateTime" )
if l then
r = r.DateTime()( assign )
else
error( fault( "Module:DateTime" ) )
end
return r
end -- fetch()
local function fiat()
-- Create sortkey from DateTime object
end -- fiat()
local function field( assign, amenable, args )
-- Combine data-sort-value, cell attributes and displayed data
-- Parameter:
-- assign -- string, sortkey
-- amenable -- string, displayed content
-- args -- table, possible attributes
-- -- align
-- -- class
-- -- id
-- -- style
-- Returns:
-- string with cell attributes and content
local start = string.format( "data-sort-value='%s'", assign )
local style
local stick
if args.align then
local expand = { c = "center",
l = "left",
r = "right",
center = "center",
left = "left",
right = "right" }
stick = expand[ args.align ]
if stick then
string.format( "text-align:%s", stick )
end
end
if args.style then
style = args.style
if stick then
style = string.format( "%s;%s", style, stick )
end
elseif stick then
style = stick
end
if style then
start = string.format( "%s style='%s'", start, style )
end
if args.class then
start = string.format( "%s class='%s'", start, args.class )
end
if args.id then
start = string.format( "%s id='%s'", start, args.id )
end
return string.format( "%s|%s", start, amenable )
end -- field()
local function figure( appoint, assign, align )
-- Create sortkey number from DateTime object
-- Parameter:
-- appoint -- table; valid DateTime object
-- assign -- digit, if adapting, or false
-- align -- true: leading zeros until 8 digits if positive
-- Returns:
-- string with number, or false
local r
local dom = appoint.dom
local month = appoint.month
local minor = 0
local start = false
if month then
if assign == 3 and not dom then
month = month - 1
end
else
if (assign == 8 or assign == 9) and not dom then
month = 99
else
month = 0
minor = 5
end
end
if dom then
if assign == 3 or assign == 4 then
dom = dom - 1
end
else
if assign == 8 or assign == 9 then
dom = 99
else
dom = 0
minor = 5
end
end
r = month * 100 + dom
if appoint.year then
r = appoint.year * 10000 + r
if align and appoint.year < 1000 and not appoint.bc then
if appoint.year < 100 then
if appoint.year < 10 then
start = "000"
else
start = "00"
end
else
start = "0"
end
end
elseif align then
if appoint.month and month < 10 and month > 0 then
start = "00000"
else
start = "0000"
end
end
if appoint.bc then
start = "-"
end
r = tostring( r )
if start then
r = start .. r
end
if assign then
minor = assign
end
if appoint.hour then
feed()
minor = minor + 100000 * appoint.hour
if appoint.min then
minor = minor + 1000 * appoint.min
if appoint.sec then
minor = minor + 10 * appoint.sec
end
end
r = string.format( "%s%c%07d",
r, World.sortSep, minor )
elseif minor > 0 then
feed()
r = string.format( "%s%c%d",
r, World.sortSep, minor )
end
return r
end -- figure()
local function flag( ahead, append )
-- Combine invisible sortkey with displayed data
-- Parameter:
-- ahead -- string, sortkey
-- append -- string, displayed content
-- Returns:
-- string with cell content
local s = "<span style='display:none' class='sortkey'>%s</span>%s"
return string.format( s, ahead, append )
end -- flag()
local function focus( analyse, assign )
-- Retrieve numeric sort value from date string
-- Parameter:
-- analyse -- string, with date; time may be appended
-- assign -- digit, if adapting, or false
-- Returns:
-- string with number, or false
local r = fetch( analyse )
if r then
r = figure( r, assign, true )
end
return r
end -- focus()
local function fore( analyse, alien )
-- Retrieve numeric sort value from probably prefixed string
-- Parameter:
-- analyse -- string, trimmed, for dating, letter at beginning
-- alien -- string, with language code, or nil
-- Returns:
-- string with number, or false
local prefix = feed( alien )
local sort = analyse:gsub( " ", " " )
:gsub( " ", " " )
:gsub( " ", " " )
local move = false
if prefix then
local lift = mw.ustring.match( analyse, "^%u" )
local n, scan
for k, v in pairs( prefix ) do
scan = v[ 1 ]
if lift then
scan = mw.ustring.upper( mw.ustring.sub( scan, 1, 1 ) )
.. mw.ustring.sub( scan, 2 )
end
n = mw.ustring.len( scan )
if mw.ustring.sub( sort, 1, n ) == scan then
sort = mw.text.trim( mw.ustring.sub( sort, n + 1 ) )
move = v[ 2 ]
break -- for k, v
end
end -- for k, v
end
return focus( sort, move )
end -- fore()
local function fruit( analyse, alien )
-- Retrieve numeric sort value
-- Parameter:
-- analyse -- string, trimmed, for dating
-- alien -- string, with language code, or nil
-- Returns:
-- string with number
local stamp = analyse:gsub( "{{0}}", "" )
local k = mw.ustring.codepoint( stamp, 1, 1 )
local r = false
if not k then -- analyse is empty
k = 48
stamp = "now"
end
if k == 45 then -- ASCII hyphen minus
if stamp:match( "^%-%d+$" ) then
r = stamp .. "0000"
end
elseif k >= 48 and k <= 57 then -- ASCII digit
r = focus( stamp, false )
elseif mw.ustring.match( stamp, "^%a" ) then -- any letter
r = fore( stamp, alien )
end
if type( r ) == "number" then
r = tostring( r )
elseif not r then
r = Invalid
end
return r
end -- fruit()
Templates.SD = function ( args, advanced )
-- Support Template:SD
-- Parameter:
-- args -- table, template parameters; each string or nil
-- 1 -- formatted date
-- align -- c l r
-- class
-- id
-- style
-- data-sort-type
-- advanced -- table, invoke parameters
-- cat -- category
-- Returns:
-- string, as template result; leading cell attributes
local show = args[ 1 ] or ""
local data = fetch( show )
local sort
if data then
sort = args[ "data-sort-type" ] or "text"
if sort == "text" then
sort = figure( data, false, true )
elseif sort == "number" then
sort = figure( data, false, false )
elseif sort == "isoDate" then
sort = data:format( "ISO" )
elseif sort == "date" then
sort = data:format( "data-sort-type:date" )
else
sort = figure( data, false, true )
end
else
sort = Invalid
show = show .. fault( "(?!)" )
if advanced.cat then
show = string.format( "%s[[Category:%s]]",
show, advanced.cat )
end
end
return field( sort, show, args )
end -- Templates.SD()
local function dts_dtsx( assigned, allow, append, appoint, alone )
-- Output of Templates:dts Templates:dtsx
-- Parameter:
-- assigned -- table, date object
-- allow -- any: permit break before year
-- append -- string with additional sorting information, or nil
-- appoint -- string with additional text to be shown, or nil
-- alone -- permit hour without minute
local opts = { london = true }
local show, sort, spec
if favorite( allow ) then
spec = "T._Mon4 JJJJ hh:mm:ss"
else
spec = "T._Mon4_JJJJ hh:mm:ss"
end
if alone then
opts.lonely = true
end
show = assigned:format( spec, opts )
if assigned.dom then
if assigned.dom < 10 then
show = Span0 .. show
end
end
if appoint then
show = string.format( "%s %s", show, appoint )
end
sort = figure( assigned, false, true )
if append then
sort = string.format( "%s %s", sort, append )
end
return flag( sort, show )
end -- dts_dtsx()
Templates.dts = function ( args )
-- Support Template:dts
-- Parameter:
-- args -- table, template parameters; each string or nil
-- 1 -- dom
-- 2 -- month, name, abbreviated name or number
-- 3 -- year, since 1
-- 4 -- time hh:mm:ss
-- u -- any: permit break before year
-- Returns:
-- string, as template result; leading sortkey
local r = args[ 4 ]
local live = r
local data
if not r then
r = false
end
data = fetch( r )
if data then
if args[ 1 ] then
data.dom = tonumber( args[ 1 ] )
live = true
end
r = args[ 2 ]
if r then
r = mw.text.trim( r )
if r:match( "^%d+$" ) then
data.month = tonumber( r )
live = true
else
data.lang = "de"
r = data:figure( r )
if r then
live = true
end
end
end
r = args[ 3 ]
if r and r:match( "^%s*-?%d+%s*$" ) then
r = tonumber( r )
if r < 0 then
data.bc = true
r = - r
end
data.year = r
live = true
end
else
live = false
end
if live then
r = dts_dtsx( data, args.u )
else
r = ""
end
return r
end -- Templates.dts()
Templates.dtsx = function ( args )
-- Support Template:dtsx
-- Parameter:
-- args -- table, template parameters; each string or nil
-- 1 -- dom
-- 2 -- month, number
-- 3 -- year, since 1
-- 4 -- hours
-- 5 -- minutes
-- 6 -- seconds
-- extra -- additional sorting information
-- u -- any: permit break before year
-- Returns:
-- string, as template result; leading sortkey
local data = fetch( false )
local r = args[ 2 ]
local lonely
local suffix
if r then
if r:match( "^%s*%d+%s*$" ) then
data.month = tonumber( r )
live = true
r = args[ 1 ]
if r and r:match( "^%s*%d+%s*$" ) then
data.dom = tonumber( r )
end
end
r = args[ 3 ]
if r and r:match( "^%s*%-?%d+%s*$" ) then
r = tonumber( r )
if r < 0 then
data.bc = true
r = - r
end
data.year = r
live = true
end
end
r = args[ 4 ]
if r then
if r:match( "^%s*%d+%s*$" ) then
data.hour = tonumber( r )
suffix = "Uhr"
live = true
r = args[ 5 ]
if r and r:match( "^%s*%d+%s*$" ) then
data.min = tonumber( r )
r = args[ 6 ]
if r and r:match( "^%s*%d+%s*$" ) then
data.sec = tonumber( r )
end
else
lonely = true
end
end
end
if live then
r = dts_dtsx( data, args.u, args.extra, suffix, lonely )
else
r = ""
end
return r
end -- Templates.dtsx()
Templates.SortDate = function ( args )
-- Support Template:dts
-- Parameter:
-- args -- table, template parameters; string or nil
-- 1 -- ISO-date, BC with leading hyphen
-- 2 -- F -- full month name
-- M -- 3-letter-abbr month
-- S -- 4 letter or abbr month
-- 2 or 3 -- nbsp -- no line break at year
-- sp -- permit break at year
-- 2, 3 or 4 -- link date
-- AT -- Austrian, if not empty
-- davor -- leading string displayed
-- Returns:
-- string, as template result; leading sortkey
local show = args[ 1 ]
local sort = Invalid
local start = args.davor
if show then
show = mw.text.trim( show )
if show ~= "" then
local data = fetch( false )
local live = false
local y, m, d
if ( mw.ustring.codepoint( show, 1, 1 ) == 45 ) then
show = show:sub( 2 )
data.bc = true
end
y, m, d = show:match( "^(%-?%d+)%-(%d+)%-(%d+)$" )
if y then
m = tonumber( m )
d = tonumber( d )
if m > 0 then
data.month = m
live = true
end
if d > 0 then
data.dom = d
live = true
end
else
y = show:match( "^(%-?%d+)$" )
end
if y then
y = tonumber( y )
if y < 0 then
data.bc = true
y = - y
end
if y > 0 then
data.year = y
live = true
end
end
if live then
local key = 2
local got = args[ key ]
local mode = 0
local lines, link
if got then
if got == "M" then
mode = 3
elseif got == "S" then
mode = 4
elseif got ~= "F" then
got = false
end
if got then
key = key + 1
end
got = args[ key ]
if got then
if got == "sp" then
lines = true
elseif got ~= "nbsp" then
got = false
end
if got then
key = key + 1
end
link = ( args[ key ] == "link" )
end
end
if data.month then
local lAT1 = ( data.month == 1 and
favorite( args.AT ) )
local score = data:full()
if mode == 0 then
if lAT1 then
show = "Jänner"
else
show = score
end
elseif mw.ustring.len( score ) > mode then
if lAT1 then
show = "Jän."
else
show = data:first()
end
else
show = score
mode = 0
end
if data.dom then
local lazy = ( link and mode == 0 )
show = string.format( "%d. %s",
data.dom, show )
if link then
if lazy then
show = string.format( "[[%s]]", show )
else
show = string.format( "[[%d. %s|%s]]",
data.dom, score,
show )
end
end
if data.dom < 10 then
show = Span0 .. show
end
end
if data.year then
if lines then
show = show .. " "
else
show = show .. " "
end
end
else
show = ""
end
if data.year then
local s = tostring( data.year )
if link then
show = string.format( "%s[[%s]]", show, s )
else
show = show .. s
end
if data.bc then
show = show .. " v. Chr."
end
end
sort = figure( data, false, true )
end
end
else
show = ""
end
if start then
if #start > 0 then
if #show > 0 then
show = " " .. show
end
show = start .. show
end
end
return flag( sort, show )
end -- Templates.SortDate()
-- Export
local p = { }
function p.f( frame )
local l, r = pcall( fruit,
mw.text.trim( frame.args[ 1 ] or "" ),
mw.text.trim( frame.args[ 2 ] or "de" ) )
return r
end -- p.f
function p.fruit( analyse, alien )
local l, r = pcall( fruit, analyse, alien )
return r
end -- p.fruit
function p.template( frame )
local r
local fun = frame.args[ 1 ]
if fun and Templates[ fun ] then
local l
l, r = pcall( Templates[ fun ],
frame:getParent().args,
frame.args )
else
r = "invalid template"
end
return r
end -- p.template
function p.test( apply, args, adjust )
local r
if apply and Templates[ apply ] then
local l
l, r = pcall( Templates[ apply ], args, adjust )
end
return r
end -- p.test
return p