scarpe 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGELOG.md +16 -2
  4. data/Gemfile.lock +7 -3
  5. data/README.md +24 -8
  6. data/Rakefile +1 -1
  7. data/examples/animate.rb +20 -0
  8. data/examples/arrow.rb +10 -0
  9. data/examples/btn_tooltip.rb +7 -0
  10. data/examples/button_style_changed.rb +7 -0
  11. data/examples/button_styles_default.rb +6 -0
  12. data/examples/gen.rb +8 -8
  13. data/examples/highlander.rb +3 -3
  14. data/examples/legacy/README.md +6 -0
  15. data/examples/legacy/not_checked/shoes-contrib/basic/shoes-notes.rb +1 -1
  16. data/examples/legacy/not_checked/simple/anim-shapes.rb +1 -1
  17. data/examples/legacy/not_checked/speedometer_app.rb +55 -0
  18. data/examples/legacy/working/simple/image-icon.rb +3 -0
  19. data/examples/legacy/{not_checked → working}/simple/image.rb +1 -1
  20. data/examples/list_box_choose.rb +17 -0
  21. data/examples/local_assets/local_file_server.rb +82 -0
  22. data/examples/local_assets/sample.gif +0 -0
  23. data/examples/local_assets/sample.mp4 +0 -0
  24. data/examples/local_fonts.rb +2 -2
  25. data/examples/local_images.rb +2 -3
  26. data/examples/para/para_text.rb +14 -0
  27. data/examples/progress.rb +31 -0
  28. data/examples/radio/radio_groups.rb +2 -2
  29. data/examples/rect.rb +4 -0
  30. data/examples/rotate_shapes.rb +17 -0
  31. data/examples/simpler-menu.rb +21 -0
  32. data/exe/scarpe +2 -1
  33. data/lacci/Gemfile +2 -0
  34. data/lacci/Gemfile.lock +8 -1
  35. data/lacci/lacci.gemspec +1 -1
  36. data/lacci/lib/lacci/scarpe_cli.rb +2 -1
  37. data/lacci/lib/lacci/scarpe_core.rb +2 -1
  38. data/lacci/lib/lacci/version.rb +1 -1
  39. data/lacci/lib/scarpe/niente/app.rb +23 -0
  40. data/lacci/lib/scarpe/niente/display_service.rb +62 -0
  41. data/lacci/lib/scarpe/niente/drawable.rb +57 -0
  42. data/lacci/lib/scarpe/niente/logger.rb +29 -0
  43. data/lacci/lib/scarpe/niente/shoes_spec.rb +87 -0
  44. data/lacci/lib/scarpe/niente.rb +20 -0
  45. data/lacci/lib/shoes/app.rb +88 -43
  46. data/lacci/lib/shoes/background.rb +2 -2
  47. data/lacci/lib/shoes/border.rb +2 -2
  48. data/lacci/lib/shoes/builtins.rb +63 -0
  49. data/lacci/lib/shoes/changelog.rb +52 -0
  50. data/lacci/lib/shoes/colors.rb +3 -1
  51. data/lacci/lib/shoes/constants.rb +19 -1
  52. data/lacci/lib/shoes/display_service.rb +39 -16
  53. data/lacci/lib/shoes/download.rb +2 -2
  54. data/lacci/lib/shoes/drawable.rb +380 -0
  55. data/lacci/lib/shoes/drawables/arc.rb +49 -0
  56. data/lacci/lib/shoes/drawables/arrow.rb +41 -0
  57. data/lacci/lib/shoes/drawables/button.rb +73 -0
  58. data/lacci/lib/shoes/{widgets → drawables}/check.rb +5 -4
  59. data/lacci/lib/shoes/{widgets → drawables}/document_root.rb +3 -3
  60. data/lacci/lib/shoes/{widgets → drawables}/edit_box.rb +6 -6
  61. data/lacci/lib/shoes/{widgets → drawables}/edit_line.rb +6 -6
  62. data/lacci/lib/shoes/{widgets → drawables}/flow.rb +6 -6
  63. data/lacci/lib/shoes/{widgets → drawables}/image.rb +6 -6
  64. data/lacci/lib/shoes/{widgets → drawables}/line.rb +7 -5
  65. data/lacci/lib/shoes/drawables/link.rb +34 -0
  66. data/lacci/lib/shoes/drawables/list_box.rb +56 -0
  67. data/lacci/lib/shoes/drawables/para.rb +118 -0
  68. data/lacci/lib/shoes/drawables/progress.rb +14 -0
  69. data/lacci/lib/shoes/drawables/radio.rb +33 -0
  70. data/lacci/lib/shoes/drawables/rect.rb +17 -0
  71. data/lacci/lib/shoes/{widgets → drawables}/shape.rb +6 -7
  72. data/lacci/lib/shoes/{widgets → drawables}/slot.rb +32 -20
  73. data/lacci/lib/shoes/{widgets → drawables}/span.rb +8 -7
  74. data/lacci/lib/shoes/{widgets → drawables}/stack.rb +6 -4
  75. data/lacci/lib/shoes/drawables/star.rb +50 -0
  76. data/lacci/lib/shoes/drawables/subscription_item.rb +93 -0
  77. data/lacci/lib/shoes/drawables/text_drawable.rb +63 -0
  78. data/lacci/lib/shoes/drawables/video.rb +16 -0
  79. data/lacci/lib/shoes/drawables/widget.rb +69 -0
  80. data/lacci/lib/shoes/drawables.rb +31 -0
  81. data/lacci/lib/shoes/errors.rb +28 -0
  82. data/lacci/lib/shoes/log.rb +2 -2
  83. data/lacci/lib/shoes/ruby_extensions.rb +15 -0
  84. data/lacci/lib/shoes/spacing.rb +2 -2
  85. data/lacci/lib/shoes-spec.rb +93 -0
  86. data/lacci/lib/shoes.rb +27 -7
  87. data/lacci/test/test_helper.rb +54 -0
  88. data/lacci/test/test_lacci.rb +12 -3
  89. data/lacci/test/test_shoes_errors.rb +49 -0
  90. data/lib/scarpe/cats_cradle.rb +81 -59
  91. data/lib/scarpe/errors.rb +77 -0
  92. data/lib/scarpe/evented_assertions.rb +50 -17
  93. data/lib/scarpe/shoes_spec.rb +181 -0
  94. data/lib/scarpe/version.rb +2 -2
  95. data/lib/scarpe/wv/app.rb +20 -20
  96. data/lib/scarpe/wv/arc.rb +4 -47
  97. data/lib/scarpe/wv/arrow.rb +9 -0
  98. data/lib/scarpe/wv/button.rb +7 -35
  99. data/lib/scarpe/wv/check.rb +3 -5
  100. data/lib/scarpe/wv/control_interface.rb +18 -20
  101. data/lib/scarpe/wv/document_root.rb +81 -4
  102. data/lib/scarpe/wv/{widget.rb → drawable.rb} +66 -43
  103. data/lib/scarpe/wv/edit_box.rb +4 -17
  104. data/lib/scarpe/wv/edit_line.rb +4 -18
  105. data/lib/scarpe/wv/flow.rb +2 -18
  106. data/lib/scarpe/wv/image.rb +8 -28
  107. data/lib/scarpe/wv/line.rb +3 -25
  108. data/lib/scarpe/wv/link.rb +3 -16
  109. data/lib/scarpe/wv/list_box.rb +6 -29
  110. data/lib/scarpe/wv/para.rb +11 -30
  111. data/lib/scarpe/wv/progress.rb +19 -0
  112. data/lib/scarpe/wv/radio.rb +9 -10
  113. data/lib/scarpe/wv/rect.rb +13 -0
  114. data/lib/scarpe/wv/shape.rb +3 -8
  115. data/lib/scarpe/wv/slot.rb +8 -25
  116. data/lib/scarpe/wv/span.rb +3 -27
  117. data/lib/scarpe/wv/stack.rb +2 -18
  118. data/lib/scarpe/wv/star.rb +3 -53
  119. data/lib/scarpe/wv/subscription_item.rb +38 -4
  120. data/lib/scarpe/wv/text_drawable.rb +32 -0
  121. data/lib/scarpe/wv/video.rb +15 -15
  122. data/lib/scarpe/wv/web_wrangler.rb +299 -329
  123. data/lib/scarpe/wv/webview_local_display.rb +48 -33
  124. data/lib/scarpe/wv/webview_relay_display.rb +12 -12
  125. data/lib/scarpe/wv/webview_relay_util.rb +7 -10
  126. data/lib/scarpe/wv/wv_display_worker.rb +2 -2
  127. data/lib/scarpe/wv.rb +45 -12
  128. data/lib/scarpe/wv_local.rb +1 -1
  129. data/lib/scarpe/wv_relay.rb +1 -1
  130. data/lib/scarpe.rb +1 -0
  131. data/logger/debug_web_wrangler.json +1 -1
  132. data/logger/scarpe_wv_test.json +1 -1
  133. data/scarpe-components/Gemfile.lock +86 -0
  134. data/scarpe-components/lib/scarpe/components/base64.rb +3 -7
  135. data/scarpe-components/lib/scarpe/components/calzini/alert.rb +49 -0
  136. data/scarpe-components/lib/scarpe/components/calzini/art_widgets.rb +203 -0
  137. data/scarpe-components/lib/scarpe/components/calzini/button.rb +39 -0
  138. data/scarpe-components/lib/scarpe/components/calzini/misc.rb +146 -0
  139. data/scarpe-components/lib/scarpe/components/calzini/para.rb +35 -0
  140. data/scarpe-components/lib/scarpe/components/calzini/slots.rb +155 -0
  141. data/scarpe-components/lib/scarpe/components/calzini/text_widgets.rb +65 -0
  142. data/scarpe-components/lib/scarpe/components/calzini.rb +149 -0
  143. data/scarpe-components/lib/scarpe/components/errors.rb +20 -0
  144. data/scarpe-components/lib/scarpe/components/file_helpers.rb +1 -0
  145. data/scarpe-components/lib/scarpe/components/html.rb +131 -0
  146. data/scarpe-components/lib/scarpe/components/minitest_export_reporter.rb +75 -0
  147. data/scarpe-components/lib/scarpe/components/minitest_import_runnable.rb +98 -0
  148. data/scarpe-components/lib/scarpe/components/minitest_result.rb +86 -0
  149. data/scarpe-components/lib/scarpe/components/modular_logger.rb +5 -5
  150. data/scarpe-components/lib/scarpe/components/print_logger.rb +9 -5
  151. data/scarpe-components/lib/scarpe/components/promises.rb +14 -14
  152. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +36 -17
  153. data/scarpe-components/lib/scarpe/components/string_helpers.rb +10 -0
  154. data/scarpe-components/lib/scarpe/components/tiranti.rb +225 -0
  155. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +45 -5
  156. data/scarpe-components/lib/scarpe/components/version.rb +2 -2
  157. data/scarpe-components/test/calzini/test_calzini_alert.rb +30 -0
  158. data/scarpe-components/test/calzini/test_calzini_art_drawables.rb +105 -0
  159. data/scarpe-components/test/calzini/test_calzini_button.rb +52 -0
  160. data/scarpe-components/test/calzini/test_calzini_misc.rb +115 -0
  161. data/scarpe-components/test/calzini/test_calzini_para.rb +37 -0
  162. data/scarpe-components/test/calzini/test_calzini_slots.rb +130 -0
  163. data/scarpe-components/test/calzini/test_calzini_text_drawables.rb +41 -0
  164. data/scarpe-components/test/mtr_data/exception.json +1 -0
  165. data/scarpe-components/test/mtr_data/fail_with_message.json +1 -0
  166. data/scarpe-components/test/mtr_data/skipped_no_message.json +1 -0
  167. data/scarpe-components/test/mtr_data/skipped_w_msg.json +1 -0
  168. data/scarpe-components/test/mtr_data/succeed_2_asserts.json +1 -0
  169. data/scarpe-components/test/test_dimensions.rb +26 -0
  170. data/scarpe-components/test/test_helper.rb +20 -0
  171. data/scarpe-components/test/test_html.rb +65 -0
  172. data/scarpe-components/test/test_minitest_result.rb +61 -0
  173. data/scarpe-components/test/test_promises.rb +5 -4
  174. data/scarpe-components/test/test_segmented_app_files.rb +8 -6
  175. data/scarpegen.rb +14 -14
  176. data/sig/scarpe.rbs +1 -1
  177. data/templates/basic_class_template.erb +13 -14
  178. data/templates/class_template_with_event_bind.erb +4 -4
  179. data/templates/class_template_with_shapes.erb +8 -17
  180. data/templates/example_template.erb +1 -1
  181. data/templates/module_template.erb +4 -4
  182. data/templates/webview_template.erb +3 -2
  183. metadata +113 -55
  184. data/examples/legacy/not_checked/shoes-contrib/elements/image-icon.rb +0 -3
  185. data/lacci/lib/shoes/widget.rb +0 -218
  186. data/lacci/lib/shoes/widgets/alert.rb +0 -19
  187. data/lacci/lib/shoes/widgets/arc.rb +0 -51
  188. data/lacci/lib/shoes/widgets/button.rb +0 -35
  189. data/lacci/lib/shoes/widgets/font.rb +0 -14
  190. data/lacci/lib/shoes/widgets/link.rb +0 -25
  191. data/lacci/lib/shoes/widgets/list_box.rb +0 -25
  192. data/lacci/lib/shoes/widgets/para.rb +0 -68
  193. data/lacci/lib/shoes/widgets/radio.rb +0 -35
  194. data/lacci/lib/shoes/widgets/star.rb +0 -44
  195. data/lacci/lib/shoes/widgets/subscription_item.rb +0 -60
  196. data/lacci/lib/shoes/widgets/text_widget.rb +0 -51
  197. data/lacci/lib/shoes/widgets/video.rb +0 -15
  198. data/lacci/lib/shoes/widgets.rb +0 -29
  199. data/lib/scarpe/wv/alert.rb +0 -66
  200. data/lib/scarpe/wv/background.rb +0 -27
  201. data/lib/scarpe/wv/border.rb +0 -24
  202. data/lib/scarpe/wv/control_interface_test.rb +0 -238
  203. data/lib/scarpe/wv/dimensions.rb +0 -22
  204. data/lib/scarpe/wv/font.rb +0 -36
  205. data/lib/scarpe/wv/html.rb +0 -108
  206. data/lib/scarpe/wv/spacing.rb +0 -41
  207. data/lib/scarpe/wv/text_widget.rb +0 -30
  208. /data/examples/legacy/not_checked/{expert → shoes-contrib/basic}/definr.rb +0 -0
  209. /data/examples/legacy/not_checked/{expert → shoes-contrib/basic}/funnies.rb +0 -0
  210. /data/examples/legacy/not_checked/shoes-contrib/{elements → basic}/list_box-select-class.rb +0 -0
  211. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/basic-edit-box.rb +0 -0
  212. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/basic-fps.rb +0 -0
  213. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/border-cat.rb +0 -0
  214. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/check-mate.rb +0 -0
  215. /data/examples/legacy/{not_checked/shoes-contrib/manipulation → working/simple}/clear-slot.rb +0 -0
  216. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/clock.rb +0 -0
  217. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/gradient-shoes.rb +0 -0
  218. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/list_box-shape-report.rb +0 -0
  219. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/list_box.rb +0 -0
  220. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/phat-button.rb +0 -0
  221. /data/examples/legacy/{not_checked/shoes-contrib → working}/simple/simple-calc.rb +0 -0
  222. /data/examples/legacy/{not_checked/shoes-contrib/position → working/simple}/stack-width.rb +0 -0
  223. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/width-introspec.rb +0 -0
@@ -8,9 +8,9 @@ require "cgi"
8
8
  # After creation, it starts in setup mode, and you can
9
9
  # use setup-mode callbacks.
10
10
 
11
- class Scarpe
11
+ module Scarpe::Webview
12
12
  # The Scarpe WebWrangler, for Webview, manages a lot of Webviews quirks. It provides
13
- # a simpler underlying abstraction for DOMWrangler and the Webview widgets.
13
+ # a simpler underlying abstraction for DOMWrangler and the Webview drawables.
14
14
  # Webview can be picky - if you send it too many messages, it can crash. If the
15
15
  # messages you send it are too large, it can crash. If you don't return control
16
16
  # to its event loop, it can crash. It doesn't save references to all event handlers,
@@ -51,26 +51,6 @@ class Scarpe
51
51
  # A reference to the control_interface that manages internal Scarpe Webview events.
52
52
  attr_reader :control_interface
53
53
 
54
- # This error indicates a problem when running ConfirmedEval
55
- class JSEvalError < Scarpe::Error
56
- def initialize(data)
57
- @data = data
58
- super(data[:msg] || (self.class.name + "!"))
59
- end
60
- end
61
-
62
- # An error running the supplied JS code string in confirmed_eval
63
- class JSRuntimeError < JSEvalError
64
- end
65
-
66
- # The code timed out for some reason
67
- class JSTimeoutError < JSEvalError
68
- end
69
-
70
- # We got weird or nonsensical results that seem like an error on WebWrangler's part
71
- class InternalError < JSEvalError
72
- end
73
-
74
54
  # This is the JS function name for eval results (internal-only)
75
55
  EVAL_RESULT = "scarpeAsyncEvalResult"
76
56
 
@@ -85,7 +65,7 @@ class Scarpe
85
65
  # @param resizable [Boolean] whether the window should be resizable by the user
86
66
  # @param heartbeat [Float] time between heartbeats in seconds
87
67
  def initialize(title:, width:, height:, resizable: false, heartbeat: 0.1)
88
- log_init("WV::WebWrangler")
68
+ log_init("Webview::WebWrangler")
89
69
 
90
70
  @log.debug("Creating WebWrangler...")
91
71
 
@@ -149,7 +129,7 @@ class Scarpe
149
129
  # @param name [String] the Javascript name for the new function
150
130
  # @yield The Ruby block to be invoked when JS calls the function
151
131
  def bind(name, &block)
152
- raise "App is running, javascript binding no longer works because it uses WebView init!" if @is_running
132
+ raise Scarpe::JSBindingError, "App is running, javascript binding no longer works because it uses WebView init!" if @is_running
153
133
 
154
134
  @webview.bind(name, &block)
155
135
  end
@@ -160,7 +140,7 @@ class Scarpe
160
140
  # @param name [String] the Javascript name for the init function
161
141
  # @yield The Ruby block to be invoked when Webview runs
162
142
  def init_code(name, &block)
163
- raise "App is running, javascript init no longer works!" if @is_running
143
+ raise Scarpe::JSInitError, "App is running, javascript init no longer works!" if @is_running
164
144
 
165
145
  # Save a reference to the init string so that it doesn't get GC'd
166
146
  code_str = "#{name}();"
@@ -176,6 +156,8 @@ class Scarpe
176
156
  # so it should be invoked when the WebWrangler is in setup mode,
177
157
  # before the Webview is running.
178
158
  #
159
+ # TODO: add a way to stop this loop and unsubscribe.
160
+ #
179
161
  # @param name [String] the name of the Javascript init function, if needed
180
162
  # @param interval [Float] the duration between invoking this block
181
163
  # @yield the Ruby block to invoke periodically
@@ -188,7 +170,7 @@ class Scarpe
188
170
  # new window. But will there ever be a new page/window? Can we just
189
171
  # use eval instead of init to set up a periodic handler and call it
190
172
  # good?
191
- raise "App is running, can't set up new periodic handlers with init!"
173
+ raise Scarpe::PeriodicHandlerSetupError, "App is running, can't set up new periodic handlers with init!"
192
174
  end
193
175
 
194
176
  js_interval = (interval.to_f * 1_000.0).to_i
@@ -214,7 +196,7 @@ class Scarpe
214
196
  # @param code [String] the Javascript code to attempt to execute
215
197
  # @return [void]
216
198
  def js_eventually(code)
217
- raise "WebWrangler isn't running, eval doesn't work!" unless @is_running
199
+ raise Scarpe::WebWranglerNotRunningError, "WebWrangler isn't running, eval doesn't work!" unless @is_running
218
200
 
219
201
  @log.warn "Deprecated: please do NOT use js_eventually, it's basically never what you want!" unless ENV["CI"]
220
202
 
@@ -242,10 +224,10 @@ class Scarpe
242
224
  #
243
225
  # @param code [String] the Javascript code to execute
244
226
  # @param timeout [Float] how long to allow before raising a timeout exception
245
- # @param wait_for [Array<Promise>] promises that must complete successfully before this JS is scheduled
227
+ # @param wait_for [Array<Scarpe::Promise>] promises that must complete successfully before this JS is scheduled
246
228
  def eval_js_async(code, timeout: EVAL_DEFAULT_TIMEOUT, wait_for: [])
247
229
  unless @is_running
248
- raise "WebWrangler isn't running, so evaluating JS won't work!"
230
+ raise Scarpe::WebWranglerNotRunningError, "WebWrangler isn't running, so evaluating JS won't work!"
249
231
  end
250
232
 
251
233
  this_eval_serial = @eval_counter
@@ -320,7 +302,7 @@ class Scarpe
320
302
  def receive_eval_result(r_type, id, val)
321
303
  entry = @pending_evals.delete(id)
322
304
  unless entry
323
- raise "Received an eval result for a nonexistent ID #{id.inspect}!"
305
+ raise Scarpe::NonexistentEvalResultError, "Received an eval result for a nonexistent ID #{id.inspect}!"
324
306
  end
325
307
 
326
308
  @log.debug("Got JS value: #{r_type} / #{id} / #{val.inspect}")
@@ -331,13 +313,13 @@ class Scarpe
331
313
  when "success"
332
314
  promise.fulfilled!(val)
333
315
  when "error"
334
- promise.rejected! JSRuntimeError.new(
316
+ promise.rejected! Scarpe::JSRuntimeError.new(
335
317
  msg: "JS runtime error: #{val.inspect}!",
336
318
  code: entry[:code],
337
319
  ret_value: val,
338
320
  )
339
321
  else
340
- promise.rejected! InternalError.new(
322
+ promise.rejected! Scarpe::JSInternalError.new(
341
323
  msg: "JS eval internal error! r_type: #{r_type.inspect}",
342
324
  code: entry[:code],
343
325
  ret_value: val,
@@ -373,13 +355,15 @@ class Scarpe
373
355
  timed_out_ids.each do |id|
374
356
  @log.error "Timing out JS eval! #{@pending_evals[id][:code]}"
375
357
  entry = @pending_evals.delete(id)
376
- err = JSTimeoutError.new(msg: "JS timeout error!", code: entry[:code], ret_value: nil)
358
+ err = Scarpe::JSTimeoutError.new(msg: "JS timeout error!", code: entry[:code], ret_value: nil)
377
359
  entry[:promise].rejected!(err)
378
360
  end
379
361
  end
380
362
 
381
363
  public
382
364
 
365
+ attr_writer :empty_page
366
+
383
367
  # After setup, we call run to go to "running" mode.
384
368
  # No more setup callbacks should be called, only running callbacks.
385
369
  def run
@@ -387,14 +371,18 @@ class Scarpe
387
371
 
388
372
  # From webview:
389
373
  # 0 - Width and height are default size
390
- # 1 - Width and height are minimum bonds
391
- # 2 - Width and height are maximum bonds
374
+ # 1 - Width and height are minimum bounds
375
+ # 2 - Width and height are maximum bounds
392
376
  # 3 - Window size can not be changed by a user
393
377
  hint = @resizable ? 0 : 3
394
378
 
395
379
  @webview.set_title(@title)
396
380
  @webview.set_size(@width, @height, hint)
397
- @webview.navigate("data:text/html, #{empty}")
381
+ unless @empty_page
382
+ raise Scarpe::EmptyPageNotSetError, "No empty page markup was set!"
383
+ end
384
+
385
+ @webview.navigate("data:text/html, #{CGI.escape @empty_page}")
398
386
 
399
387
  monkey_patch_console(@webview)
400
388
 
@@ -440,29 +428,7 @@ class Scarpe
440
428
  end
441
429
 
442
430
  def empty
443
- html = <<~HTML
444
- <html>
445
- <head id='head-wvroot'>
446
- <style id='style-wvroot'>
447
- /** Style resets **/
448
- body {
449
- font-family: arial, Helvetica, sans-serif;
450
- margin: 0;
451
- height: 100%;
452
- overflow: hidden;
453
- }
454
- p {
455
- margin: 0;
456
- }
457
- </style>
458
- </head>
459
- <body id='body-wvroot'>
460
- <div id='wrapper-wvroot'></div>
461
- </body>
462
- </html>
463
- HTML
464
-
465
- CGI.escape(html)
431
+ Scarpe::Components::Calzini.empty_page_element
466
432
  end
467
433
 
468
434
  public
@@ -535,325 +501,329 @@ class Scarpe
535
501
  end
536
502
  end
537
503
 
538
- class Scarpe
539
- class WebWrangler
540
- # Leaving DOM changes as "meh, async, we'll see when it happens" is terrible for testing.
541
- # Instead, we need to track whether particular changes have committed yet or not.
542
- # So we add a single gateway for all DOM changes, and we make sure its work is done
543
- # before we consider a redraw complete.
544
- #
545
- # DOMWrangler batches up changes into fewer RPC calls. It's fine to have a redraw
546
- # "in flight" and have changes waiting to catch the next bus. But we don't want more
547
- # than one in flight, since it seems like having too many pending RPC requests can
548
- # crash Webview. So we allow one redraw scheduled and one redraw promise waiting,
549
- # at maximum.
550
- #
551
- # A WebWrangler will create and wrap a DOMWrangler, serving as the interface
552
- # for all DOM operations.
553
- #
554
- # A batch of DOMWrangler changes may be removed if a full update is scheduled. That
555
- # update is considered to replace the previous incremental changes. Any changes that
556
- # need to execute even if a full update happens should be scheduled through
557
- # WebWrangler#eval_js_async, not DOMWrangler.
558
- class DOMWrangler
559
- include Shoes::Log
560
-
561
- # Changes that have not yet been executed
562
- attr_reader :waiting_changes
504
+ class Scarpe::Webview::WebWrangler
505
+ # Leaving DOM changes as "meh, async, we'll see when it happens" is terrible for testing.
506
+ # Instead, we need to track whether particular changes have committed yet or not.
507
+ # So we add a single gateway for all DOM changes, and we make sure its work is done
508
+ # before we consider a redraw complete.
509
+ #
510
+ # DOMWrangler batches up changes into fewer RPC calls. It's fine to have a redraw
511
+ # "in flight" and have changes waiting to catch the next bus. But we don't want more
512
+ # than one in flight, since it seems like having too many pending RPC requests can
513
+ # crash Webview. So we allow one redraw scheduled and one redraw promise waiting,
514
+ # at maximum.
515
+ #
516
+ # A WebWrangler will create and wrap a DOMWrangler, serving as the interface
517
+ # for all DOM operations.
518
+ #
519
+ # A batch of DOMWrangler changes may be removed if a full update is scheduled. That
520
+ # update is considered to replace the previous incremental changes. Any changes that
521
+ # need to execute even if a full update happens should be scheduled through
522
+ # WebWrangler#eval_js_async, not DOMWrangler.
523
+ class DOMWrangler
524
+ include Shoes::Log
563
525
 
564
- # A Scarpe::Promise for JS that has been scheduled to execute but is not yet verified complete
565
- attr_reader :pending_redraw_promise
526
+ # Changes that have not yet been executed
527
+ attr_reader :waiting_changes
528
+
529
+ # A Scarpe::Promise for JS that has been scheduled to execute but is not yet verified complete
530
+ attr_reader :pending_redraw_promise
531
+
532
+ # A Scarpe::Promise for waiting changes - it will be fulfilled when all waiting changes
533
+ # have been verified complete, or when a full redraw that removed them has been
534
+ # verified complete. If many small changes are scheduled, the same promise will be
535
+ # returned for many of them.
536
+ attr_reader :waiting_redraw_promise
537
+
538
+ # Create a DOMWrangler that is paired with a WebWrangler. The WebWrangler is
539
+ # treated as an underlying abstraction for reliable JS evaluation.
540
+ def initialize(web_wrangler)
541
+ log_init("Webview::WebWrangler::DOMWrangler")
542
+
543
+ @wrangler = web_wrangler
544
+
545
+ @waiting_changes = []
546
+ @pending_redraw_promise = nil
547
+ @waiting_redraw_promise = nil
548
+
549
+ @fully_up_to_date_promise = nil
550
+
551
+ # Initially we're waiting for a full replacement to happen.
552
+ # It's possible to request updates/changes before we have
553
+ # a DOM in place and before Webview is running. If we do
554
+ # that, we should discard those updates.
555
+ @first_draw_requested = false
556
+
557
+ @redraw_handlers = []
558
+
559
+ # The "fully up to date" logic is complicated and not
560
+ # as well tested as I'd like. This makes it far less
561
+ # likely that the event simply won't fire.
562
+ # With more comprehensive testing, this should be
563
+ # removable.
564
+ web_wrangler.periodic_code("scarpeDOMWranglerHeartbeat") do
565
+ if @fully_up_to_date_promise && fully_updated?
566
+ @log.info("Fulfilling up-to-date promise on heartbeat")
567
+ @fully_up_to_date_promise.fulfilled!
568
+ @fully_up_to_date_promise = nil
569
+ end
570
+ end
571
+ end
566
572
 
567
- # A Scarpe::Promise for waiting changes - it will be fulfilled when all waiting changes
568
- # have been verified complete, or when a full redraw that removed them has been
569
- # verified complete. If many small changes are scheduled, the same promise will be
570
- # returned for many of them.
571
- attr_reader :waiting_redraw_promise
573
+ def request_change(js_code)
574
+ # No updates until there's something to update
575
+ return unless @first_draw_requested
572
576
 
573
- # Create a DOMWrangler that is paired with a WebWrangler. The WebWrangler is
574
- # treated as an underlying abstraction for reliable JS evaluation.
575
- def initialize(web_wrangler)
576
- log_init("WV::WebWrangler::DOMWrangler")
577
+ @waiting_changes << js_code
577
578
 
578
- @wrangler = web_wrangler
579
+ promise_redraw
580
+ end
579
581
 
580
- @waiting_changes = []
581
- @pending_redraw_promise = nil
582
- @waiting_redraw_promise = nil
583
-
584
- @fully_up_to_date_promise = nil
585
-
586
- # Initially we're waiting for a full replacement to happen.
587
- # It's possible to request updates/changes before we have
588
- # a DOM in place and before Webview is running. If we do
589
- # that, we should discard those updates.
590
- @first_draw_requested = false
591
-
592
- @redraw_handlers = []
593
-
594
- # The "fully up to date" logic is complicated and not
595
- # as well tested as I'd like. This makes it far less
596
- # likely that the event simply won't fire.
597
- # With more comprehensive testing, this should be
598
- # removable.
599
- web_wrangler.periodic_code("scarpeDOMWranglerHeartbeat") do
600
- if @fully_up_to_date_promise && fully_updated?
601
- @log.info("Fulfilling up-to-date promise on heartbeat")
602
- @fully_up_to_date_promise.fulfilled!
603
- @fully_up_to_date_promise = nil
604
- end
605
- end
606
- end
582
+ def self.replacement_code(html_text)
583
+ "document.getElementById('wrapper-wvroot').innerHTML = `#{html_text}`; true"
584
+ end
607
585
 
608
- def request_change(js_code)
609
- # No updates until there's something to update
610
- return unless @first_draw_requested
586
+ def request_replace(html_text)
587
+ # Replace other pending changes, they're not needed any more
588
+ @waiting_changes = [DOMWrangler.replacement_code(html_text)]
589
+ @first_draw_requested = true
611
590
 
612
- @waiting_changes << js_code
591
+ @log.debug("Requesting DOM replacement...")
592
+ promise_redraw
593
+ end
613
594
 
614
- promise_redraw
615
- end
595
+ def on_every_redraw(&block)
596
+ @redraw_handlers << block
597
+ end
616
598
 
617
- def self.replacement_code(html_text)
618
- "document.getElementById('wrapper-wvroot').innerHTML = `#{html_text}`; true"
599
+ # promise_redraw returns a Scarpe::Promise which will be fulfilled after all current
600
+ # pending or waiting changes have completed. This may require creating a new
601
+ # promise.
602
+ #
603
+ # What are the states of redraw?
604
+ # "empty" - no waiting promise, no pending-redraw promise, no pending changes
605
+ # "pending only" - no waiting promise, but we have a pending redraw with some changes; it hasn't committed yet
606
+ # "pending and waiting" - we have a waiting promise for our unscheduled changes; we can add more unscheduled
607
+ # changes since we haven't scheduled them yet.
608
+ #
609
+ # This is often called after adding a new waiting change or replacing them, so the state may have just changed.
610
+ # It can also be called when no changes have been made and no updates need to happen.
611
+ def promise_redraw
612
+ if fully_updated?
613
+ # No changes to make, nothing in-process or waiting, so just return a pre-fulfilled promise
614
+ @log.debug("Requesting redraw but there are no pending changes or promises, return pre-fulfilled")
615
+ return ::Scarpe::Promise.fulfilled
619
616
  end
620
617
 
621
- def request_replace(html_text)
622
- # Replace other pending changes, they're not needed any more
623
- @waiting_changes = [DOMWrangler.replacement_code(html_text)]
624
- @first_draw_requested = true
625
-
626
- @log.debug("Requesting DOM replacement...")
627
- promise_redraw
618
+ # Already have a redraw requested *and* one on deck? Then all current changes will have committed
619
+ # when we (eventually) fulfill the waiting_redraw_promise.
620
+ if @waiting_redraw_promise
621
+ @log.debug("Promising eventual redraw of #{@waiting_changes.size} waiting unscheduled changes.")
622
+ return @waiting_redraw_promise
628
623
  end
629
624
 
630
- def on_every_redraw(&block)
631
- @redraw_handlers << block
625
+ if @waiting_changes.empty?
626
+ # There's no waiting_redraw_promise. There are no waiting changes. But we're not fully updated.
627
+ # So there must be a redraw in flight, and we don't need to schedule a new waiting_redraw_promise.
628
+ @log.debug("Returning in-flight redraw promise")
629
+ return @pending_redraw_promise
632
630
  end
633
631
 
634
- # promise_redraw returns a Scarpe::Promise which will be fulfilled after all current
635
- # pending or waiting changes have completed. This may require creating a new
636
- # promise.
637
- #
638
- # What are the states of redraw?
639
- # "empty" - no waiting promise, no pending-redraw promise, no pending changes
640
- # "pending only" - no waiting promise, but we have a pending redraw with some changes; it hasn't committed yet
641
- # "pending and waiting" - we have a waiting promise for our unscheduled changes; we can add more unscheduled
642
- # changes since we haven't scheduled them yet.
643
- #
644
- # This is often called after adding a new waiting change or replacing them, so the state may have just changed.
645
- # It can also be called when no changes have been made and no updates need to happen.
646
- def promise_redraw
647
- if fully_updated?
648
- # No changes to make, nothing in-process or waiting, so just return a pre-fulfilled promise
649
- @log.debug("Requesting redraw but there are no pending changes or promises, return pre-fulfilled")
650
- return Promise.fulfilled
651
- end
632
+ @log.debug("Requesting redraw with #{@waiting_changes.size} waiting changes and no waiting promise - need to schedule something!")
652
633
 
653
- # Already have a redraw requested *and* one on deck? Then all current changes will have committed
654
- # when we (eventually) fulfill the waiting_redraw_promise.
655
- if @waiting_redraw_promise
656
- @log.debug("Promising eventual redraw of #{@waiting_changes.size} waiting unscheduled changes.")
657
- return @waiting_redraw_promise
658
- end
634
+ # We have at least one waiting change, possibly newly-added. We have no waiting_redraw_promise.
635
+ # Do we already have a redraw in-flight?
636
+ if @pending_redraw_promise
637
+ # Yes we do. Schedule a new waiting promise. When it turns into the pending_redraw_promise it will
638
+ # grab all waiting changes. In the mean time, it sits here and waits.
639
+ #
640
+ # We *could* do a fancy promise thing and have it update @waiting_changes for itself, etc, when it
641
+ # schedules itself. But we should always be calling promise_redraw or having a redraw fulfilled (see below)
642
+ # when these things change. I'd rather keep the logic in this method. It's easier to reason through
643
+ # all the cases.
644
+ @waiting_redraw_promise = ::Scarpe::Promise.new
659
645
 
660
- if @waiting_changes.empty?
661
- # There's no waiting_redraw_promise. There are no waiting changes. But we're not fully updated.
662
- # So there must be a redraw in flight, and we don't need to schedule a new waiting_redraw_promise.
663
- @log.debug("Returning in-flight redraw promise")
664
- return @pending_redraw_promise
665
- end
666
-
667
- @log.debug("Requesting redraw with #{@waiting_changes.size} waiting changes and no waiting promise - need to schedule something!")
668
-
669
- # We have at least one waiting change, possibly newly-added. We have no waiting_redraw_promise.
670
- # Do we already have a redraw in-flight?
671
- if @pending_redraw_promise
672
- # Yes we do. Schedule a new waiting promise. When it turns into the pending_redraw_promise it will
673
- # grab all waiting changes. In the mean time, it sits here and waits.
674
- #
675
- # We *could* do a fancy promise thing and have it update @waiting_changes for itself, etc, when it
676
- # schedules itself. But we should always be calling promise_redraw or having a redraw fulfilled (see below)
677
- # when these things change. I'd rather keep the logic in this method. It's easier to reason through
678
- # all the cases.
679
- @waiting_redraw_promise = Promise.new
680
-
681
- @log.debug("Creating a new waiting promise since a pending promise is already in place")
682
- return @waiting_redraw_promise
683
- end
646
+ @log.debug("Creating a new waiting promise since a pending promise is already in place")
647
+ return @waiting_redraw_promise
648
+ end
684
649
 
685
- # We have no redraw in-flight and no pre-existing waiting line. The new change(s) are presumably right
686
- # after things were fully up-to-date. We can schedule them for immediate redraw.
650
+ # We have no redraw in-flight and no pre-existing waiting line. The new change(s) are presumably right
651
+ # after things were fully up-to-date. We can schedule them for immediate redraw.
687
652
 
688
- @log.debug("Requesting redraw with #{@waiting_changes.size} waiting changes - scheduling a new redraw for them!")
689
- promise = schedule_waiting_changes # This clears the waiting changes
690
- @pending_redraw_promise = promise
653
+ @log.debug("Requesting redraw with #{@waiting_changes.size} waiting changes - scheduling a new redraw for them!")
654
+ promise = schedule_waiting_changes # This clears the waiting changes
655
+ @pending_redraw_promise = promise
691
656
 
692
- promise.on_fulfilled do
693
- @redraw_handlers.each(&:call)
694
- @pending_redraw_promise = nil
657
+ promise.on_fulfilled do
658
+ @redraw_handlers.each(&:call)
659
+ @pending_redraw_promise = nil
695
660
 
696
- if @waiting_redraw_promise
697
- # While this redraw was in flight, more waiting changes got added and we made a promise
698
- # about when they'd complete. Now they get scheduled, and we'll fulfill the waiting
699
- # promise when that redraw finishes. Clear the old waiting promise. We'll add a new one
700
- # when/if more changes are scheduled during this redraw.
701
- old_waiting_promise = @waiting_redraw_promise
702
- @waiting_redraw_promise = nil
661
+ if @waiting_redraw_promise
662
+ # While this redraw was in flight, more waiting changes got added and we made a promise
663
+ # about when they'd complete. Now they get scheduled, and we'll fulfill the waiting
664
+ # promise when that redraw finishes. Clear the old waiting promise. We'll add a new one
665
+ # when/if more changes are scheduled during this redraw.
666
+ old_waiting_promise = @waiting_redraw_promise
667
+ @waiting_redraw_promise = nil
703
668
 
704
- @log.debug "Fulfilled redraw with #{@waiting_changes.size} waiting changes - scheduling a new redraw for them!"
669
+ @log.debug "Fulfilled redraw with #{@waiting_changes.size} waiting changes - scheduling a new redraw for them!"
705
670
 
706
- new_promise = promise_redraw
707
- new_promise.on_fulfilled { old_waiting_promise.fulfilled! }
708
- else
709
- # The in-flight redraw completed, and there's still no waiting promise. Good! That means
710
- # we should be fully up-to-date.
711
- @log.debug "Fulfilled redraw with no waiting changes - marking us as up to date!"
712
- if @waiting_changes.empty?
713
- # We're fully up to date! Fulfill the promise. Now we don't need it again until somebody asks
714
- # us for another.
715
- if @fully_up_to_date_promise
716
- @fully_up_to_date_promise.fulfilled!
717
- @fully_up_to_date_promise = nil
718
- end
719
- else
720
- @log.error "WHOAH, WHAT? My logic must be wrong, because there's " +
721
- "no waiting promise, but waiting changes!"
671
+ new_promise = promise_redraw
672
+ new_promise.on_fulfilled { old_waiting_promise.fulfilled! }
673
+ else
674
+ # The in-flight redraw completed, and there's still no waiting promise. Good! That means
675
+ # we should be fully up-to-date.
676
+ @log.debug "Fulfilled redraw with no waiting changes - marking us as up to date!"
677
+ if @waiting_changes.empty?
678
+ # We're fully up to date! Fulfill the promise. Now we don't need it again until somebody asks
679
+ # us for another.
680
+ if @fully_up_to_date_promise
681
+ @fully_up_to_date_promise.fulfilled!
682
+ @fully_up_to_date_promise = nil
722
683
  end
684
+ else
685
+ @log.error "WHOAH, WHAT? My logic must be wrong, because there's " +
686
+ "no waiting promise, but waiting changes!"
723
687
  end
688
+ end
724
689
 
725
- @log.debug("Redraw is now fully up-to-date") if fully_updated?
726
- end.on_rejected do
727
- @log.error "Could not complete JS redraw! #{promise.reason.full_message}"
728
- @log.debug("REDRAW FULLY UP TO DATE BUT JS FAILED") if fully_updated?
729
-
730
- raise "JS Redraw failed! Bailing!"
690
+ @log.debug("Redraw is now fully up-to-date") if fully_updated?
691
+ end.on_rejected do
692
+ @log.error "Could not complete JS redraw! #{promise.reason.full_message}"
693
+ @log.debug("REDRAW FULLY UP TO DATE BUT JS FAILED") if fully_updated?
731
694
 
732
- # Later we should figure out how to handle this. Clear the promises and queues and request another redraw?
733
- end
734
- end
695
+ raise Scarpe::JSRedrawError, "JS Redraw failed! Bailing!"
735
696
 
736
- def fully_updated?
737
- @pending_redraw_promise.nil? && @waiting_redraw_promise.nil? && @waiting_changes.empty?
697
+ # Later we should figure out how to handle this. Clear the promises and queues and request another redraw?
738
698
  end
699
+ end
739
700
 
740
- # Return a promise which will be fulfilled when the DOM is fully up-to-date
741
- def promise_fully_updated
742
- if fully_updated?
743
- # No changes to make, nothing in-process or waiting, so just return a pre-fulfilled promise
744
- return Promise.fulfilled
745
- end
701
+ def fully_updated?
702
+ @pending_redraw_promise.nil? && @waiting_redraw_promise.nil? && @waiting_changes.empty?
703
+ end
746
704
 
747
- # Do we already have a promise for this? Return it. Everybody can share one.
748
- if @fully_up_to_date_promise
749
- return @fully_up_to_date_promise
750
- end
705
+ # Return a promise which will be fulfilled when the DOM is fully up-to-date
706
+ def promise_fully_updated
707
+ if fully_updated?
708
+ # No changes to make, nothing in-process or waiting, so just return a pre-fulfilled promise
709
+ return ::Scarpe::Promise.fulfilled
710
+ end
751
711
 
752
- # We're not fully updated, so we need a promise. Create it, return it.
753
- @fully_up_to_date_promise = Promise.new
712
+ # Do we already have a promise for this? Return it. Everybody can share one.
713
+ if @fully_up_to_date_promise
714
+ return @fully_up_to_date_promise
754
715
  end
755
716
 
756
- private
717
+ # We're not fully updated, so we need a promise. Create it, return it.
718
+ @fully_up_to_date_promise = ::Scarpe::Promise.new
719
+ end
757
720
 
758
- # Put together the waiting changes into a new in-flight redraw request.
759
- # Return it as a promise.
760
- def schedule_waiting_changes
761
- return if @waiting_changes.empty?
721
+ private
762
722
 
763
- js_code = @waiting_changes.join(";")
764
- @waiting_changes = [] # They're not waiting any more!
765
- @wrangler.eval_js_async(js_code)
766
- end
723
+ # Put together the waiting changes into a new in-flight redraw request.
724
+ # Return it as a promise.
725
+ def schedule_waiting_changes
726
+ return if @waiting_changes.empty?
727
+
728
+ js_code = @waiting_changes.join(";")
729
+ @waiting_changes = [] # They're not waiting any more!
730
+ @wrangler.eval_js_async(js_code)
767
731
  end
768
732
  end
769
- end
770
733
 
771
- class Scarpe
772
- class WebWrangler
773
- # An ElementWrangler provides a way for a Widget to manipulate is DOM element(s)
774
- # via their HTML IDs. The most straightforward Widgets can have a single HTML ID
775
- # and use a single ElementWrangler to make any needed changes.
734
+ # An ElementWrangler provides a way for a Drawable to manipulate is DOM element(s)
735
+ # via their HTML IDs. The most straightforward Drawables can have a single HTML ID
736
+ # and use a single ElementWrangler to make any needed changes.
737
+ #
738
+ # For now we don't need an ElementWrangler to add DOM elements, just to manipulate them
739
+ # after initial render. New DOM objects for Drawables are normally added via full
740
+ # redraws rather than incremental updates.
741
+ #
742
+ # Any changes made via ElementWrangler may be cancelled if a full redraw occurs,
743
+ # since it is assumed that small DOM manipulations are no longer needed. If a
744
+ # change would need to be made even if a full redraw occurred, it should be
745
+ # scheduled via WebWrangler#eval_js_async, not via an ElementWrangler.
746
+ class ElementWrangler
747
+ attr_reader :html_id
748
+
749
+ # Create an ElementWrangler for the given HTML ID
776
750
  #
777
- # For now we don't need an ElementWrangler to add DOM elements, just to manipulate them
778
- # after initial render. New DOM objects for Widgets are normally added via full
779
- # redraws rather than incremental updates.
751
+ # @param html_id [String] the HTML ID for the DOM element
752
+ def initialize(html_id)
753
+ @webwrangler = ::Scarpe::Webview::DisplayService.instance.wrangler
754
+ raise Scarpe::MissingWranglerError, "Can't get WebWrangler!" unless @webwrangler
755
+
756
+ @html_id = html_id
757
+ end
758
+
759
+ # Return a promise that will be fulfilled when all changes scheduled via
760
+ # this ElementWrangler are verified complete.
780
761
  #
781
- # Any changes made via ElementWrangler may be cancelled if a full redraw occurs,
782
- # since it is assumed that small DOM manipulations are no longer needed. If a
783
- # change would need to be made even if a full redraw occurred, it should be
784
- # scheduled via WebWrangler#eval_js_async, not via an ElementWrangler.
785
- class ElementWrangler
786
- attr_reader :html_id
787
-
788
- # Create an ElementWrangler for the given HTML ID
789
- #
790
- # @param html_id [String] the HTML ID for the DOM element
791
- def initialize(html_id)
792
- @webwrangler = WebviewDisplayService.instance.wrangler
793
- @html_id = html_id
794
- end
762
+ # @return [Scarpe::Promise] a promise that will be fulfilled when scheduled changes are complete
763
+ def promise_update
764
+ @webwrangler.dom_promise_redraw
765
+ end
795
766
 
796
- # Return a promise that will be fulfilled when all changes scheduled via
797
- # this ElementWrangler are verified complete.
798
- #
799
- # @return [Scarpe::Promise] a promise that will be fulfilled when scheduled changes are complete
800
- def promise_update
801
- @webwrangler.dom_promise_redraw
802
- end
767
+ # Update the JS DOM element's value. The given Ruby value will be converted to string and assigned in backquotes.
768
+ #
769
+ # @param new_value [String] the new value
770
+ # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
771
+ def value=(new_value)
772
+ @webwrangler.dom_change("document.getElementById('" + html_id + "').value = `" + new_value + "`; true")
773
+ end
803
774
 
804
- # Update the JS DOM element's value. The given Ruby value will be converted to string and assigned in backquotes.
805
- #
806
- # @param new_value [String] the new value
807
- # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
808
- def value=(new_value)
809
- @webwrangler.dom_change("document.getElementById('" + html_id + "').value = `" + new_value + "`; true")
810
- end
775
+ # Update the JS DOM element's inner_text. The given Ruby value will be converted to string and assigned in single-quotes.
776
+ #
777
+ # @param new_text [String] the new inner_text
778
+ # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
779
+ def inner_text=(new_text)
780
+ @webwrangler.dom_change("document.getElementById('" + html_id + "').innerText = '" + new_text + "'; true")
781
+ end
811
782
 
812
- # Update the JS DOM element's inner_text. The given Ruby value will be converted to string and assigned in single-quotes.
813
- #
814
- # @param new_text [String] the new inner_text
815
- # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
816
- def inner_text=(new_text)
817
- @webwrangler.dom_change("document.getElementById('" + html_id + "').innerText = '" + new_text + "'; true")
818
- end
783
+ # Update the JS DOM element's inner_html. The given Ruby value will be converted to string and assigned in backquotes.
784
+ #
785
+ # @param new_html [String] the new inner_html
786
+ # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
787
+ def inner_html=(new_html)
788
+ @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").innerHTML = `" + new_html + "`; true")
789
+ end
819
790
 
820
- # Update the JS DOM element's inner_html. The given Ruby value will be converted to string and assigned in backquotes.
821
- #
822
- # @param new_html [String] the new inner_html
823
- # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
824
- def inner_html=(new_html)
825
- @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").innerHTML = `" + new_html + "`; true")
826
- end
791
+ # Update the JS DOM element's outer_html. The given Ruby value will be converted to string and assigned in backquotes.
792
+ #
793
+ # @param new_html [String] the new outer_html
794
+ # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
795
+ def outer_html=(new_html)
796
+ @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").outerHTML = `" + new_html + "`; true")
797
+ end
827
798
 
828
- # Update the JS DOM element's inner_html. The given Ruby value will be inspected and assigned.
829
- #
830
- # @param attribute [String] the attribute name
831
- # @param value [String] the new attribute value
832
- # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
833
- def set_attribute(attribute, value)
834
- @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").setAttribute(" + attribute.inspect + "," + value.inspect + "); true")
835
- end
799
+ # Update the JS DOM element's attribute. The given Ruby value will be inspected and assigned.
800
+ #
801
+ # @param attribute [String] the attribute name
802
+ # @param value [String] the new attribute value
803
+ # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
804
+ def set_attribute(attribute, value)
805
+ @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").setAttribute(" + attribute.inspect + "," + value.inspect + "); true")
806
+ end
836
807
 
837
- # Update an attribute of the JS DOM element's style. The given Ruby value will be inspected and assigned.
838
- #
839
- # @param style_attr [String] the style attribute name
840
- # @param value [String] the new style attribute value
841
- # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
842
- def set_style(style_attr, value)
843
- @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").style.#{style_attr} = " + value.inspect + "; true")
844
- end
808
+ # Update an attribute of the JS DOM element's style. The given Ruby value will be inspected and assigned.
809
+ #
810
+ # @param style_attr [String] the style attribute name
811
+ # @param value [String] the new style attribute value
812
+ # @return [Scarpe::Promise] a promise that will be fulfilled when the change is complete
813
+ def set_style(style_attr, value)
814
+ @webwrangler.dom_change("document.getElementById(\"" + html_id + "\").style.#{style_attr} = " + value.inspect + "; true")
815
+ end
845
816
 
846
- # Remove the specified DOM element
847
- #
848
- # @return [Scarpe::Promise] a promise that wil be fulfilled when the element is removed
849
- def remove
850
- @webwrangler.dom_change("document.getElementById('" + html_id + "').remove(); true")
851
- end
817
+ # Remove the specified DOM element
818
+ #
819
+ # @return [Scarpe::Promise] a promise that wil be fulfilled when the element is removed
820
+ def remove
821
+ @webwrangler.dom_change("document.getElementById('" + html_id + "').remove(); true")
822
+ end
852
823
 
853
- def toggle_input_button(mark)
854
- checked_value = mark ? "true" : "false"
855
- @webwrangler.dom_change("document.getElementById('#{html_id}').checked = #{checked_value};")
856
- end
824
+ def toggle_input_button(mark)
825
+ checked_value = mark ? "true" : "false"
826
+ @webwrangler.dom_change("document.getElementById('#{html_id}').checked = #{checked_value};")
857
827
  end
858
828
  end
859
829
  end