summary refs log tree commit diff stats
path: root/lib/js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/js')
-rw-r--r--lib/js/asyncjs.nim19
-rw-r--r--lib/js/dom.nim57
-rw-r--r--lib/js/jscore.nim96
-rw-r--r--lib/js/jsffi.nim30
4 files changed, 185 insertions, 17 deletions
diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim
index 62444e49a..7439b66e1 100644
--- a/lib/js/asyncjs.nim
+++ b/lib/js/asyncjs.nim
@@ -92,7 +92,10 @@ proc isFutureVoid(node: NimNode): bool =
            node[1].kind == nnkIdent and $node[1] == "void"
 
 proc generateJsasync(arg: NimNode): NimNode =
-  assert arg.kind == nnkProcDef
+  if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
+      error("Cannot transform this node kind into an async proc." &
+            " proc/method definition or lambda node expected.")
+
   result = arg
   var isVoid = false
   let jsResolve = ident("jsResolve")
@@ -108,7 +111,7 @@ proc generateJsasync(arg: NimNode): NimNode =
 
   if len(code) > 0:
     var awaitFunction = quote:
-      proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
+      proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.}
     result.body.add(awaitFunction)
 
     var resolve: NimNode
@@ -117,7 +120,7 @@ proc generateJsasync(arg: NimNode): NimNode =
         var `jsResolve` {.importcpp: "undefined".}: Future[void]
     else:
       resolve = quote:
-        proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
+        proc jsResolve[T](a: T): Future[T] {.importcpp: "#", used.}
     result.body.add(resolve)
   else:
     result.body = newEmptyNode()
@@ -129,14 +132,20 @@ proc generateJsasync(arg: NimNode): NimNode =
       return `jsResolve`
     result.body.add(voidFix)
 
-  result.pragma = quote:
+  let asyncPragma = quote:
     {.codegenDecl: "async function $2($3)".}
 
+  result.addPragma(asyncPragma[0])
 
 macro async*(arg: untyped): untyped =
   ## Macro which converts normal procedures into
   ## javascript-compatible async procedures
-  generateJsasync(arg)
+  if arg.kind == nnkStmtList:
+    result = newStmtList()
+    for oneProc in arg:
+      result.add generateJsasync(oneProc)
+  else:
+    result = generateJsasync(arg)
 
 proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
   ## A helper for wrapping callback-based functions
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index 55692d47d..cf219df3d 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -45,6 +45,7 @@ type
     location*: Location
     closed*: bool
     defaultStatus*: cstring
+    devicePixelRatio*: float
     innerHeight*, innerWidth*: int
     locationbar*: ref TLocationBar
     menubar*: ref TMenuBar
@@ -53,11 +54,15 @@ type
     pageXOffset*, pageYOffset*: int
     personalbar*: ref TPersonalBar
     scrollbars*: ref TScrollBars
+    scrollX*: float
+    scrollY*: float
     statusbar*: ref TStatusBar
     status*: cstring
     toolbar*: ref TToolBar
     frames*: seq[TFrame]
     screen*: Screen
+    performance*: Performance
+    onpopstate*: proc (event: Event)
 
   Frame* = ref FrameObj
   FrameObj {.importc.} = object of WindowObj
@@ -171,6 +176,12 @@ type
     text*: cstring
     value*: cstring
 
+  TextAreaElement* = ref object of ElementObj
+    value*: cstring
+    selectionStart*, selectionEnd*: int
+    selectionDirection*: cstring
+    rows*, cols*: int
+
   FormElement* = ref FormObj
   FormObj {.importc.} = object of ElementObj
     action*: cstring
@@ -190,7 +201,7 @@ type
     vspace*: int
     width*: int
 
-  Style = ref StyleObj
+  Style* = ref StyleObj
   StyleObj {.importc.} = object of RootObj
     background*: cstring
     backgroundAttachment*: cstring
@@ -253,6 +264,8 @@ type
     minHeight*: cstring
     minWidth*: cstring
     overflow*: cstring
+    overflowX*: cstring
+    overflowY*: cstring
     padding*: cstring
     paddingBottom*: cstring
     paddingLeft*: cstring
@@ -400,12 +413,47 @@ type
     once*: bool
     passive*: bool
 
+  BoundingRect* {.importc.} = ref object
+    top*, bottom*, left*, right*, x*, y*, width*, height*: float
+
+  PerformanceMemory* {.importc.} = ref object 
+    jsHeapSizeLimit*: float
+    totalJSHeapSize*: float
+    usedJSHeapSize*: float
+
+  PerformanceTiming* {.importc.} = ref object 
+    connectStart*: float
+    domComplete*: float
+    domContentLoadedEventEnd*: float
+    domContentLoadedEventStart*: float
+    domInteractive*: float
+    domLoading*: float
+    domainLookupEnd*: float
+    domainLookupStart*: float
+    fetchStart*: float
+    loadEventEnd*: float
+    loadEventStart*: float
+    navigationStart*: float
+    redirectEnd*: float
+    redirectStart*: float
+    requestStart*: float
+    responseEnd*: float
+    responseStart*: float
+    secureConnectionStart*: float
+    unloadEventEnd*: float
+    unloadEventStart*: float
+
+  Performance* {.importc.} = ref object
+    memory*: PerformanceMemory
+    timing*: PerformanceTiming
+
 {.push importcpp.}
 
 # EventTarget "methods"
 proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
 proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), options: AddEventListenerOptions)
 proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
+proc dispatchEvent*(et: EventTarget, ev: Event)
 
 # Window "methods"
 proc alert*(w: Window, msg: cstring)
@@ -451,6 +499,7 @@ proc cloneNode*(n: Node, copyContent: bool): Node
 proc deleteData*(n: Node, start, len: int)
 proc getAttribute*(n: Node, attr: cstring): cstring
 proc getAttributeNode*(n: Node, attr: cstring): Node
+proc getBoundingClientRect*(e: Node): BoundingRect
 proc hasChildNodes*(n: Node): bool
 proc insertBefore*(n, newNode, before: Node)
 proc insertData*(n: Node, position: int, data: cstring)
@@ -459,7 +508,7 @@ proc removeAttributeNode*(n, attr: Node)
 proc removeChild*(n, child: Node)
 proc replaceChild*(n, newNode, oldNode: Node)
 proc replaceData*(n: Node, start, len: int, text: cstring)
-proc scrollIntoView*(n: Node)
+proc scrollIntoView*(n: Node, alignToTop: bool=true)
 proc setAttribute*(n: Node, name, value: cstring)
 proc setAttributeNode*(n: Node, attr: Node)
 
@@ -530,6 +579,9 @@ proc preventDefault*(ev: Event)
 proc identifiedTouch*(list: TouchList): Touch
 proc item*(list: TouchList, i: int): Touch
 
+# Performance "methods"
+proc now*(p: Performance): float
+
 {.pop.}
 
 var
@@ -552,6 +604,7 @@ proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.}
 proc parseInt*(s: cstring): int {.importc, nodecl.}
 proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
 
+proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.}
 
 type
   TEventHandlers* {.deprecated.} = EventTargetObj
diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim
new file mode 100644
index 000000000..bf64b0794
--- /dev/null
+++ b/lib/js/jscore.nim
@@ -0,0 +1,96 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module wraps core JavaScript functions.
+##
+## Unless your application has very
+## specific requirements and solely targets JavaScript, you should be using
+## the relevant functions in the ``math``, ``json``, and ``times`` stdlib
+## modules instead.
+
+when not defined(js) and not defined(Nimdoc):
+  {.error: "This module only works on the JavaScript platform".}
+
+type
+  MathLib* = ref object
+  JsonLib* = ref object
+  DateLib* = ref object
+  DateTime* = ref object
+
+var
+  Math* {.importc, nodecl.}: MathLib
+  Date* {.importc, nodecl.}: DateLib
+  JSON* {.importc, nodecl.}: JsonLib
+
+# Math library
+proc abs*(m: MathLib, a: SomeNumber): SomeNumber {.importcpp.}
+proc acos*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc acosh*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc asin*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc asinh*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc atan*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc atan2*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc atanh*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc cbrt*(m: MathLib, f: SomeFloat): SomeFloat {.importcpp.}
+proc ceil*(m: MathLib, f: SomeFloat): SomeFloat {.importcpp.}
+proc clz32*(m: MathLib, f: SomeInteger): int {.importcpp.}
+proc cos*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc cosh*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc exp*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc expm1*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc floor*(m: MathLib, f: SomeFloat): int {.importcpp.}
+proc fround*(m: MathLib, f: SomeFloat): float32 {.importcpp.}
+proc hypot*(m: MathLib, args: varargs[distinct SomeNumber]): float {.importcpp.}
+proc imul*(m: MathLib, a, b: int32): int32 {.importcpp.}
+proc log*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc log10*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc log1p*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc log2*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc max*(m: MathLib, a, b: SomeNumber): SomeNumber {.importcpp.}
+proc min*[T: SomeNumber | JsRoot](m: MathLib, a, b: T): T {.importcpp.}
+proc pow*(m: MathLib, a, b: distinct SomeNumber): float {.importcpp.}
+proc random*(m: MathLib): float {.importcpp.}
+proc round*(m: MathLib, f: SomeFloat): int {.importcpp.}
+proc sign*(m: MathLib, f: SomeNumber): int {.importcpp.}
+proc sin*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc sinh*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc sqrt*(m: MathLib, f: SomeFloat): SomeFloat {.importcpp.}
+proc tan*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc tanh*(m: MathLib, a: SomeNumber): float {.importcpp.}
+proc trunc*(m: MathLib, f: SomeFloat): int {.importcpp.}
+
+# Date library
+proc now*(d: DateLib): int {.importcpp.}
+proc UTC*(d: DateLib): int {.importcpp.}
+proc parse*(d: DateLib, s: cstring): int {.importcpp.}
+
+proc newDate*(): DateTime {.
+  importcpp: "new Date()".}
+
+proc newDate*(date: int|string): DateTime {.
+  importcpp: "new Date(#)".}
+
+proc newDate*(year, month, day, hours, minutes,
+             seconds, milliseconds: int): DateTime {.
+  importcpp: "new Date(#,#,#,#,#,#,#)".}
+
+proc getDay*(d: DateTime): int {.importcpp.}
+proc getFullYear*(d: DateTime): int {.importcpp.}
+proc getHours*(d: DateTime): int {.importcpp.}
+proc getMilliseconds*(d: DateTime): int {.importcpp.}
+proc getMinutes*(d: DateTime): int {.importcpp.}
+proc getMonth*(d: DateTime): int {.importcpp.}
+proc getSeconds*(d: DateTime): int {.importcpp.}
+proc getYear*(d: DateTime): int {.importcpp.}
+proc getTime*(d: DateTime): int {.importcpp.}
+proc toString*(d: DateTime): cstring {.importcpp.}
+
+#JSON library
+proc stringify*(l: JsonLib, s: JsRoot): cstring {.importcpp.}
+proc parse*(l: JsonLib, s: cstring): JsRoot {.importcpp.}
diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim
index f34efe9a2..7b44c57c7 100644
--- a/lib/js/jsffi.nim
+++ b/lib/js/jsffi.nim
@@ -70,22 +70,29 @@ template mangleJsName(name: cstring): cstring =
   "mangledName" & $nameCounter
 
 type
-  JsRoot* = ref object of RootObj
-    ## Root type of both JsObject and JsAssoc
   JsObject* = ref object of JsRoot
     ## Dynamically typed wrapper around a JavaScript object.
   JsAssoc*[K, V] = ref object of JsRoot
     ## Statically typed wrapper around a JavaScript object.
-  NotString = concept c
-    c isnot string
+
   js* = JsObject
 
-var jsarguments* {.importc: "arguments", nodecl}: JsObject
-  ## JavaScript's arguments pseudo-variable
+var
+  jsArguments* {.importc: "arguments", nodecl}: JsObject
+    ## JavaScript's arguments pseudo-variable
+  jsNull* {.importc: "null", nodecl.}: JsObject
+    ## JavaScript's null literal
+  jsUndefined* {.importc: "undefined", nodecl.}: JsObject
+    ## JavaScript's undefined literal
+  jsDirname* {.importc: "__dirname", nodecl.}: cstring
+    ## JavaScript's __dirname pseudo-variable
+  jsFilename* {.importc: "__filename", nodecl.}: cstring
+    ## JavaScript's __filename pseudo-variable
 
 # New
 proc newJsObject*: JsObject {. importcpp: "{@}" .}
   ## Creates a new empty JsObject
+
 proc newJsAssoc*[K, V]: JsAssoc[K, V] {. importcpp: "{@}" .}
   ## Creates a new empty JsAssoc with key type `K` and value type `V`.
 
@@ -97,13 +104,16 @@ proc hasOwnProperty*(x: JsObject, prop: cstring): bool
 proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
   ## Returns the name of the JsObject's JavaScript type as a cstring.
 
-proc jsnew*(x: auto): JsObject {.importcpp: "(new #)".}
+proc jsNew*(x: auto): JsObject {.importcpp: "(new #)".}
   ## Turns a regular function call into an invocation of the
   ## JavaScript's `new` operator
 
-proc jsdelete*(x: auto): JsObject {.importcpp: "(delete #)".}
+proc jsDelete*(x: auto): JsObject {.importcpp: "(delete #)".}
   ## JavaScript's `delete` operator
 
+proc require*(module: cstring): JsObject {.importc.}
+  ## JavaScript's `require` function
+
 # Conversion to and from JsObject
 proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
   ## Converts a JsObject `x` to type `T`.
@@ -155,7 +165,7 @@ proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
 proc `[]=`*[T](obj: JsObject, field: int, val: T) {. importcpp: setImpl .}
   ## Set the value of a property of name `field` in a JsObject `obj` to `v`.
 
-proc `[]`*[K: NotString, V](obj: JsAssoc[K, V], field: K): V
+proc `[]`*[K: not string, V](obj: JsAssoc[K, V], field: K): V
   {. importcpp: getImpl .}
   ## Return the value of a property of name `field` from a JsAssoc `obj`.
 
@@ -163,7 +173,7 @@ proc `[]`*[V](obj: JsAssoc[string, V], field: cstring): V
   {. importcpp: getImpl .}
   ## Return the value of a property of name `field` from a JsAssoc `obj`.
 
-proc `[]=`*[K: NotString, V](obj: JsAssoc[K, V], field: K, val: V)
+proc `[]=`*[K: not string, V](obj: JsAssoc[K, V], field: K, val: V)
   {. importcpp: setImpl .}
   ## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.