turbolinks-js 0.1.0 → 0.2.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/README.md CHANGED
@@ -1,52 +1,14 @@
1
1
  Turbolinks-js
2
2
  =============
3
3
 
4
- Same as [Turbolinks](https://github.com/rails/turbolinks) but without CoffeeScript
5
- requirement.
4
+ Same as Turbolinks but without the CoffeeScript requirement.
5
+ Check [Turbolinks](https://github.com/rails/turbolinks) for
6
+ more information.
6
7
 
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.
8
+ Installation
9
+ ------------
12
10
 
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.
11
+ 1. Add `gem 'turbolinks-js'` to your Gemfile.
12
+ 2. Run `bundle install`.
13
+ 3. Add `//= require turbolinks` to your Javascript manifest file (usually found at `app/assets/javascripts/application.js`).
14
+ 4. Restart your server and you're now using turbolinks!
@@ -1,8 +1,16 @@
1
+ // Generated by CoffeeScript 1.3.3
1
2
  (function() {
2
- var anchoredLink, browserSupportsPushState, createDocument, crossOriginLink, extractLink, fetchReplacement, fullReplacement, handleClick, ignoreClick, newTabClick, noTurbolink, nonHtmlLink, reflectNewUrl, rememberInitialPage, replaceHTML, triggerPageChange, visit;
3
+ var anchoredLink, browserSupportsPushState, cacheCurrentPage, changePage, createDocument, crossOriginLink, currentState, extractLink, extractTitleAndBody, fetchHistory, fetchReplacement, garbageCollectCache, handleClick, ignoreClick, initialized, newTabClick, noTurbolink, nonHtmlLink, pageCache, recallScrollPosition, reflectNewUrl, rememberCurrentState, rememberCurrentUrl, rememberInitialPage, samePageLink, triggerEvent, visit;
4
+
5
+ pageCache = [];
6
+
7
+ currentState = null;
8
+
9
+ initialized = false;
3
10
 
4
11
  visit = function(url) {
5
- if (typeof browserSupportsPushState !== "undefined" && browserSupportsPushState !== null) {
12
+ if (browserSupportsPushState) {
13
+ cacheCurrentPage();
6
14
  reflectNewUrl(url);
7
15
  return fetchReplacement(url);
8
16
  } else {
@@ -16,47 +24,109 @@
16
24
  xhr.open('GET', url, true);
17
25
  xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
18
26
  xhr.onload = function() {
19
- return fullReplacement(xhr.responseText, url);
27
+ return changePage.apply(null, extractTitleAndBody(xhr.responseText));
20
28
  };
21
29
  xhr.onabort = function() {
22
- return console.log("Aborted turbolink fetch!");
30
+ return console.log('Aborted turbolink fetch!');
23
31
  };
24
32
  return xhr.send();
25
33
  };
26
34
 
27
- fullReplacement = function(html, url) {
28
- replaceHTML(html);
29
- return triggerPageChange();
35
+ fetchHistory = function(state) {
36
+ var page;
37
+ cacheCurrentPage();
38
+ if (page = pageCache[state.position]) {
39
+ changePage(page.title, page.body.cloneNode(true));
40
+ return recallScrollPosition(page);
41
+ } else {
42
+ return fetchReplacement(document.location.href);
43
+ }
44
+ };
45
+
46
+ cacheCurrentPage = function() {
47
+ rememberInitialPage();
48
+ pageCache[currentState.position] = {
49
+ url: document.location.href,
50
+ body: document.body,
51
+ title: document.title,
52
+ positionY: window.pageYOffset,
53
+ positionX: window.pageXOffset
54
+ };
55
+ return garbageCollectCache();
56
+ };
57
+
58
+ garbageCollectCache = function() {
59
+ if (currentState.position === window.history.length - 1 && pageCache[currentState.position - 10] !== void 0) {
60
+ return delete pageCache[currentState.position - 10];
61
+ }
62
+ };
63
+
64
+ changePage = function(title, body) {
65
+ document.title = title;
66
+ document.documentElement.replaceChild(body, document.body);
67
+ currentState = window.history.state;
68
+ return triggerEvent('page:change');
30
69
  };
31
70
 
32
71
  reflectNewUrl = function(url) {
33
72
  return window.history.pushState({
34
- turbolinks: true
35
- }, "", url);
73
+ turbolinks: true,
74
+ position: window.history.length
75
+ }, '', url);
76
+ };
77
+
78
+ rememberCurrentUrl = function() {
79
+ return window.history.replaceState({
80
+ turbolinks: true,
81
+ position: window.history.length - 1
82
+ }, '', document.location.href);
36
83
  };
37
84
 
38
- triggerPageChange = function() {
85
+ rememberCurrentState = function() {
86
+ return currentState = window.history.state;
87
+ };
88
+
89
+ rememberInitialPage = function() {
90
+ if (!initialized) {
91
+ rememberCurrentUrl();
92
+ rememberCurrentState();
93
+ return initialized = true;
94
+ }
95
+ };
96
+
97
+ recallScrollPosition = function(page) {
98
+ return window.scrollTo(page.positionX, page.positionX);
99
+ };
100
+
101
+ triggerEvent = function(name) {
39
102
  var event;
40
103
  event = document.createEvent('Events');
41
- event.initEvent('page:change', true, true);
104
+ event.initEvent(name, true, true);
42
105
  return document.dispatchEvent(event);
43
106
  };
44
107
 
108
+ extractTitleAndBody = function(html) {
109
+ var doc, title;
110
+ doc = createDocument(html);
111
+ title = doc.querySelector('title');
112
+ return [title != null ? title.textContent : void 0, doc.body];
113
+ };
114
+
45
115
  createDocument = (function() {
46
116
  var createDocumentUsingParser, createDocumentUsingWrite, testDoc, _ref;
47
117
  createDocumentUsingParser = function(html) {
48
- return (new DOMParser).parseFromString(html, "text/html");
118
+ return (new DOMParser).parseFromString(html, 'text/html');
49
119
  };
50
120
  createDocumentUsingWrite = function(html) {
51
121
  var doc;
52
- doc = document.implementation.createHTMLDocument("");
53
- doc.open("replace");
122
+ doc = document.implementation.createHTMLDocument('');
123
+ doc.open('replace');
54
124
  doc.write(html);
55
125
  doc.close;
56
126
  return doc;
57
127
  };
58
128
  if (window.DOMParser) {
59
- testDoc = createDocumentUsingParser("<html><body><p>test");
129
+ testDoc = createDocumentUsingParser('<html><body><p>test');
60
130
  }
61
131
  if ((testDoc != null ? (_ref = testDoc.body) != null ? _ref.childNodes.length : void 0 : void 0) === 1) {
62
132
  return createDocumentUsingParser;
@@ -65,17 +135,6 @@
65
135
  }
66
136
  })();
67
137
 
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
138
  extractLink = function(event) {
80
139
  var link;
81
140
  link = event.target;
@@ -85,6 +144,10 @@
85
144
  return link;
86
145
  };
87
146
 
147
+ samePageLink = function(link) {
148
+ return link.href === document.location.href;
149
+ };
150
+
88
151
  crossOriginLink = function(link) {
89
152
  return location.protocol !== link.protocol || location.host !== link.host;
90
153
  };
@@ -106,7 +169,7 @@
106
169
  };
107
170
 
108
171
  ignoreClick = function(event, link) {
109
- return crossOriginLink(link) || anchoredLink(link) || nonHtmlLink(link) || noTurbolink(link) || newTabClick(event);
172
+ return samePageLink(link) || crossOriginLink(link) || anchoredLink(link) || nonHtmlLink(link) || noTurbolink(link) || newTabClick(event);
110
173
  };
111
174
 
112
175
  handleClick = function(event) {
@@ -120,18 +183,11 @@
120
183
 
121
184
  browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState;
122
185
 
123
- rememberInitialPage = function() {
124
- return window.history.replaceState({
125
- turbolinks: true
126
- }, "", document.location.href);
127
- };
128
-
129
186
  if (browserSupportsPushState) {
130
- rememberInitialPage();
131
187
  window.addEventListener('popstate', function(event) {
132
188
  var _ref;
133
189
  if ((_ref = event.state) != null ? _ref.turbolinks : void 0) {
134
- return fetchReplacement(document.location.href);
190
+ return fetchHistory(event.state);
135
191
  }
136
192
  });
137
193
  document.addEventListener('click', function(event) {
data/test/config.ru CHANGED
@@ -1,10 +1,9 @@
1
1
  require 'sprockets'
2
- require 'coffee-script'
3
2
 
4
3
  Root = File.expand_path("../..", __FILE__)
5
4
 
6
5
  Assets = Sprockets::Environment.new do |env|
7
- env.append_path File.join(Root, "lib", "assets", "javascripts")
6
+ env.append_path File.join(Root, 'lib', 'assets', 'javascripts')
8
7
  end
9
8
 
10
9
  map "/js" do
data/test/dummy.gif ADDED
Binary file
data/test/index.html CHANGED
@@ -10,11 +10,16 @@
10
10
  });
11
11
  </script>
12
12
  </head>
13
- <body>
14
- <ul>
13
+ <body class="page-index">
14
+ <ul style="margin-top:200px;">
15
15
  <li><a href="/test/other.html">Other page</a></li>
16
16
  <li><a href="/test/other.html"><span>Wrapped link</span></a></li>
17
17
  <li><a href="http://www.google.com/">Cross origin</a></li>
18
+ <li><a href="/test/dummy.gif?12345">Query Param Image Link</a></li>
19
+ <li><a href="#">Hash link</a></li>
18
20
  </ul>
21
+
22
+ <div style="background:#ccc;height:5000px;width:200px;">
23
+ </div>
19
24
  </body>
20
25
  </html>
data/test/other.html CHANGED
@@ -10,7 +10,7 @@
10
10
  });
11
11
  </script>
12
12
  </head>
13
- <body>
13
+ <body class="page-other">
14
14
  <ul>
15
15
  <li><a href="/test/index.html">Home</a></li>
16
16
  </ul>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbolinks-js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -24,6 +24,7 @@ files:
24
24
  - README.md
25
25
  - MIT-LICENSE
26
26
  - test/config.ru
27
+ - test/dummy.gif
27
28
  - test/index.html
28
29
  - test/other.html
29
30
  homepage:
@@ -49,7 +50,6 @@ rubyforge_project:
49
50
  rubygems_version: 1.8.23
50
51
  signing_key:
51
52
  specification_version: 3
52
- summary: Turbolinks-js makes following links in your web application faster (use with
53
- Rails Asset Pipeline). No CoffeeScript requirement.
53
+ summary: Same as Turbolinks but without the CoffeeScript requirement
54
54
  test_files: []
55
55
  has_rdoc: