about summary refs log tree commit diff stats
path: root/src/html/htmlparser.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-12-18 20:46:30 +0100
committerbptato <nincsnevem662@gmail.com>2022-12-18 20:46:30 +0100
commitbfaf210d87e90016f8f2521657bd04686170aa43 (patch)
treee9711cb2f72174058d88ce2d52a76239e3c54c62 /src/html/htmlparser.nim
parent1fbe17eeddefb87bf8e819be7792ae7a6482d8f8 (diff)
downloadchawan-bfaf210d87e90016f8f2521657bd04686170aa43.tar.gz
Add JS support to documents
Diffstat (limited to 'src/html/htmlparser.nim')
-rw-r--r--src/html/htmlparser.nim68
1 files changed, 42 insertions, 26 deletions
diff --git a/src/html/htmlparser.nim b/src/html/htmlparser.nim
index f04a94f7..999625a8 100644
--- a/src/html/htmlparser.nim
+++ b/src/html/htmlparser.nim
@@ -1,3 +1,4 @@
+import deques
 import macros
 import options
 import sequtils
@@ -9,11 +10,12 @@ import unicode
 
 import css/sheet
 import data/charset
+import encoding/decoderstream
 import html/dom
 import html/tags
 import html/htmltokenizer
-import encoding/decoderstream
 import js/javascript
+import types/url
 import utils/twtstr
 
 type
@@ -205,8 +207,6 @@ func createElement(parser: HTML5Parser, token: Token, namespace: Namespace, inte
   let localName = token.tagname
   let element = document.newHTMLElement(localName, namespace, tagType = token.tagtype)
   element.appendAttributes(token.attrs)
-  #for k, v in token.attrs:
-  #  element.appendAttribute(k, v)
   if element.isResettable():
     element.resetElement()
 
@@ -232,6 +232,8 @@ proc popElement(parser: var HTML5Parser): Element =
   else:
     parser.tokenizer.hasnonhtml = not parser.adjustedCurrentNode().inHTMLNamespace()
 
+template pop_current_node = discard parser.popElement()
+
 proc insert(location: AdjustedInsertionLocation, node: Node) =
   location.inside.insert(node, location.before)
 
@@ -504,16 +506,16 @@ proc pushOntoActiveFormatting(parser: var HTML5Parser, element: Element, token:
       if it[0].localName != element.localName: continue
     if it[0].namespace != element.namespace: continue
     var fail = false
-    for k, v in it[0].attributes:
-      if k notin element.attributes:
+    for k, v in it[0].attrs:
+      if k notin element.attrs:
         fail = true
         break
-      if v != element.attributes[k]:
+      if v != element.attrs[k]:
         fail = true
         break
     if fail: continue
-    for k, v in element.attributes:
-      if k notin it[0].attributes:
+    for k, v in element.attrs:
+      if k notin it[0].attrs:
         fail = true
         break
     if fail: continue
@@ -557,8 +559,6 @@ proc reconstructActiveFormatting(parser: var HTML5Parser) =
 proc clearActiveFormattingTillMarker(parser: var HTML5Parser) =
   while parser.activeFormatting.len > 0 and parser.activeFormatting.pop()[0] != nil: discard
 
-template pop_current_node = discard parser.popElement()
-
 func isHTMLIntegrationPoint(node: Element): bool =
   return false #TODO SVG (NOTE MathML not implemented)
 
@@ -1138,8 +1138,8 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
           discard
         else:
           for k, v in token.attrs:
-            if k notin parser.openElements[0].attributes:
-              parser.openElements[0].attributes[k] = v
+            if k notin parser.openElements[0].attrs:
+              parser.openElements[0].attrs[k] = v
       )
       ("<base>", "<basefont>", "<bgsound>", "<link>", "<meta>", "<noframes>", "<script>", "<style>", "<template>", "<title>",
        "</template>") => (block: parser.processInHTMLContent(token, IN_HEAD))
@@ -1150,8 +1150,8 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
         else:
           parser.framesetOk = false
           for k, v in token.attrs:
-            if k notin parser.openElements[1].attributes:
-              parser.openElements[1].attributes[k] = v
+            if k notin parser.openElements[1].attrs:
+              parser.openElements[1].attrs[k] = v
       )
       "<frameset>" => (block:
         parse_error
@@ -1523,11 +1523,15 @@ proc processInHTMLContent(parser: var HTML5Parser, token: Token, insertionMode =
       )
       "</script>" => (block:
         #TODO microtask
-        pop_current_node
+        let script = HTMLScriptElement(parser.popElement())
         parser.insertionMode = parser.oldInsertionMode
-        #TODO document.write() ?
-        #TODO prepare script element
-        #TODO uh implement scripting or something
+        #TODO document.write() (?)
+        script.prepare()
+        while parser.document.parserBlockingScript != nil:
+          let script = parser.document.parserBlockingScript
+          parser.document.parserBlockingScript = nil
+          #TODO style sheet
+          script.execute()
       )
       TokenType.END_TAG => (block:
         pop_current_node
@@ -2164,12 +2168,18 @@ proc constructTree(parser: var HTML5Parser): Document =
     if parser.needsreinterpret:
       return nil
 
-  #TODO document.write (?)
-  #TODO etc etc...
-
   return parser.document
 
-proc parseHTML5*(inputStream: Stream, cs = none(Charset), fallbackcs = CHARSET_UTF_8): (Document, Charset) =
+proc finishParsing(parser: var HTML5Parser) =
+  while parser.openElements.len > 0:
+    pop_current_node
+  while parser.document.scriptsToExecOnLoad.len > 0:
+    #TODO spin event loop
+    let script = parser.document.scriptsToExecOnLoad.popFirst()
+    script.execute()
+  #TODO events
+
+proc parseHTML*(inputStream: Stream, cs = none(Charset), fallbackcs = CHARSET_UTF_8, window: Window = nil, url: URL = nil): (Document, Charset) =
   var parser: HTML5Parser
   var bom: string
   if cs.isSome:
@@ -2201,8 +2211,14 @@ proc parseHTML5*(inputStream: Stream, cs = none(Charset), fallbackcs = CHARSET_U
   for c in bom:
     decoder.prepend(cast[uint32](c))
   parser.document = newDocument()
+  if window != nil:
+    parser.document.window = window
+    window.document = parser.document
+  parser.document.url = url
   parser.tokenizer = newTokenizer(decoder)
-  return (parser.constructTree(), parser.charset)
+  let document = parser.constructTree()
+  parser.finishParsing()
+  return (document, parser.charset)
 
 proc newDOMParser*(): DOMParser {.jsctor.} =
   new(result)
@@ -2210,12 +2226,12 @@ proc newDOMParser*(): DOMParser {.jsctor.} =
 proc parseFromString*(parser: DOMParser, str: string, t: string): Document {.jserr, jsfunc.} =
   case t
   of "text/html":
-    let (res, _) = parseHTML5(newStringStream(str))
+    let (res, _) = parseHTML(newStringStream(str))
     return res
   of "text/xml", "application/xml", "application/xhtml+xml", "image/svg+xml":
-    JS_THROW JS_InternalError, "XML parsing is not supported yet"
+    JS_ERR JS_InternalError, "XML parsing is not supported yet"
   else:
-    JS_THROW JS_TypeError, "Invalid mime type"
+    JS_ERR JS_TypeError, "Invalid mime type"
 
 proc addHTMLModule*(ctx: JSContext) =
   ctx.registerType(DOMParser)