Module:Currency
Module documentation
This documentation is transcluded from Module:Currency/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:Currency/doc. [edit]
Module:Currency's function cell is invoked by Template:Currency cell.
Module:Currency's function main is invoked by Template:Currency.
Module:Currency requires Module:Yesno.
Module:Currency requires strict.
Module:Currency is required by
.require('strict')
local yesno = require('Module:Yesno')
local p = {}
local function parse_num(val)
if val == nil then
return nil
end
local x = tonumber(val)
if x ~= nil then
return x
end
x = tonumber((val:gsub(',', '')))
if x ~= nil then
return x
end
-- Try parsing as an expression if it wasn't a number
local status, parsed = pcall(mw.ext.ParserFunctions.expr, val)
if not status then
if parsed == '' then
-- Give a better error message than a blank string
parsed = ('Could not interpret "%s" as a number'):format(val)
end
error(parsed)
end
return tonumber(parsed) or 0
end
function p.main(frame)
local args = frame:getParent().args
return p.parse(args[1] or 0, args)
end
function p.parse(val, options)
options = options or {}
val = parse_num(val)
if val == nil then
return nil
end
local prefix = val < 0 and '-' or (yesno(options.force_sign) and (val == 0 and '±' or '+') or '')
-- Whether to show the sign on all components. For example,
-- {{Currency|-143|all_signs=yes}} would result in "-1 [[File:Silver]] -43 [[File:Copper]]"
local sign_all_components = yesno(options.all_signs) or false
local absVal = math.abs(val)
-- Control how zero value denominations are shown
-- With show_zeros=all, it will show all zero value denominations after
-- the first non-zero denomination
-- With show_zeros=none, it will not show any denomination that has zero value
-- With show_zeros=some (the default), it will show the zeros between
-- the largest and smallest denominations.
-- E.g., 4,000,002,000:
-- show_zeros=all: "4 [[File:Platinum]] 0 [[File:Gold]] 2 [[File:Silver]] 0 [[File:Copper]]"
-- show_zeros=none: "4 [[File:Platinum]] 2 [[File:Silver]]"
-- show_zeros=some: "4 [[File:Platinum]] 0 [[File:Gold]] 2 [[File:Silver]]"
options.show_zeros = (options.show_zeros or options.show_zeroes or ''):lower()
local show_all_zeros = options.show_zeros == 'all'
local show_no_zeros = (options.show_zeros == 'no' or options.show_zeros == 'none')
local show_some_zeros = not (show_all_zeros or show_no_zeros)
local output = mw.html.create('span')
:attr('data-sort-value', val)
:addClass('currency')
:css('text-wrap', 'nowrap')
local first_component = true
local divisor = 1000000000 -- Pieces of copper in a platinum
for i, denomination in ipairs{ 'Platinum', 'Gold', 'Silver', 'Copper' } do
local denomValue
if denomination == 'Copper' then
-- Round to 2 decimal places
denomValue = math.floor(absVal * 100 + 0.5) / 100
absVal = 0
else
denomValue = math.floor(absVal / divisor)
absVal = absVal % divisor
divisor = divisor / 1000
end
-- Show if non-zero, we are showing this zero, or if we got to the last component
-- and haven't output anything (for val == 0)
if denomValue ~= 0 or (show_all_zeros and not first_component) or (show_some_zeros and not first_component and absVal ~= 0) or (first_component and i == 4) then
if first_component then
first_component = false
else
-- Make sure there is a space between components
output:wikitext(' ')
if not sign_all_components then
prefix = ''
end
end
output:wikitext(('%s%s [[File:%s coin.png|link=|20px|%s]]'):format(prefix, denomValue, denomination, denomination))
end
end
return tostring(output)
end
function p.cell(frame)
local args = frame:getParent().args
return p._cell(args[1] or 0, args)
end
function p._cell(val, options)
options = options or {}
val = parse_num(val)
local prefix = val < 0 and '-' or (yesno(options.force_sign) and (val == 0 and '±' or '+') or '')
local absVal = math.abs(val)
local class = val == 0 and 'currency-zero' or (val > 0 and 'currency-pos' or 'currency-neg')
class = class .. ' currency-cell'
if options.extra_class then
class = class .. ' ' .. options.extra_class
end
-- Col/rowspan
local left_colspan = (tonumber(options.left_colspan or '0') or 0) + 1
local right_colspan = (tonumber(options.right_colspan or '0') or 0) + 1
local rowspan = tonumber(options.rowspan or '0') or 0
if left_colspan <= 1 then left_colspan = nil end
if right_colspan <= 1 then right_colspan = nil end
if rowspan <= 1 then rowspan = nil end
-- Sign style
-- {{sign=leading}} -> A new column in the front with the sign
-- {{sign=all}} -> All currency cells get the sign prepended as text
-- {{sign=first}} (default) -> Only the first cell with a value gets the sign
options.sign = (options.sign or ''):lower()
local sign_cell = options.sign == 'leading'
local sign_all_components = options.sign == 'all'
local sign_first = not (sign_cell or sign_all_components)
options.show_zeros = (options.show_zeros or options.show_zeroes or ''):lower()
local show_all_zeros = options.show_zeros == 'all'
local show_no_zeros = (options.show_zeros == 'no' or options.show_zeros == 'none')
local show_some_zeros = not (show_all_zeros or show_no_zeros)
local output_cells = {}
local first_component = true
local divisor = 1000000000 -- Pieces of copper in a platinum
-- Padding cell on the left
table.insert(output_cells, {
style = {
['border-right'] = 'none',
['width'] = '0',
['padding-right'] = '0'
},
attributes = {
['data-sort-value'] = tostring(val),
colspan = left_colspan,
rowspan = rowspan
},
content = ''
})
-- Convert the padding cell into the sign cell
if sign_cell then
output_cells[1].style['text-align'] = 'center'
output_cells[1].style['padding-right'] = nil
output_cells[1].content = prefix
prefix = ''
end
for i, denomination in ipairs{ 'Platinum', 'Gold', 'Silver', 'Copper' } do
local denomValue
if denomination == 'Copper' then
-- Round to 2 decimal places
denomValue = math.floor(absVal * 100 + 0.5) / 100
absVal = 0
else
denomValue = math.floor(absVal / divisor)
absVal = absVal % divisor
divisor = divisor / 1000
end
local value = {
style = {
['border-left'] = 'none',
['border-right'] = 'none',
['text-align'] = 'right',
['width'] = '0'
},
content = '',
attributes = {
rowspan = rowspan
}
}
local coin = {
style = {
['border-left'] = 'none',
['border-right'] = 'none',
['text-align'] = 'center',
['width'] = '0'
},
content = '',
attributes = {
rowspan = rowspan
}
}
-- Show if non-zero, we are showing this zero, or if we got to the last component
-- and haven't output anything (for val == 0)
if denomValue ~= 0 or (show_all_zeros and not first_component) or (show_some_zeros and not first_component) or (first_component and i == 4) then
-- This is a "hidden" trailing zero, and will only show if any other row contains this component
local hidden_trailing_zero = denomValue == 0 and show_some_zeros and not first_component and absVal == 0
if first_component then
first_component = false
-- For the first component, merge it into the left cell if it is
-- an empty image (i.e, not the first), so any leading sign
-- won't artifically widen the column
if i ~= 1 then
table.remove(output_cells)
value.attributes.colspan = '2'
value.style['padding-left'] = '0'
end
elseif not sign_all_components then
prefix = ''
end
value.content = prefix..tostring(denomValue)
coin.content = ('[[File:%s coin.png|link=|20px|%s]]'):format(denomination, denomination)
coin.style['padding-left'] = '0'
coin.style['padding-right'] = '0'
--[[
Extremely disgusting hack to make this work.
Each "hidden trailing zero" td will have width = 0, meaning
the column overall will have zero width. There will be
a 0 in this cell which is entirely in the overflow, which is
hidden.
*But* if there is at least one row with this column (e.g.,
another cell has a copper=1, when this cell is silver=1 with
no copper), then the zero will no longer overflow because the
entire column will have width.
The span has to be positioned on the very right of the td,
but the zero has to be to the left of the span (the
transform:translateX(-1em))
]]--
if hidden_trailing_zero then
value.style.overflow = 'hidden'
value.style.padding = '0'
coin.style.overflow = 'hidden'
local value_width = '1'
if prefix ~= '' then
value_width = '1.25'
end
value.content = '<span style="width:0;display:block;text-align:right;position:absolute;right:0;transform:translate(-'..value_width..'em, -0.75em)">'..value.content..'</span>'
value.style.position = 'relative'
coin.content = '<span style="width:0;display:block">'..coin.content..'</span>'
end
else
value.style.padding = '0'
coin.style.padding = '0'
end
table.insert(output_cells, value)
table.insert(output_cells, coin)
end
-- One more cell for right padding
table.insert(output_cells, {
style = {
['border-left'] = 'none',
['padding-left'] = '0',
['width'] = '0'
},
attributes = {
rowspan = rowspan,
colspan = right_colspan
},
content = ''
})
if yesno(options.html) then
local output = mw.html.create()
for _, cell in ipairs(output_cells) do
output:tag('td')
:css(cell.style)
:addClass(class)
:wikitext(cell.content)
:attr(cell.attributes or {})
:done()
end
return output
end
local output = {}
for i, cell in ipairs(output_cells) do
if i ~= 1 then
table.insert(output, ' ||')
end
table.insert(output, (' class="%s" style="'):format(class))
for name, value in pairs(cell.style) do
table.insert(output, ('%s:%s;'):format(name, value))
end
table.insert(output, '" ')
for attr, value in pairs(cell.attributes or {}) do
table.insert(output, ('%s="%s" '):format(attr, value))
end
table.insert(output, ('|%s'):format(cell.content))
end
return table.concat(output, '')
end
return p