Module:Item link: Difference between revisions

From Path of Exile Wiki
Jump to navigation Jump to search
(No globals.)
(Item query abstracted out to Module:Item util)
Line 57: Line 57:
     tpl_args.item_name = tpl_args.item_name or tpl_args[1]
     tpl_args.item_name = tpl_args.item_name or tpl_args[1]
     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, 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)
     tpl_args.large = m_util.cast.boolean(tpl_args.large)
      
      
     local img
     local img
     local result
     local result
    local search_param
     if 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
         tpl_args.fields = {
         local tables = {'items'}
             'items.name=name',
        local fields = {
             'items.inventory_icon=inventory_icon',
             'items._pageName',
             'items.html=html',
            'items.name',
             'items.alternate_art_inventory_icons=alternate_art_inventory_icons',
             'items.inventory_icon',
             'items.size_x=size_x',
             'items.html',
             'items.size_y=size_y',
             'items.alternate_art_inventory_icons',
             'items.size_x',
             'items.size_y',
            'items.drop_enabled',
            'items.class_id',
         }
         }
         local query = {
         tpl_args.error_category = i18n.categories.broken_item_links
            groupBy = 'items._pageID',
         result = m_item_util.query_item(tpl_args)
            orderBy = 'items.drop_enabled DESC',
         if result.error then
        }
             return result.error
        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'
        else
            tables[#tables+1] = 'maps'
            tables[#tables+1] = 'map_series'
            query.join = 'items._pageID = maps._pageID, maps.series = map_series.name'
            query.orderBy = 'map_series.ordinal DESC, items.drop_enabled DESC'
            if 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
                -- Explicitly join name_list child table instead of using HOLDS
                tables[#tables+1] = 'items__name_list'
                query.join = query.join .. ', items._ID = items__name_list._rowID'
                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'}
                )
                search_param = 'item_name'
            end
        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
         end
        result = result[1] -- Use the first result
     else
     else
         result = {
         result = {
             ['items._pageName'] = tpl_args.page or tpl_args.name
             ['_pageName'] = tpl_args.page or tpl_args.name
         }
         }
     end
     end
Line 182: Line 88:
      
      
     if tpl_args.image ~= nil then
     if tpl_args.image ~= nil then
         if result['items.alternate_art_inventory_icons'] == nil then
         if result['alternate_art_inventory_icons'] == nil then
             return m_util.misc.raise_error_or_return{
             return m_util.misc.raise_error_or_return{
                 raise_required=true,  
                 raise_required=true,  
Line 188: Line 94:
                 msg=string.format(
                 msg=string.format(
                     i18n.errors.alt_art_undefined,
                     i18n.errors.alt_art_undefined,
                     result['items._pageName']
                     result['_pageName']
                 ) .. m_util.misc.add_category({i18n.categories.broken_item_links})
                 ) .. m_util.misc.add_category({i18n.categories.broken_item_links})
             }
             }
         end
         end
          
          
         result['items.alternate_art_inventory_icons'] = m_util.string.split(
         result['alternate_art_inventory_icons'] = m_util.string.split(
             result['items.alternate_art_inventory_icons'],  
             result['alternate_art_inventory_icons'],  
             ',%s*'
             ',%s*'
         )
         )
Line 200: Line 106:
         local index = tonumber(tpl_args.image)
         local index = tonumber(tpl_args.image)
         if index ~= nil then
         if index ~= nil then
             img = result['items.alternate_art_inventory_icons'][index]
             img = result['alternate_art_inventory_icons'][index]
         else
         else
             -- offset 1 is needed
             -- offset 1 is needed
             local suffix = string.len(' inventory icon.png') + 1  
             local suffix = string.len(' inventory icon.png') + 1  
             -- add an extra offset by 1 to account for the space  
             -- add an extra offset by 1 to account for the space  
             local prefix = string.len(string.sub(result['items.inventory_icon'], 1, -suffix)) + 2
             local prefix = string.len(string.sub(result['inventory_icon'], 1, -suffix)) + 2
              
              
             for _, filename in ipairs(result['items.alternate_art_inventory_icons']) do
             for _, filename in ipairs(result['alternate_art_inventory_icons']) do
                 if string.sub(filename, prefix, -suffix) == tpl_args.image then
                 if string.sub(filename, prefix, -suffix) == tpl_args.image then
                     img = filename
                     img = filename
Line 221: Line 127:
                 msg=string.format(
                 msg=string.format(
                     i18n.errors.alt_art_invalid_index,
                     i18n.errors.alt_art_invalid_index,
                     tpl_args.image, result['items._pageName']
                     tpl_args.image, result['_pageName']
                 ) .. m_util.misc.add_category({i18n.categories.broken_item_links})
                 ) .. m_util.misc.add_category({i18n.categories.broken_item_links})
             }
             }
         end
         end
     elseif result['items.inventory_icon'] ~= nil then
     elseif result['inventory_icon'] ~= nil then
         img = result['items.inventory_icon']
         img = result['inventory_icon']
     end
     end
      
      
Line 236: Line 142:
     -- Hopefully there are no maps with identical names besides the series.
     -- Hopefully there are no maps with identical names besides the series.
     local linked_page = tpl_args.link
     local linked_page = tpl_args.link
     if result['items.class_id'] == 'Map' and m_util.table.contains({'item_name', 'item_name_exact'}, search_param) then
     if result['class_id'] == 'Map' and m_util.table.has_any_key(tpl_args, {'item_name', 'item_name_exact'}) then
         linked_page = linked_page or tpl_args[search_param]
         linked_page = linked_page or tpl_args.item_name_exact or tpl_args.item_name
     else
     else
         linked_page = linked_page or result['items._pageName']
         linked_page = linked_page or result['_pageName']
     end
     end
      
      
Line 256: Line 162:
     end
     end
      
      
     if #result['items.name'] > 0 then
     if #result['name'] > 0 then
         activator:wikitext(string.format(
         activator:wikitext(string.format(
             '[[%s|%s]]',  
             '[[%s|%s]]',  
             linked_page,  
             linked_page,  
             result['items.name'] or result['items._pageName']
             result['name'] or result['_pageName']
             )
             )
         )
         )
Line 268: Line 174:
     display:attr('class', 'c-item-hoverbox__display')
     display:attr('class', 'c-item-hoverbox__display')


     if result['items.html'] ~= nil then
     if result['html'] ~= nil then
         display:wikitext(result['items.html'])
         display:wikitext(result['html'])
              
              
         if img then
         if img then
Line 277: Line 183:


     if img and tpl_args.large then
     if img and tpl_args.large then
         local width = tonumber(result['items.size_x']) or tonumber(tpl_args.width)
         local width = tonumber(result['size_x']) or tonumber(tpl_args.width)
         local height = tonumber(result['items.size_y']) or tonumber(tpl_args.height)
         local height = tonumber(result['size_y']) or tonumber(tpl_args.height)
         if width and height then
         if width and height then
             img = string.format(
             img = string.format(

Revision as of 16:17, 18 January 2022

Module documentation[view] [edit] [history] [purge]


This module is used on 45,000+ pages.

To avoid major disruption and server load, do not make unnecessary edits to this module. Test changes to this module first using its /sandbox and /testcases subpages . All of the changes can then be applied to this module in a single edit.

Consider discussing changes on the talk page or on Discord before implementing them.

Lua logo

This module depends on the following other modules:

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

ru:Модуль:Item link de:Modul:Item link

-------------------------------------------------------------------------------
-- 
--                             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.
-------------------------------------------------------------------------------

require('Module:No globals')
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]
    tpl_args.large = m_util.cast.boolean(tpl_args.large)
    
    local img
    local result
    if tpl_args.skip_query == nil then
        tpl_args.fields = {
            'items.name=name',
            'items.inventory_icon=inventory_icon',
            'items.html=html',
            'items.alternate_art_inventory_icons=alternate_art_inventory_icons',
            'items.size_x=size_x',
            'items.size_y=size_y',
        }
        tpl_args.error_category = i18n.categories.broken_item_links
        result = m_item_util.query_item(tpl_args)
        if result.error then
            return result.error
        end
    else
        result = {
            ['_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['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['_pageName']
                ) .. m_util.misc.add_category({i18n.categories.broken_item_links})
            }
        end
        
        result['alternate_art_inventory_icons'] = m_util.string.split(
            result['alternate_art_inventory_icons'], 
            ',%s*'
        )
        
        local index = tonumber(tpl_args.image)
        if index ~= nil then
            img = result['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['inventory_icon'], 1, -suffix)) + 2
            
            for _, filename in ipairs(result['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['_pageName']
                ) .. m_util.misc.add_category({i18n.categories.broken_item_links})
            }
        end
    elseif result['inventory_icon'] ~= nil then
        img = result['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 = tpl_args.link
    if result['class_id'] == 'Map' and m_util.table.has_any_key(tpl_args, {'item_name', 'item_name_exact'}) then
        linked_page = linked_page or tpl_args.item_name_exact or tpl_args.item_name
    else
        linked_page = linked_page or result['_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['name'] > 0 then
        activator:wikitext(string.format(
            '[[%s|%s]]', 
            linked_page, 
            result['name'] or result['_pageName']
            )
        )
    end
    
    local display = mw.html.create('span')
    display:attr('class', 'c-item-hoverbox__display')

    if result['html'] ~= nil then
        display:wikitext(result['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['size_x']) or tonumber(tpl_args.width)
        local height = tonumber(result['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