Module:Data tables

--[[   Module for data tables

Attempts to create advanced infoboxes in a standardized way. ]]

local getArgs = require('Module:Arguments').getArgs local m_util = require('Module:Util') local m_cargo = require('Module:Cargo') local m_game = require('Module:Game') local f_infocard = require('Module:Infocard')._main local mw_language = mw.getLanguage('en')

local p = {}

-- Internationalization of public strings: local i18n = { character_class = { name = 'Name', id = 'Id', },   generic_stats = { name = 'Name', id = 'Id', str_id = 'Str_id', str = 'Strength', dex = 'Dexterity', int = 'Intelligence', stat_text = 'Text', value = 'Value', },   ascendancy_class = { name = 'Name', id = 'Id', flavour_text = 'Flavour text', character_id = 'Character id', character = 'Character', },   event = { name = 'Name', id = 'Id', type = 'Type', type_challenge = 'Challenge league', type_expansion = 'Expansion', type_pvp = 'PvP season', type_race = 'Race season', release_version = 'Release version', release_date = 'Release date', end_date = 'End date', standard = 'Standard', hardcore = 'Hardcore', ordinal = 'Ordinal number', short_name = 'Short name', match_challenge = 'league', match_expansion = 'Please, do not match this.', match_pvp = 'pvp season', match_race = 'race season', number_of_events = 'Number of events', price = 'Price', rewards = 'Rewards', links = 'Links', }, }

-- - -- Utility / Helper functions -- - local h = {}

function h.date(value, args) --[[   Format dates in correct and useable form.

Parameters --   value : String, required Date args : Table Table with extra formatting args.

To do: Remove hours if it isn't specified. ]]

local args = args or {}

-- List of allowed extra arguments: local arg_list = { format = { default = 'Y-m-d H:i:s', cargo  = 'Y-m-d H:i:s', no_time = 'Y-m-d', },   }

local date_format = arg_list['format']['default'] local timestamp = mw_language:formatDate(date_format, value)

-- If the time is 00:00:00 then assume that the time isn't defined: if mw_language:formatDate('H:i:s', timestamp) == '00:00:00' then date_format = arg_list['format']['no_time'] end

-- Add the extra arguments: for i,v in pairs(args) do       if i == 'format' then date_format = arg_list[i][v] end end

-- Return the final timestamp format: local out if value ~= nil then out = mw_language:formatDate(date_format, timestamp) end

return out end

function h.timezone(str) --   Check if the string contains Z at the end, if it does it implies    the time is in UTC and then return UTC.

local out = '' if str ~= nil and str:sub(-1,-1) == 'Z' then out = 'UTC' end

return out end

function h.cargo_query(tpl_args) --[[   Returns a Cargo query of all the results.

tpl_args should include these keys: tpl_args.tables tpl_args.fields tpl_args.q_*

]]

local tables = m_util.string.split(tpl_args.tables, ', ') local fields = m_util.string.split(tpl_args.fields, ', ')

-- Parse query arguments local query = { }   for key, value in pairs(tpl_args) do        if string.sub(key, 0, 2) == 'q_' then query[string.sub(key, 3)] = value end end

-- Query cargo rows: local results = m_cargo.query(tables, fields, query, args)

return results end

function h.parse_map(tpl_args, frame, tbldef) --[[       Parse the map

Input:

]]   local cargo_data = { _table = tbldef.table, }   for _, key in pairs(tbldef.parse_order) do        local data = tbldef.fields[key] local value if data.func ~= nil then if data.name then value = data.func(tpl_args, frame, tpl_args[data.name]) else value = data.func(tpl_args, frame) end else value = tpl_args[data.name] end

tpl_args[key] = value

if data.field ~= nil then if data.func_cargo then cargo_data[data.field] = data.func_cargo(tpl_args, frame) else cargo_data[data.field] = value end end end

local out = { tpl_args = tpl_args, cargo_data = cargo_data, }

return out end

h.parse_stat_args = function(tpl_args, args) --[[   Parse template args that starts with stat.+ and return them as a    array.

]]

out = {} for key, value in pairs(tpl_args) do       if string.sub(key, 0, 4) == 'stat' then local n,k = string.match(key, 'stat(%d+)_(.+)') n = tostring(n) if out[n] == nil then out[n] = {} end if n ~= nil and k ~= nil then out[n][k] = value else error(string.format( 'Wrong stat argument format. The template argument "%s" matched "%s" and "%s".', key or 'n/a', n or 'n/a', k or 'n/a' )               )            end end end

return out end

-- - -- Template: Generic stats -- -

local tables = { generic_stats = { table = 'generic_stats', order = {}, parse_order = {'name', 'id', 'stat_text', 'value'}, fields = { name = { name = 'name', field = 'name', type = 'String', wikitext = i18n.generic_stats.name, },           id = { name = 'row', field = 'id', type = 'String', wikitext = i18n.generic_stats.id, func = function(tpl_args, frame, value) return tpl_args.stats[value].id               end, },           stat_text = { name = 'row', field = 'stat_text', type = 'Wikitext', wikitext = i18n.generic_stats.stat_text, func = function(tpl_args, frame, value) return tpl_args.stats[value].stat_text end, },           value = { name = 'row', field = 'value', type = 'Integer', wikitext = i18n.generic_stats.value, func = function(tpl_args, frame, val) return tpl_args.stats[val].value end, },       },    }, }

-- Declare cargo table: p.declare_generic_stats = m_cargo.declare_factory{ data=tables.generic_stats, }

-- Attach cargo table: p.attach_generic_stats = m_cargo.attach_factory{ data=tables.generic_stats, }

p.store_data = m_cargo.store_from_lua{tables=tables, module='Data tables'}

-- -- Template: Character class -- - tables.character_classes = { table = 'character_classes', order = {'flavour_text'}, parse_order = {'name', 'flavour_text', 'id', 'str_id', 'str', 'dex', 'int'}, fields = { -- Header: name = { name = 'name', field = 'name', type = 'String', wikitext = i18n.character_class.name, },       -- Main text: flavour_text = { name = 'flavour_text', field = 'flavour_text', type = 'String', display = function(tpl_args, frame, value) return m_util.html.poe_color('unique', value) end, },       -- Fields only: id = { name = nil, field = 'id', type = 'Integer', wikitext = i18n.character_class.id, func = function(tpl_args, frame) return m_game.constants.characters[tpl_args.name].id           end, },       str_id = { name = nil, field = 'str_id', type = 'String', wikitext = i18n.character_class.str_id, func = function(tpl_args, frame) return m_game.constants.characters[tpl_args.name].str_id end, },       str = { name = nil, field = 'strength', type = 'String', wikitext = i18n.character_class.str, func = function(tpl_args, frame) return m_game.constants.characters[tpl_args.name].str end, },       dex = { name = nil, field = 'dexterity', type = 'String', wikitext = i18n.character_class.dex, func = function(tpl_args, frame) return m_game.constants.characters[tpl_args.name].dex end, },       int = { name = nil, field = 'intelligence', type = 'String', wikitext = i18n.character_class.int, func = function(tpl_args, frame) return m_game.constants.characters[tpl_args.name].int end, },   }, }

tables.character_classes_test = { table = 'character_classes_test', order = {}, parse_order = {'flavour_text_author'}, fields = { flavour_text_author = { name = nil, field = 'flavour_text_author', type = 'String', func = function(tpl_args, frame, value) return 'John (JD) Doe' end, },   }, }

tables.character_classes_test2 = { table = 'character_classes_test2', order = {}, parse_order = {'flavour_text_author'}, fields = { flavour_text_author = { name = nil, field = 'flavour_text_author', type = 'String', func = function(tpl_args, frame, value) return 'Jane Smith' end, },   }, }

-- Declare cargo table: p.declare_character_classes = m_cargo.declare_factory{data=tables.character_classes} p.declare_character_classes_test = m_cargo.declare_factory{data=tables.character_classes_test} p.declare_character_classes_test2 = m_cargo.declare_factory{data=tables.character_classes_test2}

-- Attach cargo table: p.attach_character_classes = m_cargo.attach_factory{data=tables.character_classes} p.attach_character_classes_test = m_cargo.attach_factory{data=tables.character_classes_test} p.attach_character_classes_test2 = m_cargo.attach_factory{data=tables.character_classes_test2}

function p.character_class(frame) --[[   Displays a infobox and stores cargo data for character classes.

Examples: = p.character_class{ name='Marauder', flavour_text='testing' }   ]]

-- Get template args: local tpl_args = getArgs(frame, {parentFirst = true}) local frame = m_util.misc.get_frame(frame)

-- Parse character map: local parsed_map = h.parse_map(tpl_args, frame, tables.character_classes) tpl_args = parsed_map.tpl_args local cargo_data = parsed_map.cargo_data

-- Store cargo fields: m_cargo.store(frame, cargo_data)

-- Parse and store character test maps: m_cargo.store(frame, h.parse_map(tpl_args, frame, tables.character_classes_test).cargo_data) m_cargo.store(frame, h.parse_map(tpl_args, frame, tables.character_classes_test2).cargo_data)

-- Main sections, loop through local tbl = mw.html.create('table') for _, key in ipairs(tables.character_classes.order) do       local data = tables.character_classes.fields[key]

if data.display == nil then text = tpl_args[key] else text = data.display(tpl_args, frame, tpl_args[key]) end

if text ~= nil then tbl :tag('tr') :tag('th') :wikitext(data.wikitext) :done :tag('td') :wikitext(text) :done :done elseif text then tbl :tag('tr') :tag('td') -- :attr('colspan', '2') :wikitext(text) :done :done end end

-- Output Infocard local infocard_args = { ['class'] = 'character_class', ['header'] = tpl_args.name, ['subheader'] = nil, [1] = string.format(           '',            tpl_args.name        ), [2] = tostring(tbl), }

-- Add categories: local cats = { 'Character classes' }

return f_infocard(infocard_args) .. m_util.misc.add_category(cats) end

-- - -- Template: Ascendancy Class -- -

tables.ascendancy_classes = { table = 'ascendancy_classes', order = {'flavour_text'}, parse_order = {'name', 'character', 'flavour_text', 'id', 'character_id'}, fields = { -- Header: name = { name = 'name', field = 'name', type = 'String', wikitext = i18n.ascendancy_class.name, },       -- Subheader: character = { name = nil, field = 'character_class', type = 'String', wikitext = i18n.ascendancy_class.character, func = function(tpl_args, frame, value) local id = m_game.constants.ascendancy[tpl_args.name].id               local character_id = m_game.constants.ascendancy[tpl_args.name].character

local character for i,v in pairs(m_game.constants.characters) do                   if v.id == character_id then character = i                       break end end

return character end, },       -- Main text: flavour_text = { name = 'flavour_text', field = 'flavour_text', type = 'String', display = function(tpl_args, frame, value) return m_util.html.poe_color('unique', value) end, },       -- Fields only: id = { name = nil, field = 'id', type = 'Integer', wikitext = i18n.ascendancy_class.id, func = function(tpl_args, frame, value) return m_game.constants.ascendancy[tpl_args.name].id           end, },       character_id = { name = nil, field = 'character_id', type = 'Integer', wikitext = i18n.ascendancy_class.character_id, func = function(tpl_args, frame, value) return m_game.constants.ascendancy[tpl_args.name].character end, },   }, }

-- Declare cargo table: p.declare_ascendancy_classes = m_cargo.declare_factory{data=tables.ascendancy_classes}

-- Attach cargo table: p.attach_ascendancy_classes = m_cargo.attach_factory{data=tables.ascendancy_classes}

function p.ascendancy_class (frame) --[[   Displays a infobox and stores cargo data for ascendancy classes.

Examples: = p.ascendancy_class{ name='Slayer', flavour_text='testing' }   ]]

-- Get template args: local tpl_args = getArgs(frame, {parentFirst = true}) local frame = m_util.misc.get_frame(frame)

-- Parse ascendancy map: local parsed_map = h.parse_map(tpl_args, frame, tables.ascendancy_classes) tpl_args = parsed_map.tpl_args local cargo_data = parsed_map.cargo_data

-- Store cargo fields: m_cargo.store(frame, cargo_data)

-- Main sections, loop through local tbl = mw.html.create('table') for _, key in ipairs(tables.ascendancy_classes.order) do       local data = tables.ascendancy_classes.fields[key]

if data.display == nil then text = tpl_args[key] else text = data.display(tpl_args, frame, tpl_args[key]) end

if text ~= nil then tbl :tag('tr') :tag('th') :wikitext(data.wikitext) :done :tag('td') :wikitext(text) :done :done elseif text then tbl :tag('tr') :tag('td') -- :attr('colspan', '2') :wikitext(text) :done :done end end

-- Output Infocard local infocard_args = { ['class'] = 'ascendancy_class', ['header'] = tpl_args.name, ['subheader'] = string.format('%s', tpl_args.character), [1] = string.format(           '',            tpl_args.name        ), [2] = tostring(tbl), }

-- Add categories: local cats = { 'Ascendancy classes', tpl_args.character .. ' ascendancy classes', }

return f_infocard(infocard_args) .. m_util.misc.add_category(cats) end

-- - -- Template: Event -- -

tables.events = { table = 'events', order = {'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'}, parse_order = {'id', 'name', 'short_name', 'type', 'ordinal', 'standard', 'hardcore', 'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'}, fields = { -- Header: name = { name = 'name', field = 'name', type = 'String', wikitext = i18n.event.name, },       -- Subheader: type = { name = 'type', field = 'type', type = 'String', wikitext = i18n.event.type, func = function(tpl_args, frame, value) local type_tbl = { challenge = i18n.event.type_challenge, expansion = i18n.event.type_expansion, pvp = i18n.event.type_pvp, race = i18n.event.type_race, }               return type_tbl[value] end, },       -- Main text: release_version = { name = 'release_version', field = 'release_version', type = 'String', wikitext = i18n.event.release_version, display = function(tpl_args, frame, value) if value ~= nil then return string.format('%s', value, value) end end, },       release_date = { name = 'release_date', field = 'release_date', type = 'Datetime', wikitext = i18n.event.release_date, cargo_func = function(tpl_args, frame, value) return h.date(value, {format='cargo'}) end, display = function(tpl_args, frame, value) local out if value ~= nil then out = string.format(                       '%s %s',                        h.date(value),                        h.timezone(value)                    ) end

return out end, },       end_date = { name = 'end_date', field = 'end_date', type = 'Datetime', wikitext = i18n.event.end_date, cargo_func = function(tpl_args, frame, value) return h.date(value, {format='cargo'}) end, display = function(tpl_args, frame, value) local out if value ~= nil then out = string.format(                       '%s %s',                        h.date(value),                        h.timezone(value)                    ) end

return out end, },       standard = { name = 'standard', field = 'is_standard', type = 'Boolean', wikitext = i18n.event.standard, func = function(tpl_args, frame, value) local bool_tbl = { ['false'] = 0, ['true'] = 1, }               return bool_tbl[string.lower(value or '')] end, },       hardcore = { name = 'hardcore', field = 'is_hardcore', type = 'Boolean', wikitext = i18n.event.hardcore, func = function(tpl_args, frame, value) local bool_tbl = { ['false'] = 0, ['true'] = 1, }               return bool_tbl[string.lower(value or '')] end,

},       number_of_events = { name = 'number_of_events', field = 'number_of_events', type = 'Integer', wikitext = i18n.event.number_of_events, },       rewards = { name = 'rewards', field = 'rewards', type = 'Wikitext', wikitext = 'Rewards', display = function(tpl_args, frame, value) local out if value ~= nil then out = string.format(                       ' %s ',                        value                    ) end return out end, },       price = { name = 'price', field = 'price', type = 'Wikitext', wikitext = i18n.event.price, },       links = { name = 'links', field = 'links', type = 'Wikitext', wikitext = i18n.event.links, },

-- Field calculations: id = { name = 'id', field = 'id', type = 'List of String', wikitext = i18n.event.id, },       short_name = { name = nil, field = 'short_name', type = 'String', wikitext = i18n.event.short_name, func = function(tpl_args, frame) local out = {} for i,v in pairs(tpl_args) do                   local match_tbl = { challenge = i18n.event.match_challenge, expansion = i18n.event.match_expansion, pvp = i18n.event.match_pvp, race = i18n.event.match_race, }                   for ii,vv in pairs(match_tbl) do                        if v==ii then out[#out+1] = tpl_args['name']:lower:gsub(vv, ''):gsub('^%l', string.upper) break end end end return table.concat(out, ', ') end, },       ordinal = { name = nil, field = 'ordinal', type = 'Integer', wikitext = i18n.event.ordinal, func = function(tpl_args, frame) tpl_args.tables = 'events' local count = string.format(                   'COUNT(DISTINCT %s._pageName)',                    tpl_args.tables                ) tpl_args.fields = count tpl_args.q_where = string.format(                   '%s.type = "%s" AND %s.release_date < "%s"',                    tpl_args.tables,                    tpl_args.type or ,                    tpl_args.tables,                    tpl_args.release_date or                 ) local results = h.cargo_query(tpl_args)

local out = 1 if #results > 0 then out = out + results[1][count] end

return out end, },   }, }

-- Declare cargo table: p.declare_events = m_cargo.declare_factory{data=tables.events}

-- Attach cargo table: p.attach_events = m_cargo.attach_factory{data=tables.events}

function p.event_box(tpl_args, frame) -- Main sections, loop through local tbl = mw.html.create('table') for _, key in ipairs(tables.events.order) do       local data = tables.events.fields[key]

if data.display == nil then text = tpl_args[key] else text = data.display(tpl_args, frame, tpl_args[key]) end

if text ~= nil then tbl :tag('tr') :tag('th') :wikitext(data.wikitext) :done :tag('td') :wikitext(text) :done :done elseif text then tbl :tag('tr') :tag('td') -- :attr('colspan', '2') :wikitext(text) :done :done end end

-- Output Infocard local infocard_args = { ['class'] = 'event', ['header'] = tpl_args.name, ['subheader'] = tpl_args.type, [1] = string.format(           '',            tpl_args.image or string.format('%s_logo.png', tpl_args.name)        ), [2] = tostring(tbl), }

return f_infocard(infocard_args) end

-- =p.event{name='Ascendancy', type = 'expansion', release_version = '2.2.0', release_date = '2016-03-04'} -- =p.event{name='Winterheart race season', type='race', release_version = '2.3.0', release_date='2016-01-29', end_date='2016-08-29T22:00:00Z', number_of_events='155', rewards="Asphyxia's Wrath Sapphire Ring The Whispering Ice Dyadian Dawn Call of the Brotherhood Winterheart", prize="Demigod's Dominance", links='Schedule and overview' } -- c=p.event{name='PvP season 2', type='pvp', release_date='2015-02-15', end_date='2015-03-16', rewards="Wanderlust Coral Ring Geofri's Baptism Kikazaru Meginord's Girdle Atziri's Foible", prize='Talisman of the Victor', links='EU PvP Ladder US PvP Ladder' } -- =p.event{name='Perandus league', type='challenge ', release_version = '2.2.0', release_date='2016-03-04', end_date='2016-05-30', standard = 'True', hardcore = 'True'}

function p.event(frame) --[[   Displays a infobox and stores data for various events such as    game expansions, leagues, races, pvp etc.

Examples:

]]   -- Get template args: local tpl_args = getArgs(frame, {parentFirst = true}) local frame = m_util.misc.get_frame(frame)

-- Parse event_map: local parsed_map = h.parse_map(tpl_args, frame, tables.events) tpl_args = parsed_map.tpl_args local cargo_data = parsed_map.cargo_data

-- Store cargo fields: m_cargo.store(frame, cargo_data)

-- Display infobox: local out = p.event_box(tpl_args, frame)

-- Add categories: local cats = { tpl_args.type .. 's', }

return out .. m_util.misc.add_category(cats) end

-- -

return p