about summary refs log tree commit diff stats
path: root/src/html
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-11-15 17:06:53 +0100
committerbptato <nincsnevem662@gmail.com>2024-11-15 17:06:53 +0100
commitdef4ceccfb77afd74b1dd1273b66d036b766fd5f (patch)
tree8fb976f0ebe632029afe2ee9542d31b88e4f23d1 /src/html
parentfd10019d8b8a1b5dcb0026521fa8f5f072c3a10a (diff)
downloadchawan-def4ceccfb77afd74b1dd1273b66d036b766fd5f.tar.gz
js: reorganize modules, update docs
most of it has already been moved to monoucha, and the rest fits better
in other directories.

also, move urimethodmap to config
Diffstat (limited to 'src/html')
-rw-r--r--src/html/dom.nim6
-rw-r--r--src/html/domexception.nim55
-rw-r--r--src/html/env.nim10
-rw-r--r--src/html/event.nim4
-rw-r--r--src/html/formdata.nim2
-rw-r--r--src/html/jsencoding.nim100
-rw-r--r--src/html/jsintl.nim66
-rw-r--r--src/html/xmlhttprequest.nim2
8 files changed, 233 insertions, 12 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index c6b14c27..274d401f 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -16,15 +16,15 @@ import css/cssvalues
 import css/mediaquery
 import css/sheet
 import html/catom
+import html/domexception
 import html/enums
 import html/event
 import html/script
 import io/bufwriter
+import io/console
 import io/dynstream
 import io/promise
-import js/console
-import js/domexception
-import js/timeout
+import io/timeout
 import loader/headers
 import loader/loaderiface
 import loader/request
diff --git a/src/html/domexception.nim b/src/html/domexception.nim
new file mode 100644
index 00000000..d07e88f4
--- /dev/null
+++ b/src/html/domexception.nim
@@ -0,0 +1,55 @@
+import monoucha/javascript
+import monoucha/jserror
+import monoucha/quickjs
+import types/opt
+
+const NamesTable = {
+  "IndexSizeError": 1u16,
+  "HierarchyRequestError": 3u16,
+  "WrongDocumentError": 4u16,
+  "InvalidCharacterError": 5u16,
+  "NoModificationAllowedError": 7u16,
+  "NotFoundError": 8u16,
+  "NotSupportedError": 9u16,
+  "InUseAttributeError": 10u16,
+  "InvalidStateError": 11u16,
+  "SyntaxError": 12u16,
+  "InvalidModificationError": 13u16,
+  "NamespaceError": 14u16,
+  "InvalidAccessError": 15u16,
+  "TypeMismatchError": 17u16,
+  "SecurityError": 18u16,
+  "NetworkError": 19u16,
+  "AbortError": 20u16,
+  "URLMismatchError": 21u16,
+  "QuotaExceededError": 22u16,
+  "TimeoutError": 23u16,
+  "InvalidNodeTypeError": 24u16,
+  "DataCloneError": 25u16
+}
+
+type
+  DOMException* = ref object of JSError
+    name* {.jsget.}: string
+    code {.jsget.}: uint16
+
+  DOMResult*[T] = Result[T, DOMException]
+
+jsDestructor(DOMException)
+
+proc newDOMException*(message = ""; name = "Error"): DOMException {.jsctor.} =
+  let ex = DOMException(e: jeDOMException, name: name, message: message)
+  for it in NamesTable:
+    if it[0] == name:
+      ex.code = it[1]
+      break
+  return ex
+
+template errDOMException*(message, name: string): untyped =
+  err(newDOMException(message, name))
+
+func message0(this: DOMException): string {.jsfget: "message".} =
+  return this.message
+
+proc addDOMExceptionModule*(ctx: JSContext) =
+  ctx.registerType(DOMException, JS_CLASS_ERROR, errid = opt(jeDOMException))
diff --git a/src/html/env.nim b/src/html/env.nim
index b8c4fc31..d0c77b46 100644
--- a/src/html/env.nim
+++ b/src/html/env.nim
@@ -3,17 +3,17 @@ import std/tables
 import html/catom
 import html/chadombuilder
 import html/dom
+import html/domexception
 import html/event
 import html/formdata
+import html/jsencoding
+import html/jsintl
 import html/script
 import html/xmlhttprequest
+import io/console
 import io/dynstream
 import io/promise
-import js/console
-import js/domexception
-import js/encoding
-import js/intl
-import js/timeout
+import io/timeout
 import loader/headers
 import loader/loaderiface
 import loader/request
diff --git a/src/html/event.nim b/src/html/event.nim
index 61885b57..40162a8e 100644
--- a/src/html/event.nim
+++ b/src/html/event.nim
@@ -2,9 +2,9 @@ import std/math
 import std/options
 
 import html/catom
+import html/domexception
 import html/script
-import js/domexception
-import js/timeout
+import io/timeout
 import monoucha/fromjs
 import monoucha/javascript
 import monoucha/jserror
diff --git a/src/html/formdata.nim b/src/html/formdata.nim
index 56d49df2..f6a7451b 100644
--- a/src/html/formdata.nim
+++ b/src/html/formdata.nim
@@ -1,9 +1,9 @@
 import chame/tags
 import html/catom
 import html/dom
+import html/domexception
 import html/enums
 import io/dynstream
-import js/domexception
 import monoucha/fromjs
 import monoucha/javascript
 import monoucha/tojs
diff --git a/src/html/jsencoding.nim b/src/html/jsencoding.nim
new file mode 100644
index 00000000..7aae5eb2
--- /dev/null
+++ b/src/html/jsencoding.nim
@@ -0,0 +1,100 @@
+import chagashi/charset
+import chagashi/decoder
+import monoucha/javascript
+import monoucha/jserror
+import monoucha/jstypes
+import monoucha/quickjs
+import types/opt
+
+type
+  JSTextEncoder = ref object
+
+  JSTextDecoder = ref object
+    encoding: Charset
+    ignoreBOM {.jsget.}: bool
+    errorMode: DecoderErrorMode
+    stream: bool
+    bomSeen: bool
+    tdctx: TextDecoderContext
+
+jsDestructor(JSTextDecoder)
+jsDestructor(JSTextEncoder)
+
+type TextDecoderOptions = object of JSDict
+  fatal {.jsdefault.}: bool
+  ignoreBOM {.jsdefault.}: bool
+
+func newJSTextDecoder(label = "utf-8"; options = TextDecoderOptions()):
+    JSResult[JSTextDecoder] {.jsctor.} =
+  let encoding = getCharset(label)
+  if encoding in {CHARSET_UNKNOWN, CHARSET_REPLACEMENT}:
+    return errRangeError("Invalid encoding label")
+  let errorMode = if options.fatal: demFatal else: demReplacement
+  return ok(JSTextDecoder(
+    ignoreBOM: options.ignoreBOM,
+    errorMode: errorMode,
+    tdctx: initTextDecoderContext(encoding, errorMode),
+    encoding: encoding
+  ))
+
+func fatal(this: JSTextDecoder): bool {.jsfget.} =
+  return this.errorMode == demFatal
+
+type TextDecodeOptions = object of JSDict
+  stream {.jsdefault.}: bool
+
+#TODO AllowSharedBufferSource
+proc decode(ctx: JSContext; this: JSTextDecoder;
+    input = none(JSArrayBufferView); options = TextDecodeOptions()): JSValue
+    {.jsfunc.} =
+  if not this.stream:
+    this.tdctx = initTextDecoderContext(this.encoding, this.errorMode)
+    this.bomSeen = false
+  this.stream = options.stream
+  if input.isSome:
+    let input = input.get
+    let H = int(input.abuf.len) - 1
+    var oq = ""
+    let stream = this.stream
+    for chunk in this.tdctx.decode(input.abuf.p.toOpenArray(0, H), not stream):
+      oq &= chunk
+    if this.tdctx.failed:
+      this.tdctx.failed = false
+      return JS_ThrowTypeError(ctx, "failed to decode string")
+    return JS_NewStringLen(ctx, cstring(oq), csize_t(oq.len))
+  return JS_NewString(ctx, "")
+
+func jencoding(this: JSTextDecoder): string {.jsfget: "encoding".} =
+  return $this.encoding
+
+func newTextEncoder(): JSTextEncoder {.jsctor.} =
+  return JSTextEncoder()
+
+func jencoding(this: JSTextEncoder): string {.jsfget: "encoding".} =
+  return "utf-8"
+
+proc dealloc_wrap(rt: JSRuntime; opaque, p: pointer) {.cdecl.} =
+  dealloc(p)
+
+proc encode(this: JSTextEncoder; input = ""): JSUint8Array {.jsfunc.} =
+  # we have to validate input first :/
+  #TODO it is possible to do less copies here...
+  var input = input.toValidUTF8()
+  let buf = cast[ptr UncheckedArray[uint8]](alloc(input.len))
+  copyMem(buf, addr input[0], input.len)
+  let abuf = JSArrayBuffer(
+    p: buf,
+    len: csize_t(input.len),
+    dealloc: dealloc_wrap
+  )
+  return JSUint8Array(
+    abuf: abuf,
+    offset: 0,
+    nmemb: csize_t(input.len)
+  )
+
+#TODO encodeInto
+
+proc addEncodingModule*(ctx: JSContext) =
+  ctx.registerType(JSTextDecoder, name = "TextDecoder")
+  ctx.registerType(JSTextEncoder, name = "TextEncoder")
diff --git a/src/html/jsintl.nim b/src/html/jsintl.nim
new file mode 100644
index 00000000..b980fb90
--- /dev/null
+++ b/src/html/jsintl.nim
@@ -0,0 +1,66 @@
+# Very minimal Intl module... TODO make it more complete
+
+import monoucha/javascript
+import monoucha/jstypes
+import monoucha/quickjs
+import monoucha/tojs
+
+type
+  NumberFormat = ref object
+
+  PluralRules = ref object
+
+  PRResolvedOptions = object of JSDict
+    locale: string
+
+jsDestructor(NumberFormat)
+jsDestructor(PluralRules)
+
+#TODO ...yeah
+proc newNumberFormat(name: string = "en-US"; options = none(JSValue)):
+    NumberFormat {.jsctor.} =
+  return NumberFormat()
+
+#TODO
+proc newPluralRules(): PluralRules {.jsctor.} =
+  return PluralRules()
+
+proc resolvedOptions(this: PluralRules): PRResolvedOptions {.jsfunc.} =
+  return PRResolvedOptions(
+    locale: "en-US"
+  )
+
+#TODO: this should accept string/BigInt too
+proc format(nf: NumberFormat; num: float64): string {.jsfunc.} =
+  let s = $num
+  var i = 0
+  var L = s.len
+  for k in countdown(s.high, 0):
+    if s[k] == '.':
+      L = k
+      break
+  if L mod 3 != 0:
+    while i < L mod 3:
+      result &= s[i]
+      inc i
+    if i < L:
+      result &= ','
+  let j = i
+  while i < L:
+    if j != i and i mod 3 == j:
+      result &= ','
+    result &= s[i]
+    inc i
+  if i + 1 < s.len and s[i] == '.':
+    if not (s[i + 1] == '0' and s.len == i + 2):
+      while i < s.len:
+        result &= s[i]
+        inc i
+
+proc addIntlModule*(ctx: JSContext) =
+  let global = JS_GetGlobalObject(ctx)
+  let intl = JS_NewObject(ctx)
+  ctx.registerType(NumberFormat, namespace = intl)
+  ctx.registerType(PluralRules, namespace = intl)
+  ctx.defineProperty(global, "Intl", intl)
+  JS_FreeValue(ctx, global)
diff --git a/src/html/xmlhttprequest.nim b/src/html/xmlhttprequest.nim
index 50c963c1..0185e03a 100644
--- a/src/html/xmlhttprequest.nim
+++ b/src/html/xmlhttprequest.nim
@@ -7,11 +7,11 @@ import chagashi/decoder
 import html/catom
 import html/chadombuilder
 import html/dom
+import html/domexception
 import html/event
 import html/script
 import io/dynstream
 import io/promise
-import js/domexception
 import loader/headers
 import loader/loaderiface
 import loader/request