--!strict local _, _G = ... function _G.HTML.append_attribute(node, attr, value) HTML.set_attribute(node, attr, HTML.get_attribute(node, attr) .. value) end function _G.HTML.replace_element(orig, new) HTML.insert_after(orig, new) HTML.delete_element(orig) end function _G.HTML.replace_content(parent, child) HTML.delete_content(parent) HTML.append_child(parent, child) end function _G.HTML.wrap(node, elem) assert(not HTML.is_document(elem), "`wrap` cannot be used on document nodes", 2) HTML.insert_after(node, elem) HTML.append_child(elem, node) end function _G.HTML.swap(node_a, node_b) assert(not HTML.is_document(node_a) and not HTML.is_document(node_b), "`swap` cannot be used on document nodes") local temp_node = HTML.create_text("") HTML.insert_after(node_a, temp_node) HTML.insert_after(node_b, node_a) HTML.insert_after(temp_node, node_b) HTML.delete_element(temp_node) end _G.HTML.append = HTML.append_child _G.HTML.delete = HTML.delete_element _G.HTML.prepend = HTML.prepend_child -- Advanced functions local function get_heading_level(element) if typeof(element) == "NodeRef" and HTML.is_element(element) then local tag = HTML.get_tag_name(element) local match = string.match(tag, "h([0-9]+)") if match then return tonumber(match) else return 0 end else return 0 end end _G.HTML.get_heading_level = get_heading_level function _G.HTML.get_headings_tree(element) local all_headings = HTML.select(element, "h1,h2,h3,h4,h5,h6") local stack = {} type Recursion = { root: boolean?, heading: NodeRef, children: { Recursion }, } local current: { base_level: number, obj: Recursion, } = { base_level = 0, obj = { root = true, heading = HTML.parse("a"), children = {}, }, } -- process all headings for _, heading in all_headings do local level = get_heading_level(heading) -- pop to the appropriate level while level <= current.base_level do if #stack == 0 then return error("stack underflow while processing heading tree") end local top = table.pop(stack) table.insert(top.obj.children, current.obj) current = top end -- push a new frame table.insert(stack, current) current = { base_level = level, obj = { heading = heading, children = {}, }, } end -- pop any remaining stack items while #stack > 0 do local top = table.pop(stack) table.insert(top.obj.children, current.obj) current = top end assert(current.obj.root) -- Fix multiple frames local out = current.obj.children[1] for i = 2, #current.obj.children do table.insert(out.children, current.obj.children[i]) end return out end -- TODO: Implement `HTML.get_headings_tree`