unpoly-rails 0.56.7 → 0.57.0
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.
Potentially problematic release.
This version of unpoly-rails might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1
- data/dist/unpoly.js +1569 -793
- data/dist/unpoly.min.js +4 -4
- data/lib/assets/javascripts/unpoly.coffee +2 -0
- data/lib/assets/javascripts/unpoly/browser.coffee.erb +25 -41
- data/lib/assets/javascripts/unpoly/bus.coffee.erb +20 -6
- data/lib/assets/javascripts/unpoly/classes/cache.coffee +23 -13
- data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +87 -0
- data/lib/assets/javascripts/unpoly/classes/focus_tracker.coffee +29 -0
- data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +7 -4
- data/lib/assets/javascripts/unpoly/classes/record.coffee +1 -1
- data/lib/assets/javascripts/unpoly/classes/request.coffee +38 -45
- data/lib/assets/javascripts/unpoly/classes/response.coffee +16 -1
- data/lib/assets/javascripts/unpoly/classes/store/memory.coffee +26 -0
- data/lib/assets/javascripts/unpoly/classes/store/session.coffee +59 -0
- data/lib/assets/javascripts/unpoly/cookie.coffee +56 -0
- data/lib/assets/javascripts/unpoly/dom.coffee.erb +67 -39
- data/lib/assets/javascripts/unpoly/feedback.coffee +2 -2
- data/lib/assets/javascripts/unpoly/form.coffee.erb +23 -12
- data/lib/assets/javascripts/unpoly/history.coffee +2 -2
- data/lib/assets/javascripts/unpoly/layout.coffee.erb +118 -99
- data/lib/assets/javascripts/unpoly/link.coffee.erb +12 -5
- data/lib/assets/javascripts/unpoly/log.coffee +6 -5
- data/lib/assets/javascripts/unpoly/modal.coffee.erb +9 -2
- data/lib/assets/javascripts/unpoly/motion.coffee.erb +2 -6
- data/lib/assets/javascripts/unpoly/namespace.coffee.erb +2 -2
- data/lib/assets/javascripts/unpoly/params.coffee.erb +522 -0
- data/lib/assets/javascripts/unpoly/popup.coffee.erb +3 -3
- data/lib/assets/javascripts/unpoly/proxy.coffee +42 -34
- data/lib/assets/javascripts/unpoly/{syntax.coffee → syntax.coffee.erb} +59 -117
- data/lib/assets/javascripts/unpoly/{util.coffee → util.coffee.erb} +206 -171
- data/lib/unpoly/rails/version.rb +1 -1
- data/package.json +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/assets/javascripts/integration_test.coffee +0 -4
- data/spec_app/app/assets/stylesheets/integration_test.sass +7 -1
- data/spec_app/app/controllers/pages_controller.rb +4 -0
- data/spec_app/app/views/form_test/basics/new.erb +34 -5
- data/spec_app/app/views/form_test/submission_result.erb +2 -2
- data/spec_app/app/views/form_test/uploads/new.erb +15 -2
- data/spec_app/app/views/hash_test/unpoly.erb +30 -0
- data/spec_app/app/views/pages/start.erb +2 -1
- data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +17 -2
- data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +5 -0
- data/spec_app/spec/javascripts/helpers/to_be_error.coffee +1 -1
- data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +5 -0
- data/spec_app/spec/javascripts/up/browser_spec.js.coffee +8 -8
- data/spec_app/spec/javascripts/up/bus_spec.js.coffee +58 -20
- data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +78 -0
- data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +31 -0
- data/spec_app/spec/javascripts/up/classes/request_spec.coffee +50 -0
- data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +67 -0
- data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +113 -0
- data/spec_app/spec/javascripts/up/dom_spec.js.coffee +133 -45
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +13 -13
- data/spec_app/spec/javascripts/up/layout_spec.js.coffee +110 -26
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +1 -1
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +1 -0
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +52 -51
- data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +2 -2
- data/spec_app/spec/javascripts/up/params_spec.coffee +768 -0
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +75 -36
- data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +48 -15
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +148 -131
- metadata +17 -5
- data/spec_app/spec/javascripts/up/classes/.keep +0 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
#describe 'up.FocusTracker', ->
|
2
|
+
#
|
3
|
+
# describe '#lastField', ->
|
4
|
+
#
|
5
|
+
# it 'returns undefined if no field is focused', ->
|
6
|
+
# tracker = new up.FocusTracker()
|
7
|
+
# expect(tracker.lastField()).toBeUndefined()
|
8
|
+
#
|
9
|
+
# it 'returns a <input type="text"> after it was focused', ->
|
10
|
+
# tracker = new up.FocusTracker()
|
11
|
+
# $form = affix('form')
|
12
|
+
# $input = $form.affix('input[type=text]')
|
13
|
+
# $input.focus()
|
14
|
+
# expect(tracker.lastField()).toEqual($input[0])
|
15
|
+
#
|
16
|
+
# it 'returns a <select> after it was focused', ->
|
17
|
+
# tracker = new up.FocusTracker()
|
18
|
+
# $form = affix('form')
|
19
|
+
# $select = $form.affix('select')
|
20
|
+
# $option = $select.affix('option')
|
21
|
+
# $select.focus()
|
22
|
+
# expect(tracker.lastField()).toEqual($select[0])
|
23
|
+
#
|
24
|
+
# it 'returns the field that was most recently focused after a series of focus/blur'
|
25
|
+
#
|
26
|
+
# it 'returns undefined after a field was focused, but then detached'
|
27
|
+
#
|
28
|
+
# it 'returns a previously focused field for some time after it was blurred, so we can retrieve the last field after the user submits'
|
29
|
+
#
|
30
|
+
# it 'returns undefined after a field was blurred and some time has passed'
|
31
|
+
#
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe 'up.Request', ->
|
2
|
+
|
3
|
+
describe '#url', ->
|
4
|
+
|
5
|
+
it 'returns the given URL', ->
|
6
|
+
request = new up.Request(url: 'http://host.com/foo')
|
7
|
+
expect(request.url).toEqual('http://host.com/foo')
|
8
|
+
|
9
|
+
it 'does not include a hash anchor of the constructed URL', ->
|
10
|
+
request = new up.Request(url: 'http://host.com/foo#hash')
|
11
|
+
expect(request.url).toEqual('http://host.com/foo')
|
12
|
+
|
13
|
+
it "merges { params } for HTTP methods that don't allow a payload", ->
|
14
|
+
request = new up.Request(url: 'http://host.com/foo?urlKey=urlValue', params: { paramsKey: 'paramsValue' }, method: 'get')
|
15
|
+
expect(request.url).toEqual('http://host.com/foo?urlKey=urlValue¶msKey=paramsValue')
|
16
|
+
|
17
|
+
it 'excludes { params } for HTTP methods that allow a payload', ->
|
18
|
+
request = new up.Request(url: 'http://host.com/foo?key=value', method: 'post')
|
19
|
+
expect(request.url).toEqual('http://host.com/foo')
|
20
|
+
|
21
|
+
describe '#method', ->
|
22
|
+
|
23
|
+
it 'defaults to "GET"', ->
|
24
|
+
request = new up.Request(url: 'http://host.com/foo')
|
25
|
+
expect(request.method).toEqual('GET')
|
26
|
+
|
27
|
+
describe '#hash', ->
|
28
|
+
|
29
|
+
it 'returns the hash anchor from the constructed URL', ->
|
30
|
+
request = new up.Request(url: 'http://host.com/foo#hash')
|
31
|
+
expect(request.hash).toEqual('#hash')
|
32
|
+
|
33
|
+
it 'returns undefined if the constructed URL had no hash anchor', ->
|
34
|
+
request = new up.Request(url: 'http://host.com/foo')
|
35
|
+
expect(request.hash).toBeUndefined()
|
36
|
+
|
37
|
+
describe '#params', ->
|
38
|
+
|
39
|
+
it 'returns the constructed params for HTTP methods that allow a payload', ->
|
40
|
+
params = { key: 'value' }
|
41
|
+
request = new up.Request(url: 'http://host.com/foo', params: params, method: 'post')
|
42
|
+
expect(request.params).toEqual(params)
|
43
|
+
|
44
|
+
it "returns undefined for HTTP methods that don't allow a payload", ->
|
45
|
+
request = new up.Request(url: 'http://host.com/foo', params: { key: 'value' }, method: 'get')
|
46
|
+
expect(request.params).toBeUndefined()
|
47
|
+
|
48
|
+
it 'returns the merged { params } and params from the URL for HTTP methods that allow a payload', ->
|
49
|
+
request = new up.Request(url: 'http://host.com/foo?urlKey=urlValue', params: { paramsKey: 'paramsValue' }, method: 'post')
|
50
|
+
expect(request.params).toEqual(paramsKey: 'paramsValue', urlKey: 'urlValue')
|
@@ -0,0 +1,67 @@
|
|
1
|
+
describe 'up.store.Memory', ->
|
2
|
+
|
3
|
+
describe '#get', ->
|
4
|
+
|
5
|
+
it 'returns an item that was previously set', ->
|
6
|
+
store = new up.store.Memory()
|
7
|
+
store.set('foo', 'value of foo')
|
8
|
+
store.set('bar', 'value of bar')
|
9
|
+
|
10
|
+
expect(store.get('foo')).toEqual('value of foo')
|
11
|
+
expect(store.get('bar')).toEqual('value of bar')
|
12
|
+
|
13
|
+
it 'returns undefined if no item with that key was set', ->
|
14
|
+
store = new up.store.Memory()
|
15
|
+
store.set('foo', 'value of foo')
|
16
|
+
|
17
|
+
expect(store.get('bar')).toBeUndefined()
|
18
|
+
|
19
|
+
describe '#keys', ->
|
20
|
+
|
21
|
+
it 'returns an array of keys in the store', ->
|
22
|
+
store = new up.store.Memory()
|
23
|
+
store.set('foo', 'value of foo')
|
24
|
+
store.set('bar', 'value of bar')
|
25
|
+
|
26
|
+
expect(store.keys().sort()).toEqual ['bar', 'foo']
|
27
|
+
|
28
|
+
it 'does not return keys for entries that were removed (bugfix)', ->
|
29
|
+
store = new up.store.Memory()
|
30
|
+
store.set('foo', 'value of foo')
|
31
|
+
store.set('bar', 'value of bar')
|
32
|
+
store.remove('bar')
|
33
|
+
|
34
|
+
expect(store.keys().sort()).toEqual ['foo']
|
35
|
+
|
36
|
+
describe '#values', ->
|
37
|
+
|
38
|
+
it 'returns an array of values in the store', ->
|
39
|
+
store = new up.store.Memory()
|
40
|
+
store.set('foo', 'value of foo')
|
41
|
+
store.set('bar', 'value of bar')
|
42
|
+
|
43
|
+
expect(store.values().sort()).toEqual ['value of bar', 'value of foo']
|
44
|
+
|
45
|
+
describe '#clear', ->
|
46
|
+
|
47
|
+
it 'removes all keys from the store', ->
|
48
|
+
store = new up.store.Memory()
|
49
|
+
store.set('foo', 'value of foo')
|
50
|
+
store.set('bar', 'value of bar')
|
51
|
+
|
52
|
+
store.clear()
|
53
|
+
|
54
|
+
expect(store.get('foo')).toBeUndefined()
|
55
|
+
expect(store.get('bar')).toBeUndefined()
|
56
|
+
|
57
|
+
describe '#remove', ->
|
58
|
+
|
59
|
+
it 'removes the given key from the store', ->
|
60
|
+
store = new up.store.Memory()
|
61
|
+
store.set('foo', 'value of foo')
|
62
|
+
store.set('bar', 'value of bar')
|
63
|
+
|
64
|
+
store.remove('foo')
|
65
|
+
|
66
|
+
expect(store.get('foo')).toBeUndefined()
|
67
|
+
expect(store.get('bar')).toEqual('value of bar')
|
@@ -0,0 +1,113 @@
|
|
1
|
+
describe 'up.store.Session', ->
|
2
|
+
|
3
|
+
u = up.util
|
4
|
+
|
5
|
+
afterEach ->
|
6
|
+
sessionStorage.removeItem('spec')
|
7
|
+
|
8
|
+
describe '#get', ->
|
9
|
+
|
10
|
+
it 'returns an item that was previously set', ->
|
11
|
+
store = new up.store.Session('spec')
|
12
|
+
store.set('foo', 'value of foo')
|
13
|
+
store.set('bar', 'value of bar')
|
14
|
+
|
15
|
+
expect(store.get('foo')).toEqual('value of foo')
|
16
|
+
expect(store.get('bar')).toEqual('value of bar')
|
17
|
+
|
18
|
+
it 'returns undefined if no item with that key was set', ->
|
19
|
+
store = new up.store.Session('spec')
|
20
|
+
store.set('foo', 'value of foo')
|
21
|
+
|
22
|
+
expect(store.get('bar')).toBeUndefined()
|
23
|
+
|
24
|
+
it 'does not read keys from a store with anotther root key', ->
|
25
|
+
store = new up.store.Session('spec.v1')
|
26
|
+
store.set('foo', 'value of foo')
|
27
|
+
expect(store.get('foo')).toEqual('value of foo')
|
28
|
+
|
29
|
+
store = new up.store.Session('spec.v2')
|
30
|
+
expect(store.get('foo')).toBeUndefined()
|
31
|
+
|
32
|
+
describe '#set', ->
|
33
|
+
|
34
|
+
it 'stores the given item in window.sessionStorage where it survives a follow without Unpoly', ->
|
35
|
+
store = new up.store.Session('spec')
|
36
|
+
store.set('foo', 'value of foo')
|
37
|
+
|
38
|
+
expect(window.sessionStorage.getItem('spec')).toContain('foo')
|
39
|
+
|
40
|
+
it 'stores boolean values across sessions', ->
|
41
|
+
store1 = new up.store.Session('spec')
|
42
|
+
store1.set('foo', true)
|
43
|
+
store1.set('bar', false)
|
44
|
+
|
45
|
+
store2 = new up.store.Session('spec')
|
46
|
+
expect(store2.get('foo')).toEqual(true)
|
47
|
+
expect(store2.get('bar')).toEqual(false)
|
48
|
+
|
49
|
+
it 'stores number values across sessions', ->
|
50
|
+
store1 = new up.store.Session('spec')
|
51
|
+
store1.set('foo', 123)
|
52
|
+
|
53
|
+
store2 = new up.store.Session('spec')
|
54
|
+
expect(store2.get('foo')).toEqual(123)
|
55
|
+
|
56
|
+
it 'stores structured values across sessions', ->
|
57
|
+
store1 = new up.store.Session('spec')
|
58
|
+
store1.set('foo', { bar: ['baz', 'bam'] })
|
59
|
+
|
60
|
+
store2 = new up.store.Session('spec')
|
61
|
+
storedValue = store2.get('foo')
|
62
|
+
expect(u.isObject(storedValue)).toBe(true)
|
63
|
+
expect(storedValue).toEqual { bar: ['baz', 'bam'] }
|
64
|
+
|
65
|
+
describe '#keys', ->
|
66
|
+
|
67
|
+
it 'returns an array of keys in the store', ->
|
68
|
+
store = new up.store.Session('spec')
|
69
|
+
store.set('foo', 'value of foo')
|
70
|
+
store.set('bar', 'value of bar')
|
71
|
+
|
72
|
+
expect(store.keys().sort()).toEqual ['bar', 'foo']
|
73
|
+
|
74
|
+
it 'does not return keys for entries that were removed (bugfix)', ->
|
75
|
+
store = new up.store.Session('spec')
|
76
|
+
store.set('foo', 'value of foo')
|
77
|
+
store.set('bar', 'value of bar')
|
78
|
+
store.remove('bar')
|
79
|
+
|
80
|
+
expect(store.keys().sort()).toEqual ['foo']
|
81
|
+
|
82
|
+
describe '#values', ->
|
83
|
+
|
84
|
+
it 'returns an array of values in the store', ->
|
85
|
+
store = new up.store.Session('spec')
|
86
|
+
store.set('foo', 'value of foo')
|
87
|
+
store.set('bar', 'value of bar')
|
88
|
+
|
89
|
+
expect(store.values().sort()).toEqual ['value of bar', 'value of foo']
|
90
|
+
|
91
|
+
describe '#clear', ->
|
92
|
+
|
93
|
+
it 'removes all keys from the store', ->
|
94
|
+
store = new up.store.Session('spec')
|
95
|
+
store.set('foo', 'value of foo')
|
96
|
+
store.set('bar', 'value of bar')
|
97
|
+
|
98
|
+
store.clear()
|
99
|
+
|
100
|
+
expect(store.get('foo')).toBeUndefined()
|
101
|
+
expect(store.get('bar')).toBeUndefined()
|
102
|
+
|
103
|
+
describe '#remove', ->
|
104
|
+
|
105
|
+
it 'removes the given key from the store', ->
|
106
|
+
store = new up.store.Session('spec')
|
107
|
+
store.set('foo', 'value of foo')
|
108
|
+
store.set('bar', 'value of bar')
|
109
|
+
|
110
|
+
store.remove('foo')
|
111
|
+
|
112
|
+
expect(store.get('foo')).toBeUndefined()
|
113
|
+
expect(store.get('bar')).toEqual('value of bar')
|
@@ -52,7 +52,7 @@ describe 'up.dom', ->
|
|
52
52
|
|
53
53
|
it 'returns a promise that will be fulfilled once the server response was received and the swap transition has completed', asyncSpec (next) ->
|
54
54
|
resolution = jasmine.createSpy()
|
55
|
-
promise = up.replace('.middle', '/path', transition: 'cross-fade', duration:
|
55
|
+
promise = up.replace('.middle', '/path', transition: 'cross-fade', duration: 200)
|
56
56
|
promise.then(resolution)
|
57
57
|
expect(resolution).not.toHaveBeenCalled()
|
58
58
|
expect($('.middle')).toHaveText('old-middle')
|
@@ -61,17 +61,17 @@ describe 'up.dom', ->
|
|
61
61
|
@respond()
|
62
62
|
expect(resolution).not.toHaveBeenCalled()
|
63
63
|
|
64
|
-
next.after
|
64
|
+
next.after 100, =>
|
65
65
|
expect(resolution).not.toHaveBeenCalled()
|
66
66
|
|
67
|
-
next.after
|
67
|
+
next.after 200, =>
|
68
68
|
expect(resolution).toHaveBeenCalled()
|
69
69
|
|
70
|
-
describe 'with {
|
70
|
+
describe 'with { params } option', ->
|
71
71
|
|
72
72
|
it "uses the given params as a non-GET request's payload", asyncSpec (next) ->
|
73
73
|
givenParams = { 'foo-key': 'foo-value', 'bar-key': 'bar-value' }
|
74
|
-
up.replace('.middle', '/path', method: 'put',
|
74
|
+
up.replace('.middle', '/path', method: 'put', params: givenParams)
|
75
75
|
|
76
76
|
next =>
|
77
77
|
expect(@lastRequest().data()['foo-key']).toEqual(['foo-value'])
|
@@ -79,7 +79,7 @@ describe 'up.dom', ->
|
|
79
79
|
|
80
80
|
it "encodes the given params into the URL of a GET request", asyncSpec (next) ->
|
81
81
|
givenParams = { 'foo-key': 'foo-value', 'bar-key': 'bar-value' }
|
82
|
-
up.replace('.middle', '/path', method: 'get',
|
82
|
+
up.replace('.middle', '/path', method: 'get', params: givenParams)
|
83
83
|
next => expect(@lastRequest().url).toMatchUrl('/path?foo-key=foo-value&bar-key=bar-value')
|
84
84
|
|
85
85
|
it 'uses a HTTP method given as { method } option', asyncSpec (next) ->
|
@@ -201,8 +201,8 @@ describe 'up.dom', ->
|
|
201
201
|
next => @respond(responseHeaders: { 'X-Up-Location': '/other-path' })
|
202
202
|
next => expect(location.href).toMatchUrl('/other-path')
|
203
203
|
|
204
|
-
it 'adds params from a {
|
205
|
-
up.replace('.middle', '/path',
|
204
|
+
it 'adds params from a { params } option to the URL of a GET request', asyncSpec (next) ->
|
205
|
+
up.replace('.middle', '/path', params: { 'foo-key': 'foo value', 'bar-key': 'bar value' })
|
206
206
|
next => @respond()
|
207
207
|
next => expect(location.href).toMatchUrl('/path?foo-key=foo%20value&bar-key=bar%20value')
|
208
208
|
|
@@ -1269,6 +1269,8 @@ describe 'up.dom', ->
|
|
1269
1269
|
describe 'with { reveal } option', ->
|
1270
1270
|
|
1271
1271
|
beforeEach ->
|
1272
|
+
up.history.config.enabled = true
|
1273
|
+
|
1272
1274
|
@revealedHTML = []
|
1273
1275
|
@revealedText = []
|
1274
1276
|
@revealOptions = {}
|
@@ -1345,13 +1347,13 @@ describe 'up.dom', ->
|
|
1345
1347
|
up.replace('.middle', '/path', failTarget: '.fail-target', reveal: false, failReveal: '&', origin: $origin)
|
1346
1348
|
|
1347
1349
|
next =>
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1350
|
+
@respondWith
|
1351
|
+
status: 500
|
1352
|
+
responseText: """
|
1353
|
+
<div class="fail-target">
|
1354
|
+
new fail target text
|
1355
|
+
</div>
|
1356
|
+
"""
|
1355
1357
|
|
1356
1358
|
next =>
|
1357
1359
|
expect(@revealedText).toEqual ['origin text']
|
@@ -1370,8 +1372,71 @@ describe 'up.dom', ->
|
|
1370
1372
|
|
1371
1373
|
describe 'when there is an anchor #hash in the URL', ->
|
1372
1374
|
|
1373
|
-
it 'scrolls to the top of
|
1375
|
+
it 'scrolls to the top of an element with the ID of that #hash', asyncSpec (next) ->
|
1376
|
+
up.replace('.middle', '/path#hash', reveal: true)
|
1377
|
+
@responseText =
|
1378
|
+
"""
|
1379
|
+
<div class="middle">
|
1380
|
+
<div id="hash"></div>
|
1381
|
+
</div>
|
1382
|
+
"""
|
1383
|
+
|
1384
|
+
next =>
|
1385
|
+
@respond()
|
1386
|
+
|
1387
|
+
next =>
|
1388
|
+
expect(@revealedHTML).toEqual ['<div id="hash"></div>']
|
1389
|
+
expect(@revealOptions).toEqual jasmine.objectContaining(top: true)
|
1390
|
+
|
1391
|
+
it "scrolls to the top of an <a> element with the name of that hash", asyncSpec (next) ->
|
1374
1392
|
up.replace('.middle', '/path#three', reveal: true)
|
1393
|
+
@responseText =
|
1394
|
+
"""
|
1395
|
+
<div class="middle">
|
1396
|
+
<a name="three"></a>
|
1397
|
+
</div>
|
1398
|
+
"""
|
1399
|
+
|
1400
|
+
next =>
|
1401
|
+
@respond()
|
1402
|
+
|
1403
|
+
next =>
|
1404
|
+
expect(@revealedHTML).toEqual ['<a name="three"></a>']
|
1405
|
+
expect(@revealOptions).toEqual jasmine.objectContaining(top: true)
|
1406
|
+
|
1407
|
+
it "scrolls to a hash that includes a dot character ('.') (bugfix)", asyncSpec (next) ->
|
1408
|
+
up.replace('.middle', '/path#foo.bar', reveal: true)
|
1409
|
+
@responseText =
|
1410
|
+
"""
|
1411
|
+
<div class="middle">
|
1412
|
+
<a name="foo.bar"></a>
|
1413
|
+
</div>
|
1414
|
+
"""
|
1415
|
+
|
1416
|
+
next =>
|
1417
|
+
@respond()
|
1418
|
+
|
1419
|
+
next =>
|
1420
|
+
expect(@revealedHTML).toEqual ['<a name="foo.bar"></a>']
|
1421
|
+
expect(@revealOptions).toEqual jasmine.objectContaining(top: true)
|
1422
|
+
|
1423
|
+
it 'does not scroll if { reveal: false } is also set', asyncSpec (next) ->
|
1424
|
+
up.replace('.middle', '/path#hash', reveal: false)
|
1425
|
+
@responseText =
|
1426
|
+
"""
|
1427
|
+
<div class="middle">
|
1428
|
+
<div id="hash"></div>
|
1429
|
+
</div>
|
1430
|
+
"""
|
1431
|
+
|
1432
|
+
next =>
|
1433
|
+
@respond()
|
1434
|
+
|
1435
|
+
next =>
|
1436
|
+
expect(@revealMock).not.toHaveBeenCalled()
|
1437
|
+
|
1438
|
+
it 'reveals multiple consecutive #hash targets with the same URL (bugfix)', asyncSpec (next) ->
|
1439
|
+
up.replace('.middle', '/path#two', reveal: true)
|
1375
1440
|
@responseText =
|
1376
1441
|
"""
|
1377
1442
|
<div class="middle">
|
@@ -1383,25 +1448,26 @@ describe 'up.dom', ->
|
|
1383
1448
|
|
1384
1449
|
next =>
|
1385
1450
|
@respond()
|
1451
|
+
up.replace('.middle', '/path#three', reveal: true)
|
1452
|
+
# response is already cached
|
1386
1453
|
|
1387
1454
|
next =>
|
1388
|
-
expect(@
|
1389
|
-
expect(@revealOptions).toEqual jasmine.objectContaining(top: true)
|
1455
|
+
expect(@revealedText).toEqual ['two', 'three']
|
1390
1456
|
|
1391
|
-
it "
|
1392
|
-
up.replace('.middle', '/path#
|
1457
|
+
it "does not scroll if there is no element with the ID of that #hash", asyncSpec (next) ->
|
1458
|
+
up.replace('.middle', '/path#hash', reveal: true)
|
1459
|
+
@responseText =
|
1460
|
+
"""
|
1461
|
+
<div class="middle">
|
1462
|
+
</div>
|
1463
|
+
"""
|
1393
1464
|
|
1394
1465
|
next =>
|
1395
|
-
@responseText =
|
1396
|
-
"""
|
1397
|
-
<div class="middle">
|
1398
|
-
new-middle
|
1399
|
-
</div>
|
1400
|
-
"""
|
1401
1466
|
@respond()
|
1402
1467
|
|
1403
1468
|
next =>
|
1404
|
-
expect(@
|
1469
|
+
expect(@revealMock).not.toHaveBeenCalled()
|
1470
|
+
|
1405
1471
|
|
1406
1472
|
it 'reveals a new element that is being appended', (done) ->
|
1407
1473
|
promise = up.replace('.middle:after', '/path', reveal: true)
|
@@ -1621,7 +1687,7 @@ describe 'up.dom', ->
|
|
1621
1687
|
|
1622
1688
|
it 'calls destructors when the replaced element is a singleton element like <body> (bugfix)', asyncSpec (next) ->
|
1623
1689
|
# shouldSwapElementsDirectly() is true for body, but can't have the example replace the Jasmine test runner UI
|
1624
|
-
up.
|
1690
|
+
up.util.knife.mock('isSingletonElement').and.callFake ($element) -> $element.is('.container')
|
1625
1691
|
destructor = jasmine.createSpy('destructor')
|
1626
1692
|
up.compiler '.container', -> destructor
|
1627
1693
|
$container = affix('.container')
|
@@ -1696,7 +1762,7 @@ describe 'up.dom', ->
|
|
1696
1762
|
|
1697
1763
|
it 'morphs between the old and new element', asyncSpec (next) ->
|
1698
1764
|
affix('.element.v1').text('version 1')
|
1699
|
-
up.extract('.element', '<div class="element v2">version 2</div>', transition: 'cross-fade', duration:
|
1765
|
+
up.extract('.element', '<div class="element v2">version 2</div>', transition: 'cross-fade', duration: 200, easing: 'linear')
|
1700
1766
|
|
1701
1767
|
$old = undefined
|
1702
1768
|
$new = undefined
|
@@ -1706,23 +1772,23 @@ describe 'up.dom', ->
|
|
1706
1772
|
$new = $('.element.v2')
|
1707
1773
|
|
1708
1774
|
expect($old).toHaveLength(1)
|
1709
|
-
expect(u.opacity($old)).toBeAround(1.0, 0.
|
1775
|
+
expect(u.opacity($old)).toBeAround(1.0, 0.15)
|
1710
1776
|
|
1711
1777
|
expect($new).toHaveLength(1)
|
1712
|
-
expect(u.opacity($new)).toBeAround(0.0, 0.
|
1778
|
+
expect(u.opacity($new)).toBeAround(0.0, 0.15)
|
1713
1779
|
|
1714
|
-
next.after
|
1715
|
-
expect(u.opacity($old)).toBeAround(0.5, 0.
|
1716
|
-
expect(u.opacity($new)).toBeAround(0.5, 0.
|
1780
|
+
next.after 100, =>
|
1781
|
+
expect(u.opacity($old)).toBeAround(0.5, 0.3)
|
1782
|
+
expect(u.opacity($new)).toBeAround(0.5, 0.3)
|
1717
1783
|
|
1718
|
-
next.after (
|
1784
|
+
next.after (100 + 70), =>
|
1719
1785
|
expect(u.opacity($new)).toBeAround(1.0, 0.1)
|
1720
1786
|
expect($old).toBeDetached()
|
1721
1787
|
|
1722
1788
|
|
1723
1789
|
it 'ignores a { transition } option when replacing a singleton element like <body>', asyncSpec (next) ->
|
1724
1790
|
# shouldSwapElementsDirectly() is true for body, but can't have the example replace the Jasmine test runner UI
|
1725
|
-
up.
|
1791
|
+
up.util.knife.mock('isSingletonElement').and.callFake ($element) -> $element.is('.container')
|
1726
1792
|
|
1727
1793
|
affix('.container').text('old text')
|
1728
1794
|
|
@@ -1814,7 +1880,7 @@ describe 'up.dom', ->
|
|
1814
1880
|
promise.then(resolution)
|
1815
1881
|
expect(resolution).not.toHaveBeenCalled()
|
1816
1882
|
|
1817
|
-
u.setTimer
|
1883
|
+
u.setTimer 20, ->
|
1818
1884
|
expect(resolution).not.toHaveBeenCalled()
|
1819
1885
|
|
1820
1886
|
u.setTimer 200, ->
|
@@ -1991,7 +2057,6 @@ describe 'up.dom', ->
|
|
1991
2057
|
|
1992
2058
|
it "only emits an event up:fragment:kept, but not an event up:fragment:inserted", asyncSpec (next) ->
|
1993
2059
|
insertedListener = jasmine.createSpy('subscriber to up:fragment:inserted')
|
1994
|
-
up.on('up:fragment:inserted', insertedListener)
|
1995
2060
|
keptListener = jasmine.createSpy('subscriber to up:fragment:kept')
|
1996
2061
|
up.on('up:fragment:kept', keptListener)
|
1997
2062
|
up.on 'up:fragment:inserted', insertedListener
|
@@ -2323,15 +2388,15 @@ describe 'up.dom', ->
|
|
2323
2388
|
|
2324
2389
|
it 'runs an animation before removal with { animate } option', asyncSpec (next) ->
|
2325
2390
|
$element = affix('.element')
|
2326
|
-
up.destroy($element, animation: 'fade-out', duration:
|
2391
|
+
up.destroy($element, animation: 'fade-out', duration: 200, easing: 'linear')
|
2327
2392
|
|
2328
2393
|
next ->
|
2329
|
-
expect($element).toHaveOpacity(1.0, 0.
|
2394
|
+
expect($element).toHaveOpacity(1.0, 0.15)
|
2330
2395
|
|
2331
|
-
next.after
|
2332
|
-
expect($element).toHaveOpacity(0.5, 0.
|
2396
|
+
next.after 100, ->
|
2397
|
+
expect($element).toHaveOpacity(0.5, 0.3)
|
2333
2398
|
|
2334
|
-
next.after (
|
2399
|
+
next.after (100 + 75), ->
|
2335
2400
|
expect($element).toBeDetached()
|
2336
2401
|
|
2337
2402
|
it 'calls destructors for custom elements', (done) ->
|
@@ -2477,8 +2542,31 @@ describe 'up.dom', ->
|
|
2477
2542
|
next =>
|
2478
2543
|
expect(up.browser.navigate).toHaveBeenCalledWith('/source', jasmine.anything())
|
2479
2544
|
|
2545
|
+
describe 'up.dom.layerOf', ->
|
2546
|
+
|
2547
|
+
it 'returns "popup" for an element in a popup over the page', ->
|
2548
|
+
$popup = affix('.up-popup')
|
2549
|
+
$element = $popup.affix('.element')
|
2550
|
+
expect(up.dom.layerOf($element)).toEqual('popup')
|
2551
|
+
|
2552
|
+
it 'returns "popup" for an element in a popup over a modal', ->
|
2553
|
+
$modal = affix('.up-modal')
|
2554
|
+
$popupInModal = $modal.affix('.up-popup')
|
2555
|
+
$element = $popupInModal.affix('.element')
|
2556
|
+
expect(up.dom.layerOf($element)).toEqual('popup')
|
2557
|
+
|
2558
|
+
it 'returns "modal" for an element in a modal', ->
|
2559
|
+
$modal = affix('.up-modal')
|
2560
|
+
$element = $modal.affix('.element')
|
2561
|
+
expect(up.dom.layerOf($element)).toEqual('modal')
|
2562
|
+
|
2563
|
+
it 'returns "page" for an element below a modal or popup', ->
|
2564
|
+
$element = affix('.element')
|
2565
|
+
expect(up.dom.layerOf($element)).toEqual('page')
|
2480
2566
|
|
2481
|
-
|
2567
|
+
it 'returns undefined for an empty jQuery collection', ->
|
2568
|
+
expect(up.dom.layerOf($())).toBeUndefined()
|
2482
2569
|
|
2483
|
-
it '
|
2570
|
+
it 'returns undefined for undefined', ->
|
2571
|
+
expect(up.dom.layerOf(undefined)).toBeUndefined()
|
2484
2572
|
|