unpoly-rails 0.37.0 → 0.50.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/CHANGELOG.md +127 -25
- data/LICENSE +1 -1
- data/README_RAILS.md +4 -2
- data/Rakefile +6 -1
- data/dist/unpoly.js +3192 -2198
- data/dist/unpoly.min.js +4 -3
- data/lib/assets/javascripts/unpoly/browser.coffee +51 -63
- data/lib/assets/javascripts/unpoly/bus.coffee +58 -33
- data/lib/assets/javascripts/unpoly/classes/cache.coffee +117 -0
- data/lib/assets/javascripts/unpoly/{dom → classes}/extract_cascade.coffee +3 -3
- data/lib/assets/javascripts/unpoly/{dom → classes}/extract_plan.coffee +1 -1
- data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +57 -0
- data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +52 -0
- data/lib/assets/javascripts/unpoly/classes/motion_tracker.coffee +95 -0
- data/lib/assets/javascripts/unpoly/classes/record.coffee +16 -0
- data/lib/assets/javascripts/unpoly/classes/request.coffee +228 -0
- data/lib/assets/javascripts/unpoly/classes/response.coffee +138 -0
- data/lib/assets/javascripts/unpoly/dom.coffee +151 -142
- data/lib/assets/javascripts/unpoly/feedback.coffee +67 -38
- data/lib/assets/javascripts/unpoly/form.coffee +156 -139
- data/lib/assets/javascripts/unpoly/history.coffee +22 -19
- data/lib/assets/javascripts/unpoly/layout.coffee +108 -90
- data/lib/assets/javascripts/unpoly/link.coffee +159 -158
- data/lib/assets/javascripts/unpoly/log.coffee +5 -5
- data/lib/assets/javascripts/unpoly/modal.coffee +93 -81
- data/lib/assets/javascripts/unpoly/motion.coffee +291 -250
- data/lib/assets/javascripts/unpoly/popup.coffee +67 -53
- data/lib/assets/javascripts/unpoly/protocol.coffee +67 -16
- data/lib/assets/javascripts/unpoly/proxy.coffee +282 -211
- data/lib/assets/javascripts/unpoly/rails.coffee +3 -14
- data/lib/assets/javascripts/unpoly/syntax.coffee +54 -49
- data/lib/assets/javascripts/unpoly/tooltip.coffee +18 -25
- data/lib/assets/javascripts/unpoly/util.coffee +236 -477
- data/lib/assets/javascripts/unpoly.coffee +1 -1
- data/lib/unpoly/rails/inspector.rb +67 -22
- data/lib/unpoly/rails/version.rb +1 -1
- data/package.json +1 -1
- data/spec_app/Gemfile.lock +13 -13
- data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
- data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -1
- data/spec_app/app/assets/stylesheets/jasmine_specs.sass +10 -0
- data/spec_app/app/controllers/binding_test_controller.rb +19 -2
- data/spec_app/app/controllers/method_test_controller.rb +16 -0
- data/spec_app/app/views/layouts/jasmine_rails/spec_runner.html.erb +20 -0
- data/spec_app/app/views/method_test/form_target.erb +17 -0
- data/spec_app/app/views/method_test/page1.erb +11 -0
- data/spec_app/app/views/method_test/page2.erb +6 -0
- data/spec_app/app/views/pages/start.erb +33 -19
- data/spec_app/config/initializers/assets.rb +5 -0
- data/spec_app/config/routes.rb +3 -0
- data/spec_app/spec/controllers/binding_test_controller_spec.rb +82 -27
- data/spec_app/spec/javascripts/helpers/agent_detector.coffee +17 -0
- data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +102 -0
- data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -1
- data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +5 -2
- data/spec_app/spec/javascripts/helpers/promise_state.js +18 -0
- data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +9 -0
- data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +22 -0
- data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +11 -3
- data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +10 -0
- data/spec_app/spec/javascripts/helpers/to_be_error.coffee +5 -0
- data/spec_app/spec/javascripts/helpers/to_match_url.coffee +13 -0
- data/spec_app/spec/javascripts/helpers/trigger.js.coffee +13 -6
- data/spec_app/spec/javascripts/up/browser_spec.js.coffee +92 -33
- data/spec_app/spec/javascripts/up/bus_spec.js.coffee +64 -15
- data/spec_app/spec/javascripts/up/classes/.keep +0 -0
- data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +1 -0
- data/spec_app/spec/javascripts/up/dom_spec.js.coffee +759 -551
- data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +155 -82
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +490 -349
- data/spec_app/spec/javascripts/up/history_spec.js.coffee +226 -179
- data/spec_app/spec/javascripts/up/layout_spec.js.coffee +253 -185
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +416 -270
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +459 -330
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +198 -153
- data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +9 -0
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +240 -175
- data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +38 -0
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +777 -303
- data/spec_app/spec/javascripts/up/rails_spec.js.coffee +24 -8
- data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +40 -23
- data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +80 -66
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +227 -201
- data/spec_app/vendor/asset-libs/es6-promise-4.1.6/es6-promise.auto.js +1159 -0
- metadata +30 -7
- data/spec_app/spec/javascripts/helpers/reset_path.js.coffee +0 -7
- data/spec_app/spec/javascripts/helpers/to_equal_url.coffee +0 -11
@@ -1,5 +1,6 @@
|
|
1
1
|
#= require ./unpoly/namespace
|
2
2
|
#= require ./unpoly/util
|
3
|
+
#= require_tree ./unpoly/classes
|
3
4
|
#= require ./unpoly/protocol
|
4
5
|
#= require ./unpoly/browser
|
5
6
|
#= require ./unpoly/bus
|
@@ -9,7 +10,6 @@
|
|
9
10
|
#= require ./unpoly/history
|
10
11
|
#= require ./unpoly/layout
|
11
12
|
#= require ./unpoly/dom
|
12
|
-
#= require_tree ./unpoly/dom
|
13
13
|
#= require ./unpoly/motion
|
14
14
|
#= require ./unpoly/proxy
|
15
15
|
#= require ./unpoly/link
|
@@ -22,21 +22,35 @@ module Unpoly
|
|
22
22
|
alias_method :unpoly?, :up?
|
23
23
|
|
24
24
|
##
|
25
|
-
#
|
26
|
-
#
|
25
|
+
# Returns the CSS selector for a fragment that Unpoly will update in
|
26
|
+
# case of a successful response (200 status code).
|
27
27
|
#
|
28
28
|
# The Unpoly frontend will expect an HTML response containing an element
|
29
|
-
# that matches this selector.
|
30
|
-
# to the user.
|
29
|
+
# that matches this selector.
|
31
30
|
#
|
32
|
-
# Server-side code is free to optimize its response by only returning HTML
|
31
|
+
# Server-side code is free to optimize its successful response by only returning HTML
|
33
32
|
# that matches this selector.
|
34
33
|
def target
|
35
34
|
request.headers['X-Up-Target']
|
36
35
|
end
|
37
36
|
|
38
37
|
##
|
39
|
-
#
|
38
|
+
# Returns the CSS selector for a fragment that Unpoly will update in
|
39
|
+
# case of an failed response. Server errors or validation failures are
|
40
|
+
# all examples for a failed response (non-200 status code).
|
41
|
+
#
|
42
|
+
# The Unpoly frontend will expect an HTML response containing an element
|
43
|
+
# that matches this selector.
|
44
|
+
#
|
45
|
+
# Server-side code is free to optimize its response by only returning HTML
|
46
|
+
# that matches this selector.
|
47
|
+
def fail_target
|
48
|
+
request.headers['X-Up-Fail-Target']
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns whether the given CSS selector is targeted by the current fragment
|
53
|
+
# update in case of a successful response (200 status code).
|
40
54
|
#
|
41
55
|
# Note that the matching logic is very simplistic and does not actually know
|
42
56
|
# how your page layout is structured. It will return `true` if
|
@@ -45,31 +59,46 @@ module Unpoly
|
|
45
59
|
#
|
46
60
|
# Always returns `true` if the current request is not an Unpoly fragment update.
|
47
61
|
def target?(tested_target)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
query_target(target, tested_target)
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns whether the given CSS selector is targeted by the current fragment
|
67
|
+
# update in case of a failed response (non-200 status code).
|
68
|
+
#
|
69
|
+
# Note that the matching logic is very simplistic and does not actually know
|
70
|
+
# how your page layout is structured. It will return `true` if
|
71
|
+
# the tested selector and the requested CSS selector matches exactly, or if the
|
72
|
+
# requested selector is `body` or `html`.
|
73
|
+
#
|
74
|
+
# Always returns `true` if the current request is not an Unpoly fragment update.
|
75
|
+
def fail_target?(tested_target)
|
76
|
+
query_target(fail_target, tested_target)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Returns whether the given CSS selector is targeted by the current fragment
|
81
|
+
# update for either a success or a failed response.
|
82
|
+
#
|
83
|
+
# Note that the matching logic is very simplistic and does not actually know
|
84
|
+
# how your page layout is structured. It will return `true` if
|
85
|
+
# the tested selector and the requested CSS selector matches exactly, or if the
|
86
|
+
# requested selector is `body` or `html`.
|
87
|
+
#
|
88
|
+
# Always returns `true` if the current request is not an Unpoly fragment update.
|
89
|
+
def any_target?(tested_target)
|
90
|
+
target?(tested_target) || fail_target?(tested_target)
|
62
91
|
end
|
63
92
|
|
64
93
|
##
|
65
94
|
# Returns whether the current form submission should be
|
66
|
-
# [validated](https://unpoly.com/up-validate) (and not be saved to the database).
|
95
|
+
# [validated](https://unpoly.com/input-up-validate) (and not be saved to the database).
|
67
96
|
def validate?
|
68
97
|
validate_name.present?
|
69
98
|
end
|
70
99
|
|
71
100
|
##
|
72
|
-
# If the current form submission is a [validation](https://unpoly.com/up-validate),
|
101
|
+
# If the current form submission is a [validation](https://unpoly.com/input-up-validate),
|
73
102
|
# this returns the name attribute of the form field that has triggered
|
74
103
|
# the validation.
|
75
104
|
def validate_name
|
@@ -99,6 +128,22 @@ module Unpoly
|
|
99
128
|
@controller.response
|
100
129
|
end
|
101
130
|
|
131
|
+
def query_target(actual_target, tested_target)
|
132
|
+
if up?
|
133
|
+
if actual_target == tested_target
|
134
|
+
true
|
135
|
+
elsif actual_target == 'html'
|
136
|
+
true
|
137
|
+
elsif actual_target == 'body'
|
138
|
+
not ['head', 'title', 'meta'].include?(tested_target)
|
139
|
+
else
|
140
|
+
false
|
141
|
+
end
|
142
|
+
else
|
143
|
+
true
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
102
147
|
end
|
103
148
|
end
|
104
149
|
end
|
data/lib/unpoly/rails/version.rb
CHANGED
data/package.json
CHANGED
data/spec_app/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ..
|
3
3
|
specs:
|
4
|
-
unpoly-rails (0.
|
4
|
+
unpoly-rails (0.37.0)
|
5
5
|
rails (>= 3)
|
6
6
|
|
7
7
|
GEM
|
@@ -86,14 +86,14 @@ GEM
|
|
86
86
|
haml (>= 4.0.0.rc.1)
|
87
87
|
hpricot (~> 0.8.6)
|
88
88
|
ruby_parser (~> 3.1.1)
|
89
|
-
i18n (0.
|
90
|
-
jasmine-core (2.
|
89
|
+
i18n (0.8.6)
|
90
|
+
jasmine-core (2.8.0)
|
91
91
|
jasmine-rails (0.14.1)
|
92
92
|
jasmine-core (>= 1.3, < 3.0)
|
93
93
|
phantomjs (>= 1.9)
|
94
94
|
railties (>= 3.2.0)
|
95
95
|
sprockets-rails
|
96
|
-
jquery-rails (4.
|
96
|
+
jquery-rails (4.3.1)
|
97
97
|
rails-dom-testing (>= 1, < 3)
|
98
98
|
railties (>= 4.2.0)
|
99
99
|
thor (>= 0.14, < 2.0)
|
@@ -104,13 +104,13 @@ GEM
|
|
104
104
|
mail (2.6.3)
|
105
105
|
mime-types (>= 1.16, < 3)
|
106
106
|
mime-types (2.99)
|
107
|
-
mini_portile2 (2.
|
108
|
-
minitest (5.10.
|
107
|
+
mini_portile2 (2.2.0)
|
108
|
+
minitest (5.10.3)
|
109
109
|
multi_json (1.12.1)
|
110
|
-
nokogiri (1.
|
111
|
-
mini_portile2 (~> 2.
|
110
|
+
nokogiri (1.8.0)
|
111
|
+
mini_portile2 (~> 2.2.0)
|
112
112
|
phantomjs (2.1.1.0)
|
113
|
-
rack (1.6.
|
113
|
+
rack (1.6.8)
|
114
114
|
rack-test (0.6.3)
|
115
115
|
rack (>= 1.0)
|
116
116
|
rails (4.2.0)
|
@@ -180,10 +180,10 @@ GEM
|
|
180
180
|
therubyracer (0.12.1)
|
181
181
|
libv8 (~> 3.16.14.0)
|
182
182
|
ref
|
183
|
-
thor (0.
|
184
|
-
thread_safe (0.3.
|
183
|
+
thor (0.20.0)
|
184
|
+
thread_safe (0.3.6)
|
185
185
|
tilt (1.4.1)
|
186
|
-
tzinfo (1.2.
|
186
|
+
tzinfo (1.2.3)
|
187
187
|
thread_safe (~> 0.1)
|
188
188
|
uglifier (2.6.0)
|
189
189
|
execjs (>= 0.3.0)
|
@@ -218,4 +218,4 @@ DEPENDENCIES
|
|
218
218
|
web-console (~> 2.0)
|
219
219
|
|
220
220
|
BUNDLED WITH
|
221
|
-
1.
|
221
|
+
1.16.0
|
@@ -8,12 +8,22 @@ class BindingTestController < ActionController::Base
|
|
8
8
|
render :text => up.target
|
9
9
|
end
|
10
10
|
|
11
|
+
def up_fail_target
|
12
|
+
render :text => up.fail_target
|
13
|
+
end
|
14
|
+
|
11
15
|
def up_is_target
|
12
|
-
tested_target = params[:tested_target].presence
|
13
|
-
tested_target or raise "No target given"
|
14
16
|
render :text => up.target?(tested_target).to_s
|
15
17
|
end
|
16
18
|
|
19
|
+
def up_is_fail_target
|
20
|
+
render :text => up.fail_target?(tested_target).to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def up_is_any_target
|
24
|
+
render :text => up.any_target?(tested_target).to_s
|
25
|
+
end
|
26
|
+
|
17
27
|
def is_up_validate
|
18
28
|
render :text => up.validate?.to_s
|
19
29
|
end
|
@@ -31,4 +41,11 @@ class BindingTestController < ActionController::Base
|
|
31
41
|
render :text => 'text from controller'
|
32
42
|
end
|
33
43
|
|
44
|
+
private
|
45
|
+
|
46
|
+
def tested_target
|
47
|
+
tested_target = params[:tested_target].presence
|
48
|
+
tested_target or raise "No target given"
|
49
|
+
end
|
50
|
+
|
34
51
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
|
5
|
+
<title>Unpoly Specs</title>
|
6
|
+
|
7
|
+
<%= stylesheet_link_tag *jasmine_css_files %>
|
8
|
+
<%=
|
9
|
+
jquery_suffix = params[:jquery].presence || '3'
|
10
|
+
jquery_asset = "jquery#{jquery_suffix}"
|
11
|
+
jquery_asset = "jquery" if jquery_asset == "jquery1"
|
12
|
+
javascript_include_tag jquery_asset
|
13
|
+
%>
|
14
|
+
<%= javascript_include_tag *jasmine_js_files %>
|
15
|
+
</head>
|
16
|
+
<body>
|
17
|
+
<div id="jasmine_content"></div>
|
18
|
+
<%= yield %>
|
19
|
+
</body>
|
20
|
+
</html>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<html>
|
2
|
+
<body>
|
3
|
+
|
4
|
+
<h1>form_target (<%= request.method %>)</h1>
|
5
|
+
|
6
|
+
<p>
|
7
|
+
<a href="javascript:history.pushState({}, 'page 2 title', 'page2')">Add history entry to page2</a>
|
8
|
+
</p>
|
9
|
+
|
10
|
+
<p>
|
11
|
+
<a href="javascript:location.reload()">Reload the page</a>
|
12
|
+
<br>
|
13
|
+
Do you see a "retry form submission" prompt? If yes, this browser is affected by the issue.
|
14
|
+
</p>
|
15
|
+
|
16
|
+
</body>
|
17
|
+
</html>
|
@@ -5,7 +5,38 @@
|
|
5
5
|
<h2>Unit tests</h2>
|
6
6
|
|
7
7
|
<ul>
|
8
|
-
<li
|
8
|
+
<li>
|
9
|
+
<%= link_to 'Jasmine specs with jQuery 3', '/specs?jquery=3' %>
|
10
|
+
<ul>
|
11
|
+
<% %w[
|
12
|
+
up.dom
|
13
|
+
up.feedback
|
14
|
+
up.form
|
15
|
+
up.history
|
16
|
+
up.layout
|
17
|
+
up.link
|
18
|
+
up.log
|
19
|
+
up.modal
|
20
|
+
up.motion
|
21
|
+
up.popup
|
22
|
+
up.protocol
|
23
|
+
up.proxy
|
24
|
+
up.rails
|
25
|
+
up.syntax
|
26
|
+
up.toast
|
27
|
+
up.tooltip
|
28
|
+
up.util
|
29
|
+
].each do |mod| %>
|
30
|
+
<li><%= link_to mod, "/specs?spec=#{mod}" %></li>
|
31
|
+
<% end %>
|
32
|
+
</ul>
|
33
|
+
</li>
|
34
|
+
<li>
|
35
|
+
<%= link_to 'Jasmine specs with jQuery 2', '/specs?jquery=2' %>
|
36
|
+
</li>
|
37
|
+
<li>
|
38
|
+
<%= link_to 'Jasmine specs with jQuery 1', '/specs?jquery=1' %>
|
39
|
+
</li>
|
9
40
|
</ul>
|
10
41
|
|
11
42
|
<h2>Integration tests</h2>
|
@@ -15,35 +46,18 @@
|
|
15
46
|
<%= link_to 'Tooltip', '/css_test/tooltip' %>
|
16
47
|
(<%= link_to 'with Bootstrap', '/css_test/tooltip?bootstrap=1' %>)
|
17
48
|
</li>
|
18
|
-
</ul>
|
19
|
-
|
20
|
-
<ul>
|
21
49
|
<li>
|
22
50
|
<%= link_to 'Popup', '/css_test/popup' %>
|
23
51
|
(<%= link_to 'with Bootstrap', '/css_test/popup?bootstrap=1' %>)
|
24
52
|
</li>
|
25
|
-
</ul>
|
26
|
-
|
27
|
-
<ul>
|
28
53
|
<li>
|
29
54
|
<%= link_to 'Modal', '/css_test/modal' %>
|
30
55
|
(<%= link_to 'with Bootstrap', '/css_test/modal?bootstrap=1' %>)
|
31
56
|
</li>
|
32
|
-
</ul>
|
33
|
-
|
34
|
-
<ul>
|
35
57
|
<li><%= link_to 'Form (basic)', '/form_test/basic/new' %></li>
|
36
|
-
</ul>
|
37
|
-
|
38
|
-
<ul>
|
39
58
|
<li><%= link_to 'Form (upload)', '/form_test/upload/new' %></li>
|
40
|
-
</ul>
|
41
|
-
|
42
|
-
<ul>
|
43
59
|
<li><%= link_to 'Error', '/error_test/trigger' %></li>
|
44
|
-
|
45
|
-
|
46
|
-
<ul>
|
60
|
+
<li><%= link_to 'Booting with non-GET method', '/method_test/page1' %></li>
|
47
61
|
<li><%= link_to 'Fragment update', '/replace_test/page1' %></li>
|
48
62
|
</ul>
|
49
63
|
|
@@ -11,4 +11,9 @@ Rails.application.config.assets.precompile += %w( application.js application.css
|
|
11
11
|
Rails.application.config.assets.precompile += %w( jasmine_specs.js jasmine_specs.css )
|
12
12
|
Rails.application.config.assets.precompile += %w( integration_test.js integration_test.css )
|
13
13
|
Rails.application.config.assets.precompile += %w( bootstrap_manifest.js bootstrap_manifest.css )
|
14
|
+
|
15
|
+
# Precompile jQuery versions from jquery-rails individually, so we can include them as individual <script> tags
|
16
|
+
Rails.application.config.assets.precompile += %w( jquery.js jquery2.js jquery3.js )
|
17
|
+
|
18
|
+
# Precompile Bootstrap bindings individually, so we can include them as individual <script> tags
|
14
19
|
Rails.application.config.assets.precompile += %w( unpoly-bootstrap3.js unpoly-bootstrap3.css )
|
data/spec_app/config/routes.rb
CHANGED
@@ -3,6 +3,9 @@ Rails.application.routes.draw do
|
|
3
3
|
mount JasmineRails::Engine => '/specs' if defined?(JasmineRails)
|
4
4
|
root to: 'pages#start'
|
5
5
|
|
6
|
+
get 'method_test/:action', controller: 'method_test'
|
7
|
+
post 'method_test/:action', controller: 'method_test'
|
8
|
+
|
6
9
|
get 'binding_test/:action', controller: 'binding_test'
|
7
10
|
get 'css_test/:action', controller: 'css_test'
|
8
11
|
get 'error_test/:action', controller: 'error_test'
|
@@ -19,7 +19,7 @@ describe BindingTestController do
|
|
19
19
|
|
20
20
|
describe '#target' do
|
21
21
|
|
22
|
-
it 'returns the CSS selector that
|
22
|
+
it 'returns the CSS selector that Unpoly requested for a sucessful response' do
|
23
23
|
request.headers['X-Up-Target'] = '.foo'
|
24
24
|
get :up_target
|
25
25
|
expect(response.body).to eq('.foo')
|
@@ -27,87 +27,142 @@ describe BindingTestController do
|
|
27
27
|
|
28
28
|
end
|
29
29
|
|
30
|
-
describe '#
|
30
|
+
describe '#fail_target' do
|
31
31
|
|
32
|
-
it 'returns
|
32
|
+
it 'returns the CSS selector that Unpoly requested for an error response' do
|
33
33
|
request.headers['X-Up-Target'] = '.foo'
|
34
|
-
|
34
|
+
request.headers['X-Up-Fail-Target'] = '.bar'
|
35
|
+
get :up_fail_target
|
36
|
+
expect(response.body).to eq('.bar')
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
shared_examples_for 'target query' do |opts|
|
42
|
+
|
43
|
+
let(:header) { opts.fetch(:header) }
|
44
|
+
|
45
|
+
let (:action) { opts.fetch(:action)}
|
46
|
+
|
47
|
+
def set_header(value)
|
48
|
+
request.headers[header] = value
|
49
|
+
if header != 'X-Up-Target'
|
50
|
+
# Make sure that it's considered a fragment update
|
51
|
+
request.headers['X-Up-Target'] = '.other-selector'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns true if the tested CSS selector is requested via Unpoly' do
|
56
|
+
set_header '.foo'
|
57
|
+
get action, tested_target: '.foo'
|
35
58
|
expect(response.body).to eq('true')
|
36
59
|
end
|
37
60
|
|
38
61
|
it 'returns false if Unpoly is requesting another CSS selector' do
|
39
|
-
|
40
|
-
get
|
62
|
+
set_header '.bar'
|
63
|
+
get action, tested_target: '.foo'
|
41
64
|
expect(response.body).to eq('false')
|
42
65
|
end
|
43
66
|
|
44
67
|
it 'returns true if the request is not an Unpoly request' do
|
45
|
-
get
|
68
|
+
get action, tested_target: '.foo'
|
46
69
|
expect(response.body).to eq('true')
|
47
70
|
end
|
48
71
|
|
49
72
|
it 'returns true if testing a custom selector, and Unpoly requests "body"' do
|
50
|
-
|
51
|
-
get
|
73
|
+
set_header 'body'
|
74
|
+
get action, tested_target: '.foo'
|
52
75
|
expect(response.body).to eq('true')
|
53
76
|
end
|
54
77
|
|
55
78
|
it 'returns true if testing a custom selector, and Unpoly requests "html"' do
|
56
|
-
|
57
|
-
get
|
79
|
+
set_header 'html'
|
80
|
+
get action, tested_target: '.foo'
|
58
81
|
expect(response.body).to eq('true')
|
59
82
|
end
|
60
83
|
|
61
84
|
it 'returns true if testing "body", and Unpoly requests "html"' do
|
62
|
-
|
63
|
-
get
|
85
|
+
set_header 'html'
|
86
|
+
get action, tested_target: 'body'
|
64
87
|
expect(response.body).to eq('true')
|
65
88
|
end
|
66
89
|
|
67
90
|
it 'returns true if testing "head", and Unpoly requests "html"' do
|
68
|
-
|
69
|
-
get
|
91
|
+
set_header 'html'
|
92
|
+
get action, tested_target: 'head'
|
70
93
|
expect(response.body).to eq('true')
|
71
94
|
end
|
72
95
|
|
73
96
|
it 'returns false if the tested CSS selector is "head" but Unpoly requests "body"' do
|
74
|
-
|
75
|
-
get
|
97
|
+
set_header 'body'
|
98
|
+
get action, tested_target: 'head'
|
76
99
|
expect(response.body).to eq('false')
|
77
100
|
end
|
78
101
|
|
79
102
|
it 'returns false if the tested CSS selector is "title" but Unpoly requests "body"' do
|
80
|
-
|
81
|
-
get
|
103
|
+
set_header 'body'
|
104
|
+
get action, tested_target: 'title'
|
82
105
|
expect(response.body).to eq('false')
|
83
106
|
end
|
84
107
|
|
85
108
|
it 'returns false if the tested CSS selector is "meta" but Unpoly requests "body"' do
|
86
|
-
|
87
|
-
get
|
109
|
+
set_header 'body'
|
110
|
+
get action, tested_target: 'meta'
|
88
111
|
expect(response.body).to eq('false')
|
89
112
|
end
|
90
113
|
|
91
114
|
it 'returns true if the tested CSS selector is "head", and Unpoly requests "html"' do
|
92
|
-
|
93
|
-
get
|
115
|
+
set_header 'html'
|
116
|
+
get action, tested_target: 'head'
|
94
117
|
expect(response.body).to eq('true')
|
95
118
|
end
|
96
119
|
|
97
120
|
it 'returns true if the tested CSS selector is "title", Unpoly requests "html"' do
|
98
|
-
|
99
|
-
get
|
121
|
+
set_header 'html'
|
122
|
+
get action, tested_target: 'title'
|
100
123
|
expect(response.body).to eq('true')
|
101
124
|
end
|
102
125
|
|
103
126
|
it 'returns true if the tested CSS selector is "meta", and Unpoly requests "html"' do
|
104
|
-
|
105
|
-
get
|
127
|
+
set_header 'html'
|
128
|
+
get action, tested_target: 'meta'
|
106
129
|
expect(response.body).to eq('true')
|
107
130
|
end
|
108
131
|
|
109
132
|
end
|
110
133
|
|
134
|
+
describe '#target?' do
|
135
|
+
it_behaves_like 'target query', action: :up_is_target, header: 'X-Up-Target'
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '#fail_target?' do
|
139
|
+
it_behaves_like 'target query', action: :up_is_fail_target, header: 'X-Up-Fail-Target'
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#any_target?' do
|
143
|
+
|
144
|
+
before :each do
|
145
|
+
request.headers['X-Up-Target'] = '.success'
|
146
|
+
request.headers['X-Up-Fail-Target'] = '.failure'
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'returns true if the tested CSS selector is the target for a successful response' do
|
150
|
+
get :up_is_any_target, tested_target: '.success'
|
151
|
+
expect(response.body).to eq('true')
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'returns true if the tested CSS selector is the target for a failed response' do
|
155
|
+
get :up_is_any_target, tested_target: '.failure'
|
156
|
+
expect(response.body).to eq('true')
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'returns false if the tested CSS selector is a target for neither successful nor failed response' do
|
160
|
+
get :up_is_any_target, tested_target: '.other'
|
161
|
+
expect(response.body).to eq('false')
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
111
166
|
describe '#validate?' do
|
112
167
|
|
113
168
|
it 'returns true the request is an Unpoly validation call' do
|
@@ -0,0 +1,17 @@
|
|
1
|
+
@AgentDetector = do ->
|
2
|
+
|
3
|
+
match = (regexp) ->
|
4
|
+
navigator.userAgent.match(regexp)
|
5
|
+
|
6
|
+
isIE = ->
|
7
|
+
match(/\bTrident\b/)
|
8
|
+
|
9
|
+
isEdge = ->
|
10
|
+
match(/\bEdge\b/)
|
11
|
+
|
12
|
+
isSafari = ->
|
13
|
+
match(/\bSafari\b/) && !match(/\bChrome\b/)
|
14
|
+
|
15
|
+
isIE: isIE
|
16
|
+
isEdge: isEdge
|
17
|
+
isSafari: isSafari
|