ATTENTION! The process of updating WiKi to version Eco 10.x has begun. Those wishing to participate can find out more Information on our ECO Contribution Wiki Discord.
From April 26 to May 12, errors may occur in the Wiki, as we will be carrying out a major update to the information processing modules.

Editing Module:Utils

From Eco - English Wiki

Your changes will be displayed to readers once an authorized user accepts them. (help)

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
local p = {}
local p = {}


--- Trims and parses the args into a table, then returns the table
-- Trims and parses the args into a table, then returns the table
-- @author User:Avaren
function p.normaliseArgs(frame)
function p.normaliseArgs(frame)
local origArgs = frame:getParent().args
    local origArgs = frame:getParent().args
local args = {}
    local args = {}


for k, v in pairs(origArgs) do
    for k, v in pairs(origArgs) do
v = mw.text.trim(tostring(v))
        v = mw.text.trim(tostring(v))
if v ~= '' then
        if v ~= '' then
args[k] = v
            args[k] = v
end
        end
end
    end


return args
    return args
end
end


--- Get path to icon file.
-- @author User:Avaren
function p.checkImage(name, too_expensive)
function p.checkImage(name, too_expensive)
local icon = name:gsub('%s+', '') .. '_Icon.png'
    local icon = name:gsub('%s+', '') .. '_Icon.png'
if too_expensive then
    if too_expensive then
return icon
        return icon
end
    end


if mw.title.makeTitle('File', icon).file.exists then
    if mw.title.makeTitle('File', icon).file.exists then
return icon
        return icon
else
    else
return 'NoImage.png'
        return 'NoImage.png'
end
    end
end
end


--- Check if <code>item</code> is in given <code>array</code>.
-- @param item Item to look for
-- @param #table array Table to check
-- @return #bool <code>true</code> if <code>item</code> is in <code>array</code>
-- @author User:Avaren
local function in_array(item, array)
local function in_array(item, array)
-- Should only use on short arrays
    -- Should only use on short arrays
local set = {}
    local set = {}
for _, l in ipairs(array) do
    for _, l in ipairs(array) do
set[l] = true
        set[l] = true
end
    end
return set[item] ~= nil
    return set[item] ~= nil
end
end


--- Build HTML code for an icon image.
---@param name string
-- @param name string
---@param size string|nil
-- @param size string|nil One of: <code>"iconNormal"</code> (64px) or <code>"iconRecipe"</code> (44px). Default: <code>"iconNormal"</code>
---@param bg string|nil
-- @param bg string|nil
---@param border string|nil
-- @param border string|nil
---@param too_expensive boolean|nil
-- @param too_expensive boolean|nil
-- @author User:Avaren
function p.build_icon(name, link, size, bg, border, too_expensive)
function p.build_icon(name, link, size, bg, border, too_expensive)
local L = require('Module:Localization') -- local import
    -- Size options are iconNormal or iconRecipe - 64px or 44px - defaults to iconNormal


if not size then
    local L = require('Module:Localization') -- local import
size = 'iconNormal'
end
local icon_bg
if bg then
icon_bg = bg
end
local icon_border
if border then
icon_border = border
end


local item_data = mw.loadData('Module:ItemData')
    if not size then
local item = item_data.items[name]
        size = 'iconNormal'
local image
    end
if item then
    local icon_bg
if item['group'] == L.t('Skill Books') then
    if bg then
image = 'SkillBook.png'
        icon_bg = bg
icon_bg = 'iconGold'
    end
elseif item['group'] == L.t('Skill Scrolls') then
    local icon_border
image = 'Skill Scroll'
    if border then
icon_bg = 'iconGold'
        icon_border = border
-- Attempt to generate skill page
    end
elseif in_array(L.t('Basic Research'), item['tagGroups']) then
image = string.sub(item['untranslated'], 1, -7):gsub('%s+', '') .. '_Icon.png'
icon_bg = 'paperBasic'
elseif in_array(L.t('Advanced Research'), item['tagGroups']) then
image = string.sub(item['untranslated'], 1, -10):gsub('%s+', '') .. '_Icon.png'
icon_bg = 'paperAdvanced'
elseif in_array(L.t('Modern Research'), item['tagGroups']) then
image = string.sub(item['untranslated'], 1, -8):gsub('%s+', '') .. '_Icon.png'
icon_bg = 'paperModern'
else
image = p.checkImage(item['untranslated'], too_expensive)
end
if not icon_bg then
if item['group'] == L.t('Food') then
icon_bg = 'iconGreen'
elseif item['carried'] == L.t('Hands') then
icon_bg = 'iconBrown'
end
end
else
image = p.checkImage(name, too_expensive)
end


if not icon_bg then
    local item_data = mw.loadData('Module:ItemData')
icon_bg = 'iconBlue'
    local item = item_data.items[name]
end
    local image
    if item then
        if item['group'] == L.t('Skill Books') then
            image = 'SkillBook.png'
            icon_bg = 'iconGold'
        elseif item['group'] == L.t('Skill Scrolls') then
            image = 'Skill Scroll'
            icon_bg = 'iconGold'
            -- Attempt to generate skill page
        elseif in_array(L.t('Basic Research'), item['tagGroups']) then
            image = string.sub(item['untranslated'], 1, -7):gsub('%s+', '') .. '_Icon.png'
            icon_bg = 'paperBasic'
        elseif in_array(L.t('Advanced Research'), item['tagGroups']) then
            image = string.sub(item['untranslated'], 1, -10):gsub('%s+', '') .. '_Icon.png'
            icon_bg = 'paperAdvanced'
        elseif in_array(L.t('Modern Research'), item['tagGroups']) then
            image = string.sub(item['untranslated'], 1, -8):gsub('%s+', '') .. '_Icon.png'
            icon_bg = 'paperModern'
        else
            image = p.checkImage(item['untranslated'], too_expensive)
        end
        if not icon_bg then
            if item['group'] == L.t('Food') then
                icon_bg = 'iconGreen'
            elseif item['carried'] == L.t('Hands') then
                icon_bg = 'iconBrown'
            end
        end
    else
        image = p.checkImage(name, too_expensive)
    end


if border then
    if not icon_bg then
icon_border = border
        icon_bg = 'iconBlue'
else
    end
icon_border = 'borderBlue'
end


if size == 'iconNormal' then
    if border then
icon_container = 'iconContainer'
        icon_border = border
else
    else
icon_container = 'iconContainerSmall'
        icon_border = 'borderBlue'
end
    end


if not link then
    if size == 'iconNormal' then
link = ''
        icon_container = 'iconContainer'
else
    else
link = '|link='..link
        icon_container = 'iconContainerSmall'
end
    end


local file = '[[File:' .. image .. '|frameless|class=' .. size .. ' ' .. icon_bg .. link ..']]'
    if not link then
return '<div class="' .. icon_container .. '"><div class="iconStack">' .. file .. '</div><div class="iconBorder ' .. icon_border .. '" style="position:absolute;"></div></div>'
        link = ''
    else
        link = '|link='..link
    end
 
    local file = '[[File:' .. image .. '|frameless|class=' .. size .. ' ' .. icon_bg .. link ..']]'
    return '<div class="' .. icon_container .. '"><div class="iconStack">' .. file .. '</div><div class="iconBorder ' .. icon_border .. '" style="position:absolute;"></div></div>'
end
end


--- Get HTML code for an icon image.
-- @author User:Avaren
function p.Icon(frame)
function p.Icon(frame)
args = p.normaliseArgs(frame)
    args = p.normaliseArgs(frame)
return p.build_icon(args.name, args.link, args.size, args.bg, args.border, args.too_expensive)
    return p.build_icon(args.name, args.link, args.size, args.bg, args.border, args.too_expensive)
end
end


--- Calculate the length of a table by iterating over every item in it.
-- mw.LoadData prevents #table from working correctly
--
-- <code>mw.LoadData</code> prevents <code>#tbl</code> from working correctly.
-- @param #table tbl Table to calculate the length of
-- @return #number Length of the table.
-- @author User:Avaren
function p.tableLen(tbl)
function p.tableLen(tbl)
local count = 0
    local count = 0
for _, v in ipairs(tbl) do
    for _, v in ipairs(tbl) do
if v == nil then
        if v == nil then
return count
            return count
end
        end
count = count + 1
        count = count + 1
end
    end
return count
    return count
end
 
--- Check if <code>value</code> is not <code>nil</code> and return it or if it is <code>nil</code> fall back to <code>default</code>.
-- @param value Value to check
-- @param default Value to fall back to
-- @return <code>value</code> if it is not <code>nil</code>
-- @return <code>default</code> if <code>value</code> is <code>nil</code>
-- @author User:Demian
-- @see valueOrDash
-- @see formatNilToYesNo
-- @see formatBoolToYesNo
function p.valueOrDefault(value, default)
return nil == value and default or value
end
 
--- Check if <code>value</code> is not <code>nil</code> and return it or if it is <code>nil</code> fall back to the em-dash (—).
--
-- The em-dash (—) is commonly used represent a missing, not applicable (N/A), or a negative ("no") value with just a single character.
-- @param value Value to check
-- @return <code>value</code> if it is not <code>nil</code>
-- @return #string "—" if <code>value</code> is <code>nil</code>
-- @author User:Demian
-- @see valueOrDefault
function p.valueOrDash(value)
return nil == value and "—" or value
end
 
--- Check if <code>value</code> is not <code>nil</code> and return "Yes" or "No".
-- @param value Value to check
-- @return #string "Yes" if <code>value</code> is not <code>nil</code>
-- @return #string "No" if <code>value</code> is <code>nil</code>
-- @author User:Demian
-- @see valueOrDefault
-- @usage formatNilToYesNo("Hello") == "Yes"
-- @usage formatNilToYesNo(nil) == "No"
function p.formatNilToYesNo(value)
-- TODO: Support i18n.
return nil == value and "No" or "Yes"
end
 
--- Check if <code>value</code> <em>evaluates</em> as <code>true</code> and return "Yes" or "No".
-- @param value Value to evaluate. Does not have to be a bool.
-- @return #string "Yes" if <code>value</code> evaluates as <code>true</code>
-- @return #string "No" if <code>value</code> evaluates as <code>false</code>
-- @author User:Demian
-- @see valueOrDefault
-- @usage formatBoolToYesNo("") == true
-- @usage formatBoolToYesNo(123) == true
-- @usage formatBoolToYesNo(nil) == false
function p.formatBoolToYesNo(value)
-- TODO: Support i18n.
return value and "Yes" or "No"
end
 
--- Format the input values into a string representing the range between the values.
--
-- Returning an an empty string intended to ease concatenation with other strings.
-- The en-dash (–) (instead of the hyphen-minus "-") is the appropriate character to signify a range of values.
-- @param #number min Minimum value (left side)
-- @param #number max Maximum value (right side)
-- @param #number default Default value in case of an error (only value).
-- @param #string valueFormat Format string used with <code>mw.ustring.format</code>.
-- @return #string "<code>min</code>–<code>max</code>" if <code>min < max</code>
-- @return #string "<code>default</code>" formatted with <code>valueFormat</code> if <code>min == max</code> or <code>min > max</code> and <code>default ~= nil</code>
-- @return #string "" (empty string) if either <code>min</code> <strong>or</strong> <code>max</code> do not convert to a numerical value
-- @return #nil <code>nil</code> if <code>min == max</code> or <code>min > max</code> and <code>default == nil</code>
-- @author User:Demian
function p.toRangeString(min, max, default, valueFormat)
min = tonumber(p.valueOrDefault(min, nil))
max = tonumber(p.valueOrDefault(max, nil))
default = tonumber(p.valueOrDefault(default, nil))
 
if nil ~= min and nil ~= max then
if min < max then
return mw.ustring.format(mw.ustring.format("%s–%s", valueFormat, valueFormat), min, max)
elseif nil == default then
return nil
else
return mw.ustring.format(valueFormat, default)
end
end
 
return ""
end
 
--- Get all keys from <code>tbl</code> and sort them in alphabetical order.
-- @param #table tbl Table to get keys from
-- @return #table Input table keys in alphabetical order.
-- @author User:Demian
-- @see getSortedValues
function p.getSortedKeys(tbl)
local sorted = {}
 
for key in pairs(tbl) do
table.insert(sorted, key)
end
 
table.sort(sorted)
 
return sorted
end
 
--- Get all values from <code>tbl</code> and sort them in alphabetical order.
-- @param #table tbl Table to get values from
-- @return #table Input table values in alphabetical order.
-- @author User:Demian
-- @see getSortedKeys
function p.getSortedValues(tbl)
local sorted = {}
 
for _, value in ipairs(tbl) do
table.insert(sorted, value)
end
 
table.sort(sorted)
 
return sorted
end
 
--- Split <code>str</code> by the given character.
-- @param #string str String to split
-- @param #string separator String that separates values in <code>str</code>. May optionally be surrounded by 1 <em>whitespace</em> character by default.
-- @return #table Table of strings that were split from <code>str</code>.
-- @author User:Demian
-- @usage splitString("hello, world", ",") == {"hello", "world"}
function p.splitString(str, separator)
local tbl = {}
 
for token in mw.ustring.gmatch(str, mw.ustring.format("%%s?([^%s]+)%%s?", separator)) do
table.insert(tbl, token)
end
 
return tbl
end
 
--- Sort items in the given list of values <code>str</code> separated with <code>separator</code> and return them as a single string.
-- @param #string str String with values separated by <code>separator</code>
-- @param #string separator String that separates values in <code>str</code>
-- @param #string joiner String used to join sorted values from <code>str</code>.
-- @return #string <code>str</code> with items sorted in alphabetical order.
-- @author User:Demian
-- @usage sortListString("Dog,Ape, Cat", ",", ";") == "Ape;Cat;Dog"
function p.sortListString(str, separator, joiner)
-- Split string by commas.
-- Sort items.
-- Rejoin into string.
return table.concat(p.getSortedValues(p.splitString(str, separator)), joiner)
end
 
--- Check if a page with the title "<code>name</code> (<code>disambiguationTitle</code>)" exists in the database and return that page title, otherwise return "<code>name</code>".
--
-- Use sparingly as this uses a comparatively slow MediaWiki function p.to check if a page exists.
--
-- Using this function p.will create a new entry in the <code>Special:WantedPages</code> list.
-- Be careful when calling this function p.and do not pass garbage into its parameters so you do not clog up that list.
-- This is a long-standing issue with MediaWiki that has not yet been solved, and may not be possible to solve without an architectural change to the software.
-- @param #string name Name of a page.
-- @param #string disambiguationTitle Disambiguation clarifier in a page title.
-- @return #string "<code>name</code> (<code>disambiguationTitle</code>)"
-- @return #string "<code>name</code>"
-- @author User:Demian
function p.getDirectPageName(name, disambiguationTitle)
-- Try to get the actual end page instead of the disambiguation page if it exists.
-- E.g. Salmon has "Salmon (animal)" and "Salmon (item)" as well as the "Salmon" disambiguation page between these two.
local directPage = mw.ustring.format("%s (%s)", name, disambiguationTitle)
return mw.title.new(directPage).exists and directPage or name
end
 
--- Create a wikilink with [[square brackets]] from parameters.
-- @param #string pageName The actual name of a page to create a link to
-- @param #string displayText Text to display as a clickable link instead of the page name. If <code>nil</code>, <code>pageName</code> is displayed instead.
-- @param #bool twoLineDisplayText Force the <em>last word</em> of <code>displayText</code> on the next line
-- @return #string "[[<code>name</code>|<code>displayText</code>]]" if <code>displayText</code> is not <code>nil</code>
-- @return #string "[[<code>name</code>]]" if <code>displayText</code> is <code>nil</code> or the same string as <code>name</code>
-- @author User:Demian
function p.formatWikilink(pageName, displayText, twoLineDisplayText)
local finalDisplayText = p.valueOrDefault(displayText, pageName)
 
if twoLineDisplayText then
local lastSpaceIdx = mw.ustring.find(finalDisplayText, " [^ ]*$")
 
if nil ~= lastSpaceIdx then
finalDisplayText = mw.ustring.format("%s<br>%s", mw.ustring.sub(finalDisplayText, 0, lastSpaceIdx-1), mw.ustring.sub(finalDisplayText, lastSpaceIdx+1))
end
end
 
if pageName == finalDisplayText then
return mw.ustring.format("[[%s]]", pageName)
else
return mw.ustring.format("[[%s|%s]]", pageName, finalDisplayText)
end
end
 
--- Add thousands separator to given number and use custom decimal point.
--
-- Extension:NumberFormat is more extensive, but more cumbersome to use and also not installed at the moment.
-- @param #string number Number to format. Is processed as a string regardless of type.
-- @param #string thousandsSeparator String to place between each set of 3 digits. Default: " "
-- @param #string decimalPoint String to place between the whole and fractional part of the number. Default: "."
-- @return #string <code>number</code> with the specified thousands separator and decimal point.
-- @return #string <code>number</code> unchanged if it contained 1 or more characters that are <strong>not</strong> a: digit, one of ".,-", a space.
-- @author User:Demian
-- @usage formatNumber(-1234567.89) = "-1 234 567.89"
-- @usage formatNumber("1234567,89", ".", "_") = "1,234,567_89"
function p.formatNumber(number, thousandsSeparator, decimalPoint)
-- Default separator to space.
if nil == thousandsSeparator then
thousandsSeparator = " "
end
 
-- Default point to period.
if nil == decimalPoint then
decimalPoint = "."
end
 
-- We're dealing with formatting a string here.
local numberString = tostring(number)
 
-- Check if the input number is reasonable.
-- Does NOT check for multiple instance of each character.
-- E.g. Inputting something like 123-456.789 will lead to incorrect results.
-- I can't handle every edge case: garbage in, garbage out.
-- The user has to have some responsibility in inputting reasonable numbers.
if mw.ustring.find(numberString, "[^%d%.%-, ]") then
return number
end
 
-- Split input into parts.
-- 1st group: MAY start with a "-".
-- 2nd group: MUST contain 1 or more digits-
-- 3rd group: MAY start with with one of ".,"
-- 3rd group: MAY have 0 or more digits.
local _, _, minus, digits, fraction = mw.ustring.find(tostring(numberString), "(-?)(%d+)([%.,]?%d*)")
 
-- Reverse the string of digits.
-- Append the thousands separator after (before when reversed again) each set of 3 digits.
digits = mw.ustring.gsub(string.reverse(digits), "(%d%d%d)", mw.ustring.format("%%1%s", thousandsSeparator))
 
-- Replace the existing decimal separator with the specified one.
if "" ~= fraction then
fraction = mw.ustring.format("%s%s",decimalPoint, mw.ustring.sub(fraction, 2))
end
 
-- Reverse the string of digits back to the original direction.
-- If the string digits starts with the thousands separator, remove the separator.
-- Add the optional minus in front and the optional fractional part at the back.
-- Need to remember to escape the thousandsSeparator, it could be "." which would translate to "any character"!
return mw.ustring.format("%s%s%s", minus, mw.ustring.gsub(string.reverse(digits), mw.ustring.format("^%%s", thousandsSeparator), ""), fraction)
end
 
--- Check if the string is empty or <code>nil</code>.
-- @param #string str String to check
-- @return #bool <code>true</code> if <code>str</code> is <code>nil</code> or an empty string ("").
-- @author User:Demian
function p.isEmpty(str)
return nil == str or "" == str
end
end


return p
return p
Please note that all contributions to Eco - English Wiki are considered to be released under the CC BY-NC-SA 4.0 (see Eco:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)

Template used on this page: