scarpe 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/.yardopts +11 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +112 -0
  6. data/README.md +31 -24
  7. data/Rakefile +13 -1
  8. data/docs/yard/catscradle.md +44 -0
  9. data/docs/yard/template/default/fulldoc/html/setup.rb +13 -0
  10. data/docs/yard/template/default/layout/html/setup.rb +9 -0
  11. data/examples/background_with_image.rb +16 -0
  12. data/examples/bloopsaphone/working/bronx_army_knife.rb +66 -0
  13. data/examples/bloopsaphone/working/morning_serenity.rb +21 -0
  14. data/examples/bloopsaphone/working/simpsons_theme_song_by_why.rb +6 -4
  15. data/examples/button_go_away.rb +1 -1
  16. data/examples/check.rb +18 -0
  17. data/examples/clear_and_append.rb +24 -0
  18. data/examples/download_and_show_image.rb +28 -0
  19. data/examples/edit_box.rb +3 -5
  20. data/examples/fonts.rb +2 -2
  21. data/examples/get_headers.rb +10 -0
  22. data/examples/highlander.rb +2 -0
  23. data/examples/link.rb +2 -2
  24. data/examples/local_fonts.rb +4 -0
  25. data/examples/local_images.rb +4 -0
  26. data/examples/motion_events.rb +20 -0
  27. data/examples/parse_xl_funnies.rb +58 -0
  28. data/examples/radio/radio.rb +16 -0
  29. data/examples/radio/radio_groups.rb +18 -0
  30. data/examples/radio/radio_same_slot.rb +6 -0
  31. data/examples/ruby_racer.rb +13 -15
  32. data/examples/selfitude.rb +18 -0
  33. data/examples/shapes/shapes_fill.rb +4 -3
  34. data/examples/shoes_school.rb +2 -4
  35. data/examples/show_hide.rb +6 -0
  36. data/examples/skip_ci/change_my_audio_source.rb +21 -0
  37. data/examples/skip_ci/guitar_fretboard.rb +137 -0
  38. data/examples/video.rb +10 -0
  39. data/exe/scarpe +42 -66
  40. data/fonts/Pacifico.ttf +0 -0
  41. data/lacci/Gemfile +22 -0
  42. data/lacci/Gemfile.lock +72 -0
  43. data/lacci/Rakefile +12 -0
  44. data/lacci/lacci.gemspec +37 -0
  45. data/lacci/lib/lacci/scarpe_cli.rb +70 -0
  46. data/lacci/lib/lacci/scarpe_core.rb +21 -0
  47. data/lacci/lib/lacci/version.rb +13 -0
  48. data/lacci/lib/shoes/app.rb +264 -0
  49. data/{lib/scarpe → lacci/lib/shoes}/background.rb +1 -1
  50. data/{lib/scarpe → lacci/lib/shoes}/border.rb +1 -1
  51. data/{lib/scarpe → lacci/lib/shoes}/colors.rb +1 -1
  52. data/lacci/lib/shoes/constants.rb +29 -0
  53. data/{lib/scarpe → lacci/lib/shoes}/display_service.rb +40 -45
  54. data/lacci/lib/shoes/download.rb +123 -0
  55. data/lacci/lib/shoes/log.rb +71 -0
  56. data/lacci/lib/shoes/spacing.rb +9 -0
  57. data/{lib/scarpe → lacci/lib/shoes}/widget.rb +63 -43
  58. data/{lib/scarpe → lacci/lib/shoes/widgets}/alert.rb +3 -3
  59. data/{lib/scarpe → lacci/lib/shoes/widgets}/arc.rb +7 -5
  60. data/{lib/scarpe → lacci/lib/shoes/widgets}/button.rb +3 -3
  61. data/lacci/lib/shoes/widgets/check.rb +28 -0
  62. data/lacci/lib/shoes/widgets/document_root.rb +20 -0
  63. data/{lib/scarpe → lacci/lib/shoes/widgets}/edit_box.rb +10 -5
  64. data/{lib/scarpe → lacci/lib/shoes/widgets}/edit_line.rb +2 -2
  65. data/lacci/lib/shoes/widgets/flow.rb +22 -0
  66. data/lacci/lib/shoes/widgets/font.rb +14 -0
  67. data/{lib/scarpe → lacci/lib/shoes/widgets}/image.rb +3 -7
  68. data/lacci/lib/shoes/widgets/line.rb +18 -0
  69. data/{lib/scarpe → lacci/lib/shoes/widgets}/link.rb +2 -2
  70. data/{lib/scarpe → lacci/lib/shoes/widgets}/list_box.rb +2 -2
  71. data/{lib/scarpe → lacci/lib/shoes/widgets}/para.rb +4 -26
  72. data/lacci/lib/shoes/widgets/radio.rb +35 -0
  73. data/lacci/lib/shoes/widgets/shape.rb +37 -0
  74. data/lacci/lib/shoes/widgets/slot.rb +75 -0
  75. data/{lib/scarpe → lacci/lib/shoes/widgets}/span.rb +2 -2
  76. data/lacci/lib/shoes/widgets/stack.rb +24 -0
  77. data/{lib/scarpe → lacci/lib/shoes/widgets}/star.rb +6 -9
  78. data/lacci/lib/shoes/widgets/subscription_item.rb +60 -0
  79. data/lacci/lib/shoes/widgets/text_widget.rb +51 -0
  80. data/lacci/lib/shoes/widgets/video.rb +15 -0
  81. data/lacci/lib/shoes/widgets.rb +29 -0
  82. data/lacci/lib/shoes.rb +127 -0
  83. data/lacci/test/test_colors.rb +39 -0
  84. data/lacci/test/test_helper.rb +9 -0
  85. data/lacci/test/test_lacci.rb +9 -0
  86. data/lib/scarpe/cats_cradle.rb +249 -0
  87. data/lib/scarpe/evented_assertions.rb +88 -0
  88. data/lib/scarpe/version.rb +1 -1
  89. data/lib/scarpe/wv/alert.rb +3 -2
  90. data/lib/scarpe/wv/app.rb +30 -8
  91. data/lib/scarpe/wv/arc.rb +5 -6
  92. data/lib/scarpe/wv/background.rb +10 -1
  93. data/lib/scarpe/wv/border.rb +5 -3
  94. data/lib/scarpe/wv/button.rb +11 -9
  95. data/lib/scarpe/wv/check.rb +29 -0
  96. data/lib/scarpe/wv/control_interface.rb +14 -20
  97. data/lib/scarpe/wv/control_interface_test.rb +13 -28
  98. data/lib/scarpe/wv/document_root.rb +3 -45
  99. data/lib/scarpe/wv/edit_box.rb +5 -7
  100. data/lib/scarpe/wv/edit_line.rb +2 -2
  101. data/lib/scarpe/wv/flow.rb +10 -20
  102. data/lib/scarpe/wv/font.rb +36 -0
  103. data/lib/scarpe/wv/html.rb +3 -2
  104. data/lib/scarpe/wv/image.rb +7 -2
  105. data/lib/scarpe/wv/line.rb +4 -7
  106. data/lib/scarpe/wv/link.rb +1 -0
  107. data/lib/scarpe/wv/list_box.rb +3 -3
  108. data/lib/scarpe/wv/para.rb +16 -14
  109. data/lib/scarpe/wv/radio.rb +34 -0
  110. data/lib/scarpe/wv/shape.rb +44 -8
  111. data/lib/scarpe/wv/slot.rb +81 -0
  112. data/lib/scarpe/wv/spacing.rb +1 -1
  113. data/lib/scarpe/wv/span.rb +10 -8
  114. data/lib/scarpe/wv/stack.rb +10 -30
  115. data/lib/scarpe/wv/star.rb +11 -12
  116. data/lib/scarpe/wv/subscription_item.rb +50 -0
  117. data/lib/scarpe/wv/video.rb +34 -0
  118. data/lib/scarpe/wv/web_wrangler.rb +238 -58
  119. data/lib/scarpe/wv/webview_local_display.rb +27 -5
  120. data/lib/scarpe/wv/webview_relay_display.rb +18 -119
  121. data/lib/scarpe/wv/webview_relay_util.rb +143 -0
  122. data/lib/scarpe/wv/widget.rb +80 -11
  123. data/lib/scarpe/wv/wv_display_worker.rb +17 -4
  124. data/lib/scarpe/wv.rb +33 -4
  125. data/lib/scarpe/wv_local.rb +1 -1
  126. data/lib/scarpe/wv_relay.rb +1 -1
  127. data/lib/scarpe.rb +3 -32
  128. data/scarpe-components/.gitignore +1 -0
  129. data/scarpe-components/Gemfile +22 -0
  130. data/scarpe-components/README.md +35 -0
  131. data/scarpe-components/Rakefile +12 -0
  132. data/scarpe-components/lib/scarpe/components/base64.rb +29 -0
  133. data/scarpe-components/lib/scarpe/components/file_helpers.rb +65 -0
  134. data/scarpe-components/lib/scarpe/components/modular_logger.rb +113 -0
  135. data/scarpe-components/lib/scarpe/components/print_logger.rb +43 -0
  136. data/{lib/scarpe → scarpe-components/lib/scarpe/components}/promises.rb +102 -35
  137. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +170 -0
  138. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +217 -0
  139. data/scarpe-components/lib/scarpe/components/version.rb +7 -0
  140. data/scarpe-components/scarpe-components.gemspec +38 -0
  141. data/scarpe-components/test/test_components.rb +9 -0
  142. data/scarpe-components/test/test_helper.rb +23 -0
  143. data/scarpe-components/test/test_promises.rb +260 -0
  144. data/scarpe-components/test/test_segmented_app_files.rb +182 -0
  145. data/{lib/scarpe → spikes}/glibui/widget.rb +2 -2
  146. data/{lib/scarpe → spikes}/glibui.rb +1 -1
  147. data/templates/basic_class_template.erb +1 -1
  148. data/templates/class_template_with_event_bind.erb +1 -1
  149. data/templates/class_template_with_shapes.erb +1 -1
  150. data/templates/webview_template.erb +0 -3
  151. metadata +151 -118
  152. data/examples/fill.rb +0 -25
  153. data/examples/legacy/not_checked/shoes-contrib/basic/class-book.yaml +0 -387
  154. data/examples/legacy/not_checked/shoes-contrib/good/good-clock.rb +0 -51
  155. data/examples/legacy/not_checked/shoes-contrib/good/good-follow.rb +0 -26
  156. data/examples/legacy/not_checked/shoes-contrib/good/good-reminder.rb +0 -174
  157. data/examples/legacy/not_checked/shoes-contrib/good/good-vjot.rb +0 -56
  158. data/examples/legacy/not_checked/shoes-contrib/simple/simple-timer.rb +0 -13
  159. data/examples/legacy/not_checked/shoes-dep-samples/good-clock.rb +0 -51
  160. data/examples/legacy/not_checked/shoes-dep-samples/good-follow.rb +0 -26
  161. data/examples/legacy/not_checked/shoes-dep-samples/good-reminder.rb +0 -174
  162. data/examples/legacy/not_checked/shoes-dep-samples/good-vjot.rb +0 -56
  163. data/examples/legacy/not_checked/shoes-dep-samples/simple-accordion.rb +0 -75
  164. data/examples/legacy/not_checked/shoes-dep-samples/simple-anim-shapes.rb +0 -17
  165. data/examples/legacy/not_checked/shoes-dep-samples/simple-anim-text.rb +0 -13
  166. data/examples/legacy/not_checked/shoes-dep-samples/simple-arc.rb +0 -23
  167. data/examples/legacy/not_checked/shoes-dep-samples/simple-bounce.rb +0 -24
  168. data/examples/legacy/not_checked/shoes-dep-samples/simple-calc.rb +0 -70
  169. data/examples/legacy/not_checked/shoes-dep-samples/simple-chipmunk.rb +0 -26
  170. data/examples/legacy/not_checked/shoes-dep-samples/simple-control-sizes.rb +0 -24
  171. data/examples/legacy/not_checked/shoes-dep-samples/simple-curve.rb +0 -26
  172. data/examples/legacy/not_checked/shoes-dep-samples/simple-dialogs.rb +0 -29
  173. data/examples/legacy/not_checked/shoes-dep-samples/simple-draw.rb +0 -13
  174. data/examples/legacy/not_checked/shoes-dep-samples/simple-editor.rb +0 -28
  175. data/examples/legacy/not_checked/shoes-dep-samples/simple-form.rb +0 -28
  176. data/examples/legacy/not_checked/shoes-dep-samples/simple-form.shy +0 -0
  177. data/examples/legacy/not_checked/shoes-dep-samples/simple-mask.rb +0 -21
  178. data/examples/legacy/not_checked/shoes-dep-samples/simple-menu.rb +0 -31
  179. data/examples/legacy/not_checked/shoes-dep-samples/simple-menu1.rb +0 -35
  180. data/examples/legacy/not_checked/shoes-dep-samples/simple-rubygems.rb +0 -29
  181. data/examples/legacy/not_checked/shoes-dep-samples/simple-slide.rb +0 -45
  182. data/examples/legacy/not_checked/shoes-dep-samples/simple-sphere.rb +0 -28
  183. data/examples/legacy/not_checked/shoes-dep-samples/simple-sqlite3.rb +0 -13
  184. data/examples/legacy/not_checked/shoes-dep-samples/simple-timer.rb +0 -13
  185. data/examples/legacy/not_checked/shoes-dep-samples/simple-video.rb +0 -13
  186. data/examples/legacy/not_checked/simple/anim-text.rb +0 -13
  187. data/examples/legacy/not_checked/simple/arc.rb +0 -23
  188. data/examples/legacy/not_checked/simple/bounce.rb +0 -24
  189. data/examples/legacy/not_checked/simple/chipmunk.rb +0 -26
  190. data/examples/legacy/not_checked/simple/curve.rb +0 -26
  191. data/examples/legacy/not_checked/simple/dialogs.rb +0 -29
  192. data/examples/legacy/not_checked/simple/downloader.rb +0 -40
  193. data/examples/legacy/not_checked/simple/draw.rb +0 -13
  194. data/examples/legacy/not_checked/simple/mask.rb +0 -21
  195. data/examples/legacy/not_checked/simple/slide.rb +0 -45
  196. data/examples/legacy/not_checked/simple/sphere.rb +0 -28
  197. data/lib/constants.rb +0 -5
  198. data/lib/scarpe/app.rb +0 -78
  199. data/lib/scarpe/document_root.rb +0 -20
  200. data/lib/scarpe/fill.rb +0 -23
  201. data/lib/scarpe/flow.rb +0 -19
  202. data/lib/scarpe/line.rb +0 -25
  203. data/lib/scarpe/logger.rb +0 -155
  204. data/lib/scarpe/shape.rb +0 -19
  205. data/lib/scarpe/spacing.rb +0 -9
  206. data/lib/scarpe/stack.rb +0 -70
  207. data/lib/scarpe/text_widget.rb +0 -42
  208. data/lib/scarpe/unit_test_helpers.rb +0 -163
  209. data/lib/scarpe/widgets.rb +0 -30
  210. data/lib/scarpe/wv/fill.rb +0 -30
  211. data/lib/scarpe/wv/shape_helper.rb +0 -44
  212. data/scarpe-0.2.0.gem +0 -0
  213. /data/{lib/scarpe → spikes}/glibui/README.md +0 -0
  214. /data/{lib/scarpe → spikes}/glibui/alert.rb +0 -0
  215. /data/{lib/scarpe → spikes}/glibui/app.rb +0 -0
  216. /data/{lib/scarpe → spikes}/glibui/background.rb +0 -0
  217. /data/{lib/scarpe → spikes}/glibui/border.rb +0 -0
  218. /data/{lib/scarpe → spikes}/glibui/button.rb +0 -0
  219. /data/{lib/scarpe → spikes}/glibui/dimensions.rb +0 -0
  220. /data/{lib/scarpe → spikes}/glibui/document_root.rb +0 -0
  221. /data/{lib/scarpe → spikes}/glibui/edit_box.rb +0 -0
  222. /data/{lib/scarpe → spikes}/glibui/edit_line.rb +0 -0
  223. /data/{lib/scarpe → spikes}/glibui/flow.rb +0 -0
  224. /data/{lib/scarpe → spikes}/glibui/html.rb +0 -0
  225. /data/{lib/scarpe → spikes}/glibui/image.rb +0 -0
  226. /data/{lib/scarpe → spikes}/glibui/link.rb +0 -0
  227. /data/{lib/scarpe → spikes}/glibui/local_display.rb +0 -0
  228. /data/{lib/scarpe → spikes}/glibui/para.rb +0 -0
  229. /data/{lib/scarpe → spikes}/glibui/spacing.rb +0 -0
  230. /data/{lib/scarpe → spikes}/glibui/stack.rb +0 -0
  231. /data/{lib/scarpe → spikes}/glibui/text_widget.rb +0 -0
  232. /data/{lib/scarpe → spikes}/libui/alert.rb +0 -0
  233. /data/{lib/scarpe → spikes}/libui/button.rb +0 -0
  234. /data/{lib/scarpe → spikes}/libui/colors.rb +0 -0
  235. /data/{lib/scarpe → spikes}/libui/core.rb +0 -0
  236. /data/{lib/scarpe → spikes}/libui/flow.rb +0 -0
  237. /data/{lib/scarpe → spikes}/libui/libui.rb +0 -0
  238. /data/{lib/scarpe → spikes}/libui/notepad.md +0 -0
  239. /data/{lib/scarpe → spikes}/libui/para.rb +0 -0
  240. /data/{lib/scarpe → spikes}/libui/stack.rb +0 -0
@@ -7,10 +7,16 @@
7
7
 
8
8
  require "json"
9
9
 
10
+ require "scarpe/components/unit_test_helpers"
11
+ require "scarpe/evented_assertions"
12
+
10
13
  class Scarpe
11
14
  DEFAULT_ASSERTION_TIMEOUT = 1.0
12
15
 
13
16
  class ControlInterface
17
+ include Scarpe::Test::EventedAssertions
18
+ include Scarpe::Test::Helpers
19
+
14
20
  def timed_out?
15
21
  @did_time_out
16
22
  end
@@ -44,32 +50,6 @@ class Scarpe
44
50
  data
45
51
  end
46
52
 
47
- # This does a final return of results. If it gets called
48
- # multiple times, the test fails because that's not okay.
49
- def return_results(result_bool, msg, data = {})
50
- result_file = ENV["SCARPE_TEST_RESULTS"] || "./scarpe_results.txt"
51
-
52
- result_structs = [result_bool, msg, data.merge(test_metadata)]
53
-
54
- # Multiple different sets of results is bad, even if both are passing.
55
- if @results_returned && @results_returned[0..1] != result_structs[0..1]
56
- # Just raising here doesn't reliably fail the test.
57
- # See: https://github.com/scarpe-team/scarpe/issues/212
58
- @log.error("Writing multi-result failure file to #{result_file.inspect}!")
59
-
60
- new_res_data = { first_result: @results_returned, second_result: result_structs }.merge(test_metadata)
61
- bad_result = [false, "Returned two sets of results!", new_res_data]
62
- File.write(result_file, JSON.pretty_generate(bad_result))
63
-
64
- return
65
- end
66
-
67
- @log.debug("Writing results file #{result_file.inspect} to disk!")
68
- File.write(result_file, JSON.pretty_generate(result_structs))
69
-
70
- @results_returned = result_structs
71
- end
72
-
73
53
  # Need to be able to query widgets in test code
74
54
 
75
55
  def all_wv_widgets
@@ -106,6 +86,11 @@ class Scarpe
106
86
  # We want an assertions library, but one that runs inside the spawned
107
87
  # Webview sub-process.
108
88
 
89
+ # Note that we do *not* extract this assertions library to use elsewhere
90
+ # because it's very focused on evented assertions that start and stop
91
+ # over a period of time. Instantaneous procedural asserts don't want to
92
+ # use this API.
93
+
109
94
  def return_when_assertions_done
110
95
  assertions_may_exist
111
96
 
@@ -218,8 +203,8 @@ class Scarpe
218
203
  end
219
204
  end
220
205
 
221
- # A Promise but with helper functions
222
- class TestPromise < Promise
206
+ # A {Scarpe::Promise} but with helper functions for Webview testing.
207
+ class TestPromise < Scarpe::Promise
223
208
  def initialize(iface:, state: nil, wait_for: [], &scheduler)
224
209
  @iface = iface
225
210
  super(state: state, parents: wait_for, &scheduler)
@@ -1,50 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Scarpe
4
- class WebviewDocumentRoot < Scarpe::WebviewWidget
5
- include Scarpe::WebviewBackground
6
-
7
- def initialize(properties)
8
- @callbacks = {}
9
-
10
- super
11
- end
12
-
13
- def element(&blck)
14
- HTML.render do |h|
15
- h.div(style: style.merge(height: "100%"), &blck)
16
- end
17
- end
18
-
19
- # Bind a Scarpe callback name; see Scarpe::Widget for how the naming is set up
20
- def bind(name, &block)
21
- @callbacks[name] = block
22
- end
23
-
24
- # All JS callbacks to Scarpe widgets are dispatched
25
- # via this handler, which is set up in Scarpe::App
26
- def handle_callback(name, *args)
27
- @callbacks[name].call(*args)
28
- end
29
-
30
- # The document root knows when a frame has finished. It registers end-of-frame callbacks and calls them
31
- # when requested. It also tracks when a redraw has been requested. Note that often frames will be
32
- # very rare if nothing is changing, with seconds or minutes passing in between them.
33
-
34
- def request_redraw!
35
- wrangler = WebviewDisplayService.instance.wrangler
36
- if wrangler.is_running
37
- wrangler.replace(self.to_html)
38
- end
39
- end
40
-
41
- # The document root manages the connection between widgets and the WebviewWrangler.
42
- # By centralising this and wrapping in API functions, we can keep from executing
43
- # random Javascript, mostly.
44
-
45
- # A Widget can request one or more of these as insertion points in the DOM
46
- def get_element_wrangler(html_id)
47
- Scarpe::WebWrangler::ElementWrangler.new(html_id)
48
- end
4
+ # A WebviewDocumentRoot is a WebviewFlow, with all the same properties
5
+ # and basic behavior.
6
+ class WebviewDocumentRoot < Scarpe::WebviewFlow
49
7
  end
50
8
  end
@@ -30,15 +30,13 @@ class Scarpe
30
30
  end
31
31
  end
32
32
 
33
- private
33
+ protected
34
34
 
35
35
  def style
36
- styles = {}
37
-
38
- styles[:height] = Dimensions.length(height)
39
- styles[:width] = Dimensions.length(width)
40
-
41
- styles.compact
36
+ super.merge({
37
+ height: Dimensions.length(height),
38
+ width: Dimensions.length(width),
39
+ }.compact)
42
40
  end
43
41
  end
44
42
  end
@@ -30,10 +30,10 @@ class Scarpe
30
30
  end
31
31
  end
32
32
 
33
- private
33
+ protected
34
34
 
35
35
  def style
36
- styles = {}
36
+ styles = super
37
37
 
38
38
  styles[:width] = Dimensions.length(@width) if @width
39
39
 
@@ -1,32 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Scarpe
4
- class WebviewFlow < Scarpe::WebviewWidget
5
- include Scarpe::WebviewBackground
6
- include Scarpe::WebviewBorder
7
-
4
+ class WebviewFlow < Scarpe::WebviewSlot
8
5
  def initialize(properties)
9
6
  super
10
7
  end
11
8
 
12
- def element(&block)
13
- HTML.render do |h|
14
- h.div(id: html_id, style:, &block)
15
- end
16
- end
17
-
18
- private
9
+ protected
19
10
 
20
11
  def style
21
- styles = super
22
-
23
- styles[:display] = "flex"
24
- styles["flex-direction"] = "row"
25
- styles["flex-wrap"] = "wrap"
26
- styles[:width] = Dimensions.length(@width) if @width
27
- styles[:height] = Dimensions.length(@height) if @height
28
-
29
- styles
12
+ {
13
+ display: "flex",
14
+ "flex-direction": "row",
15
+ "flex-wrap": "wrap",
16
+ "align-content": "flex-start",
17
+ "justify-content": "flex-start",
18
+ "align-items": "flex-start",
19
+ }.merge(super)
30
20
  end
31
21
  end
32
22
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "scarpe/components/base64"
4
+
5
+ class Scarpe
6
+ class WebviewFont < WebviewWidget
7
+ include Components::Base64
8
+ attr_accessor :font
9
+
10
+ def initialize(properties)
11
+ @font = properties[:font]
12
+ super
13
+ end
14
+
15
+ def font_name
16
+ File.basename(@font, ".*")
17
+ end
18
+
19
+ def element
20
+ HTML.render do |h|
21
+ h.link(href: @font, rel: "stylesheet")
22
+ h.style do
23
+ <<~CSS
24
+ @font-face {
25
+ font-family: #{font_name};
26
+ src: url("data:font/truetype;base64,#{encode_file_to_base64(@font)}") format('truetype');
27
+ }
28
+ * {
29
+ font-family: #{font_name};
30
+ }
31
+ CSS
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,8 +2,9 @@
2
2
 
3
3
  class Scarpe
4
4
  class HTML
5
- CONTENT_TAGS = [:div, :p, :button, :ul, :li, :textarea, :a, :strong, :em, :code, :u, :line, :span, :svg].freeze
6
- VOID_TAGS = [:input, :img, :polygon, :path].freeze
5
+ CONTENT_TAGS = [:div, :p, :button, :ul, :li, :textarea, :a, :video, :strong, :style, :em, :code, :u, :line, :span, :svg].freeze
6
+ VOID_TAGS = [:input, :img, :polygon, :source, :link, :path].freeze
7
+
7
8
  TAGS = (CONTENT_TAGS + VOID_TAGS).freeze
8
9
 
9
10
  class << self
@@ -1,9 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "scarpe/components/base64"
4
+
3
5
  class Scarpe
4
6
  class WebviewImage < WebviewWidget
7
+ include Components::Base64
5
8
  def initialize(properties)
6
9
  super
10
+
11
+ @url = valid_url?(@url) ? @url : "data:image/png;base64,#{encode_file_to_base64(@url)}"
7
12
  end
8
13
 
9
14
  def element
@@ -18,10 +23,10 @@ class Scarpe
18
23
  end
19
24
  end
20
25
 
21
- private
26
+ protected
22
27
 
23
28
  def style
24
- styles = {}
29
+ styles = super
25
30
 
26
31
  styles[:width] = Dimensions.length(@width) if @width
27
32
  styles[:height] = Dimensions.length(@height) if @height
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "shape_helper"
4
3
  class Scarpe
5
4
  class WebviewLine < Scarpe::WebviewWidget
6
- include ShapeHelper
7
-
8
5
  def initialize(properties)
9
6
  super(properties)
10
7
  end
@@ -19,18 +16,18 @@ class Scarpe
19
16
  end
20
17
  end
21
18
 
22
- private
19
+ protected
23
20
 
24
21
  def style
25
- {
22
+ super.merge({
26
23
  left: "#{@left}px",
27
24
  top: "#{@top}px",
28
- }
25
+ })
29
26
  end
30
27
 
31
28
  def line_style
32
29
  {
33
- stroke: " #{@color}",
30
+ stroke: @draw_context["stroke"],
34
31
  "stroke-width": "4",
35
32
  }
36
33
  end
@@ -23,6 +23,7 @@ class Scarpe
23
23
  id: html_id,
24
24
  href: @click,
25
25
  onclick: (handler_js_code("click") if @has_block),
26
+ style: style,
26
27
  }.compact
27
28
  end
28
29
  end
@@ -36,15 +36,15 @@ class Scarpe
36
36
  end
37
37
  end
38
38
 
39
- private
39
+ protected
40
40
 
41
41
  def style
42
- styles = {}
42
+ styles = super
43
43
 
44
44
  styles[:height] = Dimensions.length(height) if height
45
45
  styles[:width] = Dimensions.length(width) if width
46
46
 
47
- styles.compact
47
+ styles
48
48
  end
49
49
  end
50
50
  end
@@ -57,6 +57,22 @@ class Scarpe
57
57
  element { child_markup }
58
58
  end
59
59
 
60
+ protected
61
+
62
+ def style
63
+ super.merge({
64
+ color: rgb_to_hex(@stroke),
65
+ "font-size": font_size,
66
+ "font-family": @font,
67
+ }.compact)
68
+ end
69
+
70
+ def font_size
71
+ font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
72
+
73
+ Dimensions.length(font_size)
74
+ end
75
+
60
76
  private
61
77
 
62
78
  def child_markup
@@ -72,19 +88,5 @@ class Scarpe
72
88
  def options
73
89
  @html_attributes.merge(id: html_id, style: style)
74
90
  end
75
-
76
- def style
77
- {
78
- "color" => rgb_to_hex(@stroke),
79
- "font-size" => font_size,
80
- "font-family" => @font,
81
- }.compact
82
- end
83
-
84
- def font_size
85
- font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
86
-
87
- Dimensions.length(font_size)
88
- end
89
91
  end
90
92
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ class WebviewRadio < Scarpe::WebviewWidget
5
+ attr_reader :text
6
+
7
+ def initialize(properties)
8
+ super
9
+
10
+ bind("click") do
11
+ send_self_event(event_name: "click", target: shoes_linkable_id)
12
+ end
13
+ end
14
+
15
+ def properties_changed(changes)
16
+ items = changes.delete("checked")
17
+ html_element.toggle_input_button(items)
18
+
19
+ super
20
+ end
21
+
22
+ def element
23
+ HTML.render do |h|
24
+ h.input(type: :radio, id: html_id, onclick: handler_js_code("click"), name: group_name, value: "hmm #{text}", checked: @checked, style: style)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def group_name
31
+ @group || @parent
32
+ end
33
+ end
34
+ end
@@ -1,21 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "shape_helper"
4
-
5
3
  class Scarpe
4
+ # Should inherit from Slot?
6
5
  class WebviewShape < Scarpe::WebviewWidget
7
- include ShapeHelper
8
-
9
6
  def initialize(properties)
10
- @color = color_for_fill
11
7
  super(properties)
12
8
  end
13
9
 
10
+ def to_html
11
+ @children ||= []
12
+ child_markup = @children.map(&:to_html).join
13
+
14
+ color = @draw_context["fill"] || "black"
15
+ self_markup = HTML.render do |h|
16
+ h.div(id: html_id, style: style) do
17
+ h.svg(width: "400", height: "500") do
18
+ h.path(d: path_from_shape_commands, style: "fill:#{color};stroke-width:2;")
19
+ end
20
+ end
21
+ end
22
+
23
+ # Put child markup first for backward compatibility, but I'm pretty sure this is wrong.
24
+ child_markup + self_markup
25
+ end
26
+
14
27
  def element(&block)
28
+ color = @draw_context["fill"] || "black"
15
29
  HTML.render do |h|
16
30
  h.div(id: html_id, style: style) do
17
31
  h.svg(width: "400", height: "500") do
18
- h.path(d: shape_path, style: "fill:#{@color};stroke-width:2;")
32
+ h.path(d: path_from_shape_commands, style: "fill:#{color};stroke-width:2;")
19
33
  end
20
34
  block.call(h) if block_given?
21
35
  end
@@ -24,11 +38,33 @@ class Scarpe
24
38
 
25
39
  private
26
40
 
41
+ # We have a set of Shoes shape commands, but we need SVG objects like paths.
42
+ def path_from_shape_commands
43
+ current_path = ""
44
+
45
+ @shape_commands.each do |cmd, *args|
46
+ case cmd
47
+ when "move_to"
48
+ x, y = *args
49
+ current_path += "M #{x} #{y} "
50
+ when "line_to"
51
+ x, y = *args
52
+ current_path += "L #{x} #{y} "
53
+ else
54
+ raise "Unknown shape command! #{cmd.inspect}"
55
+ end
56
+ end
57
+
58
+ current_path
59
+ end
60
+
61
+ protected
62
+
27
63
  def style
28
- {
64
+ super.merge({
29
65
  width: "400",
30
66
  height: "900",
31
- }
67
+ })
32
68
  end
33
69
  end
34
70
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ class WebviewSlot < Scarpe::WebviewWidget
5
+ include Scarpe::WebviewBackground
6
+ include Scarpe::WebviewBorder
7
+ include Scarpe::WebviewSpacing
8
+
9
+ def initialize(properties)
10
+ @event_callbacks = {}
11
+
12
+ super
13
+ end
14
+
15
+ def element(&block)
16
+ HTML.render do |h|
17
+ h.div(attributes.merge(id: html_id, style: style), &block)
18
+ end
19
+ end
20
+
21
+ def set_event_callback(obj, event_name, js_code)
22
+ event_name = event_name.to_s
23
+ @event_callbacks[event_name] ||= {}
24
+ if @event_callbacks[event_name][obj]
25
+ raise "Can't have two callbacks on the same event, from the same object, on the same parent!"
26
+ end
27
+
28
+ @event_callbacks[event_name][obj] = js_code
29
+
30
+ update_dom_event(event_name)
31
+ end
32
+
33
+ def remove_event_callback(obj, event_name)
34
+ event_name = event_name.to_s
35
+ @event_callbacks[event_name] ||= {}
36
+ @event_callbacks[event_name].delete(obj)
37
+
38
+ update_dom_event(event_name)
39
+ end
40
+
41
+ def remove_event_callbacks(obj)
42
+ changed = []
43
+
44
+ @event_callbacks.each do |event_name, items|
45
+ changed << event_name if items.delete(obj)
46
+ end
47
+
48
+ changed.each { |event_name| update_dom_event(event_name) }
49
+ end
50
+
51
+ protected
52
+
53
+ def update_dom_event(event_name)
54
+ html_element.set_attribute(event_name, @event_callbacks[event_name].values.join(";"))
55
+ end
56
+
57
+ def attributes
58
+ attr = {}
59
+
60
+ @event_callbacks.each do |event_name, handlers|
61
+ attr[event_name] = handlers.values.join(";")
62
+ end
63
+
64
+ attr
65
+ end
66
+
67
+ def style
68
+ styles = super
69
+
70
+ styles[:"margin-top"] = @margin_top if @margin_top
71
+ styles[:"margin-bottom"] = @margin_bottom if @margin_bottom
72
+ styles[:"margin-left"] = @margin_left if @margin_left
73
+ styles[:"margin-right"] = @margin_right if @margin_right
74
+
75
+ styles[:width] = Dimensions.length(@width) if @width
76
+ styles[:height] = Dimensions.length(@height) if @height
77
+
78
+ styles
79
+ end
80
+ end
81
+ end
@@ -5,7 +5,7 @@ class Scarpe
5
5
  SPACING_DIRECTIONS = [:left, :right, :top, :bottom]
6
6
 
7
7
  def style
8
- styles = (super if defined?(super)) || {}
8
+ styles = defined?(super) ? super : {}
9
9
 
10
10
  extract_spacing_styles_for(:margin, styles, @margin)
11
11
  extract_spacing_styles_for(:padding, styles, @padding)
@@ -43,20 +43,22 @@ class Scarpe
43
43
  element { @text }
44
44
  end
45
45
 
46
- private
47
-
48
- def options
49
- @html_attributes.merge(id: html_id, style: style)
50
- end
46
+ protected
51
47
 
52
48
  def style
53
49
  {
54
- "color" => @stroke,
55
- "font-size" => font_size,
56
- "font-family" => @font,
50
+ color: @stroke,
51
+ "font-size": font_size,
52
+ "font-family": @font,
57
53
  }.compact
58
54
  end
59
55
 
56
+ private
57
+
58
+ def options
59
+ @html_attributes.merge(id: html_id, style: style)
60
+ end
61
+
60
62
  def font_size
61
63
  font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
62
64
 
@@ -1,42 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Scarpe
4
- class WebviewStack < Scarpe::WebviewWidget
5
- include Scarpe::WebviewBackground
6
- include Scarpe::WebviewBorder
7
- include Scarpe::WebviewSpacing
8
-
9
- def initialize(properties)
10
- super
11
- end
12
-
13
- def element(&block)
14
- HTML.render do |h|
15
- h.div(id: html_id, style: style, &block)
16
- end
17
- end
18
-
4
+ class WebviewStack < Scarpe::WebviewSlot
19
5
  def get_style
20
6
  style
21
7
  end
22
8
 
23
- private
9
+ protected
24
10
 
25
11
  def style
26
- styles = super
27
-
28
- styles["margin-top"] = @margin_top if @margin_top
29
- styles["margin-bottom"] = @margin_bottom if @margin_bottom
30
- styles["margin-left"] = @margin_left if @margin_left
31
- styles["margin-right"] = @margin_right if @margin_right
32
-
33
- styles[:display] = "flex"
34
- styles["flex-direction"] = "column"
35
- styles[:width] = Dimensions.length(@width) if @width
36
- styles[:height] = Dimensions.length(@height) if @height
37
- styles["overflow"] = "auto" if @scroll
38
-
39
- styles
12
+ {
13
+ display: "flex",
14
+ "flex-direction": "column",
15
+ "align-content": "flex-start",
16
+ "justify-content": "flex-start",
17
+ "align-items": "flex-start",
18
+ overflow: @scroll ? "auto" : nil,
19
+ }.compact.merge(super)
40
20
  end
41
21
  end
42
22
  end