turbograft 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/assets/javascripts/turbograft/document.coffee +11 -0
- data/lib/assets/javascripts/turbograft/response.coffee +23 -0
- data/lib/assets/javascripts/turbograft/turbohead.coffee +1 -1
- data/lib/assets/javascripts/turbograft/turbolinks.coffee +42 -58
- data/lib/turbograft.rb +2 -4
- data/lib/turbograft/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9334d30bbf9e86dd7baae353ac711bc9688f70ff
|
4
|
+
data.tar.gz: 92bc6bf6eb003c707d82b1b28d7b71bd67e59ada
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6625a059b2940513077f90ab4e11645e807cd57a62074815ed36f89710d28c3702a0277a90c62f243a079a0cc042011f8845cacd077f7881db43e576d478e5dd
|
7
|
+
data.tar.gz: 02850cbe00f2c90a16a34fd2932fb458fe542f578b766e7b1709ff9c938a75d706c5b439639a6338d93be44c6e86a0d4d3a80af20ce0e9a8760b2b7544fc9f24
|
@@ -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
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class TurboGraft.Response
|
2
|
+
constructor: (@xhr) ->
|
3
|
+
|
4
|
+
valid: -> @hasRenderableHttpStatus() && @hasValidContent()
|
5
|
+
|
6
|
+
document: ->
|
7
|
+
if @valid()
|
8
|
+
TurboGraft.Document.create(@xhr.responseText)
|
9
|
+
|
10
|
+
hasRenderableHttpStatus: ->
|
11
|
+
return true if @xhr.status == 422 # we want to render form validations
|
12
|
+
!(400 <= @xhr.status < 600)
|
13
|
+
|
14
|
+
hasValidContent: ->
|
15
|
+
if contentType = @xhr.getResponseHeader('Content-Type')
|
16
|
+
contentType.match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/)
|
17
|
+
else
|
18
|
+
throw new Error("Error encountered for XHR Response: #{this}")
|
19
|
+
|
20
|
+
toString: () ->
|
21
|
+
"URL: #{@xhr.responseURL}, " +
|
22
|
+
"ReadyState: #{@xhr.readyState}, " +
|
23
|
+
"Headers: #{@xhr.getAllResponseHeaders()}"
|
@@ -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)
|
@@ -1,14 +1,15 @@
|
|
1
1
|
xhr = null
|
2
|
+
activeDocument = document
|
2
3
|
|
3
4
|
installDocumentReadyPageEventTriggers = ->
|
4
|
-
|
5
|
+
activeDocument.addEventListener 'DOMContentLoaded', ( ->
|
5
6
|
triggerEvent 'page:change'
|
6
7
|
triggerEvent 'page:update'
|
7
8
|
), true
|
8
9
|
|
9
10
|
installJqueryAjaxSuccessPageUpdateTrigger = ->
|
10
11
|
if typeof jQuery isnt 'undefined'
|
11
|
-
jQuery(
|
12
|
+
jQuery(activeDocument).on 'ajaxSuccess', (event, xhr, settings) ->
|
12
13
|
return unless jQuery.trim xhr.responseText
|
13
14
|
triggerEvent 'page:update'
|
14
15
|
|
@@ -20,20 +21,20 @@ browserSupportsPushState =
|
|
20
21
|
window.history and window.history.pushState and window.history.replaceState and historyStateIsDefined
|
21
22
|
|
22
23
|
window.triggerEvent = (name, data) ->
|
23
|
-
event =
|
24
|
+
event = activeDocument.createEvent 'Events'
|
24
25
|
event.data = data if data
|
25
26
|
event.initEvent name, true, true
|
26
|
-
|
27
|
+
activeDocument.dispatchEvent event
|
27
28
|
|
28
29
|
window.triggerEventFor = (name, node, data) ->
|
29
|
-
event =
|
30
|
+
event = activeDocument.createEvent 'Events'
|
30
31
|
event.data = data if data
|
31
32
|
event.initEvent name, true, true
|
32
33
|
node.dispatchEvent event
|
33
34
|
|
34
35
|
popCookie = (name) ->
|
35
|
-
value =
|
36
|
-
|
36
|
+
value = activeDocument.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or ''
|
37
|
+
activeDocument.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
|
37
38
|
value
|
38
39
|
|
39
40
|
requestMethodIsSafe =
|
@@ -42,7 +43,7 @@ requestMethodIsSafe =
|
|
42
43
|
browserSupportsTurbolinks = browserSupportsPushState and requestMethodIsSafe
|
43
44
|
|
44
45
|
browserSupportsCustomEvents =
|
45
|
-
|
46
|
+
activeDocument.addEventListener and activeDocument.createEvent
|
46
47
|
|
47
48
|
if browserSupportsCustomEvents
|
48
49
|
installDocumentReadyPageEventTriggers()
|
@@ -61,7 +62,6 @@ removeNode = (node) ->
|
|
61
62
|
# TODO: clean up everything above me ^
|
62
63
|
# TODO: decide on the public API
|
63
64
|
class window.Turbolinks
|
64
|
-
createDocument = null
|
65
65
|
currentState = null
|
66
66
|
referer = null
|
67
67
|
|
@@ -80,8 +80,11 @@ class window.Turbolinks
|
|
80
80
|
fetchReplacement url, options
|
81
81
|
|
82
82
|
@fullPageNavigate: (url) ->
|
83
|
-
|
84
|
-
|
83
|
+
if url?
|
84
|
+
url = (new ComponentUrl(url)).absolute
|
85
|
+
triggerEvent('page:before-full-refresh', url: url)
|
86
|
+
activeDocument.location.href = url
|
87
|
+
return
|
85
88
|
|
86
89
|
@pushState: (state, title, url) ->
|
87
90
|
window.history.pushState(state, title, url)
|
@@ -89,6 +92,10 @@ class window.Turbolinks
|
|
89
92
|
@replaceState: (state, title, url) ->
|
90
93
|
window.history.replaceState(state, title, url)
|
91
94
|
|
95
|
+
@document: (documentToUse) ->
|
96
|
+
activeDocument = documentToUse if documentToUse
|
97
|
+
activeDocument
|
98
|
+
|
92
99
|
fetchReplacement = (url, options) ->
|
93
100
|
triggerEvent 'page:fetch', url: url.absolute
|
94
101
|
|
@@ -111,7 +118,7 @@ class window.Turbolinks
|
|
111
118
|
|
112
119
|
xhr.onload = ->
|
113
120
|
if xhr.status >= 500
|
114
|
-
Turbolinks.fullPageNavigate(url
|
121
|
+
Turbolinks.fullPageNavigate(url)
|
115
122
|
else
|
116
123
|
Turbolinks.loadPage(url, xhr, options)
|
117
124
|
xhr = null
|
@@ -121,7 +128,7 @@ class window.Turbolinks
|
|
121
128
|
if xhr.statusText == "abort"
|
122
129
|
xhr = null
|
123
130
|
return
|
124
|
-
Turbolinks.fullPageNavigate(url
|
131
|
+
Turbolinks.fullPageNavigate(url)
|
125
132
|
|
126
133
|
xhr.send()
|
127
134
|
|
@@ -130,21 +137,21 @@ class window.Turbolinks
|
|
130
137
|
@loadPage: (url, xhr, options = {}) ->
|
131
138
|
triggerEvent 'page:receive'
|
132
139
|
options.updatePushState ?= true
|
133
|
-
if upstreamDocument =
|
140
|
+
if upstreamDocument = new TurboGraft.Response(xhr).document()
|
134
141
|
if options.partialReplace
|
135
142
|
reflectNewUrl url if options.updatePushState
|
136
143
|
updateBody(upstreamDocument, xhr, options)
|
137
144
|
else
|
138
|
-
turbohead = new TurboHead(
|
145
|
+
turbohead = new TurboGraft.TurboHead(activeDocument, upstreamDocument)
|
139
146
|
if turbohead.hasAssetConflicts()
|
140
|
-
return Turbolinks.fullPageNavigate(url
|
147
|
+
return Turbolinks.fullPageNavigate(url)
|
141
148
|
reflectNewUrl url if options.updatePushState
|
142
149
|
turbohead.waitForAssets().then((result) ->
|
143
150
|
updateBody(upstreamDocument, xhr, options) unless result?.isCanceled
|
144
151
|
)
|
145
152
|
else
|
146
153
|
triggerEvent 'page:error', xhr
|
147
|
-
Turbolinks.fullPageNavigate(url
|
154
|
+
Turbolinks.fullPageNavigate(url)
|
148
155
|
|
149
156
|
updateBody = (upstreamDocument, xhr, options) ->
|
150
157
|
nodes = changePage(
|
@@ -159,7 +166,7 @@ class window.Turbolinks
|
|
159
166
|
triggerEvent 'page:load', nodes
|
160
167
|
|
161
168
|
changePage = (title, body, csrfToken, runScripts, options = {}) ->
|
162
|
-
|
169
|
+
activeDocument.title = title if title
|
163
170
|
options.onlyKeys ?= []
|
164
171
|
options.exceptKeys ?= []
|
165
172
|
|
@@ -177,7 +184,7 @@ class window.Turbolinks
|
|
177
184
|
deleteRefreshNeverNodes(body)
|
178
185
|
|
179
186
|
triggerEvent 'page:before-replace'
|
180
|
-
replaceNode(body,
|
187
|
+
replaceNode(body, activeDocument.body)
|
181
188
|
CSRFToken.update csrfToken if csrfToken?
|
182
189
|
setAutofocusElement()
|
183
190
|
executeScriptTags() if runScripts
|
@@ -190,14 +197,14 @@ class window.Turbolinks
|
|
190
197
|
getNodesMatchingRefreshKeys = (keys) ->
|
191
198
|
matchingNodes = []
|
192
199
|
for key in keys
|
193
|
-
for node in TurboGraft.querySelectorAllTGAttribute(
|
200
|
+
for node in TurboGraft.querySelectorAllTGAttribute(activeDocument, 'refresh', key)
|
194
201
|
matchingNodes.push(node)
|
195
202
|
|
196
203
|
return matchingNodes
|
197
204
|
|
198
205
|
getNodesWithRefreshAlways = ->
|
199
206
|
matchingNodes = []
|
200
|
-
for node in TurboGraft.querySelectorAllTGAttribute(
|
207
|
+
for node in TurboGraft.querySelectorAllTGAttribute(activeDocument, 'refresh-always')
|
201
208
|
matchingNodes.push(node)
|
202
209
|
|
203
210
|
return matchingNodes
|
@@ -210,8 +217,8 @@ class window.Turbolinks
|
|
210
217
|
false
|
211
218
|
|
212
219
|
setAutofocusElement = ->
|
213
|
-
autofocusElement = (list =
|
214
|
-
if autofocusElement and
|
220
|
+
autofocusElement = (list = activeDocument.querySelectorAll 'input[autofocus], textarea[autofocus]')[list.length - 1]
|
221
|
+
if autofocusElement and activeDocument.activeElement isnt autofocusElement
|
215
222
|
autofocusElement.focus()
|
216
223
|
|
217
224
|
deleteRefreshNeverNodes = (body) ->
|
@@ -260,7 +267,7 @@ class window.Turbolinks
|
|
260
267
|
persistStaticElements = (body) ->
|
261
268
|
allNodesToKeep = []
|
262
269
|
|
263
|
-
nodes = TurboGraft.querySelectorAllTGAttribute(
|
270
|
+
nodes = TurboGraft.querySelectorAllTGAttribute(activeDocument, 'tg-static')
|
264
271
|
allNodesToKeep.push(node) for node in nodes
|
265
272
|
|
266
273
|
keepNodes(body, allNodesToKeep)
|
@@ -270,22 +277,22 @@ class window.Turbolinks
|
|
270
277
|
allNodesToKeep = []
|
271
278
|
|
272
279
|
for key in keys
|
273
|
-
for node in TurboGraft.querySelectorAllTGAttribute(
|
280
|
+
for node in TurboGraft.querySelectorAllTGAttribute(activeDocument, 'refresh', key)
|
274
281
|
allNodesToKeep.push(node)
|
275
282
|
|
276
283
|
keepNodes(body, allNodesToKeep)
|
277
284
|
return
|
278
285
|
|
279
286
|
executeScriptTags = ->
|
280
|
-
scripts = Array::slice.call
|
287
|
+
scripts = Array::slice.call activeDocument.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])'
|
281
288
|
for script in scripts when script.type in ['', 'text/javascript']
|
282
289
|
executeScriptTag(script)
|
283
290
|
return
|
284
291
|
|
285
292
|
executeScriptTag = (script) ->
|
286
|
-
copy =
|
293
|
+
copy = activeDocument.createElement 'script'
|
287
294
|
copy.setAttribute attr.name, attr.value for attr in script.attributes
|
288
|
-
copy.appendChild
|
295
|
+
copy.appendChild activeDocument.createTextNode script.innerHTML
|
289
296
|
{ parentNode, nextSibling } = script
|
290
297
|
parentNode.removeChild script
|
291
298
|
parentNode.insertBefore copy, nextSibling
|
@@ -303,16 +310,16 @@ class window.Turbolinks
|
|
303
310
|
reflectRedirectedUrl = (xhr) ->
|
304
311
|
if location = xhr.getResponseHeader 'X-XHR-Redirected-To'
|
305
312
|
location = new ComponentUrl location
|
306
|
-
preservedHash = if location.hasNoHash() then
|
313
|
+
preservedHash = if location.hasNoHash() then activeDocument.location.hash else ''
|
307
314
|
Turbolinks.replaceState currentState, '', location.href + preservedHash
|
308
315
|
|
309
316
|
return
|
310
317
|
|
311
318
|
rememberReferer = ->
|
312
|
-
referer =
|
319
|
+
referer = activeDocument.location.href
|
313
320
|
|
314
321
|
@rememberCurrentUrl: ->
|
315
|
-
Turbolinks.replaceState { turbolinks: true, url:
|
322
|
+
Turbolinks.replaceState { turbolinks: true, url: activeDocument.location.href }, '', activeDocument.location.href
|
316
323
|
|
317
324
|
@rememberCurrentState: ->
|
318
325
|
currentState = window.history.state
|
@@ -321,26 +328,14 @@ class window.Turbolinks
|
|
321
328
|
window.scrollTo page.positionX, page.positionY
|
322
329
|
|
323
330
|
resetScrollPosition = ->
|
324
|
-
if
|
325
|
-
|
331
|
+
if activeDocument.location.hash
|
332
|
+
activeDocument.location.href = activeDocument.location.href
|
326
333
|
else
|
327
334
|
window.scrollTo 0, 0
|
328
335
|
|
329
336
|
pageChangePrevented = (url) ->
|
330
337
|
!triggerEvent('page:before-change', url)
|
331
338
|
|
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
339
|
installHistoryChangeHandler = (event) ->
|
345
340
|
if event.state?.turbolinks
|
346
341
|
Turbolinks.visit event.target.location.href
|
@@ -350,26 +345,15 @@ class window.Turbolinks
|
|
350
345
|
bypassOnLoadPopstate = (fn) ->
|
351
346
|
setTimeout fn, 500
|
352
347
|
|
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
348
|
if browserSupportsTurbolinks
|
365
349
|
@visit = fetch
|
366
350
|
@rememberCurrentUrl()
|
367
351
|
@rememberCurrentState()
|
368
352
|
|
369
|
-
|
353
|
+
activeDocument.addEventListener 'click', Click.installHandlerLast, true
|
370
354
|
|
371
355
|
bypassOnLoadPopstate ->
|
372
356
|
window.addEventListener 'popstate', installHistoryChangeHandler, false
|
373
357
|
|
374
358
|
else
|
375
|
-
@visit = (url) ->
|
359
|
+
@visit = (url) -> activeDocument.location.href = url
|
data/lib/turbograft.rb
CHANGED
@@ -35,10 +35,8 @@ module TurboGraft
|
|
35
35
|
end
|
36
36
|
|
37
37
|
ActiveSupport.on_load(:action_view) do
|
38
|
-
(ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).
|
39
|
-
|
40
|
-
end
|
41
|
-
end unless RUBY_VERSION =~ /^1\.8/
|
38
|
+
(ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).prepend(XHRUrlFor)
|
39
|
+
end
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
data/lib/turbograft/version.rb
CHANGED
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kristian Plettenberg-Dussault
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2016-
|
16
|
+
date: 2016-10-05 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: coffee-rails
|
@@ -224,10 +224,12 @@ files:
|
|
224
224
|
- lib/assets/javascripts/turbograft/click.coffee
|
225
225
|
- lib/assets/javascripts/turbograft/component_url.coffee
|
226
226
|
- lib/assets/javascripts/turbograft/csrf_token.coffee
|
227
|
+
- lib/assets/javascripts/turbograft/document.coffee
|
227
228
|
- lib/assets/javascripts/turbograft/initializers.coffee
|
228
229
|
- lib/assets/javascripts/turbograft/link.coffee
|
229
230
|
- lib/assets/javascripts/turbograft/page.coffee
|
230
231
|
- lib/assets/javascripts/turbograft/remote.coffee
|
232
|
+
- lib/assets/javascripts/turbograft/response.coffee
|
231
233
|
- lib/assets/javascripts/turbograft/turbohead.coffee
|
232
234
|
- lib/assets/javascripts/turbograft/turbolinks.coffee
|
233
235
|
- lib/turbograft.rb
|
@@ -247,9 +249,9 @@ require_paths:
|
|
247
249
|
- lib
|
248
250
|
required_ruby_version: !ruby/object:Gem::Requirement
|
249
251
|
requirements:
|
250
|
-
- - "
|
252
|
+
- - "~>"
|
251
253
|
- !ruby/object:Gem::Version
|
252
|
-
version: '
|
254
|
+
version: '2.1'
|
253
255
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
256
|
requirements:
|
255
257
|
- - ">="
|