diff options
Diffstat (limited to 'src/html')
-rw-r--r-- | src/html/chadombuilder.nim | 41 | ||||
-rw-r--r-- | src/html/dom.nim | 34 |
2 files changed, 66 insertions, 9 deletions
diff --git a/src/html/chadombuilder.nim b/src/html/chadombuilder.nim index f070fe8f..129082e2 100644 --- a/src/html/chadombuilder.nim +++ b/src/html/chadombuilder.nim @@ -12,6 +12,7 @@ import types/url import chakasu/charset import chame/htmlparser +import chame/htmltokenizer import chame/tags # DOMBuilder implementation for Chawan. @@ -166,7 +167,8 @@ proc elementPopped(builder: DOMBuilder[Node], element: Node) = #TODO style sheet script.execute() -proc newChaDOMBuilder(url: URL, window: Window): ChaDOMBuilder = +proc newChaDOMBuilder(url: URL, window: Window, isFragment = false): + ChaDOMBuilder = let document = newDocument() document.contentType = "text/html" document.url = url @@ -196,8 +198,44 @@ proc newChaDOMBuilder(url: URL, window: Window): ChaDOMBuilder = setScriptAlreadyStarted: setScriptAlreadyStarted, associateWithForm: associateWithForm, #TODO isSVGIntegrationPoint (SVG support) + isFragment: isFragment ) +# https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-fragments +proc parseHTMLFragment*(element: Element, s: string): seq[Node] = + let url = parseURL("about:blank").get + let builder = newChaDOMBuilder(url, nil) + builder.isFragment = true + let document = Document(builder.document) + document.mode = element.document.mode + let state = case element.tagType + of TAG_TITLE, TAG_TEXTAREA: RCDATA + of TAG_STYLE, TAG_XMP, TAG_IFRAME, TAG_NOEMBED, TAG_NOFRAMES: RAWTEXT + of TAG_SCRIPT: SCRIPT_DATA + of TAG_NOSCRIPT: + if element.document != nil and element.document.scriptingEnabled: + RAWTEXT + else: + DATA + of TAG_PLAINTEXT: + PLAINTEXT + else: DATA + let root = document.newHTMLElement(TAG_HTML) + document.append(root) + let opts = HTML5ParserOpts[Node]( + isIframeSrcdoc: false, #TODO? + scripting: false, + canReinterpret: false, + charsets: @[CHARSET_UTF_8], + ctx: some(Node(element)), + initialTokenizerState: state, + openElementsInit: @[Node(root)], + pushInTemplate: element.tagType == TAG_TEMPLATE + ) + let inputStream = newStringStream(s) + parseHTML(inputStream, builder, opts) + return root.childList + proc parseHTML*(inputStream: Stream, window: Window, url: URL, charsets: seq[Charset] = @[], canReinterpret = true): Document = let builder = newChaDOMBuilder(url, window) @@ -207,7 +245,6 @@ proc parseHTML*(inputStream: Stream, window: Window, url: URL, canReinterpret: canReinterpret, charsets: charsets ) - builder.isFragment = opts.ctx.isSome parseHTML(inputStream, builder, opts) return Document(builder.document) diff --git a/src/html/dom.nim b/src/html/dom.nim index 0363c0cd..efae857c 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -154,7 +154,7 @@ type liveCollections: HashSet[int] children_cached: HTMLCollection childNodes_cached: NodeList - document_internal: Document + document_internal: Document # not nil Attr* = ref object of Node namespaceURI* {.jsget.}: string @@ -1423,8 +1423,6 @@ func scriptingEnabled*(document: Document): bool = return document.window.settings.scripting func scriptingEnabled*(element: Element): bool = - if element.document == nil: - return false return element.document.scriptingEnabled func form*(element: FormAssociatedElement): HTMLFormElement = @@ -2604,11 +2602,14 @@ proc removeChild(parent, node: Node): DOMResult[Node] {.jsfunc.} = return ok(node) proc replaceAll(parent, node: Node) = - for i in countdown(parent.childList.high, 0): - parent.childList[i].remove(true) + var removedNodes = parent.childList # copy + for child in removedNodes: + child.remove(true) + assert parent != node if node != nil: if node.nodeType == DOCUMENT_FRAGMENT_NODE: - for child in node.childList: + var addedNodes = node.childList # copy + for child in addedNodes: parent.append(child) else: parent.append(node) @@ -2648,7 +2649,7 @@ proc renderBlocking*(element: Element): bool = proc blockRendering*(element: Element) = let document = element.document - if document != nil and document.contentType == "text/html" and document.body == nil: + if document.contentType == "text/html" and document.body == nil: element.document.renderBlockingElements.add(element) proc markAsReady(element: HTMLScriptElement, res: ScriptResult) = @@ -3044,6 +3045,25 @@ proc toBlob(ctx: JSContext, this: HTMLCanvasElement, callback: JSValue, JS_FreeValue(ctx, res) return JS_UNDEFINED +import html/chadombuilder +# https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm +proc fragmentParsingAlgorithm(element: Element, s: string): DocumentFragment = + #TODO xml + let newChildren = parseHTMLFragment(element, s) + let fragment = element.document.newDocumentFragment() + for child in newChildren: + fragment.append(child) + return fragment + +proc innerHTML(element: Element, s: string) {.jsfset.} = + #TODO shadow root + let fragment = fragmentParsingAlgorithm(element, s) + let ctx = if element.tagType == TAG_TEMPLATE: + HTMLTemplateElement(element).content + else: + element + ctx.replaceAll(fragment) + proc registerElements(ctx: JSContext, nodeCID: JSClassID) = let elementCID = ctx.registerType(Element, parent = nodeCID) const extra_getset = getElementReflectFunctions() |