render_async 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +125 -14
- data/app/views/render_async/_render_async.html.erb +27 -9
- data/app/views/render_async/_request_jquery.js.erb +45 -0
- data/app/views/render_async/_request_vanilla.js.erb +56 -0
- data/lib/render_async.rb +19 -0
- data/lib/render_async/configuration.rb +9 -0
- data/lib/render_async/version.rb +1 -1
- data/lib/render_async/view_helper.rb +13 -2
- metadata +4 -2
- data/app/views/render_async/_request.js.erb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 301c0dec3cac35c32dd7946334151d2c968fe8f182006b1e67e4fc21655e1899
|
4
|
+
data.tar.gz: 0df8c63b19c81621726efb95c993377caa81c554ba29d29d782451f5a4116d21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 261185dde786cf96d86e1d9abb5e9d67d0b0b431786adb4459f3f230621d55e34ebd89ed98950f27fb0541af355c26150ef766bae254e3ea28d7367f504ce388
|
7
|
+
data.tar.gz: 6af545d420676f1a39c98fe43dda6c63f66c8d944faab86ed57f4912dfc65243b6e350a538156389d5ed7e3ae63a579c28cd1a4161597bb09d504c79c9b93dfa
|
data/README.md
CHANGED
@@ -26,11 +26,10 @@ JavaScript is injected into `<%= content_for :render_async %>` so you choose
|
|
26
26
|
where to put it.
|
27
27
|
|
28
28
|
## Installation
|
29
|
-
S
|
30
29
|
Add this line to your application's Gemfile:
|
31
30
|
|
32
31
|
```ruby
|
33
|
-
gem '
|
32
|
+
gem 'render_async'
|
34
33
|
```
|
35
34
|
|
36
35
|
And then execute:
|
@@ -46,7 +45,7 @@ And then execute:
|
|
46
45
|
|
47
46
|
2. Then create a route that will `config/routes.rb`:
|
48
47
|
```ruby
|
49
|
-
get :comment_stats, :
|
48
|
+
get :comment_stats, controller: :comments
|
50
49
|
```
|
51
50
|
|
52
51
|
3. Fill in the logic in your controller (e.g. `app/controllers/comments_controller.rb`):
|
@@ -54,7 +53,7 @@ And then execute:
|
|
54
53
|
def comment_stats
|
55
54
|
@stats = Comment.get_stats
|
56
55
|
|
57
|
-
render :
|
56
|
+
render partial: "comment_stats"
|
58
57
|
end
|
59
58
|
```
|
60
59
|
|
@@ -74,23 +73,62 @@ And then execute:
|
|
74
73
|
|
75
74
|
Advanced usage includes information on different options, such as:
|
76
75
|
|
76
|
+
- [Passing in a container ID](#passing-in-a-container-id)
|
77
|
+
- [Passing in a container class name](#passing-in-a-container-class-name)
|
77
78
|
- [Passing in HTML options](#passing-in-html-options)
|
78
79
|
- [Passing in an HTML element name](#passing-in-an-html-element-name)
|
79
80
|
- [Passing in a placeholder](#passing-in-a-placeholder)
|
80
81
|
- [Passing in an event name](#passing-in-an-event-name)
|
82
|
+
- [Handling errors](#handling-errors)
|
81
83
|
- [Caching](#caching)
|
84
|
+
- [Doing non-GET requests](#doing-non-get-requests)
|
82
85
|
- [Using with Turbolinks](#using-with-turbolinks)
|
83
86
|
- [Using with respond_to and JS format](#using-with-respond_to-and-js-format)
|
84
87
|
- [Nested Async Renders](#nested-async-renders)
|
88
|
+
- [Configuration](#configuration)
|
85
89
|
|
86
|
-
### Passing in
|
90
|
+
### Passing in a container ID
|
91
|
+
|
92
|
+
`render_async` renders an element that gets replaced with the content
|
93
|
+
of your request response. In order to have more control over the element
|
94
|
+
that renders first (before the request), you can set the ID of that element.
|
95
|
+
|
96
|
+
To set ID of the container element, you can do the following:
|
97
|
+
```erb
|
98
|
+
<%= render_async users_path, container_id: 'users-container' %>
|
99
|
+
```
|
100
|
+
|
101
|
+
Rendered code in the view:
|
102
|
+
```html
|
103
|
+
<div id="users-container">
|
104
|
+
</div>
|
105
|
+
|
106
|
+
...
|
107
|
+
```
|
108
|
+
|
109
|
+
### Passing in a container class name
|
87
110
|
|
88
|
-
`render_async`
|
111
|
+
`render_async` renders an element that gets replaced with the content of your
|
112
|
+
request response. If you want to style that element, you can set the class name
|
113
|
+
on it.
|
114
|
+
|
115
|
+
```erb
|
116
|
+
<%= render_async users_path, container_class: 'users-container-class' %>
|
117
|
+
```
|
118
|
+
|
119
|
+
Rendered code in the view:
|
120
|
+
```html
|
121
|
+
<div id="render_async_18b8a6cd161499117471" class="users-container-class">
|
122
|
+
</div>
|
123
|
+
|
124
|
+
...
|
125
|
+
```
|
126
|
+
|
127
|
+
### Passing in HTML options
|
89
128
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
`javascript_tag`, to drop html tags into the `script` element.
|
129
|
+
`render_async` can accept `html_options` argument.
|
130
|
+
`html_options` is an optional hash that gets passed to a Rails'
|
131
|
+
`javascript_tag`, to drop HTML tags into the `script` element.
|
94
132
|
|
95
133
|
Example of utilizing `html_options` with a `nonce`:
|
96
134
|
```erb
|
@@ -168,7 +206,7 @@ after your partial is loaded through `render_async`.
|
|
168
206
|
|
169
207
|
Example of passing it to `render_async`:
|
170
208
|
```erb
|
171
|
-
<%= render_async users_path, :
|
209
|
+
<%= render_async users_path, event_name: "users-loaded" %>
|
172
210
|
```
|
173
211
|
|
174
212
|
Rendered code in view:
|
@@ -192,6 +230,38 @@ document.addEventListener("users-loaded", function() {
|
|
192
230
|
});
|
193
231
|
```
|
194
232
|
|
233
|
+
NOTE: Dispatching events is also supported for older browsers that don't
|
234
|
+
support Event constructor.
|
235
|
+
|
236
|
+
### Handling errors
|
237
|
+
|
238
|
+
`render_async` let's you handle errors by allowing you to pass in `error_message`
|
239
|
+
and `error_event_name`.
|
240
|
+
|
241
|
+
- `error_message`
|
242
|
+
|
243
|
+
passing an `error_message` will render a message if the AJAX requests fails for
|
244
|
+
some reason
|
245
|
+
```erb
|
246
|
+
<%= render_async users_path,
|
247
|
+
error_message: '<p>Sorry, users loading went wrong :(</p>' %>
|
248
|
+
```
|
249
|
+
|
250
|
+
- `error_event_name`
|
251
|
+
|
252
|
+
calling `render_async` with `error_event_name` will dispatch event in the case
|
253
|
+
of an error with your AJAX call.
|
254
|
+
```erb
|
255
|
+
<%= render_asyc users_path, error_event_name: 'users-error-event' %>
|
256
|
+
```
|
257
|
+
|
258
|
+
You can then catch the event in your code with:
|
259
|
+
```js
|
260
|
+
document.addEventListener('users-error-event', function() {
|
261
|
+
// I'm on it
|
262
|
+
})
|
263
|
+
```
|
264
|
+
|
195
265
|
### Caching
|
196
266
|
|
197
267
|
`render_async` can utilize view fragment caching to avoid extra AJAX calls.
|
@@ -204,7 +274,7 @@ In your views (e.g. `app/views/comments/show.html.erb`):
|
|
204
274
|
|
205
275
|
Then, in the partial (e.g. `app/views/comments/_comment_stats.html.erb`):
|
206
276
|
```erb
|
207
|
-
<% cache render_async_cache_key(request.path), :
|
277
|
+
<% cache render_async_cache_key(request.path), skip_digest: true do %>
|
208
278
|
<div class="col-md-6">
|
209
279
|
<%= @stats %>
|
210
280
|
</div>
|
@@ -217,6 +287,25 @@ Then, in the partial (e.g. `app/views/comments/_comment_stats.html.erb`):
|
|
217
287
|
* You can expire cache simply by passing `:expires_in` in your view where
|
218
288
|
you cache the partial
|
219
289
|
|
290
|
+
### Doing non-GET requests
|
291
|
+
|
292
|
+
By default, `render_async` creates AJAX GET requests for the path you provide.
|
293
|
+
If you want to change this behaviour, you can pass in a `method` argument to
|
294
|
+
`render_async` view helper.
|
295
|
+
|
296
|
+
```erb
|
297
|
+
<%= render_async users_path, method: 'POST' %>
|
298
|
+
```
|
299
|
+
|
300
|
+
You can also set `body` and `headers` of the request if you need them.
|
301
|
+
|
302
|
+
```erb
|
303
|
+
<%= render_async users_path,
|
304
|
+
method: 'POST',
|
305
|
+
data: { fresh: 'AF' },
|
306
|
+
headers: { 'Content-Type': 'text' } %>
|
307
|
+
```
|
308
|
+
|
220
309
|
### Using with Turbolinks
|
221
310
|
|
222
311
|
On Turbolinks applications, you may experience caching issues when navigating
|
@@ -243,7 +332,7 @@ def comment_stats
|
|
243
332
|
format.js do
|
244
333
|
@stats = Comment.get_stats
|
245
334
|
|
246
|
-
render :
|
335
|
+
render partial: "comment_stats"
|
247
336
|
end
|
248
337
|
end
|
249
338
|
end
|
@@ -257,7 +346,7 @@ You can get around it by specifying the content type to `text/html` in the
|
|
257
346
|
render call:
|
258
347
|
|
259
348
|
```ruby
|
260
|
-
render :
|
349
|
+
render partial: "comment_stats", content_type: 'text/html'
|
261
350
|
```
|
262
351
|
|
263
352
|
### Nested Async Renders
|
@@ -287,6 +376,28 @@ For example:
|
|
287
376
|
<%= content_for :render_async %>
|
288
377
|
```
|
289
378
|
|
379
|
+
### Configuration
|
380
|
+
|
381
|
+
`render_async` renders Vanilla JS (regular JavaScript, non-jQuery code)
|
382
|
+
**by default** in order to fetch the request from the server.
|
383
|
+
|
384
|
+
If you want `render_async` to use jQuery code, you need to configure it to do
|
385
|
+
so.
|
386
|
+
|
387
|
+
You can configure it by doing the following anywhere before you call
|
388
|
+
`render_async`:
|
389
|
+
```rb
|
390
|
+
RenderAsync.configure do |config|
|
391
|
+
jquery = true # This will render jQuery code, and skip Vanilla JS code
|
392
|
+
end
|
393
|
+
```
|
394
|
+
|
395
|
+
Also, you can do it like this:
|
396
|
+
```rb
|
397
|
+
# This will render jQuery code, and skip Vanilla JS code
|
398
|
+
RenderAsync.configuration.jquery = true
|
399
|
+
```
|
400
|
+
|
290
401
|
## Development
|
291
402
|
|
292
403
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
@@ -1,16 +1,34 @@
|
|
1
|
-
<<%= html_element_name %>
|
1
|
+
<<%= html_element_name %>
|
2
|
+
id="<%= container_id %>"
|
3
|
+
class="<%= container_class %>"
|
4
|
+
>
|
2
5
|
<%= placeholder %>
|
3
6
|
</<%= html_element_name %>>
|
4
7
|
|
5
8
|
<% content_for :render_async do %>
|
6
9
|
<%= javascript_tag html_options do %>
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
<% if RenderAsync.configuration.jquery %>
|
11
|
+
<%= render partial: 'render_async/request_jquery',
|
12
|
+
formats: [:js],
|
13
|
+
locals: { container_id: container_id,
|
14
|
+
path: path,
|
15
|
+
method: method,
|
16
|
+
data: data,
|
17
|
+
event_name: event_name,
|
18
|
+
headers: headers,
|
19
|
+
error_message: error_message,
|
20
|
+
error_event_name: error_event_name } %>
|
21
|
+
<% else %>
|
22
|
+
<%= render partial: 'render_async/request_vanilla',
|
23
|
+
formats: [:js],
|
24
|
+
locals: { container_id: container_id,
|
25
|
+
path: path,
|
26
|
+
method: method,
|
27
|
+
data: data,
|
28
|
+
event_name: event_name,
|
29
|
+
headers: headers,
|
30
|
+
error_message: error_message,
|
31
|
+
error_event_name: error_event_name } %>
|
32
|
+
<% end %>
|
15
33
|
<% end %>
|
16
34
|
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
if (window.jQuery) {
|
2
|
+
(function($) {
|
3
|
+
$(document).ready(function() {
|
4
|
+
var headers = <%= headers.to_json.html_safe %>;
|
5
|
+
var csrfTokenElement = document.querySelector('meta[name="csrf-token"]')
|
6
|
+
if (csrfTokenElement)
|
7
|
+
headers['X-CSRF-Token'] = csrfTokenElement.content
|
8
|
+
|
9
|
+
$.ajax({
|
10
|
+
url: '<%= path.html_safe %>',
|
11
|
+
method: '<%= method %>',
|
12
|
+
data: "<%= escape_javascript(data.to_s.html_safe) %>",
|
13
|
+
headers: headers
|
14
|
+
}).done(function(response) {
|
15
|
+
$("#<%= container_id %>").replaceWith(response);
|
16
|
+
|
17
|
+
<% if event_name.present? %>
|
18
|
+
var event = undefined;
|
19
|
+
if (typeof(Event) === 'function') {
|
20
|
+
event = new Event("<%= event_name %>");
|
21
|
+
} else {
|
22
|
+
event = document.createEvent('Event');
|
23
|
+
event.initEvent('<%= event_name %>', true, true);
|
24
|
+
}
|
25
|
+
document.dispatchEvent(event);
|
26
|
+
<% end %>
|
27
|
+
}).error(function(response) {
|
28
|
+
$("#<%= container_id %>").replaceWith('<%= error_message.try(:html_safe) %>');
|
29
|
+
|
30
|
+
<% if error_event_name.present? %>
|
31
|
+
var event = undefined;
|
32
|
+
if (typeof(Event) === 'function') {
|
33
|
+
event = new Event("<%= error_event_name %>");
|
34
|
+
} else {
|
35
|
+
event = document.createEvent('Event');
|
36
|
+
event.initEvent('<%= error_event_name %>', true, true);
|
37
|
+
}
|
38
|
+
document.dispatchEvent(event);
|
39
|
+
<% end %>
|
40
|
+
});
|
41
|
+
});
|
42
|
+
}(jQuery));
|
43
|
+
} else {
|
44
|
+
console.warn("Looks like you've enabled jQuery for render_async, but jQuery is not defined");
|
45
|
+
};
|
@@ -0,0 +1,56 @@
|
|
1
|
+
(function() {
|
2
|
+
document.addEventListener("DOMContentLoaded", function() {
|
3
|
+
var request = new XMLHttpRequest();
|
4
|
+
var asyncRequest = true;
|
5
|
+
var SUCCESS = 200;
|
6
|
+
var ERROR = 400;
|
7
|
+
|
8
|
+
request.open('<%= method %>', '<%= path.html_safe %>', asyncRequest);
|
9
|
+
|
10
|
+
var headers = <%= headers.to_json.html_safe %>;
|
11
|
+
var csrfTokenElement = document.querySelector('meta[name="csrf-token"]')
|
12
|
+
if (csrfTokenElement)
|
13
|
+
headers['X-CSRF-Token'] = csrfTokenElement.content
|
14
|
+
|
15
|
+
Object.keys(headers).map(function(key) {
|
16
|
+
request.setRequestHeader(key, headers[key]);
|
17
|
+
});
|
18
|
+
|
19
|
+
request.onreadystatechange = function() {
|
20
|
+
if (request.readyState === 4) {
|
21
|
+
if (request.status >= SUCCESS && request.status < ERROR) {
|
22
|
+
var container = document.getElementById('<%= container_id %>');
|
23
|
+
container.outerHTML = request.response;
|
24
|
+
|
25
|
+
<% if event_name.present? %>
|
26
|
+
var event = undefined;
|
27
|
+
if (typeof(Event) === 'function') {
|
28
|
+
event = new Event("<%= event_name %>");
|
29
|
+
} else {
|
30
|
+
event = document.createEvent('Event');
|
31
|
+
event.initEvent('<%= event_name %>', true, true);
|
32
|
+
}
|
33
|
+
document.dispatchEvent(event);
|
34
|
+
<% end %>
|
35
|
+
} else {
|
36
|
+
var container = document.getElementById('<%= container_id %>');
|
37
|
+
container.outerHTML = '<%= error_message.try(:html_safe) %>';
|
38
|
+
|
39
|
+
<% if error_event_name.present? %>
|
40
|
+
var event = undefined;
|
41
|
+
if (typeof(Event) === 'function') {
|
42
|
+
event = new Event("<%= error_event_name %>");
|
43
|
+
} else {
|
44
|
+
event = document.createEvent('Event');
|
45
|
+
event.initEvent('<%= error_event_name %>', true, true);
|
46
|
+
}
|
47
|
+
document.dispatchEvent(event);
|
48
|
+
<% end %>
|
49
|
+
}
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
var body = "<%= escape_javascript(data.to_s.html_safe) %>";
|
54
|
+
request.send(body);
|
55
|
+
});
|
56
|
+
})();
|
data/lib/render_async.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
require "render_async/version"
|
2
2
|
require "render_async/view_helper"
|
3
3
|
require "render_async/engine" if defined? Rails
|
4
|
+
require "render_async/configuration"
|
4
5
|
|
5
6
|
ActionView::Base.send :include, RenderAsync::ViewHelper if defined? ActionView::Base
|
7
|
+
|
8
|
+
module RenderAsync
|
9
|
+
class << self
|
10
|
+
attr_accessor :configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.configuration
|
14
|
+
@configuration ||= RenderAsync::Configuration.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.reset
|
18
|
+
@configuration = RenderAsync::Configuration.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.configure
|
22
|
+
yield(configuration)
|
23
|
+
end
|
24
|
+
end
|
data/lib/render_async/version.rb
CHANGED
@@ -19,23 +19,34 @@ module RenderAsync
|
|
19
19
|
|
20
20
|
def render_async(path, options = {}, &placeholder)
|
21
21
|
html_element_name = options.delete(:html_element_name) || 'div'
|
22
|
-
container_id =
|
22
|
+
container_id = options.delete(:container_id) || generate_container_id
|
23
|
+
container_class = options.delete(:container_class)
|
23
24
|
event_name = options.delete(:event_name)
|
24
25
|
placeholder = capture(&placeholder) if block_given?
|
25
26
|
method = options.delete(:method) || 'GET'
|
26
27
|
data = options.delete(:data)
|
27
28
|
headers = options.delete(:headers) || {}
|
29
|
+
error_message = options.delete(:error_message)
|
30
|
+
error_event_name = options.delete(:error_event_name)
|
28
31
|
|
29
32
|
render 'render_async/render_async', html_element_name: html_element_name,
|
30
33
|
container_id: container_id,
|
34
|
+
container_class: container_class,
|
31
35
|
path: path,
|
32
36
|
html_options: options,
|
33
37
|
event_name: event_name,
|
34
38
|
placeholder: placeholder,
|
35
39
|
method: method,
|
36
40
|
data: data,
|
37
|
-
headers: headers
|
41
|
+
headers: headers,
|
42
|
+
error_message: error_message,
|
43
|
+
error_event_name: error_event_name
|
38
44
|
end
|
39
45
|
|
46
|
+
private
|
47
|
+
|
48
|
+
def generate_container_id
|
49
|
+
"render_async_#{SecureRandom.hex(5)}#{Time.now.to_i}"
|
50
|
+
end
|
40
51
|
end
|
41
52
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: render_async
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kasper Grubbe
|
@@ -83,11 +83,13 @@ files:
|
|
83
83
|
- README.md
|
84
84
|
- Rakefile
|
85
85
|
- app/views/render_async/_render_async.html.erb
|
86
|
-
- app/views/render_async/
|
86
|
+
- app/views/render_async/_request_jquery.js.erb
|
87
|
+
- app/views/render_async/_request_vanilla.js.erb
|
87
88
|
- bin/console
|
88
89
|
- bin/integration-tests
|
89
90
|
- bin/setup
|
90
91
|
- lib/render_async.rb
|
92
|
+
- lib/render_async/configuration.rb
|
91
93
|
- lib/render_async/engine.rb
|
92
94
|
- lib/render_async/version.rb
|
93
95
|
- lib/render_async/view_helper.rb
|
@@ -1,57 +0,0 @@
|
|
1
|
-
if (window.jQuery) {
|
2
|
-
(function($) {
|
3
|
-
$(document).ready(function() {
|
4
|
-
var headers = <%= headers.to_json.html_safe %>;
|
5
|
-
var csrfTokenElement = document.querySelector('meta[name="csrf-token"]')
|
6
|
-
if (csrfTokenElement)
|
7
|
-
headers['X-CSRF-Token'] = csrfTokenElement.content
|
8
|
-
|
9
|
-
$.ajax({
|
10
|
-
url: '<%= path.html_safe %>',
|
11
|
-
method: '<%= method %>',
|
12
|
-
data: "<%= escape_javascript(data.to_s.html_safe) %>",
|
13
|
-
headers: headers
|
14
|
-
}).always(function(response) {
|
15
|
-
$("#<%= container_id %>").replaceWith(response);
|
16
|
-
|
17
|
-
<% if event_name.present? %>
|
18
|
-
document.dispatchEvent(new Event("<%= event_name %>"));
|
19
|
-
<% end %>
|
20
|
-
});
|
21
|
-
});
|
22
|
-
}(jQuery));
|
23
|
-
} else {
|
24
|
-
(function() {
|
25
|
-
document.addEventListener("DOMContentLoaded", function() {
|
26
|
-
var request = new XMLHttpRequest();
|
27
|
-
var asyncRequest = true;
|
28
|
-
var SUCCESS = 200;
|
29
|
-
var ERROR = 400;
|
30
|
-
|
31
|
-
request.open('<%= method %>', '<%= path.html_safe %>', asyncRequest);
|
32
|
-
|
33
|
-
var headers = <%= headers.to_json.html_safe %>;
|
34
|
-
var csrfTokenElement = document.querySelector('meta[name="csrf-token"]')
|
35
|
-
if (csrfTokenElement)
|
36
|
-
headers['X-CSRF-Token'] = csrfTokenElement.content
|
37
|
-
|
38
|
-
Object.keys(headers).map(function(key) {
|
39
|
-
request.setRequestHeader(key, headers[key]);
|
40
|
-
});
|
41
|
-
|
42
|
-
request.onload = function() {
|
43
|
-
if (request.status >= SUCCESS && request.status < ERROR) {
|
44
|
-
var container = document.getElementById('<%= container_id %>');
|
45
|
-
container.outerHTML = request.response;
|
46
|
-
|
47
|
-
<% if event_name.present? %>
|
48
|
-
document.dispatchEvent(new Event("<%= event_name %>"));
|
49
|
-
<% end %>
|
50
|
-
}
|
51
|
-
};
|
52
|
-
|
53
|
-
var body = "<%= escape_javascript(data.to_s.html_safe) %>";
|
54
|
-
request.send(body);
|
55
|
-
});
|
56
|
-
})();
|
57
|
-
}
|