gitlab-turbolinks-classic 2.5.4
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +251 -0
- data/lib/assets/javascripts/turbolinks.js.coffee +579 -0
- data/lib/turbolinks.rb +39 -0
- data/lib/turbolinks/cookies.rb +15 -0
- data/lib/turbolinks/redirection.rb +15 -0
- data/lib/turbolinks/version.rb +3 -0
- data/lib/turbolinks/x_domain_blocker.rb +21 -0
- data/lib/turbolinks/xhr_headers.rb +46 -0
- data/lib/turbolinks/xhr_url_for.rb +15 -0
- data/test/attachment.html +5 -0
- data/test/config.ru +63 -0
- data/test/dummy.gif +0 -0
- data/test/index.html +53 -0
- data/test/manifest.appcache +10 -0
- data/test/offline.html +19 -0
- data/test/other.html +26 -0
- data/test/redirect1.html +15 -0
- data/test/redirect2.html +11 -0
- data/test/reload.html +18 -0
- data/test/withoutextension +26 -0
- metadata +79 -0
data/lib/turbolinks.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'turbolinks/version'
|
2
|
+
require 'turbolinks/xhr_headers'
|
3
|
+
require 'turbolinks/xhr_url_for'
|
4
|
+
require 'turbolinks/cookies'
|
5
|
+
require 'turbolinks/x_domain_blocker'
|
6
|
+
require 'turbolinks/redirection'
|
7
|
+
|
8
|
+
module Turbolinks
|
9
|
+
class Engine < ::Rails::Engine
|
10
|
+
initializer :turbolinks do |config|
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
ActionController::Base.class_eval do
|
13
|
+
include XHRHeaders, Cookies, XDomainBlocker, Redirection
|
14
|
+
|
15
|
+
if respond_to?(:before_action)
|
16
|
+
before_action :set_xhr_redirected_to, :set_request_method_cookie
|
17
|
+
after_action :abort_xdomain_redirect
|
18
|
+
else
|
19
|
+
before_filter :set_xhr_redirected_to, :set_request_method_cookie
|
20
|
+
after_filter :abort_xdomain_redirect
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
ActionDispatch::Request.class_eval do
|
25
|
+
def referer
|
26
|
+
self.headers['X-XHR-Referer'] || super
|
27
|
+
end
|
28
|
+
alias referrer referer
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
ActiveSupport.on_load(:action_view) do
|
33
|
+
(ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).module_eval do
|
34
|
+
include XHRUrlFor
|
35
|
+
end
|
36
|
+
end unless RUBY_VERSION =~ /^1\.8/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Turbolinks
|
2
|
+
# For non-GET requests, sets a request_method cookie containing
|
3
|
+
# the request method of the current request. The Turbolinks script
|
4
|
+
# will not initialize if this cookie is set.
|
5
|
+
module Cookies
|
6
|
+
private
|
7
|
+
def set_request_method_cookie
|
8
|
+
if request.get?
|
9
|
+
cookies.delete(:request_method)
|
10
|
+
else
|
11
|
+
cookies[:request_method] = request.request_method
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Turbolinks
|
2
|
+
# Provides a means of using Turbolinks to perform redirects. The server
|
3
|
+
# will respond with a JavaScript call to Turbolinks.visit(url).
|
4
|
+
module Redirection
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def redirect_via_turbolinks_to(url = {}, response_status = {})
|
8
|
+
redirect_to(url, response_status)
|
9
|
+
|
10
|
+
self.status = 200
|
11
|
+
self.response_body = "Turbolinks.visit('#{location}');"
|
12
|
+
response.content_type = Mime::JS
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Turbolinks
|
2
|
+
# Changes the response status to 403 Forbidden if all of these conditions are true:
|
3
|
+
# - The current request originated from Turbolinks
|
4
|
+
# - The request is being redirected to a different domain
|
5
|
+
module XDomainBlocker
|
6
|
+
private
|
7
|
+
def same_origin?(a, b)
|
8
|
+
a = URI.parse URI.escape(a)
|
9
|
+
b = URI.parse URI.escape(b)
|
10
|
+
[a.scheme, a.host, a.port] == [b.scheme, b.host, b.port]
|
11
|
+
end
|
12
|
+
|
13
|
+
def abort_xdomain_redirect
|
14
|
+
to_uri = response.headers['Location'] || ""
|
15
|
+
current = request.headers['X-XHR-Referer'] || ""
|
16
|
+
unless to_uri.blank? || current.blank? || same_origin?(current, to_uri)
|
17
|
+
self.status = 403
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Turbolinks
|
2
|
+
# Intercepts calls to _compute_redirect_to_location (used by redirect_to) for two purposes.
|
3
|
+
#
|
4
|
+
# 1. Corrects the behavior of redirect_to with the :back option by using the X-XHR-Referer
|
5
|
+
# request header instead of the standard Referer request header.
|
6
|
+
#
|
7
|
+
# 2. Stores the return value (the redirect target url) to persist through to the redirect
|
8
|
+
# request, where it will be used to set the X-XHR-Redirected-To response header. The
|
9
|
+
# Turbolinks script will detect the header and use replaceState to reflect the redirected
|
10
|
+
# url.
|
11
|
+
module XHRHeaders
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
def _compute_redirect_to_location(*args)
|
15
|
+
options, request = _normalize_redirect_params(args)
|
16
|
+
|
17
|
+
store_for_turbolinks begin
|
18
|
+
if options == :back && request.headers["X-XHR-Referer"]
|
19
|
+
super(*[(request if args.length == 2), request.headers["X-XHR-Referer"]].compact)
|
20
|
+
else
|
21
|
+
super(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def store_for_turbolinks(url)
|
28
|
+
session[:_turbolinks_redirect_to] = url if session && request.headers["X-XHR-Referer"]
|
29
|
+
url
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_xhr_redirected_to
|
33
|
+
if session && session[:_turbolinks_redirect_to]
|
34
|
+
response.headers['X-XHR-Redirected-To'] = session.delete :_turbolinks_redirect_to
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Ensure backwards compatibility
|
39
|
+
# Rails < 4.2: _compute_redirect_to_location(options)
|
40
|
+
# Rails >= 4.2: _compute_redirect_to_location(request, options)
|
41
|
+
def _normalize_redirect_params(args)
|
42
|
+
options, req = args.reverse
|
43
|
+
[options, req || request]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Turbolinks
|
2
|
+
# Corrects the behavior of url_for (and link_to, which uses url_for) with the :back
|
3
|
+
# option by using the X-XHR-Referer request header instead of the standard Referer
|
4
|
+
# request header.
|
5
|
+
module XHRUrlFor
|
6
|
+
def self.included(base)
|
7
|
+
base.alias_method_chain :url_for, :xhr_referer
|
8
|
+
end
|
9
|
+
|
10
|
+
def url_for_with_xhr_referer(options = {})
|
11
|
+
options = (controller.request.headers["X-XHR-Referer"] || options) if options == :back
|
12
|
+
url_for_without_xhr_referer options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/test/config.ru
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'sprockets'
|
2
|
+
require 'coffee-script'
|
3
|
+
|
4
|
+
Root = File.expand_path("../..", __FILE__)
|
5
|
+
|
6
|
+
Assets = Sprockets::Environment.new do |env|
|
7
|
+
env.append_path File.join(Root, "lib", "assets", "javascripts")
|
8
|
+
end
|
9
|
+
|
10
|
+
class SlowResponse
|
11
|
+
CHUNKS = ['<html><body>', '.'*50, '.'*20, '<a href="/index.html">Home</a></body></html>']
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
[200, headers, self]
|
15
|
+
end
|
16
|
+
|
17
|
+
def each
|
18
|
+
CHUNKS.each do |part|
|
19
|
+
sleep rand(0.3..0.8)
|
20
|
+
yield part
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def length
|
25
|
+
CHUNKS.join.length
|
26
|
+
end
|
27
|
+
|
28
|
+
def headers
|
29
|
+
{ "Content-Length" => length.to_s, "Content-Type" => "text/html", "Cache-Control" => "no-cache, no-store, must-revalidate" }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
map "/js" do
|
34
|
+
run Assets
|
35
|
+
end
|
36
|
+
|
37
|
+
map "/500" do
|
38
|
+
# throw Internal Server Error (500)
|
39
|
+
end
|
40
|
+
|
41
|
+
map "/withoutextension" do
|
42
|
+
run Rack::File.new(File.join(Root, "test", "withoutextension"), "Content-Type" => "text/html")
|
43
|
+
end
|
44
|
+
|
45
|
+
map "/slow-response" do
|
46
|
+
run SlowResponse.new
|
47
|
+
end
|
48
|
+
|
49
|
+
map "/bounce" do
|
50
|
+
run Proc.new{ [200, { "X-XHR-Redirected-To" => "redirect1.html", "Content-Type" => "text/html" }, File.open( File.join( Root, "test", "redirect1.html" ) ) ] }
|
51
|
+
end
|
52
|
+
|
53
|
+
map "/" do
|
54
|
+
run Rack::Directory.new(File.join(Root, "test"))
|
55
|
+
end
|
56
|
+
|
57
|
+
map "/attachment.txt" do
|
58
|
+
run Rack::File.new(File.join(Root, "test", "attachment.html"), "Content-Type" => "text/plain")
|
59
|
+
end
|
60
|
+
|
61
|
+
map "/attachment.html" do
|
62
|
+
run Rack::File.new(File.join(Root, "test", "attachment.html"), "Content-Type" => "text/html", "Content-Disposition" => "attachment; filename=attachment.html")
|
63
|
+
end
|
data/test/dummy.gif
ADDED
Binary file
|
data/test/index.html
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js"></script>
|
7
|
+
<script type="text/javascript">
|
8
|
+
Turbolinks.enableProgressBar();
|
9
|
+
|
10
|
+
document.addEventListener("page:change", function() {
|
11
|
+
console.log("page changed");
|
12
|
+
});
|
13
|
+
|
14
|
+
document.addEventListener("page:update", function() {
|
15
|
+
console.log("page updated");
|
16
|
+
});
|
17
|
+
|
18
|
+
document.addEventListener("page:restore", function() {
|
19
|
+
console.log("page restored");
|
20
|
+
});
|
21
|
+
</script>
|
22
|
+
</head>
|
23
|
+
<body class="page-index">
|
24
|
+
<ul style="margin-top:20px;">
|
25
|
+
<li><a href="/other.html">Other page</a></li>
|
26
|
+
<li><a href="/slow-response">Slow loading page for progress bar</a></li>
|
27
|
+
<li><a href="/other.html"><span>Wrapped link</span></a></li>
|
28
|
+
<li><a href="/withoutextension">Without extension</a></li>
|
29
|
+
<li><a href="/withoutextension?sort=user.name">Without extension with query params</a></li>
|
30
|
+
<li><a href="http://www.google.com/">Cross origin</a></li>
|
31
|
+
<li><a href="/other.html" onclick="if(!confirm('follow link?')) { return false}">Confirm Fire Order</a></li>
|
32
|
+
<li><a href="/reload.html"><span>New assets track </span></a></li>
|
33
|
+
<li><a href="/dummy.gif?12345">Query Param Image Link</a></li>
|
34
|
+
<li><a href="/bounce">Redirect</a></li>
|
35
|
+
<li><a href="#">Hash link</a></li>
|
36
|
+
<li><a href="/reload.html#foo">New assets track with hash link</a></li>
|
37
|
+
<li><a href="/attachment.txt">A text response should load normally</a></li>
|
38
|
+
<li><a href="/attachment.html">An html response with Content-Disposition: attachment should load normally</a></li>
|
39
|
+
<li><h5>If you stop the server or go into airplane/offline mode</h5></li>
|
40
|
+
<li><a href="/doesnotexist.html">A page with client error (4xx, rfc2616 sec. 10.4) should error out</a></li>
|
41
|
+
<li><a href="/500">Also server errors (5xx, rfc2616 sec. 10.5) should error out</a></li>
|
42
|
+
<li><a href="/fallback.html">A page that has a fallback in appcache should fallback</a></li>
|
43
|
+
</ul>
|
44
|
+
|
45
|
+
<div style="background:#ccc;height:5000px;width:200px;">
|
46
|
+
</div>
|
47
|
+
<iframe height='1' scrolling='no' src='/offline.html' style='display: none;' width='1'></iframe>
|
48
|
+
|
49
|
+
<script type="text/javascript" data-turbolinks-eval=false>
|
50
|
+
console.log("turbolinks-eval-false script fired. This should only happen on the initial page load.");
|
51
|
+
</script>
|
52
|
+
</body>
|
53
|
+
</html>
|
data/test/offline.html
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en" manifest="/manifest.appcache">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js"></script>
|
7
|
+
<script type="text/javascript">
|
8
|
+
document.addEventListener("page:change", function() {
|
9
|
+
console.log("page changed");
|
10
|
+
});
|
11
|
+
</script>
|
12
|
+
</head>
|
13
|
+
<body class="page-offline">
|
14
|
+
<h1>Offline Mode Fallback</h1>
|
15
|
+
<ul>
|
16
|
+
<li><a href="/index.html">Home</a></li>
|
17
|
+
</ul>
|
18
|
+
</body>
|
19
|
+
</html>
|
data/test/other.html
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js"></script>
|
7
|
+
<script type="text/javascript">
|
8
|
+
document.addEventListener("page:change", function() {
|
9
|
+
console.log("page changed");
|
10
|
+
});
|
11
|
+
|
12
|
+
document.addEventListener("page:update", function() {
|
13
|
+
console.log("page updated");
|
14
|
+
});
|
15
|
+
|
16
|
+
document.addEventListener("page:restore", function() {
|
17
|
+
console.log("page restored");
|
18
|
+
});
|
19
|
+
</script>
|
20
|
+
</head>
|
21
|
+
<body class="page-other">
|
22
|
+
<ul>
|
23
|
+
<li><a href="/index.html">Home</a></li>
|
24
|
+
</ul>
|
25
|
+
</body>
|
26
|
+
</html>
|
data/test/redirect1.html
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js"></script>
|
7
|
+
</head>
|
8
|
+
<body class="page-other">
|
9
|
+
Should show /redirect1.html as path
|
10
|
+
<ul>
|
11
|
+
<li>Click <a href="/redirect2.html">Redirect 2</a></li>
|
12
|
+
</ul>
|
13
|
+
|
14
|
+
</body>
|
15
|
+
</html>
|
data/test/redirect2.html
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js"></script>
|
7
|
+
</head>
|
8
|
+
<body class="page-other">
|
9
|
+
Hit back button twice. It should go back to home page.
|
10
|
+
</body>
|
11
|
+
</html>
|
data/test/reload.html
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js?1" data-turbolinks-track='true'></script>
|
7
|
+
<script type="text/javascript">
|
8
|
+
document.addEventListener("page:change", function() {
|
9
|
+
console.log("page changed");
|
10
|
+
});
|
11
|
+
</script>
|
12
|
+
</head>
|
13
|
+
<body class="page-reload">
|
14
|
+
<ul>
|
15
|
+
<li><a href="/index.html">Home</a></li>
|
16
|
+
</ul>
|
17
|
+
</body>
|
18
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Home</title>
|
6
|
+
<script type="text/javascript" src="/js/turbolinks.js"></script>
|
7
|
+
<script type="text/javascript">
|
8
|
+
document.addEventListener("page:change", function() {
|
9
|
+
console.log("page changed");
|
10
|
+
});
|
11
|
+
|
12
|
+
document.addEventListener("page:update", function() {
|
13
|
+
console.log("page updated");
|
14
|
+
});
|
15
|
+
|
16
|
+
document.addEventListener("page:restore", function() {
|
17
|
+
console.log("page restored");
|
18
|
+
});
|
19
|
+
</script>
|
20
|
+
</head>
|
21
|
+
<body class="page-other">
|
22
|
+
<ul>
|
23
|
+
<li><a href="/index.html">Home</a></li>
|
24
|
+
</ul>
|
25
|
+
</body>
|
26
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gitlab-turbolinks-classic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.5.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Heinemeier Hansson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: coffee-rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description:
|
28
|
+
email: david@loudthinking.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- MIT-LICENSE
|
34
|
+
- README.md
|
35
|
+
- lib/assets/javascripts/turbolinks.js.coffee
|
36
|
+
- lib/turbolinks.rb
|
37
|
+
- lib/turbolinks/cookies.rb
|
38
|
+
- lib/turbolinks/redirection.rb
|
39
|
+
- lib/turbolinks/version.rb
|
40
|
+
- lib/turbolinks/x_domain_blocker.rb
|
41
|
+
- lib/turbolinks/xhr_headers.rb
|
42
|
+
- lib/turbolinks/xhr_url_for.rb
|
43
|
+
- test/attachment.html
|
44
|
+
- test/config.ru
|
45
|
+
- test/dummy.gif
|
46
|
+
- test/index.html
|
47
|
+
- test/manifest.appcache
|
48
|
+
- test/offline.html
|
49
|
+
- test/other.html
|
50
|
+
- test/redirect1.html
|
51
|
+
- test/redirect2.html
|
52
|
+
- test/reload.html
|
53
|
+
- test/withoutextension
|
54
|
+
homepage: https://gitlab.com/jamedjo/gitlab-turbolinks-classic/
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.5.1
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Turbolinks makes following links in your web application faster (use with
|
78
|
+
Rails Asset Pipeline)
|
79
|
+
test_files: []
|