turbograft 0.0.8 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -11
- data/lib/assets/javascripts/turbograft/click.coffee +1 -4
- data/lib/assets/javascripts/turbograft/initializers.coffee +4 -2
- data/lib/assets/javascripts/turbograft/page.coffee +3 -1
- data/lib/assets/javascripts/turbograft/remote.coffee +18 -21
- data/lib/assets/javascripts/turbograft/turbolinks.coffee +36 -53
- data/lib/turbograft/version.rb +1 -1
- data/lib/turbograft/xhr_headers.rb +16 -5
- data/lib/turbograft.js +978 -0
- metadata +34 -34
- data/lib/assets/javascripts/turbograft/page_cache.coffee +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1adee05ec0b9f2e394fd907aa38f75574715bcd1
|
4
|
+
data.tar.gz: 4d7a8bcaf0016e552e684b38dd0323a7f455b71f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41bfd3ae74adb0c3f62c7cefb2ee566ea1193cb2398a37b11186fd9a57289a6772b16b58de58c6237989e1196f65544a6ee931aacebabebfd663648b4075e744
|
7
|
+
data.tar.gz: 1cd3bc34fd7021780ae31120991cd16bba9cafc8e6f10ea0812f272ebb0816fb0e6a200001810bd16b82f909af901755af953ae42f2843b7a5dd7e21e0579452
|
data/README.md
CHANGED
@@ -12,17 +12,9 @@ In botony, one can take parts of a tree and splice it onto another tree. The DO
|
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
15
|
-
Add
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
And then execute:
|
20
|
-
|
21
|
-
$ bundle
|
22
|
-
|
23
|
-
Or install it yourself as:
|
24
|
-
|
25
|
-
$ gem install turbograft
|
15
|
+
* Add `gem "turbograft"` to your Gemfile
|
16
|
+
* Run `bundle install`
|
17
|
+
* Add `#= require turbograft` to _app/assets/javascripts/application.js_
|
26
18
|
|
27
19
|
## Usage
|
28
20
|
|
@@ -15,12 +15,9 @@ class window.Click
|
|
15
15
|
return if @event.defaultPrevented
|
16
16
|
@_extractLink()
|
17
17
|
if @_validForTurbolinks()
|
18
|
-
Turbolinks.visit @link.href
|
18
|
+
Turbolinks.visit @link.href
|
19
19
|
@event.preventDefault()
|
20
20
|
|
21
|
-
_pageChangePrevented: ->
|
22
|
-
!triggerEvent 'page:before-change' # TODO: fix this global
|
23
|
-
|
24
21
|
_extractLink: ->
|
25
22
|
link = @event.target
|
26
23
|
link = link.parentNode until !link.parentNode or link.nodeName is 'A'
|
@@ -38,8 +38,9 @@ TurboGraft.handlers.remoteMethodHandler = (ev) ->
|
|
38
38
|
fullRefresh: target.getAttribute('full-refresh')?
|
39
39
|
refreshOnSuccess: target.getAttribute('refresh-on-success')
|
40
40
|
refreshOnError: target.getAttribute('refresh-on-error')
|
41
|
+
refreshOnErrorExcept: target.getAttribute('full-refresh-on-error-except')
|
41
42
|
|
42
|
-
if !options.refreshOnSuccess && !options.refreshOnError
|
43
|
+
if !options.refreshOnSuccess && !options.refreshOnError && !options.refreshOnErrorExcept
|
43
44
|
options.fullRefresh = true
|
44
45
|
|
45
46
|
remote = new TurboGraft.Remote(options, null, target)
|
@@ -60,8 +61,9 @@ TurboGraft.handlers.remoteFormHandler = (ev) ->
|
|
60
61
|
fullRefresh: target.getAttribute('full-refresh')?
|
61
62
|
refreshOnSuccess: target.getAttribute('refresh-on-success')
|
62
63
|
refreshOnError: target.getAttribute('refresh-on-error')
|
64
|
+
refreshOnErrorExcept: target.getAttribute('full-refresh-on-error-except')
|
63
65
|
|
64
|
-
if !options.refreshOnSuccess && !options.refreshOnError
|
66
|
+
if !options.refreshOnSuccess && !options.refreshOnError && !options.refreshOnErrorExcept
|
65
67
|
options.fullRefresh = true
|
66
68
|
|
67
69
|
remote = new TurboGraft.Remote(options, target, target)
|
@@ -17,7 +17,9 @@ Page.refresh = (options = {}, callback) ->
|
|
17
17
|
location.href
|
18
18
|
|
19
19
|
if options.response
|
20
|
-
|
20
|
+
onlyKeys = options.onlyKeys || []
|
21
|
+
exceptKeys = options.exceptKeys || []
|
22
|
+
Turbolinks.loadPage null, options.response, true, callback, onlyKeys, exceptKeys
|
21
23
|
else
|
22
24
|
Turbolinks.visit newUrl, true, options.onlyKeys || [], -> callback?()
|
23
25
|
|
@@ -1,24 +1,24 @@
|
|
1
1
|
class TurboGraft.Remote
|
2
2
|
constructor: (@opts, form, target) ->
|
3
|
-
formData
|
4
|
-
|
5
|
-
@initiator = target
|
3
|
+
formData = if form then new FormData(form) else new FormData()
|
4
|
+
@initiator = target || form
|
6
5
|
|
7
6
|
actualRequestType = if @opts.httpRequestType.toLowerCase() == 'get' then 'GET' else 'POST'
|
8
7
|
|
9
8
|
formData.append("_method", @opts.httpRequestType)
|
10
9
|
|
11
|
-
@refreshOnSuccess
|
12
|
-
@refreshOnError
|
10
|
+
@refreshOnSuccess = @opts.refreshOnSuccess.split(" ") if @opts.refreshOnSuccess
|
11
|
+
@refreshOnError = @opts.refreshOnError.split(" ") if @opts.refreshOnError
|
12
|
+
@refreshOnErrorExcept = @opts.refreshOnErrorExcept.split(" ") if @opts.refreshOnErrorExcept
|
13
13
|
|
14
14
|
xhr = new XMLHttpRequest
|
15
15
|
xhr.open(actualRequestType, @opts.httpUrl, true)
|
16
16
|
xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml')
|
17
|
+
triggerEventFor('turbograft:remote:init', @initiator, xhr: xhr)
|
17
18
|
|
18
19
|
xhr.addEventListener 'loadstart', =>
|
19
|
-
|
20
|
-
xhr: xhr
|
21
|
-
initiator: @initiator
|
20
|
+
triggerEventFor 'turbograft:remote:start', @initiator,
|
21
|
+
xhr: xhr
|
22
22
|
|
23
23
|
xhr.addEventListener 'error', @onError
|
24
24
|
xhr.addEventListener 'load', (event) =>
|
@@ -28,18 +28,16 @@ class TurboGraft.Remote
|
|
28
28
|
@onError(event)
|
29
29
|
|
30
30
|
xhr.addEventListener 'loadend', =>
|
31
|
-
|
32
|
-
xhr: xhr
|
33
|
-
initiator: @initiator
|
31
|
+
triggerEventFor 'turbograft:remote:always', @initiator,
|
32
|
+
xhr: xhr
|
34
33
|
|
35
34
|
xhr.send(formData)
|
36
35
|
xhr
|
37
36
|
|
38
37
|
onSuccess: (ev) ->
|
39
38
|
xhr = ev.target
|
40
|
-
|
41
|
-
xhr: xhr
|
42
|
-
initiator: @initiator
|
39
|
+
triggerEventFor 'turbograft:remote:success', @initiator,
|
40
|
+
xhr: xhr
|
43
41
|
|
44
42
|
if redirect = xhr.getResponseHeader('X-Next-Redirect')
|
45
43
|
Page.visit(redirect, reload: true)
|
@@ -56,15 +54,14 @@ class TurboGraft.Remote
|
|
56
54
|
|
57
55
|
onError: (ev) ->
|
58
56
|
xhr = ev.target
|
59
|
-
|
60
|
-
xhr: xhr
|
61
|
-
initiator: @initiator
|
57
|
+
triggerEventFor 'turbograft:remote:fail', @initiator,
|
58
|
+
xhr: xhr
|
62
59
|
|
63
|
-
if @refreshOnError
|
60
|
+
if @refreshOnError || @refreshOnErrorExcept
|
64
61
|
Page.refresh
|
65
62
|
response: xhr
|
66
63
|
onlyKeys: @refreshOnError
|
64
|
+
exceptKeys: @refreshOnErrorExcept
|
67
65
|
else
|
68
|
-
|
69
|
-
xhr: xhr
|
70
|
-
initiator: @initiator
|
66
|
+
triggerEventFor 'turbograft:remote:fail:unhandled', @initiator,
|
67
|
+
xhr: xhr
|
@@ -1,4 +1,4 @@
|
|
1
|
-
xhr
|
1
|
+
xhr = null
|
2
2
|
|
3
3
|
installDocumentReadyPageEventTriggers = ->
|
4
4
|
document.addEventListener 'DOMContentLoaded', ( ->
|
@@ -28,6 +28,12 @@ window.triggerEvent = (name, data) ->
|
|
28
28
|
event.initEvent name, true, true
|
29
29
|
document.dispatchEvent event
|
30
30
|
|
31
|
+
window.triggerEventFor = (name, node, data) ->
|
32
|
+
event = document.createEvent 'Events'
|
33
|
+
event.data = data if data
|
34
|
+
event.initEvent name, true, true
|
35
|
+
node.dispatchEvent event
|
36
|
+
|
31
37
|
popCookie = (name) ->
|
32
38
|
value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
|
33
39
|
document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
|
@@ -54,33 +60,17 @@ class window.Turbolinks
|
|
54
60
|
currentState = null
|
55
61
|
loadedAssets = null
|
56
62
|
referer = null
|
57
|
-
usePageCache = false
|
58
|
-
@pageCache = pageCache = new PageCache()
|
59
63
|
|
60
64
|
fetch = (url, partialReplace = false, replaceContents = [], callback) ->
|
65
|
+
return if pageChangePrevented(url)
|
61
66
|
url = new ComponentUrl url
|
62
67
|
|
63
68
|
rememberReferer()
|
64
|
-
Turbolinks.cacheCurrentPage() if usePageCache
|
65
|
-
|
66
|
-
if usePageCache and cachedPage = transitionCacheFor(url.absolute)
|
67
|
-
fetchHistory cachedPage
|
68
|
-
fetchReplacement url, partialReplace, null, replaceContents
|
69
|
-
else
|
70
|
-
fetchReplacement url, partialReplace, ->
|
71
|
-
resetScrollPosition() unless replaceContents.length
|
72
|
-
callback?()
|
73
|
-
, replaceContents
|
74
|
-
|
75
|
-
@pageCacheEnabled = ->
|
76
|
-
usePageCache
|
77
69
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
cachedPage = pageCache.get(url)
|
83
|
-
cachedPage if cachedPage and !cachedPage.transitionCacheDisabled
|
70
|
+
fetchReplacement url, partialReplace, ->
|
71
|
+
resetScrollPosition() unless replaceContents.length
|
72
|
+
callback?()
|
73
|
+
, replaceContents
|
84
74
|
|
85
75
|
@pushState: (state, title, url) ->
|
86
76
|
window.history.pushState(state, title, url)
|
@@ -111,12 +101,12 @@ class window.Turbolinks
|
|
111
101
|
|
112
102
|
return
|
113
103
|
|
114
|
-
@loadPage: (url, xhr, partialReplace = false, onLoadFunction = (->), replaceContents = []) ->
|
104
|
+
@loadPage: (url, xhr, partialReplace = false, onLoadFunction = (->), replaceContents = [], replaceAllExcept = []) ->
|
115
105
|
triggerEvent 'page:receive'
|
116
106
|
|
117
107
|
if doc = processResponse(xhr, partialReplace)
|
118
108
|
reflectNewUrl url
|
119
|
-
nodes = changePage(extractTitleAndBody(doc)..., partialReplace, replaceContents)
|
109
|
+
nodes = changePage(extractTitleAndBody(doc)..., partialReplace, replaceContents, replaceAllExcept)
|
120
110
|
reflectRedirectedUrl(xhr)
|
121
111
|
triggerEvent 'page:load', nodes
|
122
112
|
onLoadFunction?()
|
@@ -125,32 +115,15 @@ class window.Turbolinks
|
|
125
115
|
|
126
116
|
return
|
127
117
|
|
128
|
-
|
129
|
-
xhr?.abort()
|
130
|
-
changePage cachedPage.title, cachedPage.body, false
|
131
|
-
recallScrollPosition cachedPage
|
132
|
-
triggerEvent 'page:restore'
|
133
|
-
|
134
|
-
|
135
|
-
@cacheCurrentPage: ->
|
136
|
-
currentStateUrl = new ComponentUrl currentState.url
|
137
|
-
|
138
|
-
pageCache.set currentStateUrl.absolute,
|
139
|
-
url: currentStateUrl.relative,
|
140
|
-
body: document.body,
|
141
|
-
title: document.title,
|
142
|
-
positionY: window.pageYOffset,
|
143
|
-
positionX: window.pageXOffset,
|
144
|
-
transitionCacheDisabled: document.querySelector('[data-no-transition-cache]')?
|
145
|
-
|
146
|
-
return
|
147
|
-
|
148
|
-
changePage = (title, body, csrfToken, runScripts, partialReplace, replaceContents = []) ->
|
118
|
+
changePage = (title, body, csrfToken, runScripts, partialReplace, replaceContents = [], replaceAllExcept = []) ->
|
149
119
|
document.title = title if title
|
150
120
|
if replaceContents.length
|
151
121
|
return refreshNodesWithKeys(replaceContents, body)
|
152
122
|
else
|
153
|
-
|
123
|
+
if replaceAllExcept.length
|
124
|
+
refreshAllExceptWithKeys(replaceAllExcept, body)
|
125
|
+
else
|
126
|
+
deleteRefreshNeverNodes(body)
|
154
127
|
|
155
128
|
triggerEvent 'page:before-replace'
|
156
129
|
document.documentElement.replaceChild body, document.body
|
@@ -204,6 +177,20 @@ class window.Turbolinks
|
|
204
177
|
|
205
178
|
refreshedNodes
|
206
179
|
|
180
|
+
refreshAllExceptWithKeys = (keys, body) ->
|
181
|
+
allNodesToKeep = []
|
182
|
+
|
183
|
+
for key in keys
|
184
|
+
for node in document.querySelectorAll("[refresh=#{key}]")
|
185
|
+
allNodesToKeep.push(node)
|
186
|
+
|
187
|
+
for existingNode in allNodesToKeep
|
188
|
+
unless nodeId = existingNode.getAttribute('id')
|
189
|
+
throw new Error "Turbolinks refresh: Refresh key elements must have an id."
|
190
|
+
|
191
|
+
remoteNode = body.querySelector("##{ nodeId }")
|
192
|
+
remoteNode.parentNode.replaceChild(existingNode, remoteNode)
|
193
|
+
|
207
194
|
executeScriptTags = ->
|
208
195
|
scripts = Array::slice.call document.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])'
|
209
196
|
for script in scripts when script.type in ['', 'text/javascript']
|
@@ -253,8 +240,8 @@ class window.Turbolinks
|
|
253
240
|
else
|
254
241
|
window.scrollTo 0, 0
|
255
242
|
|
256
|
-
pageChangePrevented = ->
|
257
|
-
!triggerEvent
|
243
|
+
pageChangePrevented = (url) ->
|
244
|
+
!triggerEvent('page:before-change', url)
|
258
245
|
|
259
246
|
processResponse = (xhr, partial = false) ->
|
260
247
|
clientOrServerError = ->
|
@@ -290,11 +277,7 @@ class window.Turbolinks
|
|
290
277
|
|
291
278
|
installHistoryChangeHandler = (event) ->
|
292
279
|
if event.state?.turbolinks
|
293
|
-
|
294
|
-
Turbolinks.cacheCurrentPage()
|
295
|
-
fetchHistory cachedPage
|
296
|
-
else
|
297
|
-
Turbolinks.visit event.target.location.href
|
280
|
+
Turbolinks.visit event.target.location.href
|
298
281
|
|
299
282
|
# Delay execution of function long enough to miss the popstate event
|
300
283
|
# some browsers fire on the initial page load.
|
data/lib/turbograft/version.rb
CHANGED
@@ -16,6 +16,17 @@ module TurboGraft
|
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
19
|
+
|
20
|
+
if Rails::VERSION::MAJOR == 4 && Rails::VERSION::MINOR > 1
|
21
|
+
def _compute_redirect_to_location_with_xhr_referer(request, options)
|
22
|
+
session[:_turbolinks_redirect_to] =
|
23
|
+
if options == :back && request.headers["X-XHR-Referer"]
|
24
|
+
_compute_redirect_to_location_without_xhr_referer(request, request.headers["X-XHR-Referer"])
|
25
|
+
else
|
26
|
+
_compute_redirect_to_location_without_xhr_referer(request, options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
19
30
|
def _compute_redirect_to_location_with_xhr_referer(options)
|
20
31
|
session[:_turbolinks_redirect_to] =
|
21
32
|
if options == :back && request.headers["X-XHR-Referer"]
|
@@ -24,12 +35,12 @@ module TurboGraft
|
|
24
35
|
_compute_redirect_to_location_without_xhr_referer(options)
|
25
36
|
end
|
26
37
|
end
|
38
|
+
end
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
40
|
+
def set_xhr_redirected_to
|
41
|
+
if session[:_turbolinks_redirect_to]
|
42
|
+
response.headers['X-XHR-Redirected-To'] = session.delete :_turbolinks_redirect_to
|
32
43
|
end
|
44
|
+
end
|
33
45
|
end
|
34
|
-
|
35
46
|
end
|