scarpe 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/CHANGELOG.md +36 -4
  4. data/Gemfile +2 -1
  5. data/Gemfile.lock +13 -3
  6. data/LICENSE.txt +7 -1
  7. data/README.md +77 -14
  8. data/Rakefile +67 -0
  9. data/examples/Edit_box_Styles.rb +8 -0
  10. data/examples/Kerning.rb +7 -0
  11. data/examples/border.rb +11 -0
  12. data/examples/check.rb +2 -0
  13. data/examples/download_and_show_image.rb +3 -0
  14. data/examples/flags/finland.rb +15 -0
  15. data/examples/flags/italy.rb +11 -0
  16. data/examples/flags/mauritius.rb +14 -0
  17. data/examples/font_family.rb +17 -0
  18. data/examples/font_shorthand.rb +9 -0
  19. data/examples/gen.rb +4 -0
  20. data/examples/legacy/not_checked/shoes-manual/append.rb +10 -0
  21. data/examples/legacy/not_checked/shoes-manual/background_change.rb +12 -0
  22. data/examples/legacy/not_checked/shoes-manual/background_pattern.rb +5 -0
  23. data/examples/legacy/not_checked/shoes-manual/basic_app.rb +8 -0
  24. data/examples/legacy/not_checked/shoes-manual/border.rb +9 -0
  25. data/examples/legacy/not_checked/shoes-manual/builtins/FONTS.rb +5 -0
  26. data/examples/legacy/not_checked/shoes-manual/builtins/ask.rb +2 -0
  27. data/examples/legacy/not_checked/shoes-manual/builtins/ask_color.rb +5 -0
  28. data/examples/legacy/not_checked/shoes-manual/builtins/ask_open_file.rb +5 -0
  29. data/examples/legacy/not_checked/shoes-manual/builtins/ask_save_folder.rb +2 -0
  30. data/examples/legacy/not_checked/shoes-manual/builtins/confirm.rb +4 -0
  31. data/examples/legacy/not_checked/shoes-manual/builtins/debug.rb +2 -0
  32. data/examples/legacy/not_checked/shoes-manual/builtins/info.rb +3 -0
  33. data/examples/legacy/not_checked/shoes-manual/button.rb +9 -0
  34. data/examples/legacy/not_checked/shoes-manual/clear.rb +7 -0
  35. data/examples/legacy/not_checked/shoes-manual/custom_header.rb +13 -0
  36. data/examples/legacy/not_checked/shoes-manual/displace.rb +14 -0
  37. data/examples/legacy/not_checked/shoes-manual/edit_box.rb +8 -0
  38. data/examples/legacy/not_checked/shoes-manual/fill_pattern.rb +5 -0
  39. data/examples/legacy/not_checked/shoes-manual/fonts.rb +7 -0
  40. data/examples/legacy/not_checked/shoes-manual/gutter.rb +6 -0
  41. data/examples/legacy/not_checked/shoes-manual/image_web.rb +4 -0
  42. data/examples/legacy/not_checked/shoes-manual/keypress.rb +7 -0
  43. data/examples/legacy/not_checked/shoes-manual/list_box.rb +10 -0
  44. data/examples/legacy/not_checked/shoes-manual/motion.rb +10 -0
  45. data/examples/legacy/not_checked/shoes-manual/mouse.rb +8 -0
  46. data/examples/legacy/not_checked/shoes-manual/move.rb +14 -0
  47. data/examples/legacy/not_checked/shoes-manual/nested_ovals.rb +8 -0
  48. data/examples/legacy/not_checked/shoes-manual/oval.rb +7 -0
  49. data/examples/legacy/not_checked/shoes-manual/ovals.rb +6 -0
  50. data/examples/legacy/not_checked/shoes-manual/ovals_image.rb +8 -0
  51. data/examples/legacy/not_checked/shoes-manual/prepend.rb +7 -0
  52. data/examples/legacy/not_checked/shoes-manual/progress_bar.rb +10 -0
  53. data/examples/legacy/not_checked/shoes-manual/radio.rb +18 -0
  54. data/examples/legacy/not_checked/shoes-manual/radio_alternative_1.rb +7 -0
  55. data/examples/legacy/not_checked/shoes-manual/radio_alternative_2.rb +9 -0
  56. data/examples/legacy/not_checked/shoes-manual/rotate_rectangle.rb +6 -0
  57. data/examples/legacy/not_checked/shoes-manual/shape.rb +11 -0
  58. data/examples/legacy/not_checked/shoes-manual/static/avatar.png +0 -0
  59. data/examples/legacy/not_checked/shoes-manual/stroke.rb +5 -0
  60. data/examples/legacy/not_checked/shoes-manual/style.rb +3 -0
  61. data/examples/legacy/not_checked/shoes-manual/style_alternative_1.rb +4 -0
  62. data/examples/legacy/not_checked/shoes-manual/style_alternative_2.rb +5 -0
  63. data/examples/legacy/not_checked/shoes-manual/style_length.rb +5 -0
  64. data/examples/legacy/not_checked/shoes-manual/timer.rb +6 -0
  65. data/examples/legacy/not_checked/shoes-manual/trigger_window.rb +8 -0
  66. data/examples/legacy/not_checked/shoes-manual/window_owner.rb +8 -0
  67. data/examples/legacy/working/shoes_manual/alert_button.rb +2 -0
  68. data/examples/legacy/working/shoes_manual/animate.rb +7 -0
  69. data/examples/legacy/working/shoes_manual/background_para.rb +4 -0
  70. data/examples/legacy/working/shoes_manual/button_alternative.rb +7 -0
  71. data/examples/legacy/working/shoes_manual/checkbox.rb +17 -0
  72. data/examples/legacy/working/shoes_manual/download.rb +12 -0
  73. data/examples/legacy/working/shoes_manual/edit_box.rb +6 -0
  74. data/examples/legacy/working/shoes_manual/editline.rb +7 -0
  75. data/examples/legacy/working/shoes_manual/fixed_height.rb +8 -0
  76. data/examples/legacy/working/shoes_manual/fixed_width.rb +12 -0
  77. data/examples/legacy/working/shoes_manual/image.rb +5 -0
  78. data/examples/legacy/working/shoes_manual/instance_variable_check.rb +10 -0
  79. data/examples/legacy/working/shoes_manual/message.rb +18 -0
  80. data/examples/legacy/working/shoes_manual/rectangle.rb +6 -0
  81. data/examples/legacy/working/shoes_manual/save_download.rb +12 -0
  82. data/examples/legacy/working/shoes_manual/self_check.rb +10 -0
  83. data/examples/legacy/working/shoes_manual/stack.rb +7 -0
  84. data/examples/legacy/working/shoes_manual/style_info.rb +8 -0
  85. data/examples/legacy/working/shoes_manual/utf8_support.rb +8 -0
  86. data/examples/legacy/working/shoes_manual/width.rb +4 -0
  87. data/examples/local_assets/multi_image.rb +5 -0
  88. data/examples/local_assets/small.png +0 -0
  89. data/examples/local_fonts.rb +3 -0
  90. data/examples/margin.rb +13 -0
  91. data/examples/margin_check.rb +27 -0
  92. data/examples/oval-with-kwargs.rb +3 -0
  93. data/examples/oval.rb +26 -0
  94. data/examples/para_font_styles.rb +17 -0
  95. data/examples/para_font_variant.rb +6 -0
  96. data/examples/para_fontweight.rb +13 -0
  97. data/examples/parse_xl_funnies.rb +3 -0
  98. data/examples/rect.rb +1 -1
  99. data/examples/scarpe_ext.rb +3 -0
  100. data/examples/shapes/star.rb +1 -3
  101. data/examples/spacing.rb +1 -1
  102. data/examples/span.rb +4 -2
  103. data/lacci/lacci.gemspec +2 -2
  104. data/lacci/lib/lacci/scarpe_cli.rb +0 -1
  105. data/lacci/lib/lacci/version.rb +1 -1
  106. data/lacci/lib/scarpe/niente/display_service.rb +5 -1
  107. data/lacci/lib/scarpe/niente/drawable.rb +2 -0
  108. data/lacci/lib/scarpe/niente/shoes_spec.rb +7 -1
  109. data/lacci/lib/scarpe/niente.rb +14 -2
  110. data/lacci/lib/shoes/app.rb +44 -50
  111. data/lacci/lib/shoes/constants.rb +23 -2
  112. data/lacci/lib/shoes/display_service.rb +43 -4
  113. data/lacci/lib/shoes/drawable.rb +309 -35
  114. data/lacci/lib/shoes/drawables/arc.rb +2 -24
  115. data/lacci/lib/shoes/drawables/arrow.rb +2 -22
  116. data/lacci/lib/shoes/drawables/border.rb +28 -0
  117. data/lacci/lib/shoes/drawables/button.rb +4 -20
  118. data/lacci/lib/shoes/drawables/check.rb +7 -3
  119. data/lacci/lib/shoes/drawables/document_root.rb +4 -4
  120. data/lacci/lib/shoes/drawables/edit_box.rb +6 -5
  121. data/lacci/lib/shoes/drawables/edit_line.rb +5 -4
  122. data/lacci/lib/shoes/drawables/flow.rb +3 -5
  123. data/lacci/lib/shoes/drawables/font_helper.rb +62 -0
  124. data/lacci/lib/shoes/drawables/image.rb +2 -2
  125. data/lacci/lib/shoes/drawables/line.rb +4 -7
  126. data/lacci/lib/shoes/drawables/link.rb +5 -8
  127. data/lacci/lib/shoes/drawables/list_box.rb +8 -5
  128. data/lacci/lib/shoes/drawables/oval.rb +48 -0
  129. data/lacci/lib/shoes/drawables/para.rb +106 -18
  130. data/lacci/lib/shoes/drawables/progress.rb +2 -1
  131. data/lacci/lib/shoes/drawables/radio.rb +5 -3
  132. data/lacci/lib/shoes/drawables/rect.rb +5 -4
  133. data/lacci/lib/shoes/drawables/shape.rb +2 -1
  134. data/lacci/lib/shoes/drawables/slot.rb +99 -8
  135. data/lacci/lib/shoes/drawables/stack.rb +6 -11
  136. data/lacci/lib/shoes/drawables/star.rb +8 -30
  137. data/lacci/lib/shoes/drawables/text_drawable.rb +93 -34
  138. data/lacci/lib/shoes/drawables/video.rb +3 -2
  139. data/lacci/lib/shoes/drawables/widget.rb +8 -3
  140. data/lacci/lib/shoes/drawables.rb +2 -1
  141. data/lacci/lib/shoes/errors.rb +13 -3
  142. data/lacci/lib/shoes/margin_helper.rb +79 -0
  143. data/lacci/lib/shoes.rb +4 -3
  144. data/lacci/test/.gitignore +1 -0
  145. data/lacci/test/test_draw_context.rb +167 -0
  146. data/lacci/test/test_font_helper.rb +57 -0
  147. data/lacci/test/test_helper.rb +31 -4
  148. data/lacci/test/test_lacci.rb +93 -6
  149. data/lacci/test/test_margin_helper.rb +82 -0
  150. data/lacci/test/test_niente_test_infra.rb +26 -0
  151. data/lacci/test/test_oval.rb +82 -0
  152. data/lacci/test/test_parenting.rb +140 -0
  153. data/lacci/test/test_text_drawables.rb +23 -0
  154. data/lib/scarpe/assets.rb +18 -0
  155. data/lib/scarpe/cats_cradle.rb +57 -98
  156. data/lib/scarpe/shoes_spec.rb +22 -43
  157. data/lib/scarpe/version.rb +1 -1
  158. data/lib/scarpe/wv/app.rb +1 -0
  159. data/lib/scarpe/wv/arc.rb +0 -4
  160. data/lib/scarpe/wv/border.rb +15 -0
  161. data/lib/scarpe/wv/control_interface.rb +2 -10
  162. data/lib/scarpe/wv/document_root.rb +2 -2
  163. data/lib/scarpe/wv/drawable.rb +6 -40
  164. data/lib/scarpe/wv/edit_box.rb +4 -1
  165. data/lib/scarpe/wv/edit_line.rb +5 -2
  166. data/lib/scarpe/wv/image.rb +2 -5
  167. data/lib/scarpe/wv/link.rb +4 -2
  168. data/lib/scarpe/wv/oval.rb +13 -0
  169. data/lib/scarpe/wv/para.rb +1 -0
  170. data/lib/scarpe/wv/scarpe_extensions.rb +8 -0
  171. data/lib/scarpe/wv/shape.rb +10 -5
  172. data/lib/scarpe/wv/text_drawable.rb +72 -14
  173. data/lib/scarpe/wv/web_wrangler.rb +33 -11
  174. data/lib/scarpe/wv/webview_local_display.rb +6 -2
  175. data/lib/scarpe/wv.rb +8 -1
  176. data/scarpe-components/Gemfile +4 -1
  177. data/scarpe-components/Gemfile.lock +2 -3
  178. data/scarpe-components/README.md +2 -2
  179. data/scarpe-components/assets/bootstrap-themes/bootstrap-cerulean.css +12229 -0
  180. data/scarpe-components/assets/bootstrap-themes/bootstrap-cosmo.css +11810 -0
  181. data/scarpe-components/assets/bootstrap-themes/bootstrap-cyborg.css +12210 -0
  182. data/scarpe-components/assets/bootstrap-themes/bootstrap-darkly.css +12153 -0
  183. data/scarpe-components/assets/bootstrap-themes/bootstrap-flatly.css +12126 -0
  184. data/scarpe-components/assets/bootstrap-themes/bootstrap-icons.min.css +5 -0
  185. data/scarpe-components/assets/bootstrap-themes/bootstrap-journal.css +12099 -0
  186. data/scarpe-components/assets/bootstrap-themes/bootstrap-litera.css +12211 -0
  187. data/scarpe-components/assets/bootstrap-themes/bootstrap-lumen.css +12369 -0
  188. data/scarpe-components/assets/bootstrap-themes/bootstrap-lux.css +11928 -0
  189. data/scarpe-components/assets/bootstrap-themes/bootstrap-materia.css +13184 -0
  190. data/scarpe-components/assets/bootstrap-themes/bootstrap-minty.css +12177 -0
  191. data/scarpe-components/assets/bootstrap-themes/bootstrap-morph.css +12750 -0
  192. data/scarpe-components/assets/bootstrap-themes/bootstrap-pulse.css +11890 -0
  193. data/scarpe-components/assets/bootstrap-themes/bootstrap-quartz.css +12622 -0
  194. data/scarpe-components/assets/bootstrap-themes/bootstrap-sandstone.css +12201 -0
  195. data/scarpe-components/assets/bootstrap-themes/bootstrap-simplex.css +12186 -0
  196. data/scarpe-components/assets/bootstrap-themes/bootstrap-sketchy.css +12451 -0
  197. data/scarpe-components/assets/bootstrap-themes/bootstrap-slate.css +12492 -0
  198. data/scarpe-components/assets/bootstrap-themes/bootstrap-solar.css +12149 -0
  199. data/scarpe-components/assets/bootstrap-themes/bootstrap-spacelab.css +12266 -0
  200. data/scarpe-components/assets/bootstrap-themes/bootstrap-superhero.css +12216 -0
  201. data/scarpe-components/assets/bootstrap-themes/bootstrap-united.css +12077 -0
  202. data/scarpe-components/assets/bootstrap-themes/bootstrap-vapor.css +12549 -0
  203. data/scarpe-components/assets/bootstrap-themes/bootstrap-yeti.css +12325 -0
  204. data/scarpe-components/assets/bootstrap-themes/bootstrap-zephyr.css +12283 -0
  205. data/scarpe-components/assets/bootstrap-themes/bootstrap.bundle.min.js +7 -0
  206. data/scarpe-components/lib/scarpe/components/asset_server.rb +219 -0
  207. data/scarpe-components/lib/scarpe/components/base64.rb +22 -0
  208. data/scarpe-components/lib/scarpe/components/calzini/{art_widgets.rb → art_drawables.rb} +42 -18
  209. data/scarpe-components/lib/scarpe/components/calzini/border.rb +38 -0
  210. data/scarpe-components/lib/scarpe/components/calzini/button.rb +6 -8
  211. data/scarpe-components/lib/scarpe/components/calzini/misc.rb +7 -17
  212. data/scarpe-components/lib/scarpe/components/calzini/para.rb +213 -11
  213. data/scarpe-components/lib/scarpe/components/calzini/slots.rb +14 -60
  214. data/scarpe-components/lib/scarpe/components/calzini.rb +88 -1
  215. data/scarpe-components/lib/scarpe/components/errors.rb +4 -0
  216. data/scarpe-components/lib/scarpe/components/html.rb +4 -1
  217. data/scarpe-components/lib/scarpe/components/minitest_export_reporter.rb +11 -3
  218. data/scarpe-components/lib/scarpe/components/minitest_result.rb +41 -0
  219. data/scarpe-components/lib/scarpe/components/print_logger.rb +17 -2
  220. data/scarpe-components/lib/scarpe/components/process_helpers.rb +37 -0
  221. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +1 -1
  222. data/scarpe-components/lib/scarpe/components/tiranti.rb +42 -100
  223. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +3 -1
  224. data/scarpe-components/lib/scarpe/components/version.rb +1 -1
  225. data/scarpe-components/test/assets/big-image.png +0 -0
  226. data/scarpe-components/test/assets/big-stylesheet.css +497 -0
  227. data/scarpe-components/test/assets/little-image.png +0 -0
  228. data/scarpe-components/test/assets/little-stylesheet.css +1 -0
  229. data/scarpe-components/test/calzini/test_calzini_art_drawables.rb +7 -7
  230. data/scarpe-components/test/calzini/test_calzini_button.rb +7 -5
  231. data/scarpe-components/test/calzini/test_calzini_misc.rb +9 -9
  232. data/scarpe-components/test/calzini/test_calzini_para.rb +6 -9
  233. data/scarpe-components/test/calzini/test_calzini_slots.rb +12 -57
  234. data/scarpe-components/test/calzini/test_calzini_text_drawables.rb +83 -18
  235. data/scarpe-components/test/calzini/test_various.rb +133 -0
  236. data/scarpe-components/test/test_asset_server.rb +72 -0
  237. data/scarpe-components/test/test_components.rb +31 -2
  238. data/scarpe-components/test/test_helper.rb +0 -1
  239. data/scarpe-components/test/test_minitest_result.rb +7 -0
  240. data/scarpe-components/test/test_segmented_app_files.rb +2 -0
  241. data/tasks/check_html_fixtures.rb +140 -0
  242. data/tasks/regenerate_html_fixtures.rb +104 -0
  243. data/templates/class_template_with_shapes.erb +0 -11
  244. metadata +180 -32
  245. data/lacci/lib/scarpe/niente/logger.rb +0 -29
  246. data/lacci/lib/shoes/drawables/span.rb +0 -27
  247. data/lacci/lib/shoes/spacing.rb +0 -9
  248. data/lib/scarpe/evented_assertions.rb +0 -121
  249. data/lib/scarpe/wv/span.rb +0 -44
  250. data/scarpe-components/lib/scarpe/components/calzini/text_widgets.rb +0 -65
  251. /data/examples/legacy/{not_checked → working}/shoes3-tests/editline/editline.rb +0 -0
@@ -16,20 +16,20 @@ module Scarpe::Components::Calzini
16
16
  oninput = handler_js_code("change", "this.value")
17
17
 
18
18
  HTML.render do |h|
19
- h.textarea(id: html_id, oninput: oninput, style: edit_box_style(props)) { props["text"] }
19
+ h.textarea(id: html_id, oninput: oninput,onmouseover: handler_js_code("hover"), style: edit_box_style(props),title: props["tooltip"]) { props["text"] }
20
20
  end
21
21
  end
22
22
 
23
23
  def edit_line_element(props)
24
24
  oninput = handler_js_code("change", "this.value")
25
-
25
+
26
26
  HTML.render do |h|
27
- h.input(id: html_id, oninput: oninput, value: props["text"], style: edit_line_style(props))
27
+ h.input(id: html_id, oninput: oninput, onmouseover: handler_js_code("hover"), value: props["text"], style: edit_line_style(props),title: props["tooltip"])
28
28
  end
29
29
  end
30
30
 
31
31
  def image_element(props)
32
- style = image_style(props)
32
+ style = drawable_style(props)
33
33
 
34
34
  if props["click"]
35
35
  HTML.render do |h|
@@ -111,26 +111,16 @@ module Scarpe::Components::Calzini
111
111
  drawable_style(props).merge({
112
112
  height: dimensions_length(props["height"]),
113
113
  width: dimensions_length(props["width"]),
114
+ font: props["font"]? parse_font(props) : nil
114
115
  }.compact)
115
116
  end
116
117
 
117
118
  def edit_line_style(props)
118
119
  styles = drawable_style(props)
119
120
 
121
+ styles[:font] = props["font"]? parse_font(props) : nil
120
122
  styles[:width] = dimensions_length(props["width"]) if props["width"]
121
-
122
- styles
123
- end
124
-
125
- def image_style(props)
126
- styles = drawable_style(props)
127
-
128
- styles[:width] = dimensions_length(props["width"]) if props["width"]
129
- styles[:height] = dimensions_length(props["height"]) if props["height"]
130
-
131
- styles[:top] = dimensions_length(props["top"]) if props["top"]
132
- styles[:left] = dimensions_length(props["left"]) if props["left"]
133
- styles[:position] = "absolute" if props["top"] || props["left"]
123
+ styles[:color] = rgb_to_hex(props["stroke"])
134
124
 
135
125
  styles
136
126
  end
@@ -1,27 +1,166 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Scarpe::Components::Calzini
4
- # para_element is a bit of a hard one, since it does not-entirely-trivial
5
- # mapping between display objects and IDs. But we don't want Calzini
6
- # messing with the display service or display objects.
7
4
  def para_element(props, &block)
5
+ # Align requires an extra wrapping div.
6
+
7
+ # Stacking strikethrough with underline requires multiple elements.
8
+ # We handle this by making strikethrough part of the main element,
9
+ # but using an extra wrapping element for underline.
10
+
11
+ tag = props["tag"] || "p"
12
+
13
+ para_styles, extra_styles = para_style(props)
14
+
8
15
  HTML.render do |h|
9
- h.p(**para_options(props), &block)
16
+ if extra_styles.empty?
17
+ h.send(tag, id: html_id, style: para_styles, &block)
18
+ else
19
+ h.div(id: html_id, style: extra_styles.merge(width: "100%")) do
20
+ h.send(tag, style: para_styles, &block)
21
+ end
22
+ end
10
23
  end
11
24
  end
12
25
 
13
26
  private
14
27
 
15
- def para_options(props)
16
- (props["html_attributes"] || {}).merge(id: html_id, style: para_style(props))
28
+ def para_style(props)
29
+
30
+ ds = drawable_style(props)
31
+ s1, s2 = text_specific_styles(props)
32
+ [ds.merge(s1), s2]
17
33
  end
18
34
 
19
- def para_style(props)
20
- drawable_style(props).merge({
21
- color: rgb_to_hex(props["stroke"]),
35
+ def text_specific_styles(props)
36
+ # Shoes3 allows align: right on TextDrawables like em(), but it does
37
+ # nothing. We can ignore it or (maybe in future?) warn if we see it.
38
+
39
+ strikethrough = props["strikethrough"]
40
+ strikethrough = nil if strikethrough == "" || strikethrough == "none"
41
+ s1 = {
42
+ "font-variant": props["font_variant"],
43
+ "color": rgb_to_hex(props["stroke"]),
44
+ "background-color": rgb_to_hex(props["fill"]),
22
45
  "font-size": para_font_size(props),
23
- "font-family": props["font"],
24
- }.compact)
46
+ "font-family": props["family"],
47
+ "text-decoration-line": strikethrough ? "line-through" : nil,
48
+ "text-decoration-color": props["strikecolor"] ? rgb_to_hex(props["strikecolor"]) : nil,
49
+ "font-weight": props["font_weight"]? props["font_weight"] : nil,
50
+ :'font-style' => case props["emphasis"]
51
+ when "normal"
52
+ "normal"
53
+ when "oblique"
54
+ "oblique"
55
+ when "italic"
56
+ "italic"
57
+ else
58
+ nil
59
+ end,
60
+ :'letter-spacing' => props["kerning"] ? "#{props["kerning"]}px" : nil,
61
+ :'vertical-align' => props["rise"] ? "#{props["rise"]}px" : nil
62
+ }.compact
63
+
64
+ s2 = {}
65
+ if props["align"] && props["align"] != ""
66
+ s2[:"text-align"] = props["align"]
67
+ end
68
+
69
+ unless [nil, "none"].include?(props["underline"])
70
+ undercolor = rgb_to_hex props["undercolor"]
71
+ s2["text-decoration-color"] = undercolor if undercolor
72
+ end
73
+
74
+ # [nil, "none", "single", "double", "low", "error"]
75
+ case props["underline"]
76
+ when nil, "none"
77
+ # Do nothing
78
+ when "single"
79
+ s2["text-decoration-line"] = "underline"
80
+ when "double"
81
+ s2["text-decoration-line"] = "underline"
82
+ s2["text-decoration-style"] = "double"
83
+ when "error"
84
+ s2["text-decoration-line"] = "underline"
85
+ s2["text-decoration-style"] = "wavy"
86
+ when "low"
87
+ s2["text-decoration-line"] = "underline"
88
+ s2["text-underline-offset"] = "0.3rem"
89
+ else
90
+ # This should normally be unreachable
91
+ raise Shoes::Errors::InvalidAttributeValueError, "Unexpected underline type #{props["underline"].inspect}!"
92
+ end
93
+
94
+ [s1, s2]
95
+ end
96
+
97
+
98
+ def parse_font(props)
99
+
100
+ def contains_number?(str)
101
+ !!(str =~ /\d/)
102
+ end
103
+ def contains_only_numbers?(string)
104
+ /^\d+\z/ =~ string
105
+ end
106
+
107
+
108
+ input = props["font"]
109
+ regex = /\s+(?=(?:[^']*'[^']*')*[^']*$)(?![^']*,[^']*')/
110
+ result = input.split(regex)
111
+
112
+ fs = "normal"
113
+ fv = "normal"
114
+ fw = "normal"
115
+ fss = "medium"
116
+ ff = "Arial"
117
+
118
+ fos = ["italic", "oblique"]
119
+ fov = ["small-caps", "initial", "inherit"]
120
+ fow = ["bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900"]
121
+ foss = ["xx-small", "x-small", "small","large", "x-large", "xx-large", "smaller", "larger"]
122
+
123
+ result.each do |i|
124
+ if fos.include?(i)
125
+ fs = i
126
+ next
127
+ elsif fov.include?(i)
128
+ fv = i
129
+ next
130
+ elsif fow.include?(i)
131
+ fw = i
132
+ next
133
+ elsif foss.include?(i)
134
+ fss = i
135
+ next
136
+ else
137
+ if contains_number?(i)
138
+
139
+ if contains_only_numbers?(i)
140
+ fss = i + "px"
141
+ else
142
+ fss = i
143
+ end
144
+
145
+ elsif i != "normal" && i != "medium" && i.strip != ""
146
+
147
+ if ff == "Arial"
148
+
149
+ ff = i
150
+
151
+ else
152
+
153
+ ff = ff+ i
154
+
155
+ end
156
+ end
157
+ end
158
+
159
+ end
160
+
161
+
162
+ "#{fs} #{fv} #{fw} #{fss} #{ff}"
163
+
25
164
  end
26
165
 
27
166
  def para_font_size(props)
@@ -32,4 +171,67 @@ module Scarpe::Components::Calzini
32
171
 
33
172
  dimensions_length(font_size)
34
173
  end
174
+
175
+ public
176
+
177
+ # The text element is used to render the equivalent of Shoes cText,
178
+ # which includes em, strong, span, link and so on. We use a
179
+ # "content" tag for it which alternates plaintext with a hash of
180
+ # properties.
181
+ def text_drawable_element(prop_array)
182
+ out = String.new # Need unfrozen string
183
+
184
+ # Each item should be a String or a property Hash
185
+ # :items, :html_id, :tag, :props
186
+ prop_array.each do |item|
187
+ if item.is_a?(String)
188
+ out << item.gsub("\n", "<br/>")
189
+ else
190
+ s, extra = text_drawable_style(item[:props])
191
+ out << HTML.render do |h|
192
+ if extra.empty?
193
+ h.send(
194
+ item[:tag] || "span",
195
+ class: "id_#{item[:html_id]}",
196
+ style: s,
197
+ **text_drawable_attrs(item[:props])
198
+ ) do
199
+ text_drawable_element(item[:items])
200
+ end
201
+ else
202
+ h.span(class: "id_#{item[:html_id]}", style: extra) do
203
+ h.send(
204
+ item[:tag] || "span",
205
+ class: "id_#{item[:html_id]}",
206
+ style: s,
207
+ **text_drawable_attrs(item[:props])
208
+ ) do
209
+ text_drawable_element(item[:items])
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ out
218
+ end
219
+
220
+ private
221
+
222
+ def text_drawable_attrs(props)
223
+ {
224
+ # These properties will normally only be set by link()
225
+ href: props["click"],
226
+ onclick: props["has_block"] ? handler_js_code("click") : nil,
227
+ }.compact
228
+ end
229
+
230
+ def text_drawable_style(props)
231
+ s, extra_s = text_specific_styles(props)
232
+
233
+ # Add hover styles, perhaps with CSS pseudo-class
234
+
235
+ [drawable_style(props).merge(s), extra_s]
236
+ end
35
237
  end
@@ -3,27 +3,30 @@
3
3
  module Scarpe::Components::Calzini
4
4
  def slot_element(props, &block)
5
5
  HTML.render do |h|
6
- h.div((props["html_attributes"] || {}).merge(id: html_id, style: slot_style(props)), &block)
6
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: slot_style(props))) do
7
+ h.div(style: { height: "100%", width: "100%" }, &block)
8
+ end
7
9
  end
8
10
  end
9
11
 
10
12
  def flow_element(props, &block)
11
13
  HTML.render do |h|
12
- h.div((props["html_attributes"] || {}).merge(id: html_id, style: flow_style(props)), &block)
14
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: flow_style(props))) do
15
+ h.div(style: { height: "100%", width: "100%", position: "relative" }, &block)
16
+ end
13
17
  end
14
18
  end
15
19
 
16
20
  def stack_element(props, &block)
17
21
  HTML.render do |h|
18
- h.div((props["html_attributes"] || {}).merge(id: html_id, style: stack_style(props)), &block)
22
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: stack_style(props))) do
23
+ h.div(style: { height: "100%", width: "100%", position: "relative" }, &block)
24
+ end
19
25
  end
20
26
  end
21
27
 
22
28
  def documentroot_element(props, &block)
23
- HTML.render do |h|
24
- # DocumentRoot rendering intentionally uses flow styles.
25
- h.div((props["html_attributes"] || {}).merge(id: html_id, style: flow_style(props)), &block)
26
- end
29
+ flow_element(props, &block)
27
30
  end
28
31
 
29
32
  private
@@ -32,12 +35,14 @@ module Scarpe::Components::Calzini
32
35
  styles = drawable_style(props)
33
36
  styles = background_style(props, styles)
34
37
  styles = border_style(props, styles)
35
- styles = spacing_styles_for_attr("margin", props, styles)
36
- styles = spacing_styles_for_attr("padding", props, styles)
37
38
 
38
39
  styles[:width] = dimensions_length(props["width"]) if props["width"]
39
40
  styles[:height] = dimensions_length(props["height"]) if props["height"]
40
41
 
42
+ ## A new slot defines a new coordinate system, so absolutely-positioned children
43
+ ## are relative to it. But that's going to need a lot of testing and Shoes3 comparison.
44
+ #styles[:position] = "relative"
45
+
41
46
  styles
42
47
  end
43
48
 
@@ -101,55 +106,4 @@ module Scarpe::Components::Calzini
101
106
 
102
107
  styles.merge(background: color)
103
108
  end
104
-
105
- SPACING_DIRECTIONS = [:left, :right, :top, :bottom]
106
-
107
- # We extract the appropriate margin and padding from the margin and
108
- # padding properties. If there are no margin or padding properties,
109
- # we fall back to props["options"] margin or padding, if it exists.
110
- #
111
- # Margin or padding (in either props or props["options"]) can be
112
- # a Hash with directions as keys, or an Array of left/right/top/bottom,
113
- # or a constant, which means all four are that constant. You can
114
- # also specify a "margin" plus "margin-top" which is constant but
115
- # margin-top is overridden, or similar.
116
- #
117
- # If any margin or padding property exists in props then we don't
118
- # check props["options"].
119
- def spacing_styles_for_attr(attr, props, styles, with_options: true)
120
- spacing_styles = {}
121
-
122
- case props[attr]
123
- when Hash
124
- props[attr].each do |dir, value|
125
- spacing_styles[:"#{attr}-#{dir}"] = dimensions_length value
126
- end
127
- when Array
128
- SPACING_DIRECTIONS.zip(props[attr]).to_h.compact.each do |dir, value|
129
- spacing_styles[:"#{attr}-#{dir}"] = dimensions_length(value)
130
- end
131
- when String, Numeric
132
- spacing_styles[attr.to_sym] = dimensions_length(props[attr])
133
- end
134
-
135
- SPACING_DIRECTIONS.each do |dir|
136
- if props["#{attr}_#{dir}"]
137
- spacing_styles[:"#{attr}-#{dir}"] = dimensions_length props["#{attr}_#{dir}"]
138
- end
139
- end
140
-
141
- unless spacing_styles.empty?
142
- return styles.merge(spacing_styles)
143
- end
144
-
145
- # We should see if there are spacing properties in props["options"],
146
- # unless we're currently doing that.
147
- if with_options && props["options"]
148
- spacing_styles = spacing_styles_for_attr(attr, props["options"], {}, with_options: false)
149
- styles.merge spacing_styles
150
- else
151
- # No "options" or we already checked it? Return the styles we were given.
152
- styles
153
- end
154
- end
155
109
  end
@@ -68,6 +68,10 @@ module Scarpe::Components::Calzini
68
68
  p {
69
69
  margin: 0;
70
70
  }
71
+ #wrapper-wvroot {
72
+ height: 100%;
73
+ width: 100%;
74
+ }
71
75
  </style>
72
76
  </head>
73
77
  <body id='body-wvroot'>
@@ -110,13 +114,96 @@ module Scarpe::Components::Calzini
110
114
  if props["hidden"]
111
115
  styles[:display] = "none"
112
116
  end
117
+
118
+ # Do we need to set CSS positioning here, especially if displace is set? Position: relative maybe?
119
+ # We need some Shoes3 screenshots and HTML-based tests here...
120
+
121
+ if props["top"] || props["left"]
122
+ styles[:position] = "absolute"
123
+ end
124
+
125
+ styles[:top] = dimensions_length(props["top"]) if props["top"]
126
+ styles[:left] = dimensions_length(props["left"]) if props["left"]
127
+ styles[:width] = dimensions_length(props["width"]) if props["width"]
128
+ styles[:height] = dimensions_length(props["height"]) if props["height"]
129
+ styles[:"margin-left"] = dimensions_length(props["margin_left"]) if props["margin_left"]
130
+ styles[:"margin-right"] = dimensions_length(props["margin_right"]) if props["margin_right"]
131
+ styles[:"margin-top"] = dimensions_length(props["margin_top"]) if props["margin_top"]
132
+ styles[:"margin-bottom"] = dimensions_length(props["margin_bottom"]) if props["margin_bottom"]
133
+
134
+
135
+
136
+ styles = spacing_styles_for_attr("padding", props, styles)
137
+
113
138
  styles
114
139
  end
115
140
 
141
+ SPACING_DIRECTIONS = [:left, :right, :top, :bottom]
142
+
143
+ # We extract the appropriate margin and padding from the margin and
144
+ # padding properties. If there are no margin or padding properties,
145
+ # we fall back to props["options"] margin or padding, if it exists.
146
+ #
147
+ # Margin or padding (in either props or props["options"]) can be
148
+ # a Hash with directions as keys, or an Array of left/right/top/bottom,
149
+ # or a constant, which means all four are that constant. You can
150
+ # also specify a "margin" plus "margin-top" which is constant but
151
+ # margin-top is overridden, or similar.
152
+ #
153
+ # If any margin or padding property exists in props then we don't
154
+ # check props["options"].
155
+ def spacing_styles_for_attr(attr, props, styles, with_options: true)
156
+ spacing_styles = {}
157
+
158
+ case props[attr]
159
+ when Hash
160
+ props[attr].each do |dir, value|
161
+ spacing_styles[:"#{attr}-#{dir}"] = dimensions_length value
162
+ end
163
+ when Array
164
+ SPACING_DIRECTIONS.zip(props[attr]).to_h.compact.each do |dir, value|
165
+ spacing_styles[:"#{attr}-#{dir}"] = dimensions_length(value)
166
+ end
167
+ when String, Numeric
168
+ spacing_styles[attr.to_sym] = dimensions_length(props[attr])
169
+ end
170
+
171
+ SPACING_DIRECTIONS.each do |dir|
172
+ if props["#{attr}_#{dir}"]
173
+ spacing_styles[:"#{attr}-#{dir}"] = dimensions_length props["#{attr}_#{dir}"]
174
+ end
175
+ end
176
+
177
+ unless spacing_styles.empty?
178
+ return styles.merge(spacing_styles)
179
+ end
180
+
181
+ # We should see if there are spacing properties in props["options"],
182
+ # unless we're currently doing that.
183
+ if with_options && props["options"]
184
+ spacing_styles = spacing_styles_for_attr(attr, props["options"], {}, with_options: false)
185
+ styles.merge spacing_styles
186
+ else
187
+ # No "options" or we already checked it? Return the styles we were given.
188
+ styles
189
+ end
190
+ end
191
+
192
+ def first_color_of(*colors)
193
+ colors.compact!
194
+ colors.select! { |c| c != "" }
195
+ rgb_to_hex(colors[0])
196
+ end
197
+
116
198
  # Convert an [r, g, b, a] array to an HTML hex color code
117
199
  # Arrays support alpha. HTML hex does not. So premultiply.
118
200
  def rgb_to_hex(color)
119
- return color if color.nil?
201
+ return nil if color.nil?
202
+ return "#000000" if color == ""
203
+
204
+ # TODO: need to figure out if it's a color name like "aquamarine"
205
+ # or a hex code or an image file to use as a pattern or what.
206
+ return color if color.is_a?(String)
120
207
 
121
208
  r, g, b, a = *color
122
209
  if r.is_a?(Float)
@@ -3,9 +3,13 @@
3
3
  # Also defined in scarpe_core
4
4
  class Scarpe::Error < StandardError; end
5
5
 
6
+ # TODO: this should be under Scarpe::Errors, and also probably merged into the normal
7
+ # Scarpe errors file.
6
8
  module Scarpe
7
9
  class InternalError < Scarpe::Error; end
8
10
 
11
+ class OperationNotAllowedError < Scarpe::Error; end
12
+
9
13
  class FileContentError < Scarpe::Error; end
10
14
 
11
15
  class NoOperationError < Scarpe::Error; end
@@ -20,6 +20,9 @@ class Scarpe::Components::HTML
20
20
  :u,
21
21
  :line,
22
22
  :span,
23
+ :sub,
24
+ :sup,
25
+ :del,
23
26
  :svg,
24
27
  :h1,
25
28
  :h2,
@@ -27,7 +30,7 @@ class Scarpe::Components::HTML
27
30
  :h4,
28
31
  :h5,
29
32
  ].freeze
30
- VOID_TAGS = [:input, :img, :polygon, :source, :link, :path, :rect].freeze
33
+ VOID_TAGS = [:input, :img, :polygon, :source, :link, :path, :rect, :ellipse].freeze
31
34
 
32
35
  TAGS = (CONTENT_TAGS + VOID_TAGS).freeze
33
36
 
@@ -24,11 +24,18 @@ module Minitest
24
24
  # the reporter will be automatically overridden and print to console instead.
25
25
  #
26
26
  # Based on https://gist.github.com/davidwessman/09a13840a8a80080e3842ac3051714c7
27
- class ShoesExportReporter < DefaultReporter
27
+ class ShoesExportReporter < BaseReporter
28
+ class << self
29
+ attr_accessor :metadata
30
+ attr_accessor :export_file
31
+ end
32
+
28
33
  def self.activate!
29
34
  unless ENV["SHOES_MINITEST_EXPORT_FILE"]
30
35
  raise "ShoesExportReporter is available, but no export file was specified! Set SHOES_MINITEST_EXPORT_FILE!"
31
36
  end
37
+ ShoesExportReporter.export_file = File.expand_path(ENV["SHOES_MINITEST_EXPORT_FILE"])
38
+ ShoesExportReporter.metadata ||= {}
32
39
 
33
40
  Minitest::Reporters.use!
34
41
  end
@@ -58,6 +65,7 @@ module Minitest
58
65
  failures: failures,
59
66
  time: result.time,
60
67
  metadata: result.respond_to?(:metadata) ? result.metadata : {},
68
+ exporter_metadata: ShoesExportReporter.metadata,
61
69
  source_location: begin
62
70
  result.source_location
63
71
  rescue
@@ -66,8 +74,8 @@ module Minitest
66
74
  }
67
75
  end
68
76
 
69
- out_file = File.expand_path ENV["SHOES_MINITEST_EXPORT_FILE"]
70
- puts "Writing Minitest results to #{out_file.inspect}."
77
+ out_file = ShoesExportReporter.export_file
78
+ #puts "Writing Minitest results to #{out_file.inspect}."
71
79
  File.write(out_file, JSON.dump(results))
72
80
  end
73
81
  end
@@ -56,6 +56,47 @@ class Scarpe::Components::MinitestResult
56
56
  end
57
57
  end
58
58
 
59
+ def one_word_result
60
+ return "error" if self.error?
61
+ return "fail" if self.fail?
62
+ return "skip" if self.skip?
63
+ "success"
64
+ end
65
+
66
+ def result_and_message
67
+ return ["error", error_message] if self.error?
68
+ return ["fail", fail_message] if self.fail?
69
+ return ["skip", skip_message] if self.skip?
70
+ ["success", "OK"]
71
+ end
72
+
73
+ def console_summary
74
+ return "Error(s): #{@exceptions.inspect}" if self.error?
75
+ return "Failure: #{@failures.inspect}" if self.fail?
76
+ return "Skip: #{skip_message.inspect}" if self.skip?
77
+ "Success!"
78
+ end
79
+
80
+ def check(expect_result: :success, min_asserts: nil, max_asserts: nil)
81
+ unless [:error, :fail, :skip, :success].include?(expect_result)
82
+ raise Scarpe::InternalError, "Expected test result should be one of [:success, :fail, :error, :skip]!"
83
+ end
84
+
85
+ res, msg = result_and_message
86
+ if expect_result.to_s != res
87
+ return [false, "Expected #{expect_result} but got #{res}: #{msg}!"]
88
+ end
89
+
90
+ if min_asserts && @assertions < min_asserts
91
+ return [false, "Expected success with at least #{min_asserts} assertions but found only #{@assertions}!"]
92
+ end
93
+ if max_asserts && @assertions > max_asserts
94
+ return [false, "Expected success with no more than #{max_asserts} assertions but found only #{@assertions}!"]
95
+ end
96
+
97
+ [true, ""]
98
+ end
99
+
59
100
  def error?
60
101
  !@exceptions.empty?
61
102
  end
@@ -11,26 +11,41 @@ class Scarpe::Components::PrintLogImpl
11
11
  class PrintLogger
12
12
  class << self
13
13
  attr_accessor :silence
14
+ attr_accessor :min_level
14
15
  end
15
16
 
17
+ LEVELS = {
18
+ :never => 1000,
19
+ :error => 4,
20
+ :warn => 3,
21
+ :info => 2,
22
+ :debug => 1,
23
+ :always => -1,
24
+ }
25
+ PrintLogger.min_level = LEVELS[:always]
26
+
16
27
  def initialize(component_name)
17
28
  @comp_name = component_name
18
29
  end
19
30
 
20
31
  def error(msg)
21
- puts "#{@comp_name} error: #{msg}" unless PrintLogger.silence
32
+ return if PrintLogger.silence || PrintLogger.min_level > LEVELS[:error]
33
+ puts "#{@comp_name} error: #{msg}"
22
34
  end
23
35
 
24
36
  def warn(msg)
37
+ return if PrintLogger.silence || PrintLogger.min_level > LEVELS[:warn]
25
38
  puts "#{@comp_name} warn: #{msg}" unless PrintLogger.silence
26
39
  end
27
40
 
28
41
  def debug(msg)
42
+ return if PrintLogger.silence || PrintLogger.min_level > LEVELS[:debug]
29
43
  puts "#{@comp_name} debug: #{msg}" unless PrintLogger.silence
30
44
  end
31
45
 
32
46
  def info(msg)
33
- puts "#{@comp_name} info: #{msg}" unless PrintLogger.silence
47
+ return if PrintLogger.silence || PrintLogger.min_level > LEVELS[:info]
48
+ puts "#{@comp_name} info: #{msg}"
34
49
  end
35
50
  end
36
51