Module:FrameTools: Difference between revisions
Jump to navigation
Jump to search
Mediawiki>ExE Boss Hoist type checks to function start |
m 1 revision imported |
(No difference)
|
Latest revision as of 02:23, 30 April 2021
See Global Lua Modules/FrameTools
- Subpages {{#dpl: | namespace = Module | titlematch = FrameTools/% | skipthispage = false }}
-- <nowiki>
--------------------------------------------------------------------------------
-- This module contains helper functions for dealing with frame objects.
--
-- @script frameTools
-- @alias p
-- @author [[User:DarthKitty]]
-- @author [[User:Dessamator]]
--------------------------------------------------------------------------------
local p = {}
local util = require "libraryUtil"
--------------------------------------------------------------------------------
-- Frame methods are protected by a `checkSelf` function, which makes them more
-- difficult to copy.
--
-- @param {Frame|PseudoFrame} frame
-- The frame of pseudo-frame to copy.
-- @return {PseudoFrame}
--------------------------------------------------------------------------------
function p.copy(frame)
util.checkType("frameTools.copy", 1, frame, "table")
local copy = mw.clone(frame)
-- Point methods on `copy` to their `frame` counterparts
for methodName, method in pairs(frame) do
if type(method) == "function" and methodName ~= "getParent" then
copy[methodName] = function (copy, ...)
return method(frame, ...)
end
end
end
-- This method needs special treatment
function copy:getParent()
local parent = frame:getParent()
if parent then
return p.copy(parent)
end
end
return copy
end
--------------------------------------------------------------------------------
-- Creates a pseudo frame with some useful functions available in
-- [[mw:Extension:Scribunto]], e.g. `newChild`.
--
-- @param[opt] {Frame} frame
-- The frame that provides implementatinos for the `preprocess` method.
-- @param[opt] {table} parentArgs
-- The parameters available on `pseudoFrame:getParent().args`
-- @param[opt] {table} childArgs
-- The parameters available on `pseudoFrame.args`
-- @return {PseudoFrame}
-- The new pseudo-Frame
--------------------------------------------------------------------------------
function p.makePseudoFrame(frame, parentArgs, childArgs)
util.checkType("frameTools.makePseudoFrame", 1, frame, "table", true)
util.checkType("frameTools.makePseudoFrame", 2, parentArgs, "table", true)
util.checkType("frameTools.makePseudoFrame", 3, childArgs, "table", true)
local pseudoFrame = {parent = {}}
local checkSelf = util.makeCheckSelfFunction("pseudoFrame", "frame", pseudoFrame, "PseudoFrame object")
local parentFrame = pseudoFrame.parent
local checkSelfParent = util.makeCheckSelfFunction("pseudoFrame", "frame", parentFrame, "parent PseudoFrame object")
local pArgs = {}
local pTitle
local args = {}
if frame then
args = frame.args
for name in pairs(frame) do
pseudoFrame[name] = function (pseudoFrame, ...)
return frame[name](frame, ...)
end
parentFrame[name] = function (parent, ...)
return pseudoFrame[name](frame, ...)
end
end
if type(frame.getParent) == "function" and frame:getParent() then
pArgs = frame:getParent().args
pTitle = frame:getParent():getTitle()
end
end
parentFrame.args = mw.clone(parentArgs or pArgs)
pseudoFrame.args = mw.clone(childArgs or args)
pseudoFrame.title = mw.title.getCurrentTitle().text
parentFrame.title = pTitle or ""
function pseudoFrame:getTitle()
checkSelf(self, "getTitle")
return self.title
end
function parentFrame:getTitle()
checkSelfParent(self, "getTitle")
return self.title
end
function pseudoFrame:getParent()
checkSelf(self, "getParent")
return self.parent
end
function parentFrame:getParent()
checkSelfParent(self, "getParent")
return self.parent
end
-- Creates a new Frame object that is a child of the current frame, optional
-- arguments and title.
-- Syntax: frame:newChild{title = title, args = table}
function pseudoFrame:newChild(attributes)
checkSelf(self, "newChild")
local tmpTable = p.makePseudoFrame(frame, self.args, attributes.args)
tmpTable.parent.title = self.title
tmpTable.title = attributes.title
return tmpTable
end
function pseudoFrame:showargs()
checkSelf(self, "showargs")
local childParams = "Child parameters:\nKey \t Value"
local parentParams = "Parent parameters:\nKey \t Value"
if self.args then
for k, v in pairs(self.args) do
childParams = childParams .. "\n" .. k .. "\t" .. v
end
end
if self.parent.args then
for k, v in pairs(self.parent.args) do
parentParams = parentParams .. "\n" .. k .. "\t" .. v
end
end
return childParams .. "\n\n" .. parentParams
end
function pseudoFrame:setArgs(childArgs, parentArgs)
checkSelf(self, "setArgs")
if childArgs then
self.args = childArgs or {}
end
if parentArgs then
self.parent.args = parentArgs
end
end
local function preprocessMock(parent) return function(self, opt)
if parent then
checkSelfParent(self, "expandTemplate")
else
checkSelf(self, "expandTemplate")
end
local text
if type(opt) == "table" then
text = opt.text
else
text = opt
end
text = tostring(text)
return text
end end
if not pseudoFrame.preprocess then
pseudoFrame.preprocess = preprocessMock()
end
if not pseudoFrame.parent.preprocess then
pseudoFrame.parent.preprocess = preprocessMock("parent")
end
local function expandTemplateMock(parent) return function(self, opt)
if parent then
checkSelfParent(self, "expandTemplate")
else
checkSelf(self, "expandTemplate")
end
if type(opt) ~= "table" then
error("frame:expandTemplate: the first parameter must be a table")
end
local title
if opt.title == nil then
error("frame:expandTemplate: a title is required")
else
title = tostring(opt.title)
end
local args
if opt.args == nil then
args = {}
elseif type(opt.args) == "table" then
args = opt.args
else
error("frame:expandTitle: args must be a table")
end
local keys = {}
for k in pairs(args) do
table.insert(keys, k)
end
table.sort(keys)
local text = {}
table.insert(text, "{{" .. title)
local anonymous_index = 0
for _, k in ipairs(keys) do
table.insert(text, "|" .. (tonumber(k) == (anonymous_index + 1) and "" or (" " .. k .. " = ")) .. args[k])
if tonumber(k) == (anonymous_index + 1) then anonymous_index = anonymous_index + 1 end
end
table.insert(text, "}}")
text = table.concat(text, '\n')
return text
end end
if not pseudoFrame.expandTemplate then
pseudoFrame.expandTemplate = expandTemplateMock()
end
if not parentFrame.expandTemplate then
parentFrame.expandTemplate = expandTemplateMock("parent")
end
if mw.getCurrentFrame() == nil then
_G.mw.getCurrentFrame = function() return pseudoFrame end
end
return pseudoFrame
end
--------------------------------------------------------------------------------
-- Returns a frame-like object with the given arguments removed.
--
-- @param {Frame|PseudoFrame} frame
-- The Frame to copy
-- @param[opt] ...
-- The arguments to omit from the new `Frame`'s `args` property
-- @return {PseudoFrame}
--------------------------------------------------------------------------------
function p.removeArgs(frame, ...)
util.checkType("frameTools.removeArgs", 1, frame, "table")
local pseudoFrame = p.copy(frame)
local args = pseudoFrame.args
local metatable = getmetatable(args)
-- disable arg caching
metatable.__index = nil
metatable.__pairs = nil
-- remove args
for _, arg in ipairs{...} do
args[arg] = nil
end
return pseudoFrame
end
--------------------------------------------------------------------------------
-- A frame-like object that provides mock implementations for the most common
-- @{Frame|mw.frame} instance methods and properties
--
-- @type {Frame} PseudoFrame
--------------------------------------------------------------------------------
return p
-- </nowiki>
-- (Add categories here.)