about summary refs log tree commit diff stats
path: root/src/html
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-06-29 18:55:28 +0200
committerbptato <nincsnevem662@gmail.com>2023-06-29 18:55:44 +0200
commit1499a0757a8877355a2c5983cbe63c16837a83f8 (patch)
treedcdd918eca1c2959269d6eafe132a5cb1241a988 /src/html
parentcd6b8bf5cf93ada0ee60202c249ae80693e5ca89 (diff)
downloadchawan-1499a0757a8877355a2c5983cbe63c16837a83f8.tar.gz
Add window.location
Note: setters do not work yet.
Diffstat (limited to 'src/html')
-rw-r--r--src/html/dom.nim134
-rw-r--r--src/html/env.nim12
2 files changed, 140 insertions, 6 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index 7fa012bc..bfb5581f 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -90,16 +90,21 @@ type
       discard #TODO
 
 type
+  Location = ref object
+    window: Window
+
   Window* = ref object
     attrs*: WindowAttributes
     console* {.jsget.}: console
     navigator* {.jsget.}: Navigator
     settings*: EnvironmentSettings
     loader*: Option[FileLoader]
+    location* {.jsget.}: Location
     jsrt*: JSRuntime
     jsctx*: JSContext
     document* {.jsget.}: Document
     timeouts*: TimeoutState[int]
+    navigate*: proc(url: URL)
 
   # Navigator stuff
   Navigator* = ref object
@@ -172,8 +177,7 @@ type
   Document* = ref object of Node
     charset*: Charset
     window*: Window
-    url*: URL #TODO expose as URL (capitalized)
-    location* {.jsget.}: URL #TODO should be location
+    url* {.jsget: "URL".}: URL
     mode*: QuirksMode
     currentScript: HTMLScriptElement
     isxml*: bool
@@ -1081,6 +1085,131 @@ func item(collection: HTMLCollection, i: int): Element {.jsfunc.} =
 func getter(collection: HTMLCollection, i: int): Option[Element] {.jsgetprop.} =
   return option(collection.item(i))
 
+proc newLocation*(window: Window): Location =
+  let location = Location(window: window)
+  let ctx = window.jsctx
+  if ctx != nil:
+    let val = toJS(ctx, location)
+    let valueOf = ctx.getOpaque().Object_prototype_valueOf
+    defineProperty(ctx, val, "valueOf", valueOf)
+    defineProperty(ctx, val, "toPrimitive", JS_UNDEFINED)
+    #TODO [[DefaultProperties]]
+    JS_FreeValue(ctx, val)
+  return location
+
+func location(document: Document): Location {.jsfget.} =
+  return document.window.location
+
+func document(location: Location): Document =
+  return location.window.document
+
+func url(location: Location): URL =
+  let document = location.document
+  if document != nil:
+    return document.url
+  return newURL("about:blank").get
+
+proc setLocation*(document: Document, s: string): Err[DOMException]
+    {.jsfset: "location".} =
+  let url = parseURL(s)
+  if url.isNone:
+    return err(newDOMException("Invalid URL", "SyntaxError"))
+  document.window.navigate(url.get)
+  return ok()
+
+# Note: we do not implement security checks (as documents are in separate
+# windows anyway).
+func href(location: Location): string {.jsfget.} =
+  return location.url.serialize()
+
+proc href(location: Location, s: string): Err[DOMException] {.jsfset.} =
+  if location.document == nil:
+    return ok()
+  return location.document.setLocation(s)
+
+func origin(location: Location): string {.jsfget.} =
+  return location.url.origin
+
+func protocol(location: Location): string {.jsfget.} =
+  return location.url.protocol
+
+proc protocol(location: Location, s: string): Err[DOMException] {.jsfset.} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setProtocol(s)
+  if copyURL.scheme != "http" and copyURL.scheme != "https":
+    return err(newDOMException("Invalid URL", "SyntaxError"))
+  document.window.navigate(copyURL)
+  return ok()
+
+func host(location: Location): string {.jsfget.} =
+  return location.url.host
+
+proc setHost(location: Location, s: string) {.jsfset: "host".} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setHost(s)
+  document.window.navigate(copyURL)
+
+proc hostname(location: Location): string {.jsfget.} =
+  return location.url.hostname
+
+proc setHostname(location: Location, s: string) {.jsfset: "hostname".} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setHostname(s)
+  document.window.navigate(copyURL)
+
+proc port(location: Location): string {.jsfget.} =
+  return location.url.port
+
+proc setPort(location: Location, s: string) {.jsfset: "port".} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setPort(s)
+  document.window.navigate(copyURL)
+
+proc pathname(location: Location): string {.jsfget.} =
+  return location.url.pathname
+
+proc setPathname(location: Location, s: string) {.jsfset: "pathname".} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setPathname(s)
+  document.window.navigate(copyURL)
+
+proc search(location: Location): string {.jsfget.} =
+  return location.url.search
+
+proc setSearch(location: Location, s: string) {.jsfset: "search".} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setSearch(s)
+  document.window.navigate(copyURL)
+
+proc hash(location: Location): string {.jsfget.} =
+  return location.url.hash
+
+proc setHash(location: Location, s: string) {.jsfset: "hash".} =
+  let document = location.document
+  if document == nil:
+    return
+  let copyURL = newURL(location.url)
+  copyURL.setHash(s)
+  document.window.navigate(copyURL)
+
 func newAttr(parent: Element, localName, value: string, prefix = "", namespaceURI = ""): Attr =
   return Attr(
     nodeType: ATTRIBUTE_NODE,
@@ -2838,6 +2967,7 @@ proc addDOMModule*(ctx: JSContext) =
   let nodeCID = ctx.registerType(Node, parent = eventTargetCID)
   ctx.registerType(NodeList)
   ctx.registerType(HTMLCollection)
+  ctx.registerType(Location)
   ctx.registerType(Document, parent = nodeCID)
   ctx.registerType(DOMImplementation)
   ctx.registerType(DOMTokenList)
diff --git a/src/html/env.nim b/src/html/env.nim
index b3c14fc5..09cf1c5c 100644
--- a/src/html/env.nim
+++ b/src/html/env.nim
@@ -86,8 +86,9 @@ proc screenTop(window: Window): int64 {.jsfget.} = 0
 #TODO outerWidth, outerHeight
 proc devicePixelRatio(window: Window): float64 {.jsfget.} = 1
 
-func location(window: Window): URL {.jsfget.} =
-  window.document.location
+proc setLocation(window: Window, s: string): Err[DOMException]
+    {.jsfset: "location".} =
+  window.document.setLocation(s)
 
 proc addScripting*(window: Window, selector: Selector[int]) =
   let rt = newJSRuntime()
@@ -129,7 +130,8 @@ proc runJSJobs*(window: Window) =
   window.jsrt.runJSJobs(window.console.err)
 
 proc newWindow*(scripting: bool, selector: Selector[int],
-    attrs: WindowAttributes, loader = none(FileLoader)): Window =
+    attrs: WindowAttributes, navigate: proc(url: URL) = nil,
+    loader = none(FileLoader)): Window =
   let window = Window(
     attrs: attrs,
     console: console(err: newFileStream(stderr)),
@@ -137,8 +139,10 @@ proc newWindow*(scripting: bool, selector: Selector[int],
     loader: loader,
     settings: EnvironmentSettings(
       scripting: scripting
-    )
+    ),
+    navigate: navigate
   )
+  window.location = window.newLocation()
   if scripting:
     window.addScripting(selector)
   return window