Path of Exile Wiki

Please consider helping keep the wiki up to date. Check the to-do list of updates needed for version 3.14.0.

Game data exports will becoming later as the technical changes in addition to regular changes take some more time.

READ MORE

Path of Exile Wiki
(Cargo port)
(Page names and item names can contain double quotes, so we must escape them with backslashes)
 
(22 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
-------------------------------------------------------------------------------
-- Item link module
 
 
--
 
--
  +
-- Module:Item link
-- This is separate from the main item module for small speed ups.
 
 
--
 
--
  +
-- This module implements Template:Item link.
-- 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
 
 
-- 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
-- ----------------------------------------------------------------------------
 
-- Imports
 
-- ----------------------------------------------------------------------------
 
 
local m_util = require('Module:Util')
 
local m_util = require('Module:Util')
local getArgs = require('Module:Arguments').getArgs
+
local m_cargo = require('Module:Cargo')
   
  +
-- The cfg table contains all localisable strings and configuration, to make it
-- ----------------------------------------------------------------------------
 
  +
-- easier to port this module to another wiki.
-- Strings
 
  +
local cfg = mw.loadData('Module:Item link/config')
-- ----------------------------------------------------------------------------
 
  +
-- This section contains strings used by this module.
 
 
local i18n = cfg.i18n
-- Add new strings here instead of in-code directly, this will help other
 
-- people to correct spelling mistakes easier and help with translation to
 
-- other PoE wikis.
 
--
 
-- TODO: Maybe move this out to a separate sub-page module
 
local i18n = {
 
categories = {
 
-- maintenance cats
 
broken_item_links = '[[Category:Pages with broken item links]]',
 
},
 
errors = {
 
invalid_args = 'Item link: page, item_name or item_name_exact must be specified',
 
no_results = 'Item link: No results found for search parameter "%s".',
 
too_many_results = 'Item link: Too many results for search parameter "%s". Consider using page parameter instead.',
 
alt_art_undefined = 'Item link: Image parameter was specified, but there is no alternate art defined on page "%s"',
 
alt_art_invalid_index = 'Item Link: Alternate art with index/name "%s" not found on page "%s"',
 
},
 
}
 
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
  +
-- Exported functions
-- Constants & Data
 
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
   
local c = {}
+
local p = {}
c.image_size = 39
 
c.image_size_full = c.image_size * 2
 
c.parameters = {
 
name = 'items.name',
 
inventory_icon = 'items.inventory_icon',
 
html = 'items.html',
 
width = 'items.size_x',
 
height = 'items.size_y',
 
}
 
 
c.selectors = {'page', 'item_name', 'item_name_exact'}
 
 
-- ----------------------------------------------------------------------------
 
-- Invokable code
 
-- ----------------------------------------------------------------------------
 
   
 
--
 
--
-- Template:Item link & Template:Sl
+
-- Template:Item link
 
--
 
--
local p = {}
 
 
 
function p.item_link (frame)
 
function p.item_link (frame)
--
+
--[[
  +
Creates a link to the item and displays the item info box on hover
-- Args/Frame
 
--
+
on the link.
 
 
  +
Examples
  +
--------
  +
= p.item_link{'Multistrike'}
  +
= p.item_link{'Multistrike Support'}
 
 
]]
 
  +
-- Get arguments:
 
local tpl_args = getArgs(frame, {
 
local tpl_args = getArgs(frame, {
 
parentFirst = true,
 
parentFirst = true,
Line 72: Line 50:
 
frame = m_util.misc.get_frame(frame)
 
frame = m_util.misc.get_frame(frame)
 
 
-- Backwards compability
 
 
tpl_args.item_name = tpl_args.item_name or tpl_args[1]
 
tpl_args.item_name = tpl_args.item_name or tpl_args[1]
if tpl_args.item_name ~= nil then
 
tpl_args.item_name = mw.ustring.lower(tpl_args.item_name)
 
end
 
 
tpl_args.name = tpl_args.name or tpl_args[2]
 
tpl_args.name = tpl_args.name or tpl_args[2]
 
 
if m_util.table.has_all_value(tpl_args, c.selectors) and tpl_args.skip_query == nil then
+
if m_util.table.has_all_value(tpl_args, cfg.selectors) and tpl_args.skip_query == nil then
 
error(i18n.errors.invalid_args)
 
error(i18n.errors.invalid_args)
 
end
 
end
Line 88: Line 62:
 
local result
 
local result
 
 
if m_util.table.has_one_value(tpl_args, c.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 query = {
 
local query = {
 
groupBy='items._pageID',
 
groupBy='items._pageID',
 
}
 
}
+
if tpl_args.metadata_id then
if tpl_args.page ~= nil then
+
query.where = string.format(
  +
'items.metadata_id="%s"',
-- TODO returns the result even if the + format is specified.
 
query.where = string.format('items._pageName="%s"', tpl_args.page)
+
tpl_args.metadata_id
 
)
 
elseif tpl_args.page then
 
-- TODO returns the result even if the + format is specified.
 
query.where = string.format(
  +
'items._pageName="%s"',
 
tpl_args.page
 
)
 
elseif tpl_args.item_name_exact then
  +
query.where = string.format(
  +
'items.name = "%s" AND items._pageNamespace = %i',
 
m_cargo.addslashes(tpl_args.item_name_exact),
  +
cfg.primary_namespace
 
)
 
else
 
else
  +
-- explicitly join a copy of the list child's table to the parent
if tpl_args.item_name ~= nil then
 
  +
-- instead of using HOLDS; we have to add one table & a join condition here
query.where = string.format('items.name_list HOLDS "%s"', tpl_args.item_name)
 
  +
tables[#tables+1] = 'items__name_list'
elseif tpl_args.item_name_exact ~= nil then
 
query.where = string.format('items.name = "%s"', tpl_args.item_name_exact)
+
query.where = string.format(
  +
'items__name_list._value="%s" AND items._pageNamespace = %i',
end
 
+
m_cargo.addslashes(tpl_args.item_name),
if tpl_args.link_type == 'skill' then
+
cfg.primary_namespace
 
)
query[#query] = query[#query] .. ' [[Concept:Skill gems]]'
 
  +
query.join = 'items._ID = items__name_list._rowID'
end
 
 
end
 
end
 
 
if tpl_args.link_type == 'skill' then
 
if tpl_args.link_type == 'skill' then
query.where = string.format('%s AND (items.class == "Active Skill Gems" OR items.class == "Support Skill Gems")', query.where)
+
query.where = string.format(
  +
'%s AND (items.class = "Active Skill Gems" OR items.class = "Support Skill Gems")',
  +
query.where
  +
)
 
end
 
end
 
 
result = m_util.cargo.query(
+
result = m_cargo.query(
{
+
tables,
'items'
 
},
 
 
{
 
{
 
'items._pageName',
 
'items._pageName',
Line 124: Line 112:
 
'items.size_x',
 
'items.size_x',
 
'items.size_y',
 
'items.size_y',
  +
'items.drop_enabled',
 
'items.class_id',
 
},
 
},
 
query
 
query
Line 129: Line 119:
 
 
 
local err
 
local err
 
local j = 1
 
if #result == 0 then
 
if #result == 0 then
err = m_util.misc.raise_error_or_return{raise_required=true, args=tpl_args, msg=string.format(
+
err = m_util.misc.raise_error_or_return{
i18n.errors.no_results,
+
raise_required=true,
tpl_args.page or tpl_args.item_name or tpl_args.item_name_exact
+
args=tpl_args,
)}
+
msg=string.format(
  +
i18n.errors.no_results,
  +
tpl_args.page or tpl_args.item_name or tpl_args.item_name_exact
  +
)
  +
}
 
elseif #result > 1 then
 
elseif #result > 1 then
  +
-- If only one of the results is drop enabled then use that one:
err = m_util.misc.raise_error_or_return{raise_required=true, args=tpl_args, msg=string.format(
 
i18n.errors.too_many_results,
+
local n = 0
  +
for i,v in ipairs(result) do
tpl_args.page or tpl_args.item_name or tpl_args.item_name_exact
 
  +
if m_util.cast.boolean(v['items.drop_enabled']) then
)}
 
  +
j = i
  +
n = n+1
  +
end
  +
end
  +
  +
if n ~= 1 then
 
err = m_util.misc.raise_error_or_return{
  +
raise_required=true,
  +
args=tpl_args,
  +
msg=string.format(
  +
i18n.errors.too_many_results,
  +
tpl_args.page or tpl_args.item_name or tpl_args.item_name_exact
  +
)
  +
}
  +
end
 
end
 
end
 
 
 
if err ~= nil then
 
if err ~= nil then
return err .. i18n.categories.broken_item_links
+
return err .. m_util.misc.add_category({i18n.categories.broken_item_links})
 
end
 
end
 
 
result = result[1]
+
result = result[j]
 
else
 
else
result = {tpl_args.page or tpl_args.name}
+
result = {
  +
['items._pageName'] = tpl_args.page or tpl_args.name
  +
}
 
end
 
end
 
 
for k, prop in pairs(c.parameters) do
+
for k, prop in pairs(cfg.parameters) do
 
if tpl_args[k] ~= nil then
 
if tpl_args[k] ~= nil then
 
result[prop] = tpl_args[k]
 
result[prop] = tpl_args[k]
Line 157: Line 169:
 
 
 
if tpl_args.image ~= nil then
 
if tpl_args.image ~= nil then
if result['items.alternate_art_inventory_icons'] == '' 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(
+
return m_util.misc.raise_error_or_return{
i18n.errors.alt_art_undefined,
+
raise_required=true,
result['items._pageName']
+
args=tpl_args,
) .. i18n.categories.broken_item_links}
+
msg=string.format(
  +
i18n.errors.alt_art_undefined,
  +
result['items._pageName']
  +
) .. m_util.misc.add_category({i18n.categories.broken_item_links})
  +
}
 
end
 
end
 
 
result['items.alternate_art_inventory_icons'] = m_util.string.split(result['items.alternate_art_inventory_icons'], ',%s*')
+
result['items.alternate_art_inventory_icons'] = m_util.string.split(
  +
result['items.alternate_art_inventory_icons'],
  +
',%s*'
  +
)
 
 
 
local index = tonumber(tpl_args.image)
 
local index = tonumber(tpl_args.image)
Line 184: Line 203:
 
 
 
if img == nil then
 
if img == nil then
return m_util.misc.raise_error_or_return{raise_required=true, args=tpl_args, msg=string.format(
+
return m_util.misc.raise_error_or_return{
i18n.errors.alt_art_invalid_index,
+
raise_required=true,
tpl_args.image, result['items._pageName']
+
args=tpl_args,
) .. i18n.categories.broken_item_links}
+
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
 
end
elseif result['items.inventory_icon'] ~= '' then
+
elseif result['items.inventory_icon'] ~= nil then
 
img = result['items.inventory_icon']
 
img = result['items.inventory_icon']
 
end
 
end
 
 
  +
--
 
-- output
 
-- 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')
 
local container = mw.html.create('span')
 
container:addClass('c-item-hoverbox')
 
container:addClass('c-item-hoverbox')
  +
 
if tpl_args.large then
  +
container:addClass('c-item-hoverbox--large')
  +
end
 
 
 
local activator = mw.html.create('span')
 
local activator = mw.html.create('span')
Line 204: Line 242:
 
activator:wikitext(string.format('[[%s|16x16px|link=|alt=]]', img))
 
activator:wikitext(string.format('[[%s|16x16px|link=|alt=]]', img))
 
end
 
end
+
activator:wikitext(string.format('[[%s|%s]]', result['items._pageName'], result['items.name'] or result['items._pageName']))
+
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')
 
local display = mw.html.create('span')
 
display:attr('class', 'c-item-hoverbox__display')
 
display:attr('class', 'c-item-hoverbox__display')
   
if result['items.html'] ~= '' then
+
if result['items.html'] ~= nil then
 
display:wikitext(result['items.html'])
 
display:wikitext(result['items.html'])
 
 
Line 222: Line 267:
 
local height = tonumber(result['items.size_y']) or tonumber(tpl_args.height)
 
local height = tonumber(result['items.size_y']) or tonumber(tpl_args.height)
 
if width and height then
 
if width and height then
img = string.format('<br>[[%s|%sx%spx|link=%s|alt=]]', img, width*c.image_size, height*c.image_size, result['items._pageName'])
+
img = string.format(
  +
'[[%s|%sx%spx|link=%s|alt=]]',
  +
img,
  +
width*cfg.image_size,
  +
height*cfg.image_size,
  +
linked_page
  +
)
 
elseif width then
 
elseif width then
img = string.format('<br>[[%s|%spx|link=%s|alt=]]', img, width*c.image_size, result['items._pageName'])
+
img = string.format(
  +
'[[%s|%spx|link=%s|alt=]]',
  +
img,
  +
width*cfg.image_size,
  +
linked_page
  +
)
 
elseif height then
 
elseif height then
img = string.format('<br>[[%s|x%spx|link=%s|alt=]]', img, height*c.image_size, result['items._pageName'])
+
img = string.format(
  +
'[[%s|x%spx|link=%s|alt=]]',
  +
img,
  +
height*cfg.image_size,
  +
linked_page
  +
)
 
else
 
else
img = string.format('<br>[[%s|link=%s|alt=]]', img, result['items._pageName'])
+
img = string.format(
  +
'[[%s|link=%s|alt=]]',
  +
img,
  +
linked_page
  +
)
 
end
 
end
 
activator:wikitext(img)
 
activator:wikitext(img)

Latest revision as of 22:44, 8 July 2021

Template info icon Module documentation[view] [edit] [history] [purge]

The item module provides functionality for linking to items.

Overview

This module is responsible for {{Item link}} (({{Il}}) which create links to items exposed via cargo through Module:Item2.

Item templates

Module:Item2

All templates defined in Module:Item2:

Module:Item table

All templates defined in Module:Item table:

Module:Item link

All templates defined in Module:Item link:

Module:Item acquisition

-------------------------------------------------------------------------------
-- 
--                             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')

-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = 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 query = {
            groupBy='items._pageID',
        }
        if tpl_args.metadata_id then
            query.where = string.format(
                'items.metadata_id="%s"', 
                tpl_args.metadata_id
            )
        elseif tpl_args.page then
            -- TODO returns the result even if the + format is specified.
            query.where = string.format(
                'items._pageName="%s"', 
                tpl_args.page
            )
        elseif tpl_args.item_name_exact then
            query.where = string.format(
                'items.name = "%s" AND items._pageNamespace = %i', 
                m_cargo.addslashes(tpl_args.item_name_exact),
                cfg.primary_namespace
            )
        else
            -- explicitly join a copy of the list child's table to the parent
            -- instead of using HOLDS; we have to add one table & a join condition here
            tables[#tables+1] = 'items__name_list'
            query.where = string.format(
                'items__name_list._value="%s" AND items._pageNamespace = %i', 
                m_cargo.addslashes(tpl_args.item_name),
                cfg.primary_namespace
            )
            query.join = 'items._ID = items__name_list._rowID'
        end
        if tpl_args.link_type == 'skill' then
            query.where = string.format(
                '%s AND (items.class = "Active Skill Gems" OR items.class = "Support Skill Gems")', 
                query.where
            )
        end
        
        result = m_cargo.query(
            tables,
            {
                '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',
            },
            query
        )
        
        local err
        local j = 1
        if #result == 0 then
            err = m_util.misc.raise_error_or_return{
                raise_required=true, 
                args=tpl_args, 
                msg=string.format(
                    i18n.errors.no_results, 
                    tpl_args.page or tpl_args.item_name or tpl_args.item_name_exact 
                )
            }
        elseif #result > 1 then
            -- If only one of the results is drop enabled then use that one:
            local n = 0
            for i,v in ipairs(result) do 
                if m_util.cast.boolean(v['items.drop_enabled']) then
                    j = i
                    n = n+1
                end
            end
            
            if n ~= 1 then 
                err = m_util.misc.raise_error_or_return{
                    raise_required=true, 
                    args=tpl_args, 
                    msg=string.format(
                        i18n.errors.too_many_results,
                        tpl_args.page or tpl_args.item_name or tpl_args.item_name_exact
                    )
                }
            end 
        end
        
        if err ~= nil then
            return err .. m_util.misc.add_category({i18n.categories.broken_item_links})
        end
        
        result = result[j]
    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