turbograft 0.1.20 → 0.2.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 +4 -4
- data/README.md +40 -35
- data/lib/assets/javascripts/turbograft/initializers.coffee +15 -15
- data/lib/assets/javascripts/turbograft/remote.coffee +2 -2
- data/lib/assets/javascripts/turbograft/turbolinks.coffee +6 -6
- data/lib/assets/javascripts/turbograft.coffee +26 -0
- data/lib/turbograft/version.rb +1 -1
- metadata +3 -4
- data/lib/turbograft.js +0 -978
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c5cd11ad075c764ef8376a3e89011fd8a42c85b
|
4
|
+
data.tar.gz: b8958bb7aea77497657f90dc1e0885512f073c90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ea57c380149b4d2f100f135b7a94429f6721e31ddf5196e3f9e5cd0135f16661d0d37c8981278fd2b1b7f28c1fc615f838cb7c7ccc80354edf5d6facb201fd5
|
7
|
+
data.tar.gz: eead55c4918b3663e4f051a0688a3c33a193435603abefabdc2b8484ff2b2e47c4e4c5c771c4921524b631618dde68dd5d3ad7adcb1c2a21f38d16bfc074f7de
|
data/README.md
CHANGED
@@ -26,22 +26,27 @@ Turbograft was built with simplicity in mind. It intends to offer the smallest a
|
|
26
26
|
|
27
27
|
|
28
28
|
## Usage
|
29
|
+
|
30
|
+
Much of Turbograft’s functionality relies on attributes HTML elements. These attributes are currently namespaced to `data-tg-*` (e.g. `data-tg-refresh`).
|
31
|
+
|
32
|
+
Versions of Turbograft older than 0.2.0 did not use this namespacing. The old attribute names (e.g. `refresh`) are deprecated.
|
33
|
+
|
29
34
|
### Partial page refresh
|
30
35
|
|
31
36
|
```html
|
32
|
-
<div id="content" refresh="page">
|
37
|
+
<div id="content" data-tg-refresh="page">
|
33
38
|
...
|
34
39
|
</div>
|
35
40
|
```
|
36
41
|
|
37
42
|
|
38
43
|
```html
|
39
|
-
<a href="#" id="partial-refresh-page" refresh="page" onclick="event.preventDefault(); Page.refresh({url: '<%= page_path(@next_id) %>',onlyKeys: ['page']});">Refresh the page</a>
|
44
|
+
<a href="#" id="partial-refresh-page" data-tg-refresh="page" onclick="event.preventDefault(); Page.refresh({url: '<%= page_path(@next_id) %>',onlyKeys: ['page']});">Refresh the page</a>
|
40
45
|
```
|
41
46
|
|
42
|
-
This performs a `GET` request, but our client state is maintained. Using the refresh attribute, we tell TurboGraft to grab the new page, but only refresh elements where refresh="page"
|
47
|
+
This performs a `GET` request, but our client state is maintained. Using the `data-tg-refresh` attribute, we tell TurboGraft to grab the new page, but only refresh elements where `data-tg-refresh="page"`. This is the lowest-level way to use TurboGraft.
|
43
48
|
|
44
|
-
`refresh` attributes on your DOM nodes can be considered somewhat analoguous to how `class` will apply styles to any nodes with that class. That is to say, many nodes can be decorated `refresh="foo"` and all matching nodes will be replaced with `onlyKeys: ['foo']`. Each node with `refresh` must have its own unique ID (this is how nodes are matched during the replacement stage). At the moment, `refresh` does not support multiple keys (e.g., `refresh="foo bar"`) like the `class` attribute does.
|
49
|
+
`data-tg-refresh` attributes on your DOM nodes can be considered somewhat analoguous to how `class` will apply styles to any nodes with that class. That is to say, many nodes can be decorated `data-tg-refresh="foo"` and all matching nodes will be replaced with `onlyKeys: ['foo']`. Each node with `data-tg-refresh` must have its own unique ID (this is how nodes are matched during the replacement stage). At the moment, `data-tg-refresh` does not support multiple keys (e.g., `data-tg-refresh="foo bar"`) like the `class` attribute does.
|
45
50
|
|
46
51
|
### onlyKeys
|
47
52
|
You can specify multiple refresh keys on a page, and you can tell TurboGraft to refresh on one or more refresh keys for a given action.
|
@@ -57,54 +62,54 @@ You can also tell TurboGraft to refresh the page, but exclude certain elements f
|
|
57
62
|
<button id='refresh-a-and-b' href="<%= page_path(@id) %>" onclick="event.preventDefault(); Page.refresh({url: '<%= page_path(@id) %>', exceptKeys: ['section-a', 'section-b']});">Refresh everything but Section A and B</button>
|
58
63
|
```
|
59
64
|
|
60
|
-
### refresh-never
|
61
|
-
The `refresh-never` attribute will cause a node only appear once in the `body` of the document. This can be used to include and initialize a tracking pixel or script just once inside the body.
|
65
|
+
### data-tg-refresh-never
|
66
|
+
The `data-tg-refresh-never` attribute will cause a node only appear once in the `body` of the document. This can be used to include and initialize a tracking pixel or script just once inside the body.
|
62
67
|
|
63
68
|
```html
|
64
|
-
<div refresh-never>
|
65
|
-
<%= link_to "Never refresh", page_path(@next_id), id: "next-page-refresh-never", refresh
|
69
|
+
<div data-tg-refresh-never>
|
70
|
+
<%= link_to "Never refresh", page_path(@next_id), id: "next-page-refresh-never", "data-tg-refresh" => "page" %>
|
66
71
|
</div>
|
67
72
|
```
|
68
73
|
|
69
|
-
## tg-remote
|
74
|
+
## data-tg-remote
|
70
75
|
|
71
|
-
The `tg-remote` option allows you to query methods on or submit forms to different endpoints, and gives partial page replacement on specified refresh keys depending on the response status.
|
76
|
+
The `data-tg-remote` option allows you to query methods on or submit forms to different endpoints, and gives partial page replacement on specified refresh keys depending on the response status.
|
72
77
|
|
73
78
|
It requires your `<form>`, `<a>`, or `<button>` to be marked up with:
|
74
79
|
|
75
|
-
* `tg-remote`: (optionally valueless for `<form>`, but requires an HTTP method for links) the HTTP method you wish to call on your endpoint
|
80
|
+
* `data-tg-remote`: (optionally valueless for `<form>`, but requires an HTTP method for links) the HTTP method you wish to call on your endpoint
|
76
81
|
* `href`: (if node is `<a>` or `<button>`) the URL of the endpoint you wish to hit
|
77
|
-
* `refresh-on-success`: (optional) The refresh keys to be refreshed, using the body of the response. This is space-delimited
|
78
|
-
* `full-refresh-on-success-except`: (optional) Replaces body except for specififed refresh keys, using the body of the XHR which has succeeded
|
79
|
-
* `refresh-on-error`: (optional) The refresh keys to be refreshed, but using body of XHR which has failed. Only works with error 422. If the XHR returns and error and you do not supply a refresh-on-error, nothing is changed
|
80
|
-
* `full-refresh-on-error-except`: (optional) Replaces body except for specified refresh keys, using the body of the XHR which has failed. Only works with error 422
|
81
|
-
* `remote-once`: (optional) The action will only be performed once. Removes `remote-method` and `remote-once` from element after consumption
|
82
|
-
* `full-refresh`: Rather than using the content of the XHR response for partial page replacement, a full page refresh is performed. If `refresh-on-success` is defined, the page will be reloaded on these keys. If `refresh-on-success` is not defined, a full page refresh is performed. Defaults to true if neither refresh-on-success nor refresh-on-error are provided
|
83
|
-
* `tg-remote-norefresh`: Prevents `Page.refresh()` from being called, allowing methods to be executed without updating client state
|
82
|
+
* `data-tg-refresh-on-success`: (optional) The refresh keys to be refreshed, using the body of the response. This is space-delimited
|
83
|
+
* `data-tg-full-refresh-on-success-except`: (optional) Replaces body except for specififed refresh keys, using the body of the XHR which has succeeded
|
84
|
+
* `data-tg-refresh-on-error`: (optional) The refresh keys to be refreshed, but using body of XHR which has failed. Only works with error 422. If the XHR returns and error and you do not supply a refresh-on-error, nothing is changed
|
85
|
+
* `data-tg-full-refresh-on-error-except`: (optional) Replaces body except for specified refresh keys, using the body of the XHR which has failed. Only works with error 422
|
86
|
+
* `data-tg-remote-once`: (optional) The action will only be performed once. Removes `data-tg-remote-method` and `data-tg-remote-once` from element after consumption
|
87
|
+
* `data-tg-full-refresh`: Rather than using the content of the XHR response for partial page replacement, a full page refresh is performed. If `data-tg-refresh-on-success` is defined, the page will be reloaded on these keys. If `data-tg-refresh-on-success` is not defined, a full page refresh is performed. Defaults to true if neither refresh-on-success nor refresh-on-error are provided
|
88
|
+
* `data-tg-remote-norefresh`: Prevents `Page.refresh()` from being called, allowing methods to be executed without updating client state
|
84
89
|
|
85
|
-
Note that as `refresh-on-*` pertains to partial refreshes and `full-refresh-on-*-except` pertains to full refreshes, they are incompatible with each other and should not be combined.
|
90
|
+
Note that as `data-tg-refresh-on-*` pertains to partial refreshes and `data-tg-full-refresh-on-*-except` pertains to full refreshes, they are incompatible with each other and should not be combined.
|
86
91
|
|
87
92
|
### Examples
|
88
93
|
|
89
94
|
Call a remote method:
|
90
95
|
|
91
96
|
```html
|
92
|
-
<a href="#" tg-remote="post" refresh-on-success="page section-a section-b">Remote-method</a>
|
97
|
+
<a href="#" data-tg-remote="post" data-tg-refresh-on-success="page section-a section-b">Remote-method</a>
|
93
98
|
```
|
94
99
|
|
95
100
|
The Rails way:
|
96
101
|
|
97
102
|
```erb
|
98
|
-
<%= link_to "Remote method", method_path, 'refresh-on-success' => 'page section-a section-b', 'full-refresh' => 'true', 'tg-remote' => 'post' %>
|
103
|
+
<%= link_to "Remote method", method_path, 'data-tg-refresh-on-success' => 'page section-a section-b', 'data-tg-full-refresh' => 'true', 'data-tg-remote' => 'post' %>
|
99
104
|
```
|
100
105
|
|
101
106
|
Post to a remote form:
|
102
107
|
|
103
108
|
```html
|
104
|
-
<div id="results" refresh="results">
|
109
|
+
<div id="results" data-tg-refresh="results">
|
105
110
|
Use the field below to submit some content, and get a result.
|
106
111
|
</div>
|
107
|
-
<form tg-remote="" action="/pages/submit" method="post" refresh-on-success="results" refresh-on-error="results">
|
112
|
+
<form data-tg-remote="" action="/pages/submit" method="post" data-tg-refresh-on-success="results" data-tg-refresh-on-error="results">
|
108
113
|
<input name="form-input" type="text">
|
109
114
|
<button type="submit">Submit</button>
|
110
115
|
</form>
|
@@ -117,28 +122,28 @@ Post to a remote form:
|
|
117
122
|
* `turbograft:remote:always`: Always fires when XHR is complete
|
118
123
|
* `turbograft:remote:success`: Always fires when XHR was successful
|
119
124
|
* `turbograft:remote:fail`: Always fires when XHR failed
|
120
|
-
* `turbograft:remote:fail:unhandled`: Fires after `turbograft:remote:fail`, but when no partial replacement with refresh-on-error was performed (because no `refresh-on-error` was supplied)
|
125
|
+
* `turbograft:remote:fail:unhandled`: Fires after `turbograft:remote:fail`, but when no partial replacement with refresh-on-error was performed (because no `data-tg-refresh-on-error` was supplied)
|
121
126
|
|
122
|
-
Each event also is sent with a copy of the XHR, as well as a reference to the element that initated the `remote-method`.
|
127
|
+
Each event also is sent with a copy of the XHR, as well as a reference to the element that initated the `data-tg-remote-method`.
|
123
128
|
|
124
|
-
### tg-static
|
129
|
+
### data-tg-static
|
125
130
|
|
126
|
-
With the `tg-static` attribute decorating a node, we can make sure that this node is not replaced during a fullpage refresh. Contrast this to partial page refreshes, where we normally specify the set of elements that need to change. With `tg-static`, we can define a set of elements (by annotating them with this attribute) that must never change.
|
131
|
+
With the `data-tg-static` attribute decorating a node, we can make sure that this node is not replaced during a fullpage refresh. Contrast this to partial page refreshes, where we normally specify the set of elements that need to change. With `data-tg-static`, we can define a set of elements (by annotating them with this attribute) that must never change.
|
127
132
|
|
128
|
-
The internal state of any nodes marked with `tg-static` will remain, even though the entire page has been swapped out. A partial page refresh with `onlyKeys` targeting a node inside of the `tg-static` node is also possible, persisting your static element but swapping the innards.
|
133
|
+
The internal state of any nodes marked with `data-tg-static` will remain, even though the entire page has been swapped out. A partial page refresh with `onlyKeys` targeting a node inside of the `data-tg-static` node is also possible, persisting your static element but swapping the innards.
|
129
134
|
|
130
|
-
Though, if you were to refresh the page at a higher level -- e.g., refreshing an ancestor of the `tg-static`, the static aspect is no longer obeyed and it is replaced!
|
135
|
+
Though, if you were to refresh the page at a higher level -- e.g., refreshing an ancestor of the `data-tg-static`, the static aspect is no longer obeyed and it is replaced!
|
131
136
|
|
132
137
|
Examples of where this may be useful include:
|
133
138
|
|
134
139
|
- running `<video>` or `<audio>` element
|
135
140
|
- a client-controlled static nav
|
136
141
|
|
137
|
-
### refresh-always
|
142
|
+
### data-tg-refresh-always
|
138
143
|
|
139
|
-
For the lazy developer in all of us, we can use the attribute `refresh-always` when we want to be sure we've absolutely replaced a certain element, if it exists. An example of such a node you may want to apply this might be an unread notification count -- always being sure to update it if it exists in the response.
|
144
|
+
For the lazy developer in all of us, we can use the attribute `data-tg-refresh-always` when we want to be sure we've absolutely replaced a certain element, if it exists. An example of such a node you may want to apply this might be an unread notification count -- always being sure to update it if it exists in the response.
|
140
145
|
|
141
|
-
### tg-remote-noserialize
|
146
|
+
### data-tg-remote-noserialize
|
142
147
|
|
143
148
|
When serializing forms for tg-remote calls, turbograft will check to ensure inputs meet the following criteria:
|
144
149
|
|
@@ -147,10 +152,10 @@ When serializing forms for tg-remote calls, turbograft will check to ensure inpu
|
|
147
152
|
|
148
153
|
and
|
149
154
|
|
150
|
-
- the input does not have the `tg-remote-noserialize` attribute
|
151
|
-
- no ancestor of the input has the `tg-remote-noserialize` attribute
|
155
|
+
- the input does not have the `data-tg-remote-noserialize` attribute
|
156
|
+
- no ancestor of the input has the `data-tg-remote-noserialize` attribute
|
152
157
|
|
153
|
-
The `tg-remote-noserialize` is useful in scenarios where a whole section of the page should be editable, i.e. not `disabled`, but should only conditionally be submitted to the server.
|
158
|
+
The `data-tg-remote-noserialize` is useful in scenarios where a whole section of the page should be editable, i.e. not `disabled`, but should only conditionally be submitted to the server.
|
154
159
|
|
155
160
|
## Example App
|
156
161
|
|
@@ -4,34 +4,34 @@ hasClass = (node, search) ->
|
|
4
4
|
nodeIsDisabled = (node) ->
|
5
5
|
node.getAttribute('disabled') || hasClass(node, 'disabled')
|
6
6
|
|
7
|
-
setupRemoteFromTarget = (target, httpRequestType,
|
8
|
-
httpUrl = target.getAttribute(
|
7
|
+
setupRemoteFromTarget = (target, httpRequestType, form = null) ->
|
8
|
+
httpUrl = target.getAttribute('href') || target.getAttribute('action')
|
9
9
|
|
10
|
-
throw new Error("Turbograft developer error: You did not provide a URL ('#{urlAttribute}' attribute) for tg-remote") unless httpUrl
|
10
|
+
throw new Error("Turbograft developer error: You did not provide a URL ('#{urlAttribute}' attribute) for data-tg-remote") unless httpUrl
|
11
11
|
|
12
|
-
if
|
13
|
-
|
14
|
-
|
12
|
+
if TurboGraft.getTGAttribute(target, "remote-once")
|
13
|
+
TurboGraft.removeTGAttribute(target, "remote-once")
|
14
|
+
TurboGraft.removeTGAttribute(target, "tg-remote")
|
15
15
|
|
16
16
|
options =
|
17
17
|
httpRequestType: httpRequestType
|
18
18
|
httpUrl: httpUrl
|
19
|
-
fullRefresh:
|
20
|
-
refreshOnSuccess:
|
21
|
-
refreshOnSuccessExcept:
|
22
|
-
refreshOnError:
|
23
|
-
refreshOnErrorExcept:
|
19
|
+
fullRefresh: TurboGraft.getTGAttribute(target, 'full-refresh')?
|
20
|
+
refreshOnSuccess: TurboGraft.getTGAttribute(target, 'refresh-on-success')
|
21
|
+
refreshOnSuccessExcept: TurboGraft.getTGAttribute(target, 'full-refresh-on-success-except')
|
22
|
+
refreshOnError: TurboGraft.getTGAttribute(target, 'refresh-on-error')
|
23
|
+
refreshOnErrorExcept: TurboGraft.getTGAttribute(target, 'full-refresh-on-error-except')
|
24
24
|
|
25
25
|
new TurboGraft.Remote(options, form, target)
|
26
26
|
|
27
27
|
TurboGraft.handlers.remoteMethodHandler = (ev) ->
|
28
28
|
target = ev.clickTarget
|
29
|
-
httpRequestType =
|
29
|
+
httpRequestType = TurboGraft.getTGAttribute(target, 'tg-remote')
|
30
30
|
|
31
31
|
return unless httpRequestType
|
32
32
|
ev.preventDefault()
|
33
33
|
|
34
|
-
remote = setupRemoteFromTarget(target, httpRequestType
|
34
|
+
remote = setupRemoteFromTarget(target, httpRequestType)
|
35
35
|
remote.submit()
|
36
36
|
return
|
37
37
|
|
@@ -39,10 +39,10 @@ TurboGraft.handlers.remoteFormHandler = (ev) ->
|
|
39
39
|
target = ev.target
|
40
40
|
method = target.getAttribute('method')
|
41
41
|
|
42
|
-
return unless
|
42
|
+
return unless TurboGraft.hasTGAttribute(target, 'tg-remote')
|
43
43
|
ev.preventDefault()
|
44
44
|
|
45
|
-
remote = setupRemoteFromTarget(target, method,
|
45
|
+
remote = setupRemoteFromTarget(target, method, target)
|
46
46
|
remote.submit()
|
47
47
|
return
|
48
48
|
|
@@ -103,7 +103,7 @@ class TurboGraft.Remote
|
|
103
103
|
_enabledInputs: (form) ->
|
104
104
|
selector = "input:not([type='reset']):not([type='button']):not([type='submit']):not([type='image']), select, textarea"
|
105
105
|
inputs = Array::slice.call(form.querySelectorAll(selector))
|
106
|
-
disabledNodes = Array::slice.call(
|
106
|
+
disabledNodes = Array::slice.call(TurboGraft.querySelectorAllTGAttribute(form, 'tg-remote-noserialize'))
|
107
107
|
|
108
108
|
return inputs unless disabledNodes.length
|
109
109
|
|
@@ -128,7 +128,7 @@ class TurboGraft.Remote
|
|
128
128
|
Page.visit(redirect, reload: true)
|
129
129
|
return
|
130
130
|
|
131
|
-
unless @initiator
|
131
|
+
unless TurboGraft.hasTGAttribute(@initiator, 'tg-remote-norefresh')
|
132
132
|
if @opts.fullRefresh && @refreshOnSuccess
|
133
133
|
Page.refresh(onlyKeys: @refreshOnSuccess)
|
134
134
|
else if @opts.fullRefresh
|
@@ -161,14 +161,14 @@ class window.Turbolinks
|
|
161
161
|
getNodesMatchingRefreshKeys = (keys) ->
|
162
162
|
matchingNodes = []
|
163
163
|
for key in keys
|
164
|
-
for node in
|
164
|
+
for node in TurboGraft.querySelectorAllTGAttribute(document, 'refresh', key)
|
165
165
|
matchingNodes.push(node)
|
166
166
|
|
167
167
|
return matchingNodes
|
168
168
|
|
169
169
|
getNodesWithRefreshAlways = ->
|
170
170
|
matchingNodes = []
|
171
|
-
for node in
|
171
|
+
for node in TurboGraft.querySelectorAllTGAttribute(document, 'refresh-always')
|
172
172
|
matchingNodes.push(node)
|
173
173
|
|
174
174
|
return matchingNodes
|
@@ -186,7 +186,7 @@ class window.Turbolinks
|
|
186
186
|
autofocusElement.focus()
|
187
187
|
|
188
188
|
deleteRefreshNeverNodes = (body) ->
|
189
|
-
for node in
|
189
|
+
for node in TurboGraft.querySelectorAllTGAttribute(body, 'refresh-never')
|
190
190
|
removeNode(node)
|
191
191
|
|
192
192
|
return
|
@@ -215,7 +215,7 @@ class window.Turbolinks
|
|
215
215
|
else
|
216
216
|
refreshedNodes.push(newNode)
|
217
217
|
|
218
|
-
else if
|
218
|
+
else if TurboGraft.getTGAttribute(existingNode, "refresh-always") == null
|
219
219
|
removeNode(existingNode)
|
220
220
|
|
221
221
|
refreshedNodes
|
@@ -231,7 +231,7 @@ class window.Turbolinks
|
|
231
231
|
persistStaticElements = (body) ->
|
232
232
|
allNodesToKeep = []
|
233
233
|
|
234
|
-
nodes =
|
234
|
+
nodes = TurboGraft.querySelectorAllTGAttribute(document, 'tg-static')
|
235
235
|
allNodesToKeep.push(node) for node in nodes
|
236
236
|
|
237
237
|
keepNodes(body, allNodesToKeep)
|
@@ -241,7 +241,7 @@ class window.Turbolinks
|
|
241
241
|
allNodesToKeep = []
|
242
242
|
|
243
243
|
for key in keys
|
244
|
-
for node in
|
244
|
+
for node in TurboGraft.querySelectorAllTGAttribute(document, 'refresh', key)
|
245
245
|
allNodesToKeep.push(node)
|
246
246
|
|
247
247
|
keepNodes(body, allNodesToKeep)
|
@@ -2,3 +2,29 @@
|
|
2
2
|
#= require_tree ./turbograft
|
3
3
|
|
4
4
|
window.TurboGraft ?= { handlers: {} }
|
5
|
+
|
6
|
+
TurboGraft.tgAttribute = (attr) ->
|
7
|
+
tgAttr = if attr[0...3] == 'tg-'
|
8
|
+
"data-#{attr}"
|
9
|
+
else
|
10
|
+
"data-tg-#{attr}"
|
11
|
+
|
12
|
+
TurboGraft.getTGAttribute = (node, attr) ->
|
13
|
+
tgAttr = TurboGraft.tgAttribute(attr)
|
14
|
+
node.getAttribute(tgAttr) || node.getAttribute(attr)
|
15
|
+
|
16
|
+
TurboGraft.removeTGAttribute = (node, attr) ->
|
17
|
+
tgAttr = TurboGraft.tgAttribute(attr)
|
18
|
+
node.removeAttribute(tgAttr)
|
19
|
+
node.removeAttribute(attr)
|
20
|
+
|
21
|
+
TurboGraft.hasTGAttribute = (node, attr) ->
|
22
|
+
tgAttr = TurboGraft.tgAttribute(attr)
|
23
|
+
node.getAttribute(tgAttr)? || node.getAttribute(attr)?
|
24
|
+
|
25
|
+
TurboGraft.querySelectorAllTGAttribute = (node, attr, value = null) ->
|
26
|
+
tgAttr = TurboGraft.tgAttribute(attr)
|
27
|
+
if value
|
28
|
+
node.querySelectorAll("[#{tgAttr}=#{value}], [#{attr}=#{value}]")
|
29
|
+
else
|
30
|
+
node.querySelectorAll("[#{tgAttr}], [#{attr}]")
|
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
|
+
version: 0.2.0
|
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: 2015-
|
16
|
+
date: 2015-11-23 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: coffee-rails
|
@@ -229,7 +229,6 @@ files:
|
|
229
229
|
- lib/assets/javascripts/turbograft/page.coffee
|
230
230
|
- lib/assets/javascripts/turbograft/remote.coffee
|
231
231
|
- lib/assets/javascripts/turbograft/turbolinks.coffee
|
232
|
-
- lib/turbograft.js
|
233
232
|
- lib/turbograft.rb
|
234
233
|
- lib/turbograft/cookies.rb
|
235
234
|
- lib/turbograft/redirection.rb
|
@@ -257,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
256
|
version: '0'
|
258
257
|
requirements: []
|
259
258
|
rubyforge_project:
|
260
|
-
rubygems_version: 2.
|
259
|
+
rubygems_version: 2.4.5.1
|
261
260
|
signing_key:
|
262
261
|
specification_version: 4
|
263
262
|
summary: turbolinks with partial page replacement
|
data/lib/turbograft.js
DELETED
@@ -1,978 +0,0 @@
|
|
1
|
-
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
2
|
-
window.Click = (function() {
|
3
|
-
Click.installHandlerLast = function(event) {
|
4
|
-
if (!event.defaultPrevented) {
|
5
|
-
document.removeEventListener('click', Click.handle, false);
|
6
|
-
return document.addEventListener('click', Click.handle, false);
|
7
|
-
}
|
8
|
-
};
|
9
|
-
|
10
|
-
Click.handle = function(event) {
|
11
|
-
return new Click(event);
|
12
|
-
};
|
13
|
-
|
14
|
-
function Click(event) {
|
15
|
-
this.event = event;
|
16
|
-
if (this.event.defaultPrevented) {
|
17
|
-
return;
|
18
|
-
}
|
19
|
-
this._extractLink();
|
20
|
-
if (this._validForTurbolinks()) {
|
21
|
-
if (!this._pageChangePrevented()) {
|
22
|
-
Turbolinks.visit(this.link.href);
|
23
|
-
}
|
24
|
-
this.event.preventDefault();
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
Click.prototype._pageChangePrevented = function() {
|
29
|
-
return !triggerEvent('page:before-change');
|
30
|
-
};
|
31
|
-
|
32
|
-
Click.prototype._extractLink = function() {
|
33
|
-
var link;
|
34
|
-
link = this.event.target;
|
35
|
-
while (!(!link.parentNode || link.nodeName === 'A')) {
|
36
|
-
link = link.parentNode;
|
37
|
-
}
|
38
|
-
if (link.nodeName === 'A' && link.href.length !== 0) {
|
39
|
-
return this.link = new Link(link);
|
40
|
-
}
|
41
|
-
};
|
42
|
-
|
43
|
-
Click.prototype._validForTurbolinks = function() {
|
44
|
-
return (this.link != null) && !(this.link.shouldIgnore() || this._nonStandardClick());
|
45
|
-
};
|
46
|
-
|
47
|
-
Click.prototype._nonStandardClick = function() {
|
48
|
-
return this.event.which > 1 || this.event.metaKey || this.event.ctrlKey || this.event.shiftKey || this.event.altKey;
|
49
|
-
};
|
50
|
-
|
51
|
-
return Click;
|
52
|
-
|
53
|
-
})();
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
},{}],2:[function(require,module,exports){
|
58
|
-
window.ComponentUrl = (function() {
|
59
|
-
function ComponentUrl(original) {
|
60
|
-
this.original = original != null ? original : document.location.href;
|
61
|
-
if (this.original.constructor === ComponentUrl) {
|
62
|
-
return this.original;
|
63
|
-
}
|
64
|
-
this._parse();
|
65
|
-
}
|
66
|
-
|
67
|
-
ComponentUrl.prototype.withoutHash = function() {
|
68
|
-
return this.href.replace(this.hash, '');
|
69
|
-
};
|
70
|
-
|
71
|
-
ComponentUrl.prototype.withoutHashForIE10compatibility = function() {
|
72
|
-
return this.withoutHash();
|
73
|
-
};
|
74
|
-
|
75
|
-
ComponentUrl.prototype.hasNoHash = function() {
|
76
|
-
return this.hash.length === 0;
|
77
|
-
};
|
78
|
-
|
79
|
-
ComponentUrl.prototype._parse = function() {
|
80
|
-
var _ref;
|
81
|
-
(this.link != null ? this.link : this.link = document.createElement('a')).href = this.original;
|
82
|
-
_ref = this.link, this.href = _ref.href, this.protocol = _ref.protocol, this.host = _ref.host, this.hostname = _ref.hostname, this.port = _ref.port, this.pathname = _ref.pathname, this.search = _ref.search, this.hash = _ref.hash;
|
83
|
-
this.origin = [this.protocol, '//', this.hostname].join('');
|
84
|
-
if (this.port.length !== 0) {
|
85
|
-
this.origin += ":" + this.port;
|
86
|
-
}
|
87
|
-
this.relative = [this.pathname, this.search, this.hash].join('');
|
88
|
-
return this.absolute = this.href;
|
89
|
-
};
|
90
|
-
|
91
|
-
return ComponentUrl;
|
92
|
-
|
93
|
-
})();
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
},{}],3:[function(require,module,exports){
|
98
|
-
window.CSRFToken = (function() {
|
99
|
-
function CSRFToken() {}
|
100
|
-
|
101
|
-
CSRFToken.get = function(doc) {
|
102
|
-
var tag;
|
103
|
-
if (doc == null) {
|
104
|
-
doc = document;
|
105
|
-
}
|
106
|
-
return {
|
107
|
-
node: tag = doc.querySelector('meta[name="csrf-token"]'),
|
108
|
-
token: tag != null ? typeof tag.getAttribute === "function" ? tag.getAttribute('content') : void 0 : void 0
|
109
|
-
};
|
110
|
-
};
|
111
|
-
|
112
|
-
CSRFToken.update = function(latest) {
|
113
|
-
var current;
|
114
|
-
current = this.get();
|
115
|
-
if ((current.token != null) && (latest != null) && current.token !== latest) {
|
116
|
-
return current.node.setAttribute('content', latest);
|
117
|
-
}
|
118
|
-
};
|
119
|
-
|
120
|
-
return CSRFToken;
|
121
|
-
|
122
|
-
})();
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
},{}],4:[function(require,module,exports){
|
127
|
-
var documentListenerForButtons, hasClass, nodeIsDisabled;
|
128
|
-
|
129
|
-
window.TurboGraft = {
|
130
|
-
handlers: {}
|
131
|
-
};
|
132
|
-
|
133
|
-
hasClass = function(node, search) {
|
134
|
-
var className, _i, _len, _ref;
|
135
|
-
_ref = node.classList;
|
136
|
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
137
|
-
className = _ref[_i];
|
138
|
-
if (className === search) {
|
139
|
-
return true;
|
140
|
-
}
|
141
|
-
}
|
142
|
-
return false;
|
143
|
-
};
|
144
|
-
|
145
|
-
nodeIsDisabled = function(node) {
|
146
|
-
return node.getAttribute('disabled') || hasClass(node, 'disabled');
|
147
|
-
};
|
148
|
-
|
149
|
-
TurboGraft.handlers.partialGraftClickHandler = function(ev) {
|
150
|
-
var href, keys, partialGraft, refresh, target;
|
151
|
-
target = ev.target;
|
152
|
-
partialGraft = target.getAttribute("partial-graft");
|
153
|
-
if (partialGraft == null) {
|
154
|
-
return;
|
155
|
-
}
|
156
|
-
ev.preventDefault();
|
157
|
-
href = target.getAttribute("href");
|
158
|
-
refresh = target.getAttribute("refresh");
|
159
|
-
if (href == null) {
|
160
|
-
throw "TurboGraft developer error: href is not defined on node " + target;
|
161
|
-
}
|
162
|
-
if (refresh == null) {
|
163
|
-
throw "TurboGraft developer error: refresh is not defined on node " + target;
|
164
|
-
}
|
165
|
-
keys = refresh.trim().split(" ");
|
166
|
-
return Page.refresh({
|
167
|
-
url: href,
|
168
|
-
onlyKeys: keys
|
169
|
-
});
|
170
|
-
};
|
171
|
-
|
172
|
-
TurboGraft.handlers.remoteMethodHandler = function(ev) {
|
173
|
-
var httpRequestType, httpUrl, onlyOnce, options, remote, target;
|
174
|
-
target = ev.target;
|
175
|
-
if (!target.getAttribute('remote-method')) {
|
176
|
-
return;
|
177
|
-
}
|
178
|
-
ev.preventDefault();
|
179
|
-
httpUrl = target.getAttribute('href');
|
180
|
-
httpRequestType = target.getAttribute('remote-method');
|
181
|
-
if (!httpRequestType) {
|
182
|
-
throw "Turbograft developer error: You did not provide a request type for remote-method";
|
183
|
-
}
|
184
|
-
if (!httpUrl) {
|
185
|
-
throw "Turbograft developer error: You did not provide a URL for remote-method";
|
186
|
-
}
|
187
|
-
if (onlyOnce = target.getAttribute("remote-once")) {
|
188
|
-
target.removeAttribute("remote-once");
|
189
|
-
target.removeAttribute("remote-method");
|
190
|
-
}
|
191
|
-
options = {
|
192
|
-
httpRequestType: httpRequestType,
|
193
|
-
httpUrl: httpUrl,
|
194
|
-
fullRefresh: target.getAttribute('full-refresh') != null,
|
195
|
-
refreshOnSuccess: target.getAttribute('refresh-on-success'),
|
196
|
-
refreshOnError: target.getAttribute('refresh-on-error')
|
197
|
-
};
|
198
|
-
remote = new TurboGraft.Remote(options);
|
199
|
-
};
|
200
|
-
|
201
|
-
documentListenerForButtons = function(eventType, handler, useCapture) {
|
202
|
-
if (useCapture == null) {
|
203
|
-
useCapture = false;
|
204
|
-
}
|
205
|
-
return document.addEventListener(eventType, function(ev) {
|
206
|
-
var target;
|
207
|
-
target = ev.target;
|
208
|
-
if (!(target.nodeName === "A" || target.nodeName === "BUTTON") || nodeIsDisabled(target)) {
|
209
|
-
return;
|
210
|
-
}
|
211
|
-
return handler(ev);
|
212
|
-
});
|
213
|
-
};
|
214
|
-
|
215
|
-
documentListenerForButtons('click', TurboGraft.handlers.partialGraftClickHandler, true);
|
216
|
-
|
217
|
-
documentListenerForButtons('click', TurboGraft.handlers.remoteMethodHandler, true);
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
},{}],5:[function(require,module,exports){
|
222
|
-
var __hasProp = {}.hasOwnProperty,
|
223
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
224
|
-
__slice = [].slice;
|
225
|
-
|
226
|
-
window.Link = (function(_super) {
|
227
|
-
__extends(Link, _super);
|
228
|
-
|
229
|
-
Link.HTML_EXTENSIONS = ['html'];
|
230
|
-
|
231
|
-
Link.allowExtensions = function() {
|
232
|
-
var extension, extensions, _i, _len;
|
233
|
-
extensions = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
234
|
-
for (_i = 0, _len = extensions.length; _i < _len; _i++) {
|
235
|
-
extension = extensions[_i];
|
236
|
-
Link.HTML_EXTENSIONS.push(extension);
|
237
|
-
}
|
238
|
-
return Link.HTML_EXTENSIONS;
|
239
|
-
};
|
240
|
-
|
241
|
-
function Link(link) {
|
242
|
-
this.link = link;
|
243
|
-
if (this.link.constructor === Link) {
|
244
|
-
return this.link;
|
245
|
-
}
|
246
|
-
this.original = this.link.href;
|
247
|
-
Link.__super__.constructor.apply(this, arguments);
|
248
|
-
}
|
249
|
-
|
250
|
-
Link.prototype.shouldIgnore = function() {
|
251
|
-
return this._crossOrigin() || this._anchored() || this._nonHtml() || this._optOut() || this._target();
|
252
|
-
};
|
253
|
-
|
254
|
-
Link.prototype._crossOrigin = function() {
|
255
|
-
return this.origin !== (new ComponentUrl).origin;
|
256
|
-
};
|
257
|
-
|
258
|
-
Link.prototype._anchored = function() {
|
259
|
-
var current;
|
260
|
-
return ((this.hash && this.withoutHash()) === (current = new ComponentUrl).withoutHash()) || (this.href === current.href + '#');
|
261
|
-
};
|
262
|
-
|
263
|
-
Link.prototype._nonHtml = function() {
|
264
|
-
return this.pathname.match(/\.[a-z]+$/g) && !this.pathname.match(new RegExp("\\.(?:" + (Link.HTML_EXTENSIONS.join('|')) + ")?$", 'g'));
|
265
|
-
};
|
266
|
-
|
267
|
-
Link.prototype._optOut = function() {
|
268
|
-
var ignore, link;
|
269
|
-
link = this.link;
|
270
|
-
while (!(ignore || link === document || link === null)) {
|
271
|
-
ignore = link.getAttribute('data-no-turbolink') != null;
|
272
|
-
link = link.parentNode;
|
273
|
-
}
|
274
|
-
return ignore;
|
275
|
-
};
|
276
|
-
|
277
|
-
Link.prototype._target = function() {
|
278
|
-
return this.link.target.length !== 0;
|
279
|
-
};
|
280
|
-
|
281
|
-
return Link;
|
282
|
-
|
283
|
-
})(ComponentUrl);
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
},{}],6:[function(require,module,exports){
|
288
|
-
if (!window.Page) {
|
289
|
-
window.Page = {};
|
290
|
-
}
|
291
|
-
|
292
|
-
Page.visit = function(url, opts) {
|
293
|
-
if (opts == null) {
|
294
|
-
opts = {};
|
295
|
-
}
|
296
|
-
if (opts.reload) {
|
297
|
-
return window.location = url;
|
298
|
-
} else {
|
299
|
-
return Turbolinks.visit(url);
|
300
|
-
}
|
301
|
-
};
|
302
|
-
|
303
|
-
Page.refresh = function(options, callback) {
|
304
|
-
var newUrl, paramString;
|
305
|
-
if (options == null) {
|
306
|
-
options = {};
|
307
|
-
}
|
308
|
-
newUrl = options.url ? options.url : options.queryParams ? (paramString = $.param(options.queryParams), paramString ? paramString = "?" + paramString : void 0, location.pathname + paramString) : location.href;
|
309
|
-
if (options.response) {
|
310
|
-
return Turbolinks.loadPage(null, options.response, true, callback, options.onlyKeys || []);
|
311
|
-
} else {
|
312
|
-
return Turbolinks.visit(newUrl, true, options.onlyKeys || [], function() {
|
313
|
-
return typeof callback === "function" ? callback() : void 0;
|
314
|
-
});
|
315
|
-
}
|
316
|
-
};
|
317
|
-
|
318
|
-
Page.open = function() {
|
319
|
-
return window.open.apply(window, arguments);
|
320
|
-
};
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
},{}],7:[function(require,module,exports){
|
325
|
-
window.PageCache = (function() {
|
326
|
-
var simultaneousAdditionOffset, storage;
|
327
|
-
|
328
|
-
storage = {};
|
329
|
-
|
330
|
-
simultaneousAdditionOffset = 0;
|
331
|
-
|
332
|
-
function PageCache(cacheSize) {
|
333
|
-
this.cacheSize = cacheSize != null ? cacheSize : 10;
|
334
|
-
storage = {};
|
335
|
-
return this;
|
336
|
-
}
|
337
|
-
|
338
|
-
PageCache.prototype.get = function(key) {
|
339
|
-
return storage[key];
|
340
|
-
};
|
341
|
-
|
342
|
-
PageCache.prototype.set = function(key, value) {
|
343
|
-
if (typeof value !== "object") {
|
344
|
-
throw "Developer error: You must store objects in this cache";
|
345
|
-
}
|
346
|
-
value['cachedAt'] = new Date().getTime() + (simultaneousAdditionOffset += 1);
|
347
|
-
storage[key] = value;
|
348
|
-
return this.constrain();
|
349
|
-
};
|
350
|
-
|
351
|
-
PageCache.prototype.clear = function() {
|
352
|
-
return storage = {};
|
353
|
-
};
|
354
|
-
|
355
|
-
PageCache.prototype.setCacheSize = function(newSize) {
|
356
|
-
if (/^[\d]+$/.test(newSize)) {
|
357
|
-
this.cacheSize = parseInt(newSize, 10);
|
358
|
-
return this.constrain();
|
359
|
-
} else {
|
360
|
-
throw "Developer error: Invalid parameter '" + newSize + "' for PageCache; must be integer";
|
361
|
-
}
|
362
|
-
};
|
363
|
-
|
364
|
-
PageCache.prototype.constrain = function() {
|
365
|
-
var cacheTimesRecentFirst, key, pageCacheKeys, _i, _len, _results;
|
366
|
-
pageCacheKeys = Object.keys(storage);
|
367
|
-
cacheTimesRecentFirst = pageCacheKeys.map((function(_this) {
|
368
|
-
return function(url) {
|
369
|
-
return storage[url].cachedAt;
|
370
|
-
};
|
371
|
-
})(this)).sort(function(a, b) {
|
372
|
-
return b - a;
|
373
|
-
});
|
374
|
-
_results = [];
|
375
|
-
for (_i = 0, _len = pageCacheKeys.length; _i < _len; _i++) {
|
376
|
-
key = pageCacheKeys[_i];
|
377
|
-
if (!(storage[key].cachedAt <= cacheTimesRecentFirst[this.cacheSize])) {
|
378
|
-
continue;
|
379
|
-
}
|
380
|
-
triggerEvent('page:expire', storage[key]);
|
381
|
-
_results.push(delete storage[key]);
|
382
|
-
}
|
383
|
-
return _results;
|
384
|
-
};
|
385
|
-
|
386
|
-
PageCache.prototype.length = function() {
|
387
|
-
return Object.keys(storage).length;
|
388
|
-
};
|
389
|
-
|
390
|
-
return PageCache;
|
391
|
-
|
392
|
-
})();
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
},{}],8:[function(require,module,exports){
|
397
|
-
TurboGraft.Remote = (function() {
|
398
|
-
function Remote(opts, form) {
|
399
|
-
var actualRequestType, formData, xhr;
|
400
|
-
this.opts = opts;
|
401
|
-
if (form) {
|
402
|
-
formData = new FormData(form);
|
403
|
-
} else {
|
404
|
-
formData = new FormData();
|
405
|
-
}
|
406
|
-
actualRequestType = this.opts.httpRequestType.toLowerCase() === 'get' ? 'GET' : 'POST';
|
407
|
-
formData.append("_method", this.opts.httpRequestType);
|
408
|
-
if (this.opts.refreshOnSuccess) {
|
409
|
-
this.refreshOnSuccess = this.opts.refreshOnSuccess.split(" ");
|
410
|
-
}
|
411
|
-
if (this.opts.refreshOnError) {
|
412
|
-
this.refreshOnError = this.opts.refreshOnError.split(" ");
|
413
|
-
}
|
414
|
-
xhr = new XMLHttpRequest;
|
415
|
-
xhr.open(actualRequestType, this.opts.httpUrl, true);
|
416
|
-
xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
|
417
|
-
xhr.addEventListener('loadstart', function() {
|
418
|
-
return triggerEvent('turbograft:remote:start', xhr);
|
419
|
-
});
|
420
|
-
xhr.addEventListener('error', this.onError);
|
421
|
-
xhr.addEventListener('load', (function(_this) {
|
422
|
-
return function(event) {
|
423
|
-
if (xhr.status < 400) {
|
424
|
-
return _this.onSuccess(event);
|
425
|
-
} else {
|
426
|
-
return _this.onError(event);
|
427
|
-
}
|
428
|
-
};
|
429
|
-
})(this));
|
430
|
-
xhr.addEventListener('loadend', function() {
|
431
|
-
return triggerEvent('turbograft:remote:always', xhr);
|
432
|
-
});
|
433
|
-
xhr.send(formData);
|
434
|
-
return xhr;
|
435
|
-
}
|
436
|
-
|
437
|
-
Remote.prototype.onSuccess = function(ev) {
|
438
|
-
var redirect, xhr;
|
439
|
-
xhr = ev.target;
|
440
|
-
triggerEvent('turbograft:remote:success', xhr);
|
441
|
-
if (redirect = xhr.getResponseHeader('X-Next-Redirect')) {
|
442
|
-
Page.visit(redirect, {
|
443
|
-
reload: true
|
444
|
-
});
|
445
|
-
return;
|
446
|
-
}
|
447
|
-
if (this.opts.fullRefresh) {
|
448
|
-
return Page.refresh({
|
449
|
-
onlyKeys: this.refreshOnSuccess
|
450
|
-
});
|
451
|
-
} else if (this.refreshOnSuccess) {
|
452
|
-
return Page.refresh({
|
453
|
-
response: xhr,
|
454
|
-
onlyKeys: this.refreshOnSuccess
|
455
|
-
});
|
456
|
-
}
|
457
|
-
};
|
458
|
-
|
459
|
-
Remote.prototype.onError = function(ev) {
|
460
|
-
var xhr;
|
461
|
-
xhr = ev.target;
|
462
|
-
triggerEvent('turbograft:remote:fail', xhr);
|
463
|
-
if (this.refreshOnError) {
|
464
|
-
return Page.refresh({
|
465
|
-
response: xhr,
|
466
|
-
onlyKeys: this.refreshOnError
|
467
|
-
});
|
468
|
-
} else {
|
469
|
-
return triggerEvent('turbograft:remote:fail:unhandled', xhr);
|
470
|
-
}
|
471
|
-
};
|
472
|
-
|
473
|
-
return Remote;
|
474
|
-
|
475
|
-
})();
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
},{}],9:[function(require,module,exports){
|
480
|
-
var browserIsntBuggy, browserSupportsCustomEvents, browserSupportsPushState, browserSupportsTurbolinks, historyStateIsDefined, installDocumentReadyPageEventTriggers, installJqueryAjaxSuccessPageUpdateTrigger, popCookie, requestMethodIsSafe, xhr, _ref,
|
481
|
-
__slice = [].slice,
|
482
|
-
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
483
|
-
|
484
|
-
xhr = null;
|
485
|
-
|
486
|
-
installDocumentReadyPageEventTriggers = function() {
|
487
|
-
return document.addEventListener('DOMContentLoaded', (function() {
|
488
|
-
triggerEvent('page:change');
|
489
|
-
return triggerEvent('page:update');
|
490
|
-
}), true);
|
491
|
-
};
|
492
|
-
|
493
|
-
installJqueryAjaxSuccessPageUpdateTrigger = function() {
|
494
|
-
if (typeof jQuery !== 'undefined') {
|
495
|
-
return jQuery(document).on('ajaxSuccess', function(event, xhr, settings) {
|
496
|
-
if (!jQuery.trim(xhr.responseText)) {
|
497
|
-
return;
|
498
|
-
}
|
499
|
-
return triggerEvent('page:update');
|
500
|
-
});
|
501
|
-
}
|
502
|
-
};
|
503
|
-
|
504
|
-
historyStateIsDefined = window.history.state !== void 0 || navigator.userAgent.match(/Firefox\/2[6|7]/);
|
505
|
-
|
506
|
-
browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState && historyStateIsDefined;
|
507
|
-
|
508
|
-
browserIsntBuggy = !navigator.userAgent.match(/CriOS\//);
|
509
|
-
|
510
|
-
window.triggerEvent = function(name, data) {
|
511
|
-
var event;
|
512
|
-
event = document.createEvent('Events');
|
513
|
-
if (data) {
|
514
|
-
event.data = data;
|
515
|
-
}
|
516
|
-
event.initEvent(name, true, true);
|
517
|
-
return document.dispatchEvent(event);
|
518
|
-
};
|
519
|
-
|
520
|
-
popCookie = function(name) {
|
521
|
-
var value, _ref;
|
522
|
-
value = ((_ref = document.cookie.match(new RegExp(name + "=(\\w+)"))) != null ? _ref[1].toUpperCase() : void 0) || '';
|
523
|
-
document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/';
|
524
|
-
return value;
|
525
|
-
};
|
526
|
-
|
527
|
-
requestMethodIsSafe = (_ref = popCookie('request_method')) === 'GET' || _ref === '';
|
528
|
-
|
529
|
-
browserSupportsTurbolinks = browserSupportsPushState && browserIsntBuggy && requestMethodIsSafe;
|
530
|
-
|
531
|
-
browserSupportsCustomEvents = document.addEventListener && document.createEvent;
|
532
|
-
|
533
|
-
if (browserSupportsCustomEvents) {
|
534
|
-
installDocumentReadyPageEventTriggers();
|
535
|
-
installJqueryAjaxSuccessPageUpdateTrigger();
|
536
|
-
}
|
537
|
-
|
538
|
-
window.Turbolinks = (function() {
|
539
|
-
var browserCompatibleDocumentParser, bypassOnLoadPopstate, changePage, createDocument, currentState, deleteRefreshNeverNodes, executeScriptTag, executeScriptTags, extractTitleAndBody, fetch, fetchHistory, fetchReplacement, installHistoryChangeHandler, loadedAssets, pageCache, pageChangePrevented, processResponse, recallScrollPosition, referer, reflectNewUrl, reflectRedirectedUrl, refreshNodesWithKeys, rememberReferer, removeNoscriptTags, resetScrollPosition, transitionCacheFor, usePageCache;
|
540
|
-
|
541
|
-
function Turbolinks() {}
|
542
|
-
|
543
|
-
createDocument = null;
|
544
|
-
|
545
|
-
currentState = null;
|
546
|
-
|
547
|
-
loadedAssets = null;
|
548
|
-
|
549
|
-
referer = null;
|
550
|
-
|
551
|
-
usePageCache = false;
|
552
|
-
|
553
|
-
Turbolinks.pageCache = pageCache = new PageCache();
|
554
|
-
|
555
|
-
fetch = function(url, partialReplace, replaceContents, callback) {
|
556
|
-
var cachedPage;
|
557
|
-
if (partialReplace == null) {
|
558
|
-
partialReplace = false;
|
559
|
-
}
|
560
|
-
if (replaceContents == null) {
|
561
|
-
replaceContents = [];
|
562
|
-
}
|
563
|
-
url = new ComponentUrl(url);
|
564
|
-
rememberReferer();
|
565
|
-
if (usePageCache) {
|
566
|
-
Turbolinks.cacheCurrentPage();
|
567
|
-
}
|
568
|
-
if (usePageCache && (cachedPage = transitionCacheFor(url.absolute))) {
|
569
|
-
fetchHistory(cachedPage);
|
570
|
-
return fetchReplacement(url, partialReplace, null, replaceContents);
|
571
|
-
} else {
|
572
|
-
return fetchReplacement(url, partialReplace, function() {
|
573
|
-
if (!replaceContents.length) {
|
574
|
-
resetScrollPosition();
|
575
|
-
}
|
576
|
-
return typeof callback === "function" ? callback() : void 0;
|
577
|
-
}, replaceContents);
|
578
|
-
}
|
579
|
-
};
|
580
|
-
|
581
|
-
Turbolinks.pageCacheEnabled = function() {
|
582
|
-
return usePageCache;
|
583
|
-
};
|
584
|
-
|
585
|
-
Turbolinks.usePageCache = function(status) {
|
586
|
-
return usePageCache = status;
|
587
|
-
};
|
588
|
-
|
589
|
-
transitionCacheFor = function(url) {
|
590
|
-
var cachedPage;
|
591
|
-
cachedPage = pageCache.get(url);
|
592
|
-
if (cachedPage && !cachedPage.transitionCacheDisabled) {
|
593
|
-
return cachedPage;
|
594
|
-
}
|
595
|
-
};
|
596
|
-
|
597
|
-
Turbolinks.pushState = function(state, title, url) {
|
598
|
-
return window.history.pushState(state, title, url);
|
599
|
-
};
|
600
|
-
|
601
|
-
Turbolinks.replaceState = function(state, title, url) {
|
602
|
-
return window.history.replaceState(state, title, url);
|
603
|
-
};
|
604
|
-
|
605
|
-
fetchReplacement = function(url, partialReplace, onLoadFunction, replaceContents) {
|
606
|
-
triggerEvent('page:fetch', {
|
607
|
-
url: url.absolute
|
608
|
-
});
|
609
|
-
if (xhr != null) {
|
610
|
-
xhr.abort();
|
611
|
-
}
|
612
|
-
xhr = new XMLHttpRequest;
|
613
|
-
xhr.open('GET', url.withoutHashForIE10compatibility(), true);
|
614
|
-
xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
|
615
|
-
xhr.setRequestHeader('X-XHR-Referer', referer);
|
616
|
-
xhr.onload = function() {
|
617
|
-
if (xhr.status >= 500) {
|
618
|
-
return document.location.href = url.absolute;
|
619
|
-
} else {
|
620
|
-
return Turbolinks.loadPage(url, xhr, partialReplace, onLoadFunction, replaceContents);
|
621
|
-
}
|
622
|
-
};
|
623
|
-
xhr.onloadend = function() {
|
624
|
-
return xhr = null;
|
625
|
-
};
|
626
|
-
xhr.onerror = function() {
|
627
|
-
return document.location.href = url.absolute;
|
628
|
-
};
|
629
|
-
xhr.send();
|
630
|
-
};
|
631
|
-
|
632
|
-
Turbolinks.loadPage = function(url, xhr, partialReplace, onLoadFunction, replaceContents) {
|
633
|
-
var doc, nodes;
|
634
|
-
if (partialReplace == null) {
|
635
|
-
partialReplace = false;
|
636
|
-
}
|
637
|
-
if (onLoadFunction == null) {
|
638
|
-
onLoadFunction = (function() {});
|
639
|
-
}
|
640
|
-
if (replaceContents == null) {
|
641
|
-
replaceContents = [];
|
642
|
-
}
|
643
|
-
triggerEvent('page:receive');
|
644
|
-
if (doc = processResponse(xhr, partialReplace)) {
|
645
|
-
reflectNewUrl(url);
|
646
|
-
nodes = changePage.apply(null, __slice.call(extractTitleAndBody(doc)).concat([partialReplace], [replaceContents]));
|
647
|
-
reflectRedirectedUrl(xhr);
|
648
|
-
triggerEvent('page:load', nodes);
|
649
|
-
if (typeof onLoadFunction === "function") {
|
650
|
-
onLoadFunction();
|
651
|
-
}
|
652
|
-
} else {
|
653
|
-
document.location.href = url.absolute;
|
654
|
-
}
|
655
|
-
};
|
656
|
-
|
657
|
-
fetchHistory = function(cachedPage) {
|
658
|
-
if (xhr != null) {
|
659
|
-
xhr.abort();
|
660
|
-
}
|
661
|
-
changePage(cachedPage.title, cachedPage.body, false);
|
662
|
-
recallScrollPosition(cachedPage);
|
663
|
-
return triggerEvent('page:restore');
|
664
|
-
};
|
665
|
-
|
666
|
-
Turbolinks.cacheCurrentPage = function() {
|
667
|
-
var currentStateUrl;
|
668
|
-
currentStateUrl = new ComponentUrl(currentState.url);
|
669
|
-
pageCache.set(currentStateUrl.absolute, {
|
670
|
-
url: currentStateUrl.relative,
|
671
|
-
body: document.body,
|
672
|
-
title: document.title,
|
673
|
-
positionY: window.pageYOffset,
|
674
|
-
positionX: window.pageXOffset,
|
675
|
-
transitionCacheDisabled: document.querySelector('[data-no-transition-cache]') != null
|
676
|
-
});
|
677
|
-
};
|
678
|
-
|
679
|
-
changePage = function(title, body, csrfToken, runScripts, partialReplace, replaceContents) {
|
680
|
-
if (replaceContents == null) {
|
681
|
-
replaceContents = [];
|
682
|
-
}
|
683
|
-
if (title) {
|
684
|
-
document.title = title;
|
685
|
-
}
|
686
|
-
if (replaceContents.length) {
|
687
|
-
return refreshNodesWithKeys(replaceContents, body);
|
688
|
-
} else {
|
689
|
-
deleteRefreshNeverNodes(body);
|
690
|
-
triggerEvent('page:before-replace');
|
691
|
-
document.documentElement.replaceChild(body, document.body);
|
692
|
-
if (csrfToken != null) {
|
693
|
-
CSRFToken.update(csrfToken);
|
694
|
-
}
|
695
|
-
if (runScripts) {
|
696
|
-
executeScriptTags();
|
697
|
-
}
|
698
|
-
currentState = window.history.state;
|
699
|
-
triggerEvent('page:change');
|
700
|
-
triggerEvent('page:update');
|
701
|
-
}
|
702
|
-
};
|
703
|
-
|
704
|
-
deleteRefreshNeverNodes = function(body) {
|
705
|
-
var node, _i, _len, _ref1;
|
706
|
-
_ref1 = body.querySelectorAll('[refresh-never]');
|
707
|
-
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
708
|
-
node = _ref1[_i];
|
709
|
-
node.parentNode.removeChild(node);
|
710
|
-
}
|
711
|
-
};
|
712
|
-
|
713
|
-
refreshNodesWithKeys = function(keys, body) {
|
714
|
-
var allNodesToBeRefreshed, existingNode, key, newNode, node, nodeId, parentIsRefreshing, refreshedNodes, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref1, _ref2;
|
715
|
-
allNodesToBeRefreshed = [];
|
716
|
-
_ref1 = document.querySelectorAll("[refresh-always]");
|
717
|
-
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
718
|
-
node = _ref1[_i];
|
719
|
-
allNodesToBeRefreshed.push(node);
|
720
|
-
}
|
721
|
-
for (_j = 0, _len1 = keys.length; _j < _len1; _j++) {
|
722
|
-
key = keys[_j];
|
723
|
-
_ref2 = document.querySelectorAll("[refresh=" + key + "]");
|
724
|
-
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
725
|
-
node = _ref2[_k];
|
726
|
-
allNodesToBeRefreshed.push(node);
|
727
|
-
}
|
728
|
-
}
|
729
|
-
triggerEvent('page:before-partial-replace', allNodesToBeRefreshed);
|
730
|
-
parentIsRefreshing = function(node) {
|
731
|
-
var potentialParent, _l, _len3;
|
732
|
-
for (_l = 0, _len3 = allNodesToBeRefreshed.length; _l < _len3; _l++) {
|
733
|
-
potentialParent = allNodesToBeRefreshed[_l];
|
734
|
-
if (node !== potentialParent) {
|
735
|
-
if (potentialParent.contains(node)) {
|
736
|
-
return true;
|
737
|
-
}
|
738
|
-
}
|
739
|
-
}
|
740
|
-
return false;
|
741
|
-
};
|
742
|
-
refreshedNodes = [];
|
743
|
-
for (_l = 0, _len3 = allNodesToBeRefreshed.length; _l < _len3; _l++) {
|
744
|
-
existingNode = allNodesToBeRefreshed[_l];
|
745
|
-
if (parentIsRefreshing(existingNode)) {
|
746
|
-
continue;
|
747
|
-
}
|
748
|
-
if (!(nodeId = existingNode.getAttribute('id'))) {
|
749
|
-
throw new Error("Turbolinks refresh: Refresh key elements must have an id.");
|
750
|
-
}
|
751
|
-
if (newNode = body.querySelector("#" + nodeId)) {
|
752
|
-
existingNode.parentNode.replaceChild(newNode, existingNode);
|
753
|
-
if (newNode.nodeName === 'SCRIPT' && newNode.getAttribute("data-turbolinks-eval") !== "false") {
|
754
|
-
executeScriptTag(newNode);
|
755
|
-
} else {
|
756
|
-
refreshedNodes.push(newNode);
|
757
|
-
}
|
758
|
-
} else if (existingNode.getAttribute("refresh-always") === null) {
|
759
|
-
existingNode.parentNode.removeChild(existingNode);
|
760
|
-
}
|
761
|
-
}
|
762
|
-
return refreshedNodes;
|
763
|
-
};
|
764
|
-
|
765
|
-
executeScriptTags = function() {
|
766
|
-
var script, scripts, _i, _len, _ref1;
|
767
|
-
scripts = Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])'));
|
768
|
-
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
|
769
|
-
script = scripts[_i];
|
770
|
-
if ((_ref1 = script.type) === '' || _ref1 === 'text/javascript') {
|
771
|
-
executeScriptTag(script);
|
772
|
-
}
|
773
|
-
}
|
774
|
-
};
|
775
|
-
|
776
|
-
executeScriptTag = function(script) {
|
777
|
-
var attr, copy, nextSibling, parentNode, _i, _len, _ref1;
|
778
|
-
copy = document.createElement('script');
|
779
|
-
_ref1 = script.attributes;
|
780
|
-
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
781
|
-
attr = _ref1[_i];
|
782
|
-
copy.setAttribute(attr.name, attr.value);
|
783
|
-
}
|
784
|
-
copy.appendChild(document.createTextNode(script.innerHTML));
|
785
|
-
parentNode = script.parentNode, nextSibling = script.nextSibling;
|
786
|
-
parentNode.removeChild(script);
|
787
|
-
parentNode.insertBefore(copy, nextSibling);
|
788
|
-
};
|
789
|
-
|
790
|
-
removeNoscriptTags = function(node) {
|
791
|
-
node.innerHTML = node.innerHTML.replace(/<noscript[\S\s]*?<\/noscript>/ig, '');
|
792
|
-
return node;
|
793
|
-
};
|
794
|
-
|
795
|
-
reflectNewUrl = function(url) {
|
796
|
-
if ((url = new ComponentUrl(url)).absolute !== referer) {
|
797
|
-
Turbolinks.pushState({
|
798
|
-
turbolinks: true,
|
799
|
-
url: url.absolute
|
800
|
-
}, '', url.absolute);
|
801
|
-
}
|
802
|
-
};
|
803
|
-
|
804
|
-
reflectRedirectedUrl = function(xhr) {
|
805
|
-
var location, preservedHash;
|
806
|
-
if (location = xhr.getResponseHeader('X-XHR-Redirected-To')) {
|
807
|
-
location = new ComponentUrl(location);
|
808
|
-
preservedHash = location.hasNoHash() ? document.location.hash : '';
|
809
|
-
Turbolinks.replaceState(currentState, '', location.href + preservedHash);
|
810
|
-
}
|
811
|
-
};
|
812
|
-
|
813
|
-
rememberReferer = function() {
|
814
|
-
return referer = document.location.href;
|
815
|
-
};
|
816
|
-
|
817
|
-
Turbolinks.rememberCurrentUrl = function() {
|
818
|
-
return Turbolinks.replaceState({
|
819
|
-
turbolinks: true,
|
820
|
-
url: document.location.href
|
821
|
-
}, '', document.location.href);
|
822
|
-
};
|
823
|
-
|
824
|
-
Turbolinks.rememberCurrentState = function() {
|
825
|
-
return currentState = window.history.state;
|
826
|
-
};
|
827
|
-
|
828
|
-
recallScrollPosition = function(page) {
|
829
|
-
return window.scrollTo(page.positionX, page.positionY);
|
830
|
-
};
|
831
|
-
|
832
|
-
resetScrollPosition = function() {
|
833
|
-
if (document.location.hash) {
|
834
|
-
return document.location.href = document.location.href;
|
835
|
-
} else {
|
836
|
-
return window.scrollTo(0, 0);
|
837
|
-
}
|
838
|
-
};
|
839
|
-
|
840
|
-
pageChangePrevented = function() {
|
841
|
-
return !triggerEvent('page:before-change');
|
842
|
-
};
|
843
|
-
|
844
|
-
processResponse = function(xhr, partial) {
|
845
|
-
var assetsChanged, changed, clientOrServerError, doc, extractTrackAssets, intersection, validContent;
|
846
|
-
if (partial == null) {
|
847
|
-
partial = false;
|
848
|
-
}
|
849
|
-
clientOrServerError = function() {
|
850
|
-
var _ref1;
|
851
|
-
if (xhr.status === 422) {
|
852
|
-
return false;
|
853
|
-
}
|
854
|
-
return (400 <= (_ref1 = xhr.status) && _ref1 < 600);
|
855
|
-
};
|
856
|
-
validContent = function() {
|
857
|
-
return xhr.getResponseHeader('Content-Type').match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/);
|
858
|
-
};
|
859
|
-
extractTrackAssets = function(doc) {
|
860
|
-
var node, _i, _len, _ref1, _results;
|
861
|
-
_ref1 = doc.head.childNodes;
|
862
|
-
_results = [];
|
863
|
-
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
864
|
-
node = _ref1[_i];
|
865
|
-
if ((typeof node.getAttribute === "function" ? node.getAttribute('data-turbolinks-track') : void 0) != null) {
|
866
|
-
_results.push(node.getAttribute('src') || node.getAttribute('href'));
|
867
|
-
}
|
868
|
-
}
|
869
|
-
return _results;
|
870
|
-
};
|
871
|
-
assetsChanged = function(doc) {
|
872
|
-
var fetchedAssets;
|
873
|
-
loadedAssets || (loadedAssets = extractTrackAssets(document));
|
874
|
-
fetchedAssets = extractTrackAssets(doc);
|
875
|
-
return fetchedAssets.length !== loadedAssets.length || intersection(fetchedAssets, loadedAssets).length !== loadedAssets.length;
|
876
|
-
};
|
877
|
-
intersection = function(a, b) {
|
878
|
-
var value, _i, _len, _ref1, _results;
|
879
|
-
if (a.length > b.length) {
|
880
|
-
_ref1 = [b, a], a = _ref1[0], b = _ref1[1];
|
881
|
-
}
|
882
|
-
_results = [];
|
883
|
-
for (_i = 0, _len = a.length; _i < _len; _i++) {
|
884
|
-
value = a[_i];
|
885
|
-
if (__indexOf.call(b, value) >= 0) {
|
886
|
-
_results.push(value);
|
887
|
-
}
|
888
|
-
}
|
889
|
-
return _results;
|
890
|
-
};
|
891
|
-
if (!clientOrServerError() && validContent()) {
|
892
|
-
doc = createDocument(xhr.responseText);
|
893
|
-
changed = assetsChanged(doc);
|
894
|
-
if (doc && (!changed || partial)) {
|
895
|
-
return doc;
|
896
|
-
}
|
897
|
-
}
|
898
|
-
};
|
899
|
-
|
900
|
-
extractTitleAndBody = function(doc) {
|
901
|
-
var title;
|
902
|
-
title = doc.querySelector('title');
|
903
|
-
return [title != null ? title.textContent : void 0, removeNoscriptTags(doc.body), CSRFToken.get(doc).token, 'runScripts'];
|
904
|
-
};
|
905
|
-
|
906
|
-
installHistoryChangeHandler = function(event) {
|
907
|
-
var cachedPage, _ref1;
|
908
|
-
if ((_ref1 = event.state) != null ? _ref1.turbolinks : void 0) {
|
909
|
-
if (cachedPage = pageCache.get((new ComponentUrl(event.state.url)).absolute)) {
|
910
|
-
Turbolinks.cacheCurrentPage();
|
911
|
-
return fetchHistory(cachedPage);
|
912
|
-
} else {
|
913
|
-
return Turbolinks.visit(event.target.location.href);
|
914
|
-
}
|
915
|
-
}
|
916
|
-
};
|
917
|
-
|
918
|
-
bypassOnLoadPopstate = function(fn) {
|
919
|
-
return setTimeout(fn, 500);
|
920
|
-
};
|
921
|
-
|
922
|
-
browserCompatibleDocumentParser = function() {
|
923
|
-
var createDocumentUsingDOM, createDocumentUsingParser, createDocumentUsingWrite, e, testDoc, _ref1;
|
924
|
-
createDocumentUsingParser = function(html) {
|
925
|
-
return (new DOMParser).parseFromString(html, 'text/html');
|
926
|
-
};
|
927
|
-
createDocumentUsingDOM = function(html) {
|
928
|
-
var doc;
|
929
|
-
doc = document.implementation.createHTMLDocument('');
|
930
|
-
doc.documentElement.innerHTML = html;
|
931
|
-
return doc;
|
932
|
-
};
|
933
|
-
createDocumentUsingWrite = function(html) {
|
934
|
-
var doc;
|
935
|
-
doc = document.implementation.createHTMLDocument('');
|
936
|
-
doc.open('replace');
|
937
|
-
doc.write(html);
|
938
|
-
doc.close();
|
939
|
-
return doc;
|
940
|
-
};
|
941
|
-
try {
|
942
|
-
if (window.DOMParser) {
|
943
|
-
testDoc = createDocumentUsingParser('<html><body><p>test');
|
944
|
-
return createDocumentUsingParser;
|
945
|
-
}
|
946
|
-
} catch (_error) {
|
947
|
-
e = _error;
|
948
|
-
testDoc = createDocumentUsingDOM('<html><body><p>test');
|
949
|
-
return createDocumentUsingDOM;
|
950
|
-
} finally {
|
951
|
-
if ((testDoc != null ? (_ref1 = testDoc.body) != null ? _ref1.childNodes.length : void 0 : void 0) !== 1) {
|
952
|
-
return createDocumentUsingWrite;
|
953
|
-
}
|
954
|
-
}
|
955
|
-
};
|
956
|
-
|
957
|
-
if (browserSupportsTurbolinks) {
|
958
|
-
Turbolinks.visit = fetch;
|
959
|
-
Turbolinks.rememberCurrentUrl();
|
960
|
-
Turbolinks.rememberCurrentState();
|
961
|
-
createDocument = browserCompatibleDocumentParser();
|
962
|
-
document.addEventListener('click', Click.installHandlerLast, true);
|
963
|
-
bypassOnLoadPopstate(function() {
|
964
|
-
return window.addEventListener('popstate', installHistoryChangeHandler, false);
|
965
|
-
});
|
966
|
-
} else {
|
967
|
-
Turbolinks.visit = function(url) {
|
968
|
-
return document.location.href = url;
|
969
|
-
};
|
970
|
-
}
|
971
|
-
|
972
|
-
return Turbolinks;
|
973
|
-
|
974
|
-
})();
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
},{}]},{},[1,2,3,5,6,7,9,4,8]);
|