diff options
author | bptato <nincsnevem662@gmail.com> | 2024-01-12 00:25:42 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-01-12 00:31:38 +0100 |
commit | 1915e6d25e45a135caaacec1bc9a603510adfad1 (patch) | |
tree | 9512858a73c614a8b789e5845bb9f934667418e9 /src/html | |
parent | 9f26d1b8215cf039b38735d785753dda035103b7 (diff) | |
download | chawan-1915e6d25e45a135caaacec1bc9a603510adfad1.tar.gz |
dom: standard-compliant innerHTML/outerHTML
It's still not perfect, but at least now we do not apply non-standard whitespace changes. The stringifier is left as it is since it's more useful for debugging this way.
Diffstat (limited to 'src/html')
-rw-r--r-- | src/html/dom.nim | 72 | ||||
-rw-r--r-- | src/html/enums.nim | 6 |
2 files changed, 73 insertions, 5 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim index 89716be5..aa8fb982 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -1828,13 +1828,75 @@ func attrb*(element: Element, s: string): bool = return true return false +# https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments +func serializesAsVoid(element: Element): bool = + const Extra = {TAG_BASEFONT, TAG_BGSOUND, TAG_FRAME, TAG_KEYGEN, TAG_PARAM} + return element.tagType in VoidElements + Extra + +func serializeFragment(node: Node): string + +func serializeFragmentInner(child: Node, parentType: TagType): string = + result = "" + if child of Element: + let element = Element(child) + result &= '<' + #TODO qualified name if not HTML, SVG or MathML + result &= element.localName + #TODO custom elements + for k, v in element.attrs: + #TODO namespaced attrs + result &= ' ' & k & "=\"" & v.escapeText(true) & "\"" + result &= '>' + result &= element.serializeFragment() + result &= "</" + result &= element.localName + result &= '>' + elif child of Text: + let text = Text(child) + const LiteralTags = { + TAG_STYLE, TAG_SCRIPT, TAG_XMP, TAG_IFRAME, TAG_NOEMBED, TAG_NOFRAMES, + TAG_PLAINTEXT, TAG_NOSCRIPT + } + result = if parentType in LiteralTags: + text.data + else: + text.data.escapeText() + elif child of Comment: + result &= "<!--" & Comment(child).data & "-->" + elif child of ProcessingInstruction: + let inst = ProcessingInstruction(child) + result &= "<?" & inst.target & " " & inst.data & '>' + elif child of DocumentType: + result &= "<!DOCTYPE " & DocumentType(child).name & '>' + +func serializeFragment(node: Node): string = + var node = node + var parentType = TAG_UNKNOWN + if node of Element: + let element = Element(node) + if element.serializesAsVoid(): + return "" + if element of HTMLTemplateElement: + node = HTMLTemplateElement(element).content + else: + parentType = element.tagType + if parentType == TAG_NOSCRIPT and not element.scriptingEnabled: + # Pretend parentType is not noscript, so we do not append literally + # in serializeFragmentInner. + parentType = TAG_UNKNOWN + var s = "" + for child in node.childList: + s &= child.serializeFragmentInner(parentType) + return s + # Element attribute reflection (getters) -func innerHTML*(element: Element): string {.jsfget.} = - for child in element.childList: - result &= $child +func innerHTML(element: Element): string {.jsfget.} = + #TODO xml + return element.serializeFragment() -func outerHTML*(element: Element): string {.jsfget.} = - return $element +func outerHTML(element: Element): string {.jsfget.} = + #TODO xml + return element.serializeFragmentInner(TAG_UNKNOWN) func crossOrigin0(element: HTMLElement): CORSAttribute = if not element.attrb("crossorigin"): diff --git a/src/html/enums.nim b/src/html/enums.nim index e990495e..24f496bb 100644 --- a/src/html/enums.nim +++ b/src/html/enums.nim @@ -34,6 +34,12 @@ const LabelableElements* = { TAG_BUTTON, TAG_INPUT, TAG_METER, TAG_OUTPUT, TAG_PROGRESS, TAG_SELECT, TAG_TEXTAREA } +# https://html.spec.whatwg.org/multipage/syntax.html#void-elements +const VoidElements* = { + TAG_AREA, TAG_BASE, TAG_BR, TAG_COL, TAG_EMBED, TAG_HR, TAG_IMG, TAG_INPUT, + TAG_LINK, TAG_META, TAG_SOURCE, TAG_TRACK, TAG_WBR +} + func getInputTypeMap(): Table[string, InputType] = for i in InputType: let enumname = $InputType(i) |