opal-browser 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +95 -0
  3. data/.gitignore +2 -0
  4. data/Gemfile +17 -3
  5. data/LICENSE +2 -1
  6. data/README.md +116 -54
  7. data/Rakefile +29 -1
  8. data/config.ru +20 -3
  9. data/docs/polyfills.md +24 -0
  10. data/examples/2048/Gemfile +7 -0
  11. data/examples/2048/README.md +13 -0
  12. data/examples/2048/app/application.rb +169 -0
  13. data/examples/2048/config.ru +9 -0
  14. data/examples/canvas/Gemfile +7 -0
  15. data/examples/canvas/README.md +9 -0
  16. data/examples/canvas/app/application.rb +55 -0
  17. data/examples/canvas/config.ru +9 -0
  18. data/examples/component/Gemfile +7 -0
  19. data/examples/component/README.md +10 -0
  20. data/examples/component/app/application.rb +66 -0
  21. data/examples/component/config.ru +9 -0
  22. data/examples/integrations/README.md +24 -0
  23. data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +7 -0
  24. data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
  25. data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
  26. data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
  27. data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
  28. data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +8 -0
  29. data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
  30. data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
  31. data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
  32. data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
  33. data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
  34. data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
  35. data/examples/integrations/dynamic-roda-tilt/Gemfile +9 -0
  36. data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
  37. data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
  38. data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
  39. data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
  40. data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
  41. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +8 -0
  42. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
  43. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
  44. data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
  45. data/examples/integrations/static-bash/.gitignore +2 -0
  46. data/examples/integrations/static-bash/Gemfile +4 -0
  47. data/examples/integrations/static-bash/README.md +8 -0
  48. data/examples/integrations/static-bash/app/application.rb +6 -0
  49. data/examples/integrations/static-bash/build.sh +4 -0
  50. data/examples/integrations/static-bash/index.html +10 -0
  51. data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
  52. data/examples/integrations/static-bash-opal-parser/Gemfile +4 -0
  53. data/examples/integrations/static-bash-opal-parser/README.md +10 -0
  54. data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
  55. data/examples/integrations/static-bash-opal-parser/index.html +19 -0
  56. data/examples/integrations/static-rake/.gitignore +1 -0
  57. data/examples/integrations/static-rake/Gemfile +5 -0
  58. data/examples/integrations/static-rake/README.md +7 -0
  59. data/examples/integrations/static-rake/Rakefile +10 -0
  60. data/examples/integrations/static-rake/app/application.rb +6 -0
  61. data/examples/integrations/static-rake/index.html +9 -0
  62. data/examples/integrations/static-rake-guard/.gitignore +1 -0
  63. data/examples/integrations/static-rake-guard/Gemfile +7 -0
  64. data/examples/integrations/static-rake-guard/Guardfile +3 -0
  65. data/examples/integrations/static-rake-guard/README.md +10 -0
  66. data/examples/integrations/static-rake-guard/Rakefile +10 -0
  67. data/examples/integrations/static-rake-guard/app/application.rb +6 -0
  68. data/examples/integrations/static-rake-guard/index.html +9 -0
  69. data/examples/svg/.gitignore +1 -0
  70. data/examples/svg/Gemfile +5 -0
  71. data/examples/svg/README.md +7 -0
  72. data/examples/svg/Rakefile +10 -0
  73. data/examples/svg/app/application.rb +11 -0
  74. data/examples/svg/index.html +17 -0
  75. data/examples/svg/index.svg +6 -0
  76. data/index.html.erb +2 -3
  77. data/opal/browser/audio/node.rb +121 -0
  78. data/opal/browser/audio/param_schedule.rb +43 -0
  79. data/opal/browser/audio.rb +66 -0
  80. data/opal/browser/blob.rb +94 -0
  81. data/opal/browser/canvas/data.rb +1 -1
  82. data/opal/browser/canvas/gradient.rb +1 -1
  83. data/opal/browser/canvas/style.rb +3 -1
  84. data/opal/browser/canvas/text.rb +1 -1
  85. data/opal/browser/canvas.rb +17 -3
  86. data/opal/browser/console.rb +3 -1
  87. data/opal/browser/cookies.rb +16 -7
  88. data/opal/browser/crypto.rb +79 -0
  89. data/opal/browser/css/declaration.rb +1 -1
  90. data/opal/browser/css/rule.rb +1 -1
  91. data/opal/browser/css/style_sheet.rb +2 -2
  92. data/opal/browser/css.rb +23 -7
  93. data/opal/browser/database/sql.rb +7 -8
  94. data/opal/browser/delay.rb +16 -0
  95. data/opal/browser/dom/attribute.rb +1 -1
  96. data/opal/browser/dom/builder.rb +29 -10
  97. data/opal/browser/dom/document.rb +81 -13
  98. data/opal/browser/dom/document_fragment.rb +18 -0
  99. data/opal/browser/dom/document_or_shadow_root.rb +19 -0
  100. data/opal/browser/dom/element/attributes.rb +28 -4
  101. data/opal/browser/dom/element/button.rb +31 -0
  102. data/opal/browser/dom/element/custom.rb +177 -0
  103. data/opal/browser/dom/element/data.rb +17 -2
  104. data/opal/browser/dom/element/editable.rb +47 -0
  105. data/opal/browser/dom/element/form.rb +38 -0
  106. data/opal/browser/dom/element/iframe.rb +37 -0
  107. data/opal/browser/dom/element/image.rb +2 -0
  108. data/opal/browser/dom/element/input.rb +36 -0
  109. data/opal/browser/dom/element/media.rb +17 -0
  110. data/opal/browser/dom/element/scroll.rb +106 -74
  111. data/opal/browser/dom/element/select.rb +6 -0
  112. data/opal/browser/dom/element/size.rb +12 -0
  113. data/opal/browser/dom/element/template.rb +2 -0
  114. data/opal/browser/dom/element/textarea.rb +2 -0
  115. data/opal/browser/dom/element.rb +193 -48
  116. data/opal/browser/dom/mutation_observer.rb +2 -2
  117. data/opal/browser/dom/node.rb +53 -13
  118. data/opal/browser/dom/node_set.rb +11 -2
  119. data/opal/browser/dom/shadow_root.rb +12 -0
  120. data/opal/browser/dom/text.rb +2 -2
  121. data/opal/browser/dom.rb +38 -5
  122. data/opal/browser/effects.rb +170 -4
  123. data/opal/browser/event/all.rb +26 -0
  124. data/opal/browser/event/animation.rb +2 -0
  125. data/opal/browser/event/audio_processing.rb +2 -0
  126. data/opal/browser/event/base.rb +35 -4
  127. data/opal/browser/event/before_unload.rb +2 -0
  128. data/opal/browser/event/clipboard.rb +9 -0
  129. data/opal/browser/event/close.rb +2 -0
  130. data/opal/browser/event/composition.rb +2 -0
  131. data/opal/browser/event/custom.rb +1 -1
  132. data/opal/browser/event/data_transfer.rb +95 -0
  133. data/opal/browser/event/device_light.rb +2 -0
  134. data/opal/browser/event/device_motion.rb +2 -0
  135. data/opal/browser/event/device_orientation.rb +2 -0
  136. data/opal/browser/event/device_proximity.rb +2 -0
  137. data/opal/browser/event/drag.rb +9 -5
  138. data/opal/browser/event/focus.rb +2 -0
  139. data/opal/browser/event/gamepad.rb +3 -1
  140. data/opal/browser/event/hash_change.rb +2 -0
  141. data/opal/browser/event/keyboard.rb +14 -1
  142. data/opal/browser/event/message.rb +2 -0
  143. data/opal/browser/event/mouse.rb +10 -6
  144. data/opal/browser/event/page_transition.rb +2 -0
  145. data/opal/browser/event/pop_state.rb +2 -0
  146. data/opal/browser/event/progress.rb +2 -0
  147. data/opal/browser/event/sensor.rb +2 -0
  148. data/opal/browser/event/storage.rb +2 -0
  149. data/opal/browser/event/touch.rb +2 -0
  150. data/opal/browser/event/wheel.rb +2 -0
  151. data/opal/browser/event.rb +26 -116
  152. data/opal/browser/event_source.rb +1 -1
  153. data/opal/browser/form_data.rb +225 -0
  154. data/opal/browser/history.rb +4 -8
  155. data/opal/browser/http/request.rb +32 -10
  156. data/opal/browser/http/response.rb +5 -1
  157. data/opal/browser/http.rb +0 -2
  158. data/opal/browser/immediate.rb +0 -2
  159. data/opal/browser/location.rb +7 -1
  160. data/opal/browser/navigator.rb +105 -4
  161. data/opal/browser/polyfill/visual_viewport.rb +216 -0
  162. data/opal/browser/screen.rb +2 -2
  163. data/opal/browser/setup/base.rb +6 -0
  164. data/opal/browser/setup/full.rb +13 -0
  165. data/opal/browser/setup/large.rb +17 -0
  166. data/opal/browser/setup/mini.rb +8 -0
  167. data/opal/browser/setup/traditional.rb +10 -0
  168. data/opal/browser/socket.rb +3 -3
  169. data/opal/browser/storage.rb +2 -2
  170. data/opal/browser/support.rb +13 -1
  171. data/opal/browser/utils.rb +94 -14
  172. data/opal/browser/version.rb +1 -1
  173. data/opal/browser/visual_viewport.rb +39 -0
  174. data/opal/browser/window/size.rb +14 -0
  175. data/opal/browser/window/view.rb +15 -0
  176. data/opal/browser/window.rb +29 -16
  177. data/opal/browser.rb +1 -11
  178. data/opal-browser.gemspec +3 -3
  179. data/spec/database/sql_spec.rb +43 -35
  180. data/spec/delay_spec.rb +15 -12
  181. data/spec/dom/document_spec.rb +10 -8
  182. data/spec/dom/element/custom_spec.rb +106 -0
  183. data/spec/dom/element/subclass_spec.rb +144 -0
  184. data/spec/dom/element_spec.rb +42 -0
  185. data/spec/dom/mutation_observer_spec.rb +12 -8
  186. data/spec/dom/node_spec.rb +48 -0
  187. data/spec/dom_spec.rb +8 -0
  188. data/spec/event_source_spec.rb +15 -12
  189. data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
  190. data/spec/history_spec.rb +23 -19
  191. data/spec/http_spec.rb +19 -31
  192. data/spec/immediate_spec.rb +5 -4
  193. data/spec/interval_spec.rb +18 -9
  194. data/spec/native_cached_wrapper_spec.rb +46 -0
  195. data/spec/runner.rb +37 -62
  196. data/spec/socket_spec.rb +15 -12
  197. data/spec/spec_helper.rb +2 -1
  198. data/spec/spec_helper_promise.rb.erb +25 -0
  199. metadata +119 -16
  200. data/.travis.yml +0 -74
  201. data/opal/browser/window/scroll.rb +0 -59
@@ -1,6 +1,5 @@
1
1
  require 'browser/window/view'
2
2
  require 'browser/window/size'
3
- require 'browser/window/scroll'
4
3
 
5
4
  module Browser
6
5
 
@@ -30,7 +29,7 @@ class Window
30
29
  }
31
30
  end
32
31
 
33
- include Native
32
+ include Browser::NativeCachedWrapper
34
33
  include Event::Target
35
34
 
36
35
  target {|value|
@@ -45,8 +44,8 @@ class Window
45
44
  end
46
45
 
47
46
  # Display a prompt dialog with the passed string as text.
48
- def prompt(value)
49
- `#@native.prompt(value) || nil`
47
+ def prompt(value, default=nil)
48
+ `#@native.prompt(value, #{default || ""}) || nil`
50
49
  end
51
50
 
52
51
  # Display a confirmation dialog with the passed string as text.
@@ -54,25 +53,43 @@ class Window
54
53
  `#@native.confirm(value) || false`
55
54
  end
56
55
 
56
+ # @!attribute [r] parent
57
+ # @return [Window] parent of the current window or subframe
58
+ def parent
59
+ @parent ||= Browser::Window.new(`#@native.parent`)
60
+ end
61
+
62
+ # @!attribute [r] top
63
+ # @return [Window] reference to the topmost window in the window hierarchy
64
+ def top
65
+ @top ||= Browser::Window.new(`#@native.top`)
66
+ end
67
+
68
+ # @!attribute [r] opener
69
+ # @return [Window] reference to the window that opened the window using `open`
70
+ def opener
71
+ @opener ||= Browser::Window.new(`#@native.opener`)
72
+ end
73
+
57
74
  # Get the {View} for the window.
58
75
  #
59
76
  # @return [View]
60
77
  def view
61
- View.new(self)
78
+ @view ||= View.new(self)
62
79
  end
63
80
 
64
81
  # Get the {Size} for this window.
65
82
  #
66
83
  # @return [Size]
67
84
  def size
68
- Size.new(self)
85
+ @size ||= Size.new(self)
69
86
  end
70
87
 
71
- # Get the {Scroll} for this window.
88
+ # Get the {DOM::Element::Scroll} for this window.
72
89
  #
73
- # @return [Scroll]
90
+ # @return [DOM::Element::Scroll]
74
91
  def scroll
75
- Scroll.new(self)
92
+ @scroll ||= DOM::Element::Scroll.new(self)
76
93
  end
77
94
 
78
95
  if Browser.supports? 'Window.send'
@@ -90,11 +107,7 @@ class Window
90
107
  end
91
108
 
92
109
  def close
93
- %x{
94
- return (window.open('', '_self', '') && window.close()) ||
95
- (window.opener = null && window.close()) ||
96
- (window.opener = '' && window.close());
97
- }
110
+ `#{@native}.close()`
98
111
  end
99
112
  end
100
113
 
@@ -109,8 +122,8 @@ module Kernel
109
122
  end
110
123
 
111
124
  # (see Browser::Window#prompt)
112
- def prompt(value)
113
- $window.prompt(value)
125
+ def prompt(value, default=nil)
126
+ $window.prompt(value, default)
114
127
  end
115
128
 
116
129
  # (see Browser::Window#confirm)
data/opal/browser.rb CHANGED
@@ -1,11 +1 @@
1
- require 'native'
2
- require 'paggio'
3
-
4
- require 'browser/version'
5
- require 'browser/utils'
6
- require 'browser/support'
7
-
8
- require 'browser/event'
9
- require 'browser/window'
10
- require 'browser/dom'
11
- require 'browser/css'
1
+ require 'browser/setup/traditional'
data/opal-browser.gemspec CHANGED
@@ -4,7 +4,7 @@ require 'browser/version'
4
4
  Gem::Specification.new {|s|
5
5
  s.name = 'opal-browser'
6
6
  s.version = Browser::VERSION
7
- s.author = 'meh.'
7
+ s.author = ['meh.', 'hmdne']
8
8
  s.email = 'meh@schizofreni.co'
9
9
  s.homepage = 'http://github.com/opal/opal-browser'
10
10
  s.platform = Gem::Platform::RUBY
@@ -16,6 +16,6 @@ Gem::Specification.new {|s|
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
17
  s.require_paths = ['lib']
18
18
 
19
- s.add_dependency 'opal'
20
- s.add_dependency 'paggio'
19
+ s.add_dependency 'opal', ['>= 1.0', '< 2.0']
20
+ s.add_dependency 'paggio', '>= 0.3.0'
21
21
  }
@@ -24,107 +24,115 @@ describe Browser::Database::SQL do
24
24
  end
25
25
 
26
26
  describe '#transaction' do
27
- async 'calls the block with the transaction' do
27
+ it 'calls the block with the transaction' do
28
28
  sql = SQL.new('test', size: SIZE)
29
29
 
30
+ promise = Browser::Promise.new
30
31
  sql.transaction {|t|
31
- async {
32
- expect(t).to be_a(SQL::Transaction)
33
- }
32
+ expect(t).to be_a(SQL::Transaction)
33
+ promise.resolve
34
34
  }
35
+ promise.for_rspec
35
36
  end
36
37
 
37
- async 'the transaction database is the right one' do
38
+ it 'the transaction database is the right one' do
38
39
  sql = SQL.new('test', size: SIZE)
39
40
 
41
+ promise = Browser::Promise.new
40
42
  sql.transaction {|t|
41
- async {
42
- expect(t.database).to eq(sql)
43
- }
43
+ expect(t.database).to eq(sql)
44
+ promise.resolve
44
45
  }
46
+ promise.for_rspec
45
47
  end
46
48
  end
47
49
 
48
50
  describe SQL::Transaction do
49
51
  describe '#query' do
50
- async 'returns a promise' do
52
+ it 'returns a promise' do
51
53
  sql = SQL.new('test', size: SIZE)
52
54
 
55
+ promise = Browser::Promise.new
53
56
  sql.transaction {|t|
54
- async {
55
- expect(t.query('hue')).to be_a(Promise)
56
- }
57
+ expect(t.query('hue')).to be_a(Promise)
58
+ promise.resolve
57
59
  }
60
+ promise.for_rspec
58
61
  end
59
62
 
60
- async 'resolves on success' do
63
+ it 'resolves on success' do
61
64
  sql = SQL.new('test', size: SIZE)
62
65
 
66
+ promise = Browser::Promise.new
63
67
  sql.transaction {|t|
64
68
  t.query('CREATE TABLE IF NOT EXISTS test(ID INTEGER PRIMARY KEY ASC, a TEXT)').then {|r|
65
- async {
66
- expect(r).to be_a(SQL::Result)
67
- }
69
+ expect(r).to be_a(SQL::Result)
70
+ promise.resolve
68
71
  }
69
72
  }
73
+ promise.for_rspec
70
74
  end
71
75
 
72
- async 'rejects on failure' do
76
+ it 'rejects on failure' do
73
77
  sql = SQL.new('test', size: SIZE)
74
78
 
79
+ promise = Browser::Promise.new
75
80
  sql.transaction {|t|
76
81
  t.query('huehue').rescue {|e|
77
- async {
78
- expect(e).to be_a(SQL::Error::Syntax)
79
- }
82
+ expect(e).to be_a(SQL::Error::Syntax)
83
+ promise.resolve
80
84
  }
81
85
  }
86
+ promise.for_rspec
82
87
  end
83
88
  end
84
89
  end
85
90
 
86
91
  describe SQL::Result do
87
92
  describe '#length' do
88
- async 'has the proper length' do
93
+ it 'has the proper length' do
89
94
  sql = SQL.new('test', size: SIZE)
90
95
 
96
+ promise = Browser::Promise.new
91
97
  sql.transaction {|t|
92
98
  t.query('SELECT 1').then {|r|
93
- async {
94
- expect(r.length).to eq(1)
95
- }
99
+ expect(r.length).to eq(1)
100
+ promise.resolve
96
101
  }
97
102
  }
103
+ promise.for_rspec
98
104
  end
99
105
  end
100
106
 
101
107
  describe '#[]' do
102
- async 'returns a row' do
108
+ it 'returns a row' do
103
109
  sql = SQL.new('test', size: SIZE)
104
110
 
111
+ promise = Browser::Promise.new
105
112
  sql.transaction {|t|
106
113
  t.query('SELECT 1, 2, 3').then {|r|
107
- async {
108
- expect(r[0]).to be_a(SQL::Row)
109
- expect(r[-1]).to be_a(SQL::Row)
114
+ expect(r[0]).to be_a(SQL::Row)
115
+ expect(r[-1]).to be_a(SQL::Row)
110
116
 
111
- expect(r[0]).to eq(r[-1])
112
- }
117
+ expect(r[0]).to eq(r[-1])
118
+ promise.resolve
113
119
  }
114
120
  }
121
+ promise.for_rspec
115
122
  end
116
123
 
117
- async 'returns nil on missing row' do
124
+ it 'returns nil on missing row' do
118
125
  sql = SQL.new('test', size: SIZE)
119
126
 
127
+ promise = Browser::Promise.new
120
128
  sql.transaction {|t|
121
129
  t.query('SELECT 1, 2, 3').then {|r|
122
- async {
123
- expect(r[5]).to be_nil
124
- expect(r[-5]).to be_nil
125
- }
130
+ expect(r[5]).to be_nil
131
+ expect(r[-5]).to be_nil
132
+ promise.resolve
126
133
  }
127
134
  }
135
+ promise.for_rspec
128
136
  end
129
137
  end
130
138
  end
data/spec/delay_spec.rb CHANGED
@@ -3,36 +3,39 @@ require 'browser/delay'
3
3
 
4
4
  describe Browser::Window do
5
5
  describe '#after' do
6
- async 'calls the block after the given time' do
6
+ it 'calls the block after the given time' do
7
+ promise = Browser::Promise.new
7
8
  $window.after 0.3 do
8
- async {
9
- expect(true).to be_truthy
10
- }
9
+ expect(true).to be_truthy
10
+ promise.resolve
11
11
  end
12
+ promise.for_rspec
12
13
  end
13
14
  end
14
15
  end
15
16
 
16
17
  describe Kernel do
17
18
  describe '#after' do
18
- async 'calls the block after the given time' do
19
+ it 'calls the block after the given time' do
20
+ promise = Browser::Promise.new
19
21
  after 0.3 do
20
- async {
21
- expect(true).to be_truthy
22
- }
22
+ expect(true).to be_truthy
23
+ promise.resolve
23
24
  end
25
+ promise.for_rspec
24
26
  end
25
27
  end
26
28
  end
27
29
 
28
30
  describe Proc do
29
31
  describe '#after' do
30
- async 'calls the block after the given time' do
32
+ it 'calls the block after the given time' do
33
+ promise = Browser::Promise.new
31
34
  -> {
32
- async {
33
- expect(true).to be_truthy
34
- }
35
+ expect(true).to be_truthy
36
+ promise.resolve
35
37
  }.after 0.3
38
+ promise.for_rspec
36
39
  end
37
40
  end
38
41
  end
@@ -39,22 +39,24 @@ describe Browser::DOM::Document do
39
39
  end
40
40
 
41
41
  describe "#ready" do
42
- async "calls the block when the document is ready" do
42
+ it "calls the block when the document is ready" do
43
+ promise = Browser::Promise.new
43
44
  $document.ready do
44
- async {
45
- expect(true).to be_truthy
46
- }
45
+ expect(true).to be_truthy
46
+ promise.resolve
47
47
  end
48
+ promise.for_rspec
48
49
  end
49
50
  end
50
51
 
51
52
  describe "#ready?" do
52
- async "is true inside a #ready block" do
53
+ it "is true inside a #ready block" do
54
+ promise = Browser::Promise.new
53
55
  $document.ready do
54
- async {
55
- expect($document.ready?).to be_truthy
56
- }
56
+ expect($document.ready?).to be_truthy
57
+ promise.resolve
57
58
  end
59
+ promise.for_rspec
58
60
  end
59
61
  end
60
62
  end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'browser/dom/element/custom'
3
+
4
+ describe Browser::DOM::Element::Custom do
5
+ before(:each) do
6
+ $scratchpad = Hash.new { false }
7
+ end
8
+
9
+ def create_custom_class(name, observed_attrs = [])
10
+ Class.new(Browser::DOM::Element::Custom) do
11
+ def initialize(node)
12
+ super
13
+ $scratchpad[:initialized] = true
14
+ end
15
+
16
+ def attached
17
+ $scratchpad[:attached] = true
18
+ end
19
+
20
+ def detached
21
+ $scratchpad[:detached] = true
22
+ end
23
+
24
+ def adopted
25
+ $scratchpad[:adopted] = true
26
+ end
27
+
28
+ def attribute_changed(attr, from, to)
29
+ $scratchpad[:attribute_changed] = [attr, from, to]
30
+ end
31
+
32
+ self.observed_attributes = observed_attrs
33
+
34
+ def_custom name
35
+ end
36
+ end
37
+
38
+ describe "upgrades" do
39
+ html <<-HTML
40
+ <app-ex1></app-ex1>
41
+ <app-ex2></app-ex2>
42
+ <app-ex7 prop="true"></app-ex7>
43
+ HTML
44
+
45
+ it "existing elements when they have been initialized before" do
46
+ expect($document.at_css("app-ex1").class).to eq(Browser::DOM::Element)
47
+ klass = create_custom_class("app-ex1")
48
+ expect($document.at_css("app-ex1").class).to eq(klass)
49
+ expect($scratchpad[:initialized]).to be(true)
50
+ expect($scratchpad[:attached]).to be(true)
51
+ end
52
+
53
+ it "existing elements when they have not been initialized before" do
54
+ klass = create_custom_class("app-ex2")
55
+ expect($scratchpad[:initialized]).to be(true)
56
+ expect($scratchpad[:attached]).to be(true)
57
+ expect($document.at_css("app-ex2").class).to eq(klass)
58
+ end
59
+
60
+ it "and fires property update events when upgraded" do
61
+ klass = create_custom_class("app-ex7", ["prop"])
62
+ expect($scratchpad[:attribute_changed]).to eq([:prop, nil, "true"])
63
+ end
64
+ end
65
+
66
+ it "creates and handles new elements correctly" do
67
+ klass = create_custom_class("app-ex3")
68
+ elem = klass.new
69
+ expect($scratchpad[:initialized]).to be(true)
70
+ expect($scratchpad[:attached]).to be(false)
71
+ $document.body << elem
72
+ expect($scratchpad[:detached]).to be(false)
73
+ expect($scratchpad[:attached]).to be(true)
74
+ elem.remove
75
+ expect($scratchpad[:detached]).to be(true)
76
+ end
77
+
78
+ it "correctly tracks updated properties" do
79
+ klass = create_custom_class("app-ex4")
80
+ elem = klass.new
81
+ expect($scratchpad[:attribute_changed]).to be(false)
82
+ elem[:untracked] = "test"
83
+ expect($scratchpad[:attribute_changed]).to be(false)
84
+
85
+ klass = create_custom_class("app-ex5", ["tracked"])
86
+ elem = klass.new
87
+ expect($scratchpad[:attribute_changed]).to be(false)
88
+ elem[:untracked] = "test"
89
+ expect($scratchpad[:attribute_changed]).to be(false)
90
+ elem[:tracked] = "test"
91
+ expect($scratchpad[:attribute_changed]).to eq([:tracked, nil, "test"])
92
+ end
93
+
94
+ it "allows creation of custom elements in various ways" do
95
+ klass = create_custom_class("app-ex6")
96
+
97
+ elem = klass.new
98
+ expect(elem).to be_a(klass)
99
+ elem = $document.create_element("app-ex6")
100
+ expect(elem).to be_a(klass)
101
+ elem = DOM("<app-ex6>")
102
+ expect(elem).to be_a(klass)
103
+ elem = DOM { e("app-ex6") }
104
+ expect(elem).to be_a(klass)
105
+ end
106
+ end
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Browser::DOM::Element subclassing" do
4
+ class1 = Class.new(Browser::DOM::Element) do
5
+ def_selector ".class1"
6
+
7
+ def hello
8
+ "world"
9
+ end
10
+ end
11
+
12
+ class2 = Class.new(Browser::DOM::Element::Input) do
13
+ def_selector "input.class2[type='text']"
14
+
15
+ def hello
16
+ "goodbye"
17
+ end
18
+ end
19
+
20
+ class3 = Class.new(class2) do
21
+ def_selector "input.class2.class3[type='text']"
22
+
23
+ def self.create(value)
24
+ super().tap { |elem| elem.value = value }
25
+ end
26
+ end
27
+
28
+ class4 = Class.new(Browser::DOM::Element) do
29
+ def_selector "custom-element"
30
+
31
+ def hello
32
+ text
33
+ end
34
+ end
35
+
36
+ html <<-HTML
37
+ <div class='class1' id='hiho'></div>
38
+ <input class='class2' type='text' id='hoho'></div>
39
+ <input class='class2' type='hidden' id='hehe'></div>
40
+ <custom-element id='class4'>value</custom-element>
41
+ HTML
42
+
43
+ it 'dispatches from DOM correctly' do
44
+ elem = $document.at_css('#hiho')
45
+ expect(elem.class).to eq(class1)
46
+ expect(elem.hello).to eq('world')
47
+
48
+ elem = $document.at_css('#hoho')
49
+ expect(elem.class).to eq(class2)
50
+ expect(elem.hello).to eq('goodbye')
51
+
52
+ elem = $document.at_css('#hehe')
53
+ expect(elem.class).to eq(Browser::DOM::Element::Input)
54
+ end
55
+
56
+ it 'supports creating elements correctly' do
57
+ elem = class1.create
58
+ expect(elem.class).to eq(class1)
59
+ expect(elem.class_name).to eq('class1')
60
+ expect(elem.name).to eq('DIV')
61
+ expect(elem.hello).to eq('world')
62
+
63
+ elem = class2.create
64
+ expect(elem.class).to eq(class2)
65
+ expect(elem.class_name).to eq('class2')
66
+ expect(elem.name).to eq('INPUT')
67
+ expect(elem.hello).to eq('goodbye')
68
+ expect(elem.type).to eq('text')
69
+ end
70
+
71
+ it 'supports nested subclassing and .create overloading' do
72
+ elem = class3.create('well')
73
+ expect(elem.class).to eq(class3)
74
+ expect(elem.class_name).to eq('class2 class3')
75
+ expect(elem.value).to eq('well')
76
+ expect(elem.hello).to eq('goodbye')
77
+ end
78
+
79
+ it 'supports custom elements' do
80
+ elem = $document.at_css('#class4')
81
+ expect(elem.class).to eq(class4)
82
+ expect(elem.name).to eq('CUSTOM-ELEMENT')
83
+ expect(elem.hello).to eq('value')
84
+
85
+ elem = class4.create
86
+ expect(elem.class).to eq(class4)
87
+ expect(elem.name).to eq('CUSTOM-ELEMENT')
88
+ expect(elem.hello).to eq('')
89
+ end
90
+
91
+ it 'works with Paggio' do
92
+ elem = DOM { div.class1 }
93
+ expect(elem.class).to eq(class1)
94
+ expect(elem.hello).to eq('world')
95
+ end
96
+
97
+ it 'works with Paggio with a .create/.new intializer' do
98
+ elems = DOM {
99
+ class1.create(self)
100
+ class1.new(self, attrs: { x: :y })
101
+ class1.new(self)
102
+ }
103
+ expect(elems.class).to eq(Browser::DOM::NodeSet)
104
+ expect(elems.length).to eq(3)
105
+ expect(elems[1][:x]).to eq(:y)
106
+ expect(elems.to_ary.map(&:class)).to eq([class1] * 3)
107
+ end
108
+
109
+ it 'works with Paggio, .create/.new and nested blocks' do
110
+ elem = DOM { |d|
111
+ class1.new(d) {
112
+ d.div.noticeme
113
+ class1.new(d) {
114
+ d.div.noticeme3
115
+ }
116
+ d.div.noticeme2
117
+ }
118
+ }
119
+ expect(elem.class).to eq(class1)
120
+ expect(elem.children.length).to eq(3)
121
+ expect(elem.children[1].class).to eq(class1)
122
+ expect(elem.children[1].children.length).to eq(1)
123
+ expect(elem.children[0].class).to eq(Browser::DOM::Element)
124
+ expect(elem.children[2].class).to eq(Browser::DOM::Element)
125
+ expect(elem.children[1].children[0].class).to eq(Browser::DOM::Element)
126
+ end
127
+
128
+ it 'works with Paggio, .create/.new, nested blocks and without DOM{}' do
129
+ elem = class1.new {
130
+ div.noticeme
131
+ class1.new(self) {
132
+ div.noticeme3
133
+ }
134
+ div.noticeme2
135
+ }
136
+ expect(elem.class).to eq(class1)
137
+ expect(elem.children.length).to eq(3)
138
+ expect(elem.children[1].class).to eq(class1)
139
+ expect(elem.children[1].children.length).to eq(1)
140
+ expect(elem.children[0].class).to eq(Browser::DOM::Element)
141
+ expect(elem.children[2].class).to eq(Browser::DOM::Element)
142
+ expect(elem.children[1].children[0].class).to eq(Browser::DOM::Element)
143
+ end
144
+ end
@@ -178,4 +178,46 @@ describe Browser::DOM::Element do
178
178
  expect($document.at_xpath('//div', '//span', '//[@id="lol"]')).to be_a(DOM::Element)
179
179
  end
180
180
  end
181
+
182
+ describe '#shadow' do
183
+ html <<-HTML
184
+ <div id="shadowtest"></div>
185
+ HTML
186
+
187
+ it 'creates a shadow root' do
188
+ expect($document[:shadowtest].shadow?).to be(false)
189
+ expect($document[:shadowtest].shadow).to be_a(DOM::ShadowRoot)
190
+ expect($document[:shadowtest].shadow?).to be(true)
191
+ end
192
+
193
+ it 'accesses a shadow root' do
194
+ $document[:shadowtest].shadow # Create one
195
+ expect($document[:shadowtest].shadow?).to be(true)
196
+ expect($document[:shadowtest].shadow).to be_a(DOM::ShadowRoot)
197
+ end
198
+
199
+ it 'works like a typical opal-browser DOM tree' do
200
+ DOM {
201
+ div.shadow_item "Hello world!"
202
+ }.append_to($document[:shadowtest].shadow)
203
+
204
+ expect($document[:shadowtest].at_css(".shadow_item")).to be_nil
205
+ expect($document[:shadowtest].shadow.at_css(".shadow_item").text).to be("Hello world!")
206
+ end
207
+
208
+ it 'supports stylesheets' do
209
+ $document[:shadowtest].shadow << CSS {
210
+ rule("p") {
211
+ color "rgb(255, 0, 0)"
212
+ }
213
+ rule(":host") {
214
+ color "rgb(0, 0, 255)"
215
+ }
216
+ } << DOM { p }
217
+
218
+ expect($document[:shadowtest].shadow.at_css("p").style!.color).to be("rgb(255, 0, 0)")
219
+ expect($document[:shadowtest].style!.color).to be("rgb(0, 0, 255)")
220
+ expect($document[:shadowtest].shadow.stylesheets.count).to be(1)
221
+ end
222
+ end
181
223
  end