Module:Utils: Difference between revisions
From Eco - English Wiki
[checked revision] | [pending revision] |
p.tableLen |
No edit summary |
||
(29 intermediate revisions by 3 users not shown) | |||
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 | ||
function p.normalise(args) | |||
for k, v in pairs(args) do | |||
v = mw.text.trim(tostring(v)) | |||
if v ~= '' then | |||
args[k] = v | |||
end | |||
end | |||
return args | |||
end | |||
--- 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 args = {} | |||
for k, v in pairs(origArgs) do | |||
v = mw.text.trim(tostring(v)) | |||
if v ~= '' then | |||
args[k] = v | |||
end | |||
end | |||
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' | |||
if too_expensive then | |||
return icon | |||
end | |||
if mw.title.makeTitle('File', icon).file.exists then | |||
return icon | |||
else | |||
return 'NoIcon.png' | |||
end | |||
end | |||
function p.itemId(name) | |||
return name:gsub('%s+', '') .. 'Item' | |||
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) | |||
-- Should only use on short arrays | |||
local set = {} | |||
for _, l in ipairs(array) do | |||
set[l] = true | |||
end | |||
return set[item] ~= nil | |||
end | end | ||
-- mw.LoadData prevents # | --- Calculate the length of a table by iterating over every item in it. | ||
-- | |||
-- <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 | |||
for _, v in ipairs(tbl) do | |||
if v == nil then | |||
return count | |||
end | |||
count = count + 1 | |||
end | |||
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 | |||
function p.mapColour(colourName) | |||
local foreground = "white" | |||
local background = "#1165AF" | |||
mw.log(colourName) | |||
colour_map = { | |||
["aliceblue"] = "f0f8ff", | |||
["antiquewhite"] = "faebd7", | |||
["aqua"] = "00ffff", | |||
["aquamarine"] = "7fffd4", | |||
["azure"] = "f0ffff", | |||
["beige"] = "f5f5dc", | |||
["bisque"] = "ffe4c4", | |||
["black"] = "000000", | |||
["blanchedalmond"] = "ffebcd", | |||
["blue"] = "0000ff", | |||
["blueviolet"] = "8a2be2", | |||
["brown"] = "a52a2a", | |||
["burlywood"] = "deb887", | |||
["cadetblue"] = "5f9ea0", | |||
["chartreuse"] = "7fff00", | |||
["chocolate"] = "d2691e", | |||
["coral"] = "ff7f50", | |||
["cornflowerblue"] = "6495ed", | |||
["cornsilk"] = "fff8dc", | |||
["crimson"] = "dc143c", | |||
["cyan"] = "00ffff", | |||
["darkblue"] = "00008b", | |||
["darkcyan"] = "008b8b", | |||
["darkgoldenrod"] = "b8860b", | |||
["darkgray"] = "a9a9a9", | |||
["darkgreen"] = "006400", | |||
["darkkhaki"] = "bdb76b", | |||
["darkmagenta"] = "8b008b", | |||
["darkolivegreen"] = "556b2f", | |||
["darkorange"] = "ff8c00", | |||
["darkorchid"] = "9932cc", | |||
["darkred"] = "8b0000", | |||
["darksalmon"] = "e9967a", | |||
["darkseagreen"] = "8fbc8f", | |||
["darkslateblue"] = "483d8b", | |||
["darkslategray"] = "2f4f4f", | |||
["darkturquoise"] = "00ced1", | |||
["darkviolet"] = "9400d3", | |||
["deeppink"] = "ff1493", | |||
["deepskyblue"] = "00bfff", | |||
["dimgray"] = "696969", | |||
["dodgerblue"] = "1e90ff", | |||
["feldspar"] = "d19275", | |||
["firebrick"] = "b22222", | |||
["floralwhite"] = "fffaf0", | |||
["forestgreen"] = "228b22", | |||
["fuchsia"] = "ff00ff", | |||
["gainsboro"] = "dcdcdc", | |||
["ghostwhite"] = "f8f8ff", | |||
["gold"] = "ffd700", | |||
["goldenrod"] = "daa520", | |||
["gray"] = "808080", | |||
["green"] = "008000", | |||
["greenyellow"] = "adff2f", | |||
["honeydew"] = "f0fff0", | |||
["hotpink"] = "ff69b4", | |||
["indianred "] = "cd5c5c", | |||
["indigo "] = "4b0082", | |||
["ivory"] = "fffff0", | |||
["khaki"] = "f0e68c", | |||
["lavender"] = "e6e6fa", | |||
["lavenderblush"] = "fff0f5", | |||
["lawngreen"] = "7cfc00", | |||
["lemonchiffon"] = "fffacd", | |||
["lightblue"] = "add8e6", | |||
["lightcoral"] = "f08080", | |||
["lightcyan"] = "e0ffff", | |||
["lightgoldenrodyellow"] = "fafad2", | |||
["lightgrey"] = "d3d3d3", | |||
["lightgreen"] = "90ee90", | |||
["lightpink"] = "ffb6c1", | |||
["lightsalmon"] = "ffa07a", | |||
["lightseagreen"] = "20b2aa", | |||
["lightskyblue"] = "87cefa", | |||
["lightslateblue"] = "8470ff", | |||
["lightslategray"] = "778899", | |||
["lightsteelblue"] = "b0c4de", | |||
["lightyellow"] = "ffffe0", | |||
["lime"] = "00ff00", | |||
["limegreen"] = "32cd32", | |||
["linen"] = "faf0e6", | |||
["magenta"] = "ff00ff", | |||
["maroon"] = "800000", | |||
["mediumaquamarine"] = "66cdaa", | |||
["mediumblue"] = "0000cd", | |||
["mediumorchid"] = "ba55d3", | |||
["mediumpurple"] = "9370d8", | |||
["mediumseagreen"] = "3cb371", | |||
["mediumslateblue"] = "7b68ee", | |||
["mediumspringgreen"] = "00fa9a", | |||
["mediumturquoise"] = "48d1cc", | |||
["mediumvioletred"] = "c71585", | |||
["midnightblue"] = "191970", | |||
["mintcream"] = "f5fffa", | |||
["mistyrose"] = "ffe4e1", | |||
["moccasin"] = "ffe4b5", | |||
["navajowhite"] = "ffdead", | |||
["navy"] = "000080", | |||
["oldlace"] = "fdf5e6", | |||
["olive"] = "808000", | |||
["olivedrab"] = "6b8e23", | |||
["orange"] = "ffa500", | |||
["orangered"] = "ff4500", | |||
["orchid"] = "da70d6", | |||
["palegoldenrod"] = "eee8aa", | |||
["palegreen"] = "98fb98", | |||
["paleturquoise"] = "afeeee", | |||
["palevioletred"] = "d87093", | |||
["papayawhip"] = "ffefd5", | |||
["peachpuff"] = "ffdab9", | |||
["peru"] = "cd853f", | |||
["pink"] = "ffc0cb", | |||
["plum"] = "dda0dd", | |||
["powderblue"] = "b0e0e6", | |||
["purple"] = "800080", | |||
["red"] = "ff0000", | |||
["rosybrown"] = "bc8f8f", | |||
["royalblue"] = "4169e1", | |||
["saddlebrown"] = "8b4513", | |||
["salmon"] = "fa8072", | |||
["sandybrown"] = "f4a460", | |||
["seagreen"] = "2e8b57", | |||
["seashell"] = "fff5ee", | |||
["sienna"] = "a0522d", | |||
["silver"] = "c0c0c0", | |||
["skyblue"] = "87ceeb", | |||
["slateblue"] = "6a5acd", | |||
["slategray"] = "708090", | |||
["snow"] = "fffafa", | |||
["springgreen"] = "00ff7f", | |||
["steelblue"] = "4682b4", | |||
["tan"] = "d2b48c", | |||
["teal"] = "008080", | |||
["thistle"] = "d8bfd8", | |||
["tomato"] = "ff6347", | |||
["turquoise"] = "40e0d0", | |||
["violet"] = "ee82ee", | |||
["violetred"] = "d02090", | |||
["wheat"] = "f5deb3", | |||
["white"] = "ffffff", | |||
["whitesmoke"] = "f5f5f5", | |||
["yellow"] = "ffff00", | |||
["yellowgreen"] = "9acd32" | |||
} | |||
colour_found = colour_map[colourName:lower()] | |||
if colour_found ~= nil then | |||
background = '#' .. colour_found | |||
end | end | ||
return foreground, background | |||
end | end | ||
return p | return p |
Latest revision as of 10:16, 5 September 2024
This module provides utility functions used from other modules.
Usage[edit source]
Add the following line of code at the top of your file.
local Utils = require("Module:Utils")
-- You may then call functions from this module in your script. For example:
local tableLength = Utils.tableLen(myTable)
local p = {}
--- Trims and parses the args into a table, then returns the table
function p.normalise(args)
for k, v in pairs(args) do
v = mw.text.trim(tostring(v))
if v ~= '' then
args[k] = v
end
end
return args
end
--- Trims and parses the args into a table, then returns the table
-- @author User:Avaren
function p.normaliseArgs(frame)
local origArgs = frame:getParent().args
local args = {}
for k, v in pairs(origArgs) do
v = mw.text.trim(tostring(v))
if v ~= '' then
args[k] = v
end
end
return args
end
--- Get path to icon file.
-- @author User:Avaren
function p.checkImage(name, too_expensive)
local icon = name:gsub('%s+', '') .. '_Icon.png'
if too_expensive then
return icon
end
if mw.title.makeTitle('File', icon).file.exists then
return icon
else
return 'NoIcon.png'
end
end
function p.itemId(name)
return name:gsub('%s+', '') .. 'Item'
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)
-- Should only use on short arrays
local set = {}
for _, l in ipairs(array) do
set[l] = true
end
return set[item] ~= nil
end
--- Calculate the length of a table by iterating over every item in it.
--
-- <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)
local count = 0
for _, v in ipairs(tbl) do
if v == nil then
return count
end
count = count + 1
end
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
function p.mapColour(colourName)
local foreground = "white"
local background = "#1165AF"
mw.log(colourName)
colour_map = {
["aliceblue"] = "f0f8ff",
["antiquewhite"] = "faebd7",
["aqua"] = "00ffff",
["aquamarine"] = "7fffd4",
["azure"] = "f0ffff",
["beige"] = "f5f5dc",
["bisque"] = "ffe4c4",
["black"] = "000000",
["blanchedalmond"] = "ffebcd",
["blue"] = "0000ff",
["blueviolet"] = "8a2be2",
["brown"] = "a52a2a",
["burlywood"] = "deb887",
["cadetblue"] = "5f9ea0",
["chartreuse"] = "7fff00",
["chocolate"] = "d2691e",
["coral"] = "ff7f50",
["cornflowerblue"] = "6495ed",
["cornsilk"] = "fff8dc",
["crimson"] = "dc143c",
["cyan"] = "00ffff",
["darkblue"] = "00008b",
["darkcyan"] = "008b8b",
["darkgoldenrod"] = "b8860b",
["darkgray"] = "a9a9a9",
["darkgreen"] = "006400",
["darkkhaki"] = "bdb76b",
["darkmagenta"] = "8b008b",
["darkolivegreen"] = "556b2f",
["darkorange"] = "ff8c00",
["darkorchid"] = "9932cc",
["darkred"] = "8b0000",
["darksalmon"] = "e9967a",
["darkseagreen"] = "8fbc8f",
["darkslateblue"] = "483d8b",
["darkslategray"] = "2f4f4f",
["darkturquoise"] = "00ced1",
["darkviolet"] = "9400d3",
["deeppink"] = "ff1493",
["deepskyblue"] = "00bfff",
["dimgray"] = "696969",
["dodgerblue"] = "1e90ff",
["feldspar"] = "d19275",
["firebrick"] = "b22222",
["floralwhite"] = "fffaf0",
["forestgreen"] = "228b22",
["fuchsia"] = "ff00ff",
["gainsboro"] = "dcdcdc",
["ghostwhite"] = "f8f8ff",
["gold"] = "ffd700",
["goldenrod"] = "daa520",
["gray"] = "808080",
["green"] = "008000",
["greenyellow"] = "adff2f",
["honeydew"] = "f0fff0",
["hotpink"] = "ff69b4",
["indianred "] = "cd5c5c",
["indigo "] = "4b0082",
["ivory"] = "fffff0",
["khaki"] = "f0e68c",
["lavender"] = "e6e6fa",
["lavenderblush"] = "fff0f5",
["lawngreen"] = "7cfc00",
["lemonchiffon"] = "fffacd",
["lightblue"] = "add8e6",
["lightcoral"] = "f08080",
["lightcyan"] = "e0ffff",
["lightgoldenrodyellow"] = "fafad2",
["lightgrey"] = "d3d3d3",
["lightgreen"] = "90ee90",
["lightpink"] = "ffb6c1",
["lightsalmon"] = "ffa07a",
["lightseagreen"] = "20b2aa",
["lightskyblue"] = "87cefa",
["lightslateblue"] = "8470ff",
["lightslategray"] = "778899",
["lightsteelblue"] = "b0c4de",
["lightyellow"] = "ffffe0",
["lime"] = "00ff00",
["limegreen"] = "32cd32",
["linen"] = "faf0e6",
["magenta"] = "ff00ff",
["maroon"] = "800000",
["mediumaquamarine"] = "66cdaa",
["mediumblue"] = "0000cd",
["mediumorchid"] = "ba55d3",
["mediumpurple"] = "9370d8",
["mediumseagreen"] = "3cb371",
["mediumslateblue"] = "7b68ee",
["mediumspringgreen"] = "00fa9a",
["mediumturquoise"] = "48d1cc",
["mediumvioletred"] = "c71585",
["midnightblue"] = "191970",
["mintcream"] = "f5fffa",
["mistyrose"] = "ffe4e1",
["moccasin"] = "ffe4b5",
["navajowhite"] = "ffdead",
["navy"] = "000080",
["oldlace"] = "fdf5e6",
["olive"] = "808000",
["olivedrab"] = "6b8e23",
["orange"] = "ffa500",
["orangered"] = "ff4500",
["orchid"] = "da70d6",
["palegoldenrod"] = "eee8aa",
["palegreen"] = "98fb98",
["paleturquoise"] = "afeeee",
["palevioletred"] = "d87093",
["papayawhip"] = "ffefd5",
["peachpuff"] = "ffdab9",
["peru"] = "cd853f",
["pink"] = "ffc0cb",
["plum"] = "dda0dd",
["powderblue"] = "b0e0e6",
["purple"] = "800080",
["red"] = "ff0000",
["rosybrown"] = "bc8f8f",
["royalblue"] = "4169e1",
["saddlebrown"] = "8b4513",
["salmon"] = "fa8072",
["sandybrown"] = "f4a460",
["seagreen"] = "2e8b57",
["seashell"] = "fff5ee",
["sienna"] = "a0522d",
["silver"] = "c0c0c0",
["skyblue"] = "87ceeb",
["slateblue"] = "6a5acd",
["slategray"] = "708090",
["snow"] = "fffafa",
["springgreen"] = "00ff7f",
["steelblue"] = "4682b4",
["tan"] = "d2b48c",
["teal"] = "008080",
["thistle"] = "d8bfd8",
["tomato"] = "ff6347",
["turquoise"] = "40e0d0",
["violet"] = "ee82ee",
["violetred"] = "d02090",
["wheat"] = "f5deb3",
["white"] = "ffffff",
["whitesmoke"] = "f5f5f5",
["yellow"] = "ffff00",
["yellowgreen"] = "9acd32"
}
colour_found = colour_map[colourName:lower()]
if colour_found ~= nil then
background = '#' .. colour_found
end
return foreground, background
end
return p