Compare commits
8 Commits
3d99a4aa92
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 231d30c561 | |||
| 325e890737 | |||
| c1b0d8559c | |||
| dff979350a | |||
| 18cd4d3bd9 | |||
| 3cb7f56167 | |||
| cc26bd7e13 | |||
| e8acb62f6b |
@@ -1,28 +1,14 @@
|
|||||||
#lang info
|
#lang info
|
||||||
|
|
||||||
(define pkg-authors '(hnmdijkema))
|
(define pkg-authors '(hnmdijkema))
|
||||||
(define version "0.1.6")
|
(define version "0.1.7")
|
||||||
(define license 'MIT)
|
(define license 'MIT)
|
||||||
(define collection "racket-webview")
|
(define collection "racket-webview")
|
||||||
(define pkg-desc "racket-webview - A Web Based GUI library, based on a Qt WebEngine backend")
|
(define pkg-desc "racket-webview - A Web Based GUI library, based on a Qt WebEngine backend")
|
||||||
|
|
||||||
(define scribblings
|
(define scribblings
|
||||||
'(
|
'(
|
||||||
("scrbl/racket-webview-intro.scrbl" () (gui-library) "racket-webview-introduction")
|
("scrbl/racket-webview-collection.scrbl" (multi-page) (gui-library 0) "racket-webview")
|
||||||
("scrbl/wv-context.scrbl" () (gui-library) "wv-context")
|
|
||||||
("scrbl/wv-settings.scrbl" () (gui-library) "wv-settings")
|
|
||||||
("scrbl/wv-window.scrbl" () (gui-library) "wv-window")
|
|
||||||
("scrbl/wv-tray.scrbl" () (gui-library) "wv-tray")
|
|
||||||
("scrbl/menu.scrbl" () (gui-library) "menu")
|
|
||||||
("scrbl/wv-dialog.scrbl" () (gui-library) "wv-dialog")
|
|
||||||
("scrbl/wv-element.scrbl" () (gui-library) "wv-element")
|
|
||||||
("scrbl/wv-input.scrbl" () (gui-library) "wv-input")
|
|
||||||
("scrbl/racket-webview-qt.scrbl" () (gui-library) "racket-webview-qt")
|
|
||||||
("scrbl/racket-webview.scrbl" () (gui-library) "racket-webview")
|
|
||||||
("scrbl/rgba.scrbl" () (gui-library) "rgba")
|
|
||||||
("scrbl/mimetypes.scrbl" () (gui-library) "mimetypes")
|
|
||||||
("scrbl/rktwebview-api.scrbl" () (gui-library) "rktwebview-api")
|
|
||||||
("scrbl/rktwebviewqt-internals.scrbl" () (gui-library) "rktwebviewqt-internals")
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -281,6 +281,9 @@
|
|||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
((_ (a c b1 b2))
|
((_ (a c b1 b2))
|
||||||
(cond
|
(cond
|
||||||
|
((eq? (syntax->datum #'a) 'define) #'(js-def c (b1 b2)))
|
||||||
|
((eq? (syntax->datum #'a) 'lambda) #'(js-lambda c b1 b2))
|
||||||
|
((eq? (syntax->datum #'a) 'λ) #'(js-lambda c b1 b2))
|
||||||
((eq? (syntax->datum #'a) 'if) #'(js2-if c b1 b2))
|
((eq? (syntax->datum #'a) 'if) #'(js2-if c b1 b2))
|
||||||
((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 b2))
|
((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 b2))
|
||||||
((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 b2))
|
((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 b2))
|
||||||
@@ -321,6 +324,7 @@
|
|||||||
((eq? (syntax->datum #'a) 'return) #'(js-return b))
|
((eq? (syntax->datum #'a) 'return) #'(js-return b))
|
||||||
((eq? (syntax->datum #'a) 'quote) #'(js-quote b))
|
((eq? (syntax->datum #'a) 'quote) #'(js-quote b))
|
||||||
((eq? (syntax->datum #'a) 'eval) #'(js-eval b))
|
((eq? (syntax->datum #'a) 'eval) #'(js-eval b))
|
||||||
|
((eq? (syntax->datum #'a) 'list) #'(js-op a b))
|
||||||
;string-append
|
;string-append
|
||||||
; "\"" (esc-double-quote (format "~a" 'b)) "\""))
|
; "\"" (esc-double-quote (format "~a" 'b)) "\""))
|
||||||
(else
|
(else
|
||||||
@@ -334,6 +338,8 @@
|
|||||||
(cond
|
(cond
|
||||||
((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 ...))
|
((eq? (syntax->datum #'a) 'let*) #'(js2-let* c b1 ...))
|
||||||
((eq? (syntax->datum #'a) 'define) #'(js-def c (b1 ...)))
|
((eq? (syntax->datum #'a) 'define) #'(js-def c (b1 ...)))
|
||||||
|
((eq? (syntax->datum #'a) 'lambda) #'(js-lambda c b1 ...))
|
||||||
|
((eq? (syntax->datum #'a) 'λ) #'(js-lambda c b1 ...))
|
||||||
((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 ...))
|
((memq (syntax->datum #'a) js-ops) #'(js-op a c b1 ...))
|
||||||
((eq? (syntax->datum #'a) 'begin) #'(js-begin c b1 ...))
|
((eq? (syntax->datum #'a) 'begin) #'(js-begin c b1 ...))
|
||||||
((eq? (syntax->datum #'a) 'let) #'(error "let is not supported in js context, use let*"))
|
((eq? (syntax->datum #'a) 'let) #'(error "let is not supported in js context, use let*"))
|
||||||
@@ -392,10 +398,11 @@
|
|||||||
#|
|
#|
|
||||||
(define t1
|
(define t1
|
||||||
(js (set! window.myfunc (λ (x)
|
(js (set! window.myfunc (λ (x)
|
||||||
(let* ((el (document.getElementById 'hi))
|
(let* ((el (send document getElementById 'hi))
|
||||||
(y (* x x)))
|
(y (* x x)))
|
||||||
(el.setAttribute "x" (+ y ""))
|
(send el setAttribute "x" (+ y ""))
|
||||||
)
|
)
|
||||||
|
(send console log "dit set attribute x on element hi")
|
||||||
)
|
)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
@@ -408,6 +415,33 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(define t3 (js (define (f x y z)
|
||||||
|
(send console log (cons x (cons y (list z))))
|
||||||
|
(let* ((l (cons x (cons y (list z)))))
|
||||||
|
(return (send l map (λ (a) (return (+ a 10)))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
==>
|
||||||
|
function f(x, y, z) {
|
||||||
|
console.log([ x].concat([ y].concat([ z])));
|
||||||
|
{
|
||||||
|
let l = [ x].concat([ y].concat([ z]));
|
||||||
|
return (l.map(function (a) { return (a + 10);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|#
|
|#
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+39
-25
@@ -30,6 +30,7 @@
|
|||||||
lru-cache
|
lru-cache
|
||||||
racket-self-signed-cert
|
racket-self-signed-cert
|
||||||
simple-log
|
simple-log
|
||||||
|
js-maker
|
||||||
)
|
)
|
||||||
|
|
||||||
(provide webview-new-context
|
(provide webview-new-context
|
||||||
@@ -396,6 +397,12 @@
|
|||||||
#f))
|
#f))
|
||||||
|
|
||||||
|
|
||||||
|
(define-syntax with-id->el
|
||||||
|
(syntax-rules ()
|
||||||
|
((_ id el e1 ...)
|
||||||
|
(js (let ((el (send document getElementById (eval id))))
|
||||||
|
e1 ...)))))
|
||||||
|
|
||||||
(define-syntax with-id
|
(define-syntax with-id
|
||||||
(syntax-rules ()
|
(syntax-rules ()
|
||||||
((_ id el
|
((_ id el
|
||||||
@@ -718,10 +725,11 @@
|
|||||||
(wv-win-window-nr wv) sel evt (if no-prevent-default 'true 'false)))
|
(wv-win-window-nr wv) sel evt (if no-prevent-default 'true 'false)))
|
||||||
(r (webview-call-js wv j))
|
(r (webview-call-js wv j))
|
||||||
)
|
)
|
||||||
;(dbg-webview "called js: ~a" j)
|
(if (eq? r #f)
|
||||||
(map (λ (el)
|
#f
|
||||||
(list (string->symbol (car el)) (cadr el) (caddr el)))
|
(map (λ (el)
|
||||||
r))))
|
(list (string->symbol (car el)) (cadr el) (caddr el)))
|
||||||
|
r)))))
|
||||||
|
|
||||||
(define/contract (webview-unbind! wv selector event)
|
(define/contract (webview-unbind! wv selector event)
|
||||||
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) list?)
|
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) list?)
|
||||||
@@ -735,9 +743,11 @@
|
|||||||
(let ((r (webview-call-js wv
|
(let ((r (webview-call-js wv
|
||||||
(format "return window.rkt_unbind_evt_ids(~a, '~a', ~a)"
|
(format "return window.rkt_unbind_evt_ids(~a, '~a', ~a)"
|
||||||
(wv-win-window-nr wv) sel evt))))
|
(wv-win-window-nr wv) sel evt))))
|
||||||
(map (λ (el)
|
(if (eq? r #f)
|
||||||
(list (string->symbol (car el)) (cadr el) (caddr el)))
|
#f
|
||||||
r))))
|
(map (λ (el)
|
||||||
|
(list (string->symbol (car el)) (cadr el) (caddr el)))
|
||||||
|
r)))))
|
||||||
|
|
||||||
(define/contract (webview-run-js wv js)
|
(define/contract (webview-run-js wv js)
|
||||||
(-> wv-win? string? symbol?)
|
(-> wv-win? string? symbol?)
|
||||||
@@ -762,15 +772,14 @@
|
|||||||
|
|
||||||
(define/contract (webview-call-js wv js)
|
(define/contract (webview-call-js wv js)
|
||||||
(-> wv-win? string? (or/c string? list? boolean? hash? symbol? number?))
|
(-> wv-win? string? (or/c string? list? boolean? hash? symbol? number?))
|
||||||
|
(displayln js)
|
||||||
(let ((result (rkt-webview-call-js (wv-win-handle wv) js)))
|
(let ((result (rkt-webview-call-js (wv-win-handle wv) js)))
|
||||||
;(displayln result)
|
|
||||||
(if (webview-call-js-result? result)
|
(if (webview-call-js-result? result)
|
||||||
(if (eq? (car result) 'oke)
|
(if (eq? (car result) 'oke)
|
||||||
(hash-ref (fromJson (cadr result)) 'result #f)
|
(hash-ref (fromJson (cadr result)) 'result #f)
|
||||||
(error
|
(begin
|
||||||
(format "Error calling javascript. Message: ~a"
|
(err-webview "Error calling javascript: ~a" result)
|
||||||
(hash-ref (fromJson (cadr result)) 'exn result)))
|
#f))
|
||||||
)
|
|
||||||
(error
|
(error
|
||||||
(format "Wrong result from webview-call-js: ~a" result))
|
(format "Wrong result from webview-call-js: ~a" result))
|
||||||
)
|
)
|
||||||
@@ -785,9 +794,12 @@
|
|||||||
(-> wv-win? symbol? (or/c string? xexpr?) symbol?)
|
(-> wv-win? symbol? (or/c string? xexpr?) symbol?)
|
||||||
(if (string? html)
|
(if (string? html)
|
||||||
(let ((r (webview-call-js wv
|
(let ((r (webview-call-js wv
|
||||||
(with-id id el
|
(with-id->el id el
|
||||||
("el.innerHTML = '~a'; return true;"
|
(set! (js-dot el innerHTML) (eval html))
|
||||||
(esc-quote html))))))
|
#t))))
|
||||||
|
;(with-id id el
|
||||||
|
; ("el.innerHTML = '~a'; return true;"
|
||||||
|
; (esc-quote html))))))
|
||||||
(if r 'oke 'failed))
|
(if r 'oke 'failed))
|
||||||
(webview-set-innerHTML! wv id (xexpr->string html))
|
(webview-set-innerHTML! wv id (xexpr->string html))
|
||||||
)
|
)
|
||||||
@@ -859,7 +871,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(define/contract (webview-add-class! wv id-or-selector class)
|
(define/contract (webview-add-class! wv id-or-selector class)
|
||||||
(-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) hash?)
|
(-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) (or/c hash? boolean?))
|
||||||
(let ((sel (if (symbol? id-or-selector)
|
(let ((sel (if (symbol? id-or-selector)
|
||||||
(format "#~a" id-or-selector)
|
(format "#~a" id-or-selector)
|
||||||
id-or-selector))
|
id-or-selector))
|
||||||
@@ -879,7 +891,7 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
(define/contract (webview-remove-class! wv id-or-selector class)
|
(define/contract (webview-remove-class! wv id-or-selector class)
|
||||||
(-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) hash?)
|
(-> wv-win? (or/c symbol? string?) (or/c symbol? string? list?) (or/c hash? boolean?))
|
||||||
(let ((sel (if (symbol? id-or-selector)
|
(let ((sel (if (symbol? id-or-selector)
|
||||||
(format "#~a" id-or-selector)
|
(format "#~a" id-or-selector)
|
||||||
id-or-selector))
|
id-or-selector))
|
||||||
@@ -901,7 +913,7 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
(define/contract (webview-set-style! wv selector style-entries)
|
(define/contract (webview-set-style! wv selector style-entries)
|
||||||
(-> wv-win? (or/c symbol? string?) (or/c kv? list-of-kv?) hash?)
|
(-> wv-win? (or/c symbol? string?) (or/c kv? list-of-kv?) (or/c hash? boolean?))
|
||||||
(let ((sel (if (symbol? selector)
|
(let ((sel (if (symbol? selector)
|
||||||
(format "#~a" selector)
|
(format "#~a" selector)
|
||||||
selector))
|
selector))
|
||||||
@@ -947,18 +959,20 @@
|
|||||||
" return { id: id, style: r };"
|
" return { id: id, style: r };"
|
||||||
"}") cl))
|
"}") cl))
|
||||||
)))
|
)))
|
||||||
(let ((h (hash-ref r 'with-ids)))
|
(if (eq? r #f)
|
||||||
(let ((l (map (λ (e) (cons (string->symbol (hash-ref e 'id)) (hash-ref e 'style))) h)))
|
#f
|
||||||
(if (symbol? selector)
|
(let ((h (hash-ref r 'with-ids)))
|
||||||
(cdr (car l))
|
(let ((l (map (λ (e) (cons (string->symbol (hash-ref e 'id)) (hash-ref e 'style))) h)))
|
||||||
l)))
|
(if (symbol? selector)
|
||||||
|
(cdr (car l))
|
||||||
|
l))))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
(define/contract (webview-unset-style! wv selector style-entries)
|
(define/contract (webview-unset-style! wv selector style-entries)
|
||||||
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) hash?)
|
(-> wv-win? (or/c symbol? string?) (or/c symbol? list-of-symbol?) (or/c hash? boolean?))
|
||||||
(let ((sel (if (symbol? selector)
|
(let ((sel (if (symbol? selector)
|
||||||
(format "#~a" selector)
|
(format "#~a" selector)
|
||||||
selector))
|
selector))
|
||||||
@@ -984,7 +998,7 @@
|
|||||||
|
|
||||||
(define/contract (webview-set-attr! wv selector attr-entries)
|
(define/contract (webview-set-attr! wv selector attr-entries)
|
||||||
(-> wv-win? (or/c symbol? string?)
|
(-> wv-win? (or/c symbol? string?)
|
||||||
(or/c kv? list-of-kv?) hash?)
|
(or/c kv? list-of-kv?) (or/c hash? boolean?))
|
||||||
(let* ((sel (if (symbol? selector)
|
(let* ((sel (if (symbol? selector)
|
||||||
(format "#~a" selector)
|
(format "#~a" selector)
|
||||||
selector))
|
selector))
|
||||||
|
|||||||
@@ -0,0 +1,340 @@
|
|||||||
|
#lang scribble/manual
|
||||||
|
|
||||||
|
@(require (for-label racket/base
|
||||||
|
"../private/js-transform.rkt"))
|
||||||
|
|
||||||
|
@title{JavaScript Transformation}
|
||||||
|
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
|
||||||
|
|
||||||
|
@defmodule[racket-webview/private/js-transform]
|
||||||
|
|
||||||
|
This module provides a small compile-time DSL for generating JavaScript source
|
||||||
|
text from Racket-like forms. It is used internally by the webview
|
||||||
|
implementation to construct JavaScript snippets in a structured way, without
|
||||||
|
having to write the complete snippet as one raw string.
|
||||||
|
|
||||||
|
The module exports only @racket[js]. The other forms described in this section
|
||||||
|
are DSL forms recognized by @racket[js]; they are not exported as separate
|
||||||
|
bindings.
|
||||||
|
|
||||||
|
@defform[
|
||||||
|
(js js-statement ...)
|
||||||
|
]{
|
||||||
|
|
||||||
|
Transforms each @racket[js-statement] into JavaScript source text. The result
|
||||||
|
is a string. The generated string is not evaluated by Racket and no JavaScript
|
||||||
|
is executed by this module.
|
||||||
|
|
||||||
|
Each top-level statement is emitted with a trailing semicolon and newline. The
|
||||||
|
resulting string can be passed to the webview layer for injection or execution
|
||||||
|
in the browser context.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(define source
|
||||||
|
(js
|
||||||
|
(set! window.myfunc
|
||||||
|
(λ (x)
|
||||||
|
(let* ((el (send document getElementById 'hi))
|
||||||
|
(y (* x x)))
|
||||||
|
(send el setAttribute "x" (+ y "")))
|
||||||
|
(send console log "did set attribute x on element hi")))))
|
||||||
|
]
|
||||||
|
|
||||||
|
This generates JavaScript source that assigns a function to
|
||||||
|
@tt{window.myfunc}. The function looks up a DOM element, calculates a value,
|
||||||
|
sets an attribute, and writes a message to the JavaScript console.
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Primitive values}
|
||||||
|
|
||||||
|
Numbers are emitted as JavaScript numeric literals. Strings are emitted as
|
||||||
|
double-quoted JavaScript strings, with embedded double quotes escaped.
|
||||||
|
Identifiers are emitted as JavaScript names.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(send console log "hello")
|
||||||
|
(send console log 42))
|
||||||
|
]
|
||||||
|
|
||||||
|
Symbols can be quoted to produce JavaScript string values:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(send console log 'hello))
|
||||||
|
]
|
||||||
|
|
||||||
|
@section{Function calls and method calls}
|
||||||
|
|
||||||
|
A form that is not recognized as a special DSL form is treated as a JavaScript
|
||||||
|
function call:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(alert "Hello from Racket"))
|
||||||
|
]
|
||||||
|
|
||||||
|
This generates a JavaScript call to @tt{alert}.
|
||||||
|
|
||||||
|
Method calls can be written with @racket[send]:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(send document getElementById 'hi))
|
||||||
|
]
|
||||||
|
|
||||||
|
The @racket[send] form has the shape:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(send object method arg ...)
|
||||||
|
]
|
||||||
|
|
||||||
|
and generates a JavaScript method call of the form:
|
||||||
|
|
||||||
|
@codeblock|{
|
||||||
|
object.method(arg, ...)
|
||||||
|
}|
|
||||||
|
|
||||||
|
For example, @racket[(send document getElementById 'hi)] generates a call shaped
|
||||||
|
like:
|
||||||
|
|
||||||
|
@codeblock|{
|
||||||
|
document.getElementById("hi")
|
||||||
|
}|
|
||||||
|
|
||||||
|
Using @racket[send] keeps the method-call structure explicit in the DSL. It is
|
||||||
|
usually clearer than writing dotted JavaScript names directly as function names.
|
||||||
|
|
||||||
|
@section{Operators}
|
||||||
|
|
||||||
|
The DSL supports a small set of JavaScript infix operators.
|
||||||
|
|
||||||
|
@itemlist[
|
||||||
|
#:style 'compact
|
||||||
|
|
||||||
|
@item{@racket[(+ a b ...)], @racket[(- a b ...)],
|
||||||
|
@racket[(* a b ...)] and @racket[(/ a b ...)] generate arithmetic infix
|
||||||
|
expressions.}
|
||||||
|
|
||||||
|
@item{@racket[(and a b ...)] and @racket[(or a b ...)] generate JavaScript
|
||||||
|
@tt{&&} and @tt{||} expressions.}
|
||||||
|
|
||||||
|
@item{@racket[(> a b)], @racket[(< a b)], @racket[(>= a b)],
|
||||||
|
@racket[(<= a b)], @racket[(== a b)], @racket[(=== a b)] and
|
||||||
|
@racket[(!= a b)] generate JavaScript comparison expressions.}
|
||||||
|
]
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(define (inside-range x)
|
||||||
|
(if (and (> x 10) (< x 15))
|
||||||
|
(return x)
|
||||||
|
(return (* x x)))))
|
||||||
|
]
|
||||||
|
|
||||||
|
@section{Definitions and assignments}
|
||||||
|
|
||||||
|
@defform[(define (name arg ...) body ...)]{
|
||||||
|
|
||||||
|
Generates a JavaScript function declaration.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(define (square x)
|
||||||
|
(return (* x x))))
|
||||||
|
]
|
||||||
|
|
||||||
|
This produces a JavaScript function named @tt{square}.
|
||||||
|
}
|
||||||
|
|
||||||
|
@defform[(set! name expr)]{
|
||||||
|
|
||||||
|
Generates a JavaScript assignment.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(set! window.answer 42))
|
||||||
|
]
|
||||||
|
|
||||||
|
This produces an assignment to @tt{window.answer}.
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Functions}
|
||||||
|
|
||||||
|
@defform[(lambda (arg ...) body ...)]{
|
||||||
|
Generates a JavaScript function expression.
|
||||||
|
}
|
||||||
|
|
||||||
|
@defform[(λ (arg ...) body ...)]{
|
||||||
|
Equivalent to @racket[lambda].
|
||||||
|
}
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(set! window.square
|
||||||
|
(λ (x)
|
||||||
|
(return (* x x)))))
|
||||||
|
]
|
||||||
|
|
||||||
|
A function body may contain more than one DSL statement:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(set! window.f
|
||||||
|
(λ (x)
|
||||||
|
(send console log x)
|
||||||
|
(return (* x x)))))
|
||||||
|
]
|
||||||
|
|
||||||
|
@section{Control flow and statement blocks}
|
||||||
|
|
||||||
|
@defform[(if condition then-expr else-expr)]{
|
||||||
|
|
||||||
|
Generates a JavaScript @tt{if}/@tt{else} statement. The condition is translated
|
||||||
|
as a JavaScript expression. The two branches are translated as JavaScript
|
||||||
|
statements.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(define (f x)
|
||||||
|
(if (> x 0)
|
||||||
|
(return x)
|
||||||
|
(return (- 0 x)))))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@defform[(begin body ...)]{
|
||||||
|
|
||||||
|
Generates a JavaScript block.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(if (> x 10)
|
||||||
|
(begin
|
||||||
|
(send console log x)
|
||||||
|
(return x))
|
||||||
|
(return 0)))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@defform[(return expr)]{
|
||||||
|
|
||||||
|
Generates a JavaScript @tt{return} statement.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(define (id x)
|
||||||
|
(return x)))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Sequential bindings}
|
||||||
|
|
||||||
|
@defform[(let* ((id expr) ...) body ...)]{
|
||||||
|
|
||||||
|
Generates a JavaScript block with sequential @tt{let} declarations, followed by
|
||||||
|
the generated body statements.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(let* ((x 10)
|
||||||
|
(y (* x x)))
|
||||||
|
(send console log y)
|
||||||
|
(return y)))
|
||||||
|
]
|
||||||
|
|
||||||
|
The plain @racket[let] form is intentionally not supported in a JavaScript
|
||||||
|
context. Use @racket[let*] instead, so that the generated JavaScript bindings
|
||||||
|
remain explicitly sequential.
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Lists}
|
||||||
|
|
||||||
|
@defform[(list expr ...)]{
|
||||||
|
|
||||||
|
Generates a JavaScript array literal.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(send console log (list 1 2 3)))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@defform[(cons expr list-expr)]{
|
||||||
|
|
||||||
|
Generates JavaScript that prepends a value to an array-like expression by
|
||||||
|
concatenating a one-element array with the translated list expression.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(js
|
||||||
|
(send console log (cons x (cons y (list z)))))
|
||||||
|
]
|
||||||
|
|
||||||
|
This generates JavaScript shaped like:
|
||||||
|
|
||||||
|
@codeblock|{
|
||||||
|
console.log([ x].concat([ y].concat([ z])));
|
||||||
|
}|
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Embedding Racket values}
|
||||||
|
|
||||||
|
@defform[(eval value)]{
|
||||||
|
|
||||||
|
Embeds a simple Racket value as a JavaScript literal at expansion time. The
|
||||||
|
supported values are strings, symbols, numbers and lists containing those same
|
||||||
|
kinds of values.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(define names '(alice bob charlie))
|
||||||
|
|
||||||
|
(js
|
||||||
|
(send console log (eval names)))
|
||||||
|
]
|
||||||
|
|
||||||
|
The value is converted to JavaScript source text before the generated JavaScript
|
||||||
|
is returned.
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Example}
|
||||||
|
|
||||||
|
The following example combines function definition, method calls, list
|
||||||
|
construction, sequential bindings and a lambda expression passed to a JavaScript
|
||||||
|
method:
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(define source
|
||||||
|
(js
|
||||||
|
(define (f x y z)
|
||||||
|
(send console log (cons x (cons y (list z))))
|
||||||
|
(let* ((l (cons x (cons y (list z)))))
|
||||||
|
(return
|
||||||
|
(send l map
|
||||||
|
(λ (a)
|
||||||
|
(return (+ a 10)))))))))
|
||||||
|
]
|
||||||
|
|
||||||
|
This generates a JavaScript function that logs an array, constructs the same
|
||||||
|
array in a local binding, maps over it, and returns the mapped result.
|
||||||
|
|
||||||
|
@section{Limitations}
|
||||||
|
|
||||||
|
This transformer is intentionally small. It is not a complete JavaScript
|
||||||
|
parser, not a JavaScript evaluator and not a general Racket-to-JavaScript
|
||||||
|
compiler. Unrecognized forms are generally treated as JavaScript function
|
||||||
|
calls. This keeps the implementation compact, but it also means that some
|
||||||
|
mistakes may produce JavaScript source that only fails when the browser runs the
|
||||||
|
generated code.
|
||||||
|
|
||||||
|
The generated source is intended for small snippets used by the webview layer,
|
||||||
|
not for translating arbitrary Racket programs to JavaScript.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#lang scribble/manual
|
||||||
|
|
||||||
|
@(require racket/runtime-path
|
||||||
|
scribble/core
|
||||||
|
)
|
||||||
|
|
||||||
|
@title{@elem{racket-webview}}
|
||||||
|
|
||||||
|
@table-of-contents[]
|
||||||
|
|
||||||
|
@include-section["racket-webview-intro.scrbl"]
|
||||||
|
@include-section["wv-context.scrbl"]
|
||||||
|
@include-section["wv-settings.scrbl"]
|
||||||
|
@include-section["wv-window.scrbl"]
|
||||||
|
@include-section["menu.scrbl"]
|
||||||
|
@include-section["wv-dialog.scrbl"]
|
||||||
|
@include-section["wv-element.scrbl"]
|
||||||
|
@include-section["wv-input.scrbl"]
|
||||||
|
@include-section["js-transform.scrbl"]
|
||||||
|
@include-section["racket-webview.scrbl"]
|
||||||
|
@include-section["racket-webview-qt.scrbl"]
|
||||||
|
@include-section["rgba.scrbl"]
|
||||||
|
@include-section["mimetypes.scrbl"]
|
||||||
|
@include-section["rktwebview-api.scrbl"]
|
||||||
|
@include-section["rktwebviewqt-internals.scrbl"]
|
||||||
|
|
||||||
|
@index-section[]
|
||||||
Reference in New Issue
Block a user