Index: examples/fortune.scm ================================================================== --- examples/fortune.scm +++ examples/fortune.scm @@ -22,19 +22,21 @@ ;; SOFTWARE. ;; (import (chicken fixnum) - (chicken io) (only (chicken blob) string->blob) (only (chicken time) current-seconds) + (chicken io) + (only (chicken port) call-with-output-string) (only srfi-1 break!) - (only srfi-13 string-null? string-prefix? string-join) srfi-4 + (only srfi-13 string-null? string-prefix? string-join) tweetnacl lmdb - webview) + webview + (only webview-content write-js)) (define rng (open-random-stream (string->blob "Not a very random stream key ;-)") (do ([v (make-u8vector random-stream-noncebytes)] @@ -89,66 +91,78 @@ #f db #:from key))) (and key (retry (substring key 0 (fx- (string-length key) 1))))))) #:read-only)) -(define (render-fortune) +(define (make-fortune) (cond [(get-fortune) => (cut list 'pre <>)] [else '(pre ([style "text-color: grey;"]) "(nothing found)")])) -(define (inject-fortune view) - (webview-eval view "document.getElementById('save').style.setProperty('display','none')") - (webview-inject view "fortune" (render-fortune))) - -(define (inject-editor view) - (webview-eval view "document.getElementById('save').style.setProperty('display','inline')") - (webview-inject view "fortune" - '(textarea ([cols "72"] [rows "16"] [wrap "off"]) - ""))) - -(define (render-app) - `(begin - (div ([class "toolbar"]) - (button ([type "click"] [onclick "external.invoke('random')"]) - "Random") - (button ([type "click"] [onclick "external.invoke('add-file')"]) - "Add File…") - (button ([type "click"] [onclick "external.invoke('edit')"]) - "New…") - (button ([type "click"] [id "save"] [onclick "external.invoke('save:' + document.getElementById('fortune').getElementsByTagName('textarea')[0].value)"] [style "display: none;"]) - "Save")) - (div ([class "content"]) - (code ([id "fortune"]) - ,(render-fortune))))) - -(define (inject-app view) - (webview-inject view "app" (render-app))) +(define (inject-fortune! view) + (webview-style-set! view "#save" "display" "none") + (webview-html-set! view "#fortune" (make-fortune))) + +(define (inject-editor! view) + (webview-style-set! view "#save" "display" "inline") + (webview-html-set! view "#fortune" + '(textarea ([cols "72"] [rows "16"] [wrap "off"] [style "font-family: monospace;"])))) + +(define (make-invocation name #!optional selector) + (call-with-output-string + (lambda (port) + (display "window.external.invoke(" port) + (write-js name port) + (when selector + (display "+document.querySelector(" port) + (write-js selector port) + (display ").value" port)) + (display #\) port)))) + +(define (inject-app! view) + (webview-html-set! view "#app" + `(begin + (div ([class "toolbar"]) + (button ([type "button"] [onclick ,(make-invocation "random")]) + "Random") + (button ([type "button"] [onclick ,(make-invocation "add-file")]) + "Add File…") + (button ([type "button"] [onclick ,(make-invocation "edit")]) + "New…") + (button ([type "button"] [onclick ,(make-invocation "save:" "#fortune textarea")] + [id "save"] [style "display: none;"]) + "Save")) + (div ([class "content"]) + (code ([id "fortune"]) + ,(make-fortune)))))) + +(define (on-add-file view) + (and-let* ([p (webview-dialog view "Add File" #:open)] + [n (add-fortunes-file! p)]) + (webview-dialog + view "Add File" #:info + (string-append (number->string n) " fortunes added")))) (webview "Fortune" (lambda (view msg) (cond [(string=? "load" msg) - (inject-app view)] + (inject-app! view)] [(string=? "random" msg) - (inject-fortune view)] + (inject-fortune! view)] [(string=? "add-file" msg) - (and-let* ([p (webview-dialog view "Add File" #:open)] - [n (add-fortunes-file! p)]) - (webview-dialog - view "Add File" #:info - (string-append (number->string n) " fortunes added")))] + (on-add-file view)] [(string=? "edit" msg) - (inject-editor view)] + (inject-editor! view)] [(string-prefix? "save:" msg) (add-fortune! (substring msg 5)) - (inject-fortune view)] + (inject-fortune! view)] [else (webview-log (string-append "Unknown Message: " msg))])) #:width 640 #:height 320) (close-database-environment) ;; vim: set ai et ts=4 sts=2 sw=2 ft=scheme: ;; Index: main.scm ================================================================== --- main.scm +++ main.scm @@ -123,21 +123,64 @@ int "webview_eval" nonnull-webview nonnull-c-string) view script)) (error 'webview-eval "JavaScript evaluation failed"))) -(define (webview-inject view id html) +(define (webview-style-set! view selector property value #!optional [priority ""]) + (webview-eval + view + (call-with-output-string + (lambda (port) + (display "Array.prototype.forEach.call(document.querySelectorAll(" port) + (write-js selector port) + (display "),function(it){it.style.setProperty(" port) + (write-js property port) + (display #\, port) + (write-js value port) + (display #\, port) + (write-js priority port) + (display ")})" port))))) + +(define (webview-style-delete! view selector property) + (webview-eval + view + (call-with-output-string + (lambda (port) + (display "Array.prototype.forEach.call(document.querySelectorAll(" port) + (write-js selector port) + (display "),function(it){it.style.removeProperty(" port) + (write-js property port) + (display ")})" port))))) + +(define (webview-html-set! view selector html #!optional [outer? #f]) + (webview-eval + view + (call-with-output-string + (lambda (port) + (display "document.querySelector(" port) + (write-js selector port) + (display ")." port) + (display (if outer? "outer" "inner") port) + (display "HTML=" port) + (write-js + (call-with-output-string (cut write-html html <>)) + port))))) + +(define (webview-html-delete! view selector #!optional [outer? #f]) (webview-eval view (call-with-output-string (lambda (port) - (display "document.getElementById(" port) - (write-js id port) - (display ").innerHTML=" port) - (write-js - (call-with-output-string (cut write-html html <>)) - port))))) + (display "(function(it){" port) + (display + (if outer? + "it.parentNode.removeChild(it)" + "while(it.firstChild){it.removeChild(it.firstChild)}") + port) + (display "})(document.querySelector(" port) + (write-js selector port) + (display "))" port))))) (define (webview-dialog view title type #!optional value) (let ([type (case type [(#:open #:open-directory) Index: webview.scm ================================================================== --- webview.scm +++ webview.scm @@ -32,18 +32,21 @@ (prefix (only utf8 string-length string-ref display) utf8-) (only srfi-13 string-pad) utf8-srfi-14 (prefix unicode-char-sets unicode-) srfi-69) - (include + (include "content.scm")) (module webview (webview? webview webview-terminate! webview-title-set! webview-fullscreen-set! - webview-eval webview-inject webview-dialog webview-log) + webview-eval + webview-style-set! webview-style-delete! + webview-html-set! webview-html-delete! + webview-dialog webview-log) (import scheme (chicken base) (chicken condition) (chicken fixnum) Index: webview.wiki ================================================================== --- webview.wiki +++ webview.wiki @@ -74,19 +74,50 @@ Asynchronously triggers evaluation of the given SCRIPT code in the context of the page displayed by the given WEBVIEW.

- (webview-inject WEBVIEW ID HTML) ⇒ VOID + (webview-style-set! WEBVIEW SELECTOR PROPERTY VALUE [PRIORITY]) ⇒ VOID +

+ +Asynchronously triggers a style modification of all DOM elements matching the +given SELECTOR on the page displayed by the given WEBVIEW. +The given style PROPERTY is set to the given VALUE for the +selected elements, optionally specifying a PRIORITY other than the +default. + +

+ (webview-style-set! WEBVIEW SELECTOR PROPERTY VALUE [PRIORITY]) ⇒ VOID +

+ +Asynchronously triggers a style modification of all DOM elements matching the given +SELECTOR on the page displayed by the given WEBVIEW. The +given style PROPERTY is removed from the selected elements. + +

+ (webview-html-set! WEBVIEW SELECTOR HTML [OUTER?]) ⇒ VOID

-Asynchronously triggers replacement of the DOM element with the given -ID on the page displayed by the given WEBVIEW with the +Asynchronously triggers replacement of the first DOM element matching the given +SELECTOR on the page displayed by the given WEBVIEW with the given HTML content. HTML content is specified in the form accepted by write-html. + +If OUTER? is #f or not given, only the contents of +the specified element are replaced, otherwise the entire element is replaced. + +

+ (webview-html-delete! WEBVIEW SELECTOR [OUTER?]) ⇒ VOID +

+ +Asynchronously triggers removal of the first DOM element matching the given +SELECTOR from the page displayed by the given WEBVIEW. + +If OUTER? is #f or not given, only the contents of +the specified element are removed, otherwise the entire element is deleted.

Dialogs

(webview-dialog WEBVIEW TITLE TYPE [VALUE]) ⇒ VALUE