turbograft 0.0.8 → 0.0.10
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/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
|