about summary refs log tree commit diff stats
path: root/src/html
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-07-14 00:42:30 +0200
committerbptato <nincsnevem662@gmail.com>2022-07-14 01:13:27 +0200
commit82dd9ac98d40b0416b392b6c82c7fe1acc8fb9de (patch)
tree183b6ed235cd863e2bcd32ce02267e3d3de4504e /src/html
parentbb7a5ddcc44d8aab63d6463ce1cb72490e03c3e1 (diff)
downloadchawan-82dd9ac98d40b0416b392b6c82c7fe1acc8fb9de.tar.gz
Clean up HTML namespace mess, enable processInForeignContent
Diffstat (limited to 'src/html')
-rw-r--r--src/html/dom.nim17
-rw-r--r--src/html/htmlparser.nim100
2 files changed, 91 insertions, 26 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index e412a366..8562caa0 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -22,6 +22,7 @@ type
     NO_QUIRKS, QUIRKS, LIMITED_QUIRKS
 
   Namespace* = enum
+    NO_NAMESPACE,
     HTML = "http://www.w3.org/1999/xhtml",
     MATHML = "http://www.w3.org/1998/Math/MathML",
     SVG = "http://www.w3.org/2000/svg",
@@ -516,13 +517,8 @@ func newComment*(document: Document, data: string = ""): Comment =
   result.data = data
   result.rootNode = result
 
-func namespace(s: string): Option[Namespace] =
-  for n in Namespace:
-    if s == $n:
-      return some(n)
-
 # note: we do not implement custom elements
-func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace.HTML, prefix = Option[string]): HTMLElement =
+func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace.HTML, prefix = none[string]()): HTMLElement =
   case tagType
   of TAG_INPUT:
     result = new(HTMLInputElement)
@@ -569,12 +565,15 @@ func newHTMLElement*(document: Document, tagType: TagType, namespace = Namespace
   result.nodeType = ELEMENT_NODE
   result.tagType = tagType
   result.css = rootProperties()
+  result.namespace = namespace
+  result.namespacePrefix = prefix
   result.rootNode = result
   result.document = document
 
-func newHTMLElement*(document: Document, localName: string, namespace = "", prefix = none[string](), tagType = tagType(localName)): Element =
-  result = document.newHTMLElement(tagType, namespace(namespace).get(HTML))
-  result.namespacePrefix = prefix
+func newHTMLElement*(document: Document, localName: string, namespace = Namespace.HTML, prefix = none[string](), tagType = tagType(localName)): Element =
+  result = document.newHTMLElement(tagType, namespace, prefix)
+  if tagType == TAG_UNKNOWN:
+    result.localName = localName
 
 func newDocument*(): Document =
   new(result)
diff --git a/src/html/htmlparser.nim b/src/html/htmlparser.nim
index a9c9b1fd..dfd10589 100644
--- a/src/html/htmlparser.nim
+++ b/src/html/htmlparser.nim
@@ -188,7 +188,7 @@ func hasElementInSelectScope(elements: seq[Element], target: TagType): bool =
       return false
   assert false
 
-func createElement(parser: HTML5Parser, token: Token, namespace: string, intendedParent: Node): Element =
+func createElement(parser: HTML5Parser, token: Token, namespace: Namespace, intendedParent: Node): Element =
   #TODO custom elements
   let document = intendedParent.document
   let localName = token.tagname
@@ -208,7 +208,7 @@ func createElement(parser: HTML5Parser, token: Token, namespace: string, intende
 proc insert(location: AdjustedInsertionLocation, node: Node) =
   location.inside.insert(node, location.before)
 
-proc insertForeignElement(parser: var HTML5Parser, token: Token, namespace: string): Element =
+proc insertForeignElement(parser: var HTML5Parser, token: Token, namespace: Namespace): Element =
   let location = parser.appropriatePlaceForInsert()
   let element = parser.createElement(token, namespace, location.inside)
   if location.inside.preInsertionValidity(element, location.before):
@@ -218,7 +218,75 @@ proc insertForeignElement(parser: var HTML5Parser, token: Token, namespace: stri
   return element
 
 proc insertHTMLElement(parser: var HTML5Parser, token: Token): Element =
-  return parser.insertForeignElement(token, $Namespace.HTML)
+  return parser.insertForeignElement(token, Namespace.HTML)
+
+proc adjustSVGAttributes(token: var Token) =
+  const adjusted = {
+    "attributename": "attributeName",
+    "attributetype": "attributeType",
+    "basefrequency": "baseFrequency",
+    "baseprofile": "baseProfile",
+    "calcmode": "calcMode",
+    "clippathunits": "clipPathUnits",
+    "diffuseconstant": "diffuseConstant",
+    "edgemode": "edgeMode",
+    "filterunits": "filterUnits",
+    "glyphref": "glyphRef",
+    "gradienttransform": "gradientTransform",
+    "gradientunits": "gradientUnits",
+    "kernelmatrix": "kernelMatrix",
+    "kernelunitlength": "kernelUnitLength",
+    "keypoints": "keyPoints",
+    "keysplines": "keySplines",
+    "keytimes": "keyTimes",
+    "lengthadjust": "lengthAdjust",
+    "limitingconeangle": "limitingConeAngle",
+    "markerheight": "markerHeight",
+    "markerunits": "markerUnits",
+    "markerwidth": "markerWidth",
+    "maskcontentunits": "maskContentUnits",
+    "maskunits": "maskUnits",
+    "numoctaves": "numOctaves",
+    "pathlength": "pathLength",
+    "patterncontentunits": "patternContentUnits",
+    "patterntransform": "patternTransform",
+    "patternunits": "patternUnits",
+    "pointsatx": "pointsAtX",
+    "pointsaty": "pointsAtY",
+    "pointsatz": "pointsAtZ",
+    "preservealpha": "preserveAlpha",
+    "preserveaspectratio": "preserveAspectRatio",
+    "primitiveunits": "primitiveUnits",
+    "refx": "refX",
+    "refy": "refY",
+    "repeatcount": "repeatCount",
+    "repeatdur": "repeatDur",
+    "requiredextensions": "requiredExtensions",
+    "requiredfeatures": "requiredFeatures",
+    "specularconstant": "specularConstant",
+    "specularexponent": "specularExponent",
+    "spreadmethod": "spreadMethod",
+    "startoffset": "startOffset",
+    "stddeviation": "stdDeviation",
+    "stitchtiles": "stitchTiles",
+    "surfacescale": "surfaceScale",
+    "systemlanguage": "systemLanguage",
+    "tablevalues": "tableValues",
+    "targetx": "targetX",
+    "targety": "targetY",
+    "textlength": "textLength",
+    "viewbox": "viewBox",
+    "viewtarget": "viewTarget",
+    "xchannelselector": "xChannelSelector",
+    "ychannelselector": "yChannelSelector",
+    "zoomandpan": "zoomAndPan",
+  }.toTable()
+  var todo: seq[string]
+  for k in token.attrs.keys:
+    if k in adjusted:
+      todo.add(k)
+  for s in todo:
+    token.attrs[adjusted[s]] = token.attrs[s]
 
 template insert_character_impl(parser: var HTML5Parser, data: typed) =
   let location = parser.appropriatePlaceForInsert()
@@ -407,7 +475,7 @@ proc pushOntoActiveFormatting(parser: var HTML5Parser, element: Element, token:
     if it[0] == nil: break
     if it[0].tagType != element.tagType: continue
     if it[0].tagType == TAG_UNKNOWN:
-      if it[0].localName != element.localName: continue #TODO local or qualified?
+      if it[0].localName != element.localName: continue
     if it[0].namespace != element.namespace: continue
     var fail = false
     for k, v in it[0].attributes:
@@ -481,7 +549,8 @@ func isHTMLIntegrationPoint(node: Element): bool =
 # * Finally, the whole thing is wrapped in a named block, to implement a
 #   pseudo-goto by breaking out only when the else statement needn't be
 #   executed.
-# So for example the following code:
+#
+# e.g. the following code:
 #
 #   match token:
 #     TokenType.COMMENT => (block: echo "comment")
@@ -686,7 +755,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
       TokenType.COMMENT => (block: parser.insertComment(token, last_child_of(parser.document)))
       AsciiWhitespace => (block: discard)
       "<html>" => (block:
-        let element = parser.createElement(token, $Namespace.HTML, parser.document)
+        let element = parser.createElement(token, Namespace.HTML, parser.document)
         parser.document.append(element)
         parser.openElements.add(element)
         parser.insertionMode = BEFORE_HEAD
@@ -694,7 +763,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
       ("</head>", "</body>", "</html>", "</br>") => (block: anything_else)
       TokenType.END_TAG => (block: parse_error)
       _ => (block:
-        let element = parser.document.newHTMLElement(TAG_HTML)
+        let element = parser.document.newHTMLElement(TAG_HTML, Namespace.HTML)
         parser.document.append(element)
         parser.openElements.add(element)
         parser.insertionMode = BEFORE_HEAD
@@ -745,7 +814,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
       ("<noframes>", "<style>") => (block: parser.genericRawtextElementParsingAlgorithm(token))
       "<script>" => (block:
         let location = parser.appropriatePlaceForInsert()
-        let element = HTMLScriptElement(parser.createElement(token, $Namespace.HTML, location.inside))
+        let element = HTMLScriptElement(parser.createElement(token, Namespace.HTML, location.inside))
         element.parserDocument = parser.document
         element.forceAsync = false
         if parser.fragment:
@@ -847,7 +916,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
       while parser.openElements.pop().tagType != TAG_P: discard
 
     proc adoptionAgencyAlgorithm(parser: var HTML5Parser, token: Token): bool =
-      if parser.currentNode.tagType != TAG_UNKNOWN and parser.currentNode.tagtype == token.tagtype or parser.currentNode.localName == token.tagname: #TODO local or qualified name?
+      if parser.currentNode.tagType != TAG_UNKNOWN and parser.currentNode.tagtype == token.tagtype or parser.currentNode.localName == token.tagname:
         var fail = true
         for it in parser.activeFormatting:
           if it[0] == parser.currentNode:
@@ -919,7 +988,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
             if nodeStackIndex < furthestBlockIndex:
               dec furthestBlockIndex
             continue
-          let element = parser.createElement(parser.activeFormatting[nodeFormattingIndex][1], $Namespace.HTML, commonAncestor)
+          let element = parser.createElement(parser.activeFormatting[nodeFormattingIndex][1], Namespace.HTML, commonAncestor)
           parser.activeFormatting[nodeFormattingIndex] = (element, parser.activeFormatting[nodeFormattingIndex][1])
           parser.openElements[nodeFormattingIndex] = element
           aboveNode = parser.openElements[nodeFormattingIndex - 1]
@@ -931,7 +1000,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
         let location = parser.appropriatePlaceForInsert(commonAncestor)
         location.inside.insert(lastNode, location.before)
         let token = parser.activeFormatting[formattingIndex][1]
-        let element = parser.createElement(token, $Namespace.HTML, furthestBlock)
+        let element = parser.createElement(token, Namespace.HTML, furthestBlock)
         for child in furthestBlock.childNodes:
           child.remove()
           element.append(child)
@@ -948,7 +1017,7 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
     template any_other_end_tag() =
       for i in countdown(parser.openElements.high, 0):
         let node = parser.openElements[i]
-        if node.tagType != TAG_UNKNOWN and node.tagType == token.tagtype or node.localName == token.tagname: #TODO local or qualified name?
+        if node.tagType != TAG_UNKNOWN and node.tagType == token.tagtype or node.localName == token.tagname:
           parser.generateImpliedEndTags(token.tagtype)
           if node != parser.currentNode: parse_error
           while parser.openElements.pop() != node: discard
@@ -1900,7 +1969,6 @@ proc processInForeignContent(parser: var HTML5Parser, token: Token) =
       if node.namespace == Namespace.HTML: break
       parser.processInHTMLContent(token)
 
-
   match token:
     '\0' => (block:
       parse_error
@@ -1926,7 +1994,7 @@ proc processInForeignContent(parser: var HTML5Parser, token: Token) =
       #NOTE MathML not implemented
       #TODO SVG
       #TODO adjust foreign attributes
-      let element = parser.insertForeignElement(token, $parser.adjustedCurrentNode.namespace)
+      let element = parser.insertForeignElement(token, parser.adjustedCurrentNode.namespace)
       if token.selfclosing and element.inSVGNamespace():
         script_end_tag
       else:
@@ -1953,9 +2021,7 @@ proc constructTree(parser: var HTML5Parser): Document =
       #NOTE MathML not implemented
       parser.processInHTMLContent(token)
     else:
-      #TODO disabled path because I'm pretty sure it'd just break things
-      #parser.processInForeignContent(token)
-      pop_current_node
+      parser.processInForeignContent(token)
 
   #TODO document.write (?)
   #TODO etc etc...