about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2025-01-10 21:22:05 +0100
committerbptato <nincsnevem662@gmail.com>2025-01-10 21:28:58 +0100
commit79b46e28b1518f59cc34c4907fadaff7e8cc4c54 (patch)
tree9cad6dfc9c3d667b9026d9f8f92bd20a41d7fa4a /src
parent8ce8a12bef5b820b5cd7a3e95291a1c0a4328d84 (diff)
downloadchawan-79b46e28b1518f59cc34c4907fadaff7e8cc4c54.tar.gz
dom: add createDocument
Diffstat (limited to 'src')
-rw-r--r--src/html/catom.nim10
-rw-r--r--src/html/dom.nim64
2 files changed, 55 insertions, 19 deletions
diff --git a/src/html/catom.nim b/src/html/catom.nim
index 1900a502..c9927ab3 100644
--- a/src/html/catom.nim
+++ b/src/html/catom.nim
@@ -6,6 +6,7 @@ import std/strutils
 import chame/tags
 import monoucha/fromjs
 import monoucha/javascript
+import monoucha/quickjs
 import monoucha/tojs
 import types/opt
 import utils/twtstr
@@ -319,9 +320,12 @@ proc toStr*(ctx: JSContext; sa: StaticAtom): string =
   return ctx.getFactoryImpl().toStr(sa)
 
 proc fromJS*(ctx: JSContext; val: JSValue; res: var CAtom): Opt[void] =
-  var s: string
-  ?ctx.fromJS(val, s)
-  res = ctx.getFactoryImpl().toAtom(s)
+  if JS_IsNull(val):
+    res = CAtomNull
+  else:
+    var s: string
+    ?ctx.fromJS(val, s)
+    res = ctx.getFactoryImpl().toAtom(s)
   return ok()
 
 proc fromJS*(ctx: JSContext; val: JSAtom; res: var CAtom): Opt[void] =
diff --git a/src/html/dom.nim b/src/html/dom.nim
index e792fdbe..fe500fd1 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -226,6 +226,8 @@ type
 
     internalCookie: string
 
+  XMLDocument = ref object of Document
+
   CharacterData* = ref object of Node
     data* {.jsgetset.}: string
 
@@ -492,6 +494,7 @@ jsDestructor(HTMLAllCollection)
 jsDestructor(HTMLOptionsCollection)
 jsDestructor(Location)
 jsDestructor(Document)
+jsDestructor(XMLDocument)
 jsDestructor(DOMImplementation)
 jsDestructor(DOMTokenList)
 jsDestructor(DOMStringMap)
@@ -3618,7 +3621,6 @@ proc newHTMLElement*(document: Document; tagType: TagType): HTMLElement =
   return HTMLElement(document.newElement(localName, Namespace.HTML, NO_PREFIX))
 
 proc newDocument*(factory: CAtomFactory): Document =
-  assert factory != nil
   let document = Document(
     url: newURL("about:blank").get,
     index: -1,
@@ -3631,6 +3633,16 @@ proc newDocument*(factory: CAtomFactory): Document =
 proc newDocument(ctx: JSContext): Document {.jsctor.} =
   return newDocument(ctx.getGlobal().factory)
 
+proc newXMLDocument(ctx: JSContext): XMLDocument =
+  let document = XMLDocument(
+    url: newURL("about:blank").get,
+    index: -1,
+    factory: ctx.getGlobal().factory,
+    contentType: "application/xml"
+  )
+  document.implementation = DOMImplementation(document: document)
+  return document
+
 func newDocumentType*(document: Document; name, publicId, systemId: string):
     DocumentType =
   return DocumentType(
@@ -5224,23 +5236,20 @@ proc createElement(document: Document; localName: string): DOMResult[Element]
     NO_NAMESPACE
   return ok(document.newElement(localName, namespace))
 
-proc validateAndExtract(ctx: JSContext; document: Document; namespace: JSValue;
-    qname: string; namespaceOut, prefixOut, localNameOut: var CAtom):
-    DOMResult[void] =
+proc validateAndExtract(ctx: JSContext; document: Document; qname: string;
+    namespace, prefixOut, localNameOut: var CAtom): DOMResult[void] =
   ?qname.validateQName()
-  if JS_IsNull(namespace):
-    namespaceOut = CAtomNull
-  else:
-    ?ctx.fromJS(namespace, namespaceOut)
+  if namespace == ctx.toAtom(""):
+    namespace = CAtomNull
   var prefix = ""
   var localName = qname.until(':')
   if localName.len < qname.len:
     prefix = move(localName)
     localName = qname.substr(prefix.len + 1)
-  if namespaceOut == CAtomNull and prefix != "":
+  if namespace == CAtomNull and prefix != "":
     return errDOMException("Got namespace prefix, but no namespace",
       "NamespaceError")
-  let sns = document.toStaticAtom(namespaceOut)
+  let sns = document.toStaticAtom(namespace)
   if prefix == "xml" and sns != satNamespaceXML:
     return errDOMException("Expected XML namespace", "NamespaceError")
   if (qname == "xmlns" or prefix == "xmlns") != (sns == satNamespaceXMLNS):
@@ -5249,11 +5258,11 @@ proc validateAndExtract(ctx: JSContext; document: Document; namespace: JSValue;
   localNameOut = document.toAtom(localName)
   ok()
 
-proc createElementNS(ctx: JSContext; document: Document; namespace0: JSValue;
+proc createElementNS(ctx: JSContext; document: Document; namespace: CAtom;
     qname: string): DOMResult[Element] {.jsfunc.} =
-  var namespace, prefix, localName: CAtom
-  ?ctx.validateAndExtract(document, namespace0, qname, namespace, prefix,
-    localName)
+  var namespace = namespace
+  var prefix, localName: CAtom
+  ?ctx.validateAndExtract(document, qname, namespace, prefix, localName)
   #TODO custom elements (is)
   return ok(document.newElement(localName, namespace, prefix))
 
@@ -5266,6 +5275,28 @@ proc createDocumentType(implementation: var DOMImplementation; qualifiedName,
   let document = implementation.document
   return ok(document.newDocumentType(qualifiedName, publicId, systemId))
 
+proc createDocument(ctx: JSContext; implementation: var DOMImplementation;
+    namespace: CAtom; qname0 = JS_NULL; doctype = none(DocumentType)):
+    DOMResult[XMLDocument] {.jsfunc.} =
+  let document = newXMLDocument(ctx)
+  var qname = ""
+  if not JS_IsNull(qname0):
+    ?ctx.fromJS(qname0, qname)
+  let element = if qname != "":
+    ?ctx.createElementNS(document, namespace, qname)
+  else:
+    nil
+  if doctype.isSome:
+    document.append(doctype.get)
+  if element != nil:
+    document.append(element)
+  document.origin = implementation.document.origin
+  case document.toStaticAtom(namespace)
+  of satNamespaceHTML: document.contentType = "application/xml+html"
+  of satNamespaceSVG: document.contentType = "image/svg+xml"
+  else: discard
+  return ok(document)
+
 proc createHTMLDocument(ctx: JSContext; implementation: var DOMImplementation;
     title = none(string)): Document {.jsfunc.} =
   let doc = newDocument(ctx)
@@ -5280,7 +5311,7 @@ proc createHTMLDocument(ctx: JSContext; implementation: var DOMImplementation;
     titleElement.append(doc.newText(title.get))
     head.append(titleElement)
   html.append(doc.newHTMLElement(TAG_BODY))
-  #TODO set origin
+  doc.origin = implementation.document.origin
   return doc
 
 proc hasFeature(implementation: var DOMImplementation): bool {.jsfunc.} =
@@ -5808,7 +5839,8 @@ proc addDOMModule*(ctx: JSContext) =
   ctx.registerType(HTMLOptionsCollection, parent = htmlCollectionCID)
   ctx.registerType(RadioNodeList, parent = nodeListCID)
   ctx.registerType(Location)
-  ctx.registerType(Document, parent = nodeCID)
+  let documentCID = ctx.registerType(Document, parent = nodeCID)
+  ctx.registerType(XMLDocument, parent = documentCID)
   ctx.registerType(DOMImplementation)
   ctx.registerType(DOMTokenList)
   ctx.registerType(DOMStringMap)