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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4b7c786dc5fe799560978873952c05876224aa42
4
- data.tar.gz: f79c665b9dadef0b27cb3d252c9773f90b57e6c7
3
+ metadata.gz: a29652f5af8636c6c8e56062fcaee11ec2997453
4
+ data.tar.gz: c90a5773bee34e8d043876e5a3b4f4520bda207c
5
5
  SHA512:
6
- metadata.gz: 652de423718540abd5069b448a58c6dde9c7c2e92e2ef01c1e48b3356ecee0e2cd706db3084a42489ac88415e3861b72304bc939f7d775891fe3be0e356664c7
7
- data.tar.gz: 39eb0d8d11d6e73b69da4a191dbf99143f4b2b3c4ff0f730684536982808010899fe0cd1e22599e015c28d14899a446b54d8d5cf16420645870040104a552163
6
+ metadata.gz: 6d2be7089afe4cc2c492090bd411cc325900df7515875f9917ab76ce29316eb2f8a358e39381d04aa73fdc3a4eb542ea261dd2126cab16bcd66d844b02ac4207
7
+ data.tar.gz: 2dff851cfb527fdc0e6b3bb262dfb0baaea02f602b0f170da6cd020d9c45412c9346e877230d42af72b2754d11125034c61ba8721faa5a7127a10163d2ed12a4
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2012 David Heinemeier Hansson
1
+ Copyright 2012-2014 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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', removeHashForIE10compatiblity(url), true
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
- pageCache[currentState.url] =
67
- url: document.location.href,
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
- preservedHash = if removeHash(location) is location then document.location.hash else ''
122
- window.history.replaceState currentState, '', location + preservedHash
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
- installClickHandlerLast = (event) ->
246
- unless event.defaultPrevented
247
- document.removeEventListener 'click', handleClick, false
248
- document.addEventListener 'click', handleClick, false
249
-
250
- handleClick = (event) ->
251
- unless event.defaultPrevented
252
- link = extractLink event
253
- if link.nodeName is 'A' and !ignoreClick(event, link)
254
- visit link.href unless pageChangePrevented()
255
- event.preventDefault()
256
-
257
-
258
- extractLink = (event) ->
259
- link = event.target
260
- link = link.parentNode until !link.parentNode or link.nodeName is 'A'
261
- link
262
-
263
- crossOriginLink = (link) ->
264
- location.protocol isnt link.protocol or location.host isnt link.host
265
-
266
- anchoredLink = (link) ->
267
- ((link.hash and removeHash(link)) is removeHash(location)) or
268
- (link.href is location.href + '#')
269
-
270
- nonHtmlLink = (link) ->
271
- url = removeHash link
272
- url.match(/\.[a-z]+(\?.*)?$/g) and not url.match(new RegExp("\\.(?:#{htmlExtensions.join('|')})?(\\?.*)?$", 'g'))
273
-
274
- noTurbolink = (link) ->
275
- until ignore or link is document
276
- ignore = link.getAttribute('data-no-turbolink')?
277
- link = link.parentNode
278
- ignore
279
-
280
- targetLink = (link) ->
281
- link.target.length isnt 0
282
-
283
- nonStandardClick = (event) ->
284
- event.which > 1 or event.metaKey or event.ctrlKey or event.shiftKey or event.altKey
285
-
286
- ignoreClick = (event, link) ->
287
- crossOriginLink(link) or anchoredLink(link) or nonHtmlLink(link) or noTurbolink(link) or targetLink(link) or nonStandardClick(event)
288
-
289
- allowLinkExtensions = (extensions...) ->
290
- htmlExtensions.push extension for extension in extensions
291
- htmlExtensions
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', installClickHandlerLast, true
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
- ActionController::Base.class_eval do
12
- include XHRHeaders, Cookies, XDomainBlocker, Redirection
13
- before_filter :set_xhr_redirected_to, :set_request_method_cookie
14
- after_filter :abort_xdomain_redirect
15
- end
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
- ActionDispatch::Request.class_eval do
18
- def referer
19
- self.headers['X-XHR-Referer'] || super
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
- (ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).module_eval do
25
- include XHRUrlFor
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
@@ -1,3 +1,3 @@
1
1
  module Turbolinks
2
- VERSION = '2.2.1'
2
+ VERSION = '2.2.2'
3
3
  end
@@ -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 = (xhr_referer || options) if options == :back
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.1
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-01-31 00:00:00.000000000 Z
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