turbograft 0.1.20 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3a2afc7a9635bccddb3fa74d3fa6d0006496f825
4
- data.tar.gz: 4e6d65bf91ed1f62768eaad503646cc66f4ad2b1
3
+ metadata.gz: 7c5cd11ad075c764ef8376a3e89011fd8a42c85b
4
+ data.tar.gz: b8958bb7aea77497657f90dc1e0885512f073c90
5
5
  SHA512:
6
- metadata.gz: 86ca1f4af9f69cf573e6eec31aae7436fe277e3d5714ef789ae4e17abe2a0a48b332d0bf16995b90951f1444934c6e717d62a459e4ff5b330d4af1e3125a8df6
7
- data.tar.gz: 4f02bc5496e36f9f532c8b062de695b17783601ca0f21ab712bad70d9e1e866fb3b53c7f246ead4f69ccf542e6d31c9df0371ac29bc07c4ab780000613be3585
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". This is the lowest-level way to use TurboGraft.
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: "page" %>
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, urlAttribute, form = null) ->
8
- httpUrl = target.getAttribute(urlAttribute)
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 target.getAttribute("remote-once")
13
- target.removeAttribute("remote-once")
14
- target.removeAttribute("tg-remote")
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: target.getAttribute('full-refresh')?
20
- refreshOnSuccess: target.getAttribute('refresh-on-success')
21
- refreshOnSuccessExcept: target.getAttribute('full-refresh-on-success-except')
22
- refreshOnError: target.getAttribute('refresh-on-error')
23
- refreshOnErrorExcept: target.getAttribute('full-refresh-on-error-except')
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 = target.getAttribute('tg-remote')
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, 'href')
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 target.getAttribute('tg-remote')?
42
+ return unless TurboGraft.hasTGAttribute(target, 'tg-remote')
43
43
  ev.preventDefault()
44
44
 
45
- remote = setupRemoteFromTarget(target, method, 'action', target)
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(form.querySelectorAll("[tg-remote-noserialize]"))
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.hasAttribute('tg-remote-norefresh')
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 document.querySelectorAll("[refresh=#{key}]")
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 document.querySelectorAll("[refresh-always]")
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 body.querySelectorAll('[refresh-never]')
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 existingNode.getAttribute("refresh-always") == null
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 = document.querySelectorAll("[tg-static]")
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 document.querySelectorAll("[refresh=#{key}]")
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}]")
@@ -1,3 +1,3 @@
1
1
  module TurboGraft
2
- VERSION = '0.1.20'
2
+ VERSION = '0.2.0'
3
3
  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.1.20
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-10-27 00:00:00.000000000 Z
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.2.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]);