turbolinks 2.3.0 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9287368c8706ded534c851a89ad71ea39b090a64
4
- data.tar.gz: ecea87430693e024274720d50e3eea02b43cfe1a
3
+ metadata.gz: 5fba03f6769899590a73f8d2f6f1e2b1756335cc
4
+ data.tar.gz: fcb4ee4559b15a8d3037ccd75636a8de9513365e
5
5
  SHA512:
6
- metadata.gz: dbe8bda0952f6f8f19fc8e0192a1c8305286c14393db2c3a2f5cde40839e1e390d8f301948da3fcbbbdf802960ba28ec6ed414a55f6aeb7dd54be250a4a20d31
7
- data.tar.gz: d0de51d589fc9d6553d4815f8a4e2593a3a7cc7a63e461f5c24f5765347d0e1153a592328f587e31ffa8c762840f7cc6fdd24ed186d0eb2642763211f9c86fd0
6
+ metadata.gz: 0cf63e984ac0cfed94831716ecfaf3db1be2045e83e07d9b8e4304ce6639135ddee36876b6c945fcec564730d33bb5f00e1c66d456218bc0db054568a2ef7790
7
+ data.tar.gz: 6733c1c8dc08e44e4271962e50ed4891ed96e0ba30a531c08025b001ecf700d0b4c5ef082891d62391d91c9a8f0bf81f7ce3e1838bf8774b582302289d42660c
data/README.md CHANGED
@@ -33,8 +33,9 @@ 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 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)
36
+ * `page:before-unload` the page has been parsed and is about to be changed
37
+ * `page:change` the page has been changed to the new version (and on DOMContentLoaded)
38
+ * `page:update` is triggered alongside both page:change and jQuery's ajaxSuccess (if jQuery is available - otherwise you can manually trigger it when calling XMLHttpRequest in your own code)
38
39
  * `page:load` is fired at the end of the loading process.
39
40
 
40
41
  Handlers bound to the `page:before-change` event may return `false`, which will cancel the Turbolinks process.
@@ -42,6 +43,7 @@ Handlers bound to the `page:before-change` event may return `false`, which will
42
43
  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:
43
44
 
44
45
  ***Restore* a cached page from the client-side cache:**
46
+ * `page:before-unload` page has been fetched from the cache and is about to be changed
45
47
  * `page:change` page has changed to the cached page.
46
48
  * `page:restore` is fired at the end of restore process.
47
49
 
@@ -10,6 +10,16 @@ referer = null
10
10
  createDocument = null
11
11
  xhr = null
12
12
 
13
+ EVENTS =
14
+ BEFORE_CHANGE: 'page:before-change'
15
+ FETCH: 'page:fetch'
16
+ RECEIVE: 'page:receive'
17
+ CHANGE: 'page:change'
18
+ UPDATE: 'page:update'
19
+ LOAD: 'page:load'
20
+ RESTORE: 'page:restore'
21
+ BEFORE_UNLOAD: 'page:before-unload'
22
+ EXPIRE: 'page:expire'
13
23
 
14
24
  fetch = (url) ->
15
25
  url = new ComponentUrl url
@@ -30,8 +40,8 @@ transitionCacheFor = (url) ->
30
40
  enableTransitionCache = (enable = true) ->
31
41
  transitionCacheEnabled = enable
32
42
 
33
- fetchReplacement = (url, onLoadFunction = =>) ->
34
- triggerEvent 'page:fetch', url: url.absolute
43
+ fetchReplacement = (url, onLoadFunction = =>) ->
44
+ triggerEvent EVENTS.FETCH, url: url.absolute
35
45
 
36
46
  xhr?.abort()
37
47
  xhr = new XMLHttpRequest
@@ -40,7 +50,7 @@ fetchReplacement = (url, onLoadFunction = =>) ->
40
50
  xhr.setRequestHeader 'X-XHR-Referer', referer
41
51
 
42
52
  xhr.onload = ->
43
- triggerEvent 'page:receive', url: url.absolute
53
+ triggerEvent EVENTS.RECEIVE, url: url.absolute
44
54
 
45
55
  if doc = processResponse()
46
56
  reflectNewUrl url
@@ -48,7 +58,7 @@ fetchReplacement = (url, onLoadFunction = =>) ->
48
58
  manuallyTriggerHashChangeForFirefox()
49
59
  reflectRedirectedUrl()
50
60
  onLoadFunction()
51
- triggerEvent 'page:load'
61
+ triggerEvent EVENTS.LOAD
52
62
  else
53
63
  document.location.href = url.absolute
54
64
 
@@ -61,7 +71,7 @@ fetchHistory = (cachedPage) ->
61
71
  xhr?.abort()
62
72
  changePage cachedPage.title, cachedPage.body
63
73
  recallScrollPosition cachedPage
64
- triggerEvent 'page:restore'
74
+ triggerEvent EVENTS.RESTORE
65
75
 
66
76
 
67
77
  cacheCurrentPage = ->
@@ -89,24 +99,26 @@ constrainPageCacheTo = (limit) ->
89
99
  .sort (a, b) -> b - a
90
100
 
91
101
  for key in pageCacheKeys when pageCache[key].cachedAt <= cacheTimesRecentFirst[limit]
92
- triggerEvent 'page:expire', pageCache[key]
102
+ triggerEvent EVENTS.EXPIRE, pageCache[key]
93
103
  delete pageCache[key]
94
104
 
95
105
  changePage = (title, body, csrfToken, runScripts) ->
106
+ triggerEvent EVENTS.BEFORE_UNLOAD
96
107
  document.title = title
97
108
  document.documentElement.replaceChild body, document.body
98
109
  CSRFToken.update csrfToken if csrfToken?
99
110
  setAutofocusElement()
100
111
  executeScriptTags() if runScripts
101
112
  currentState = window.history.state
102
- triggerEvent 'page:change'
103
- triggerEvent 'page:update'
113
+ triggerEvent EVENTS.CHANGE
114
+ triggerEvent EVENTS.UPDATE
104
115
 
105
116
  executeScriptTags = ->
106
117
  scripts = Array::slice.call document.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])'
107
118
  for script in scripts when script.type in ['', 'text/javascript']
108
119
  copy = document.createElement 'script'
109
120
  copy.setAttribute attr.name, attr.value for attr in script.attributes
121
+ copy.async = false unless script.hasAttribute 'async'
110
122
  copy.appendChild document.createTextNode script.innerHTML
111
123
  { parentNode, nextSibling } = script
112
124
  parentNode.removeChild script
@@ -164,29 +176,39 @@ resetScrollPosition = ->
164
176
  window.scrollTo 0, 0
165
177
 
166
178
 
179
+ clone = (original) ->
180
+ return original if not original? or typeof original isnt 'object'
181
+ copy = new original.constructor()
182
+ copy[key] = clone value for key, value of original
183
+ copy
184
+
167
185
  popCookie = (name) ->
168
186
  value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
169
187
  document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
170
188
  value
171
189
 
172
190
  triggerEvent = (name, data) ->
191
+ if typeof Prototype isnt 'undefined'
192
+ Event.fire document, name, data, true
193
+
173
194
  event = document.createEvent 'Events'
174
195
  event.data = data if data
175
196
  event.initEvent name, true, true
176
197
  document.dispatchEvent event
177
198
 
178
- pageChangePrevented = ->
179
- !triggerEvent 'page:before-change'
199
+ pageChangePrevented = (url) ->
200
+ !triggerEvent EVENTS.BEFORE_CHANGE, url: url
180
201
 
181
202
  processResponse = ->
182
203
  clientOrServerError = ->
183
204
  400 <= xhr.status < 600
184
205
 
185
206
  validContent = ->
186
- xhr.getResponseHeader('Content-Type').match /^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/
207
+ (contentType = xhr.getResponseHeader('Content-Type'))? and
208
+ contentType.match /^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/
187
209
 
188
210
  extractTrackAssets = (doc) ->
189
- for node in doc.head.childNodes when node.getAttribute?('data-turbolinks-track')?
211
+ for node in doc.querySelector('head').childNodes when node.getAttribute?('data-turbolinks-track')?
190
212
  node.getAttribute('src') or node.getAttribute('href')
191
213
 
192
214
  assetsChanged = (doc) ->
@@ -205,7 +227,7 @@ processResponse = ->
205
227
 
206
228
  extractTitleAndBody = (doc) ->
207
229
  title = doc.querySelector 'title'
208
- [ title?.textContent, removeNoscriptTags(doc.body), CSRFToken.get(doc).token, 'runScripts' ]
230
+ [ title?.textContent, removeNoscriptTags(doc.querySelector('body')), CSRFToken.get(doc).token, 'runScripts' ]
209
231
 
210
232
  CSRFToken =
211
233
  get: (doc = document) ->
@@ -233,6 +255,15 @@ browserCompatibleDocumentParser = ->
233
255
  doc.close()
234
256
  doc
235
257
 
258
+ createDocumentUsingFragment = (html) ->
259
+ head = html.match(/<head[^>]*>([\s\S.]*)<\/head>/i)?[0] or '<head></head>'
260
+ body = html.match(/<body[^>]*>([\s\S.]*)<\/body>/i)?[0] or '<body></body>'
261
+ htmlWrapper = document.createElement 'html'
262
+ htmlWrapper.innerHTML = head + body
263
+ doc = document.createDocumentFragment()
264
+ doc.appendChild htmlWrapper
265
+ doc
266
+
236
267
  # Use createDocumentUsingParser if DOMParser is defined and natively
237
268
  # supports 'text/html' parsing (Firefox 12+, IE 10)
238
269
  #
@@ -243,16 +274,32 @@ browserCompatibleDocumentParser = ->
243
274
  # - DOMParser isn't defined
244
275
  # - createDocumentUsingParser returns null due to unsupported type 'text/html' (Chrome, Safari)
245
276
  # - createDocumentUsingDOM doesn't create a valid HTML document (safeguarding against potential edge cases)
277
+ #
278
+ # Use createDocumentUsingFragment if the previously selected parser does not
279
+ # correctly parse <form> tags. (Safari 7.1+ - see github.com/rails/turbolinks/issues/408)
280
+ buildTestsUsing = (createMethod) ->
281
+ buildTest = (fallback, passes) ->
282
+ passes: passes()
283
+ fallback: fallback
284
+
285
+ structureTest = buildTest createDocumentUsingWrite, =>
286
+ (createMethod '<html><body><p>test')?.body?.childNodes.length is 1
287
+
288
+ formNestingTest = buildTest createDocumentUsingFragment, =>
289
+ (createMethod '<html><body><form></form><div></div></body></html>')?.body?.childNodes.length is 2
290
+
291
+ [structureTest, formNestingTest]
292
+
246
293
  try
247
294
  if window.DOMParser
248
- testDoc = createDocumentUsingParser '<html><body><p>test'
295
+ docTests = buildTestsUsing createDocumentUsingParser
249
296
  createDocumentUsingParser
250
297
  catch e
251
- testDoc = createDocumentUsingDOM '<html><body><p>test'
298
+ docTests = buildTestsUsing createDocumentUsingDOM
252
299
  createDocumentUsingDOM
253
300
  finally
254
- unless testDoc?.body?.childNodes.length is 1
255
- return createDocumentUsingWrite
301
+ for docTest in docTests
302
+ return docTest.fallback unless docTest.passes
256
303
 
257
304
 
258
305
  # The ComponentUrl class converts a basic URL string into an object
@@ -265,7 +312,7 @@ class ComponentUrl
265
312
  return @original if @original.constructor is ComponentUrl
266
313
  @_parse()
267
314
 
268
- withoutHash: -> @href.replace @hash, ''
315
+ withoutHash: -> @href.replace(@hash, '').replace('#', '')
269
316
 
270
317
  # Intention revealing function alias
271
318
  withoutHashForIE10compatibility: -> @withoutHash()
@@ -293,6 +340,8 @@ class Link extends ComponentUrl
293
340
  constructor: (@link) ->
294
341
  return @link if @link.constructor is Link
295
342
  @original = @link.href
343
+ @originalElement = @link
344
+ @link = @link.cloneNode false
296
345
  super
297
346
 
298
347
  shouldIgnore: ->
@@ -306,14 +355,14 @@ class Link extends ComponentUrl
306
355
  @origin isnt (new ComponentUrl).origin
307
356
 
308
357
  _anchored: ->
309
- ((@hash and @withoutHash()) is (current = new ComponentUrl).withoutHash()) or
310
- (@href is current.href + '#')
358
+ (@hash.length > 0 or @href.charAt(@href.length - 1) is '#') and
359
+ (@withoutHash() is (new ComponentUrl).withoutHash())
311
360
 
312
361
  _nonHtml: ->
313
362
  @pathname.match(/\.[a-z]+$/g) and not @pathname.match(new RegExp("\\.(?:#{Link.HTML_EXTENSIONS.join('|')})?$", 'g'))
314
363
 
315
364
  _optOut: ->
316
- link = @link
365
+ link = @originalElement
317
366
  until ignore or link is document
318
367
  ignore = link.getAttribute('data-no-turbolink')?
319
368
  link = link.parentNode
@@ -340,7 +389,7 @@ class Click
340
389
  return if @event.defaultPrevented
341
390
  @_extractLink()
342
391
  if @_validForTurbolinks()
343
- visit @link.href unless pageChangePrevented()
392
+ visit @link.href unless pageChangePrevented(@link.absolute)
344
393
  @event.preventDefault()
345
394
 
346
395
  _extractLink: ->
@@ -366,15 +415,15 @@ bypassOnLoadPopstate = (fn) ->
366
415
 
367
416
  installDocumentReadyPageEventTriggers = ->
368
417
  document.addEventListener 'DOMContentLoaded', ( ->
369
- triggerEvent 'page:change'
370
- triggerEvent 'page:update'
418
+ triggerEvent EVENTS.CHANGE
419
+ triggerEvent EVENTS.UPDATE
371
420
  ), true
372
421
 
373
422
  installJqueryAjaxSuccessPageUpdateTrigger = ->
374
423
  if typeof jQuery isnt 'undefined'
375
424
  jQuery(document).on 'ajaxSuccess', (event, xhr, settings) ->
376
425
  return unless jQuery.trim xhr.responseText
377
- triggerEvent 'page:update'
426
+ triggerEvent EVENTS.UPDATE
378
427
 
379
428
  installHistoryChangeHandler = (event) ->
380
429
  if event.state?.turbolinks
@@ -433,4 +482,12 @@ else
433
482
  # Turbolinks.enableTransitionCache()
434
483
  # Turbolinks.allowLinkExtensions('md')
435
484
  # Turbolinks.supported
436
- @Turbolinks = { visit, pagesCached, enableTransitionCache, allowLinkExtensions: Link.allowExtensions, supported: browserSupportsTurbolinks }
485
+ # Turbolinks.EVENTS
486
+ @Turbolinks = {
487
+ visit,
488
+ pagesCached,
489
+ enableTransitionCache,
490
+ allowLinkExtensions: Link.allowExtensions,
491
+ supported: browserSupportsTurbolinks,
492
+ EVENTS: clone(EVENTS)
493
+ }
@@ -1,10 +1,15 @@
1
1
  module Turbolinks
2
- # Sets a request_method cookie containing the request method of the current request.
3
- # The Turbolinks script will not initialize if this cookie is set to anything other than GET.
2
+ # For non-GET requests, sets a request_method cookie containing
3
+ # the request method of the current request. The Turbolinks script
4
+ # will not initialize if this cookie is set.
4
5
  module Cookies
5
6
  private
6
7
  def set_request_method_cookie
7
- cookies[:request_method] = request.request_method
8
+ if request.get?
9
+ cookies.delete(:request_method)
10
+ else
11
+ cookies[:request_method] = request.request_method
12
+ end
8
13
  end
9
14
  end
10
- end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Turbolinks
2
- VERSION = '2.3.0'
2
+ VERSION = '2.4.0'
3
3
  end
@@ -25,12 +25,12 @@ module Turbolinks
25
25
 
26
26
  private
27
27
  def store_for_turbolinks(url)
28
- session[:_turbolinks_redirect_to] = url if request.headers["X-XHR-Referer"]
28
+ session[:_turbolinks_redirect_to] = url if session && request.headers["X-XHR-Referer"]
29
29
  url
30
30
  end
31
31
 
32
32
  def set_xhr_redirected_to
33
- if session[:_turbolinks_redirect_to]
33
+ if session && session[:_turbolinks_redirect_to]
34
34
  response.headers['X-XHR-Redirected-To'] = session.delete :_turbolinks_redirect_to
35
35
  end
36
36
  end
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.3.0
4
+ version: 2.4.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: 2014-08-21 00:00:00.000000000 Z
11
+ date: 2014-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coffee-rails