crazy_render 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.all-contributorsrc +155 -0
- data/.gitignore +17 -0
- data/.gitmodules +4 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +107 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +481 -0
- data/Rakefile +6 -0
- data/app/views/render_async/_render_async.html.erb +40 -0
- data/app/views/render_async/_request_jquery.js.erb +90 -0
- data/app/views/render_async/_request_vanilla.js.erb +103 -0
- data/bin/console +14 -0
- data/bin/integration-tests +13 -0
- data/bin/setup +8 -0
- data/lib/render_async/configuration.rb +10 -0
- data/lib/render_async/engine.rb +5 -0
- data/lib/render_async/version.rb +3 -0
- data/lib/render_async/view_helper.rb +56 -0
- data/lib/render_async.rb +24 -0
- data/render_async.gemspec +27 -0
- metadata +108 -0
data/README.md
ADDED
@@ -0,0 +1,481 @@
|
|
1
|
+
[![Build Status](https://semaphoreci.com/api/v1/renderedtext/render_async/branches/master/shields_badge.svg)](https://semaphoreci.com/renderedtext/render_async)
|
2
|
+
[![All Contributors](https://img.shields.io/badge/all_contributors-15-orange.svg?style=flat-square)](#contributors)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/render_async.svg)](https://badge.fury.io/rb/render_async)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/renderedtext/render_async/badges/gpa.svg)](https://codeclimate.com/github/renderedtext/render_async)
|
5
|
+
[![Test Coverage](https://codeclimate.com/github/renderedtext/render_async/badges/coverage.svg)](https://codeclimate.com/github/renderedtext/render_async/coverage)
|
6
|
+
[![Help Contribute to Open Source](https://www.codetriage.com/renderedtext/render_async/badges/users.svg)](https://www.codetriage.com/renderedtext/render_async)
|
7
|
+
|
8
|
+
![render_async](http://s2blog.wpengine.com/wp-content/uploads/assets/images/2017-06-08/speed-up-rendering-rails-pages-with-render-async.png)
|
9
|
+
|
10
|
+
# render_async
|
11
|
+
|
12
|
+
Speed up rendering Rails pages with this gem.
|
13
|
+
|
14
|
+
`render_async` renders partials to your views **asynchronously**. This is done
|
15
|
+
through adding JavaScript code that does AJAX request to your controller which
|
16
|
+
then renders your partial into a Rails view.
|
17
|
+
|
18
|
+
Workflow:
|
19
|
+
|
20
|
+
1. user visits a Rails page
|
21
|
+
2. AJAX request on the controller action
|
22
|
+
3. controller renders a partial
|
23
|
+
4. partials renders in the place where you put `render_async` helper
|
24
|
+
|
25
|
+
JavaScript is injected into `<%= content_for :render_async %>` so you choose
|
26
|
+
where to put it.
|
27
|
+
|
28
|
+
## Installation
|
29
|
+
Add this line to your application's Gemfile:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
gem 'render_async'
|
33
|
+
```
|
34
|
+
|
35
|
+
And then execute:
|
36
|
+
|
37
|
+
$ bundle install
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
1. Include `render_async` view helper somewhere in your views (e.g. `app/views/comments/show.html.erb`):
|
42
|
+
```erb
|
43
|
+
<%= render_async comment_stats_path %>
|
44
|
+
```
|
45
|
+
|
46
|
+
2. Then create a route that will `config/routes.rb`:
|
47
|
+
```ruby
|
48
|
+
get :comment_stats, controller: :comments
|
49
|
+
```
|
50
|
+
|
51
|
+
3. Fill in the logic in your controller (e.g. `app/controllers/comments_controller.rb`):
|
52
|
+
```ruby
|
53
|
+
def comment_stats
|
54
|
+
@stats = Comment.get_stats
|
55
|
+
|
56
|
+
render partial: "comment_stats"
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
4. Create a partial that will render (e.g. `app/views/comments/_comment_stats.html.erb`):
|
61
|
+
```erb
|
62
|
+
<div class="col-md-6">
|
63
|
+
<%= @stats %>
|
64
|
+
</div>
|
65
|
+
```
|
66
|
+
|
67
|
+
5. Add `content_for` in your base view file in the body part (e.g. `app/views/layouts/application.html.erb`):
|
68
|
+
```erb
|
69
|
+
<%= content_for :render_async %>
|
70
|
+
```
|
71
|
+
|
72
|
+
## Advanced usage
|
73
|
+
|
74
|
+
Advanced usage includes information on different options, such as:
|
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)
|
78
|
+
- [Passing in HTML options](#passing-in-html-options)
|
79
|
+
- [Passing in an HTML element name](#passing-in-an-html-element-name)
|
80
|
+
- [Passing in a placeholder](#passing-in-a-placeholder)
|
81
|
+
- [Passing in an event name](#passing-in-an-event-name)
|
82
|
+
- [Retry on failure](#retry-on-failure)
|
83
|
+
- [Polling](#polling)
|
84
|
+
- [Handling errors](#handling-errors)
|
85
|
+
- [Caching](#caching)
|
86
|
+
- [Doing non-GET requests](#doing-non-get-requests)
|
87
|
+
- [Using with Turbolinks](#using-with-turbolinks)
|
88
|
+
- [Using with respond_to and JS format](#using-with-respond_to-and-js-format)
|
89
|
+
- [Nested Async Renders](#nested-async-renders)
|
90
|
+
- [Configuration](#configuration)
|
91
|
+
|
92
|
+
### Passing in a container ID
|
93
|
+
|
94
|
+
`render_async` renders an element that gets replaced with the content
|
95
|
+
of your request response. In order to have more control over the element
|
96
|
+
that renders first (before the request), you can set the ID of that element.
|
97
|
+
|
98
|
+
To set ID of the container element, you can do the following:
|
99
|
+
```erb
|
100
|
+
<%= render_async users_path, container_id: 'users-container' %>
|
101
|
+
```
|
102
|
+
|
103
|
+
Rendered code in the view:
|
104
|
+
```html
|
105
|
+
<div id="users-container">
|
106
|
+
</div>
|
107
|
+
|
108
|
+
...
|
109
|
+
```
|
110
|
+
|
111
|
+
### Passing in a container class name
|
112
|
+
|
113
|
+
`render_async` renders an element that gets replaced with the content of your
|
114
|
+
request response. If you want to style that element, you can set the class name
|
115
|
+
on it.
|
116
|
+
|
117
|
+
```erb
|
118
|
+
<%= render_async users_path, container_class: 'users-container-class' %>
|
119
|
+
```
|
120
|
+
|
121
|
+
Rendered code in the view:
|
122
|
+
```html
|
123
|
+
<div id="render_async_18b8a6cd161499117471" class="users-container-class">
|
124
|
+
</div>
|
125
|
+
|
126
|
+
...
|
127
|
+
```
|
128
|
+
|
129
|
+
### Passing in HTML options
|
130
|
+
|
131
|
+
`render_async` can accept `html_options` argument.
|
132
|
+
`html_options` is an optional hash that gets passed to a Rails'
|
133
|
+
`javascript_tag`, to drop HTML tags into the `script` element.
|
134
|
+
|
135
|
+
Example of utilizing `html_options` with a `nonce`:
|
136
|
+
```erb
|
137
|
+
<%= render_async users_path, nonce: 'lWaaV6eYicpt+oyOfcShYINsz0b70iR+Q1mohZqNaag=' %>
|
138
|
+
```
|
139
|
+
|
140
|
+
Rendered code in the view:
|
141
|
+
```html
|
142
|
+
<div id="render_async_18b8a6cd161499117471">
|
143
|
+
</div>
|
144
|
+
|
145
|
+
<script nonce="lWaaV6eYicpt+oyOfcShYINsz0b70iR+Q1mohZqNaag=">
|
146
|
+
//<![CDATA[
|
147
|
+
...
|
148
|
+
//]]>
|
149
|
+
</script>
|
150
|
+
```
|
151
|
+
|
152
|
+
### Passing in an HTML element name
|
153
|
+
|
154
|
+
`render_async` can take in an HTML element name, allowing you to control
|
155
|
+
what type of container gets rendered. This can be useful when you're using
|
156
|
+
[`render_async` inside a table](https://github.com/renderedtext/render_async/issues/12)
|
157
|
+
and you need it to render a `tr` element before your request gets loaded, so
|
158
|
+
your content doesn't get pushed out of the table.
|
159
|
+
|
160
|
+
Example of using HTML element name:
|
161
|
+
```erb
|
162
|
+
<%= render_async users_path, html_element_name: 'tr' %>
|
163
|
+
```
|
164
|
+
|
165
|
+
Rendered code in the view:
|
166
|
+
```html
|
167
|
+
<tr id="render_async_04229e7abe1507987376">
|
168
|
+
</tr>
|
169
|
+
...
|
170
|
+
```
|
171
|
+
|
172
|
+
### Passing in a placeholder
|
173
|
+
|
174
|
+
`render_async` can be called with a block that will act as a placeholder before
|
175
|
+
your AJAX call finishes.
|
176
|
+
|
177
|
+
Example of passing in a block:
|
178
|
+
|
179
|
+
```erb
|
180
|
+
<%= render_async users_path do %>
|
181
|
+
<h1>Users are loading...</h1>
|
182
|
+
<% end %>
|
183
|
+
```
|
184
|
+
|
185
|
+
Rendered code in the view:
|
186
|
+
```html
|
187
|
+
<div id="render_async_14d7ac165d1505993721">
|
188
|
+
<h1>Users are loading...</h1>
|
189
|
+
</div>
|
190
|
+
|
191
|
+
<script>
|
192
|
+
//<![CDATA[
|
193
|
+
...
|
194
|
+
//]]>
|
195
|
+
</script>
|
196
|
+
```
|
197
|
+
|
198
|
+
After AJAX is finished, placeholder will be replaced with the request's
|
199
|
+
response.
|
200
|
+
|
201
|
+
### Passing in an event name
|
202
|
+
|
203
|
+
`render_async` can receive `:event_name` option which will emit JavaScript
|
204
|
+
event after it's done with fetching and rendering request content to HTML.
|
205
|
+
|
206
|
+
This can be useful to have if you want to add some JavaScript functionality
|
207
|
+
after your partial is loaded through `render_async`.
|
208
|
+
|
209
|
+
Example of passing it to `render_async`:
|
210
|
+
```erb
|
211
|
+
<%= render_async users_path, event_name: "users-loaded" %>
|
212
|
+
```
|
213
|
+
|
214
|
+
Rendered code in view:
|
215
|
+
```html
|
216
|
+
<div id="render_async_04229e7abe1507987376">
|
217
|
+
</div>
|
218
|
+
|
219
|
+
<script>
|
220
|
+
//<![CDATA[
|
221
|
+
...
|
222
|
+
document.dispatchEvent(new Event("users-loaded"));
|
223
|
+
...
|
224
|
+
//]]>
|
225
|
+
</script>
|
226
|
+
```
|
227
|
+
|
228
|
+
Then, in your JS, you could do something like this:
|
229
|
+
```javascript
|
230
|
+
document.addEventListener("users-loaded", function() {
|
231
|
+
console.log("Users have loaded!");
|
232
|
+
});
|
233
|
+
```
|
234
|
+
|
235
|
+
NOTE: Dispatching events is also supported for older browsers that don't
|
236
|
+
support Event constructor.
|
237
|
+
|
238
|
+
### Retry on failure
|
239
|
+
|
240
|
+
`render_async` can retry your requests if they fail for some reason.
|
241
|
+
|
242
|
+
If you want `render_async` to retry a request for number of times, you can do
|
243
|
+
this:
|
244
|
+
```erb
|
245
|
+
<%= render_async users_path, retry_count: 5, error_message: "Couldn't fetch it" %>
|
246
|
+
```
|
247
|
+
|
248
|
+
Now render_async will retry `users_path` for 5 times. If it succedes in
|
249
|
+
between, it will stop with dispatching requests. If it fails after 5 times,
|
250
|
+
it will show an [error message](#handling-errors) which you need to specify.
|
251
|
+
|
252
|
+
This can show useful when you know your requests often fail, and you don't want
|
253
|
+
to refresh the whole page just to retry them.
|
254
|
+
|
255
|
+
### Polling
|
256
|
+
|
257
|
+
You can call `render_async` with interval argument. This will make render_async
|
258
|
+
call specified path at specified interval.
|
259
|
+
|
260
|
+
By doing this:
|
261
|
+
```erb
|
262
|
+
<%= render_async comments_path, interval: 5000 %>
|
263
|
+
```
|
264
|
+
You are telling `render_async` to fetch comments_path every 5 seconds.
|
265
|
+
|
266
|
+
This can be handy if you want to enable polling for a specific URL.
|
267
|
+
|
268
|
+
NOTE: By passing interval to `render_async`, initial container element
|
269
|
+
will remain in HTML tree, it will not be replaced with request response.
|
270
|
+
You can handle how that container element is rendered and its style by
|
271
|
+
[passing in an HTML element name](#passing-in-an-html-element-name) and
|
272
|
+
[HTML element class](#passing-in-a-container-class-name).
|
273
|
+
|
274
|
+
### Handling errors
|
275
|
+
|
276
|
+
`render_async` let's you handle errors by allowing you to pass in `error_message`
|
277
|
+
and `error_event_name`.
|
278
|
+
|
279
|
+
- `error_message`
|
280
|
+
|
281
|
+
passing an `error_message` will render a message if the AJAX requests fails for
|
282
|
+
some reason
|
283
|
+
```erb
|
284
|
+
<%= render_async users_path,
|
285
|
+
error_message: '<p>Sorry, users loading went wrong :(</p>' %>
|
286
|
+
```
|
287
|
+
|
288
|
+
- `error_event_name`
|
289
|
+
|
290
|
+
calling `render_async` with `error_event_name` will dispatch event in the case
|
291
|
+
of an error with your AJAX call.
|
292
|
+
```erb
|
293
|
+
<%= render_asyc users_path, error_event_name: 'users-error-event' %>
|
294
|
+
```
|
295
|
+
|
296
|
+
You can then catch the event in your code with:
|
297
|
+
```js
|
298
|
+
document.addEventListener('users-error-event', function() {
|
299
|
+
// I'm on it
|
300
|
+
})
|
301
|
+
```
|
302
|
+
|
303
|
+
### Caching
|
304
|
+
|
305
|
+
`render_async` can utilize view fragment caching to avoid extra AJAX calls.
|
306
|
+
|
307
|
+
In your views (e.g. `app/views/comments/show.html.erb`):
|
308
|
+
```erb
|
309
|
+
# note 'render_async_cache' instead of standard 'render_async'
|
310
|
+
<%= render_async_cache comment_stats_path %>
|
311
|
+
```
|
312
|
+
|
313
|
+
Then, in the partial (e.g. `app/views/comments/_comment_stats.html.erb`):
|
314
|
+
```erb
|
315
|
+
<% cache render_async_cache_key(request.path), skip_digest: true do %>
|
316
|
+
<div class="col-md-6">
|
317
|
+
<%= @stats %>
|
318
|
+
</div>
|
319
|
+
<% end %>
|
320
|
+
```
|
321
|
+
|
322
|
+
* The first time the page renders, it will make the AJAX call.
|
323
|
+
* Any other times (until the cache expires), it will render from cache
|
324
|
+
instantly, without making the AJAX call.
|
325
|
+
* You can expire cache simply by passing `:expires_in` in your view where
|
326
|
+
you cache the partial
|
327
|
+
|
328
|
+
### Doing non-GET requests
|
329
|
+
|
330
|
+
By default, `render_async` creates AJAX GET requests for the path you provide.
|
331
|
+
If you want to change this behaviour, you can pass in a `method` argument to
|
332
|
+
`render_async` view helper.
|
333
|
+
|
334
|
+
```erb
|
335
|
+
<%= render_async users_path, method: 'POST' %>
|
336
|
+
```
|
337
|
+
|
338
|
+
You can also set `body` and `headers` of the request if you need them.
|
339
|
+
|
340
|
+
```erb
|
341
|
+
<%= render_async users_path,
|
342
|
+
method: 'POST',
|
343
|
+
data: { fresh: 'AF' },
|
344
|
+
headers: { 'Content-Type': 'text' } %>
|
345
|
+
```
|
346
|
+
|
347
|
+
### Using with Turbolinks
|
348
|
+
|
349
|
+
On Turbolinks applications, you may experience caching issues when navigating
|
350
|
+
away from, and then back to, a page with a `render_async` call on it. This will
|
351
|
+
likely show up as an empty div.
|
352
|
+
|
353
|
+
If you're using Turbolinks 5 or higher, you can resolve this by setting Turbolinks
|
354
|
+
configurtion of `render_async` to true:
|
355
|
+
|
356
|
+
```rb
|
357
|
+
RenderAsync.configure do |config|
|
358
|
+
config.turbolinks = true # Enable this option if you are using Turbolinks 5+
|
359
|
+
end
|
360
|
+
```
|
361
|
+
|
362
|
+
This way, you're not breaking Turbolinks flow of loading or reloading a page.
|
363
|
+
It makes it more efficient that the next option that is suggested below.
|
364
|
+
|
365
|
+
Another option:
|
366
|
+
If you want, you can tell Turbolinks to reload your `render_async` call as follows:
|
367
|
+
|
368
|
+
```erb
|
369
|
+
<%= render_async events_path, 'data-turbolinks-track': 'reload' %>
|
370
|
+
```
|
371
|
+
|
372
|
+
This will reload the whole page with Turbolinks.
|
373
|
+
|
374
|
+
Make sure to put `<%= content_for :render_async %>` in your base view file in
|
375
|
+
the `<head>` and not the `<body>`.
|
376
|
+
|
377
|
+
### Using with respond_to and JS format
|
378
|
+
|
379
|
+
If you need to restrict the action to only respond to AJAX requests, you'll
|
380
|
+
likely wrap it inside `respond_to`/`format.js` blocks like this:
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
def comment_stats
|
384
|
+
respond_to do |format|
|
385
|
+
format.js do
|
386
|
+
@stats = Comment.get_stats
|
387
|
+
|
388
|
+
render partial: "comment_stats"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
```
|
393
|
+
|
394
|
+
When you do this, Rails will sometime set the response's `Content-Type` header
|
395
|
+
to `text/javascript`. This causes the partial not to be rendered in the HTML.
|
396
|
+
This usually happens when there's browser caching.
|
397
|
+
|
398
|
+
You can get around it by specifying the content type to `text/html` in the
|
399
|
+
render call:
|
400
|
+
|
401
|
+
```ruby
|
402
|
+
render partial: "comment_stats", content_type: 'text/html'
|
403
|
+
```
|
404
|
+
|
405
|
+
### Nested Async Renders
|
406
|
+
|
407
|
+
It is possible to nest async templates within other async templates. When doing
|
408
|
+
so, another `content_for` is required to ensure the JavaScript needed to load
|
409
|
+
nested templates is included.
|
410
|
+
|
411
|
+
For example:
|
412
|
+
```erb
|
413
|
+
<%# app/views/comments/show.html.erb %>
|
414
|
+
|
415
|
+
<%= render_async comment_stats_path %>
|
416
|
+
```
|
417
|
+
|
418
|
+
```erb
|
419
|
+
<%# app/views/comments/_comment_stats.html.erb %>
|
420
|
+
|
421
|
+
<div class="col-md-6">
|
422
|
+
<%= @stats %>
|
423
|
+
</div>
|
424
|
+
|
425
|
+
<div class="col-md-6">
|
426
|
+
<%= render_async comment_advanced_stats_path %>
|
427
|
+
</div>
|
428
|
+
|
429
|
+
<%= content_for :render_async %>
|
430
|
+
```
|
431
|
+
|
432
|
+
### Configuration
|
433
|
+
|
434
|
+
`render_async` renders Vanilla JS (regular JavaScript, non-jQuery code)
|
435
|
+
**by default** in order to fetch the request from the server.
|
436
|
+
|
437
|
+
If you want `render_async` to use jQuery code, you need to configure it to do
|
438
|
+
so.
|
439
|
+
|
440
|
+
You can configure it by doing the following anywhere before you call
|
441
|
+
`render_async`:
|
442
|
+
```rb
|
443
|
+
RenderAsync.configure do |config|
|
444
|
+
config.jquery = true # This will render jQuery code, and skip Vanilla JS code
|
445
|
+
config.turbolinks = false # Enable this option if you are using Turbolinks 5+
|
446
|
+
end
|
447
|
+
```
|
448
|
+
|
449
|
+
Also, you can do it like this:
|
450
|
+
```rb
|
451
|
+
# This will render jQuery code, and skip Vanilla JS code
|
452
|
+
RenderAsync.configuration.jquery = true
|
453
|
+
```
|
454
|
+
|
455
|
+
## Development
|
456
|
+
|
457
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
458
|
+
`rake spec` to run the tests. You can also run `bin/console` for an interactive
|
459
|
+
prompt that will allow you to experiment.
|
460
|
+
|
461
|
+
## Contributing
|
462
|
+
|
463
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/renderedtext/render_async.
|
464
|
+
|
465
|
+
## License
|
466
|
+
|
467
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
468
|
+
|
469
|
+
## Contributors
|
470
|
+
|
471
|
+
Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
|
472
|
+
|
473
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
474
|
+
<!-- prettier-ignore -->
|
475
|
+
| [<img src="https://avatars2.githubusercontent.com/u/3028124?v=4" width="100px;"/><br /><sub><b>Nikola Đuza</b></sub>](http://nikoladjuza.me/)<br />[💬](#question-nikolalsvk "Answering Questions") [💻](https://github.com/renderedtext/render_async/commits?author=nikolalsvk "Code") [📖](https://github.com/renderedtext/render_async/commits?author=nikolalsvk "Documentation") [👀](#review-nikolalsvk "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/3866868?v=4" width="100px;"/><br /><sub><b>Colin</b></sub>](http://www.colinxfleming.com)<br />[💻](https://github.com/renderedtext/render_async/commits?author=colinxfleming "Code") [📖](https://github.com/renderedtext/render_async/commits?author=colinxfleming "Documentation") [💡](#example-colinxfleming "Examples") | [<img src="https://avatars2.githubusercontent.com/u/334273?v=4" width="100px;"/><br /><sub><b>Kasper Grubbe</b></sub>](http://kaspergrubbe.com)<br />[💻](https://github.com/renderedtext/render_async/commits?author=kaspergrubbe "Code") | [<img src="https://avatars2.githubusercontent.com/u/163584?v=4" width="100px;"/><br /><sub><b>Sai Ram Kunala</b></sub>](https://sairam.xyz/)<br />[📖](https://github.com/renderedtext/render_async/commits?author=sairam "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3065882?v=4" width="100px;"/><br /><sub><b>Josh Arnold</b></sub>](https://github.com/nightsurge)<br />[💻](https://github.com/renderedtext/render_async/commits?author=nightsurge "Code") [📖](https://github.com/renderedtext/render_async/commits?author=nightsurge "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/107798?v=4" width="100px;"/><br /><sub><b>Elad Shahar</b></sub>](https://eladshahar.com)<br />[💻](https://github.com/renderedtext/render_async/commits?author=SaladFork "Code") [💡](#example-SaladFork "Examples") | [<img src="https://avatars3.githubusercontent.com/u/232392?v=4" width="100px;"/><br /><sub><b>Sasha</b></sub>](http://www.revzin.co.il)<br />[💻](https://github.com/renderedtext/render_async/commits?author=sasharevzin "Code") [📖](https://github.com/renderedtext/render_async/commits?author=sasharevzin "Documentation") |
|
476
|
+
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
477
|
+
| [<img src="https://avatars3.githubusercontent.com/u/50223?v=4" width="100px;"/><br /><sub><b>Ernest Surudo</b></sub>](http://elsurudo.com)<br />[💻](https://github.com/renderedtext/render_async/commits?author=elsurudo "Code") | [<img src="https://avatars1.githubusercontent.com/u/334809?v=4" width="100px;"/><br /><sub><b>Kurtis Rainbolt-Greene</b></sub>](https://kurtis.rainbolt-greene.online)<br />[💻](https://github.com/renderedtext/render_async/commits?author=krainboltgreene "Code") | [<img src="https://avatars2.githubusercontent.com/u/59744?v=4" width="100px;"/><br /><sub><b>Richard Schneeman</b></sub>](https://www.schneems.com)<br />[📖](https://github.com/renderedtext/render_async/commits?author=schneems "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/75705?v=4" width="100px;"/><br /><sub><b>Richard Venneman</b></sub>](https://www.cityspotters.com)<br />[📖](https://github.com/renderedtext/render_async/commits?author=richardvenneman "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/381395?v=4" width="100px;"/><br /><sub><b>Filipe W. Lima</b></sub>](https://github.com/filipewl)<br />[📖](https://github.com/renderedtext/render_async/commits?author=filipewl "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/3135638?v=4" width="100px;"/><br /><sub><b>Jesús Eduardo Clemens Chong</b></sub>](https://github.com/eclemens)<br />[💻](https://github.com/renderedtext/render_async/commits?author=eclemens "Code") | [<img src="https://avatars3.githubusercontent.com/u/1935686?v=4" width="100px;"/><br /><sub><b>René Klačan</b></sub>](https://github.com/reneklacan)<br />[💻](https://github.com/renderedtext/render_async/commits?author=reneklacan "Code") |
|
478
|
+
| [<img src="https://avatars1.githubusercontent.com/u/1313442?v=4" width="100px;"/><br /><sub><b>Gil Gomes</b></sub>](http://gilgomes.com.br)<br />[📖](https://github.com/renderedtext/render_async/commits?author=gil27 "Documentation") |
|
479
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
480
|
+
|
481
|
+
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
<<%= html_element_name %>
|
2
|
+
id="<%= container_id %>"
|
3
|
+
class="<%= container_class %>"
|
4
|
+
>
|
5
|
+
<%= placeholder %>
|
6
|
+
</<%= html_element_name %>>
|
7
|
+
|
8
|
+
<% content_for :render_async do %>
|
9
|
+
<%= javascript_tag html_options do %>
|
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
|
+
retry_count: retry_count,
|
22
|
+
interval: interval,
|
23
|
+
turbolinks: RenderAsync.configuration.turbolinks } %>
|
24
|
+
<% else %>
|
25
|
+
<%= render partial: 'render_async/request_vanilla',
|
26
|
+
formats: [:js],
|
27
|
+
locals: { container_id: container_id,
|
28
|
+
path: path,
|
29
|
+
method: method,
|
30
|
+
data: data,
|
31
|
+
event_name: event_name,
|
32
|
+
headers: headers,
|
33
|
+
error_message: error_message,
|
34
|
+
error_event_name: error_event_name,
|
35
|
+
retry_count: retry_count,
|
36
|
+
interval: interval,
|
37
|
+
turbolinks: RenderAsync.configuration.turbolinks } %>
|
38
|
+
<% end %>
|
39
|
+
<% end %>
|
40
|
+
<% end %>
|
@@ -0,0 +1,90 @@
|
|
1
|
+
if (window.jQuery) {
|
2
|
+
(function($) {
|
3
|
+
<% if turbolinks %>
|
4
|
+
if (document.documentElement.hasAttribute("data-turbolinks-preview")) {
|
5
|
+
return;
|
6
|
+
}
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
var _listener = function(currentRetryCount) {
|
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
|
+
$.ajax({
|
16
|
+
url: '<%= path.html_safe %>',
|
17
|
+
method: '<%= method %>',
|
18
|
+
data: "<%= escape_javascript(data.to_s.html_safe) %>",
|
19
|
+
headers: headers
|
20
|
+
}).done(function(response) {
|
21
|
+
<% if interval %>
|
22
|
+
$("#<%= container_id %>").empty();
|
23
|
+
$("#<%= container_id %>").append(response);
|
24
|
+
<% else %>
|
25
|
+
$("#<%= container_id %>").replaceWith(response);
|
26
|
+
<% end %>
|
27
|
+
|
28
|
+
<% if event_name.present? %>
|
29
|
+
var event = undefined;
|
30
|
+
if (typeof(Event) === 'function') {
|
31
|
+
event = new Event("<%= event_name %>");
|
32
|
+
} else {
|
33
|
+
event = document.createEvent('Event');
|
34
|
+
event.initEvent('<%= event_name %>', true, true);
|
35
|
+
}
|
36
|
+
document.dispatchEvent(event);
|
37
|
+
<% end %>
|
38
|
+
}).fail(function(response) {
|
39
|
+
var skipErrorMessage = false;
|
40
|
+
<% if retry_count > 0 %>
|
41
|
+
skipErrorMessage = retry(currentRetryCount)
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
if (skipErrorMessage) return;
|
45
|
+
|
46
|
+
$("#<%= container_id %>").replaceWith('<%= error_message.try(:html_safe) %>');
|
47
|
+
|
48
|
+
<% if error_event_name.present? %>
|
49
|
+
var event = undefined;
|
50
|
+
if (typeof(Event) === 'function') {
|
51
|
+
event = new Event("<%= error_event_name %>");
|
52
|
+
} else {
|
53
|
+
event = document.createEvent('Event');
|
54
|
+
event.initEvent('<%= error_event_name %>', true, true);
|
55
|
+
}
|
56
|
+
document.dispatchEvent(event);
|
57
|
+
<% end %>
|
58
|
+
});
|
59
|
+
};
|
60
|
+
|
61
|
+
<% if retry_count > 0 %>
|
62
|
+
var retry = function(currentRetryCount) {
|
63
|
+
if (typeof(currentRetryCount) === 'number') {
|
64
|
+
if (currentRetryCount >= <%= retry_count %>)
|
65
|
+
return false;
|
66
|
+
|
67
|
+
_listener(currentRetryCount + 1);
|
68
|
+
return true;
|
69
|
+
}
|
70
|
+
|
71
|
+
_listener(1);
|
72
|
+
return true;
|
73
|
+
}
|
74
|
+
<% end %>
|
75
|
+
|
76
|
+
<% if turbolinks %>
|
77
|
+
$(document).one('turbolinks:load', _listener);
|
78
|
+
<% elsif interval %>
|
79
|
+
var _intervalFunction = function() {
|
80
|
+
_listener();
|
81
|
+
setInterval(_listener, <%= interval %>);
|
82
|
+
}
|
83
|
+
$(document).ready(_intervalFunction);
|
84
|
+
<% else %>
|
85
|
+
$(document).ready(_listener);
|
86
|
+
<% end %>
|
87
|
+
}(jQuery));
|
88
|
+
} else {
|
89
|
+
console.warn("Looks like you've enabled jQuery for render_async, but jQuery is not defined");
|
90
|
+
};
|