turbograft 0.4.2 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/assets/javascripts/turbograft/document.coffee +11 -0
- data/lib/assets/javascripts/turbograft/page.coffee +10 -10
- data/lib/assets/javascripts/turbograft/remote.coffee +10 -5
- data/lib/assets/javascripts/turbograft/response.coffee +31 -0
- data/lib/assets/javascripts/turbograft/turbohead.coffee +7 -2
- data/lib/assets/javascripts/turbograft/turbolinks.coffee +76 -90
- data/lib/turbograft.rb +12 -10
- data/lib/turbograft/redirection.rb +1 -2
- data/lib/turbograft/version.rb +1 -1
- data/lib/turbograft/xhr_headers.rb +24 -15
- metadata +13 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 151e2b8deeb6da6a8e1b5c732e236c8db0df7427c3bf7f763b9eecf863d1bbe6
|
4
|
+
data.tar.gz: 4ffff77fc18c82fb496446492617a6acab056e767afc77c660208eb6cd26630f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbe47332102f1fff3ebd2deb9c706e47f463f99d51fdb7ba35c9acceaca030e2c04a50eb227671c47a7c4231086e403f2fbcafaabfdb034129f92453f0ea01b2
|
7
|
+
data.tar.gz: d10f83071df4a30ae08b8cf1327e20119bbba40297eac5496e32cd3f84bcf00be2bdd330d0dda5d7ba96e629dc4cf5b42b48868b7679ffe94a2bc6af9e31948e
|
@@ -0,0 +1,11 @@
|
|
1
|
+
TurboGraft.Document =
|
2
|
+
create: (html) ->
|
3
|
+
if /<(html|body)/i.test(html)
|
4
|
+
doc = document.documentElement.cloneNode()
|
5
|
+
doc.innerHTML = html
|
6
|
+
else
|
7
|
+
doc = document.documentElement.cloneNode(true)
|
8
|
+
doc.querySelector('body').innerHTML = html
|
9
|
+
doc.head = doc.querySelector('head')
|
10
|
+
doc.body = doc.querySelector('body')
|
11
|
+
doc
|
@@ -16,18 +16,18 @@ Page.refresh = (options = {}, callback) ->
|
|
16
16
|
else
|
17
17
|
location.href
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
options.
|
19
|
+
turboOptions = {
|
20
|
+
partialReplace: true,
|
21
|
+
exceptKeys: options.exceptKeys,
|
22
|
+
onlyKeys: options.onlyKeys,
|
23
|
+
updatePushState: options.updatePushState,
|
24
|
+
callback: callback
|
25
|
+
}
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
Turbolinks.loadPage null, xhr, options
|
27
|
+
if xhr = options.response
|
28
|
+
Turbolinks.loadPage null, xhr, turboOptions
|
26
29
|
else
|
27
|
-
|
28
|
-
options.callback = callback if callback
|
29
|
-
|
30
|
-
Turbolinks.visit newUrl, options
|
30
|
+
Turbolinks.visit newUrl, turboOptions
|
31
31
|
|
32
32
|
Page.open = ->
|
33
33
|
window.open(arguments...)
|
@@ -134,16 +134,19 @@ class TurboGraft.Remote
|
|
134
134
|
else if @opts.fullRefresh
|
135
135
|
Page.refresh()
|
136
136
|
else if @refreshOnSuccess
|
137
|
-
Page.refresh
|
137
|
+
Page.refresh(
|
138
138
|
response: xhr
|
139
139
|
onlyKeys: @refreshOnSuccess
|
140
|
+
)
|
140
141
|
else if @refreshOnSuccessExcept
|
141
|
-
Page.refresh
|
142
|
+
Page.refresh(
|
142
143
|
response: xhr
|
143
144
|
exceptKeys: @refreshOnSuccessExcept
|
145
|
+
)
|
144
146
|
else
|
145
|
-
Page.refresh
|
147
|
+
Page.refresh(
|
146
148
|
response: xhr
|
149
|
+
)
|
147
150
|
|
148
151
|
onError: (ev) =>
|
149
152
|
@opts.fail?()
|
@@ -162,13 +165,15 @@ class TurboGraft.Remote
|
|
162
165
|
else if @opts.fullRefresh
|
163
166
|
Page.refresh()
|
164
167
|
else if @refreshOnError
|
165
|
-
Page.refresh
|
168
|
+
Page.refresh(
|
166
169
|
response: xhr
|
167
170
|
onlyKeys: @refreshOnError
|
171
|
+
)
|
168
172
|
else if @refreshOnErrorExcept
|
169
|
-
Page.refresh
|
173
|
+
Page.refresh(
|
170
174
|
response: xhr
|
171
175
|
exceptKeys: @refreshOnErrorExcept
|
176
|
+
)
|
172
177
|
else
|
173
178
|
triggerEventFor 'turbograft:remote:fail:unhandled', @initiator,
|
174
179
|
xhr: xhr
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class TurboGraft.Response
|
2
|
+
constructor: (@xhr, intendedURL) ->
|
3
|
+
if intendedURL && intendedURL.withoutHash() != @xhr.responseURL
|
4
|
+
redirectedTo = @xhr.responseURL
|
5
|
+
else
|
6
|
+
redirectedTo = @xhr.getResponseHeader('X-XHR-Redirected-To')
|
7
|
+
|
8
|
+
@finalURL = redirectedTo || intendedURL
|
9
|
+
|
10
|
+
valid: -> @hasRenderableHttpStatus() && @hasValidContent()
|
11
|
+
|
12
|
+
document: ->
|
13
|
+
if @valid()
|
14
|
+
TurboGraft.Document.create(@xhr.responseText)
|
15
|
+
|
16
|
+
hasRenderableHttpStatus: ->
|
17
|
+
return true if @xhr.status == 422 # we want to render form validations
|
18
|
+
!(400 <= @xhr.status < 600)
|
19
|
+
|
20
|
+
hasValidContent: ->
|
21
|
+
if contentType = @xhr.getResponseHeader('Content-Type')
|
22
|
+
contentType.match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/)
|
23
|
+
else
|
24
|
+
throw new Error("Error encountered for XHR Response: #{this}")
|
25
|
+
|
26
|
+
toString: () ->
|
27
|
+
"URL: #{@xhr.responseURL}, " +
|
28
|
+
"ReadyState: #{@xhr.readyState}, " +
|
29
|
+
"Headers: #{@xhr.getAllResponseHeaders()}"
|
30
|
+
|
31
|
+
TurboGraft.location = () -> location.href
|
@@ -10,7 +10,7 @@ waitForCompleteDownloads = ->
|
|
10
10
|
scriptPromises[url]
|
11
11
|
Promise.all(loadingPromises)
|
12
12
|
|
13
|
-
class
|
13
|
+
class TurboGraft.TurboHead
|
14
14
|
constructor: (@activeDocument, @upstreamDocument) ->
|
15
15
|
@activeAssets = extractTrackedAssets(@activeDocument)
|
16
16
|
@upstreamAssets = extractTrackedAssets(@upstreamDocument)
|
@@ -44,6 +44,9 @@ class window.TurboHead
|
|
44
44
|
noMatchingSrc(node) || noMatchingHref(node)
|
45
45
|
)
|
46
46
|
|
47
|
+
movingFromTrackedToUntracked: () ->
|
48
|
+
@upstreamAssets.length == 0 && @activeAssets.length > 0
|
49
|
+
|
47
50
|
hasNamedAssetConflicts: () ->
|
48
51
|
@newScripts
|
49
52
|
.concat(@newLinks)
|
@@ -51,7 +54,9 @@ class window.TurboHead
|
|
51
54
|
.some(datasetMatchesIn(TRACKED_ATTRIBUTE_NAME, @activeAssets))
|
52
55
|
|
53
56
|
hasAssetConflicts: () ->
|
54
|
-
@
|
57
|
+
@movingFromTrackedToUntracked() ||
|
58
|
+
@hasNamedAssetConflicts() ||
|
59
|
+
@hasChangedAnonymousAssets()
|
55
60
|
|
56
61
|
waitForAssets: () ->
|
57
62
|
resolvePreviousRequest?(isCanceled: true)
|
@@ -1,14 +1,19 @@
|
|
1
|
+
Response = TurboGraft.Response
|
2
|
+
TurboHead = TurboGraft.TurboHead
|
3
|
+
jQuery = window.jQuery
|
4
|
+
|
1
5
|
xhr = null
|
6
|
+
activeDocument = document
|
2
7
|
|
3
8
|
installDocumentReadyPageEventTriggers = ->
|
4
|
-
|
9
|
+
activeDocument.addEventListener 'DOMContentLoaded', ( ->
|
5
10
|
triggerEvent 'page:change'
|
6
11
|
triggerEvent 'page:update'
|
7
12
|
), true
|
8
13
|
|
9
14
|
installJqueryAjaxSuccessPageUpdateTrigger = ->
|
10
15
|
if typeof jQuery isnt 'undefined'
|
11
|
-
jQuery(
|
16
|
+
jQuery(activeDocument).on 'ajaxSuccess', (event, xhr, settings) ->
|
12
17
|
return unless jQuery.trim xhr.responseText
|
13
18
|
triggerEvent 'page:update'
|
14
19
|
|
@@ -20,20 +25,20 @@ browserSupportsPushState =
|
|
20
25
|
window.history and window.history.pushState and window.history.replaceState and historyStateIsDefined
|
21
26
|
|
22
27
|
window.triggerEvent = (name, data) ->
|
23
|
-
event =
|
28
|
+
event = activeDocument.createEvent 'Events'
|
24
29
|
event.data = data if data
|
25
30
|
event.initEvent name, true, true
|
26
|
-
|
31
|
+
activeDocument.dispatchEvent event
|
27
32
|
|
28
33
|
window.triggerEventFor = (name, node, data) ->
|
29
|
-
event =
|
34
|
+
event = activeDocument.createEvent 'Events'
|
30
35
|
event.data = data if data
|
31
36
|
event.initEvent name, true, true
|
32
37
|
node.dispatchEvent event
|
33
38
|
|
34
39
|
popCookie = (name) ->
|
35
|
-
value =
|
36
|
-
|
40
|
+
value = activeDocument.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
|
41
|
+
activeDocument.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
|
37
42
|
value
|
38
43
|
|
39
44
|
requestMethodIsSafe =
|
@@ -42,7 +47,7 @@ requestMethodIsSafe =
|
|
42
47
|
browserSupportsTurbolinks = browserSupportsPushState and requestMethodIsSafe
|
43
48
|
|
44
49
|
browserSupportsCustomEvents =
|
45
|
-
|
50
|
+
activeDocument.addEventListener and activeDocument.createEvent
|
46
51
|
|
47
52
|
if browserSupportsCustomEvents
|
48
53
|
installDocumentReadyPageEventTriggers()
|
@@ -61,27 +66,30 @@ removeNode = (node) ->
|
|
61
66
|
# TODO: clean up everything above me ^
|
62
67
|
# TODO: decide on the public API
|
63
68
|
class window.Turbolinks
|
64
|
-
createDocument = null
|
65
69
|
currentState = null
|
66
70
|
referer = null
|
67
71
|
|
68
72
|
fetch = (url, options = {}) ->
|
69
73
|
return if pageChangePrevented(url)
|
70
|
-
url = new ComponentUrl
|
74
|
+
url = new ComponentUrl(url)
|
71
75
|
|
72
76
|
rememberReferer()
|
73
77
|
|
74
|
-
options
|
75
|
-
options.onlyKeys ?= []
|
76
|
-
options.onLoadFunction = ->
|
77
|
-
resetScrollPosition() unless options.onlyKeys.length
|
78
|
-
options.callback?()
|
78
|
+
fetchReplacement(url, options)
|
79
79
|
|
80
|
-
|
80
|
+
isPartialReplace = (response, options) ->
|
81
|
+
Boolean(
|
82
|
+
options.partialReplace ||
|
83
|
+
options.onlyKeys?.length ||
|
84
|
+
options.exceptKeys?.length
|
85
|
+
)
|
81
86
|
|
82
87
|
@fullPageNavigate: (url) ->
|
83
|
-
|
84
|
-
|
88
|
+
if url?
|
89
|
+
url = (new ComponentUrl(url)).absolute
|
90
|
+
triggerEvent('page:before-full-refresh', url: url)
|
91
|
+
activeDocument.location.href = url
|
92
|
+
return
|
85
93
|
|
86
94
|
@pushState: (state, title, url) ->
|
87
95
|
window.history.pushState(state, title, url)
|
@@ -89,6 +97,10 @@ class window.Turbolinks
|
|
89
97
|
@replaceState: (state, title, url) ->
|
90
98
|
window.history.replaceState(state, title, url)
|
91
99
|
|
100
|
+
@document: (documentToUse) ->
|
101
|
+
activeDocument = documentToUse if documentToUse
|
102
|
+
activeDocument
|
103
|
+
|
92
104
|
fetchReplacement = (url, options) ->
|
93
105
|
triggerEvent 'page:fetch', url: url.absolute
|
94
106
|
|
@@ -111,7 +123,7 @@ class window.Turbolinks
|
|
111
123
|
|
112
124
|
xhr.onload = ->
|
113
125
|
if xhr.status >= 500
|
114
|
-
Turbolinks.fullPageNavigate(url
|
126
|
+
Turbolinks.fullPageNavigate(url)
|
115
127
|
else
|
116
128
|
Turbolinks.loadPage(url, xhr, options)
|
117
129
|
xhr = null
|
@@ -121,7 +133,7 @@ class window.Turbolinks
|
|
121
133
|
if xhr.statusText == "abort"
|
122
134
|
xhr = null
|
123
135
|
return
|
124
|
-
Turbolinks.fullPageNavigate(url
|
136
|
+
Turbolinks.fullPageNavigate(url)
|
125
137
|
|
126
138
|
xhr.send()
|
127
139
|
|
@@ -129,24 +141,28 @@ class window.Turbolinks
|
|
129
141
|
|
130
142
|
@loadPage: (url, xhr, options = {}) ->
|
131
143
|
triggerEvent 'page:receive'
|
144
|
+
response = new Response(xhr, url)
|
132
145
|
options.updatePushState ?= true
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
updateBody(upstreamDocument, xhr, options)
|
137
|
-
else
|
138
|
-
turbohead = new TurboHead(document, upstreamDocument)
|
139
|
-
if turbohead.hasAssetConflicts()
|
140
|
-
return Turbolinks.fullPageNavigate(url.absolute)
|
141
|
-
reflectNewUrl url if options.updatePushState
|
142
|
-
turbohead.waitForAssets().then((result) ->
|
143
|
-
updateBody(upstreamDocument, xhr, options) unless result?.isCanceled
|
144
|
-
)
|
145
|
-
else
|
146
|
+
options.partialReplace = isPartialReplace(response, options)
|
147
|
+
|
148
|
+
unless upstreamDocument = response.document()
|
146
149
|
triggerEvent 'page:error', xhr
|
147
|
-
Turbolinks.fullPageNavigate(
|
150
|
+
Turbolinks.fullPageNavigate(response.finalURL)
|
151
|
+
return
|
152
|
+
|
153
|
+
if options.partialReplace
|
154
|
+
updateBody(upstreamDocument, response, options)
|
155
|
+
return
|
156
|
+
|
157
|
+
turbohead = new TurboHead(activeDocument, upstreamDocument)
|
158
|
+
if turbohead.hasAssetConflicts()
|
159
|
+
return Turbolinks.fullPageNavigate(response.finalURL)
|
160
|
+
|
161
|
+
turbohead.waitForAssets().then((result) ->
|
162
|
+
updateBody(upstreamDocument, response, options) unless result?.isCanceled
|
163
|
+
)
|
148
164
|
|
149
|
-
updateBody = (upstreamDocument,
|
165
|
+
updateBody = (upstreamDocument, response, options) ->
|
150
166
|
nodes = changePage(
|
151
167
|
upstreamDocument.querySelector('title')?.textContent,
|
152
168
|
removeNoscriptTags(upstreamDocument.querySelector('body')),
|
@@ -154,16 +170,17 @@ class window.Turbolinks
|
|
154
170
|
'runScripts',
|
155
171
|
options
|
156
172
|
)
|
157
|
-
|
158
|
-
|
173
|
+
reflectNewUrl(response.finalURL) if options.updatePushState
|
174
|
+
|
175
|
+
Turbolinks.resetScrollPosition() unless options.partialReplace
|
176
|
+
|
177
|
+
options.callback?()
|
159
178
|
triggerEvent 'page:load', nodes
|
160
179
|
|
161
180
|
changePage = (title, body, csrfToken, runScripts, options = {}) ->
|
162
|
-
|
163
|
-
options.onlyKeys ?= []
|
164
|
-
options.exceptKeys ?= []
|
181
|
+
activeDocument.title = title if title
|
165
182
|
|
166
|
-
if options.onlyKeys
|
183
|
+
if options.onlyKeys?.length
|
167
184
|
nodesToRefresh = [].concat(getNodesWithRefreshAlways(), getNodesMatchingRefreshKeys(options.onlyKeys))
|
168
185
|
nodes = refreshNodes(nodesToRefresh, body)
|
169
186
|
setAutofocusElement() if anyAutofocusElement(nodes)
|
@@ -171,13 +188,13 @@ class window.Turbolinks
|
|
171
188
|
else
|
172
189
|
refreshNodes(getNodesWithRefreshAlways(), body)
|
173
190
|
persistStaticElements(body)
|
174
|
-
if options.exceptKeys
|
191
|
+
if options.exceptKeys?.length
|
175
192
|
refreshAllExceptWithKeys(options.exceptKeys, body)
|
176
193
|
else
|
177
194
|
deleteRefreshNeverNodes(body)
|
178
195
|
|
179
196
|
triggerEvent 'page:before-replace'
|
180
|
-
replaceNode(body,
|
197
|
+
replaceNode(body, activeDocument.body)
|
181
198
|
CSRFToken.update csrfToken if csrfToken?
|
182
199
|
setAutofocusElement()
|
183
200
|
executeScriptTags() if runScripts
|
@@ -190,14 +207,14 @@ class window.Turbolinks
|
|
190
207
|
getNodesMatchingRefreshKeys = (keys) ->
|
191
208
|
matchingNodes = []
|
192
209
|
for key in keys
|
193
|
-
for node in TurboGraft.querySelectorAllTGAttribute(
|
210
|
+
for node in TurboGraft.querySelectorAllTGAttribute(activeDocument, 'refresh', key)
|
194
211
|
matchingNodes.push(node)
|
195
212
|
|
196
213
|
return matchingNodes
|
197
214
|
|
198
215
|
getNodesWithRefreshAlways = ->
|
199
216
|
matchingNodes = []
|
200
|
-
for node in TurboGraft.querySelectorAllTGAttribute(
|
217
|
+
for node in TurboGraft.querySelectorAllTGAttribute(activeDocument, 'refresh-always')
|
201
218
|
matchingNodes.push(node)
|
202
219
|
|
203
220
|
return matchingNodes
|
@@ -210,8 +227,8 @@ class window.Turbolinks
|
|
210
227
|
false
|
211
228
|
|
212
229
|
setAutofocusElement = ->
|
213
|
-
autofocusElement = (list =
|
214
|
-
if autofocusElement and
|
230
|
+
autofocusElement = (list = activeDocument.querySelectorAll 'input[autofocus], textarea[autofocus]')[list.length - 1]
|
231
|
+
if autofocusElement and activeDocument.activeElement isnt autofocusElement
|
215
232
|
autofocusElement.focus()
|
216
233
|
|
217
234
|
deleteRefreshNeverNodes = (body) ->
|
@@ -260,7 +277,7 @@ class window.Turbolinks
|
|
260
277
|
persistStaticElements = (body) ->
|
261
278
|
allNodesToKeep = []
|
262
279
|
|
263
|
-
nodes = TurboGraft.querySelectorAllTGAttribute(
|
280
|
+
nodes = TurboGraft.querySelectorAllTGAttribute(activeDocument, 'tg-static')
|
264
281
|
allNodesToKeep.push(node) for node in nodes
|
265
282
|
|
266
283
|
keepNodes(body, allNodesToKeep)
|
@@ -270,22 +287,22 @@ class window.Turbolinks
|
|
270
287
|
allNodesToKeep = []
|
271
288
|
|
272
289
|
for key in keys
|
273
|
-
for node in TurboGraft.querySelectorAllTGAttribute(
|
290
|
+
for node in TurboGraft.querySelectorAllTGAttribute(activeDocument, 'refresh', key)
|
274
291
|
allNodesToKeep.push(node)
|
275
292
|
|
276
293
|
keepNodes(body, allNodesToKeep)
|
277
294
|
return
|
278
295
|
|
279
296
|
executeScriptTags = ->
|
280
|
-
scripts = Array::slice.call
|
297
|
+
scripts = Array::slice.call activeDocument.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])'
|
281
298
|
for script in scripts when script.type in ['', 'text/javascript']
|
282
299
|
executeScriptTag(script)
|
283
300
|
return
|
284
301
|
|
285
302
|
executeScriptTag = (script) ->
|
286
|
-
copy =
|
303
|
+
copy = activeDocument.createElement 'script'
|
287
304
|
copy.setAttribute attr.name, attr.value for attr in script.attributes
|
288
|
-
copy.appendChild
|
305
|
+
copy.appendChild activeDocument.createTextNode script.innerHTML
|
289
306
|
{ parentNode, nextSibling } = script
|
290
307
|
parentNode.removeChild script
|
291
308
|
parentNode.insertBefore copy, nextSibling
|
@@ -300,19 +317,11 @@ class window.Turbolinks
|
|
300
317
|
Turbolinks.pushState { turbolinks: true, url: url.absolute }, '', url.absolute
|
301
318
|
return
|
302
319
|
|
303
|
-
reflectRedirectedUrl = (xhr) ->
|
304
|
-
if location = xhr.getResponseHeader 'X-XHR-Redirected-To'
|
305
|
-
location = new ComponentUrl location
|
306
|
-
preservedHash = if location.hasNoHash() then document.location.hash else ''
|
307
|
-
Turbolinks.replaceState currentState, '', location.href + preservedHash
|
308
|
-
|
309
|
-
return
|
310
|
-
|
311
320
|
rememberReferer = ->
|
312
|
-
referer =
|
321
|
+
referer = activeDocument.location.href
|
313
322
|
|
314
323
|
@rememberCurrentUrl: ->
|
315
|
-
Turbolinks.replaceState { turbolinks: true, url:
|
324
|
+
Turbolinks.replaceState { turbolinks: true, url: activeDocument.location.href }, '', activeDocument.location.href
|
316
325
|
|
317
326
|
@rememberCurrentState: ->
|
318
327
|
currentState = window.history.state
|
@@ -320,27 +329,15 @@ class window.Turbolinks
|
|
320
329
|
recallScrollPosition = (page) ->
|
321
330
|
window.scrollTo page.positionX, page.positionY
|
322
331
|
|
323
|
-
resetScrollPosition
|
324
|
-
if
|
325
|
-
|
332
|
+
@resetScrollPosition: ->
|
333
|
+
if activeDocument.location.hash
|
334
|
+
activeDocument.location.href = activeDocument.location.href
|
326
335
|
else
|
327
336
|
window.scrollTo 0, 0
|
328
337
|
|
329
338
|
pageChangePrevented = (url) ->
|
330
339
|
!triggerEvent('page:before-change', url)
|
331
340
|
|
332
|
-
processResponse = (xhr) ->
|
333
|
-
clientOrServerError = ->
|
334
|
-
return false if xhr.status == 422 # we want to render form validations
|
335
|
-
400 <= xhr.status < 600
|
336
|
-
|
337
|
-
validContent = ->
|
338
|
-
xhr.getResponseHeader('Content-Type').match /^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/
|
339
|
-
|
340
|
-
if !clientOrServerError() && validContent()
|
341
|
-
upstreamDocument = createDocument(xhr.responseText)
|
342
|
-
return upstreamDocument
|
343
|
-
|
344
341
|
installHistoryChangeHandler = (event) ->
|
345
342
|
if event.state?.turbolinks
|
346
343
|
Turbolinks.visit event.target.location.href
|
@@ -350,26 +347,15 @@ class window.Turbolinks
|
|
350
347
|
bypassOnLoadPopstate = (fn) ->
|
351
348
|
setTimeout fn, 500
|
352
349
|
|
353
|
-
createDocument = (html) ->
|
354
|
-
if /<(html|body)/i.test(html)
|
355
|
-
doc = document.documentElement.cloneNode()
|
356
|
-
doc.innerHTML = html
|
357
|
-
else
|
358
|
-
doc = document.documentElement.cloneNode(true)
|
359
|
-
doc.querySelector('body').innerHTML = html
|
360
|
-
doc.head = doc.querySelector('head')
|
361
|
-
doc.body = doc.querySelector('body')
|
362
|
-
doc
|
363
|
-
|
364
350
|
if browserSupportsTurbolinks
|
365
351
|
@visit = fetch
|
366
352
|
@rememberCurrentUrl()
|
367
353
|
@rememberCurrentState()
|
368
354
|
|
369
|
-
|
355
|
+
activeDocument.addEventListener 'click', Click.installHandlerLast, true
|
370
356
|
|
371
357
|
bypassOnLoadPopstate ->
|
372
358
|
window.addEventListener 'popstate', installHistoryChangeHandler, false
|
373
359
|
|
374
360
|
else
|
375
|
-
@visit = (url) ->
|
361
|
+
@visit = (url) -> activeDocument.location.href = url
|
data/lib/turbograft.rb
CHANGED
@@ -14,16 +14,20 @@ module TurboGraft
|
|
14
14
|
self.controllers = ["ActionController::Base"]
|
15
15
|
end
|
16
16
|
|
17
|
+
def self.included(controller)
|
18
|
+
controller.class_eval do
|
19
|
+
include XHRHeaders, Cookies, XDomainBlocker, Redirection
|
20
|
+
before_action :set_xhr_redirected_to, :set_request_method_cookie
|
21
|
+
after_action :abort_xdomain_redirect
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
17
25
|
class Engine < ::Rails::Engine
|
18
26
|
|
19
27
|
initializer :turbograft do |config|
|
20
28
|
ActiveSupport.on_load(:action_controller) do
|
21
|
-
Config.controllers.each do |
|
22
|
-
|
23
|
-
include XHRHeaders, Cookies, XDomainBlocker, Redirection
|
24
|
-
before_action :set_xhr_redirected_to, :set_request_method_cookie
|
25
|
-
after_action :abort_xdomain_redirect
|
26
|
-
end
|
29
|
+
Config.controllers.each do |class_name|
|
30
|
+
class_name.constantize.include(::TurboGraft)
|
27
31
|
end
|
28
32
|
|
29
33
|
ActionDispatch::Request.class_eval do
|
@@ -35,10 +39,8 @@ module TurboGraft
|
|
35
39
|
end
|
36
40
|
|
37
41
|
ActiveSupport.on_load(:action_view) do
|
38
|
-
(ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).
|
39
|
-
|
40
|
-
end
|
41
|
-
end unless RUBY_VERSION =~ /^1\.8/
|
42
|
+
(ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).prepend(XHRUrlFor)
|
43
|
+
end
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
@@ -7,10 +7,9 @@ module TurboGraft
|
|
7
7
|
private
|
8
8
|
def redirect_via_turbolinks_to(url = {}, response_status = {})
|
9
9
|
redirect_to(url, response_status)
|
10
|
-
|
11
10
|
self.status = 200
|
12
11
|
self.response_body = "Turbolinks.visit('#{location}');"
|
13
|
-
response.content_type = Mime
|
12
|
+
response.content_type = Mime[:js]
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
data/lib/turbograft/version.rb
CHANGED
@@ -25,23 +25,32 @@ module TurboGraft
|
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
28
|
-
def store_for_turbolinks(url)
|
29
|
-
session[:_turbolinks_redirect_to] = url if session && request.headers["X-XHR-Referer"]
|
30
|
-
url
|
31
|
-
end
|
32
28
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
29
|
+
# Ensure backwards compatibility
|
30
|
+
# Rails < 4.2: _compute_redirect_to_location(options)
|
31
|
+
# Rails >= 4.2: _compute_redirect_to_location(request, options)
|
32
|
+
def _normalize_redirect_params(args)
|
33
|
+
options, req = args.reverse
|
34
|
+
[options, req || request]
|
35
|
+
end
|
36
|
+
|
37
|
+
def store_for_turbolinks(url)
|
38
|
+
session[:_turbolinks_redirect_to] = url if session && request.headers["X-XHR-Referer"]
|
39
|
+
url
|
40
|
+
end
|
38
41
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def _normalize_redirect_params(args)
|
43
|
-
options, req = args.reverse
|
44
|
-
[options, req || request]
|
42
|
+
def set_xhr_redirected_to
|
43
|
+
if turbolinks_redirected? && request_matches_redirect?
|
44
|
+
response.headers['X-XHR-Redirected-To'] = session.delete(:_turbolinks_redirect_to)
|
45
45
|
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def turbolinks_redirected?
|
49
|
+
session && session[:_turbolinks_redirect_to]
|
50
|
+
end
|
51
|
+
|
52
|
+
def request_matches_redirect?
|
53
|
+
session[:_turbolinks_redirect_to] == request.original_url
|
54
|
+
end
|
46
55
|
end
|
47
56
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbograft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kristian Plettenberg-Dussault
|
@@ -10,10 +10,12 @@ authors:
|
|
10
10
|
- Tyler Mercier
|
11
11
|
- Anthony Cameron
|
12
12
|
- Patrick Donovan
|
13
|
+
- Mathew Allen
|
14
|
+
- Gord Pearson
|
13
15
|
autorequire:
|
14
16
|
bindir: bin
|
15
17
|
cert_chain: []
|
16
|
-
date:
|
18
|
+
date: 2020-09-01 00:00:00.000000000 Z
|
17
19
|
dependencies:
|
18
20
|
- !ruby/object:Gem::Dependency
|
19
21
|
name: coffee-rails
|
@@ -211,9 +213,11 @@ dependencies:
|
|
211
213
|
- - ">="
|
212
214
|
- !ruby/object:Gem::Version
|
213
215
|
version: '0'
|
214
|
-
description:
|
216
|
+
description: Turbograft is a hard fork of Turbolinks, allowing you to perform partial
|
217
|
+
page refreshes and offering ajax form utilities.
|
215
218
|
email:
|
216
219
|
- tylermercier@gmail.com
|
220
|
+
- mathew.allen@shopify.com
|
217
221
|
executables: []
|
218
222
|
extensions: []
|
219
223
|
extra_rdoc_files: []
|
@@ -224,10 +228,12 @@ files:
|
|
224
228
|
- lib/assets/javascripts/turbograft/click.coffee
|
225
229
|
- lib/assets/javascripts/turbograft/component_url.coffee
|
226
230
|
- lib/assets/javascripts/turbograft/csrf_token.coffee
|
231
|
+
- lib/assets/javascripts/turbograft/document.coffee
|
227
232
|
- lib/assets/javascripts/turbograft/initializers.coffee
|
228
233
|
- lib/assets/javascripts/turbograft/link.coffee
|
229
234
|
- lib/assets/javascripts/turbograft/page.coffee
|
230
235
|
- lib/assets/javascripts/turbograft/remote.coffee
|
236
|
+
- lib/assets/javascripts/turbograft/response.coffee
|
231
237
|
- lib/assets/javascripts/turbograft/turbohead.coffee
|
232
238
|
- lib/assets/javascripts/turbograft/turbolinks.coffee
|
233
239
|
- lib/turbograft.rb
|
@@ -240,7 +246,8 @@ files:
|
|
240
246
|
homepage: https://github.com/Shopify/turbograft
|
241
247
|
licenses:
|
242
248
|
- MIT
|
243
|
-
metadata:
|
249
|
+
metadata:
|
250
|
+
allowed_push_host: https://rubygems.org
|
244
251
|
post_install_message:
|
245
252
|
rdoc_options: []
|
246
253
|
require_paths:
|
@@ -249,15 +256,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
249
256
|
requirements:
|
250
257
|
- - ">="
|
251
258
|
- !ruby/object:Gem::Version
|
252
|
-
version: '
|
259
|
+
version: '2.1'
|
253
260
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
261
|
requirements:
|
255
262
|
- - ">="
|
256
263
|
- !ruby/object:Gem::Version
|
257
264
|
version: '0'
|
258
265
|
requirements: []
|
259
|
-
|
260
|
-
rubygems_version: 2.5.1
|
266
|
+
rubygems_version: 3.0.3
|
261
267
|
signing_key:
|
262
268
|
specification_version: 4
|
263
269
|
summary: turbolinks with partial page replacement
|