unpoly-rails 0.60.3 → 1.0.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -2
- data/CHANGELOG.md +84 -0
- data/README.md +1 -1
- data/Rakefile +11 -1
- data/dist/unpoly.js +226 -91
- data/dist/unpoly.min.js +4 -4
- data/lib/assets/javascripts/unpoly/browser.coffee.erb +10 -5
- data/lib/assets/javascripts/unpoly/classes/body_shifter.coffee +21 -12
- data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +2 -2
- data/lib/assets/javascripts/unpoly/classes/event_listener.coffee +1 -1
- data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +11 -3
- data/lib/assets/javascripts/unpoly/classes/params.coffee.erb +1 -0
- data/lib/assets/javascripts/unpoly/element.coffee.erb +9 -6
- data/lib/assets/javascripts/unpoly/event.coffee.erb +12 -4
- data/lib/assets/javascripts/unpoly/form.coffee.erb +85 -14
- data/lib/assets/javascripts/unpoly/fragment.coffee.erb +7 -3
- data/lib/assets/javascripts/unpoly/framework.coffee +7 -9
- data/lib/assets/javascripts/unpoly/link.coffee.erb +1 -1
- data/lib/assets/javascripts/unpoly/log.coffee +6 -2
- data/lib/assets/javascripts/unpoly/modal.coffee.erb +4 -2
- data/lib/assets/javascripts/unpoly/motion.coffee.erb +1 -1
- data/lib/assets/javascripts/unpoly/protocol.coffee +1 -1
- data/lib/assets/javascripts/unpoly/syntax.coffee.erb +3 -4
- data/lib/assets/javascripts/unpoly/util.coffee.erb +4 -2
- data/lib/assets/javascripts/unpoly/viewport.coffee.erb +26 -2
- data/lib/unpoly/rails/version.rb +1 -1
- data/package.json +1 -1
- data/spec_app/Gemfile +2 -4
- data/spec_app/Gemfile.lock +23 -27
- data/spec_app/app/views/compiler_test/timestamp.erb +1 -0
- data/spec_app/app/views/css_test/modal.erb +1 -1
- data/spec_app/app/views/css_test/popup.erb +1 -1
- data/spec_app/app/views/pages/start.erb +2 -1
- data/spec_app/app/views/replace_test/table.erb +16 -0
- data/spec_app/spec/javascripts/up/event_spec.js.coffee +34 -0
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +128 -0
- data/spec_app/spec/javascripts/up/fragment_spec.js.coffee +36 -1
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +7 -2
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +23 -1
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +2 -1
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +28 -0
- metadata +4 -4
@@ -50,15 +50,13 @@ up.framework = do ->
|
|
50
50
|
# From here on, all event handlers (both Unpoly's and user code) should be able
|
51
51
|
# to work with the DOM, so wait for the DOM to be ready.
|
52
52
|
up.event.onReady ->
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
up.emit('up:app:boot', log: 'Booting user application')
|
61
|
-
up.emit('up:app:booted', log: 'User application booted')
|
53
|
+
# By now all non-sync <script> tags have been loaded and called, including
|
54
|
+
# those after us. All user-provided compilers, event handlers, etc. have
|
55
|
+
# been registered.
|
56
|
+
#
|
57
|
+
# The following event will cause Unpoly to compile the <body>.
|
58
|
+
up.emit('up:app:boot', log: 'Booting user application')
|
59
|
+
up.emit('up:app:booted', log: 'User application booted')
|
62
60
|
else
|
63
61
|
console.log?("Unpoly doesn't support this browser. Framework was not booted.")
|
64
62
|
|
@@ -16,7 +16,7 @@ This makes for an unfriendly experience:
|
|
16
16
|
- State changes caused by AJAX updates get lost during the page transition.
|
17
17
|
- Unsaved form changes get lost during the page transition.
|
18
18
|
- The JavaScript VM is reset during the page transition.
|
19
|
-
- If the page layout is composed from multiple
|
19
|
+
- If the page layout is composed from multiple scrollable containers
|
20
20
|
(e.g. a pane view), the scroll positions get lost during the page transition.
|
21
21
|
- The user sees a "flash" as the browser loads and renders the new page,
|
22
22
|
even if large portions of the old and new page are the same (navigation, layout, etc.).
|
@@ -37,12 +37,15 @@ up.log = do ->
|
|
37
37
|
prints to the developer console.
|
38
38
|
@param {string} [options.prefix='[UP] ']
|
39
39
|
A string to prepend to Unpoly's logging messages so you can distinguish it from your own messages.
|
40
|
+
@param {boolean} [options.banner=true]
|
41
|
+
Print the Unpoly banner to the developer console.
|
40
42
|
@stable
|
41
43
|
###
|
42
44
|
config = new up.Config
|
43
45
|
prefix: '[UP] '
|
44
46
|
enabled: sessionStore.get('enabled')
|
45
47
|
collapse: false
|
48
|
+
banner: true
|
46
49
|
|
47
50
|
reset = ->
|
48
51
|
config.reset()
|
@@ -200,7 +203,9 @@ up.log = do ->
|
|
200
203
|
banner += "Call `up.log.enable()` to enable logging for this session."
|
201
204
|
console.log(banner)
|
202
205
|
|
203
|
-
|
206
|
+
if config.banner
|
207
|
+
up.on 'up:framework:booted', printBanner
|
208
|
+
|
204
209
|
up.on 'up:framework:reset', reset
|
205
210
|
|
206
211
|
setEnabled = (value) ->
|
@@ -245,4 +250,3 @@ up.log = do ->
|
|
245
250
|
|
246
251
|
up.puts = up.log.puts
|
247
252
|
up.warn = up.log.warn
|
248
|
-
|
@@ -250,6 +250,7 @@ up.modal = do ->
|
|
250
250
|
createHiddenFrame = (target, options) ->
|
251
251
|
html = templateHtml()
|
252
252
|
state.modalElement = modalElement = e.createFromHtml(html)
|
253
|
+
modalElement.setAttribute('aria-modal', 'true') # tell modern screen readers to make all other elements inert
|
253
254
|
modalElement.setAttribute('up-flavor', state.flavor)
|
254
255
|
modalElement.setAttribute('up-position', state.position) if u.isPresent(state.position)
|
255
256
|
|
@@ -288,7 +289,7 @@ up.modal = do ->
|
|
288
289
|
var link = document.querySelector('a')
|
289
290
|
up.modal.follow(link)
|
290
291
|
|
291
|
-
Any option attributes for [`a[up-modal]`](/a
|
292
|
+
Any option attributes for [`a[up-modal]`](/a-up-modal) will be honored.
|
292
293
|
|
293
294
|
Emits events [`up:modal:open`](/up:modal:open) and [`up:modal:opened`](/up:modal:opened).
|
294
295
|
|
@@ -436,6 +437,7 @@ up.modal = do ->
|
|
436
437
|
options.layer = 'modal'
|
437
438
|
options.failTarget ?= link.getAttribute('up-fail-target')
|
438
439
|
options.failLayer ?= link.getAttribute('up-fail-layer') ? 'auto'
|
440
|
+
options.cache ?= e.booleanAttr(link, 'up-cache')
|
439
441
|
|
440
442
|
animateOptions = up.motion.animateOptions(options, link, duration: flavorDefault('openDuration', options.flavor), easing: flavorDefault('openEasing', options.flavor))
|
441
443
|
|
@@ -650,7 +652,7 @@ up.modal = do ->
|
|
650
652
|
|
651
653
|
Clicking would request the path `/blog` and select `.blog-list` from
|
652
654
|
the HTML response. Unpoly will dim the page
|
653
|
-
and place the matching `.blog-list` tag
|
655
|
+
and place the matching `.blog-list` tag in
|
654
656
|
a modal dialog.
|
655
657
|
|
656
658
|
@selector a[up-modal]
|
@@ -246,7 +246,7 @@ up.protocol = do ->
|
|
246
246
|
The parameter name can be configured as a string or as function that returns the parameter name.
|
247
247
|
If no name is set, no token will be sent.
|
248
248
|
|
249
|
-
Defaults to the `content` attribute of a `<meta>` tag named `csrf-
|
249
|
+
Defaults to the `content` attribute of a `<meta>` tag named `csrf-param`:
|
250
250
|
|
251
251
|
<meta name="csrf-param" content="authenticity_token" />
|
252
252
|
|
@@ -215,7 +215,7 @@ up.syntax = do ->
|
|
215
215
|
###**
|
216
216
|
Registers a [compiler](/up.compiler) that is run before all other compilers.
|
217
217
|
|
218
|
-
Use `up.macro()` to register a compiler that sets
|
218
|
+
Use `up.macro()` to register a compiler that sets multiple Unpoly attributes.
|
219
219
|
|
220
220
|
\#\#\# Example
|
221
221
|
|
@@ -373,10 +373,9 @@ up.syntax = do ->
|
|
373
373
|
clean = (fragment) ->
|
374
374
|
cleanables = e.subtree(fragment, '.up-can-clean')
|
375
375
|
u.each cleanables, (cleanable) ->
|
376
|
-
if destructors = cleanable
|
376
|
+
if destructors = u.pluckKey(cleanable, 'upDestructors')
|
377
377
|
destructor() for destructor in destructors
|
378
|
-
|
379
|
-
# The element we just cleaned is about to be removed from the DOM.
|
378
|
+
cleanable.classList.remove('up-can-clean')
|
380
379
|
|
381
380
|
###**
|
382
381
|
Checks if the given element has an [`up-data`](/up-data) attribute.
|
@@ -499,7 +499,8 @@ up.util = do ->
|
|
499
499
|
@stable
|
500
500
|
###
|
501
501
|
isJQuery = (object) ->
|
502
|
-
|
502
|
+
# We cannot do `object instanceof jQuery` since window.jQuery might not be set
|
503
|
+
!!object?.jquery
|
503
504
|
|
504
505
|
###**
|
505
506
|
Returns whether the given argument is an object with a `then` method.
|
@@ -1163,6 +1164,7 @@ up.util = do ->
|
|
1163
1164
|
"<": "<"
|
1164
1165
|
">": ">"
|
1165
1166
|
'"': '"'
|
1167
|
+
"'": '''
|
1166
1168
|
|
1167
1169
|
###**
|
1168
1170
|
Escapes the given string of HTML by replacing control chars with their HTML entities.
|
@@ -1173,7 +1175,7 @@ up.util = do ->
|
|
1173
1175
|
@stable
|
1174
1176
|
###
|
1175
1177
|
escapeHtml = (string) ->
|
1176
|
-
string.replace /[&<>"]/g, (char) -> ESCAPE_HTML_ENTITY_MAP[char]
|
1178
|
+
string.replace /[&<>"']/g, (char) -> ESCAPE_HTML_ENTITY_MAP[char]
|
1177
1179
|
|
1178
1180
|
###**
|
1179
1181
|
@function up.util.escapeRegexp
|
@@ -506,13 +506,37 @@ up.viewport = do ->
|
|
506
506
|
|
507
507
|
The scroll positions will be associated with the current URL.
|
508
508
|
They can later be restored by calling [`up.viewport.restoreScroll()`](/up.viewport.restoreScroll)
|
509
|
-
at the same URL
|
509
|
+
at the same URL, or by following a link with an [`[up-restore-scroll]`](/a-up-follow#up-restore-scroll)
|
510
|
+
attribute.
|
510
511
|
|
511
|
-
Unpoly automatically saves scroll positions
|
512
|
+
Unpoly automatically saves scroll positions before a [fragment update](/up.replace)
|
513
|
+
you will rarely need to call this function yourself.
|
514
|
+
|
515
|
+
\#\#\# Examples
|
516
|
+
|
517
|
+
Should you need to save the current scroll positions outside of a [fragment update](/up.replace),
|
518
|
+
you may call:
|
519
|
+
|
520
|
+
up.viewport.saveScroll()
|
521
|
+
|
522
|
+
Instead of saving the current scroll positions for the current URL, you may also pass another
|
523
|
+
url or vertical scroll positionsfor each viewport:
|
524
|
+
|
525
|
+
up.viewport.saveScroll({
|
526
|
+
url: '/inbox',
|
527
|
+
tops: {
|
528
|
+
'body': 0,
|
529
|
+
'.sidebar', 100,
|
530
|
+
'.main', 320
|
531
|
+
}
|
532
|
+
})
|
512
533
|
|
513
534
|
@function up.viewport.saveScroll
|
514
535
|
@param {string} [options.url]
|
536
|
+
The URL for which to save scroll positions.
|
537
|
+
If omitted, the current browser location is used.
|
515
538
|
@param {Object<string, number>} [options.tops]
|
539
|
+
An object mapping viewport selectors to vertical scroll positions in pixels.
|
516
540
|
@experimental
|
517
541
|
###
|
518
542
|
saveScroll = (options = {}) ->
|
data/lib/unpoly/rails/version.rb
CHANGED
data/package.json
CHANGED
data/spec_app/Gemfile
CHANGED
@@ -14,11 +14,9 @@ gem 'bower-rails'
|
|
14
14
|
gem 'bootstrap-sass', '~> 3.3'
|
15
15
|
gem 'rake', '< 11'
|
16
16
|
|
17
|
-
# Jasmine spec runner won't boot with a more modern version of sprockets.
|
18
|
-
# It crashes with an "asset not precompiled" error.
|
19
17
|
gem 'tilt', '=1.4.1'
|
20
|
-
gem 'sprockets-rails', '
|
21
|
-
gem 'sprockets', '
|
18
|
+
gem 'sprockets-rails', '~> 3.2.1'
|
19
|
+
gem 'sprockets', '~> 3.7.2'
|
22
20
|
|
23
21
|
group :development, :test do
|
24
22
|
gem 'byebug'
|
data/spec_app/Gemfile.lock
CHANGED
@@ -12,7 +12,7 @@ GIT
|
|
12
12
|
PATH
|
13
13
|
remote: ..
|
14
14
|
specs:
|
15
|
-
unpoly-rails (0.
|
15
|
+
unpoly-rails (0.62.1)
|
16
16
|
rails (>= 3)
|
17
17
|
|
18
18
|
GEM
|
@@ -62,7 +62,7 @@ GEM
|
|
62
62
|
autoprefixer-rails (>= 5.2.1)
|
63
63
|
sass (>= 3.3.4)
|
64
64
|
bower-rails (0.9.2)
|
65
|
-
builder (3.2.
|
65
|
+
builder (3.2.4)
|
66
66
|
byebug (3.5.1)
|
67
67
|
columnize (~> 0.8)
|
68
68
|
debugger-linecache (~> 1.2)
|
@@ -75,8 +75,8 @@ GEM
|
|
75
75
|
execjs
|
76
76
|
coffee-script-source (1.12.2)
|
77
77
|
columnize (0.9.0)
|
78
|
-
concurrent-ruby (1.1.
|
79
|
-
crass (1.0.
|
78
|
+
concurrent-ruby (1.1.6)
|
79
|
+
crass (1.0.6)
|
80
80
|
debug_inspector (0.0.2)
|
81
81
|
debugger-linecache (1.2.0)
|
82
82
|
diff-lcs (1.2.5)
|
@@ -92,7 +92,6 @@ GEM
|
|
92
92
|
haml (>= 3.1, < 5.0)
|
93
93
|
html2haml (>= 1.0.1)
|
94
94
|
railties (>= 4.0.1)
|
95
|
-
hike (1.2.3)
|
96
95
|
hpricot (0.8.6)
|
97
96
|
html2haml (1.0.1)
|
98
97
|
erubis (~> 2.7.0)
|
@@ -102,25 +101,24 @@ GEM
|
|
102
101
|
i18n (0.9.5)
|
103
102
|
concurrent-ruby (~> 1.0)
|
104
103
|
jasmine-core (2.99.2)
|
105
|
-
jquery-rails (4.3.
|
104
|
+
jquery-rails (4.3.5)
|
106
105
|
rails-dom-testing (>= 1, < 3)
|
107
106
|
railties (>= 4.2.0)
|
108
107
|
thor (>= 0.14, < 2.0)
|
109
108
|
json (1.8.6)
|
110
109
|
libv8 (3.16.14.3)
|
111
|
-
loofah (2.
|
110
|
+
loofah (2.4.0)
|
112
111
|
crass (~> 1.0.2)
|
113
112
|
nokogiri (>= 1.5.9)
|
114
113
|
mail (2.6.3)
|
115
114
|
mime-types (>= 1.16, < 3)
|
116
115
|
mime-types (2.99)
|
117
116
|
mini_portile2 (2.4.0)
|
118
|
-
minitest (5.
|
119
|
-
|
120
|
-
nokogiri (1.9.1)
|
117
|
+
minitest (5.14.0)
|
118
|
+
nokogiri (1.10.9)
|
121
119
|
mini_portile2 (~> 2.4.0)
|
122
120
|
phantomjs (2.1.1.0)
|
123
|
-
rack (1.6.
|
121
|
+
rack (1.6.13)
|
124
122
|
rack-test (0.6.3)
|
125
123
|
rack (>= 1.0)
|
126
124
|
rails (4.2.0)
|
@@ -140,8 +138,8 @@ GEM
|
|
140
138
|
activesupport (>= 4.2.0, < 5.0)
|
141
139
|
nokogiri (~> 1.6)
|
142
140
|
rails-deprecated_sanitizer (>= 1.0.1)
|
143
|
-
rails-html-sanitizer (1.0
|
144
|
-
loofah (~> 2.
|
141
|
+
rails-html-sanitizer (1.3.0)
|
142
|
+
loofah (~> 2.3)
|
145
143
|
railties (4.2.0)
|
146
144
|
actionpack (= 4.2.0)
|
147
145
|
activesupport (= 4.2.0)
|
@@ -177,23 +175,21 @@ GEM
|
|
177
175
|
tilt (>= 1.1, < 3)
|
178
176
|
sexp_processor (4.4.4)
|
179
177
|
slop (3.6.0)
|
180
|
-
sprockets (
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
activesupport (>= 3.0)
|
188
|
-
sprockets (>= 2.8, < 4.0)
|
178
|
+
sprockets (3.7.2)
|
179
|
+
concurrent-ruby (~> 1.0)
|
180
|
+
rack (> 1, < 3)
|
181
|
+
sprockets-rails (3.2.1)
|
182
|
+
actionpack (>= 4.0)
|
183
|
+
activesupport (>= 4.0)
|
184
|
+
sprockets (>= 3.0.0)
|
189
185
|
sqlite3 (1.3.10)
|
190
186
|
therubyracer (0.12.1)
|
191
187
|
libv8 (~> 3.16.14.0)
|
192
188
|
ref
|
193
|
-
thor (0.
|
189
|
+
thor (1.0.1)
|
194
190
|
thread_safe (0.3.6)
|
195
191
|
tilt (1.4.1)
|
196
|
-
tzinfo (1.2.
|
192
|
+
tzinfo (1.2.7)
|
197
193
|
thread_safe (~> 0.1)
|
198
194
|
uglifier (2.6.0)
|
199
195
|
execjs (>= 0.3.0)
|
@@ -220,8 +216,8 @@ DEPENDENCIES
|
|
220
216
|
rake (< 11)
|
221
217
|
rspec-rails
|
222
218
|
sass-rails (~> 5.0)
|
223
|
-
sprockets (
|
224
|
-
sprockets-rails (
|
219
|
+
sprockets (~> 3.7.2)
|
220
|
+
sprockets-rails (~> 3.2.1)
|
225
221
|
sqlite3
|
226
222
|
therubyracer
|
227
223
|
tilt (= 1.4.1)
|
@@ -230,4 +226,4 @@ DEPENDENCIES
|
|
230
226
|
web-console (~> 2.0)
|
231
227
|
|
232
228
|
BUNDLED WITH
|
233
|
-
1.
|
229
|
+
1.17.3
|
@@ -63,7 +63,8 @@
|
|
63
63
|
<li><%= link_to 'Form (redirect)', '/form_test/redirect/new' %></li>
|
64
64
|
<li><%= link_to 'Error', '/error_test/trigger' %></li>
|
65
65
|
<li><%= link_to 'Booting with non-GET method', '/method_test/page1' %></li>
|
66
|
-
<li><%= link_to 'Fragment update', '/replace_test/page1' %></li>
|
66
|
+
<li><%= link_to 'Fragment update (basic)', '/replace_test/page1' %></li>
|
67
|
+
<li><%= link_to 'Fragment update (table)', '/replace_test/table' %></li>
|
67
68
|
<li><%= link_to 'Hash links (without Unpoly)', '/hash_test/vanilla#one' %></li>
|
68
69
|
<li><%= link_to 'Hash links (with Unpoly)', '/hash_test/unpoly#one' %></li>
|
69
70
|
<li><%= link_to 'Revealing content in an overflowing <div> ', '/reveal_test/within_overflowing_div_viewport' %></li>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<table>
|
2
|
+
<tbody>
|
3
|
+
<tr id="one">
|
4
|
+
<td><%= Time.now %></td>
|
5
|
+
<td><a href="table" up-target="#one">Replace this row</a></td>
|
6
|
+
</tr>
|
7
|
+
<tr id="two">
|
8
|
+
<td><%= Time.now %></td>
|
9
|
+
<td><a href="table" up-target="#two">Replace this row</a></td>
|
10
|
+
</tr>
|
11
|
+
<tr id="three">
|
12
|
+
<td><%= Time.now %></td>
|
13
|
+
<td><a href="table" up-target="#three">Replace this row</a></td>
|
14
|
+
</tr>
|
15
|
+
</tbody>
|
16
|
+
</table>
|
@@ -494,3 +494,37 @@ describe 'up.event', ->
|
|
494
494
|
promiseState(promise).then (result) ->
|
495
495
|
expect(result.state).toEqual('rejected')
|
496
496
|
done()
|
497
|
+
|
498
|
+
describe 'up.event.halt', ->
|
499
|
+
|
500
|
+
it 'stops propagation of the given event to other event listeners on the same element', ->
|
501
|
+
otherListenerBefore = jasmine.createSpy()
|
502
|
+
otherListenerAfter = jasmine.createSpy()
|
503
|
+
element = fixture('div')
|
504
|
+
|
505
|
+
element.addEventListener('foo', otherListenerBefore)
|
506
|
+
element.addEventListener('foo', up.event.halt)
|
507
|
+
element.addEventListener('foo', otherListenerAfter)
|
508
|
+
|
509
|
+
up.emit(element, 'foo')
|
510
|
+
|
511
|
+
expect(otherListenerBefore).toHaveBeenCalled()
|
512
|
+
expect(otherListenerAfter).not.toHaveBeenCalled()
|
513
|
+
|
514
|
+
it 'stops the event from bubbling up the document tree', ->
|
515
|
+
parent = fixture('div')
|
516
|
+
element = e.affix(parent, 'div')
|
517
|
+
parentListener = jasmine.createSpy()
|
518
|
+
parent.addEventListener('foo', parentListener)
|
519
|
+
element.addEventListener('foo', up.event.halt)
|
520
|
+
|
521
|
+
up.emit(element, 'foo')
|
522
|
+
|
523
|
+
expect(parentListener).not.toHaveBeenCalled()
|
524
|
+
|
525
|
+
it 'prevents default on the event', ->
|
526
|
+
element = fixture('div')
|
527
|
+
element.addEventListener('foo', up.event.halt)
|
528
|
+
event = up.emit(element, 'foo')
|
529
|
+
expect(event.defaultPrevented).toBe(true)
|
530
|
+
|