Module:Item link: Difference between revisions
Jump to navigation
Jump to search
(Better handling for maps, which nearly always return multiple results when queried by name. Now uses the one from the most recent map series, regardless of whether it's drop enabled. This prevents item links from breaking when maps are removed from the Atlas.) |
No edit summary |
||
Line 67: | Line 67: | ||
if m_util.table.has_one_value(tpl_args, cfg.selectors, nil) and tpl_args.skip_query == nil then | if m_util.table.has_one_value(tpl_args, cfg.selectors, nil) and tpl_args.skip_query == nil then | ||
local tables = {'items | local tables = {'items'} | ||
local fields = { | local fields = { | ||
'items._pageName', | 'items._pageName', | ||
Line 80: | Line 80: | ||
} | } | ||
local query = { | local query = { | ||
groupBy = 'items._pageID', | groupBy = 'items._pageID', | ||
orderBy = ' | orderBy = 'items.drop_enabled DESC', | ||
} | } | ||
local search_param | local search_param | ||
Line 95: | Line 94: | ||
tables[#tables+1] = '_pageData' | tables[#tables+1] = '_pageData' | ||
fields[#fields+1] = '_pageData._pageNameOrRedirect' | fields[#fields+1] = '_pageData._pageNameOrRedirect' | ||
query.join = 'items._pageName = _pageData._pageNameOrRedirect' | |||
query.where = string.format( | query.where = string.format( | ||
'_pageData._pageName="%s"', | '_pageData._pageName="%s"', | ||
tpl_args.page | tpl_args.page | ||
) | ) | ||
search_param = 'page' | search_param = 'page' | ||
elseif tpl_args.item_name_exact then | elseif tpl_args.item_name_exact then | ||
Line 109: | Line 108: | ||
search_param = 'item_name_exact' | search_param = 'item_name_exact' | ||
else | else | ||
tables[#tables+1] = 'maps' | |||
tables[#tables+1] = 'map_series' | |||
-- Explicitly join name_list child table instead of using HOLDS | -- Explicitly join name_list child table instead of using HOLDS | ||
tables[#tables+1] = 'items__name_list' | tables[#tables+1] = 'items__name_list' | ||
query.join = 'items._ID = items__name_list._rowID, items._pageID = maps._pageID, maps.series = map_series.name' | |||
query.where = string.format( | query.where = string.format( | ||
'items__name_list._value="%s" AND items._pageNamespace IN (%s)', | 'items__name_list._value = "%s" AND items._pageNamespace IN (%s)', | ||
m_cargo.addslashes(tpl_args.item_name), | m_cargo.addslashes(tpl_args.item_name), | ||
m_item_util.get_item_namespaces{format = 'list'} | m_item_util.get_item_namespaces{format = 'list'} | ||
) | ) | ||
query. | query.orderBy = 'map_series.ordinal DESC, items.drop_enabled DESC' | ||
search_param = 'item_name' | search_param = 'item_name' | ||
end | end | ||
result = m_cargo.query(tables, fields, query) | |||
result = m_cargo.query( | |||
local err | local err | ||
if #result == 0 then | if #result == 0 then | ||
Line 166: | Line 162: | ||
end | end | ||
end | end | ||
if err ~= nil then | if err ~= nil then | ||
return err .. m_util.misc.add_category({i18n.categories.broken_item_links}) | return err .. m_util.misc.add_category({i18n.categories.broken_item_links}) | ||
end | end | ||
result = result[1] -- Use the first result | result = result[1] -- Use the first result | ||
else | else |
Revision as of 20:45, 15 January 2022
This module implements {{item link}} and facilitates the creation of item links.
The above documentation is transcluded from Module:Item link/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.
-------------------------------------------------------------------------------
--
-- Module:Item link
--
-- This module implements Template:Item link.
--
-- This is separate from the main item module for small speed ups. Those speed
-- ups are only sigificant if the module is called a lot of times (100+), in
-- tests this amounted to only a ~10% difference in page load times at best. It
-- should be noted those tests are difficult because of the large variance in
-- page load times.
-------------------------------------------------------------------------------
local getArgs = require('Module:Arguments').getArgs
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local m_item_util = require('Module:Item util')
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Item link')
-- 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:Item link/config/sandbox') or mw.loadData('Module:Item link/config')
local i18n = cfg.i18n
-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------
local p = {}
--
-- Template:Item link
--
function p.item_link (frame)
--[[
Creates a link to the item and displays the item info box on hover
on the link.
Examples
--------
= p.item_link{'Multistrike'}
= p.item_link{'Multistrike Support'}
]]
-- Get arguments:
local tpl_args = getArgs(frame, {
parentFirst = true,
removeBlanks = false,
})
frame = m_util.misc.get_frame(frame)
tpl_args.item_name = tpl_args.item_name or tpl_args[1]
tpl_args.name = tpl_args.name or tpl_args[2]
if m_util.table.has_all_value(tpl_args, cfg.selectors) and tpl_args.skip_query == nil then
error(i18n.errors.invalid_args)
end
tpl_args.large = m_util.cast.boolean(tpl_args.large)
local img
local result
if m_util.table.has_one_value(tpl_args, cfg.selectors, nil) and tpl_args.skip_query == nil then
local tables = {'items'}
local fields = {
'items._pageName',
'items.name',
'items.inventory_icon',
'items.html',
'items.alternate_art_inventory_icons',
'items.size_x',
'items.size_y',
'items.drop_enabled',
'items.class_id',
}
local query = {
groupBy = 'items._pageID',
orderBy = 'items.drop_enabled DESC',
}
local search_param
if tpl_args.metadata_id then
query.where = string.format(
'items.metadata_id="%s"',
tpl_args.metadata_id
)
search_param = 'metadata_id'
elseif tpl_args.page then
-- Join with _pageData in order to check for page redirect
tables[#tables+1] = '_pageData'
fields[#fields+1] = '_pageData._pageNameOrRedirect'
query.join = 'items._pageName = _pageData._pageNameOrRedirect'
query.where = string.format(
'_pageData._pageName="%s"',
tpl_args.page
)
search_param = 'page'
elseif tpl_args.item_name_exact then
query.where = string.format(
'items.name = "%s" AND items._pageNamespace IN (%s)',
m_cargo.addslashes(tpl_args.item_name_exact),
m_item_util.get_item_namespaces{format = 'list'}
)
search_param = 'item_name_exact'
else
tables[#tables+1] = 'maps'
tables[#tables+1] = 'map_series'
-- Explicitly join name_list child table instead of using HOLDS
tables[#tables+1] = 'items__name_list'
query.join = 'items._ID = items__name_list._rowID, items._pageID = maps._pageID, maps.series = map_series.name'
query.where = string.format(
'items__name_list._value = "%s" AND items._pageNamespace IN (%s)',
m_cargo.addslashes(tpl_args.item_name),
m_item_util.get_item_namespaces{format = 'list'}
)
query.orderBy = 'map_series.ordinal DESC, items.drop_enabled DESC'
search_param = 'item_name'
end
result = m_cargo.query(tables, fields, query)
local err
if #result == 0 then
-- No results found
err = m_util.misc.raise_error_or_return{
raise_required=true,
args=tpl_args,
msg=string.format(
i18n.errors.no_results,
search_param,
tpl_args[search_param]
)
}
elseif #result > 1 then
-- More than one result found
--
-- If results are all maps, use the one from the most recent map
-- series, regardless of whether it's drop enabled. Otherwise,
-- if only one of the results is drop enabled then use that one.
local map_count = 0
local drop_enabled_count = 0
for i, v in ipairs(result) do
if v['items.class_id'] == 'Map' then
map_count = map_count + 1
end
if m_util.cast.boolean(v['items.drop_enabled']) then
drop_enabled_count = drop_enabled_count + 1
end
end
if (map_count == 0 or map_count ~= #result) and drop_enabled_count ~= 1 then
err = m_util.misc.raise_error_or_return{
raise_required=true,
args=tpl_args,
msg=string.format(
i18n.errors.too_many_results,
search_param,
tpl_args[search_param]
)
}
end
end
if err ~= nil then
return err .. m_util.misc.add_category({i18n.categories.broken_item_links})
end
result = result[1] -- Use the first result
else
result = {
['items._pageName'] = tpl_args.page or tpl_args.name
}
end
for k, prop in pairs(cfg.parameters) do
if tpl_args[k] ~= nil then
result[prop] = tpl_args[k]
end
end
if tpl_args.image ~= nil then
if result['items.alternate_art_inventory_icons'] == nil then
return m_util.misc.raise_error_or_return{
raise_required=true,
args=tpl_args,
msg=string.format(
i18n.errors.alt_art_undefined,
result['items._pageName']
) .. m_util.misc.add_category({i18n.categories.broken_item_links})
}
end
result['items.alternate_art_inventory_icons'] = m_util.string.split(
result['items.alternate_art_inventory_icons'],
',%s*'
)
local index = tonumber(tpl_args.image)
if index ~= nil then
img = result['items.alternate_art_inventory_icons'][index]
else
-- offset 1 is needed
local suffix = string.len(' inventory icon.png') + 1
-- add an extra offset by 1 to account for the space
local prefix = string.len(string.sub(result['items.inventory_icon'], 1, -suffix)) + 2
for _, filename in ipairs(result['items.alternate_art_inventory_icons']) do
if string.sub(filename, prefix, -suffix) == tpl_args.image then
img = filename
break
end
end
end
if img == nil then
return m_util.misc.raise_error_or_return{
raise_required=true,
args=tpl_args,
msg=string.format(
i18n.errors.alt_art_invalid_index,
tpl_args.image, result['items._pageName']
) .. m_util.misc.add_category({i18n.categories.broken_item_links})
}
end
elseif result['items.inventory_icon'] ~= nil then
img = result['items.inventory_icon']
end
--
-- output
--
-- Maps have their main page on the item name now, link there instead.
-- Hopefully there are no maps with identical names besides the series.
local linked_page
if result['items.class_id'] == 'Map' and tpl_args.page == nil then
linked_page = tpl_args.link or tpl_args.item_name
else
linked_page = tpl_args.link or result['items._pageName']
end
local container = mw.html.create('span')
container:addClass('c-item-hoverbox')
if tpl_args.large then
container:addClass('c-item-hoverbox--large')
end
local activator = mw.html.create('span')
activator:addClass('c-item-hoverbox__activator')
if img and not tpl_args.large then
activator:wikitext(string.format('[[%s|16x16px|link=|alt=]]', img))
end
if #result['items.name'] > 0 then
activator:wikitext(string.format(
'[[%s|%s]]',
linked_page,
result['items.name'] or result['items._pageName']
)
)
end
local display = mw.html.create('span')
display:attr('class', 'c-item-hoverbox__display')
if result['items.html'] ~= nil then
display:wikitext(result['items.html'])
if img then
display:wikitext(string.format('[[%s|link=|alt=]]', img))
end
end
if img and tpl_args.large then
local width = tonumber(result['items.size_x']) or tonumber(tpl_args.width)
local height = tonumber(result['items.size_y']) or tonumber(tpl_args.height)
if width and height then
img = string.format(
'[[%s|%sx%spx|link=%s|alt=]]',
img,
width*cfg.image_size,
height*cfg.image_size,
linked_page
)
elseif width then
img = string.format(
'[[%s|%spx|link=%s|alt=]]',
img,
width*cfg.image_size,
linked_page
)
elseif height then
img = string.format(
'[[%s|x%spx|link=%s|alt=]]',
img,
height*cfg.image_size,
linked_page
)
else
img = string.format(
'[[%s|link=%s|alt=]]',
img,
linked_page
)
end
activator:wikitext(img)
end
container
:node(activator)
:node(display)
:done()
return tostring(container)
end
return p