Module:Version: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
(Translation strings moved to Module:Version/config. No globals. Use invoker factory from Module:Util.) |
||
Line 1: | Line 1: | ||
require('Module:No globals') | |||
local m_util = require('Module:Util') | local m_util = require('Module:Util') | ||
local m_cargo = require('Module:Cargo') | local m_cargo = require('Module:Cargo') | ||
local f_item_link = require('Module:Item link').item_link | local f_item_link = require('Module:Item link').item_link | ||
local cargo = mw.ext.cargo | local cargo = mw.ext.cargo | ||
local | -- Should we use the sandbox version of our submodules? | ||
local use_sandbox = m_util.misc.maybe_sandbox('Version') | |||
local | -- The cfg table contains all localisable strings and configuration, to make it | ||
-- easier to port this module to another wiki. | |||
local cfg = use_sandbox and mw.loadData('Module:Version/config/sandbox') or mw.loadData('Module:Version/config') | |||
local | local i18n = cfg.i18n | ||
-- --------------------------------------------------------------------- | -- --------------------------------------------------------------------- | ||
Line 40: | Line 21: | ||
local h = {} | local h = {} | ||
function h.cargo_query( | function h.cargo_query(args) | ||
--[[ | --[[ | ||
Returns a Cargo query of all the results. | Returns a Cargo query of all the results. | ||
args should include these keys: | |||
args.tables | |||
args.fields | |||
args.q_* | |||
]] | ]] | ||
local tables = m_util.string.split( | local tables = m_util.string.split(args.tables, ', ') | ||
local fields = m_util.string.split( | local fields = m_util.string.split(args.fields, ', ') | ||
-- Parse query arguments | -- Parse query arguments | ||
local query = { | local query = { | ||
} | } | ||
for key, value in pairs( | for key, value in pairs(args) do | ||
if string.sub(key, 0, 2) == 'q_' then | if string.sub(key, 0, 2) == 'q_' then | ||
query[string.sub(key, 3)] = value | query[string.sub(key, 3)] = value | ||
Line 92: | Line 73: | ||
}, | }, | ||
} | } | ||
local lang = mw.getContentLanguage() | |||
local date_format = arg_list['format']['default'] | local date_format = arg_list['format']['default'] | ||
local timestamp = | local timestamp = lang:formatDate(date_format, value) | ||
-- If the time is 00:00:00 then assume that the time isn't defined: | -- If the time is 00:00:00 then assume that the time isn't defined: | ||
if | if lang:formatDate('H:i:s', timestamp) == '00:00:00' then | ||
date_format = arg_list['format']['no_time'] | date_format = arg_list['format']['no_time'] | ||
end | end | ||
Line 111: | Line 93: | ||
local out | local out | ||
if value ~= nil then | if value ~= nil then | ||
out = | out = lang:formatDate(date_format, timestamp) | ||
end | end | ||
Line 117: | Line 99: | ||
end | end | ||
function h.validate_version(value) | |||
if value == nil then | if value == nil then | ||
return value | return value | ||
Line 131: | Line 107: | ||
end | end | ||
function h.show_date(args) | |||
return function( | return function(targs) | ||
local version = | local version = targs[args.key] | ||
local date = | local date = targs[string.format('%s_date', args.key)] | ||
if version and date then | if version and date then | ||
date = h.date(date) or '' | date = h.date(date) or '' | ||
if args.key == 'before' then | if args.key == 'before' then | ||
return | return string.format(i18n.show_date.before, version, version, date) | ||
elseif args.key == 'after' then | elseif args.key == 'after' then | ||
return | return string.format(i18n.show_date.after, version, version, date) | ||
end | end | ||
else | else | ||
Line 148: | Line 124: | ||
end | end | ||
-- ---------------------------------------------------------------------------- | |||
-- Cargo tables | |||
-- ---------------------------------------------------------------------------- | |||
local | local tables = {} | ||
tables.versions ={ | |||
table = 'versions', | table = 'versions', | ||
fields = { | fields = { | ||
Line 155: | Line 136: | ||
field = 'version', | field = 'version', | ||
type = 'String', | type = 'String', | ||
validate = validate_version, | validate = h.validate_version, | ||
}, | }, | ||
patchdate = { | patchdate = { | ||
Line 181: | Line 162: | ||
field = 'previous', | field = 'previous', | ||
type = 'String', | type = 'String', | ||
validate = validate_version, | validate = h.validate_version, | ||
show = show_date{key='before'}, | show = h.show_date{key='before'}, | ||
}, | }, | ||
after = { | after = { | ||
field = 'after', | field = 'after', | ||
type = 'String', | type = 'String', | ||
validate = validate_version, | validate = h.validate_version, | ||
show = show_date{key='after'}, | show = h.show_date{key='after'}, | ||
}, | }, | ||
}, | }, | ||
} | } | ||
-- ---------------------------------------------------------------------------- | |||
-- Main functions | |||
-- ---------------------------------------------------------------------------- | |||
local function _version(args) | |||
--[[ | --[[ | ||
This function creates a infobox and stores the data in a cargo table. | This function creates a infobox and stores the data in a cargo table. | ||
Line 208: | Line 191: | ||
--]] | --]] | ||
for k, data in pairs(tables.versions.fields) do | |||
for k, data in pairs( | |||
if data.validate ~= nil then | if data.validate ~= nil then | ||
args[k] = data.validate(args[k]) | |||
end | end | ||
end | end | ||
Line 219: | Line 199: | ||
-- Workaround for patchdate returning the string 'nil' when it's nil, | -- Workaround for patchdate returning the string 'nil' when it's nil, | ||
-- not sure if that's intentional: | -- not sure if that's intentional: | ||
if not | if not args.patch or not args.patchdate or args.patchdate == 'nil' then | ||
error(i18n.version.required_args) | error(i18n.version.required_args) | ||
end | end | ||
local version_parts = m_util.cast.version( | local version_parts = m_util.cast.version(args.patch, {return_type='table'}) | ||
args.major_part = tonumber(version_parts[1]) | |||
args.minor_part = tonumber(version_parts[2]) | |||
args.patch_part = tonumber(version_parts[3]) | |||
if version_parts[4] then | if version_parts[4] then | ||
args.revision_part = version_parts[4] | |||
end | end | ||
-- Check and set 'before' and 'after' | -- Check and set 'before' and 'after' args | ||
local edge_names = {'before', 'after'} | local edge_names = {'before', 'after'} | ||
for _, key in ipairs(edge_names) do | for _, key in ipairs(edge_names) do | ||
local v = | local v = args[key] | ||
if v then | if v then | ||
local results = cargo.query( | local results = cargo.query( | ||
Line 246: | Line 226: | ||
) | ) | ||
if #results == 1 then | if #results == 1 then | ||
args[string.format('%s_date', key)] = results[1]['versions.release_date'] | |||
elseif #results > 1 then | elseif #results > 1 then | ||
error(i18n.version.multiple_versions) | error(i18n.version.multiple_versions) | ||
Line 256: | Line 236: | ||
-- Set Cargo data | -- Set Cargo data | ||
local _properties = { | local _properties = { | ||
_table = | _table = tables.versions.table, | ||
} | } | ||
for key, data in pairs( | for key, data in pairs(tables.versions.fields) do | ||
if | if args[key] ~= nil then | ||
_properties[data.field] = | _properties[data.field] = args[key] | ||
end | end | ||
end | end | ||
Line 266: | Line 246: | ||
m_cargo.store(_properties) | m_cargo.store(_properties) | ||
mw.getCurrentFrame():expandTemplate{ | |||
title = 'Template:Version/cargo/versions/attach', | title = 'Template:Version/cargo/versions/attach', | ||
args = {} | args = {} | ||
Line 272: | Line 252: | ||
-- Generate output | -- Generate output | ||
local release_date = h.date( | local release_date = h.date(args.patchdate) | ||
local tbl = | local tbl = mw.html.create('table') | ||
tbl | tbl | ||
:addClass('wikitable successionbox') | :addClass('wikitable successionbox') | ||
Line 285: | Line 265: | ||
:tag('td') | :tag('td') | ||
:cssText('width: 30%') | :cssText('width: 30%') | ||
:wikitext( | :wikitext(tables.versions.fields.before.show(args)) | ||
:done() | :done() | ||
:tag('td') | :tag('td') | ||
:cssText('width: 40%') | :cssText('width: 40%') | ||
:wikitext( | :wikitext(string.format('<b>%s</b><br>%s', args.patch, release_date)) | ||
:done() | :done() | ||
:tag('td') | :tag('td') | ||
:cssText('width: 30%') | :cssText('width: 30%') | ||
:wikitext( | :wikitext(tables.versions.fields.after.show(args)) | ||
local cats = { | local cats = { | ||
Line 302: | Line 282: | ||
end | end | ||
local function _timeline(args) | |||
function | |||
--[[ | --[[ | ||
Add a timeline when versions or items were added to the game. | Add a timeline when versions or items were added to the game. | ||
Line 328: | Line 303: | ||
q_limit = 5000, | q_limit = 5000, | ||
} | } | ||
--]] | |||
-- Query results: | -- Query results: | ||
local results = h.cargo_query( | local results = h.cargo_query(args) | ||
-- Preallocate: | -- Preallocate: | ||
Line 417: | Line 386: | ||
end | end | ||
----- | -- ---------------------------------------------------------------------------- | ||
-- Exported functions | |||
-- ---------------------------------------------------------------------------- | |||
local p = {} | |||
p.table_versions = m_cargo.declare_factory{data=tables.versions} | |||
-- | |||
-- Template:Version | |||
-- | |||
p.version = m_util.misc.invoker_factory(_version, { | |||
parentFirst = true, | |||
}) | |||
-- | |||
-- Template:Timeline | |||
-- | |||
p.timeline = m_util.misc.invoker_factory(_timeline, { | |||
parentFirst = true, | |||
}) | |||
return p | return p |
Revision as of 16:39, 6 April 2024
The above documentation is transcluded from Module:Version/doc.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
require('Module:No globals')
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local f_item_link = require('Module:Item link').item_link
local cargo = mw.ext.cargo
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Version')
-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Version/config/sandbox') or mw.loadData('Module:Version/config')
local i18n = cfg.i18n
-- ---------------------------------------------------------------------
-- Helper functions
-- ---------------------------------------------------------------------
local h = {}
function h.cargo_query(args)
--[[
Returns a Cargo query of all the results.
args should include these keys:
args.tables
args.fields
args.q_*
]]
local tables = m_util.string.split(args.tables, ', ')
local fields = m_util.string.split(args.fields, ', ')
-- Parse query arguments
local query = {
}
for key, value in pairs(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)
return results
end
function h.date(value, args)
--[[
Format dates in correct and useable form.
Parameters
----------
value : String, required
Date
args : Table
Table with extra formatting args.
]]
local args = args or {}
-- List of allowed extra arguments:
local arg_list = {
format = {
default = 'F j, Y H:i:s',
cargo = 'Y-m-d H:i:s',
no_time = 'F j, Y',
},
}
local lang = mw.getContentLanguage()
local date_format = arg_list['format']['default']
local timestamp = lang:formatDate(date_format, value)
-- If the time is 00:00:00 then assume that the time isn't defined:
if lang: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 = lang:formatDate(date_format, timestamp)
end
return out
end
function h.validate_version(value)
if value == nil then
return value
else
return m_util.cast.version(value, {return_type='string'})
end
end
function h.show_date(args)
return function(targs)
local version = targs[args.key]
local date = targs[string.format('%s_date', args.key)]
if version and date then
date = h.date(date) or ''
if args.key == 'before' then
return string.format(i18n.show_date.before, version, version, date)
elseif args.key == 'after' then
return string.format(i18n.show_date.after, version, version, date)
end
else
return ''
end
end
end
-- ----------------------------------------------------------------------------
-- Cargo tables
-- ----------------------------------------------------------------------------
local tables = {}
tables.versions ={
table = 'versions',
fields = {
patch = {
field = 'version',
type = 'String',
validate = h.validate_version,
},
patchdate = {
field = 'release_date',
type = 'Datetime',
validate = tostring,
},
major_part = {
field = 'major_part',
type = 'Integer',
},
minor_part = {
field = 'minor_part',
type = 'Integer',
},
patch_part = {
field = 'patch_part',
type = 'Integer',
},
revision_part = {
field = 'revision_part',
type = 'String',
},
before = {
field = 'previous',
type = 'String',
validate = h.validate_version,
show = h.show_date{key='before'},
},
after = {
field = 'after',
type = 'String',
validate = h.validate_version,
show = h.show_date{key='after'},
},
},
}
-- ----------------------------------------------------------------------------
-- Main functions
-- ----------------------------------------------------------------------------
local function _version(args)
--[[
This function creates a infobox and stores the data in a cargo table.
Examples:
= p.version{
before = '2.4.1',
patch = '2.4.1b',
patchdate = 'October 18, 2016',
after = '2.4.2',
}
--]]
for k, data in pairs(tables.versions.fields) do
if data.validate ~= nil then
args[k] = data.validate(args[k])
end
end
-- Workaround for patchdate returning the string 'nil' when it's nil,
-- not sure if that's intentional:
if not args.patch or not args.patchdate or args.patchdate == 'nil' then
error(i18n.version.required_args)
end
local version_parts = m_util.cast.version(args.patch, {return_type='table'})
args.major_part = tonumber(version_parts[1])
args.minor_part = tonumber(version_parts[2])
args.patch_part = tonumber(version_parts[3])
if version_parts[4] then
args.revision_part = version_parts[4]
end
-- Check and set 'before' and 'after' args
local edge_names = {'before', 'after'}
for _, key in ipairs(edge_names) do
local v = args[key]
if v then
local results = cargo.query(
'versions',
'versions.release_date',
{
where=string.format('version="%s"', v),
-- Cargo bug work around
groupBy='versions._pageID',
}
)
if #results == 1 then
args[string.format('%s_date', key)] = results[1]['versions.release_date']
elseif #results > 1 then
error(i18n.version.multiple_versions)
end
end
end
-- Set Cargo data
local _properties = {
_table = tables.versions.table,
}
for key, data in pairs(tables.versions.fields) do
if args[key] ~= nil then
_properties[data.field] = args[key]
end
end
m_cargo.store(_properties)
mw.getCurrentFrame():expandTemplate{
title = 'Template:Version/cargo/versions/attach',
args = {}
}
-- Generate output
local release_date = h.date(args.patchdate)
local tbl = mw.html.create('table')
tbl
:addClass('wikitable successionbox')
:tag('tr')
:tag('th')
:attr('colspan', 3)
:wikitext(i18n.version.header)
:done()
:done()
:tag('tr')
:tag('td')
:cssText('width: 30%')
:wikitext(tables.versions.fields.before.show(args))
:done()
:tag('td')
:cssText('width: 40%')
:wikitext(string.format('<b>%s</b><br>%s', args.patch, release_date))
:done()
:tag('td')
:cssText('width: 30%')
:wikitext(tables.versions.fields.after.show(args))
local cats = {
i18n.categories.versions,
}
return tostring(tbl) .. m_util.misc.add_category(cats)
end
local function _timeline(args)
--[[
Add a timeline when versions or items were added to the game.
Examples:
= p.timeline{
tables = 'versions',
fields = 'versions.version, versions.release_date',
q_where = 'versions.version <> ""',
q_orderBy = 'versions.version DESC, versions.release_date ASC'
}
= p.timeline{
tables = 'versions, items',
fields = 'versions.version, versions.release_date, versions._pageName, items.class, items._pageName, items.name, items.release_version, items.inventory_icon, items.html',
q_join = 'versions.version=items.release_version',
q_where = 'versions.version IS NOT NULL AND items.release_version IS NOT NULL AND items.rarity = "Unique"',
q_orderBy = 'versions.version DESC, versions.release_date ASC, items.name ASC',
q_groupBy = 'versions._pageID, items.name',
q_limit = 5000,
}
--]]
-- Query results:
local results = h.cargo_query(args)
-- Preallocate:
local out = {}
local last_main_version
local last_minor_version
local current_version
local result_list
-- Loop through all the results from the query:
for i, result in ipairs(results) do
local release_version = result['versions.version']
local v = m_util.cast.version(release_version)
local version_h2 = table.concat({v[1], v[2]}, '.')
if release_version ~= last_minor_version then
if version_h2 ~= last_main_version then
if current_version ~= nil then
out[#out + 1] = tostring(current_version)
end
out[#out+1] = string.format(
'===%s %s===',
i18n.timeline.version,
table.concat({v[1], v[2], 0}, '.')
)
current_version = mw.html.create('ul')
end
current_version
:tag('li')
:wikitext(string.format(
'%s - [[%s %s]]',
h.date(result['versions.release_date']),
i18n.timeline.version,
release_version,
result['versions.version'])
)
result_list = current_version:tag('ol')
end
-- If the result has an item class, then add another list with
-- the results.
if result['items.class'] ~= nil then
-- result_list:tag('li'):wikitext(string.format('%s',
-- f_item_link{
-- page=result['items._pageName'],
-- name=result['items.name'],
-- inventory_icon=result['items.inventory_icon'] or '',
-- html=result['items.html'] or '',
-- skip_query=true
-- }
-- )
-- )
result_list:tag('li'):wikitext(string.format('[[%s]]',
result['items._pageName']
)
)
end
-- Save the last list:
if (i == #results) and (current_version ~= nil) then
out[#out + 1] = tostring(current_version)
end
last_main_version = version_h2
last_minor_version = release_version
end
-- Add categories:
local cats = {
i18n.categories.timelines,
}
return table.concat(out, '\n') .. m_util.misc.add_category(cats)
end
-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------
local p = {}
p.table_versions = m_cargo.declare_factory{data=tables.versions}
--
-- Template:Version
--
p.version = m_util.misc.invoker_factory(_version, {
parentFirst = true,
})
--
-- Template:Timeline
--
p.timeline = m_util.misc.invoker_factory(_timeline, {
parentFirst = true,
})
return p