otclient-redemption/modules/modulelib/htmlloader.lua

194 lines
5.9 KiB
Lua
Raw Permalink Normal View History

local WATCH_CYCLE_CHECK_MS = 50
2024-07-16 21:36:58 -03:00
local OFICIAL_HTML_CSS = {}
local parseCss, parseAndSetDisplayAttr, parseAndSetFloatStyle = dofile('ext/style')
local parseStyle, parseLayout, parseExpression = dofile('ext/parse')
local parseEvents, onCreateWidget, setText, createRadioGroup, afterLoadElement = dofile('ext/parseevent')
2024-07-16 21:36:58 -03:00
local translateStyleName, translateAttribute = dofile('ext/translator')
local function readNode(el, parent, controller, watchList)
local styleName = g_ui.getStyleName(translateStyleName(el.name, el))
2024-07-16 21:36:58 -03:00
local widget = g_ui.createWidget(styleName ~= '' and styleName or 'UIWidget', parent or rootWidget)
widget:setOnHtml(true)
2024-07-16 21:36:58 -03:00
el.widget = widget
onCreateWidget(el, widget, controller)
for attr, v in pairs(el.attributes) do
2024-09-18 18:39:39 -03:00
local attr = translateAttribute(styleName, el.name, attr)
2024-07-16 21:36:58 -03:00
if attr:starts('on') then
parseEvents(el, widget, attr:lower(), v, controller)
elseif attr == 'anchor' then
-- ignore
elseif attr == 'style' then
parseStyle(widget, el)
elseif attr == 'layout' then
parseLayout(widget, el)
elseif attr == 'class' then
for _, className in pairs(v:split(' ')) do
local css = g_ui.getStyle(className)
if css then
widget:mergeStyle(css)
end
end
else
local methodName = ''
for _, _name in pairs(attr:trim():split('-')) do
methodName = methodName .. _name:gsub("^%l", string.upper)
end
local watchObj = nil
local isExp = methodName:starts('*')
if isExp then
methodName = methodName:sub(2):gsub("^%l", string.upper)
local vStr = v
local f = loadstring('return function(self, target) return ' .. vStr .. ' end')
local fnc = f()
v = fnc(controller)
watchObj = {
widget = widget,
res = v,
el = el,
2024-07-16 21:36:58 -03:00
method = nil,
fnc = function(self)
2024-08-29 18:07:23 -03:00
local value = fnc(controller, self.widget)
2024-07-16 21:36:58 -03:00
if value ~= self.res then
self.method(self.widget, value)
self.res = value
end
end
}
elseif v == '' or v == methodName then
v = true
end
v = tonumber(v) or toboolean(v) or v
local method = nil
if methodName == 'Text' then
method = function(widget, v) setText(el, v) end
else
method = widget['set' .. methodName]
end
2024-07-16 21:36:58 -03:00
if method then
method(widget, v)
if watchObj then
watchObj.method = method
table.insert(watchList, watchObj)
end
else
local _name = string.sub(methodName, 1, 1):lower() .. string.sub(methodName, 2, -1)
widget[_name] = v
end
end
end
if #el.nodes > 0 then
if not widget.HTML_onReadNodes or widget:HTML_onReadNodes(el.nodes) then
local prevEl = nil
for _, chield in pairs(el.nodes) do
chield.prev = prevEl
readNode(chield, widget, controller, watchList)
prevEl = chield
end
end
end
return widget
end
parseCss(io.content('modulelib/html.css'), OFICIAL_HTML_CSS, false)
2024-07-16 21:36:58 -03:00
function HtmlLoader(path, parent, controller)
HTML_PATH = path
local cssList = {}
table.insertall(cssList, OFICIAL_HTML_CSS)
local root = HtmlParser.parse(parseExpression(io.content(path), controller))
2024-07-16 21:36:58 -03:00
root.widget = nil
root.path = path
local watchList = {}
local prevEl = nil
2024-07-16 21:36:58 -03:00
for _, el in pairs(root.nodes) do
el.prev = prevEl
if el.name == 'style' then
parseCss(el:getcontent(), cssList, true)
elseif el.name == 'link' then
local href = el.attributes.href
if href then
parseCss(io.content(href), cssList, true)
end
2024-07-16 21:36:58 -03:00
else
root.widget = readNode(el, parent, controller, watchList)
end
prevEl = el
end
for _, css in pairs(cssList) do
local els = root:find(css.selector)
if css.checkExist and #els == 0 then
pwarning('[' .. path .. '][style] selector(' .. css.selector .. ') no element was found.')
end
for _, el in pairs(els) do
if not el.style then
el.style = {};
end
table.merge(el.style, css.attrs)
if el.widget then
el.widget:mergeStyle(el.style)
end
end
end
local radioGroups = {}
local all = root:find('*')
for i = #all, 1, -1 do
local el = all[i]
2024-07-16 21:36:58 -03:00
if el.widget then
parseAndSetDisplayAttr(el)
parseAndSetFloatStyle(el)
if el.name == 'input' and el.attributes.type == 'radio' then
createRadioGroup(el, radioGroups, controller)
end
afterLoadElement(el)
2024-07-16 21:36:58 -03:00
end
end
if #watchList > 0 then
local event = nil
event = controller:cycleEvent(function()
table.remove_if(watchList, function(i, obj)
local isDestroyed = obj.widget:isDestroyed()
if isDestroyed then
2024-08-29 18:07:23 -03:00
obj.widget = nil
obj.el.widget = nil
else
obj.fnc(obj)
end
return isDestroyed
end)
if #watchList == 0 then
removeEvent(event)
2024-07-16 21:36:58 -03:00
end
end, WATCH_CYCLE_CHECK_MS)
2024-07-16 21:36:58 -03:00
end
return root
end