turbolinks 1.3.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -6
- data/lib/assets/javascripts/turbolinks.js.coffee +66 -38
- data/lib/turbolinks.rb +13 -1
- data/test/index.html +8 -0
- data/test/other.html +8 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42e6215f4902695d105228b3ee98d24219a2d690
|
4
|
+
data.tar.gz: 57aa487dbbb45d7cd209b295cc0006e6c602c853
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0619a0efb53282613f6e745e89d2eb3bf21673b8b460e9aba14f4bbf6f41df1dd59fb2d555c43ad399a3600f2de8d647764c9af1a32755a693faaf805becefc
|
7
|
+
data.tar.gz: 0e983e4382e1ec55236bc832c4c0021b5fb5766fa3b78e51a5d6d637329eff87a5329c76d281d7c31cb84f0bbd2cf39f913d21077cfecfb5690398879672644d
|
data/README.md
CHANGED
@@ -18,10 +18,10 @@ In any case, the benefit can be up to [twice as fast](https://github.com/stevekl
|
|
18
18
|
The best way to find out just how fast it is? Try it on your own application. It hardly takes any effort at all.
|
19
19
|
|
20
20
|
|
21
|
-
No jQuery or any other
|
21
|
+
No jQuery or any other library
|
22
22
|
--------------------------------
|
23
23
|
|
24
|
-
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
|
24
|
+
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 library to work. But it works great _with_ the jQuery or Prototype framework, or whatever else have you.
|
25
25
|
|
26
26
|
|
27
27
|
Events
|
@@ -33,10 +33,11 @@ With Turbolinks pages will change without a full reload, so you can't rely on `D
|
|
33
33
|
* `page:before-change` a Turbolinks-enabled link has been clicked *(see below for more details)*
|
34
34
|
* `page:fetch` starting to fetch a new target page
|
35
35
|
* `page:receive` the page has been fetched from the server, but not yet parsed
|
36
|
-
* `page:change` the page has been parsed and changed to the new version
|
36
|
+
* `page:change` the page has been parsed and changed to the new version and on DOMContentLoaded
|
37
|
+
* `page:update` is triggered whenever page:change is PLUS on jQuery's ajaxSucess, if jQuery is available (otherwise you can manually trigger it when calling XMLHttpRequest in your own code)
|
37
38
|
* `page:load` is fired at the end of the loading process.
|
38
39
|
|
39
|
-
Handlers bound to the `page:before-change` event may return `false`, which will cancel the Turbolinks process.
|
40
|
+
Handlers bound to the `page:before-change` event may return `false`, which will cancel the Turbolinks process.
|
40
41
|
|
41
42
|
By default, Turbolinks caches 10 of these page loads. It listens to the [popstate](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history#The_popstate_event) event and attempts to restore page state from the cache when it's triggered. When `popstate` is fired the following process happens:
|
42
43
|
|
@@ -58,7 +59,7 @@ To implement a client-side spinner, you could listen for `page:fetch` to start i
|
|
58
59
|
|
59
60
|
document.addEventListener("page:fetch", startSpinner);
|
60
61
|
document.addEventListener("page:receive", stopSpinner);
|
61
|
-
|
62
|
+
|
62
63
|
DOM transformations that are idempotent are best. If you have transformations that are not, hook them to happen only on `page:load` instead of `page:change` (as that would run them again on the cached pages).
|
63
64
|
|
64
65
|
Initialization
|
@@ -88,7 +89,7 @@ By default, all internal HTML links will be funneled through Turbolinks, but you
|
|
88
89
|
</div>
|
89
90
|
```
|
90
91
|
|
91
|
-
Note that internal links to files
|
92
|
+
Note that internal links to files containing a file extension other than **.html** will automatically be opted out of Turbolinks. So links to /images/panda.gif will just work as expected.
|
92
93
|
|
93
94
|
Also, Turbolinks is installed as the last click handler for links. So if you install another handler that calls event.preventDefault(), Turbolinks will not run. This ensures that you can safely use Turbolinks with stuff like `data-method`, `data-remote`, or `data-confirm` from Rails.
|
94
95
|
|
@@ -139,6 +140,8 @@ Triggering a Turbolinks visit manually
|
|
139
140
|
|
140
141
|
You can use `Turbolinks.visit(path)` to go to a URL through Turbolinks.
|
141
142
|
|
143
|
+
You can also use `redirect_via_turbolinks_to` in Rails to perform a redirect via Turbolinks.
|
144
|
+
|
142
145
|
|
143
146
|
Full speed for pushState browsers, graceful fallback for everything else
|
144
147
|
------------------------------------------------------------------------
|
@@ -165,7 +168,10 @@ Installation
|
|
165
168
|
Language Ports
|
166
169
|
--------------
|
167
170
|
|
171
|
+
*These projects are not affiliated with or endorsed by the Rails Turbolinks team.*
|
172
|
+
|
168
173
|
* [Flask Turbolinks](https://github.com/lepture/flask-turbolinks) (Python Flask)
|
174
|
+
* [ASP.NET MVC Turbolinks](https://github.com/kazimanzurrashid/aspnetmvcturbolinks)
|
169
175
|
|
170
176
|
Credits
|
171
177
|
-------
|
@@ -1,22 +1,22 @@
|
|
1
|
+
pageCache = {}
|
1
2
|
cacheSize = 10
|
2
3
|
currentState = null
|
3
|
-
referer = null
|
4
4
|
loadedAssets = null
|
5
|
-
|
5
|
+
|
6
|
+
referer = null
|
7
|
+
|
6
8
|
createDocument = null
|
7
|
-
requestMethod = document.cookie.match(/request_method=(\w+)/)?[1].toUpperCase() or ''
|
8
9
|
xhr = null
|
9
10
|
|
10
11
|
|
11
|
-
fetchReplacement = (url) ->
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
safeUrl = removeHash url
|
12
|
+
fetchReplacement = (url) ->
|
13
|
+
rememberReferer()
|
14
|
+
cacheCurrentPage()
|
15
|
+
triggerEvent 'page:fetch', url: url
|
16
16
|
|
17
17
|
xhr?.abort()
|
18
18
|
xhr = new XMLHttpRequest
|
19
|
-
xhr.open 'GET',
|
19
|
+
xhr.open 'GET', removeHashForIE10compatiblity(url), true
|
20
20
|
xhr.setRequestHeader 'Accept', 'text/html, application/xhtml+xml, application/xml'
|
21
21
|
xhr.setRequestHeader 'X-XHR-Referer', referer
|
22
22
|
|
@@ -27,10 +27,7 @@ fetchReplacement = (url) ->
|
|
27
27
|
reflectNewUrl url
|
28
28
|
changePage extractTitleAndBody(doc)...
|
29
29
|
reflectRedirectedUrl()
|
30
|
-
|
31
|
-
document.location.href = document.location.href
|
32
|
-
else
|
33
|
-
resetScrollPosition()
|
30
|
+
resetScrollPosition()
|
34
31
|
triggerEvent 'page:load'
|
35
32
|
else
|
36
33
|
document.location.href = url
|
@@ -41,12 +38,11 @@ fetchReplacement = (url) ->
|
|
41
38
|
|
42
39
|
xhr.send()
|
43
40
|
|
44
|
-
fetchHistory = (
|
41
|
+
fetchHistory = (cachedPage) ->
|
45
42
|
cacheCurrentPage()
|
46
|
-
page = pageCache[position]
|
47
43
|
xhr?.abort()
|
48
|
-
changePage
|
49
|
-
recallScrollPosition
|
44
|
+
changePage cachedPage.title, cachedPage.body
|
45
|
+
recallScrollPosition cachedPage
|
50
46
|
triggerEvent 'page:restore'
|
51
47
|
|
52
48
|
|
@@ -76,6 +72,7 @@ changePage = (title, body, csrfToken, runScripts) ->
|
|
76
72
|
executeScriptTags() if runScripts
|
77
73
|
currentState = window.history.state
|
78
74
|
triggerEvent 'page:change'
|
75
|
+
triggerEvent 'page:update'
|
79
76
|
|
80
77
|
executeScriptTags = ->
|
81
78
|
scripts = Array::slice.call document.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])'
|
@@ -102,6 +99,9 @@ reflectRedirectedUrl = ->
|
|
102
99
|
preservedHash = if removeHash(location) is location then document.location.hash else ''
|
103
100
|
window.history.replaceState currentState, '', location + preservedHash
|
104
101
|
|
102
|
+
rememberReferer = ->
|
103
|
+
referer = document.location.href
|
104
|
+
|
105
105
|
rememberCurrentUrl = ->
|
106
106
|
window.history.replaceState { turbolinks: true, position: Date.now() }, '', document.location.href
|
107
107
|
|
@@ -112,7 +112,15 @@ recallScrollPosition = (page) ->
|
|
112
112
|
window.scrollTo page.positionX, page.positionY
|
113
113
|
|
114
114
|
resetScrollPosition = ->
|
115
|
-
|
115
|
+
if document.location.hash
|
116
|
+
document.location.href = document.location.href
|
117
|
+
else
|
118
|
+
window.scrollTo 0, 0
|
119
|
+
|
120
|
+
|
121
|
+
# Intention revealing function alias
|
122
|
+
removeHashForIE10compatiblity = (url) ->
|
123
|
+
removeHash url
|
116
124
|
|
117
125
|
removeHash = (url) ->
|
118
126
|
link = url
|
@@ -121,8 +129,14 @@ removeHash = (url) ->
|
|
121
129
|
link.href = url
|
122
130
|
link.href.replace link.hash, ''
|
123
131
|
|
124
|
-
|
132
|
+
popCookie = (name) ->
|
133
|
+
value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
|
134
|
+
document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
|
135
|
+
value
|
136
|
+
|
137
|
+
triggerEvent = (name, data) ->
|
125
138
|
event = document.createEvent 'Events'
|
139
|
+
event.data = data if data
|
126
140
|
event.initEvent name, true, true
|
127
141
|
document.dispatchEvent event
|
128
142
|
|
@@ -250,20 +264,33 @@ nonStandardClick = (event) ->
|
|
250
264
|
ignoreClick = (event, link) ->
|
251
265
|
crossOriginLink(link) or anchoredLink(link) or nonHtmlLink(link) or noTurbolink(link) or targetLink(link) or nonStandardClick(event)
|
252
266
|
|
267
|
+
|
268
|
+
installDocumentReadyPageEventTriggers = ->
|
269
|
+
document.addEventListener 'DOMContentLoaded', ( ->
|
270
|
+
triggerEvent 'page:change'
|
271
|
+
triggerEvent 'page:update'
|
272
|
+
), true
|
273
|
+
|
274
|
+
installJqueryAjaxSuccessPageUpdateTrigger = ->
|
275
|
+
if typeof jQuery isnt 'undefined'
|
276
|
+
jQuery(document).on 'ajaxSuccess', (event, xhr, settings) ->
|
277
|
+
return unless jQuery.trim xhr.responseText
|
278
|
+
triggerEvent 'page:update'
|
279
|
+
|
280
|
+
installHistoryChangeHandler = (event) ->
|
281
|
+
if event.state?.turbolinks
|
282
|
+
if cachedPage = pageCache[event.state.position]
|
283
|
+
fetchHistory cachedPage
|
284
|
+
else
|
285
|
+
visit event.target.location.href
|
286
|
+
|
253
287
|
initializeTurbolinks = ->
|
254
288
|
rememberCurrentUrl()
|
255
289
|
rememberCurrentState()
|
256
290
|
createDocument = browserCompatibleDocumentParser()
|
257
|
-
document.addEventListener 'click', installClickHandlerLast, true
|
258
|
-
window.addEventListener 'popstate', (event) ->
|
259
|
-
state = event.state
|
260
291
|
|
261
|
-
|
262
|
-
|
263
|
-
fetchHistory state.position
|
264
|
-
else
|
265
|
-
visit event.target.location.href
|
266
|
-
, false
|
292
|
+
document.addEventListener 'click', installClickHandlerLast, true
|
293
|
+
window.addEventListener 'popstate', installHistoryChangeHandler, false
|
267
294
|
|
268
295
|
browserSupportsPushState =
|
269
296
|
window.history and window.history.pushState and window.history.replaceState and window.history.state != undefined
|
@@ -272,21 +299,22 @@ browserIsntBuggy =
|
|
272
299
|
!navigator.userAgent.match /CriOS\//
|
273
300
|
|
274
301
|
requestMethodIsSafe =
|
275
|
-
|
302
|
+
popCookie('request_method') in ['GET','']
|
303
|
+
|
304
|
+
browserSupportsTurbolinks = browserSupportsPushState and browserIsntBuggy and requestMethodIsSafe
|
276
305
|
|
277
|
-
|
278
|
-
|
279
|
-
referer = document.location.href
|
280
|
-
cacheCurrentPage()
|
281
|
-
fetchReplacement url
|
306
|
+
installDocumentReadyPageEventTriggers()
|
307
|
+
installJqueryAjaxSuccessPageUpdateTrigger()
|
282
308
|
|
309
|
+
if browserSupportsTurbolinks
|
310
|
+
visit = fetchReplacement
|
283
311
|
initializeTurbolinks()
|
284
312
|
else
|
285
|
-
visit = (url) ->
|
286
|
-
document.location.href = url
|
313
|
+
visit = (url) -> document.location.href = url
|
287
314
|
|
288
315
|
# Public API
|
289
316
|
# Turbolinks.visit(url)
|
290
|
-
# Turbolinks.pagesCached()
|
317
|
+
# Turbolinks.pagesCached()
|
291
318
|
# Turbolinks.pagesCached(20)
|
292
|
-
|
319
|
+
# Turbolinks.supported
|
320
|
+
@Turbolinks = { visit, pagesCached, supported: browserSupportsTurbolinks }
|
data/lib/turbolinks.rb
CHANGED
@@ -47,10 +47,22 @@ module Turbolinks
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
module Redirection
|
51
|
+
extend ActiveSupport::Concern
|
52
|
+
|
53
|
+
def redirect_via_turbolinks_to(url = {}, response_status = {})
|
54
|
+
redirect_to(url, response_status)
|
55
|
+
|
56
|
+
self.status = 200
|
57
|
+
self.response_body = "Turbolinks.visit('#{location}');"
|
58
|
+
response.content_type = Mime::JS
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
50
62
|
class Engine < ::Rails::Engine
|
51
63
|
initializer :turbolinks_xhr_headers do |config|
|
52
64
|
ActionController::Base.class_eval do
|
53
|
-
include XHRHeaders, Cookies, XDomainBlocker
|
65
|
+
include XHRHeaders, Cookies, XDomainBlocker, Redirection
|
54
66
|
before_filter :set_xhr_redirected_to, :set_request_method_cookie
|
55
67
|
after_filter :abort_xdomain_redirect
|
56
68
|
end
|
data/test/index.html
CHANGED
@@ -8,6 +8,14 @@
|
|
8
8
|
document.addEventListener("page:change", function() {
|
9
9
|
console.log("page changed");
|
10
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
|
+
});
|
11
19
|
</script>
|
12
20
|
</head>
|
13
21
|
<body class="page-index">
|
data/test/other.html
CHANGED
@@ -8,6 +8,14 @@
|
|
8
8
|
document.addEventListener("page:change", function() {
|
9
9
|
console.log("page changed");
|
10
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
|
+
});
|
11
19
|
</script>
|
12
20
|
</head>
|
13
21
|
<body class="page-other">
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbolinks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coffee-rails
|
@@ -61,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
61
|
version: '0'
|
62
62
|
requirements: []
|
63
63
|
rubyforge_project:
|
64
|
-
rubygems_version: 2.0.
|
64
|
+
rubygems_version: 2.0.3
|
65
65
|
signing_key:
|
66
66
|
specification_version: 4
|
67
67
|
summary: Turbolinks makes following links in your web application faster (use with
|