deploy: 1c90c6cf04
This commit is contained in:
@@ -1,214 +0,0 @@
|
||||
local errorManager = require("errorManager")
|
||||
local PropertySystem = require("propertySystem")
|
||||
local log = require("log")
|
||||
|
||||
local protectedNames = {
|
||||
colors = true,
|
||||
math = true,
|
||||
clamp = true,
|
||||
round = true
|
||||
}
|
||||
|
||||
local mathEnv = {
|
||||
clamp = function(val, min, max)
|
||||
return math.min(math.max(val, min), max)
|
||||
end,
|
||||
round = function(val)
|
||||
return math.floor(val + 0.5)
|
||||
end
|
||||
}
|
||||
|
||||
local function parseExpression(expr, element, propName)
|
||||
expr = expr:gsub("^{(.+)}$", "%1")
|
||||
|
||||
expr = expr:gsub("([%w_]+)%$([%w_]+)", function(obj, prop)
|
||||
if obj == "self" then
|
||||
return string.format('__getState("%s")', prop)
|
||||
elseif obj == "parent" then
|
||||
return string.format('__getParentState("%s")', prop)
|
||||
else
|
||||
return string.format('__getElementState("%s", "%s")', obj, prop)
|
||||
end
|
||||
end)
|
||||
|
||||
expr = expr:gsub("([%w_]+)%.([%w_]+)", function(obj, prop)
|
||||
if protectedNames[obj] then
|
||||
return obj.."."..prop
|
||||
end
|
||||
return string.format('__getProperty("%s", "%s")', obj, prop)
|
||||
end)
|
||||
|
||||
local env = setmetatable({
|
||||
colors = colors,
|
||||
math = math,
|
||||
tostring = tostring,
|
||||
tonumber = tonumber,
|
||||
__getState = function(prop)
|
||||
return element:getState(prop)
|
||||
end,
|
||||
__getParentState = function(prop)
|
||||
return element.parent:getState(prop)
|
||||
end,
|
||||
__getElementState = function(objName, prop)
|
||||
local target = element:getBaseFrame():getChild(objName)
|
||||
if not target then
|
||||
errorManager.header = "Reactive evaluation error"
|
||||
errorManager.error("Could not find element: " .. objName)
|
||||
return nil
|
||||
end
|
||||
return target:getState(prop).value
|
||||
end,
|
||||
__getProperty = function(objName, propName)
|
||||
if objName == "self" then
|
||||
return element.get(propName)
|
||||
elseif objName == "parent" then
|
||||
return element.parent.get(propName)
|
||||
else
|
||||
local target = element:getBaseFrame():getChild(objName)
|
||||
if not target then
|
||||
errorManager.header = "Reactive evaluation error"
|
||||
errorManager.error("Could not find element: " .. objName)
|
||||
return nil
|
||||
end
|
||||
|
||||
return target.get(propName)
|
||||
end
|
||||
end
|
||||
}, { __index = mathEnv })
|
||||
|
||||
if(element._properties[propName].type == "string")then
|
||||
expr = "tostring(" .. expr .. ")"
|
||||
elseif(element._properties[propName].type == "number")then
|
||||
expr = "tonumber(" .. expr .. ")"
|
||||
end
|
||||
|
||||
local func, err = load("return "..expr, "reactive", "t", env)
|
||||
if not func then
|
||||
errorManager.header = "Reactive evaluation error"
|
||||
errorManager.error("Invalid expression: " .. err)
|
||||
return function() return nil end
|
||||
end
|
||||
|
||||
return func
|
||||
end
|
||||
|
||||
local function validateReferences(expr, element)
|
||||
for ref in expr:gmatch("([%w_]+)%.") do
|
||||
if not protectedNames[ref] then
|
||||
if ref == "self" then
|
||||
elseif ref == "parent" then
|
||||
if not element.parent then
|
||||
errorManager.header = "Reactive evaluation error"
|
||||
errorManager.error("No parent element available")
|
||||
return false
|
||||
end
|
||||
else
|
||||
local target = element:getBaseFrame():getChild(ref)
|
||||
if not target then
|
||||
errorManager.header = "Reactive evaluation error"
|
||||
errorManager.error("Referenced element not found: " .. ref)
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local functionCache = setmetatable({}, {__mode = "k"})
|
||||
|
||||
local observerCache = setmetatable({}, {
|
||||
__mode = "k",
|
||||
__index = function(t, k)
|
||||
t[k] = {}
|
||||
return t[k]
|
||||
end
|
||||
})
|
||||
|
||||
local function setupObservers(element, expr, propertyName)
|
||||
if observerCache[element][propertyName] then
|
||||
for _, observer in ipairs(observerCache[element][propertyName]) do
|
||||
observer.target:removeObserver(observer.property, observer.callback)
|
||||
end
|
||||
end
|
||||
|
||||
local observers = {}
|
||||
for ref, prop in expr:gmatch("([%w_]+)%.([%w_]+)") do
|
||||
if not protectedNames[ref] then
|
||||
local target
|
||||
if ref == "self" then
|
||||
target = element
|
||||
elseif ref == "parent" then
|
||||
target = element.parent
|
||||
else
|
||||
target = element:getBaseFrame():getChild(ref)
|
||||
end
|
||||
|
||||
if target then
|
||||
local observer = {
|
||||
target = target,
|
||||
property = prop,
|
||||
callback = function()
|
||||
element:updateRender()
|
||||
end
|
||||
}
|
||||
target:observe(prop, observer.callback)
|
||||
table.insert(observers, observer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
observerCache[element][propertyName] = observers
|
||||
end
|
||||
|
||||
PropertySystem.addSetterHook(function(element, propertyName, value, config)
|
||||
if type(value) == "string" and value:match("^{.+}$") then
|
||||
local expr = value:gsub("^{(.+)}$", "%1")
|
||||
if not validateReferences(expr, element) then
|
||||
return config.default
|
||||
end
|
||||
|
||||
setupObservers(element, expr, propertyName)
|
||||
|
||||
if not functionCache[element] then
|
||||
functionCache[element] = {}
|
||||
end
|
||||
if not functionCache[element][value] then
|
||||
local parsedFunc = parseExpression(value, element, propertyName)
|
||||
functionCache[element][value] = parsedFunc
|
||||
end
|
||||
|
||||
return function(self)
|
||||
local success, result = pcall(functionCache[element][value])
|
||||
if not success then
|
||||
errorManager.header = "Reactive evaluation error"
|
||||
if type(result) == "string" then
|
||||
errorManager.error("Error evaluating expression: " .. result)
|
||||
else
|
||||
errorManager.error("Error evaluating expression")
|
||||
end
|
||||
return config.default
|
||||
end
|
||||
return result
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local BaseElement = {}
|
||||
|
||||
BaseElement.hooks = {
|
||||
destroy = function(self)
|
||||
if observerCache[self] then
|
||||
for propName, observers in pairs(observerCache[self]) do
|
||||
for _, observer in ipairs(observers) do
|
||||
observer.target:removeObserver(observer.property, observer.callback)
|
||||
end
|
||||
end
|
||||
observerCache[self] = nil
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
return {
|
||||
BaseElement = BaseElement
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user