unpoly-rails 0.57.0 → 0.60.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +393 -1
  3. data/Gemfile.lock +5 -2
  4. data/README.md +1 -1
  5. data/README_RAILS.md +1 -1
  6. data/Rakefile +10 -1
  7. data/design/es6.js +32 -0
  8. data/design/ie11.txt +9 -0
  9. data/design/measure_jquery/element_list.js +41 -0
  10. data/design/measure_jquery/up.on_vs_addEventListener.js +56 -0
  11. data/design/todo_jquery.txt +13 -0
  12. data/dist/unpoly-bootstrap3.js +8 -8
  13. data/dist/unpoly-bootstrap3.min.js +1 -1
  14. data/dist/unpoly.css +22 -20
  15. data/dist/unpoly.js +6990 -5336
  16. data/dist/unpoly.min.css +1 -1
  17. data/dist/unpoly.min.js +4 -4
  18. data/lib/assets/javascripts/unpoly-bootstrap3/viewport-ext.coffee +5 -0
  19. data/lib/assets/javascripts/unpoly.coffee +8 -6
  20. data/lib/assets/javascripts/unpoly/browser.coffee.erb +23 -118
  21. data/lib/assets/javascripts/unpoly/classes/body_shifter.coffee +36 -0
  22. data/lib/assets/javascripts/unpoly/classes/cache.coffee +4 -4
  23. data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +45 -39
  24. data/lib/assets/javascripts/unpoly/classes/config.coffee +9 -0
  25. data/lib/assets/javascripts/unpoly/classes/css_transition.coffee +18 -27
  26. data/lib/assets/javascripts/unpoly/classes/divertible_chain.coffee +39 -0
  27. data/lib/assets/javascripts/unpoly/classes/event_listener.coffee +116 -0
  28. data/lib/assets/javascripts/unpoly/classes/extract_cascade.coffee +8 -8
  29. data/lib/assets/javascripts/unpoly/classes/extract_plan.coffee +19 -19
  30. data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +54 -31
  31. data/lib/assets/javascripts/unpoly/classes/{focus_tracker.coffee → focus_follower.coffee} +2 -2
  32. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +25 -25
  33. data/lib/assets/javascripts/unpoly/classes/html_parser.coffee +4 -11
  34. data/lib/assets/javascripts/unpoly/classes/motion_controller.coffee +157 -0
  35. data/lib/assets/javascripts/unpoly/classes/params.coffee.erb +525 -0
  36. data/lib/assets/javascripts/unpoly/classes/record.coffee +8 -2
  37. data/lib/assets/javascripts/unpoly/classes/rect.js +21 -0
  38. data/lib/assets/javascripts/unpoly/classes/request.coffee +41 -35
  39. data/lib/assets/javascripts/unpoly/classes/response.coffee +7 -3
  40. data/lib/assets/javascripts/unpoly/classes/reveal_motion.coffee +102 -0
  41. data/lib/assets/javascripts/unpoly/classes/scroll_motion.coffee +67 -0
  42. data/lib/assets/javascripts/unpoly/classes/selector.coffee +60 -0
  43. data/lib/assets/javascripts/unpoly/classes/tether.coffee +105 -0
  44. data/lib/assets/javascripts/unpoly/classes/url_set.coffee +12 -7
  45. data/lib/assets/javascripts/unpoly/element.coffee.erb +1126 -0
  46. data/lib/assets/javascripts/unpoly/event.coffee.erb +437 -0
  47. data/lib/assets/javascripts/unpoly/feedback.coffee +73 -94
  48. data/lib/assets/javascripts/unpoly/form.coffee.erb +188 -181
  49. data/lib/assets/javascripts/unpoly/{dom.coffee.erb → fragment.coffee.erb} +250 -283
  50. data/lib/assets/javascripts/unpoly/framework.coffee +67 -0
  51. data/lib/assets/javascripts/unpoly/history.coffee +29 -28
  52. data/lib/assets/javascripts/unpoly/legacy.coffee +60 -0
  53. data/lib/assets/javascripts/unpoly/link.coffee.erb +127 -119
  54. data/lib/assets/javascripts/unpoly/log.coffee +99 -19
  55. data/lib/assets/javascripts/unpoly/modal.coffee.erb +95 -118
  56. data/lib/assets/javascripts/unpoly/motion.coffee.erb +158 -138
  57. data/lib/assets/javascripts/unpoly/namespace.coffee.erb +0 -5
  58. data/lib/assets/javascripts/unpoly/popup.coffee.erb +119 -102
  59. data/lib/assets/javascripts/unpoly/protocol.coffee +11 -15
  60. data/lib/assets/javascripts/unpoly/proxy.coffee +62 -65
  61. data/lib/assets/javascripts/unpoly/radio.coffee +3 -5
  62. data/lib/assets/javascripts/unpoly/rails.coffee +8 -9
  63. data/lib/assets/javascripts/unpoly/syntax.coffee.erb +173 -125
  64. data/lib/assets/javascripts/unpoly/toast.coffee +25 -24
  65. data/lib/assets/javascripts/unpoly/tooltip.coffee +89 -79
  66. data/lib/assets/javascripts/unpoly/util.coffee.erb +579 -1074
  67. data/lib/assets/javascripts/unpoly/{layout.coffee.erb → viewport.coffee.erb} +334 -264
  68. data/lib/assets/stylesheets/unpoly/dom.sass +1 -1
  69. data/lib/assets/stylesheets/unpoly/layout.sass +2 -0
  70. data/lib/assets/stylesheets/unpoly/popup.sass +0 -1
  71. data/lib/assets/stylesheets/unpoly/tooltip.sass +17 -12
  72. data/lib/unpoly/rails/version.rb +1 -1
  73. data/package.json +1 -2
  74. data/spec_app/Gemfile +2 -1
  75. data/spec_app/Gemfile.lock +38 -27
  76. data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
  77. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -2
  78. data/spec_app/app/assets/stylesheets/integration_test.sass +14 -1
  79. data/spec_app/app/controllers/scroll_test_controller.rb +5 -0
  80. data/spec_app/app/views/css_test/modal.erb +6 -6
  81. data/spec_app/app/views/css_test/popup.erb +44 -18
  82. data/spec_app/app/views/css_test/tooltip.erb +23 -4
  83. data/spec_app/app/views/error_test/trigger.erb +1 -1
  84. data/spec_app/app/views/form_test/basics/new.erb +1 -3
  85. data/spec_app/app/views/pages/start.erb +9 -2
  86. data/spec_app/app/views/reveal_test/long1.erb +1 -1
  87. data/spec_app/app/views/reveal_test/long2.erb +1 -1
  88. data/spec_app/app/views/reveal_test/within_document_viewport.erb +24 -0
  89. data/spec_app/app/views/reveal_test/within_overflowing_div_viewport.erb +28 -0
  90. data/spec_app/app/views/scroll_test/long1.erb +30 -0
  91. data/spec_app/config/routes.rb +1 -0
  92. data/spec_app/spec/javascripts/helpers/agent_detector.coffee +3 -0
  93. data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +1 -0
  94. data/spec_app/spec/javascripts/helpers/browser_switches.js.coffee +17 -5
  95. data/spec_app/spec/javascripts/helpers/enable_logging.js.coffee +1 -1
  96. data/spec_app/spec/javascripts/helpers/fixture.js.coffee +25 -0
  97. data/spec_app/spec/javascripts/helpers/jquery_no_conflict.js +1 -0
  98. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -0
  99. data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +1 -1
  100. data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +2 -2
  101. data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +4 -1
  102. data/spec_app/spec/javascripts/helpers/remove_body_margin.js.coffee +3 -0
  103. data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +2 -1
  104. data/spec_app/spec/javascripts/helpers/reset_knife.js.coffee +2 -2
  105. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +18 -11
  106. data/spec_app/spec/javascripts/helpers/restore_body_scroll.js.coffee +3 -0
  107. data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +3 -0
  108. data/spec_app/spec/javascripts/helpers/spec_util.coffee +47 -0
  109. data/spec_app/spec/javascripts/helpers/to_be_around.js.coffee +3 -0
  110. data/spec_app/spec/javascripts/helpers/to_be_array.coffee +5 -0
  111. data/spec_app/spec/javascripts/helpers/to_be_attached.coffee +6 -2
  112. data/spec_app/spec/javascripts/helpers/to_be_blank.js.coffee +3 -0
  113. data/spec_app/spec/javascripts/helpers/to_be_detached.coffee +6 -2
  114. data/spec_app/spec/javascripts/helpers/to_be_element.js.coffee +8 -0
  115. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +3 -0
  116. data/spec_app/spec/javascripts/helpers/to_be_given.js.coffee +3 -0
  117. data/spec_app/spec/javascripts/helpers/to_be_hidden.js.coffee +8 -0
  118. data/spec_app/spec/javascripts/helpers/to_be_missing.js.coffee +3 -0
  119. data/spec_app/spec/javascripts/helpers/to_be_present.js.coffee +3 -0
  120. data/spec_app/spec/javascripts/helpers/to_be_scrolled_to.coffee +3 -0
  121. data/spec_app/spec/javascripts/helpers/to_be_visible.js.coffee +9 -0
  122. data/spec_app/spec/javascripts/helpers/to_contain.js.coffee +3 -0
  123. data/spec_app/spec/javascripts/helpers/to_end_with.js.coffee +3 -0
  124. data/spec_app/spec/javascripts/helpers/to_equal_jquery.js.coffee +1 -2
  125. data/spec_app/spec/javascripts/helpers/to_equal_node_list.coffee +7 -0
  126. data/spec_app/spec/javascripts/helpers/to_equal_via_is_equal.js.coffee +7 -0
  127. data/spec_app/spec/javascripts/helpers/to_have_class.js.coffee +10 -0
  128. data/spec_app/spec/javascripts/helpers/to_have_descendant.js.coffee +10 -0
  129. data/spec_app/spec/javascripts/helpers/to_have_length.js.coffee +8 -0
  130. data/spec_app/spec/javascripts/helpers/to_have_opacity.coffee +7 -3
  131. data/spec_app/spec/javascripts/helpers/to_have_own_property.js.coffee +3 -0
  132. data/spec_app/spec/javascripts/helpers/to_have_request_method.js.coffee +1 -0
  133. data/spec_app/spec/javascripts/helpers/to_have_text.js.coffee +9 -0
  134. data/spec_app/spec/javascripts/helpers/to_have_unhandled_rejections.coffee +0 -21
  135. data/spec_app/spec/javascripts/helpers/to_match_list.coffee +14 -0
  136. data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +3 -0
  137. data/spec_app/spec/javascripts/helpers/to_match_text.js.coffee +4 -1
  138. data/spec_app/spec/javascripts/helpers/to_match_url.coffee +1 -0
  139. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +91 -7
  140. data/spec_app/spec/javascripts/helpers/wait_until_dom_ready.js.coffee +3 -0
  141. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +23 -90
  142. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +3 -0
  143. data/spec_app/spec/javascripts/up/classes/config_spec.coffee +24 -0
  144. data/spec_app/spec/javascripts/up/classes/divertible_chain_spec.coffee +45 -0
  145. data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +5 -2
  146. data/spec_app/spec/javascripts/up/classes/params_spec.coffee +557 -0
  147. data/spec_app/spec/javascripts/up/classes/request_spec.coffee +7 -4
  148. data/spec_app/spec/javascripts/up/classes/scroll_motion_spec.js.coffee +51 -0
  149. data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +3 -0
  150. data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +3 -2
  151. data/spec_app/spec/javascripts/up/element_spec.coffee +897 -0
  152. data/spec_app/spec/javascripts/up/event_spec.js.coffee +496 -0
  153. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +69 -48
  154. data/spec_app/spec/javascripts/up/form_spec.js.coffee +252 -194
  155. data/spec_app/spec/javascripts/up/{dom_spec.js.coffee → fragment_spec.js.coffee} +381 -388
  156. data/spec_app/spec/javascripts/up/history_spec.js.coffee +21 -19
  157. data/spec_app/spec/javascripts/up/jquery_spec.js.coffee +4 -0
  158. data/spec_app/spec/javascripts/up/legacy_spec.js.coffee +27 -0
  159. data/spec_app/spec/javascripts/up/link_spec.js.coffee +163 -160
  160. data/spec_app/spec/javascripts/up/log_spec.js.coffee +85 -12
  161. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +141 -123
  162. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +117 -113
  163. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +60 -77
  164. data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +1 -0
  165. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +85 -78
  166. data/spec_app/spec/javascripts/up/radio_spec.js.coffee +29 -22
  167. data/spec_app/spec/javascripts/up/rails_spec.js.coffee +14 -13
  168. data/spec_app/spec/javascripts/up/spec_spec.js.coffee +9 -0
  169. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +96 -66
  170. data/spec_app/spec/javascripts/up/toast_spec.js.coffee +37 -0
  171. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +31 -47
  172. data/spec_app/spec/javascripts/up/util_spec.js.coffee +725 -562
  173. data/spec_app/spec/javascripts/up/{layout_spec.js.coffee → viewport_spec.js.coffee} +175 -149
  174. metadata +57 -19
  175. data/lib/assets/javascripts/unpoly-bootstrap3/layout-ext.coffee +0 -5
  176. data/lib/assets/javascripts/unpoly/bus.coffee.erb +0 -518
  177. data/lib/assets/javascripts/unpoly/classes/extract_step.coffee +0 -4
  178. data/lib/assets/javascripts/unpoly/classes/motion_tracker.coffee +0 -125
  179. data/lib/assets/javascripts/unpoly/params.coffee.erb +0 -522
  180. data/spec_app/spec/javascripts/helpers/append_fixture.js.coffee +0 -8
  181. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +0 -210
  182. data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +0 -9
  183. data/spec_app/spec/javascripts/up/params_spec.coffee +0 -768
  184. data/spec_app/vendor/asset-libs/jasmine-fixture-1.3.4/jasmine-fixture.js +0 -433
  185. data/spec_app/vendor/asset-libs/jasmine-jquery-2.1.1/.bower.json +0 -26
  186. data/spec_app/vendor/asset-libs/jasmine-jquery-2.1.1/jasmine-jquery.js +0 -838
@@ -0,0 +1,496 @@
1
+ u = up.util
2
+ e = up.element
3
+ $ = jQuery
4
+
5
+ describe 'up.event', ->
6
+
7
+ describe 'JavaScript functions', ->
8
+
9
+ describe 'up.on', ->
10
+
11
+ it 'registers a delagating event listener to the document, which passes the element as a second argument to the listener', asyncSpec (next) ->
12
+ fixture('.container .child')
13
+ observeClass = jasmine.createSpy()
14
+ up.on 'click', '.child', (event, element) ->
15
+ observeClass(element.className)
16
+
17
+ Trigger.click($('.container'))
18
+ Trigger.click($('.child'))
19
+
20
+ next =>
21
+ expect(observeClass).not.toHaveBeenCalledWith('container')
22
+ expect(observeClass).toHaveBeenCalledWith('child')
23
+
24
+ it 'calls the event listener if the event was triggered on a child of the requested selector', asyncSpec (next) ->
25
+ $container = $fixture('.container')
26
+ $child = $container.affix('.child')
27
+ listener = jasmine.createSpy()
28
+ up.on 'click', '.container', listener
29
+
30
+ Trigger.click($('.child'))
31
+
32
+ next =>
33
+ expect(listener).toHaveBeenCalledWith(
34
+ jasmine.any(MouseEvent),
35
+ $container[0],
36
+ {}
37
+ )
38
+
39
+ it 'passes the event target as the second argument if no selector was passed to up.on()', asyncSpec (next) ->
40
+ $element = $fixture('.element')
41
+ listener = jasmine.createSpy()
42
+ up.on 'click', listener
43
+ Trigger.click($element)
44
+
45
+ next =>
46
+ expect(listener).toHaveBeenCalledWith(
47
+ jasmine.any(MouseEvent),
48
+ $element[0],
49
+ {}
50
+ )
51
+
52
+ it 'allows to bind the listener to a given element', asyncSpec (next) ->
53
+ element1 = fixture('.element')
54
+ element2 = fixture('.element')
55
+ listener = jasmine.createSpy()
56
+ up.on(element1, 'click', listener)
57
+ Trigger.click(element1)
58
+
59
+ next ->
60
+ expect(listener).toHaveBeenCalledWith(
61
+ jasmine.any(MouseEvent),
62
+ element1,
63
+ {}
64
+ )
65
+ expect(listener.calls.count()).toBe(1)
66
+
67
+ it 'allows to bind the listener to a given element while also passing a selector', asyncSpec (next) ->
68
+ element1 = fixture('.element.one')
69
+ element2 = fixture('.element.two')
70
+ element2Child1 = e.affix(element2, '.child.one')
71
+ element2Child2 = e.affix(element2, '.child.two')
72
+ listener = jasmine.createSpy('event listener')
73
+ up.on(element2, 'click', '.one', listener)
74
+
75
+ Trigger.click(element2Child1)
76
+
77
+ next ->
78
+ expect(listener).toHaveBeenCalledWith(
79
+ jasmine.any(MouseEvent),
80
+ element2Child1,
81
+ {}
82
+ )
83
+ expect(listener.calls.count()).toBe(1)
84
+
85
+
86
+ it 'allows to bind the listener to an array of elements at once', asyncSpec (next) ->
87
+ element1 = fixture('.element')
88
+ element2 = fixture('.element')
89
+ listener = jasmine.createSpy()
90
+
91
+ unbindAll = up.on([element1, element2], 'click', listener)
92
+
93
+ Trigger.click(element1)
94
+
95
+ next =>
96
+ expect(listener.calls.count()).toBe(1)
97
+ expect(listener.calls.argsFor(0)[1]).toBe(element1)
98
+
99
+ Trigger.click(element2)
100
+
101
+ next =>
102
+ expect(listener.calls.count()).toBe(2)
103
+ expect(listener.calls.argsFor(1)[1]).toBe(element2)
104
+
105
+ unbindAll()
106
+
107
+ Trigger.click(element1)
108
+ Trigger.click(element2)
109
+
110
+ next =>
111
+ expect(listener.calls.count()).toBe(2)
112
+
113
+ it 'allows to explicitly bind a listener to the document', asyncSpec (next) ->
114
+ listener = jasmine.createSpy()
115
+ up.on(document, 'foo', listener)
116
+ up.emit(document, 'foo')
117
+
118
+ next ->
119
+ expect(listener).toHaveBeenCalledWith(
120
+ jasmine.any(Event),
121
+ document,
122
+ {}
123
+ )
124
+ expect(listener.calls.count()).toBe(1)
125
+
126
+ it 'allows to bind a listener to the window', asyncSpec (next) ->
127
+ listener = jasmine.createSpy()
128
+ up.on(window, 'foo', listener)
129
+ up.emit(window, 'foo')
130
+
131
+ next ->
132
+ expect(listener).toHaveBeenCalledWith(
133
+ jasmine.any(Event),
134
+ window,
135
+ {}
136
+ )
137
+ expect(listener.calls.count()).toBe(1)
138
+
139
+ it 'registers the listener to multiple, space-separated events', ->
140
+ listener = jasmine.createSpy()
141
+
142
+ up.on 'foo bar', listener
143
+
144
+ up.emit('foo')
145
+ expect(listener.calls.count()).toEqual(1)
146
+
147
+ up.emit('bar')
148
+ expect(listener.calls.count()).toEqual(2)
149
+
150
+ # it 'registers the listener to an array of event names', ->
151
+ # listener = jasmine.createSpy()
152
+ #
153
+ # up.on ['foo', 'bar'], listener
154
+ #
155
+ # up.emit('foo')
156
+ # expect(listener.calls.count()).toEqual(1)
157
+ #
158
+ # up.emit('bar')
159
+ # expect(listener.calls.count()).toEqual(2)
160
+
161
+ it 'returns a method that unregisters the event listener when called', asyncSpec (next) ->
162
+ $child = $fixture('.child')
163
+ clickSpy = jasmine.createSpy()
164
+ unsubscribe = up.on 'click', '.child', clickSpy
165
+ Trigger.click($('.child'))
166
+
167
+ next =>
168
+ expect(clickSpy.calls.count()).toEqual(1)
169
+ unsubscribe()
170
+ Trigger.click($('.child'))
171
+
172
+ next =>
173
+ expect(clickSpy.calls.count()).toEqual(1)
174
+
175
+ it 'throws an error when trying to register the same callback multiple times', ->
176
+ callback = ->
177
+ register = -> up.on 'foo', callback
178
+ register()
179
+ expect(register).toThrowError(/cannot be registered more than once/i)
180
+
181
+ it 'allows to register the same callback for different event names (bugfix)', ->
182
+ callback = ->
183
+ register = ->
184
+ up.on('foo', callback)
185
+ up.on('bar', callback)
186
+ expect(register).not.toThrowError()
187
+
188
+ it 'allows to register the same callback for different elements (bugfix)', ->
189
+ element1 = fixture('.element1')
190
+ element2 = fixture('.element2')
191
+ callback = ->
192
+ register = ->
193
+ up.on(element1, 'foo', callback)
194
+ up.on(element2, 'foo', callback)
195
+ expect(register).not.toThrowError()
196
+
197
+ it 'allows to register the same callback for different selectors (bugfix)', ->
198
+ callback = ->
199
+ register = ->
200
+ up.on('foo', '.one', callback)
201
+ up.on('foo', '.two', callback)
202
+ expect(register).not.toThrowError()
203
+
204
+ it 'does not throw an error if a callback is registered, unregistered and registered a second time', ->
205
+ callback = ->
206
+ register = -> up.on 'foo', callback
207
+ unregister = -> up.off 'foo', callback
208
+ register()
209
+ unregister()
210
+ expect(register).not.toThrowError()
211
+
212
+ describe 'passing of [up-data]', ->
213
+
214
+ it 'parses an [up-data] attribute as JSON and passes the parsed object as a third argument to the listener', asyncSpec (next) ->
215
+ observeArgs = jasmine.createSpy()
216
+ up.on 'click', '.child', (event, element, data) ->
217
+ observeArgs(element.className, data)
218
+
219
+ $child = $fixture(".child")
220
+ data = { key1: 'value1', key2: 'value2' }
221
+ $child.attr('up-data', JSON.stringify(data))
222
+
223
+ Trigger.click($child)
224
+
225
+ next =>
226
+ expect(observeArgs).toHaveBeenCalledWith('child', data)
227
+
228
+ it 'passes an empty object as a second argument to the listener if there is no [up-data] attribute', asyncSpec (next) ->
229
+ $child = $fixture('.child')
230
+ observeArgs = jasmine.createSpy()
231
+ up.on 'click', '.child', (event, element, data) ->
232
+ observeArgs(element.className, data)
233
+
234
+ Trigger.click($('.child'))
235
+
236
+ next =>
237
+ expect(observeArgs).toHaveBeenCalledWith('child', {})
238
+
239
+ it 'does not parse an [up-data] attribute if the listener function only takes one argument', asyncSpec (next) ->
240
+ parseDataSpy = spyOn(up.syntax, 'data').and.returnValue({})
241
+
242
+ $child = $fixture('.child')
243
+ up.on 'click', '.child', (event) -> # no-op
244
+
245
+ Trigger.click($child)
246
+
247
+ next =>
248
+ expect(parseDataSpy).not.toHaveBeenCalled()
249
+
250
+ it 'does not parse an [up-data] attribute if the listener function only takes two arguments', asyncSpec (next) ->
251
+ parseDataSpy = spyOn(up.syntax, 'data').and.returnValue({})
252
+
253
+ $child = $fixture('.child')
254
+ up.on 'click', '.child', (event, $element) -> # no-op
255
+
256
+ Trigger.click($child)
257
+
258
+ next =>
259
+ expect(parseDataSpy).not.toHaveBeenCalled()
260
+
261
+ # it 'allows to bind and unbind events by their old, deprecated name', ->
262
+ # warnSpy = spyOn(up, 'warn')
263
+ # listener = jasmine.createSpy('listener')
264
+ #
265
+ # # Reister listener for the old event name
266
+ # up.on('up:proxy:received', listener)
267
+ # expect(warnSpy).toHaveBeenCalled()
268
+ #
269
+ # # Emit event with new name and see that it invokes the legacy listener
270
+ # up.emit('up:proxy:loaded')
271
+ # expect(listener.calls.count()).toBe(1)
272
+ #
273
+ # # Check that up.off works with the old event name
274
+ # up.off('up:proxy:received', listener)
275
+ #
276
+ # up.emit('up:proxy:loaded')
277
+ # expect(listener.calls.count()).toBe(1)
278
+
279
+
280
+ describe 'up.$on', ->
281
+
282
+ it 'registers a delagating event listener to the document body, which passes a jQuery-wrapped element as a second argument to the listener', asyncSpec (next) ->
283
+ fixture('.container[data-mark=container] .child[data-mark=child]')
284
+ observeClass = jasmine.createSpy()
285
+ up.$on 'click', '.child', (event, $element) ->
286
+ observeClass($element.attr('data-mark'))
287
+
288
+ Trigger.click($('.container'))
289
+ Trigger.click($('.child'))
290
+
291
+ next =>
292
+ expect(observeClass).not.toHaveBeenCalledWith('container')
293
+ expect(observeClass).toHaveBeenCalledWith('child')
294
+
295
+
296
+ describe 'up.off', ->
297
+
298
+ it 'unregisters an event listener previously registered through up.on', asyncSpec (next) ->
299
+ $child = $fixture('.child')
300
+ clickSpy = jasmine.createSpy()
301
+ up.on 'click', '.child', clickSpy
302
+ Trigger.click($('.child'))
303
+ up.off 'click', '.child', clickSpy
304
+ Trigger.click($('.child'))
305
+
306
+ next =>
307
+ expect(clickSpy.calls.count()).toEqual(1)
308
+
309
+ it 'allows to unregister a single event from a group of events that were registered in a single up.on call', asyncSpec (next) ->
310
+ listener = jasmine.createSpy()
311
+ element = fixture('.element')
312
+ up.on(element, 'mouseover mouseout', listener)
313
+
314
+ up.off(element, 'mouseover', listener)
315
+ Trigger.mouseover(element)
316
+
317
+ next ->
318
+ expect(listener.calls.count()).toBe(0)
319
+
320
+ Trigger.mouseout(element)
321
+
322
+ next ->
323
+ expect(listener.calls.count()).toBe(1)
324
+
325
+ up.off(element, 'mouseout', listener)
326
+
327
+ Trigger.mouseout(element)
328
+
329
+ next =>
330
+ expect(listener.calls.count()).toBe(1)
331
+
332
+ it 'allows to unregister a single element from a group of elements that were registered in a single up.on call', asyncSpec (next) ->
333
+ listener = jasmine.createSpy()
334
+ element1 = fixture('.element1')
335
+ element2 = fixture('.element2')
336
+
337
+ up.on([element1, element2], 'mouseover', listener)
338
+
339
+ up.off(element1, 'mouseover', listener)
340
+ Trigger.mouseover(element1)
341
+
342
+ next ->
343
+ expect(listener.calls.count()).toBe(0)
344
+
345
+ Trigger.mouseover(element2)
346
+
347
+ next ->
348
+ expect(listener.calls.count()).toBe(1)
349
+
350
+ up.off(element2, 'mouseover', listener)
351
+
352
+ Trigger.mouseover(element2)
353
+
354
+ next =>
355
+ expect(listener.calls.count()).toBe(1)
356
+
357
+ # it 'throws an error if the given event listener was not registered through up.on', ->
358
+ # someFunction = ->
359
+ # offing = -> up.off 'click', '.child', someFunction
360
+ # expect(offing).toThrowError(/(not|never) registered/i)
361
+
362
+
363
+ describe 'up.$off', ->
364
+
365
+ it 'unregisters an event listener previously registered through up.$on', asyncSpec (next) ->
366
+ $child = $fixture('.child')
367
+ clickSpy = jasmine.createSpy()
368
+ up.$on 'click', '.child', clickSpy
369
+ Trigger.click($('.child'))
370
+ up.$off 'click', '.child', clickSpy
371
+ Trigger.click($('.child'))
372
+
373
+ next =>
374
+ expect(clickSpy.calls.count()).toEqual(1)
375
+
376
+
377
+ describe 'up.emit', ->
378
+
379
+ it 'triggers an event on the document', ->
380
+ emittedEvent = undefined
381
+ emittedTarget = undefined
382
+
383
+ up.on 'foo', (event, target) ->
384
+ emittedEvent = event
385
+ emittedTarget = target
386
+
387
+ expect(emittedEvent).toBeUndefined()
388
+ expect(emittedTarget).toBeUndefined()
389
+
390
+ up.emit('foo')
391
+
392
+ expect(emittedEvent).toBeDefined()
393
+ expect(emittedEvent.preventDefault).toBeDefined()
394
+ expect(emittedTarget).toEqual(document)
395
+
396
+ it 'triggers an event that bubbles', ->
397
+ $parent = $fixture('.parent')
398
+ $element = $parent.affix('.element')
399
+ callback = jasmine.createSpy('event handler')
400
+ $parent[0].addEventListener('custom:name', callback)
401
+ up.emit($element[0], 'custom:name')
402
+ expect(callback).toHaveBeenCalled()
403
+
404
+ it 'triggers an event that can be stopped from propagating', ->
405
+ $parent = $fixture('.parent')
406
+ $element = $parent.affix('.element')
407
+ callback = jasmine.createSpy('event handler')
408
+ $parent[0].addEventListener('custom:name', callback)
409
+ $element[0].addEventListener('custom:name', (event) -> event.stopPropagation())
410
+ up.emit($element[0], 'custom:name')
411
+ expect(callback).not.toHaveBeenCalled()
412
+
413
+ it 'triggers an event that can have its default prevented (IE11 bugfix)', ->
414
+ element = fixture('.element')
415
+ element.addEventListener('custom:name', (event) -> event.preventDefault())
416
+ event = up.emit(element, 'custom:name')
417
+ expect(event.defaultPrevented).toBe(true)
418
+
419
+ describe 'custom event properties', ->
420
+
421
+ it 'accepts custom event properties that can be accessed from an up.on() handler', ->
422
+ emittedEvent = undefined
423
+ up.on 'foo', (event) -> emittedEvent = event
424
+
425
+ up.emit('foo', { customField: 'custom-value' })
426
+
427
+ expect(emittedEvent.customField).toEqual('custom-value')
428
+
429
+ it 'accepts custom event properties that can be accessed from an jQuery.on() handler', ->
430
+ emittedEvent = undefined
431
+ $(document).on 'foo', (event) -> emittedEvent = event.originalEvent
432
+
433
+ up.emit('foo', { customField: 'custom-value' })
434
+
435
+ expect(emittedEvent.customField).toEqual('custom-value')
436
+
437
+ it 'accepts custom event properties that can be accessed from an addEventListener() handler', ->
438
+ emittedEvent = undefined
439
+ document.addEventListener 'foo', (event) -> emittedEvent = event
440
+
441
+ up.emit('foo', { customField: 'custom-value' })
442
+
443
+ expect(emittedEvent.customField).toEqual('custom-value')
444
+
445
+ it 'triggers an event on an element passed as { target } option', ->
446
+ emittedEvent = undefined
447
+ emittedElement = undefined
448
+
449
+ element = fixture('.element')
450
+
451
+ up.on 'foo', (event, element) ->
452
+ emittedEvent = event
453
+ emittedElement = element
454
+
455
+ up.emit('foo', target: element)
456
+
457
+ expect(emittedEvent).toBeDefined()
458
+ expect(emittedElement).toEqual(element)
459
+
460
+ expect(emittedEvent.target).toEqual(element)
461
+
462
+ it 'triggers an event on an element passed as the first argument', ->
463
+ emittedEvent = undefined
464
+ emittedElement = undefined
465
+
466
+ element = fixture('.element')
467
+
468
+ up.on 'foo', (event, element) ->
469
+ emittedEvent = event
470
+ emittedElement = element
471
+
472
+ up.emit(element, 'foo')
473
+
474
+ expect(emittedEvent).toBeDefined()
475
+ expect(emittedElement).toEqual(element)
476
+
477
+ expect(emittedEvent.target).toEqual(element)
478
+
479
+ describe 'up.event.whenEmitted', ->
480
+
481
+ it 'emits the event and fulfills the returned promise when no listener calls event.preventDefault()', (done) ->
482
+ eventListener = jasmine.createSpy('event listener')
483
+ up.on('my:event', eventListener)
484
+ promise = up.event.whenEmitted('my:event', key: 'value')
485
+ promiseState(promise).then (result) ->
486
+ expect(eventListener).toHaveBeenCalledWith(jasmine.objectContaining(key: 'value'), jasmine.anything(), jasmine.anything())
487
+ expect(result.state).toEqual('fulfilled')
488
+ done()
489
+
490
+ it 'emits the event and rejects the returned promise when any listener calls event.preventDefault()', (done) ->
491
+ eventListener = (event) -> event.preventDefault()
492
+ up.on('my:event', eventListener)
493
+ promise = up.event.whenEmitted('my:event', key: 'value')
494
+ promiseState(promise).then (result) ->
495
+ expect(result.state).toEqual('rejected')
496
+ done()