opal-browser 0.2.0 → 0.3.3

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 (202) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +78 -0
  3. data/.gitignore +3 -0
  4. data/CHANGELOG.md +11 -0
  5. data/Gemfile +17 -3
  6. data/LICENSE +2 -1
  7. data/README.md +131 -54
  8. data/Rakefile +29 -1
  9. data/config.ru +20 -3
  10. data/docs/polyfills.md +24 -0
  11. data/examples/2048/Gemfile +6 -0
  12. data/examples/2048/README.md +13 -0
  13. data/examples/2048/app/application.rb +169 -0
  14. data/examples/2048/config.ru +9 -0
  15. data/examples/canvas/Gemfile +6 -0
  16. data/examples/canvas/README.md +9 -0
  17. data/examples/canvas/app/application.rb +55 -0
  18. data/examples/canvas/config.ru +9 -0
  19. data/examples/component/Gemfile +6 -0
  20. data/examples/component/README.md +10 -0
  21. data/examples/component/app/application.rb +66 -0
  22. data/examples/component/config.ru +9 -0
  23. data/examples/integrations/README.md +24 -0
  24. data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +6 -0
  25. data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
  26. data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
  27. data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
  28. data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
  29. data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +7 -0
  30. data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
  31. data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
  32. data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
  33. data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
  34. data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
  35. data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
  36. data/examples/integrations/dynamic-roda-tilt/Gemfile +8 -0
  37. data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
  38. data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
  39. data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
  40. data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
  41. data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
  42. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +7 -0
  43. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
  44. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
  45. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
  46. data/examples/integrations/static-bash/.gitignore +2 -0
  47. data/examples/integrations/static-bash/Gemfile +3 -0
  48. data/examples/integrations/static-bash/README.md +8 -0
  49. data/examples/integrations/static-bash/app/application.rb +6 -0
  50. data/examples/integrations/static-bash/build.sh +4 -0
  51. data/examples/integrations/static-bash/index.html +10 -0
  52. data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
  53. data/examples/integrations/static-bash-opal-parser/Gemfile +3 -0
  54. data/examples/integrations/static-bash-opal-parser/README.md +10 -0
  55. data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
  56. data/examples/integrations/static-bash-opal-parser/index.html +19 -0
  57. data/examples/integrations/static-rake/.gitignore +1 -0
  58. data/examples/integrations/static-rake/Gemfile +4 -0
  59. data/examples/integrations/static-rake/README.md +7 -0
  60. data/examples/integrations/static-rake/Rakefile +10 -0
  61. data/examples/integrations/static-rake/app/application.rb +6 -0
  62. data/examples/integrations/static-rake/index.html +9 -0
  63. data/examples/integrations/static-rake-guard/.gitignore +1 -0
  64. data/examples/integrations/static-rake-guard/Gemfile +6 -0
  65. data/examples/integrations/static-rake-guard/Guardfile +3 -0
  66. data/examples/integrations/static-rake-guard/README.md +10 -0
  67. data/examples/integrations/static-rake-guard/Rakefile +10 -0
  68. data/examples/integrations/static-rake-guard/app/application.rb +6 -0
  69. data/examples/integrations/static-rake-guard/index.html +9 -0
  70. data/examples/svg/.gitignore +1 -0
  71. data/examples/svg/Gemfile +4 -0
  72. data/examples/svg/README.md +7 -0
  73. data/examples/svg/Rakefile +10 -0
  74. data/examples/svg/app/application.rb +11 -0
  75. data/examples/svg/index.html +17 -0
  76. data/examples/svg/index.svg +6 -0
  77. data/index.html.erb +2 -3
  78. data/opal/browser/audio/node.rb +121 -0
  79. data/opal/browser/audio/param_schedule.rb +43 -0
  80. data/opal/browser/audio.rb +66 -0
  81. data/opal/browser/blob.rb +94 -0
  82. data/opal/browser/canvas/data.rb +1 -1
  83. data/opal/browser/canvas/gradient.rb +1 -1
  84. data/opal/browser/canvas/style.rb +3 -1
  85. data/opal/browser/canvas/text.rb +1 -1
  86. data/opal/browser/canvas.rb +17 -3
  87. data/opal/browser/console.rb +3 -1
  88. data/opal/browser/cookies.rb +72 -34
  89. data/opal/browser/crypto.rb +79 -0
  90. data/opal/browser/css/declaration.rb +1 -1
  91. data/opal/browser/css/rule.rb +1 -1
  92. data/opal/browser/css/style_sheet.rb +2 -2
  93. data/opal/browser/css.rb +23 -7
  94. data/opal/browser/database/sql.rb +7 -8
  95. data/opal/browser/delay.rb +16 -0
  96. data/opal/browser/dom/attribute.rb +1 -1
  97. data/opal/browser/dom/builder.rb +29 -10
  98. data/opal/browser/dom/document.rb +81 -13
  99. data/opal/browser/dom/document_fragment.rb +18 -0
  100. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  101. data/opal/browser/dom/element/attributes.rb +28 -4
  102. data/opal/browser/dom/element/button.rb +31 -0
  103. data/opal/browser/dom/element/custom.rb +177 -0
  104. data/opal/browser/dom/element/data.rb +17 -2
  105. data/opal/browser/dom/element/editable.rb +47 -0
  106. data/opal/browser/dom/element/form.rb +38 -0
  107. data/opal/browser/dom/element/iframe.rb +37 -0
  108. data/opal/browser/dom/element/image.rb +2 -0
  109. data/opal/browser/dom/element/input.rb +36 -0
  110. data/opal/browser/dom/element/media.rb +17 -0
  111. data/opal/browser/dom/element/scroll.rb +106 -74
  112. data/opal/browser/dom/element/select.rb +6 -0
  113. data/opal/browser/dom/element/size.rb +12 -0
  114. data/opal/browser/dom/element/template.rb +2 -0
  115. data/opal/browser/dom/element/textarea.rb +2 -0
  116. data/opal/browser/dom/element.rb +194 -50
  117. data/opal/browser/dom/mutation_observer.rb +2 -2
  118. data/opal/browser/dom/node.rb +53 -13
  119. data/opal/browser/dom/node_set.rb +13 -2
  120. data/opal/browser/dom/shadow_root.rb +12 -0
  121. data/opal/browser/dom/text.rb +2 -2
  122. data/opal/browser/dom.rb +38 -5
  123. data/opal/browser/effects.rb +170 -4
  124. data/opal/browser/event/all.rb +26 -0
  125. data/opal/browser/event/animation.rb +2 -0
  126. data/opal/browser/event/audio_processing.rb +2 -0
  127. data/opal/browser/event/base.rb +35 -4
  128. data/opal/browser/event/before_unload.rb +2 -0
  129. data/opal/browser/event/clipboard.rb +9 -0
  130. data/opal/browser/event/close.rb +2 -0
  131. data/opal/browser/event/composition.rb +2 -0
  132. data/opal/browser/event/custom.rb +1 -1
  133. data/opal/browser/event/data_transfer.rb +95 -0
  134. data/opal/browser/event/device_light.rb +2 -0
  135. data/opal/browser/event/device_motion.rb +2 -0
  136. data/opal/browser/event/device_orientation.rb +2 -0
  137. data/opal/browser/event/device_proximity.rb +2 -0
  138. data/opal/browser/event/drag.rb +9 -5
  139. data/opal/browser/event/focus.rb +2 -0
  140. data/opal/browser/event/gamepad.rb +3 -1
  141. data/opal/browser/event/hash_change.rb +2 -0
  142. data/opal/browser/event/keyboard.rb +14 -1
  143. data/opal/browser/event/message.rb +2 -0
  144. data/opal/browser/event/mouse.rb +10 -6
  145. data/opal/browser/event/page_transition.rb +2 -0
  146. data/opal/browser/event/pop_state.rb +2 -0
  147. data/opal/browser/event/progress.rb +2 -0
  148. data/opal/browser/event/sensor.rb +2 -0
  149. data/opal/browser/event/storage.rb +2 -0
  150. data/opal/browser/event/touch.rb +2 -0
  151. data/opal/browser/event/wheel.rb +2 -0
  152. data/opal/browser/event.rb +26 -116
  153. data/opal/browser/event_source.rb +1 -1
  154. data/opal/browser/form_data.rb +225 -0
  155. data/opal/browser/history.rb +4 -8
  156. data/opal/browser/http/request.rb +32 -10
  157. data/opal/browser/http/response.rb +5 -1
  158. data/opal/browser/http.rb +0 -2
  159. data/opal/browser/immediate.rb +0 -2
  160. data/opal/browser/location.rb +7 -1
  161. data/opal/browser/navigator.rb +105 -4
  162. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  163. data/opal/browser/screen.rb +2 -2
  164. data/opal/browser/setup/base.rb +6 -0
  165. data/opal/browser/setup/full.rb +13 -0
  166. data/opal/browser/setup/large.rb +17 -0
  167. data/opal/browser/setup/mini.rb +8 -0
  168. data/opal/browser/setup/traditional.rb +10 -0
  169. data/opal/browser/socket.rb +3 -3
  170. data/opal/browser/storage.rb +2 -2
  171. data/opal/browser/support.rb +46 -22
  172. data/opal/browser/utils.rb +94 -14
  173. data/opal/browser/version.rb +1 -1
  174. data/opal/browser/visual_viewport.rb +39 -0
  175. data/opal/browser/window/size.rb +14 -0
  176. data/opal/browser/window/view.rb +15 -0
  177. data/opal/browser/window.rb +29 -16
  178. data/opal/browser.rb +1 -11
  179. data/opal-browser.gemspec +3 -3
  180. data/spec/database/sql_spec.rb +43 -35
  181. data/spec/delay_spec.rb +15 -12
  182. data/spec/dom/document_spec.rb +10 -8
  183. data/spec/dom/element/custom_spec.rb +106 -0
  184. data/spec/dom/element/subclass_spec.rb +144 -0
  185. data/spec/dom/element_spec.rb +42 -0
  186. data/spec/dom/mutation_observer_spec.rb +12 -8
  187. data/spec/dom/node_spec.rb +48 -0
  188. data/spec/dom_spec.rb +8 -0
  189. data/spec/event_source_spec.rb +15 -12
  190. data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
  191. data/spec/history_spec.rb +23 -19
  192. data/spec/http_spec.rb +19 -31
  193. data/spec/immediate_spec.rb +5 -4
  194. data/spec/interval_spec.rb +18 -9
  195. data/spec/native_cached_wrapper_spec.rb +46 -0
  196. data/spec/runner.rb +37 -62
  197. data/spec/socket_spec.rb +15 -12
  198. data/spec/spec_helper.rb +2 -1
  199. data/spec/spec_helper_promise.rb.erb +25 -0
  200. metadata +120 -16
  201. data/.travis.yml +0 -74
  202. data/opal/browser/window/scroll.rb +0 -59
@@ -0,0 +1,216 @@
1
+ # VisualViewport polyfill (mainly for Firefox browsers) taken from:
2
+ # https://github.com/WICG/visual-viewport/blob/gh-pages/polyfill/visualViewport.js
3
+ # Licensed under "W3C 3-clause BSD License".
4
+
5
+ # Let's make sure the functions aren't poluting the global context:
6
+ %x{
7
+ (function(){ "use strict";
8
+
9
+ // This is hacky but necessary in order to get the innerWidth/Height without
10
+ // page scale applied reliably.
11
+ function updateUnscaledDimensions() {
12
+ if (!window.viewPolyfill.iframeDummy) {
13
+ var iframe = document.createElement('iframe');
14
+ iframe.style.position="absolute";
15
+ iframe.style.width="100%";
16
+ iframe.style.height="100%";
17
+ iframe.style.left="0px";
18
+ iframe.style.top="0px";
19
+ iframe.style.border="0";
20
+ iframe.style.visibility="hidden";
21
+ iframe.style.zIndex="-1";
22
+ iframe.srcdoc = "<!DOCTYPE html><html><body style='margin:0px; padding:0px'></body></html>";
23
+
24
+ document.body.appendChild(iframe);
25
+ window.viewPolyfill.iframeDummy = iframe;
26
+ }
27
+
28
+ var iframe = window.viewPolyfill.iframeDummy;
29
+
30
+ var documentRect = document.documentElement.getBoundingClientRect();
31
+ var iframeBody = iframe.contentDocument.body;
32
+ iframeBody.style.width = documentRect.width + 'px';
33
+ iframeBody.style.height = documentRect.height + 'px';
34
+
35
+ // Hide overflow temporarily so that the iframe size isn't shrunk by
36
+ // scrollbars.
37
+ var prevDocumentOverflow = document.documentElement.style.overflow;
38
+ document.documentElement.style.overflow = "hidden";
39
+
40
+ var iframeWindow = window.viewPolyfill.iframeDummy.contentWindow;
41
+ window.viewPolyfill.unscaledInnerWidth = iframeWindow.innerWidth;
42
+ window.viewPolyfill.unscaledInnerHeight = iframeWindow.innerHeight;
43
+
44
+ document.documentElement.style.overflow = prevDocumentOverflow;
45
+ }
46
+
47
+ function fireScrollEvent() {
48
+ var listeners = window.viewPolyfill.scrollEventListeners;
49
+ for (var i = 0; i < listeners.length; i++)
50
+ listeners[i]();
51
+ }
52
+
53
+ function fireResizeEvent() {
54
+ var listeners = window.viewPolyfill.resizeEventListeners;
55
+ for (var i = 0; i < listeners.length; i++)
56
+ listeners[i]();
57
+ }
58
+
59
+ function updateViewportChanged() {
60
+ var scrollChanged =
61
+ window.viewPolyfill.offsetLeftSinceLastChange != window.visualViewport.offsetLeft ||
62
+ window.viewPolyfill.offsetTopSinceLastChange != window.visualViewport.offsetTop;
63
+
64
+ var sizeChanged =
65
+ window.viewPolyfill.widthSinceLastChange != window.visualViewport.width ||
66
+ window.viewPolyfill.heightSinceLastChange != window.visualViewport.height ||
67
+ window.viewPolyfill.scaleSinceLastChange != window.visualViewport.scale;
68
+
69
+ window.viewPolyfill.offsetLeftSinceLastChange = window.visualViewport.offsetLeft;
70
+ window.viewPolyfill.offsetTopSinceLastChange = window.visualViewport.offsetTop;
71
+ window.viewPolyfill.widthSinceLastChange = window.visualViewport.width;
72
+ window.viewPolyfill.heightSinceLastChange = window.visualViewport.height;
73
+ window.viewPolyfill.scaleSinceLastChange = window.visualViewport.scale;
74
+
75
+ if (scrollChanged)
76
+ fireScrollEvent();
77
+
78
+ if (sizeChanged)
79
+ fireResizeEvent();
80
+
81
+ setTimeout(updateViewportChanged, 500);
82
+ }
83
+
84
+ function registerChangeHandlers() {
85
+ window.addEventListener('scroll', updateViewportChanged, {'passive': true});
86
+ window.addEventListener('resize', updateViewportChanged, {'passive': true});
87
+ window.addEventListener('resize', updateUnscaledDimensions, {'passive': true});
88
+ }
89
+
90
+ var isChrome = navigator.userAgent.indexOf('Chrome') > -1;
91
+ var isSafari = navigator.userAgent.indexOf("Safari") > -1;
92
+ var isIEEdge = navigator.userAgent.indexOf('Edge') > -1;
93
+
94
+ if ((isChrome)&&(isSafari))
95
+ isSafari=false;
96
+
97
+ if (window.visualViewport) {
98
+ console.log('Using real visual viewport API');
99
+ } else {
100
+ console.log('Polyfilling Viewport API');
101
+ var layoutDummy = document.createElement('div');
102
+ layoutDummy.style.width = "100%";
103
+ layoutDummy.style.height = "100%";
104
+ if (isSafari) {
105
+ layoutDummy.style.position = "fixed";
106
+ } else {
107
+ layoutDummy.style.position = "absolute";
108
+ }
109
+ layoutDummy.style.left = "0px";
110
+ layoutDummy.style.top = "0px";
111
+ layoutDummy.style.visibility = "hidden";
112
+
113
+ window.viewPolyfill = {
114
+ "offsetLeftSinceLastChange": null,
115
+ "offsetTopSinceLastChange": null,
116
+ "widthSinceLastChange": null,
117
+ "heightSinceLastChange": null,
118
+ "scaleSinceLastChange": null,
119
+ "scrollEventListeners": [],
120
+ "resizeEventListeners": [],
121
+ "layoutDummy": layoutDummy,
122
+ "iframeDummy": null,
123
+ "unscaledInnerWidth": 0,
124
+ "unscaledInnerHeight": 0
125
+ }
126
+
127
+ registerChangeHandlers();
128
+
129
+ // TODO: Need to wait for <body> to be loaded but this is probably
130
+ // later than needed.
131
+ window.addEventListener('load', function() {
132
+ updateUnscaledDimensions();
133
+ document.body.appendChild(layoutDummy);
134
+
135
+ var viewport = {
136
+ get offsetLeft() {
137
+ if (isSafari) {
138
+ // Note: Safari's getBoundingClientRect left/top is wrong when pinch-zoomed requiring this "unscaling".
139
+ return window.scrollX - (layoutDummy.getBoundingClientRect().left * this.scale + window.scrollX * this.scale);
140
+ } else {
141
+ return window.scrollX + layoutDummy.getBoundingClientRect().left;
142
+ }
143
+ },
144
+ get offsetTop() {
145
+ if (isSafari) {
146
+ // Note: Safari's getBoundingClientRect left/top is wrong when pinch-zoomed requiring this "unscaling".
147
+ return window.scrollY - (layoutDummy.getBoundingClientRect().top * this.scale + window.scrollY * this.scale);
148
+ } else {
149
+ return window.scrollY + layoutDummy.getBoundingClientRect().top;
150
+ }
151
+ },
152
+ get width() {
153
+ var clientWidth = document.documentElement.clientWidth;
154
+ if (isIEEdge) {
155
+ // If there's no scrollbar before pinch-zooming, Edge will add
156
+ // a non-layout-affecting overlay scrollbar. This won't be
157
+ // reflected in documentElement.clientWidth so we need to
158
+ // manually subtract it out.
159
+ if (document.documentElement.clientWidth == window.viewPolyfill.unscaledInnerWidth
160
+ && this.scale > 1) {
161
+ var oldWidth = document.documentElement.clientWidth;
162
+ var prevHeight = layoutDummy.style.height;
163
+ // Lengthen the dummy to add a layout vertical scrollbar.
164
+ layoutDummy.style.height = "200%";
165
+ var scrollbarWidth = oldWidth - document.documentElement.clientWidth;
166
+ layoutDummy.style.width = prevHeight;
167
+ clientWidth -= scrollbarWidth;
168
+ }
169
+ }
170
+ return clientWidth / this.scale;
171
+ },
172
+ get height() {
173
+ var clientHeight = document.documentElement.clientHeight;
174
+ if (isIEEdge) {
175
+ // If there's no scrollbar before pinch-zooming, Edge will add
176
+ // a non-layout-affecting overlay scrollbar. This won't be
177
+ // reflected in documentElement.clientHeight so we need to
178
+ // manually subtract it out.
179
+ if (document.documentElement.clientHeight == window.viewPolyfill.unscaledInnerHeight
180
+ && this.scale > 1) {
181
+ var oldHeight = document.documentElement.clientHeight;
182
+ var prevWidth = layoutDummy.style.width;
183
+ // Widen the dummy to add a layout horizontal scrollbar.
184
+ layoutDummy.style.width = "200%";
185
+ var scrollbarHeight = oldHeight - document.documentElement.clientHeight;
186
+ layoutDummy.style.width = prevWidth;
187
+ clientHeight -= scrollbarHeight;
188
+ }
189
+ }
190
+ return clientHeight / this.scale;
191
+ },
192
+ get scale() {
193
+ return window.viewPolyfill.unscaledInnerWidth / window.innerWidth;
194
+ },
195
+ get pageLeft() {
196
+ return window.scrollX;
197
+ },
198
+ get pageTop() {
199
+ return window.scrollY;
200
+ },
201
+ "addEventListener": function(name, func) {
202
+ // TODO: Match event listener semantics. i.e. can't add the same callback twice.
203
+ if (name === 'scroll')
204
+ window.viewPolyfill.scrollEventListeners.push(func);
205
+ else if (name === 'resize')
206
+ window.viewPolyfill.resizeEventListeners.push(func);
207
+ }
208
+ };
209
+
210
+ window.visualViewport = viewport;
211
+ });
212
+ }
213
+
214
+ })();
215
+
216
+ }
@@ -4,7 +4,7 @@ module Browser
4
4
  #
5
5
  # @see https://developer.mozilla.org/en-US/docs/Web/API/Window.screen
6
6
  class Screen
7
- include Native
7
+ include Browser::NativeCachedWrapper
8
8
  include Event::Target
9
9
 
10
10
  target {|value|
@@ -59,7 +59,7 @@ class Window
59
59
  # @!attribute [r] screen
60
60
  # @return [Screen] the screen for the window
61
61
  def screen
62
- Screen.new(`#@native.screen`)
62
+ @screen ||= Screen.new(`#@native.screen`)
63
63
  end
64
64
  end
65
65
 
@@ -0,0 +1,6 @@
1
+ # browser/setup/base: Setup only the base requires
2
+
3
+ require 'browser/version'
4
+ require 'browser/utils'
5
+ require 'browser/form_data'
6
+ require 'browser/support'
@@ -0,0 +1,13 @@
1
+ # browser/setup/full - a full set of requires to provide all features at once
2
+
3
+ require 'paggio'
4
+
5
+ require 'browser/setup/large'
6
+
7
+ require 'browser/event/all'
8
+
9
+ require 'browser/dom/builder'
10
+ require 'browser/dom/mutation_observer'
11
+ require 'browser/dom/element/custom'
12
+
13
+ require 'browser/canvas'
@@ -0,0 +1,17 @@
1
+ # browser/setup/large - a larger set of requires for more complex applications
2
+ #
3
+ # Note - it doesn't include Paggio (or Paggio support) or many events
4
+
5
+ require 'browser/setup/mini'
6
+
7
+ require 'browser/effects'
8
+ require 'browser/http'
9
+ require 'browser/delay'
10
+ require 'browser/interval'
11
+ require 'browser/immediate'
12
+ require 'browser/storage'
13
+ require 'browser/blob'
14
+ require 'browser/animation_frame'
15
+ require 'browser/socket'
16
+ require 'browser/history'
17
+ require 'browser/navigator'
@@ -0,0 +1,8 @@
1
+ # browser/setup/mini - A smaller set of requires, designed for slim codebases
2
+
3
+ require 'browser/setup/base'
4
+
5
+ require 'browser/event'
6
+ require 'browser/window'
7
+ require 'browser/dom'
8
+ require 'browser/css'
@@ -0,0 +1,10 @@
1
+ # browser/setup/traditional, browser, opal-browser
2
+ # ------------------------------------------------
3
+ # A traditional set of requires.
4
+
5
+ require 'native'
6
+ require 'paggio'
7
+
8
+ require 'browser/setup/mini'
9
+ require 'browser/event/all'
10
+ require 'browser/dom/builder'
@@ -4,13 +4,13 @@ module Browser
4
4
  # connection.
5
5
  #
6
6
  # @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
7
- class Socket
7
+ class Socket < IO
8
8
  def self.supported?
9
9
  Browser.supports? :WebSocket
10
10
  end
11
11
 
12
- include Native
13
- include IO::Writable
12
+ include Native::Wrapper
13
+ include IO::Writable if defined? IO::Writable
14
14
  include Event::Target
15
15
 
16
16
  target {|value|
@@ -196,12 +196,12 @@ class Storage
196
196
  #
197
197
  # @return [String] the JSON representation
198
198
  def to_json
199
- io = StringIO.new("{")
199
+ io = StringIO.new << "{"
200
200
 
201
201
  io << JSON.create_id.to_json << ":" << self.class.name.to_json << ","
202
202
 
203
203
  @data.each {|key, value|
204
- io << key.to_json.to_json << ":" << value.to_json << ","
204
+ io << key.to_json.to_s << ":" << value.to_json << ","
205
205
  }
206
206
 
207
207
  io.seek(-1, IO::SEEK_CUR)
@@ -75,14 +75,16 @@ module Browser
75
75
  when 'Window.send (Asynchronous)'
76
76
  if defined?(`window.postMessage`) && !defined?(`window.importScripts`)
77
77
  %x{
78
- var ok = true,
79
- old = window.onmessage;
78
+ (function() {
79
+ var ok = true,
80
+ old = window.onmessage;
80
81
 
81
- window.onmessage = function() { ok = false; };
82
- window.postMessage("", "*")
83
- window.onmessage = old;
82
+ window.onmessage = function() { ok = false; };
83
+ window.postMessage("", "*")
84
+ window.onmessage = old;
84
85
 
85
- return ok;
86
+ return ok;
87
+ })()
86
88
  }
87
89
  end
88
90
 
@@ -98,15 +100,20 @@ module Browser
98
100
  when 'Window.scroll'
99
101
  defined?(`document.documentElement.scrollLeft`)
100
102
 
103
+ when 'Window.scrollBy'
104
+ defined?(`document.documentElement.scrollBy`)
105
+
101
106
  when 'Window.pageOffset'
102
107
  defined?(`window.pageXOffset`)
103
108
 
104
109
  when 'Attr.isId'
105
110
  %x{
106
- var div = document.createElement('div');
107
- div.setAttribute('id', 'xxxxxxxxxxxxx');
111
+ (function() {
112
+ var div = document.createElement('div');
113
+ div.setAttribute('id', 'xxxxxxxxxxxxx');
108
114
 
109
- return typeof(div.attributes['id'].isId) !== "undefined";
115
+ return typeof(div.attributes['id'].isId) !== "undefined";
116
+ })()
110
117
  }
111
118
 
112
119
  when 'Element.addBehavior'
@@ -114,34 +121,42 @@ module Browser
114
121
 
115
122
  when 'Element.className'
116
123
  %x{
117
- var div = document.createElement("div");
118
- div.setAttribute('className', 'x');
124
+ (function() {
125
+ var div = document.createElement("div");
126
+ div.setAttribute('className', 'x');
119
127
 
120
- return div.className === 'x';
128
+ return div.className === 'x';
129
+ })()
121
130
  }
122
131
 
123
132
  when 'Element.class'
124
133
  %x{
125
- var div = document.createElement("div");
126
- div.setAttribute('class', 'x');
134
+ (function() {
135
+ var div = document.createElement("div");
136
+ div.setAttribute('class', 'x');
127
137
 
128
- return div.className === 'x';
138
+ return div.className === 'x';
139
+ })()
129
140
  }
130
141
 
131
142
  when 'Element.for'
132
143
  %x{
133
- var label = document.createElement("label");
134
- label.setAttribute('for', 'x');
144
+ (function() {
145
+ var label = document.createElement("label");
146
+ label.setAttribute('for', 'x');
135
147
 
136
- return label.htmlFor === 'x';
148
+ return label.htmlFor === 'x';
149
+ })()
137
150
  }
138
151
 
139
152
  when 'Element.htmlFor'
140
153
  %x{
141
- var label = document.createElement("label");
142
- label.setAttribute('htmlFor', 'x');
154
+ (function() {
155
+ var label = document.createElement("label");
156
+ label.setAttribute('htmlFor', 'x');
143
157
 
144
- return label.htmlFor === 'x';
158
+ return label.htmlFor === 'x';
159
+ })()
145
160
  }
146
161
 
147
162
  when 'Element.clientSize'
@@ -182,7 +197,7 @@ module Browser
182
197
  `new MouseEvent("click")`
183
198
 
184
199
  true
185
- rescue
200
+ rescue StandardError, JS::Error
186
201
  false
187
202
  end
188
203
 
@@ -269,6 +284,15 @@ module Browser
269
284
 
270
285
  when 'Animation.cancelRequest (Chrome)', 'Animation.cancelRequest (Safari)'
271
286
  defined?(`window.webkitCancelRequestAnimationFrame`)
287
+
288
+ when 'Audio'
289
+ defined?(`window.AudioContext`)
290
+
291
+ when 'Audio (Safari)', 'Audio (Chrome)'
292
+ defined?(`window.webkitAudioContext`)
293
+
294
+ when 'Custom Elements'
295
+ defined?(`window.customElements`)
272
296
  end
273
297
 
274
298
  `#@support[#{feature}] = #{support}`
@@ -1,51 +1,133 @@
1
1
  module Browser
2
+ Promise = defined?(PromiseV2) ? PromiseV2 : ::Promise
3
+
2
4
  Size = Struct.new(:width, :height)
3
5
  Position = Struct.new(:x, :y)
6
+
7
+ # {Browser::NativeCachedWrapper} is a special case of {Native::Wrapper}.
8
+ #
9
+ # What this module does is it makes sure that your Ruby objects
10
+ # are mapped 1:1 to your Javascript objects. So that for instance
11
+ # your `$document.at_css('body')` is always the same Ruby object.
12
+ #
13
+ # You can only use it if your final `.new` is of the signature
14
+ # `.new(native)` and your native (probably DOM) object persists and
15
+ # doesn't mind arbitrary properties.
16
+ #
17
+ # The rule of thumb is: if it does overload `#initialize`'s signature
18
+ # and not `.new`'s - it won't work. Use {Native::Wrapper} in this case.
19
+ module NativeCachedWrapper
20
+ def self.included(klass)
21
+ klass.include Native::Wrapper
22
+ klass.extend NativeCachedWrapperClassMethods
23
+ end
24
+
25
+ def restricted?
26
+ !!@restricted
27
+ end
28
+
29
+ # Change a native reference and make sure the change is reflected on JS
30
+ # side as well. This method is used by Node#initialize_copy. Please don't
31
+ # use this method outside of the cloning semantic.
32
+ def set_native_reference(native)
33
+ `#{native}.$$opal_native_cached = #{self}`
34
+ @native = native
35
+ end
36
+ end
37
+
38
+ module NativeCachedWrapperClassMethods
39
+ # Check if we don't have access to arbitrary properties of a (presumably)
40
+ # native object.
41
+ private def restricted?(native)
42
+ %x{
43
+ try {
44
+ typeof(#{native}.$$try_restricted_access);
45
+ } catch (e) {
46
+ if (e.name == 'SecurityError') return true;
47
+ }
48
+ return false;
49
+ }
50
+ end
51
+
52
+ def new(native)
53
+ # We can't access arbitrary properties if an element is restricted
54
+ # i.e. the DOM element is an item we can't fully access due to CORS.
55
+ if restricted?(native)
56
+ # Let's try to bypass any further initializers... may be ugly, but
57
+ # works.
58
+ obj = allocate
59
+ obj.instance_variable_set :@native, native
60
+ obj.instance_variable_set :@restricted, true
61
+ return obj
62
+ end
63
+
64
+ # It's not a native element? Weird, better throw an exception.
65
+ raise ArgumentError if !native?(native)
66
+
67
+ if defined? `#{native}.$$opal_native_cached`
68
+ `#{native}.$$opal_native_cached`
69
+ else
70
+ `#{native}.$$opal_native_cached = #{super(native)}`
71
+ end
72
+ end
73
+ end
4
74
  end
5
75
 
6
76
  class Object
7
77
  # Encode as URI.
8
78
  #
79
+ # @deprecated Please use FormData.encode_uri
9
80
  # @return [String] the {Object#to_s} encoded for usage as URI
10
81
  def encode_uri
11
- to_s.encode_uri
82
+ warn "opal-browser: Object#encode_uri is deprecated. Please use FormData.encode_uri"
83
+ FormData.encode_uri(to_s)
12
84
  end
13
85
 
14
86
  # Encode as URI component.
15
87
  #
88
+ # @deprecated Please use FormData.encode
16
89
  # @return [String] the {Object#to_s} encoded for usage as URI component
17
90
  def encode_uri_component
18
- to_s.encode_uri_component
91
+ warn "opal-browser: Object#encode_uri_component is deprecated. Please use FormData.encode"
92
+ FormData.encode(to_s)
19
93
  end
20
94
  end
21
95
 
22
96
  class String
23
97
  # Encode as URI component.
24
98
  #
99
+ # @deprecated Please use FormData.encode
25
100
  # @return [String] the string encoded for usage as URI component
26
101
  def encode_uri_component
27
- `encodeURIComponent(self)`
102
+ warn "opal-browser: String#encode_uri_component is deprecated. Please use FormData.encode"
103
+ FormData.encode(self)
28
104
  end
29
105
 
30
106
  # Encode as URI.
31
107
  #
108
+ # @deprecated Please use FormData.encode_uri
32
109
  # @return [String] the string encoded as URI
33
110
  def encode_uri
34
- `encodeURI(self)`
111
+ warn "opal-browser: String#encode_uri is deprecated. Please use FormData.encode_uri"
112
+ FormData.encode_uri(self)
35
113
  end
36
114
 
37
115
  # Decode as URI component.
38
116
  #
117
+ # @deprecated Please use FormData.decode
39
118
  # @return [String] the string decoded as URI component
40
119
  def decode_uri_component
41
- `decodeURIComponent(self)`
120
+ warn "opal-browser: String#decode_uri_component is deprecated. Please use FormData.decode"
121
+ FormData.decode(self)
42
122
  end
43
123
 
44
124
  # Decode as URI.
45
125
  #
126
+ # @deprecated Please use FormData.decode_uri
46
127
  # @return [String] the string decoded as URI
47
128
  def decode_uri
48
- `decodeURI(self)`
129
+ warn "opal-browser: String#decode_uri is deprecated. Please use FormData.decode_uri"
130
+ FormData.decode_uri(self)
49
131
  end
50
132
  end
51
133
 
@@ -54,21 +136,19 @@ class Hash
54
136
  #
55
137
  # @param string [String] the URL encoded form
56
138
  #
139
+ # @deprecated Please use FormData.parse_query
57
140
  # @return [Hash]
58
141
  def self.decode_uri(string)
59
- self[string.split(?&).map {|part|
60
- name, value = part.split(?=)
61
-
62
- [name.decode_uri_component, value.decode_uri_component]
63
- }]
142
+ warn "opal-browser: Hash.decode_uri is deprecated. Please use FormData.parse_query"
143
+ FormData.parse_query(string)
64
144
  end
65
145
 
66
146
  # Encode the Hash to an URL form.
67
147
  #
148
+ # @deprecated Please use FormData.build_query
68
149
  # @return [String] the URL encoded form
69
150
  def encode_uri
70
- map {|name, value|
71
- "#{name.to_s.encode_uri_component}=#{value.to_s.encode_uri_component}"
72
- }.join(?&)
151
+ warn "opal-browser: Hash#encode_uri is deprecated. Please use FormData.build_query"
152
+ FormData.build_query(self)
73
153
  end
74
154
  end
@@ -1,3 +1,3 @@
1
1
  module Browser
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.3'
3
3
  end
@@ -0,0 +1,39 @@
1
+ # Firefox browsers need either a flag or a polyfill
2
+ require "browser/polyfill/visual_viewport"
3
+
4
+ module Browser
5
+ # The mobile web contains two viewports, the Layout and Visual viewport.
6
+ # The Layout viewport is what a page lays out its elements into and the
7
+ # Visual viewport is what is actually visible on the screen. When the user
8
+ # pinch-zooms into the page, the visual viewport shrinks but the layout viewport
9
+ # is unchanged. UI like the on-screen keyboard (OSK) can also shrink the visual
10
+ # viewport without affecting the layout viewport.
11
+ #
12
+ # https://github.com/WICG/visual-viewport
13
+ # https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport
14
+ class VisualViewport
15
+ include Native::Wrapper
16
+ include Event::Target
17
+
18
+ alias_native :offset_left, :offsetLeft
19
+ alias_native :offset_top, :offsetTop
20
+ alias_native :page_left, :pageLeft
21
+ alias_native :page_top, :pageTop
22
+ alias_native :width, :width
23
+ alias_native :height, :height
24
+ alias_native :scale, :scale
25
+
26
+ attr_accessor :native
27
+ end
28
+
29
+ class Window
30
+ def visual_viewport
31
+ @visual_viewport ||= VisualViewport.new(`#@native.visualViewport`)
32
+
33
+ # Polyfill can take some time to load
34
+ @visual_viewport.native ||= `#@native.visualViewport`
35
+
36
+ @visual_viewport
37
+ end
38
+ end
39
+ end