turbolinks 2.2.1 → 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +1 -0
- data/lib/assets/javascripts/turbolinks.js.coffee +121 -73
- data/lib/turbolinks.rb +15 -11
- data/lib/turbolinks/version.rb +1 -1
- data/lib/turbolinks/xhr_url_for.rb +3 -8
- data/test/config.ru +4 -0
- data/test/index.html +2 -0
- data/test/withoutextension +26 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a29652f5af8636c6c8e56062fcaee11ec2997453
|
4
|
+
data.tar.gz: c90a5773bee34e8d043876e5a3b4f4520bda207c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d2be7089afe4cc2c492090bd411cc325900df7515875f9917ab76ce29316eb2f8a358e39381d04aa73fdc3a4eb542ea261dd2126cab16bcd66d844b02ac4207
|
7
|
+
data.tar.gz: 2dff851cfb527fdc0e6b3bb262dfb0baaea02f602b0f170da6cd020d9c45412c9346e877230d42af72b2754d11125034c61ba8721faa5a7127a10163d2ed12a4
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -197,6 +197,7 @@ Language Ports
|
|
197
197
|
* [Flask Turbolinks](https://github.com/lepture/flask-turbolinks) (Python Flask)
|
198
198
|
* [ASP.NET MVC Turbolinks](https://github.com/kazimanzurrashid/aspnetmvcturbolinks)
|
199
199
|
* [PHP Turbolinks Component](https://github.com/helthe/Turbolinks) (Symfony Component)
|
200
|
+
* [PHP Turbolinks Package](https://github.com/frenzyapp/turbolinks) (Laravel Package)
|
200
201
|
|
201
202
|
Credits
|
202
203
|
-------
|
@@ -4,7 +4,6 @@ transitionCacheEnabled = false
|
|
4
4
|
|
5
5
|
currentState = null
|
6
6
|
loadedAssets = null
|
7
|
-
htmlExtensions = ['html']
|
8
7
|
|
9
8
|
referer = null
|
10
9
|
|
@@ -13,11 +12,13 @@ xhr = null
|
|
13
12
|
|
14
13
|
|
15
14
|
fetch = (url) ->
|
15
|
+
url = new ComponentUrl url
|
16
|
+
|
16
17
|
rememberReferer()
|
17
18
|
cacheCurrentPage()
|
18
19
|
reflectNewUrl url
|
19
20
|
|
20
|
-
if transitionCacheEnabled and cachedPage = transitionCacheFor(url)
|
21
|
+
if transitionCacheEnabled and cachedPage = transitionCacheFor(url.absolute)
|
21
22
|
fetchHistory cachedPage
|
22
23
|
fetchReplacement url
|
23
24
|
else
|
@@ -31,11 +32,11 @@ enableTransitionCache = (enable = true) ->
|
|
31
32
|
transitionCacheEnabled = enable
|
32
33
|
|
33
34
|
fetchReplacement = (url, onLoadFunction = =>) ->
|
34
|
-
triggerEvent 'page:fetch', url: url
|
35
|
+
triggerEvent 'page:fetch', url: url.absolute
|
35
36
|
|
36
37
|
xhr?.abort()
|
37
38
|
xhr = new XMLHttpRequest
|
38
|
-
xhr.open 'GET',
|
39
|
+
xhr.open 'GET', url.withoutHashForIE10compatibility(), true
|
39
40
|
xhr.setRequestHeader 'Accept', 'text/html, application/xhtml+xml, application/xml'
|
40
41
|
xhr.setRequestHeader 'X-XHR-Referer', referer
|
41
42
|
|
@@ -48,10 +49,10 @@ fetchReplacement = (url, onLoadFunction = =>) ->
|
|
48
49
|
onLoadFunction()
|
49
50
|
triggerEvent 'page:load'
|
50
51
|
else
|
51
|
-
document.location.href = url
|
52
|
+
document.location.href = url.absolute
|
52
53
|
|
53
54
|
xhr.onloadend = -> xhr = null
|
54
|
-
xhr.onerror = -> document.location.href = url
|
55
|
+
xhr.onerror = -> document.location.href = url.absolute
|
55
56
|
|
56
57
|
xhr.send()
|
57
58
|
|
@@ -63,8 +64,10 @@ fetchHistory = (cachedPage) ->
|
|
63
64
|
|
64
65
|
|
65
66
|
cacheCurrentPage = ->
|
66
|
-
|
67
|
-
|
67
|
+
currentStateUrl = new ComponentUrl currentState.url
|
68
|
+
|
69
|
+
pageCache[currentStateUrl.absolute] =
|
70
|
+
url: currentStateUrl.relative,
|
68
71
|
body: document.body,
|
69
72
|
title: document.title,
|
70
73
|
positionY: window.pageYOffset,
|
@@ -113,13 +116,14 @@ removeNoscriptTags = (node) ->
|
|
113
116
|
node
|
114
117
|
|
115
118
|
reflectNewUrl = (url) ->
|
116
|
-
if url isnt referer
|
117
|
-
window.history.pushState { turbolinks: true, url: url }, '', url
|
119
|
+
if (url = new ComponentUrl url).absolute isnt referer
|
120
|
+
window.history.pushState { turbolinks: true, url: url.absolute }, '', url.absolute
|
118
121
|
|
119
122
|
reflectRedirectedUrl = ->
|
120
123
|
if location = xhr.getResponseHeader 'X-XHR-Redirected-To'
|
121
|
-
|
122
|
-
|
124
|
+
location = new ComponentUrl location
|
125
|
+
preservedHash = if location.hasNoHash() then document.location.hash else ''
|
126
|
+
window.history.replaceState currentState, '', location.href + preservedHash
|
123
127
|
|
124
128
|
rememberReferer = ->
|
125
129
|
referer = document.location.href
|
@@ -140,17 +144,6 @@ resetScrollPosition = ->
|
|
140
144
|
window.scrollTo 0, 0
|
141
145
|
|
142
146
|
|
143
|
-
# Intention revealing function alias
|
144
|
-
removeHashForIE10compatiblity = (url) ->
|
145
|
-
removeHash url
|
146
|
-
|
147
|
-
removeHash = (url) ->
|
148
|
-
link = url
|
149
|
-
unless url.href?
|
150
|
-
link = document.createElement 'A'
|
151
|
-
link.href = url
|
152
|
-
link.href.replace link.hash, ''
|
153
|
-
|
154
147
|
popCookie = (name) ->
|
155
148
|
value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
|
156
149
|
document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
|
@@ -242,53 +235,108 @@ browserCompatibleDocumentParser = ->
|
|
242
235
|
return createDocumentUsingWrite
|
243
236
|
|
244
237
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
238
|
+
# The ComponentUrl class converts a basic URL string into an object
|
239
|
+
# that behaves similarly to document.location.
|
240
|
+
#
|
241
|
+
# If an instance is created from a relative URL, the current document
|
242
|
+
# is used to fill in the missing attributes (protocol, host, port).
|
243
|
+
class ComponentUrl
|
244
|
+
constructor: (@original = document.location.href) ->
|
245
|
+
return @original if @original.constructor is ComponentUrl
|
246
|
+
@_parse()
|
247
|
+
|
248
|
+
withoutHash: -> @href.replace @hash, ''
|
249
|
+
|
250
|
+
# Intention revealing function alias
|
251
|
+
withoutHashForIE10compatibility: -> @withoutHash()
|
252
|
+
|
253
|
+
hasNoHash: -> @hash.length is 0
|
254
|
+
|
255
|
+
_parse: ->
|
256
|
+
(@link ?= document.createElement 'a').href = @original
|
257
|
+
{ @href, @protocol, @host, @hostname, @port, @pathname, @search, @hash } = @link
|
258
|
+
@origin = [@protocol, '//', @hostname].join ''
|
259
|
+
@origin += ":#{@port}" unless @port.length is 0
|
260
|
+
@relative = [@pathname, @search, @hash].join ''
|
261
|
+
@absolute = @href
|
262
|
+
|
263
|
+
# The Link class derives from the ComponentUrl class, but is built from an
|
264
|
+
# existing link element. Provides verification functionality for Turbolinks
|
265
|
+
# to use in determining whether it should process the link when clicked.
|
266
|
+
class Link extends ComponentUrl
|
267
|
+
@HTML_EXTENSIONS: ['html']
|
268
|
+
|
269
|
+
@allowExtensions: (extensions...) ->
|
270
|
+
Link.HTML_EXTENSIONS.push extension for extension in extensions
|
271
|
+
Link.HTML_EXTENSIONS
|
272
|
+
|
273
|
+
constructor: (@link) ->
|
274
|
+
return @link if @link.constructor is Link
|
275
|
+
@original = @link.href
|
276
|
+
super
|
277
|
+
|
278
|
+
shouldIgnore: ->
|
279
|
+
@_crossOrigin() or
|
280
|
+
@_anchored() or
|
281
|
+
@_nonHtml() or
|
282
|
+
@_optOut() or
|
283
|
+
@_target()
|
284
|
+
|
285
|
+
_crossOrigin: ->
|
286
|
+
@origin isnt (new ComponentUrl).origin
|
287
|
+
|
288
|
+
_anchored: ->
|
289
|
+
((@hash and @withoutHash()) is (current = new ComponentUrl).withoutHash()) or
|
290
|
+
(@href is current.href + '#')
|
291
|
+
|
292
|
+
_nonHtml: ->
|
293
|
+
@pathname.match(/\.[a-z]+$/g) and not @pathname.match(new RegExp("\\.(?:#{Link.HTML_EXTENSIONS.join('|')})?$", 'g'))
|
294
|
+
|
295
|
+
_optOut: ->
|
296
|
+
link = @link
|
297
|
+
until ignore or link is document
|
298
|
+
ignore = link.getAttribute('data-no-turbolink')?
|
299
|
+
link = link.parentNode
|
300
|
+
ignore
|
301
|
+
|
302
|
+
_target: ->
|
303
|
+
@link.target.length isnt 0
|
304
|
+
|
305
|
+
|
306
|
+
# The Click class handles clicked links, verifying if Turbolinks should
|
307
|
+
# take control by inspecting both the event and the link. If it should,
|
308
|
+
# the page change process is initiated. If not, control is passed back
|
309
|
+
# to the browser for default functionality.
|
310
|
+
class Click
|
311
|
+
@installHandlerLast: (event) ->
|
312
|
+
unless event.defaultPrevented
|
313
|
+
document.removeEventListener 'click', Click.handle, false
|
314
|
+
document.addEventListener 'click', Click.handle, false
|
315
|
+
|
316
|
+
@handle: (event) ->
|
317
|
+
new Click event
|
318
|
+
|
319
|
+
constructor: (@event) ->
|
320
|
+
return if @event.defaultPrevented
|
321
|
+
@_extractLink()
|
322
|
+
if @_validForTurbolinks()
|
323
|
+
visit @link.href unless pageChangePrevented()
|
324
|
+
@event.preventDefault()
|
325
|
+
|
326
|
+
_extractLink: ->
|
327
|
+
link = @event.target
|
328
|
+
link = link.parentNode until !link.parentNode or link.nodeName is 'A'
|
329
|
+
@link = new Link(link) if link.nodeName is 'A' and link.href.length isnt 0
|
330
|
+
|
331
|
+
_validForTurbolinks: ->
|
332
|
+
@link? and not (@link.shouldIgnore() or @_nonStandardClick())
|
333
|
+
|
334
|
+
_nonStandardClick: ->
|
335
|
+
@event.which > 1 or
|
336
|
+
@event.metaKey or
|
337
|
+
@event.ctrlKey or
|
338
|
+
@event.shiftKey or
|
339
|
+
@event.altKey
|
292
340
|
|
293
341
|
|
294
342
|
# Delay execution of function long enough to miss the popstate event
|
@@ -310,7 +358,7 @@ installJqueryAjaxSuccessPageUpdateTrigger = ->
|
|
310
358
|
|
311
359
|
installHistoryChangeHandler = (event) ->
|
312
360
|
if event.state?.turbolinks
|
313
|
-
if cachedPage = pageCache[event.state.url]
|
361
|
+
if cachedPage = pageCache[(new ComponentUrl(event.state.url)).absolute]
|
314
362
|
cacheCurrentPage()
|
315
363
|
fetchHistory cachedPage
|
316
364
|
else
|
@@ -321,7 +369,7 @@ initializeTurbolinks = ->
|
|
321
369
|
rememberCurrentState()
|
322
370
|
createDocument = browserCompatibleDocumentParser()
|
323
371
|
|
324
|
-
document.addEventListener 'click',
|
372
|
+
document.addEventListener 'click', Click.installHandlerLast, true
|
325
373
|
|
326
374
|
bypassOnLoadPopstate ->
|
327
375
|
window.addEventListener 'popstate', installHistoryChangeHandler, false
|
@@ -361,4 +409,4 @@ else
|
|
361
409
|
# Turbolinks.enableTransitionCache()
|
362
410
|
# Turbolinks.allowLinkExtensions('md')
|
363
411
|
# Turbolinks.supported
|
364
|
-
@Turbolinks = { visit, pagesCached, enableTransitionCache, allowLinkExtensions, supported: browserSupportsTurbolinks }
|
412
|
+
@Turbolinks = { visit, pagesCached, enableTransitionCache, allowLinkExtensions: Link.allowExtensions, supported: browserSupportsTurbolinks }
|
data/lib/turbolinks.rb
CHANGED
@@ -8,21 +8,25 @@ require 'turbolinks/redirection'
|
|
8
8
|
module Turbolinks
|
9
9
|
class Engine < ::Rails::Engine
|
10
10
|
initializer :turbolinks do |config|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
ActionController::Base.class_eval do
|
13
|
+
include XHRHeaders, Cookies, XDomainBlocker, Redirection
|
14
|
+
before_filter :set_xhr_redirected_to, :set_request_method_cookie
|
15
|
+
after_filter :abort_xdomain_redirect
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
ActionDispatch::Request.class_eval do
|
19
|
+
def referer
|
20
|
+
self.headers['X-XHR-Referer'] || super
|
21
|
+
end
|
22
|
+
alias referrer referer
|
20
23
|
end
|
21
|
-
alias referrer referer
|
22
24
|
end
|
23
25
|
|
24
|
-
(
|
25
|
-
|
26
|
+
ActiveSupport.on_load(:action_view) do
|
27
|
+
(ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).module_eval do
|
28
|
+
include XHRUrlFor
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
data/lib/turbolinks/version.rb
CHANGED
@@ -7,14 +7,9 @@ module Turbolinks
|
|
7
7
|
base.alias_method_chain :url_for, :xhr_referer
|
8
8
|
end
|
9
9
|
|
10
|
-
def url_for_with_xhr_referer(options)
|
11
|
-
options = (
|
10
|
+
def url_for_with_xhr_referer(options = {})
|
11
|
+
options = (controller.request.headers["X-XHR-Referer"] || options) if options == :back
|
12
12
|
url_for_without_xhr_referer options
|
13
13
|
end
|
14
|
-
|
15
|
-
private
|
16
|
-
def xhr_referer
|
17
|
-
controller.request.headers["X-XHR-Referer"]
|
18
|
-
end
|
19
14
|
end
|
20
|
-
end
|
15
|
+
end
|
data/test/config.ru
CHANGED
@@ -15,6 +15,10 @@ map "/500" do
|
|
15
15
|
# throw Internal Server Error (500)
|
16
16
|
end
|
17
17
|
|
18
|
+
map "/withoutextension" do
|
19
|
+
run Rack::File.new(File.join(Root, "test", "withoutextension"), "Content-Type" => "text/html")
|
20
|
+
end
|
21
|
+
|
18
22
|
map "/" do
|
19
23
|
run Rack::Directory.new(File.join(Root, "test"))
|
20
24
|
end
|
data/test/index.html
CHANGED
@@ -22,6 +22,8 @@
|
|
22
22
|
<ul style="margin-top:200px;">
|
23
23
|
<li><a href="/other.html">Other page</a></li>
|
24
24
|
<li><a href="/other.html"><span>Wrapped link</span></a></li>
|
25
|
+
<li><a href="/withoutextension">Without extension</a></li>
|
26
|
+
<li><a href="/withoutextension?sort=user.name">Without extension with query params</a></li>
|
25
27
|
<li><a href="http://www.google.com/">Cross origin</a></li>
|
26
28
|
<li><a href="/other.html" onclick="if(!confirm('follow link?')) { return false}">Confirm Fire Order</a></li>
|
27
29
|
<li><a href="/reload.html"><span>New assets track </span></a></li>
|
@@ -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
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbolinks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.2
|
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: 2014-
|
11
|
+
date: 2014-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coffee-rails
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- test/offline.html
|
48
48
|
- test/other.html
|
49
49
|
- test/reload.html
|
50
|
+
- test/withoutextension
|
50
51
|
homepage: https://github.com/rails/turbolinks/
|
51
52
|
licenses:
|
52
53
|
- MIT
|