1013 lines
29 KiB
Racket
1013 lines
29 KiB
Racket
(module web-wire racket/base
|
|
|
|
(require racket/system
|
|
racket/file
|
|
racket/gui
|
|
racket/port
|
|
file/unzip
|
|
net/url
|
|
racket/port
|
|
data/queue
|
|
json
|
|
"../utils/utils.rkt"
|
|
"css.rkt"
|
|
"menu.rkt"
|
|
"webui-wire-ffi.rkt"
|
|
)
|
|
|
|
(provide ww-start
|
|
ww-stop
|
|
ww-set-web-wire-location!
|
|
|
|
ww-set-debug
|
|
ww-debug
|
|
ww-error
|
|
ww-display-log
|
|
|
|
ww-cmd
|
|
ww-cmd-nok?
|
|
|
|
ww-protocol
|
|
ww-log-level
|
|
ww-set-stylesheet
|
|
ww-get-stylesheet
|
|
|
|
ww-new
|
|
ww-close
|
|
|
|
ww-move
|
|
ww-resize
|
|
ww-set-title
|
|
ww-set-icon
|
|
|
|
ww-set-menu
|
|
|
|
ww-set-html
|
|
ww-set-url
|
|
|
|
ww-set-inner-html
|
|
ww-get-inner-html
|
|
|
|
ww-set-attr
|
|
ww-get-attr
|
|
ww-get-attrs
|
|
ww-del-attr
|
|
|
|
ww-set-style
|
|
ww-add-style
|
|
ww-get-style
|
|
|
|
ww-add-class
|
|
ww-remove-class
|
|
ww-has-class?
|
|
|
|
ww-set-value
|
|
ww-get-value
|
|
|
|
ww-get-elements
|
|
|
|
ww-set-show-state
|
|
ww-get-show-state
|
|
|
|
ww-bind
|
|
ww-on
|
|
ww-element-info
|
|
|
|
ww-file-open
|
|
ww-file-save
|
|
ww-choose-dir
|
|
|
|
windows
|
|
windows-evt-handlers
|
|
ww-get-window-for-id
|
|
|
|
ww-from-string
|
|
|
|
ww-win-id
|
|
)
|
|
|
|
(define current-win-release "https://github.com/hdijkema/web-wire/releases/download/0.1/web-wire-0.1-win64.zip")
|
|
(define user-web-wire-location #f)
|
|
|
|
(define (ww-set-web-wire-location! path-or-dir)
|
|
(set! user-web-wire-location (build-path path-or-dir))
|
|
user-web-wire-location)
|
|
|
|
(define (os)
|
|
(format "~a-~a" (system-type) (system-type 'word)))
|
|
|
|
(define (web-wire-exe)
|
|
(if (eq? (system-type) 'windows)
|
|
"web-wire.exe"
|
|
"web-wire"))
|
|
|
|
(define (web-wire-dir)
|
|
(if (eq? user-web-wire-location #f)
|
|
(let* ((cache-dir (find-system-path 'cache-dir))
|
|
(os-dir (build-path cache-dir (os)))
|
|
(web-wire-prg (build-path os-dir (web-wire-exe)))
|
|
)
|
|
(unless (file-exists? web-wire-prg)
|
|
(error "Web wire executable not found: '~a'" web-wire-prg))
|
|
os-dir)
|
|
(let ((web-wire-prg (build-path user-web-wire-location (web-wire-exe))))
|
|
(unless (file-exists? web-wire-prg)
|
|
(error "Web wire executable not found: '~a'" web-wire-prg))
|
|
user-web-wire-location)
|
|
))
|
|
|
|
(define (web-wire-prg)
|
|
(build-path (web-wire-dir) (web-wire-exe)))
|
|
|
|
(define (do-download-and-extract release version os-dir)
|
|
(let* ((url (string->url release))
|
|
(port-in (get-pure-port url #:redirections 10))
|
|
(release-file (build-path os-dir "release.zip"))
|
|
(port-out (open-output-file release-file #:exists 'replace))
|
|
)
|
|
(letrec ((f (lambda (count next-c len)
|
|
(let ((bytes (read-bytes 16384 port-in)))
|
|
(if (eof-object? bytes)
|
|
count
|
|
(let ((read-len (bytes-length bytes)))
|
|
(when (> read-len 0)
|
|
(set! count (+ count read-len))
|
|
(when (> count next-c)
|
|
(display (format "~a..." count))
|
|
(set! next-c (+ count len)))
|
|
(write-bytes bytes port-out)
|
|
)
|
|
(f count next-c len)))))
|
|
))
|
|
(display "Downloading web-wire...")
|
|
(let ((count (f 0 0 10000000)))
|
|
(displayln (format "~a downloaded" count)))
|
|
(close-input-port port-in)
|
|
(close-output-port port-out)
|
|
(display "Unzipping...")
|
|
(unzip release-file
|
|
(make-filesystem-entry-reader #:dest os-dir
|
|
#:strip-count 1
|
|
#:exists 'replace)
|
|
)
|
|
(display "removing zip file...")
|
|
(delete-file release-file)
|
|
(displayln "done")
|
|
)))
|
|
|
|
(define (download-if-needed release)
|
|
(let* ((os-dir (web-wire-dir))
|
|
(re #px"web[-]wire[-]([0-9.]+)[-]")
|
|
)
|
|
(unless (directory-exists? os-dir)
|
|
(make-directory* os-dir))
|
|
(let ((m (regexp-match re release)))
|
|
(unless (eq? m #f)
|
|
(let* ((version-file (build-path os-dir "version"))
|
|
(version (cadr m))
|
|
(has-version #f))
|
|
(when (file-exists? version-file)
|
|
(let ((file-version (file->value version-file)))
|
|
(when (string=? file-version version)
|
|
(set! has-version #t))))
|
|
(unless has-version
|
|
(do-download-and-extract release version os-dir)
|
|
(write-to-file version version-file)
|
|
))
|
|
))))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Some utils
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define (drop expected s)
|
|
(let ((e (string-append expected ":")))
|
|
(if (string-prefix? s e)
|
|
(substring s (string-length e))
|
|
#f)))
|
|
|
|
(define (as-string s)
|
|
(let ((s* (format "~a" s)))
|
|
(with-output-to-string (lambda () (write s*)))))
|
|
|
|
(define (ww-from-string s)
|
|
(let ((s* (substring s 1 (- (string-length s) 1))))
|
|
(string-replace s* "\\\"" "\"")))
|
|
|
|
(define (to-server-file html-file)
|
|
(let* ((path (build-path html-file))
|
|
(complete-p (path->complete-path path))
|
|
(a-file (format "~a" complete-p))
|
|
(the-file (string-replace a-file "\\" "/")))
|
|
the-file))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; web-wire handling (interaction with the library)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define _ww-debug #f)
|
|
|
|
(define (ww-set-debug yn) (set! _ww-debug yn))
|
|
|
|
(define (do-debug str . var)
|
|
(when _ww-debug
|
|
(if (null? var)
|
|
(displayln (format "Debug: ~a" str))
|
|
(displayln (format "Debug: ~a: ~a" (car var) str))
|
|
)))
|
|
|
|
(define (err str . var)
|
|
(if (null? var)
|
|
(displayln (format "Error: ~a" str))
|
|
(displayln (format "Error: ~a: ~a" var str))
|
|
))
|
|
|
|
(define-syntax debug
|
|
(syntax-rules ()
|
|
((_ str)
|
|
(do-debug str))
|
|
((_ var str)
|
|
(do-debug str 'var))
|
|
))
|
|
|
|
(define-syntax ww-debug
|
|
(syntax-rules ()
|
|
((_ str)
|
|
(do-debug str))
|
|
((_ var str)
|
|
(do-debug str 'var))
|
|
))
|
|
|
|
(define-syntax ww-error
|
|
(syntax-rules ()
|
|
((_ str)
|
|
(err str))
|
|
((_ var str)
|
|
(err str 'var))
|
|
))
|
|
|
|
(define re-kind #px"([A-Z]+)[(]([0-9]+)[)][:]")
|
|
;(define re-event #px"([^:]+)[:]([0-9]+)([:](.*))?")
|
|
(define re-js-event #px"^([^:]+)([:](.*))?")
|
|
(define re-js-result #px"([0-9]+)[:]([^:]+)[:](.*)")
|
|
(define re-js-handle #px"([^:]+)[:]([0-9]+)[:]([0-9]+)([:](.*))?")
|
|
|
|
(define windows-evt-handlers (make-hash))
|
|
(define windows (make-hash))
|
|
|
|
(define (ww-get-window-for-id win-id)
|
|
(hash-ref windows win-id #f))
|
|
|
|
(define-struct web-rkt
|
|
([handle #:mutable]
|
|
[event-thread #:mutable]
|
|
[stop-thread #:mutable]
|
|
)
|
|
)
|
|
|
|
(define ww-current-handle #f)
|
|
|
|
(define evt-sem (make-semaphore))
|
|
(define evt-fifo (make-queue))
|
|
(define log-fifo (make-queue))
|
|
(define log-fifo-max 100)
|
|
|
|
(define re-event #px"^([^:]+)([:]([^:]+))?")
|
|
|
|
|
|
(define (event-queuer evt)
|
|
(enqueue! evt-fifo evt)
|
|
(semaphore-post evt-sem))
|
|
|
|
(define (process-event h evt*)
|
|
(let* ((evt (bytes->string/utf-8 evt*))
|
|
(m (regexp-match re-event evt)))
|
|
(ww-debug evt)
|
|
(let* ((e (string->symbol (string-downcase (list-ref m 1))))
|
|
(win-id (if (eq? (list-ref m 3) #f) #f (string->number (list-ref m 3))))
|
|
(evt-handler (hash-ref windows-evt-handlers win-id #f))
|
|
(payload* (substring evt (string-length (list-ref m 0))))
|
|
(payload (if (string=? payload* "")
|
|
(make-hash)
|
|
(with-input-from-string (substring payload* 1) read-json)))
|
|
)
|
|
(if (eq? evt-handler #f)
|
|
(ww-error (format "no event handler to handle event ~a" evt))
|
|
(queue-callback (lambda () (evt-handler e payload))))
|
|
)
|
|
)
|
|
)
|
|
|
|
(define (event-handler h)
|
|
(parameterize ([current-eventspace (current-eventspace)])
|
|
(thread
|
|
(lambda ()
|
|
(letrec ((f (lambda ()
|
|
(semaphore-wait evt-sem)
|
|
(queue-callback
|
|
(lambda () (process-event h (dequeue! evt-fifo))))
|
|
(f))))
|
|
(f))))))
|
|
|
|
|
|
(define (process-log kind* msg*)
|
|
(define (ensure-fifo)
|
|
(if (> (queue-length log-fifo) log-fifo-max)
|
|
(begin
|
|
(dequeue! log-fifo)
|
|
(ensure-fifo))
|
|
(queue-length log-fifo)))
|
|
(let ((kind (bytes->string/utf-8 kind*))
|
|
(msg (bytes->string/utf-8 msg*)))
|
|
(enqueue! log-fifo (cons kind msg))
|
|
(ensure-fifo)))
|
|
|
|
(define (ww-display-log)
|
|
(for-each (λ (item)
|
|
(displayln (format "~a - ~a" (car item) (cdr item))))
|
|
(queue->list log-fifo)))
|
|
|
|
|
|
(define (ww-start . args)
|
|
(when (eq? ww-current-handle #f)
|
|
(let ((existing-h (webwire-current)))
|
|
(let ((h (make-web-rkt (if (eq? existing-h #f)
|
|
(webwire-new)
|
|
existing-h)
|
|
#f
|
|
#f)))
|
|
(unless (eq? (webwire-status (web-rkt-handle h)) 'valid)
|
|
(error (format "Invalid handle, cannot start. Reason: ~a"
|
|
(webwire-status->string
|
|
(webwire-status (web-rkt-handle h))))))
|
|
(let ((thrd (event-handler h)))
|
|
(webwire-handlers! (web-rkt-handle h)
|
|
event-queuer
|
|
process-log)
|
|
(set-web-rkt-event-thread! h thrd)
|
|
(set! ww-current-handle h)))))
|
|
(unless (null? args)
|
|
(ww-log-level (car args)))
|
|
ww-current-handle)
|
|
|
|
(define (ww-stop)
|
|
(unless (eq? ww-current-handle #f)
|
|
(let ((thr (web-rkt-event-thread ww-current-handle)))
|
|
(kill-thread thr))
|
|
;; inform event handlers of destroying of windows.
|
|
(let ((keys (hash-keys windows-evt-handlers)))
|
|
(for-each (λ (win-id)
|
|
(let ((handler (hash-ref windows-evt-handlers win-id)))
|
|
(handler 'destroyed #f)))
|
|
keys))
|
|
(webwire-destroy (web-rkt-handle ww-current-handle))
|
|
(set! ww-current-handle #f)))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Commands
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;;;;;;;;;; Types
|
|
|
|
(define-struct ww-win
|
|
(id)
|
|
#:transparent)
|
|
|
|
(define-struct cmdr
|
|
(ok kind win r))
|
|
|
|
;;;;;;;;;;;; Command Utilities
|
|
|
|
(define (cmdr->list r)
|
|
(list (cmdr-ok r) (cmdr-kind r)
|
|
(cmdr-win r) (cmdr-r r)))
|
|
|
|
(define (cmdr-dbg r)
|
|
(ww-debug (cmdr->list r))
|
|
(cmdr-r r))
|
|
|
|
(define (ww-from-json result)
|
|
(hash-ref (with-input-from-string
|
|
(string-replace result "\\\"" "\"")
|
|
read-json) 'result #f))
|
|
|
|
(define re-generic-result #px"^(OK|NOK)[:]([^:]+)([:]([0-9]+))?")
|
|
|
|
(define (convert-result result)
|
|
(let ((m (regexp-match re-generic-result result)))
|
|
(ww-debug result)
|
|
(ww-debug m)
|
|
(if m
|
|
(let* ((ok (string=? (list-ref m 1) "OK"))
|
|
(kind (list-ref m 2))
|
|
(win (if (eq? (list-ref m 4) #f)
|
|
#f
|
|
(string->number (list-ref m 4))))
|
|
(r (substring result (string-length (list-ref m 0))))
|
|
)
|
|
(make-cmdr ok (string->symbol kind)
|
|
win
|
|
(if (string-prefix? r ":")
|
|
(substring r 1)
|
|
r)))
|
|
(make-cmdr #f 'parse-error #f result))
|
|
)
|
|
)
|
|
|
|
(define (check-nok cmd r)
|
|
(when (eq? (cmdr-ok r) #f)
|
|
(process-log 'CMD-NOK
|
|
(format "~a - ~a" cmd (cmdr->list r)))))
|
|
|
|
;;;;;;;;;;;; Calling commands in the web wire environment
|
|
|
|
(define (ww-cmd cmd)
|
|
(ww-debug (format "ww-cmd ~a" cmd))
|
|
(if (eq? cmd 'quit)
|
|
(let ((result (webwire-command (web-rkt-handle ww-current-handle) "exit")))
|
|
(let ((r (convert-result result)))
|
|
(check-nok cmd r)
|
|
(ww-stop)
|
|
r))
|
|
(let ((result (webwire-command (web-rkt-handle ww-current-handle) cmd)))
|
|
(let ((r (convert-result result)))
|
|
(check-nok cmd r)
|
|
r))))
|
|
|
|
(define (ww-cmd-nok? r)
|
|
(if (cmdr? r)
|
|
(eq? (cmdr-ok r) #f)
|
|
(eq? r 'cmd-nok)))
|
|
|
|
;;;;;;;;;;;; Check functions and converter functions
|
|
|
|
;;;;; Check functions
|
|
|
|
(define (stylesheet-or-string? st)
|
|
(or (stylesheet? st) (string? st)))
|
|
|
|
(define (is-icon-file? ext)
|
|
(lambda (v)
|
|
(let ((r #f))
|
|
(when (string? v)
|
|
(let ((e (string-append "." (symbol->string ext))))
|
|
(when (string-suffix? v e)
|
|
(when (file-exists? v)
|
|
(set! r #t)))))
|
|
(unless r
|
|
(error (format "Need an existing file of type ~a, got ~a"
|
|
ext v)))
|
|
r)))
|
|
|
|
(define (html-file-exists? f)
|
|
(file-exists? f))
|
|
|
|
(define (html-or-file? v)
|
|
(if (file-exists? v)
|
|
#t
|
|
(string? v)))
|
|
|
|
(define (symbol-or-string? s)
|
|
(or (symbol? s) (string? s)))
|
|
|
|
(define (any? v)
|
|
#t)
|
|
|
|
(define (selector? s)
|
|
(or (symbol? s) (string? s)
|
|
(if (list? s)
|
|
(if (null? s)
|
|
#f
|
|
(letrec ((f (λ (l)
|
|
(if (null? l)
|
|
#t
|
|
(and (or (symbol? (car l))
|
|
(string? (car l)))
|
|
(f (cdr l))))
|
|
)
|
|
))
|
|
(f s))
|
|
)
|
|
#f)
|
|
)
|
|
)
|
|
|
|
;;;;; Conversion functions
|
|
|
|
(define (to-selector v)
|
|
(if (symbol? v)
|
|
(format "#~a, ~a" v v)
|
|
(if (string? v)
|
|
v
|
|
(if (list? v)
|
|
(letrec ((f (λ (l)
|
|
(if (null? l)
|
|
""
|
|
(string-append ", " (to-selector (car l))
|
|
(f (cdr l)))))
|
|
))
|
|
(string-append (to-selector (car v))
|
|
(f (cdr v))))
|
|
""))))
|
|
|
|
(define (convert-cmd-result-to type str)
|
|
(ww-debug type)
|
|
(ww-debug str)
|
|
(cond
|
|
((or (eq? type 'number) (eq? type 'int) (eq? type 'real)) (string->number str))
|
|
((eq? type 'symbol) (string->symbol str))
|
|
((eq? type 'json) (ww-from-json str))
|
|
((eq? type 'stylesheet) (string->stylesheet str))
|
|
((eq? type 'ww-win) (make-ww-win (string->number str)))
|
|
((eq? type 'void) 'void)
|
|
((eq? type 'css-style) (string->css-style str))
|
|
(else str)))
|
|
|
|
(define (check-cmd-type v vname type typename)
|
|
(let ((is-type (type v)))
|
|
(unless is-type
|
|
(error
|
|
(format "Expected ~a of type ~a"
|
|
vname typename)))
|
|
#t))
|
|
|
|
(define (convert-arg-to-cmd v vname type)
|
|
(cond
|
|
((eq? type 'symbol?) v)
|
|
((eq? type 'string?) v)
|
|
((or (eq? type 'stylesheet?)
|
|
(eq? type 'stylesheet-or-string?))
|
|
(let* ((css (if (stylesheet? v)
|
|
(stylesheet->string v)
|
|
v))
|
|
(h (let ((h (make-hasheq)))
|
|
(hash-set! h 'css css)
|
|
h))
|
|
(json (jsexpr->string h))
|
|
)
|
|
json))
|
|
((eq? type 'ww-win?) (ww-win-id v))
|
|
((eq? type 'is-menu?) (menu->json v))
|
|
((eq? type 'html-file-exists?) (to-server-file v))
|
|
((eq? type 'html-or-file?) (if (file-exists? v)
|
|
(to-server-file v)
|
|
v))
|
|
((eq? type 'any?) (as-string v))
|
|
((eq? type 'selector?) (to-selector v))
|
|
((eq? type 'css-style?) (css-style->string v))
|
|
((eq? type 'boolean?) (if (eq? v #f) 'false 'true))
|
|
((eq? type 'symbol-or-string?) v)
|
|
((eq? type 'number?) v)
|
|
(else (begin
|
|
(ww-error (format "Convert-arg-to-cmd Unexpected: ~a ~a ~a" vname type v))
|
|
v))))
|
|
|
|
|
|
;;;; Generic syntax to define commands
|
|
(define-syntax def-cmd-check
|
|
(syntax-rules ()
|
|
((_ var type)
|
|
(check-cmd-type var 'var type 'type))
|
|
)
|
|
)
|
|
|
|
(define-syntax check-opt
|
|
(syntax-rules ()
|
|
((_ i (var type) args)
|
|
(begin
|
|
(unless (>= i (length args))
|
|
(check-cmd-type (list-ref args i)
|
|
'var
|
|
type 'type)
|
|
(set! i (+ i 1)))))
|
|
)
|
|
)
|
|
|
|
(define-syntax def-cmd-opt-checks
|
|
(syntax-rules ()
|
|
((_ (vt ...) more)
|
|
(let ((i 0))
|
|
(begin
|
|
(check-opt i vt more)
|
|
...)
|
|
(when (< i (length more))
|
|
(error "Too many arguments given"))))
|
|
)
|
|
)
|
|
|
|
(define (mk-cmd-arg* v vname type)
|
|
(let ((o (open-output-string)))
|
|
(display " " o)
|
|
(write (convert-arg-to-cmd v vname type) o)
|
|
(get-output-string o)))
|
|
|
|
(define-syntax mk-cmd-arg
|
|
(syntax-rules ()
|
|
((_ a type)
|
|
(mk-cmd-arg* a 'a 'type))))
|
|
|
|
(define-syntax mk-cmd-opt-args
|
|
(syntax-rules ()
|
|
((_ c ((a t) ...) more)
|
|
(letrec ((f (lambda (m ts)
|
|
(if (null? m)
|
|
""
|
|
(string-append (mk-cmd-arg* (car m) (caar ts) (cadar ts)) ;;; TODO -- Hier convert-arg-to-cmd in plotten, want dit worden symbols en dat is niet de bedoeling.
|
|
(f (cdr m) (cdr ts)))))))
|
|
(set! c (string-append c (f more (list '(a t) ...)))))
|
|
)
|
|
)
|
|
)
|
|
|
|
(define-syntax mk-cmd-call
|
|
(syntax-rules ()
|
|
((_ cmd type output-cvt)
|
|
(let ((r (ww-cmd cmd)))
|
|
(ww-debug (cmdr->list r))
|
|
(if (cmdr-ok r)
|
|
(output-cvt (convert-cmd-result-to type (cmdr-r r)))
|
|
'cmd-nok))
|
|
)
|
|
)
|
|
)
|
|
|
|
(define-syntax mk-func-def
|
|
(syntax-rules ()
|
|
((_ func cmd () () args type output-cvt)
|
|
(define (func)
|
|
(let ((c (format "~a" 'cmd)))
|
|
(mk-cmd-call c type output-cvt)))
|
|
)
|
|
((_ func cmd ((a t) ...) () args type output-cvt)
|
|
(define (func a ...)
|
|
(begin
|
|
(def-cmd-check a t)
|
|
...)
|
|
(let ((c (format "~a" 'cmd)))
|
|
(begin
|
|
(set! c (string-append c (mk-cmd-arg a t)))
|
|
...)
|
|
(mk-cmd-call c type output-cvt)
|
|
))
|
|
)
|
|
((_ func cmd () ((a t) ...) args type output-cvt)
|
|
(define (func . args)
|
|
(def-cmd-opt-checks ((a t) ...) args)
|
|
(let ((c (format "~a" 'cmd)))
|
|
(mk-cmd-opt-args c ((a t) ...) args)
|
|
(mk-cmd-call c type output-cvt)))
|
|
)
|
|
((_ func cmd ((a t ) ...) ((oa ot) ...) args type output-cvt)
|
|
(define (func a ... . args)
|
|
(begin
|
|
(def-cmd-check a t)
|
|
...)
|
|
(def-cmd-opt-checks ((oa ot) ...) args)
|
|
(let ((c (format "~a" 'cmd)))
|
|
(begin
|
|
(set! c (string-append c (mk-cmd-arg a t)))
|
|
...)
|
|
(mk-cmd-opt-args c ((oa ot) ...) args)
|
|
(mk-cmd-call c type output-cvt)))
|
|
)
|
|
)
|
|
)
|
|
|
|
(define-syntax id-converter
|
|
(syntax-rules ()
|
|
((_ val) val)))
|
|
|
|
(define-syntax def-cmd
|
|
(syntax-rules (args)
|
|
((_ func cmd mandatories optionals -> type)
|
|
(mk-func-def func cmd mandatories optionals args 'type id-converter))
|
|
((_ func cmd mandatories optionals -> type => output-converter)
|
|
(mk-func-def func cmd mandatories optionals args 'type output-converter))
|
|
)
|
|
)
|
|
|
|
(define-syntax def-func
|
|
(syntax-rules ()
|
|
((_ func () () args body)
|
|
(define (func)
|
|
body))
|
|
((_ func ((a t) ...) () args body)
|
|
(define (func a ...)
|
|
(begin
|
|
(def-cmd-check a t)
|
|
...)
|
|
(begin body)))
|
|
((_ func () ((oa ot) ...) args body)
|
|
(define (func . args)
|
|
(def-cmd-opt-checks ((oa ot) ...) args)
|
|
(begin body)))
|
|
((_ func ((a t) ...) ((oa ot) ...) args body)
|
|
(define (func a ... . args)
|
|
(begin
|
|
(def-cmd-check a t)
|
|
...)
|
|
(def-cmd-opt-checks ((oa ot) ...) args)
|
|
(begin body))
|
|
)
|
|
)
|
|
)
|
|
|
|
(define-syntax define/typed
|
|
(syntax-rules (args)
|
|
((_ (func mandatories optionals) body)
|
|
(def-func func mandatories optionals args body)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Web Wire Commands
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
(def-cmd ww-log-level
|
|
loglevel () ((level symbol?)) -> symbol)
|
|
(def-cmd ww-protocol
|
|
protocol () () -> int)
|
|
|
|
;; Global stylesheet
|
|
(def-cmd ww-set-stylesheet
|
|
set-stylesheet ((st stylesheet-or-string?)) () -> void)
|
|
(def-cmd ww-get-stylesheet
|
|
get-stylesheet () () -> stylesheet)
|
|
|
|
;; New window
|
|
(def-cmd ww-new
|
|
new ((profile symbol?)) [(use-browser boolean?) (parent ww-win?)]
|
|
-> ww-win)
|
|
|
|
;; Close window
|
|
(def-cmd ww-close
|
|
close ((win-id ww-win?)) [] -> void)
|
|
|
|
;; Move window
|
|
(def-cmd ww-move
|
|
move ((win-id ww-win?) (x number?) (y number?)) [] -> void)
|
|
|
|
;; Resize window
|
|
(def-cmd ww-resize
|
|
resize ((win-id ww-win?) (width? number?) (height number?)) [] -> void)
|
|
|
|
;; Set title of window
|
|
(def-cmd ww-set-title
|
|
set-title ((win-id ww-win?) (title string?)) [] -> void)
|
|
|
|
;; Set icon of window
|
|
(def-cmd ww-set-icon
|
|
set-icon ((win-id ww-win?)
|
|
(svg-file (is-icon-file? 'svg))
|
|
(png-file (is-icon-file? 'png))) [] -> void)
|
|
|
|
;; Set menu of window
|
|
(def-cmd ww-set-menu
|
|
set-menu ((win-id ww-win?)
|
|
(menu is-menu?)) [] -> void)
|
|
|
|
|
|
(define (new-handle)
|
|
#t)
|
|
|
|
;; set url
|
|
(def-cmd ww-set-url
|
|
set-url ((win-id ww-win?)
|
|
(url string?)) () -> void)
|
|
|
|
;; Set html of window
|
|
(def-cmd ww-set-html
|
|
set-html ((win-id ww-win?)
|
|
(html-file html-file-exists?)) ()
|
|
-> number)
|
|
|
|
|
|
;; Set inner html of an Id of the HTML in the window
|
|
(def-cmd ww-set-inner-html
|
|
set-inner-html ((win-id ww-win?)
|
|
(html-of-file html-or-file?)) () -> void)
|
|
|
|
|
|
;; Het the inner html of an id of the HTML in the window
|
|
(def-cmd ww-get-inner-html
|
|
get-inner-html ((win-id ww-win?)
|
|
(element-id symbol-or-string?)) () -> json)
|
|
|
|
;; Set attribute of element in html
|
|
(def-cmd ww-set-attr
|
|
set-attr ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(attr symbol-or-string?)
|
|
(val any?)) () -> void)
|
|
|
|
;; Get attribute value of element in html
|
|
(def-cmd ww-get-attr
|
|
get-attr ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(attr symbol-or-string?)) () -> json)
|
|
|
|
;; Get all attributes of an element with given id
|
|
|
|
(define (mk-attrs r)
|
|
(let ((attrs (make-hash)))
|
|
(for-each (λ (attr-val)
|
|
(hash-set! attrs
|
|
(string->symbol (car attr-val))
|
|
(cadr attr-val)))
|
|
r)
|
|
attrs))
|
|
|
|
(def-cmd ww-get-attrs
|
|
get-attrs ((win-id ww-win?)
|
|
(element-id symbol-or-string?)) () -> json
|
|
-> mk-attrs)
|
|
|
|
;(define (ww-get-attrs w id)
|
|
; (let ((r (ww-get-attrs* w id)))
|
|
; (if (ww-cmd-nok? r)
|
|
; r
|
|
; (mk-attrs r))))
|
|
|
|
;; Get info of all elements for a selector
|
|
(def-cmd ww-get-elements
|
|
get-elements ((win-id ww-win?)
|
|
(selector selector?)) () -> json
|
|
-> (λ (r)
|
|
(map (λ (item)
|
|
(cons (string->symbol (car item))
|
|
(mk-attrs (cadr item))))
|
|
r)))
|
|
|
|
|
|
;(define (ww-get-elements win-id selector)
|
|
; (let ((r (ww-get-elements* win-id selector)))
|
|
; (map (λ (item)
|
|
; (cons (string->symbol (car item))
|
|
; (mk-attrs (cadr item))))
|
|
; r)))
|
|
|
|
;; Delete attribute of element
|
|
(def-cmd ww-del-attr
|
|
del-attr ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(attr symbol-or-string?)
|
|
) () -> void)
|
|
|
|
(define (ww-await . args)
|
|
#t)
|
|
|
|
;; get value of an element
|
|
(def-cmd ww-get-value
|
|
value ((win-id ww-win?)
|
|
(element-id symbol-or-string?)) () -> string)
|
|
|
|
;; set value of an element
|
|
(def-cmd ww-set-value
|
|
value ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(value any?)) () -> void)
|
|
|
|
;; Bind some CSS selector to an event, given that each
|
|
;; element that satisfies the selector has to have an id.
|
|
;; Note: get-elements, also working on selectors, will
|
|
;; assign an id to all elements that satisfy the selector
|
|
;; without one.
|
|
;; Returns list of lists of id, tag an type attribute of
|
|
;; each element that has been bound.
|
|
(def-cmd ww-bind
|
|
bind ((win-id ww-win?)
|
|
(event symbol-or-string?)
|
|
(selector selector?)) () -> json
|
|
-> (λ (r)
|
|
(map (λ (item)
|
|
(map string->symbol item))
|
|
r)))
|
|
|
|
;; Bind an element with the given id to the event
|
|
(def-cmd ww-on
|
|
on ((win-id ww-win?)
|
|
(event symbol-or-string?)
|
|
(id symbol-or-string?)) () -> void)
|
|
|
|
;; Element info
|
|
(def-cmd ww-element-info
|
|
element-info ((win-id ww-win?)
|
|
(element-id symbol-or-string?)) ()
|
|
-> json
|
|
-> (λ (r)
|
|
(list (string->symbol (car r))
|
|
(if (string=? (cadr r) "")
|
|
#f
|
|
(string->symbol (cadr r)))
|
|
(if (string=? (caddr r) "")
|
|
#f
|
|
(string->symbol (caddr r)))
|
|
(cadddr r)))
|
|
)
|
|
|
|
|
|
;; Add a class to an element
|
|
(def-cmd ww-add-class
|
|
add-class ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(class symbol-or-string?))
|
|
() -> void)
|
|
|
|
;; Remove a class from an element
|
|
(def-cmd ww-remove-class
|
|
remove-class ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(class symbol-or-string?))
|
|
() -> void)
|
|
|
|
;; Has a class
|
|
(define re-class-split #px"\\s+")
|
|
|
|
(define/typed (ww-has-class? ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(class* symbol-or-string?))
|
|
())
|
|
(let* ((cl (string-trim (ww-get-attr win-id element-id "class")))
|
|
(class (format "~a" class*)))
|
|
(if (eq? cl #f)
|
|
#f
|
|
(let* ((cls (regexp-split re-class-split cl)))
|
|
(letrec ((f (lambda (cls)
|
|
(if (null? cls)
|
|
#f
|
|
(let ((cl (car cls)))
|
|
(if (string=? cl class)
|
|
#t
|
|
(f (cdr cls))))
|
|
))
|
|
))
|
|
(f cls)))
|
|
)
|
|
)
|
|
)
|
|
|
|
;; Add a style to an element
|
|
(def-cmd ww-add-style
|
|
add-style ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(css-style css-style?)) () -> void)
|
|
|
|
;; Set a style of an element
|
|
(def-cmd ww-set-style
|
|
set-style ((win-id ww-win?)
|
|
(element-id symbol-or-string?)
|
|
(css-style css-style?)) () -> void)
|
|
|
|
;; Get the style of an element
|
|
(def-cmd ww-get-style
|
|
get-style ((win-id ww-win?)
|
|
(element-id symbol-or-string?)) ()
|
|
-> css-style)
|
|
|
|
;; Show State
|
|
(def-cmd ww-set-show-state
|
|
set-show-state ((win-id ww-win?)
|
|
(state symbol?)) ()
|
|
-> void)
|
|
|
|
(def-cmd ww-get-show-state
|
|
show-state ((win-id ww-win?)) ()
|
|
-> symbol)
|
|
|
|
;; Files and directories
|
|
(define (ww-file-open win-id title dir file-filters)
|
|
(let ((cmd (format "file-open ~a ~a ~a ~a" win-id
|
|
(as-string title)
|
|
(as-string dir)
|
|
(as-string file-filters))))
|
|
(ww-cmd cmd)))
|
|
|
|
(define (ww-file-save win-id title dir file-filters overwrite)
|
|
(let ((cmd (format "file-save ~a ~a ~a ~a ~a" win-id
|
|
(as-string title)
|
|
(as-string dir)
|
|
(as-string file-filters)
|
|
(if overwrite 1 0))))
|
|
(ww-cmd cmd)))
|
|
|
|
(define (ww-choose-dir win-id title dir)
|
|
(let ((cmd (format "choose-dir ~a ~a ~a" win-id
|
|
(as-string title)
|
|
(as-string dir))))
|
|
(ww-cmd cmd)))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Finalizing stuff
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;(define will (make-will-executor))
|
|
|
|
;(define (ww-register-finalizer obj proc)
|
|
; (will-register will obj proc))
|
|
|
|
;(void (thread (λ () (let loop () (will-execute will) (loop)))))
|
|
|
|
); end of module |