webview

Check-in [56a431953b]
Login

Check-in [56a431953b]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improved content modification tools
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 56a431953b596a2466e1e7971d25a9c9adae8feb0043af4e56974b3c49651d7b
User & Date: murphy 2018-09-01 15:08:29.837
Context
2018-09-01
15:28
Documentation links check-in: 30b8e128e3 user: murphy tags: trunk, v1.0.0
15:08
Improved content modification tools check-in: 56a431953b user: murphy tags: trunk
13:06
Silly fortune database example check-in: 0f7cbfc3e6 user: murphy tags: trunk
Changes
Unified Diff Show Whitespace Changes Patch
Changes to examples/fortune.scm.
20
21
22
23
24
25
26
27
28
29


30
31
32

33
34
35

36
37
38
39
40
41
42
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;; SOFTWARE.
;;

(import
  (chicken fixnum)
  (chicken io)
  (only (chicken blob) string->blob)
  (only (chicken time) current-seconds)


  (only srfi-1 break!)
  (only srfi-13 string-null? string-prefix? string-join)
  srfi-4

  tweetnacl
  lmdb
  webview)


(define rng
  (open-random-stream
   (string->blob "Not a very random stream key ;-)")
   (do ([v (make-u8vector random-stream-noncebytes)]
        [n (current-seconds) (quotient n 256)]
        [i 0 (fx+ i 1)])







<


>
>

<

>


|
>







20
21
22
23
24
25
26

27
28
29
30
31

32
33
34
35
36
37
38
39
40
41
42
43
44
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;; SOFTWARE.
;;

(import
  (chicken fixnum)

  (only (chicken blob) string->blob)
  (only (chicken time) current-seconds)
  (chicken io)
  (only (chicken port) call-with-output-string)
  (only srfi-1 break!)

  srfi-4
  (only srfi-13 string-null? string-prefix? string-join)
  tweetnacl
  lmdb
  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)]
        [n (current-seconds) (quotient n 256)]
        [i 0 (fx+ i 1)])
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109










110
111

112
113
114
115
116
117
118
119

120
121
122
123
124
125
126


127


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
               (database-fold
                (lambda (key val seed) (return val))
                #f db #:from key)))
           (and key
                (retry (substring key 0 (fx- (string-length key) 1)))))))
   #:read-only))

(define (render-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)))



(webview
 "Fortune"
 (lambda (view msg)
   (cond
     [(string=? "load" msg)
      (inject-app view)]
     [(string=? "random" msg)
      (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")))]
     [(string=? "edit" msg)
      (inject-editor view)]
     [(string-prefix? "save:" msg)
      (add-fortune! (substring msg 5))
      (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: ;;







|






|
|
|

|
|
|
|
|
>
>
>
>
>
>
>
>
>
>

|
>


|

|

|

>
|



|

|
>
>
|
>
>






|

|

<
<
|
<
<

|


|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155


156


157
158
159
160
161
162
163
164
165
166
167
168
               (database-fold
                (lambda (key val seed) (return val))
                #f db #:from key)))
           (and key
                (retry (substring key 0 (fx- (string-length key) 1)))))))
   #:read-only))

(define (make-fortune)
  (cond
    [(get-fortune)
     => (cut list 'pre <>)]
    [else
     '(pre ([style "text-color: grey;"]) "(nothing found)")]))

(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)]
     [(string=? "random" msg)
      (inject-fortune! view)]
     [(string=? "add-file" msg)


      (on-add-file view)]


     [(string=? "edit" msg)
      (inject-editor! view)]
     [(string-prefix? "save:" msg)
      (add-fortune! (substring msg 5))
      (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: ;;
Changes to main.scm.
121
122
123
124
125
126
127















128
129
130
131
132











133
134
135


136
137
138















139
140
141
142
143
144
145
  (unless (zero?
           ((foreign-safe-lambda
             int "webview_eval"
             nonnull-webview nonnull-c-string)
            view script))
    (error 'webview-eval "JavaScript evaluation failed")))
















(define (webview-inject view id html)
  (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)))))
















(define (webview-dialog view title type #!optional value)
  (let ([type
         (case type
           [(#:open #:open-directory)
            (foreign-value "WEBVIEW_DIALOG_TYPE_OPEN" int)]
           [(#:save)







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|




>
>
>
>
>
>
>
>
>
>
>
|
|
|
>
>



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  (unless (zero?
           ((foreign-safe-lambda
             int "webview_eval"
             nonnull-webview nonnull-c-string)
            view script))
    (error 'webview-eval "JavaScript evaluation failed")))

(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 "(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)
            (foreign-value "WEBVIEW_DIALOG_TYPE_OPEN" int)]
           [(#:save)
Changes to webview.scm.
37
38
39
40
41
42
43



44
45
46
47
48
49
50
51
  (include 
    "content.scm"))

(module webview
  (webview?
   webview webview-terminate!
   webview-title-set! webview-fullscreen-set!



   webview-eval webview-inject webview-dialog webview-log)
  (import
    scheme
    (chicken base)
    (chicken condition)
    (chicken fixnum)
    (chicken bitwise)
    (chicken foreign)







>
>
>
|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  (include 
    "content.scm"))

(module webview
  (webview?
   webview webview-terminate!
   webview-title-set! webview-fullscreen-set!
   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)
    (chicken bitwise)
    (chicken foreign)
Changes to webview.wiki.
72
73
74
75
76
77
78


79








80
81








82
83
84
85
86
87













88
89
90
91
92
93
94
  (webview-eval WEBVIEW SCRIPT) ⇒ VOID
</nowiki></tt></h3>

Asynchronously triggers evaluation of the given <tt>SCRIPT</tt> code in
the context of the page displayed by the given <tt>WEBVIEW</tt>.

<h3><tt><nowiki>


  (webview-inject WEBVIEW ID HTML) ⇒ VOID








</nowiki></tt></h3>









Asynchronously triggers replacement of the DOM element with the given
<tt>ID</tt> on the page displayed by the given <tt>WEBVIEW</tt> with the
given <tt>HTML</tt> content.

<tt>HTML</tt> content is specified in the form accepted by
<tt>write-html</tt>.














<h2>Dialogs</h2>

<h3><tt><nowiki>
  (webview-dialog WEBVIEW TITLE TYPE [VALUE]) ⇒ VALUE
</nowiki></tt></h3>








>
>
|
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
|
|




>
>
>
>
>
>
>
>
>
>
>
>
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  (webview-eval WEBVIEW SCRIPT) ⇒ VOID
</nowiki></tt></h3>

Asynchronously triggers evaluation of the given <tt>SCRIPT</tt> code in
the context of the page displayed by the given <tt>WEBVIEW</tt>.

<h3><tt><nowiki>
  (webview-style-set! WEBVIEW SELECTOR PROPERTY VALUE [PRIORITY]) ⇒ VOID
</nowiki></tt></h3>

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

<h3><tt><nowiki>
  (webview-style-set! WEBVIEW SELECTOR PROPERTY VALUE [PRIORITY]) ⇒ VOID
</nowiki></tt></h3>

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

<h3><tt><nowiki>
  (webview-html-set! WEBVIEW SELECTOR HTML [OUTER?]) ⇒ VOID
</nowiki></tt></h3>

Asynchronously triggers replacement of the first DOM element matching the given
<tt>SELECTOR</tt> on the page displayed by the given <tt>WEBVIEW</tt> with the
given <tt>HTML</tt> content.

<tt>HTML</tt> content is specified in the form accepted by
<tt>write-html</tt>.

If <tt>OUTER?</tt> is <tt>#f</tt> or not given, only the <em>contents</em> of
the specified element are replaced, otherwise the entire element is replaced.

<h3><tt><nowiki>
  (webview-html-delete! WEBVIEW SELECTOR [OUTER?]) ⇒ VOID
</nowiki></tt></h3>

Asynchronously triggers removal of the first DOM element matching the given
<tt>SELECTOR</tt> from the page displayed by the given <tt>WEBVIEW</tt>.

If <tt>OUTER?</tt> is <tt>#f</tt> or not given, only the <em>contents</em> of
the specified element are removed, otherwise the entire element is deleted.

<h2>Dialogs</h2>

<h3><tt><nowiki>
  (webview-dialog WEBVIEW TITLE TYPE [VALUE]) ⇒ VALUE
</nowiki></tt></h3>