Permanently protected module

Difference between revisions of "Module:Item link"

From Path of Exile Wiki
Jump to: navigation, search
(Start using an explicit join to the list child table instead of using REGEXP)
(Translation strings moved to Module:Item link/config for easier porting.)
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')
 
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 = 'Pages with broken item links',
 
},
 
errors = {
 
invalid_args = 'Item link: metadata_id, 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"',
 
},
 
}
 
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
 
-- Invokable 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 = {'metadata_id', 'page', 'item_name', 'item_name_exact'}
 
 
-- ----------------------------------------------------------------------------
 
-- Invokable code
 
-- ----------------------------------------------------------------------------
 
   
 
--
 
--
 
-- Template:Item link
 
-- Template:Item link
 
--
 
--
local p = {}
 
 
 
function p.item_link (frame)
 
function p.item_link (frame)
 
--[[
 
--[[
Line 85: Line 54:
 
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 94: Line 63:
 
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 tables = { 'items' }
 
local query = {
 
local query = {
 
groupBy='items._pageID',
 
groupBy='items._pageID',
Line 113: Line 82:
 
else
 
else
 
if tpl_args.item_name ~= nil then
 
if tpl_args.item_name ~= nil then
-- explicitly join a copy of the list child's table to the parent
+
-- 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
+
-- instead of using HOLDS; we have to add one table & a join condition here
tables[#tables+1] = 'items__name_list'
+
tables[#tables+1] = 'items__name_list'
 
query.where = string.format(
 
query.where = string.format(
 
'items__name_list._value="%s"',
 
'items__name_list._value="%s"',
Line 137: Line 106:
 
 
 
result = m_cargo.query(
 
result = m_cargo.query(
tables,
+
tables,
 
{
 
{
 
'items._pageName',
 
'items._pageName',
Line 196: Line 165:
 
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 304: Line 273:
 
'[[%s|%sx%spx|link=%s|alt=]]',
 
'[[%s|%sx%spx|link=%s|alt=]]',
 
img,
 
img,
width*c.image_size,
+
width*cfg.image_size,
height*c.image_size,
+
height*cfg.image_size,
 
linked_page
 
linked_page
 
)
 
)
Line 312: Line 281:
 
'[[%s|%spx|link=%s|alt=]]',
 
'[[%s|%spx|link=%s|alt=]]',
 
img,
 
img,
width*c.image_size,
+
width*cfg.image_size,
 
linked_page
 
linked_page
 
)
 
)
Line 319: Line 288:
 
'[[%s|x%spx|link=%s|alt=]]',
 
'[[%s|x%spx|link=%s|alt=]]',
 
img,
 
img,
height*c.image_size,
+
height*cfg.image_size,
 
linked_page
 
linked_page
 
)
 
)

Revision as of 22:30, 16 May 2021

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

-- ----------------------------------------------------------------------------
-- Invokable 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)
    
    -- Backwards compability
    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 ~= nil then
            query.where = string.format(
                'items.metadata_id="%s"', 
                tpl_args.metadata_id
            )
        elseif tpl_args.page ~= nil then
            -- TODO returns the result even if the + format is specified. 
            query.where = string.format(
                'items._pageName="%s"', 
                tpl_args.page
            )
        else
            if tpl_args.item_name ~= nil then
                -- 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"', 
                    tpl_args.item_name
                )
                query.join = 'items._ID = items__name_list._rowID'
            elseif tpl_args.item_name_exact ~= nil then
                query.where = string.format(
                    'items.name = "%s"', 
                    tpl_args.item_name_exact
                )
            end
        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