turbolinks-js 0.1.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.
- data/MIT-LICENSE +20 -0
- data/README.md +52 -0
- data/lib/assets/javascripts/turbolinks.js +146 -0
- data/lib/turbolinks.rb +4 -0
- data/test/config.ru +14 -0
- data/test/index.html +20 -0
- data/test/other.html +18 -0
- metadata +55 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 David Heinemeier Hansson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
Turbolinks-js
|
2
|
+
=============
|
3
|
+
|
4
|
+
Same as [Turbolinks](https://github.com/rails/turbolinks) but without CoffeeScript
|
5
|
+
requirement.
|
6
|
+
|
7
|
+
Turbolinks makes following links in your web application faster. Instead of
|
8
|
+
letting the browser recompile the JavaScript and CSS between each page change,
|
9
|
+
and potentially spend extra HTTP requests checking if the assets are up-to-date,
|
10
|
+
we keep the current instance alive and replace only the body and the title in the
|
11
|
+
head. Think CGI vs persistent process.
|
12
|
+
|
13
|
+
This is similar to pjax, but instead of worrying about what element on the page to
|
14
|
+
replace, and tailoring the server-side response to fit, we replace the entire body.
|
15
|
+
This means that you get the bulk of the speed benefits from pjax (no recompiling of
|
16
|
+
the JavaScript or CSS) without having to tailor the server-side response. It just
|
17
|
+
works.
|
18
|
+
|
19
|
+
By default, all internal links will be funneled through Turbolinks, but you can opt
|
20
|
+
out by marking links with data-no-turbolink.
|
21
|
+
|
22
|
+
No jQuery or any other framework
|
23
|
+
--------------------------------
|
24
|
+
|
25
|
+
Turbolinks is designed to be as light-weight as possible (so you won't think twice about using it even for mobile stuff). It does not require jQuery or any other framework to work.
|
26
|
+
But it works great _with_ jQuery or Prototype or whatever else have you.
|
27
|
+
|
28
|
+
The page:update event
|
29
|
+
---------------------
|
30
|
+
|
31
|
+
Since pages will change without a full reload with Turbolinks, you can't by default
|
32
|
+
rely on `dom:loaded` to trigger your JavaScript code. Instead, Turbolinks uses the
|
33
|
+
`page:update` event.
|
34
|
+
|
35
|
+
Triggering a Turbolinks visit manually
|
36
|
+
---------------------------------------
|
37
|
+
|
38
|
+
You can use `Turbolinks.visit(path)` to go to a URL through Turbolinks.
|
39
|
+
|
40
|
+
Available only for pushState browsers
|
41
|
+
-------------------------------------
|
42
|
+
|
43
|
+
Like pjax, this naturally only works with browsers capable of `pushState`. But of
|
44
|
+
course we fall back gracefully to full page reloads for browsers that do not support
|
45
|
+
it.
|
46
|
+
|
47
|
+
Work left to do
|
48
|
+
---------------
|
49
|
+
|
50
|
+
* CSS/JS asset change detection and reload.
|
51
|
+
* Add a DOM cache for faster back button.
|
52
|
+
* Remember scroll position when using back button.
|
@@ -0,0 +1,146 @@
|
|
1
|
+
(function() {
|
2
|
+
var anchoredLink, browserSupportsPushState, createDocument, crossOriginLink, extractLink, fetchReplacement, fullReplacement, handleClick, ignoreClick, newTabClick, noTurbolink, nonHtmlLink, reflectNewUrl, rememberInitialPage, replaceHTML, triggerPageChange, visit;
|
3
|
+
|
4
|
+
visit = function(url) {
|
5
|
+
if (typeof browserSupportsPushState !== "undefined" && browserSupportsPushState !== null) {
|
6
|
+
reflectNewUrl(url);
|
7
|
+
return fetchReplacement(url);
|
8
|
+
} else {
|
9
|
+
return document.location.href = url;
|
10
|
+
}
|
11
|
+
};
|
12
|
+
|
13
|
+
fetchReplacement = function(url) {
|
14
|
+
var xhr;
|
15
|
+
xhr = new XMLHttpRequest;
|
16
|
+
xhr.open('GET', url, true);
|
17
|
+
xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
|
18
|
+
xhr.onload = function() {
|
19
|
+
return fullReplacement(xhr.responseText, url);
|
20
|
+
};
|
21
|
+
xhr.onabort = function() {
|
22
|
+
return console.log("Aborted turbolink fetch!");
|
23
|
+
};
|
24
|
+
return xhr.send();
|
25
|
+
};
|
26
|
+
|
27
|
+
fullReplacement = function(html, url) {
|
28
|
+
replaceHTML(html);
|
29
|
+
return triggerPageChange();
|
30
|
+
};
|
31
|
+
|
32
|
+
reflectNewUrl = function(url) {
|
33
|
+
return window.history.pushState({
|
34
|
+
turbolinks: true
|
35
|
+
}, "", url);
|
36
|
+
};
|
37
|
+
|
38
|
+
triggerPageChange = function() {
|
39
|
+
var event;
|
40
|
+
event = document.createEvent('Events');
|
41
|
+
event.initEvent('page:change', true, true);
|
42
|
+
return document.dispatchEvent(event);
|
43
|
+
};
|
44
|
+
|
45
|
+
createDocument = (function() {
|
46
|
+
var createDocumentUsingParser, createDocumentUsingWrite, testDoc, _ref;
|
47
|
+
createDocumentUsingParser = function(html) {
|
48
|
+
return (new DOMParser).parseFromString(html, "text/html");
|
49
|
+
};
|
50
|
+
createDocumentUsingWrite = function(html) {
|
51
|
+
var doc;
|
52
|
+
doc = document.implementation.createHTMLDocument("");
|
53
|
+
doc.open("replace");
|
54
|
+
doc.write(html);
|
55
|
+
doc.close;
|
56
|
+
return doc;
|
57
|
+
};
|
58
|
+
if (window.DOMParser) {
|
59
|
+
testDoc = createDocumentUsingParser("<html><body><p>test");
|
60
|
+
}
|
61
|
+
if ((testDoc != null ? (_ref = testDoc.body) != null ? _ref.childNodes.length : void 0 : void 0) === 1) {
|
62
|
+
return createDocumentUsingParser;
|
63
|
+
} else {
|
64
|
+
return createDocumentUsingWrite;
|
65
|
+
}
|
66
|
+
})();
|
67
|
+
|
68
|
+
replaceHTML = function(html) {
|
69
|
+
var doc, originalBody, title;
|
70
|
+
doc = createDocument(html);
|
71
|
+
originalBody = document.body;
|
72
|
+
document.documentElement.appendChild(doc.body, originalBody);
|
73
|
+
document.documentElement.removeChild(originalBody);
|
74
|
+
if (title = doc.querySelector("title")) {
|
75
|
+
return document.title = title.textContent;
|
76
|
+
}
|
77
|
+
};
|
78
|
+
|
79
|
+
extractLink = function(event) {
|
80
|
+
var link;
|
81
|
+
link = event.target;
|
82
|
+
while (!(link === document || link.nodeName === 'A')) {
|
83
|
+
link = link.parentNode;
|
84
|
+
}
|
85
|
+
return link;
|
86
|
+
};
|
87
|
+
|
88
|
+
crossOriginLink = function(link) {
|
89
|
+
return location.protocol !== link.protocol || location.host !== link.host;
|
90
|
+
};
|
91
|
+
|
92
|
+
anchoredLink = function(link) {
|
93
|
+
return ((link.hash && link.href.replace(link.hash, '')) === location.href.replace(location.hash, '')) || (link.href === location.href + '#');
|
94
|
+
};
|
95
|
+
|
96
|
+
nonHtmlLink = function(link) {
|
97
|
+
return link.href.match(/\.[a-z]+$/g) && !link.href.match(/\.html?$/g);
|
98
|
+
};
|
99
|
+
|
100
|
+
noTurbolink = function(link) {
|
101
|
+
return link.getAttribute('data-no-turbolink') != null;
|
102
|
+
};
|
103
|
+
|
104
|
+
newTabClick = function(event) {
|
105
|
+
return event.which > 1 || event.metaKey || event.ctrlKey;
|
106
|
+
};
|
107
|
+
|
108
|
+
ignoreClick = function(event, link) {
|
109
|
+
return crossOriginLink(link) || anchoredLink(link) || nonHtmlLink(link) || noTurbolink(link) || newTabClick(event);
|
110
|
+
};
|
111
|
+
|
112
|
+
handleClick = function(event) {
|
113
|
+
var link;
|
114
|
+
link = extractLink(event);
|
115
|
+
if (link.nodeName === 'A' && !ignoreClick(event, link)) {
|
116
|
+
visit(link.href);
|
117
|
+
return event.preventDefault();
|
118
|
+
}
|
119
|
+
};
|
120
|
+
|
121
|
+
browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState;
|
122
|
+
|
123
|
+
rememberInitialPage = function() {
|
124
|
+
return window.history.replaceState({
|
125
|
+
turbolinks: true
|
126
|
+
}, "", document.location.href);
|
127
|
+
};
|
128
|
+
|
129
|
+
if (browserSupportsPushState) {
|
130
|
+
rememberInitialPage();
|
131
|
+
window.addEventListener('popstate', function(event) {
|
132
|
+
var _ref;
|
133
|
+
if ((_ref = event.state) != null ? _ref.turbolinks : void 0) {
|
134
|
+
return fetchReplacement(document.location.href);
|
135
|
+
}
|
136
|
+
});
|
137
|
+
document.addEventListener('click', function(event) {
|
138
|
+
return handleClick(event);
|
139
|
+
});
|
140
|
+
}
|
141
|
+
|
142
|
+
this.Turbolinks = {
|
143
|
+
visit: visit
|
144
|
+
};
|
145
|
+
|
146
|
+
}).call(this);
|
data/lib/turbolinks.rb
ADDED
data/test/config.ru
ADDED
@@ -0,0 +1,14 @@
|
|
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
|
+
map "/js" do
|
11
|
+
run Assets
|
12
|
+
end
|
13
|
+
|
14
|
+
run Rack::Directory.new(Root)
|
data/test/index.html
ADDED
@@ -0,0 +1,20 @@
|
|
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
|
+
</script>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<ul>
|
15
|
+
<li><a href="/test/other.html">Other page</a></li>
|
16
|
+
<li><a href="/test/other.html"><span>Wrapped link</span></a></li>
|
17
|
+
<li><a href="http://www.google.com/">Cross origin</a></li>
|
18
|
+
</ul>
|
19
|
+
</body>
|
20
|
+
</html>
|
data/test/other.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"></script>
|
7
|
+
<script type="text/javascript">
|
8
|
+
document.addEventListener("page:change", function() {
|
9
|
+
console.log("page changed");
|
10
|
+
});
|
11
|
+
</script>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<ul>
|
15
|
+
<li><a href="/test/index.html">Home</a></li>
|
16
|
+
</ul>
|
17
|
+
</body>
|
18
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: turbolinks-js
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Heinemeier Hansson
|
9
|
+
- Francesco Rodriguez
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-09-27 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description:
|
16
|
+
email:
|
17
|
+
- lrodriguezsanc@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/assets/javascripts/turbolinks.js
|
23
|
+
- lib/turbolinks.rb
|
24
|
+
- README.md
|
25
|
+
- MIT-LICENSE
|
26
|
+
- test/config.ru
|
27
|
+
- test/index.html
|
28
|
+
- test/other.html
|
29
|
+
homepage:
|
30
|
+
licenses: []
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 1.8.23
|
50
|
+
signing_key:
|
51
|
+
specification_version: 3
|
52
|
+
summary: Turbolinks-js makes following links in your web application faster (use with
|
53
|
+
Rails Asset Pipeline). No CoffeeScript requirement.
|
54
|
+
test_files: []
|
55
|
+
has_rdoc:
|