2024-08-02 18:33:00 -03:00
|
|
|
local WATCH_CYCLE_CHECK_MS = 50
|
2024-07-16 21:36:58 -03:00
|
|
|
local OFICIAL_HTML_CSS = {}
|
|
|
|
|
|
2024-07-26 14:01:35 -03:00
|
|
|
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)
|
2024-07-26 14:01:35 -03:00
|
|
|
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-26 14:01:35 -03:00
|
|
|
|
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,
|
2024-08-02 18:33:00 -03:00
|
|
|
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
|
|
|
|
|
|
2024-07-26 14:01:35 -03:00
|
|
|
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
|
|
|
|
|
|
2024-07-26 14:01:35 -03:00
|
|
|
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)
|
|
|
|
|
|
2024-07-26 14:01:35 -03:00
|
|
|
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 = {}
|
2024-07-26 14:01:35 -03:00
|
|
|
local prevEl = nil
|
2024-07-16 21:36:58 -03:00
|
|
|
for _, el in pairs(root.nodes) do
|
|
|
|
|
el.prev = prevEl
|
2024-07-26 14:01:35 -03:00
|
|
|
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('*')
|
2024-07-26 14:01:35 -03:00
|
|
|
for i = #all, 1, -1 do
|
|
|
|
|
local el = all[i]
|
2024-07-16 21:36:58 -03:00
|
|
|
if el.widget then
|
2024-07-26 14:01:35 -03:00
|
|
|
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
|
2024-08-02 18:33:00 -03:00
|
|
|
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
|
2024-08-02 18:33:00 -03:00
|
|
|
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
|
2024-08-02 18:33:00 -03:00
|
|
|
end, WATCH_CYCLE_CHECK_MS)
|
2024-07-16 21:36:58 -03:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
end
|