モジュール:AutosortTable

--
AutosortTable: Creates a table which is automatically sorted

Usage: (Remove the hidden comments before use)


local _module = {}

_module.create = function(frame)

local args = frame.args

-- Named parameters

local class = args.class
local style = args.style
local sep = args.separator
local order = args.order
local desc = args.descending or ""
local nsort = args.numeric or ""
local hidden = args.hidden or ""
local header = args.header
local footer = args.footer
local colstyle = args.colstyle

-- Frequently-used functions

local strIndexOf = mw.ustring.find
local strSplit = mw.text.split
local strSub = mw.ustring.sub
local strTrim = mw.text.trim

local seplen = #sep
local nsortLookup, descLookup, hiddenLookup = {}, {}, {}

-- Create the table

local html = mw.html.create()
local htable = html:tag('table')
if class then htable:attr('class', class) end
if style then htable:attr('style', style) end

-- Parses a row string. The key paremter is used to assign a unique key to the result so that equal rows do not cause sort errors.
local parse = function(s, key)
local css
local firstSep = strIndexOf(s, sep, 1, true)
if firstSep == 1 then  -- no CSS
css = nil
s = strSub(s, seplen + 1, -1)
else   -- CSS before first separator
css = strSub(s, 1, firstSep - 1)
s = strSub(s, firstSep + seplen, -1)
end 

return { key = key, css = css, data = strSplit(s, sep, true) }
end

--
Writes a row to the table.
css: CSS to apply to the row.
data: The data (cells) of the row
_type: Can be 'header', 'footer' or nil.

local writeHtml = function(css, data, _type)
local row = htable:tag('tr')
if css then row:attr('style', strTrim(css)) end

for i, v in ipairs(data) do
if not hiddenLookupi then
local cell
if _type == 'header' then
-- Header: use the 'th' tag with scope="col"
cell = row:tag('th')
cell:attr('scope', 'col')
elseif _type == 'footer' then
-- Footer: Mark as 'sortbottom' so that it does not sort whe the table is made user-sortable
-- with the 'wikitable sortable' class
cell = row:tag('td')
cell:attr('class', 'sortbottom')
else
-- Ordinary cell
cell = row:tag('td')
local cellCss = colstyle and colstylei
if cellCss then cell:attr('style', strTrim(cellCss)) end   -- Apply the column styling, if necessary
end
cell:wikitext(strTrim(v))
end
end

return row
end

-- Parse the column styles
if colstyle then colstyle = parse(colstyle, -1).data end

-- Write the header first
if header then
local headerData = parse(header)
writeHtml(headerData.css, headerData.data, 'header')
end

-- Parse the data
local data = {}
for i, v in ipairs(frame.args) do datai = parse(v, i) end

order = strSplit(order, '%s*,%s*')
nsort = strSplit(nsort, '%s*,%s*')
desc = strSplit(desc, '%s*,%s*')
hidden = strSplit(hidden, '%s*,%s*')

for i, v in ipairs(order) do orderi = tonumber(v) end
for i, v in ipairs(nsort) do nsortLookuptonumber(v) or -1 = true end
for i, v in ipairs(desc) do descLookuptonumber(v) or -1 = true end
for i, v in ipairs(hidden) do hiddenLookuptonumber(v) or -1 = true end

--Sorting comparator function.
local sortFunc = function(a, b)
local ad, bd = a.data, b.data
for i = 1, #order do
local index = orderi
local ai, bi = adindex, bdindex
if nsortLookupindex then
-- Numeric sort. Find the first occurence of a number an use it. Decimal points are allowed. Scientific notation not supported.
ai = tonumber( (ai:find('.', 1, true) and ai:match('+-?%d*%.%d+') or ai:match('+-?%d+')) or 0 )
bi = tonumber( (bi:find('.', 1, true) and bi:match('+-?%d*%.%d+') or bi:match('+-?%d+')) or 0 )
end
if ai ~= bi then
if descLookupindex then return ai > bi else return ai < bi end
end
end
return a.key < b.key
end
table.sort(data, sortFunc)

-- Write the sorted data to the HTML output
for i, v in ipairs(data) do writeHtml(v.css, v.data, nil) end

-- Write the footer
if footer then
local footerData = parse(footer)
writeHtml(footerData.css, footerData.data, 'footer')
end

return tostring(html)

end

return _module