Module:Sandbox/LVL: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
LVL (talk | contribs)
No edit summary
LVL (talk | contribs)
Blanked the page
Tag: Blanking
Line 1: Line 1:
local Tabs = {}


--[[
=================================================================
Start of dependency: Module:Table
=================================================================
]]
local Table = {}
function Table.size(tbl)
local i = 0
for _ in pairs(tbl) do
i = i + 1
end
return i
end
function Table.includes(tbl, value, isPattern)
for _, entry in pairs(tbl) do
if isPattern and string.find(entry, value)
or not isPattern and entry == value then
return true
end
end
return false
end
function Table.getKeyOfValue(tbl, value)
for key, entry in pairs(tbl) do
if entry == value then
return key
end
end
return nil
end
function Table.filter(tbl, predicate, argument)
local filteredTbl = {}
local foundMatches = 1
for _, entry in pairs(tbl) do
if predicate(entry, argument) then
filteredTbl[foundMatches] = entry
foundMatches = foundMatches + 1
end
end
return filteredTbl
end
function Table.filterByKey(tbl, predicate)
local filteredTbl = {}
for key, entry in pairs(tbl) do
if predicate(key, entry) then
filteredTbl[key] = entry
end
end
return filteredTbl
end
function Table.isEmpty(tbl)
if tbl == nil then
return true
end
for _, _ in pairs(tbl) do
return false
end
return true
end
function Table.isNotEmpty(tbl)
return not Table.isEmpty(tbl)
end
function Table.copy(tbl)
local result = {}
for key, entry in pairs(tbl) do
result[key] = entry
end
return result
end
function Table.deepCopy(tbl_, options)
options = options or {}
assert(type(tbl_) == 'table', 'Table.deepCopy: Input must be a table')
local function deepCopy(tbl)
local result = {}
for key, value in pairs(tbl) do
result[key] = type(value) == 'table' and deepCopy(value) or value
end
if options.copyMetatable then
local metatable = getmetatable(tbl)
if type(metatable) == 'table' then
setmetatable(result, deepCopy(metatable))
end
end
return result
end
return deepCopy(tbl_)
end
function Table.deepEquals(xTable, yTable)
assert(type(xTable) == 'table', 'Table.deepEquals: First argument must be a table')
assert(type(yTable) == 'table', 'Table.deepEquals: Second argument must be a table')
for key, value in pairs(xTable) do
if not Logic.deepEquals(value, yTable[key]) then
return false
end
end
for key, _ in pairs(yTable) do
if xTable[key] == nil then
return false
end
end
return true
end
function Table.mergeInto(target, ...)
local objs = Table.pack(...)
for i = 1, objs.n do
if type(objs[i]) == 'table' then
for key, value in pairs(objs[i]) do
target[key] = value
end
end
end
return target
end
function Table.merge(...)
return Table.mergeInto({}, ...)
end
function Table.deepMergeInto(target, ...)
local tbls = Table.pack(...)
for i = 1, tbls.n do
if type(tbls[i]) == 'table' then
for key, value in pairs(tbls[i]) do
if type(target[key]) == 'table' and type(value) == 'table' then
Table.deepMergeInto(target[key], value)
else
target[key] = value
end
end
end
end
return target
end
function Table.deepMerge(...)
return Table.deepMergeInto({}, ...)
end
function Table.map(xTable, f)
local yTable = {}
for xKey, xValue in pairs(xTable) do
local yKey, yValue = f(xKey, xValue)
yTable[yKey] = yValue
end
return yTable
end
function Table.mapArgumentsByPrefix(args, prefixes, f, noInterleave)
local function indexFromKey(key)
local prefix, index = key:match('^([%a_]+)(%d+)$')
if Table.includes(prefixes, prefix) then
return tonumber(index), prefix
else
return nil
end
end
return Table.mapArguments(args, indexFromKey, f, noInterleave)
end
function Table.mapArguments(args, indexFromKey, f, noInterleave)
local entriesByIndex = {}
-- Non-numeric args
for key, _ in pairs(args) do
local function post(index, ...)
if index and not entriesByIndex[index] then
entriesByIndex[index] = f(key, index, ...)
end
end
if type(key) == 'string' then
post(indexFromKey(key))
end
end
if noInterleave then
return entriesByIndex
end
-- Numeric index entries fills in gaps of prefixN= entries if not disabled
local entryIndex = 1
for argIndex = 1, math.huge do
if not args[argIndex] then
break
end
while entriesByIndex[entryIndex] do
entryIndex = entryIndex + 1
end
entriesByIndex[entryIndex] = f(argIndex, entryIndex)
end
return entriesByIndex
end
function Table.mapValues(xTable, f)
local yTable = {}
for xKey, xValue in pairs(xTable) do
yTable[xKey] = f(xValue)
end
return yTable
end
function Table.all(tbl, predicate)
for key, value in pairs(tbl) do
if not predicate(key, value) then
return false
end
end
return true
end
function Table.any(tbl, predicate)
for key, value in pairs(tbl) do
if predicate(key, value) then
return true
end
end
return false
end
function Table.groupBy(tbl, f)
local groups = {}
for key, value in pairs(tbl) do
local groupKey = f(key, value)
if not groups[groupKey] then
groups[groupKey] = {}
end
groups[groupKey][key] = value
end
return groups
end
function Table.extract(tbl, key)
local value = tbl[key]
tbl[key] = nil
return value
end
function Table.getByPathOrNil(tbl, path)
for _, fieldName in ipairs(path) do
if type(tbl) ~= 'table' then
return nil
end
tbl = tbl[fieldName]
end
return tbl
end
function Table.setByPath(tbl, path, value)
for i = 1, #path - 1 do
if tbl[path[i]] == nil then
tbl[path[i]] = {}
end
tbl = tbl[path[i]]
end
tbl[path[#path]] = value
end
function Table.uniqueKey(tbl)
local key0 = nil
for key, _ in pairs(tbl) do
if key0 ~= nil then return nil end
key0 = key
end
return key0
end
function Table.entries(tbl)
local entries = {}
for key, value in pairs(tbl) do
table.insert(entries, {key, value})
end
return entries
end
function Table.pack(...)
return {n = select('#', ...), ...}
end
Table.iter = {}
function Table.iter.spairs(tbl, order)
local keys = {}
for k in pairs(tbl) do keys[#keys+1] = k end
if order then
table.sort(keys, function(a,b) return order(tbl, a, b) end)
else
table.sort(keys)
end
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], tbl[keys[i]]
end
end
end
function Table.iter.pairsByPrefix(tbl, prefixes, options)
options = options or {}
if type(prefixes) == 'string' then
prefixes = {prefixes}
end
local getByPrefixes = function(index)
for _, prefix in ipairs(prefixes) do
local key = prefix .. index
if tbl[key] then
return key, tbl[key]
end
end
end
local i = 1
return function()
local key, value = getByPrefixes(i)
if options.requireIndex == false and i == 1 and not value then
key, value = getByPrefixes('')
end
i = i + 1
if value then
return key, value, (i - 1)
else
return nil
end
end
end
--[[
=================================================================
Start of dependency: Module:Logic
=================================================================
]]
local Logic = {}
function Logic.emptyOr(val1, val2, default)
if not Logic.isEmpty(val1) then
return val1
elseif not Logic.isEmpty(val2) then
return val2
else
return default
end
end
function Logic.nilOr(...)
local args = Table.pack(...)
for i = 1, args.n do
local arg = args[i]
local val
if type(arg) == 'function' then
val = arg()
else
val = arg
end
if val ~= nil then
return val
end
end
return nil
end
function Logic.isEmpty(val)
if type(val) == 'table' then
return Table.isEmpty(val)
else
return val == '' or val == nil
end
end
function Logic.isNotEmpty(val)
if type(val) == 'table' then
return Table.isNotEmpty(val)
else
return val ~= nil and val ~= ''
end
end
function Logic.nilIfEmpty(val)
return Logic.isNotEmpty(val) and val or nil
end
function Logic.isDeepEmpty(val)
return Logic.isEmpty(val) or type(val) == 'table' and
Table.all(val, function(key, item) return Logic.isDeepEmpty(item) end)
end
function Logic.isNotDeepEmpty(val)
return not Logic.isDeepEmpty(val)
end
function Logic.readBool(val)
return val == 'true' or val == 't' or val == 'yes' or val == 'y' or val == true or val == '1' or val == 1
end
function Logic.readBoolOrNil(val)
if Logic.readBool(val) then
return true
elseif val == 'false' or val == 'f' or val == 'no' or val == 'n' or val == false or val == '0' or val == 0 then
return false
else
return nil
end
end
function Logic.nilThrows(val)
if val == nil then
error('Unexpected nil', 2)
end
return val
end
function Logic.tryCatch(try, catch)
local ran, result = pcall(try)
if not ran then
catch(result)
else
return result
end
end
function Logic.deepEquals(x, y)
if x == y then
return true
elseif type(x) == 'table' and type(y) == 'table' then
return Table.deepEquals(x, y)
else
return false
end
end
--[[
=================================================================
Start of dependency: Module:Array
=================================================================
]]
local Array = {}
function Array.randomize(tbl)
math.randomseed(os.time())
for i = #tbl, 2, -1 do
local j = math.random(i)
tbl[i], tbl[j] = tbl[j], tbl[i]
end
return tbl
end
function Array.isArray(tbl)
return type(tbl) == 'table' and Table.size(tbl) == #tbl
end
function Array.copy(tbl)
local copy = {}
for _, element in ipairs(tbl) do
table.insert(copy, element)
end
return copy
end
function Array.sub(tbl, startIndex, endIndex)
if startIndex < 0 then startIndex = #tbl + 1 + startIndex end
if not endIndex then endIndex = #tbl end
if endIndex < 0 then endIndex = #tbl + 1 + endIndex end
local subArray = {}
for index = startIndex, endIndex do
table.insert(subArray, tbl[index])
end
return subArray
end
function Array.map(elements, funct)
local mappedArray = {}
for index, element in ipairs(elements) do
local mappedElement = funct(element, index)
table.insert(mappedArray, mappedElement)
end
return mappedArray
end
function Array.filter(tbl, predicate)
local filteredArray = {}
for index, element in ipairs(tbl) do
if predicate(element, index) then
table.insert(filteredArray, element)
end
end
return filteredArray
end
function Array.flatten(tbl)
local flattenedArray = {}
for _, x in ipairs(tbl) do
if type(x) == 'table' then
for _, y in ipairs(x) do
table.insert(flattenedArray, y)
end
else
table.insert(flattenedArray, x)
end
end
return flattenedArray
end
function Array.flatMap(elements, funct)
return Array.flatten(Array.map(elements, funct))
end
function Array.all(tbl, predicate)
for _, element in ipairs(tbl) do
if not predicate(element) then
return false
end
end
return true
end
function Array.any(tbl, predicate)
for _, element in ipairs(tbl) do
if predicate(element) then
return true
end
end
return false
end
function Array.find(tbl, predicate)
for index, element in ipairs(tbl) do
if predicate(element, index) then
return element
end
end
return nil
end
function Array.groupBy(tbl, funct)
local groupsByKey = {}
local groups = {}
for _, xValue in ipairs(tbl) do
local yValue = funct(xValue)
if yValue then
local group = groupsByKey[yValue]
if not group then
group = {}
groupsByKey[yValue] = group
table.insert(groups, group)
end
table.insert(group, xValue)
end
end
return groups, groupsByKey
end
function Array.groupAdjacentBy(array, f, equals)
equals = equals or Logic.deepEquals
local groups = {}
local currentKey
for index, elem in ipairs(array) do
local key = f(elem)
if index == 1 or not equals(key, currentKey) then
currentKey = key
table.insert(groups, {})
end
table.insert(groups[#groups], elem)
end
return groups
end
function Array.lexicalCompare(tblX, tblY)
for index = 1, math.min(#tblX, #tblY) do
if tblX[index] < tblY[index] then
return true
elseif tblX[index] > tblY[index] then
return false
end
end
return #tblX < #tblY
end
function Array.lexicalCompareIfTable(y1, y2)
if type(y1) == 'table' and type(y2) == 'table' then
return Array.lexicalCompare(y1, y2)
else
return y1 < y2
end
end
function Array.sortBy(tbl, funct, compare)
local copy = Table.copy(tbl)
Array.sortInPlaceBy(copy, funct, compare)
return copy
end
function Array.sortInPlaceBy(tbl, funct, compare)
compare = compare or Array.lexicalCompareIfTable
table.sort(tbl, function(x1, x2) return compare(funct(x1), funct(x2)) end)
end
function Array.reverse(tbl)
local reversedArray = {}
for index = #tbl, 1, -1 do
table.insert(reversedArray, tbl[index])
end
return reversedArray
end
function Array.append(tbl, ...)
return Array.appendWith(Array.copy(tbl), ...)
end
function Array.appendWith(tbl, ...)
local elements = Table.pack(...)
for index = 1, elements.n do
if elements[index] ~= nil then
table.insert(tbl, elements[index])
end
end
return tbl
end
function Array.extend(tbl, ...)
return Array.extendWith({}, tbl, ...)
end
function Array.extendWith(tbl, ...)
local arrays = Table.pack(...)
for index = 1, arrays.n do
if type(arrays[index]) == 'table' then
for _, element in ipairs(arrays[index]) do
table.insert(tbl, element)
end
elseif arrays[index] ~= nil then
table.insert(tbl, arrays[index])
end
end
return tbl
end
function Array.mapIndexes(funct)
local arr = {}
for index = 1, math.huge do
local y = funct(index)
if y then
table.insert(arr, y)
else
break
end
end
return arr
end
function Array.range(from, to)
local elements = {}
for element = from, to do
table.insert(elements, element)
end
return elements
end
function Array.extractKeys(tbl, iterator, ...)
iterator = iterator or pairs
local array = {}
for key, _ in iterator(tbl, ...) do
table.insert(array, key)
end
return array
end
function Array.extractValues(tbl, iterator, ...)
iterator = iterator or pairs
local array = {}
for _, item in iterator(tbl, ...) do
table.insert(array, item)
end
return array
end
function Array.forEach(elements, funct)
for index, element in ipairs(elements) do
funct(element, index)
end
end
function Array.reduce(array, operator, initialValue)
local aggregate
if initialValue ~= nil then
aggregate = initialValue
else
aggregate = array[1]
end
for index = initialValue ~= nil and 1 or 2, #array do
aggregate = operator(aggregate, array[index])
end
return aggregate
end
function Array.maxBy(array, funct, compare)
compare = compare or Array.lexicalCompareIfTable
local max, maxScore
for _, item in ipairs(array) do
local score = funct(item)
if max == nil or compare(maxScore, score) then
max = item
maxScore = score
end
end
return max
end
function Array.max(array, compare)
return Array.maxBy(array, function(x) return x end, compare)
end
function Array.minBy(array, funct, compare)
compare = compare or Array.lexicalCompareIfTable
local min, minScore
for _, item in ipairs(array) do
local score = funct(item)
if min == nil or compare(score, minScore) then
min = item
minScore = score
end
end
return min
end
function Array.min(array, compare)
return Array.minBy(array, function(x) return x end, compare)
end
function Array.indexOf(array, pred)
for ix, elem in ipairs(array) do
if pred(elem, ix) then
return ix
end
end
return 0
end
function Array.unique(elements)
local elementCache = {}
local uniqueElements = {}
for _, element in ipairs(elements) do
if elementCache[element] == nil then
table.insert(uniqueElements, element)
elementCache[element] = true
end
end
return uniqueElements
end
function Array.parseCommaSeparatedString(inputString, sep)
if Logic.isEmpty(inputString) then return {} end
return Array.map(mw.text.split(inputString, sep or ','), mw.text.trim)
end
function Array.interleave(elements, x)
local size = #elements
return Array.flatMap(elements, function(element, index)
if index == size then
return {element}
end
return {element, x}
end)
end
--[[
=================================================================
Start of dependency: Module:Operator
=================================================================
]]
local Operator = {}
function Operator.add(a, b) return a + b end
function Operator.sub(a, b) return a - b end
function Operator.mul(a, b) return a * b end
function Operator.div(a, b) return a / b end
function Operator.pow(a, b) return a ^ b end
function Operator.eq(a, b) return a == b end
function Operator.neq(a, b) return a ~= b end
function Operator.lt(a, b) return a < b end
function Operator.le(a, b) return a <= b end
function Operator.gt(a, b) return a > b end
function Operator.ge(a, b) return a >= b end
function Operator.property(item)
assert(type(item) == 'string' or type(item) == 'number', 'Invalid or missing input to `Operator.property`')
local pathSegments = mw.text.split(item, '.', true)
return function(tbl)
local selected = tbl
for segmentIndex, pathSegment in ipairs(pathSegments) do
if type(selected) ~= 'table' and segmentIndex == 1 then
error('Nil supplied to `Operator.property(' .. item .. ')`')
elseif type(selected) ~= 'table' then
local pathUntilHere = Array.sub(pathSegments, 1, segmentIndex - 1)
error('Could not index "tbl.' .. table.concat(pathUntilHere, '.') .. '"')
end
selected = selected[pathSegment] or selected[tonumber(pathSegment)]
end
return selected
end
end
function Operator.method(funcName, ...)
local args = {...}
return function(obj)
return obj[funcName](obj, unpack(args))
end
end
--[[
=================================================================
Start of dependency: Module:Page
=================================================================
]]
local Page = {}
function Page.exists(link)
local existingPage = mw.title.new(link)
if existingPage == nil then
return false
end
return existingPage.exists
end
function Page.makeInternalLink(options, display, customLink)
if type(options) == 'string' then
customLink = display
display = options
end
if Logic.isEmpty(display) then
return nil
elseif Logic.isEmpty(customLink) then
customLink = display
end
if (options or {}).onlyIfExists == true and (not Page.exists(customLink)) then
return nil
end
return '[[' .. customLink .. '|' .. display .. ']]'
end
function Page.makeExternalLink(display, link)
if Logic.isEmpty(display) or Logic.isEmpty(link) then
return nil
end
return '[' .. link .. ' ' .. display .. ']'
end
function Page.pageifyLink(link)
if Logic.isEmpty(link) then
return nil
end
return (mw.ext.TeamLiquidIntegration.resolve_redirect(link):gsub(' ', '_'))
end
--[[
=================================================================
Start of original Module:Tabs code
=================================================================
]]
function Tabs._readArguments(args, options)
local tabArgs = {}
local tabIndex = 1
local this = tonumber(args.This)
local this2 = tonumber(args.This2)
while args['name' .. tabIndex] or args['link' .. tabIndex] do
if args['content' .. tabIndex] or not options.removeEmptyTabs then
table.insert(tabArgs, {
name = Table.extract(args, 'name' .. tabIndex),
link = Table.extract(args, 'link' .. tabIndex),
content = Table.extract(args, 'content' .. tabIndex),
tabs = Table.extract(args, 'tabs' .. tabIndex),
this = this == tabIndex or (options.allowThis2 and this2 == tabIndex),
})
end
tabIndex = tabIndex + 1
end
if Logic.readBool(args.returnIfEmpty) then
return tabArgs
end
assert(Logic.isNotEmpty(tabArgs), 'You are trying to add a "Tabs" template without arguments for names nor links')
return tabArgs
end
function Tabs._setThis(tabArgs)
if Array.any(tabArgs, Operator.property('this')) then return end
local fullPageName = mw.title.getCurrentTitle().prefixedText
local this
local maxLinkLength = -1
Array.forEach(tabArgs, function (tab, tabIndex)
local link = tab.link
if not link then return end
link = link:gsub('_', ' ')
local linkLength = string.len(link)
local charAfter = string.sub(fullPageName, linkLength + 1, linkLength + 1)
local pagePartial = string.sub(fullPageName, 1, linkLength)
if pagePartial == link and (charAfter == '/' or charAfter == '') and linkLength > maxLinkLength then
maxLinkLength = linkLength
this = tabIndex
end
end)
if not this then return end
tabArgs[this].this = true
end
function Tabs._buildContentDiv(hasContent, hybridTabs, noPadding)
if hasContent then
local contentDiv = mw.html.create('div')
:addClass('tabs-content')
if hybridTabs then
contentDiv
:css('border-style', 'none !important')
:css('padding', '0 !important')
elseif noPadding then
contentDiv
:css('padding', '0 !important')
end
return contentDiv
end
local style = ''
if hybridTabs then
style = 'border-style:none !important; padding:0 !important;'
elseif noPadding then
style = 'padding:0 !important;'
end
return '\n<div class="tabs-content" style="' .. style .. '">'
end
function Tabs._single(tab, showHeader)
local header
if showHeader then
header = mw.html.create()
:tag('h6'):wikitext(tab.name):done()
:newline()
end
return mw.html.create()
:node(header)
:node(tab.content)
end
function Tabs._getDisplayNameFromLink(link)
local linkParts = mw.text.split(link, '/', true)
return linkParts[#linkParts]
end
function Tabs.static(args)
args = args or {}
local tabArgs = Tabs._readArguments(args, {allowThis2 = true})
local tabCount = #tabArgs
if tabCount == 0 then return end
Tabs._setThis(tabArgs)
local tabs = mw.html.create('ul')
:attr('class', 'nav nav-tabs navigation-not-searchable tabs tabs' .. tabCount)
:attr('data-nosnippet')
local subTabs = mw.html.create()
Array.forEach(tabArgs, function(tab)
local name = tab.name or Tabs._getDisplayNameFromLink(tab.link)
local text = tab.link and Page.makeInternalLink({}, name, tab.link) or tab.name
tabs:tag('li'):addClass(tab.this and 'active' or nil):wikitext(text)
subTabs:node(tab.this and tab.tabs or nil)
end)
return mw.html.create()
:tag('div')
:addClass('tabs-static')
:attr('data-nosnippet', '')
:node(tabs)
:done()
:node(subTabs)
end
function Tabs.dynamic(args)
args = args or {}
local tabArgs = Tabs._readArguments(args, {removeEmptyTabs = Logic.readBool(args.removeEmptyTabs)})
local tabCount = #tabArgs
if tabCount == 0 then return end
local hasContent = Array.all(tabArgs, function(tab)
return Logic.isNotEmpty(tab.content) end)
local allEmpty = Array.all(tabArgs, function(tab)
return Logic.isEmpty(tab.content) end)
assert(hasContent or allEmpty, 'Some of the tabs have contents while others do not')
local isSingular = tabCount == 1 and hasContent
if isSingular and not Logic.readBool(args.showSingularAsTab) then
return Tabs._single(tabArgs[1], not Logic.readBool(args.suppressHeader))
end
local tabs = mw.html.create('ul')
:addClass('nav nav-tabs tabs tabs' .. tabCount)
if not Array.any(tabArgs, Operator.property('this')) then
tabArgs[1].this = true
end
local build = function(obj, elementType, content, class, isActive)
local element = mw.html.create(elementType)
:addClass(class)
:addClass(isActive and 'active' or nil)
:newline()
:node(content)
obj:newline():node(element)
end
Array.forEach(tabArgs, function(tabData, tabIndex)
build(tabs, 'li', tabData.name, 'tab' .. tabIndex, tabData.this)
end)
if not Logic.nilOr(Logic.readBoolOrNil(args['hide-showall']), isSingular) then
tabs:tag('li')
:addClass('show-all')
:wikitext('Show All')
end
tabs:newline()
local contents = Tabs._buildContentDiv(
hasContent,
Logic.readBool(args['hybrid-tabs']),
Logic.readBool(args['no-padding'])
)
if not hasContent then
return '<div class="tabs-dynamic navigation-not-searchable" data-nosnippet>\n'
.. tostring(tabs) .. contents
end
Array.forEach(tabArgs, function(tabData, tabIndex)
build(contents, 'div', tabData.content, 'content' .. tabIndex, tabData.this)
end)
return mw.html.create('div')
:addClass('tabs-dynamic navigation-not-searchable')
:attr('data-nosnippet')
:node(tabs)
:newline()
:node(contents)
end
return Tabs

Revision as of 19:33, 7 July 2025

Documentation for this module may be created at Module:Sandbox/LVL/doc