turbolinks 2.2.1 → 2.2.2
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.
- 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
|