gitlab-turbolinks-classic 2.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|