render_async 2.1.2 β†’ 2.1.7

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
  SHA256:
3
- metadata.gz: 9b91f800c218048a1e608c413909a1f9e55ae5a7ec450937d645f49526ac478c
4
- data.tar.gz: a0675247df2c42dba16036c548e13f5443234724326e09ca2aa619cfa807f3bf
3
+ metadata.gz: 80f65d684e925ba32249eef7d5dd817b268b72dfebd0ecd9525fbe544d16af57
4
+ data.tar.gz: 46b675280ceb449a68953e9a2833332ff74222d773a3aa66ec95036d25587273
5
5
  SHA512:
6
- metadata.gz: e26aa8dda9a9e5cfb9b4617999bc7a6a80671bb11ee0cb3d7519f8ad3d03e6154370bf46f95c4cd9eefa3ae23b1643a99014d5501a2ea8008c8ad760b7e59801
7
- data.tar.gz: c4f3aa9fe15e413df9ea442c8c7bd778aee560ef87a2af16973645eb3db2bedac4e2b3c944f06c737cf2371b07e35576a57823da4942db2687a04c064f33e4bb
6
+ metadata.gz: 3bdd39f73528d3b9a8035ab5c8629b9c5261186f1d3eae2d5b82b856942c0ae602d5c670d96e009a240744fe5e7d93a97136298f05ef55c010f7d6f7972b4f40
7
+ data.tar.gz: a73351396f72b02895c03a4ff20068f096ae71279adc7345518d31e26111f63ac46b5b76424a24e566a7a0268f1748d1c1c364489e17d030dea12a691cc227eb
@@ -11,7 +11,7 @@
11
11
  "login": "nikolalsvk",
12
12
  "name": "Nikola Đuza",
13
13
  "avatar_url": "https://avatars2.githubusercontent.com/u/3028124?v=4",
14
- "profile": "http://nikoladjuza.me/",
14
+ "profile": "https://nikolalsvk.github.io",
15
15
  "contributions": [
16
16
  "question",
17
17
  "code",
@@ -168,6 +168,43 @@
168
168
  "contributions": [
169
169
  "code"
170
170
  ]
171
+ },
172
+ {
173
+ "login": "fffx",
174
+ "name": "fangxing",
175
+ "avatar_url": "https://avatars3.githubusercontent.com/u/11586335?v=4",
176
+ "profile": "https://github.com/fffx",
177
+ "contributions": [
178
+ "code"
179
+ ]
180
+ },
181
+ {
182
+ "login": "lipsumar",
183
+ "name": "Emmanuel Pire",
184
+ "avatar_url": "https://avatars3.githubusercontent.com/u/1191418?v=4",
185
+ "profile": "http://blog.lipsumarium.com",
186
+ "contributions": [
187
+ "code",
188
+ "doc"
189
+ ]
190
+ },
191
+ {
192
+ "login": "maximgeerinck",
193
+ "name": "Maxim Geerinck",
194
+ "avatar_url": "https://avatars1.githubusercontent.com/u/615509?v=4",
195
+ "profile": "https://github.com/maximgeerinck",
196
+ "contributions": [
197
+ "code"
198
+ ]
199
+ },
200
+ {
201
+ "login": "vanboom",
202
+ "name": "Don",
203
+ "avatar_url": "https://avatars1.githubusercontent.com/u/251706?v=4",
204
+ "profile": "https://github.com/vanboom",
205
+ "contributions": [
206
+ "code"
207
+ ]
171
208
  }
172
209
  ],
173
210
  "repoType": "github"
@@ -0,0 +1,3 @@
1
+ github: nikolalsvk
2
+ tidelift: rubygems/render_async
3
+ custom: "https://www.paypal.me/nikolalsvk/10"
@@ -1,8 +1,42 @@
1
- ### 2.1.1 (2019/8/17)
1
+ ### 2.1.7 (2020/8/1)
2
+
3
+ * [#125](https://github.com/renderedtext/render_async/pull/125): Implement retry after some time feature - [@nikolalsvk](https://github.com/nikolalsvk).
4
+ * [#124](https://github.com/renderedtext/render_async/pull/124): Add more info on how to control polling - [@nikolalsvk](https://github.com/nikolalsvk).
5
+ * [#123](https://github.com/renderedtext/render_async/pull/123): Simplify calling of start and stop event when interval is defined - [@nikolalsvk](https://github.com/nikolalsvk).
6
+ * [#119](https://github.com/renderedtext/render_async/pull/119): Add polling control start/stop events - [@vanboom](https://github.com/vanboom).
7
+ * [#120](https://github.com/renderedtext/render_async/pull/120): Fine tune custom content_for feature - [@nikolalsvk](https://github.com/nikolalsvk).
8
+ * [#117](https://github.com/renderedtext/render_async/pull/117): Allow a custom content_for name - [@vanboom](https://github.com/vanboom).
9
+
10
+ ### 2.1.6 (2020/5/9)
11
+
12
+ * [#114](https://github.com/renderedtext/render_async/pull/114): Call render_async logic if document state is ready or interactive - [@nikolalsvk](https://github.com/nikolalsvk).
13
+ * [#113](https://github.com/renderedtext/render_async/pull/113): Remove interval after Turbolinks visit event - [@nikolalsvk](https://github.com/nikolalsvk).
14
+ * [#112](https://github.com/renderedtext/render_async/pull/112): Add X-Requested-With header in Vanilla JS - [@nikolalsvk](https://github.com/nikolalsvk).
15
+ * [#110](https://github.com/renderedtext/render_async/pull/110): Remove preventDefault, and load toggle in stream - [@vanboom](https://github.com/vanboom).
16
+
17
+ ### 2.1.5 (2020/3/22)
18
+
19
+ * [#105](https://github.com/renderedtext/render_async/pull/105): Load toggle listeners after page loads - [@nikolalsvk](https://github.com/nikolalsvk).
20
+ * [#104](https://github.com/renderedtext/render_async/pull/104): Attach container to dispatched events - [@nikolalsvk](https://github.com/nikolalsvk).
21
+ * [#103](https://github.com/renderedtext/render_async/pull/103): Add generic "load" and "error" events - [@lipsumar](https://github.com/lipsumar).
22
+ * [#98](https://github.com/renderedtext/render_async/pull/98): Bump nonce pattern in the README to follow Rails CSP standard - [@colinxfleming](https://github.com/colinxfleming).
23
+
24
+ ### 2.1.4 (2019/11/11)
25
+
26
+ * [#96](https://github.com/renderedtext/render_async/pull/96): Add once option to remove event once it's triggered #94 - [@fffx](https://github.com/fffx).
27
+
28
+ ### 2.1.3 (2019/9/24)
29
+
30
+ * [#95](https://github.com/renderedtext/render_async/pull/95): Use double quotes for displaying error message - [@nikolalsvk](https://github.com/nikolalsvk).
31
+ * [#93](https://github.com/renderedtext/render_async/pull/93): Fix: "Uncaught ReferenceError: \_interval" #92 - [@fffx](https://github.com/fffx).
32
+
33
+ ### 2.1.2 (2019/8/17)
34
+
2
35
  * [#89](https://github.com/renderedtext/render_async/pull/89): Bump version to 2.1.2 - [@nikolalsvk](https://github.com/nikolalsvk).
3
36
  * [#82](https://github.com/renderedtext/render_async/pull/88): When toggle true, do not fire `_renderAsyncFunc` on `turbolinks:load` - [@ThanhKhoaIT](https://github.com/ThanhKhoaIT).
4
37
 
5
38
  ### 2.1.1 (2019/8/17)
39
+
6
40
  * [#85](https://github.com/renderedtext/render_async/pull/85): Rename main JS function and support toggle feature with other features - [@nikolalsvk](https://github.com/nikolalsvk).
7
41
  * [#82](https://github.com/renderedtext/render_async/pull/82): Add toggle selector and event to render - [@ThanhKhoaIT](https://github.com/ThanhKhoaIT).
8
42
  * DEPRECATION WARNING - html_options is now a hash that you pass to render_async instead of an argument. If you passed for example a nonce: '21312aas...', you will need to pass
data/README.md CHANGED
@@ -1,31 +1,70 @@
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-17-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
1
+ <p align="center">
2
+ <img src='http://s2blog.wpengine.com/wp-content/uploads/assets/images/2017-06-08/speed-up-rendering-rails-pages-with-render-async.png' alt='render_async' />
3
+
4
+ <h1 align="center">πŸ‘‹ Welcome to render_async</h1>
5
+
6
+ <h3 align="center">Let's make your Rails pages fast again :racehorse:</h3>
7
+
8
+ <br />
9
+
10
+ <p align="center">
11
+ <a href="https://www.paypal.me/nikolalsvk/10" target="_blank">
12
+ <img src="https://img.shields.io/badge/$-support-green.svg" alt="Donate" />
13
+ </a>
14
+ <a href="https://rubygems.org/gems/render_async" target="_blank">
15
+ <img src="https://img.shields.io/gem/dt/render_async" alt="Downloads" />
16
+ </a>
17
+ <a href="#contributors" target="_blank">
18
+ <img src="https://img.shields.io/github/all-contributors/renderedtext/render_async" alt="All contributors" />
19
+ </a>
20
+ <a href="https://badge.fury.io/rb/render_async" target="_blank">
21
+ <img src="https://badge.fury.io/rb/render_async.svg" alt="Gem Version" />
22
+ </a>
23
+ <br />
24
+ <a href="https://discord.gg/SPfbeRm" target="_blank">
25
+ <img src="https://img.shields.io/discord/738783603214909521" alt="Discord Server" />
26
+ </a>
27
+ <a href="https://semaphoreci.com/renderedtext/render_async" target="_blank">
28
+ <img src="https://semaphoreci.com/api/v1/renderedtext/render_async/branches/master/shields_badge.svg" alt="Build Status" />
29
+ </a>
30
+ <a href="https://codeclimate.com/github/renderedtext/render_async" target="_blank">
31
+ <img src="https://img.shields.io/codeclimate/maintainability/renderedtext/render_async" alt="Code Climate Maintainablity" />
32
+ </a>
33
+ <a href="https://codeclimate.com/github/renderedtext/render_async/coverage" target="_blank">
34
+ <img src="https://img.shields.io/codeclimate/coverage/renderedtext/render_async" alt="Test Coverage" />
35
+ </a>
36
+ <a href="https://github.com/renderedtext/render_async/blob/master/LICENSE" target="_blank">
37
+ <img src="https://img.shields.io/github/license/renderedtext/render_async" alt="License" />
38
+ </a>
39
+ <a href="https://www.codetriage.com/renderedtext/render_async" target="_blank">
40
+ <img src="https://www.codetriage.com/renderedtext/render_async/badges/users.svg" alt="Help Contribute to Open Source" />
41
+ </a>
42
+ </p>
43
+ </p>
44
+
45
+ ### `render_async` is here to make your pages show faster to users.
46
+
47
+ Pages become faster seamlessly by rendering partials to your views.
48
+
49
+ Partials render **asynchronously** and let users see your page **faster**
50
+ than using regular rendering.
51
+
52
+ It works with Rails and its tools out of the box.
53
+
54
+ :sparkles: A quick overview of how `render_async` does its magic:
55
+
56
+ 1. user visits a page
57
+ 2. `render_async` makes an AJAX request on the controller action
22
58
  3. controller renders a partial
23
- 4. partials renders in the place where you put `render_async` helper
59
+ 4. partial renders in the place where you put `render_async` view helper
24
60
 
25
- JavaScript is injected into `<%= content_for :render_async %>` so you choose
61
+ JavaScript is injected straight into `<%= content_for :render_async %>` so you choose
26
62
  where to put it.
27
63
 
28
- ## Installation
64
+ :mega: P.S. Join our [Discord channel](https://discord.gg/SPfbeRm) for help and discussion, and let's make `render_async` even better!
65
+
66
+ ## :package: Installation
67
+
29
68
  Add this line to your application's Gemfile:
30
69
 
31
70
  ```ruby
@@ -36,7 +75,7 @@ And then execute:
36
75
 
37
76
  $ bundle install
38
77
 
39
- ## Usage
78
+ ## :hammer: Usage
40
79
 
41
80
  1. Include `render_async` view helper somewhere in your views (e.g. `app/views/comments/show.html.erb`):
42
81
  ```erb
@@ -69,7 +108,7 @@ And then execute:
69
108
  <%= content_for :render_async %>
70
109
  ```
71
110
 
72
- ## Advanced usage
111
+ ## :hammer_and_wrench: Advanced usage
73
112
 
74
113
  Advanced usage includes information on different options, such as:
75
114
 
@@ -79,15 +118,20 @@ Advanced usage includes information on different options, such as:
79
118
  - [Passing in an HTML element name](#passing-in-an-html-element-name)
80
119
  - [Passing in a placeholder](#passing-in-a-placeholder)
81
120
  - [Passing in an event name](#passing-in-an-event-name)
121
+ - [Using default events](#using-default-events)
82
122
  - [Retry on failure](#retry-on-failure)
123
+ - [Retry after some time](#retry-after-some-time)
83
124
  - [Toggle event](#toggle-event)
125
+ - [Control polling with a toggle](#control-polling-with-a-toggle)
84
126
  - [Polling](#polling)
127
+ - [Controlled polling](#controlled-polling)
85
128
  - [Handling errors](#handling-errors)
86
129
  - [Caching](#caching)
87
130
  - [Doing non-GET requests](#doing-non-get-requests)
88
131
  - [Using with Turbolinks](#using-with-turbolinks)
89
132
  - [Using with respond_to and JS format](#using-with-respond_to-and-js-format)
90
133
  - [Nested Async Renders](#nested-async-renders)
134
+ - [Customizing the content_for name](#customizing-the-content_for-name)
91
135
  - [Configuration](#configuration)
92
136
 
93
137
  ### Passing in a container ID
@@ -133,21 +177,23 @@ Rendered code in the view:
133
177
  `html_options` is an optional hash that gets passed to a Rails'
134
178
  `javascript_tag`, to drop HTML tags into the `script` element.
135
179
 
136
- Example of utilizing `html_options` with a `nonce`:
180
+ Example of utilizing `html_options` with a [nonce](https://edgeguides.rubyonrails.org/security.html#content-security-policy):
137
181
  ```erb
138
- <%= render_async users_path, html_options: { nonce: 'lWaaV6eYicpt+oyOfcShYINsz0b70iR+Q1mohZqNaag=' } %>
182
+ <%= render_async users_path, html_options: { nonce: true } %>
139
183
  ```
140
184
 
141
185
  Rendered code in the view:
142
186
  ```html
143
- <div id="render_async_18b8a6cd161499117471">
144
- </div>
145
-
146
- <script nonce="lWaaV6eYicpt+oyOfcShYINsz0b70iR+Q1mohZqNaag=">
187
+ <script nonce="2x012CYGxKgM8qAApxRHxA==">
147
188
  //<![CDATA[
148
189
  ...
149
190
  //]]>
150
191
  </script>
192
+
193
+ ...
194
+
195
+ <div id="render_async_18b8a6cd161499117471" class="">
196
+ </div>
151
197
  ```
152
198
 
153
199
  ### Passing in an HTML element name
@@ -207,6 +253,9 @@ event after it's done with fetching and rendering request content to HTML.
207
253
  This can be useful to have if you want to add some JavaScript functionality
208
254
  after your partial is loaded through `render_async`.
209
255
 
256
+ You can also access the associated container (DOM node) in the event object
257
+ that gets emitted.
258
+
210
259
  Example of passing it to `render_async`:
211
260
  ```erb
212
261
  <%= render_async users_path, event_name: "users-loaded" %>
@@ -226,15 +275,47 @@ Rendered code in view:
226
275
  </script>
227
276
  ```
228
277
 
229
- Then, in your JS, you could do something like this:
278
+ Then, in your JavaScript code, you could do something like this:
230
279
  ```javascript
231
- document.addEventListener("users-loaded", function() {
232
- console.log("Users have loaded!");
280
+ document.addEventListener("users-loaded", function(event) {
281
+ console.log("Users have loaded!", event.container); // Access the container which loaded the users
233
282
  });
234
283
  ```
235
284
 
236
- NOTE: Dispatching events is also supported for older browsers that don't
237
- support Event constructor.
285
+ > :bulb: Dispatching events is also supported for older browsers that don't support Event constructor.
286
+
287
+ ### Using default events
288
+
289
+ `render_async` will fire the event `render_async_load` when an async partial
290
+ has loaded and rendered on page.
291
+
292
+ In case there is an error, the event `render_async_error` will fire instead.
293
+
294
+ This event will fire for all `render_async` partials on the page. For every
295
+ event, the associated container (DOM node) will be passed along.
296
+
297
+ This can be useful to apply JavaScript to content loaded after the page is
298
+ ready.
299
+
300
+ Example of using events:
301
+
302
+ ```js
303
+ // Vanilla javascript
304
+ document.addEventListener('render_async_load', function(event) {
305
+ console.log('Async partial loaded in this container:', event.container);
306
+ });
307
+ document.addEventListener('render_async_error', function(event) {
308
+ console.log('Async partial could not load in this container:', event.container);
309
+ });
310
+
311
+ // with jQuery
312
+ $(document).on('render_async_load', function(event) {
313
+ console.log('Async partial loaded in this container:', event.container);
314
+ });
315
+ $(document).on('render_async_error', function(event) {
316
+ console.log('Async partial could not load in this container:', event.container);
317
+ });
318
+ ```
238
319
 
239
320
  ### Retry on failure
240
321
 
@@ -246,13 +327,46 @@ this:
246
327
  <%= render_async users_path, retry_count: 5, error_message: "Couldn't fetch it" %>
247
328
  ```
248
329
 
249
- Now render_async will retry `users_path` for 5 times. If it succedes in
330
+ Now render_async will retry `users_path` for 5 times. If it succeeds in
250
331
  between, it will stop with dispatching requests. If it fails after 5 times,
251
332
  it will show an [error message](#handling-errors) which you need to specify.
252
333
 
253
334
  This can show useful when you know your requests often fail, and you don't want
254
335
  to refresh the whole page just to retry them.
255
336
 
337
+ #### Retry after some time
338
+
339
+ If you want to retry requests but with some delay in between the calls, you can
340
+ pass a `retry_delay` option together with `retry_count` like so:
341
+
342
+ ```erb
343
+ <%= render_async users_path,
344
+ retry_count: 5,
345
+ retry_delay: 2000 %>
346
+ ```
347
+
348
+ This will make `render_async` wait for 2 seconds before retrying after each
349
+ failure. In the end, if the request is still failing after 5th time, it will
350
+ dispatch a [default error event](#using-default-events).
351
+
352
+ > :candy: If you are catching an event after an error, you can get `retryCount` from
353
+ the event. `retryCount` will have number of retries it took before the event was dispatched.
354
+
355
+ Here is an example on how to get `retryCount`:
356
+
357
+ ```erb
358
+ <%= render_async users_path,
359
+ retry_count: 5,
360
+ retry_delay: 2000,
361
+ error_event_name: 'it-failed-badly' %>
362
+
363
+ <script>
364
+ document.addEventListener('it-failed-badly', function(event) {
365
+ console.log("Request failed after " + event.retryCount + " tries!")
366
+ });
367
+ </script>
368
+ ```
369
+
256
370
  ### Toggle event
257
371
 
258
372
  You can trigger `render_async` loading by clicking or doing another event to a
@@ -262,29 +376,33 @@ default event that will trigger `render_async` will be 'click' event. You can
262
376
  do this by doing the following:
263
377
 
264
378
  ```erb
265
- <a href='#' id='detail-button'>Detail</a>
266
- <%= render_async comments_path, toggle: { selector: '#detail-button', event: :click } %>
379
+ <a href='#' id='comments-button'>Load comments</a>
380
+ <%= render_async comments_path, toggle: { selector: '#comments-button', event: :click } %>
267
381
  ```
268
382
 
269
- This will trigger `render_async` to load the `comments_path` when you click the `#details-button` element.
383
+ This will trigger `render_async` to load the `comments_path` when you click the `#comments-button` element.
384
+ If you want to remove event once it's triggered, you can pass `once: true` in the toggle options.
385
+ The `once` option is false by default.
270
386
 
271
387
  You can also pass in a placeholder before the `render_async` is triggered. That
272
388
  way, the element that started `render_async` logic will be removed after the
273
389
  request has been completed. You can achieve this behaviour with something like this:
274
390
 
275
391
  ```erb
276
- <%= render_async comments_path, toggle: { selector: '#detail-button', event: :click } do %>
277
- <a href='#' id='detail-button'>Detail</a>
392
+ <%= render_async comments_path, toggle: { selector: '#comments-button', event: :click } do %>
393
+ <a href='#' id='comments-button'>Load comments</a>
278
394
  <% end %>
279
395
  ```
280
396
 
397
+ #### Control polling with a toggle
398
+
281
399
  Also, you can mix interval and toggle features. This way, you can turn polling
282
- on, and off by clicking the "Detail" button. In order to do this, you need to
400
+ on, and off by clicking the "Load comments" button. In order to do this, you need to
283
401
  pass `toggle` and `interval` arguments to `render_async` call like this:
284
402
 
285
403
  ```erb
286
- <a href='#' id='detail-button'>Detail</a>
287
- <%= render_async comments_path, toggle: { selector: '#detail-button', event: :click }, interval: 2000 %>
404
+ <a href='#' id='comments-button'>Load comments</a>
405
+ <%= render_async comments_path, toggle: { selector: '#comments-button', event: :click }, interval: 2000 %>
288
406
  ```
289
407
 
290
408
  ### Polling
@@ -300,11 +418,61 @@ You are telling `render_async` to fetch comments_path every 5 seconds.
300
418
 
301
419
  This can be handy if you want to enable polling for a specific URL.
302
420
 
303
- NOTE: By passing interval to `render_async`, initial container element
304
- will remain in HTML tree, it will not be replaced with request response.
305
- You can handle how that container element is rendered and its style by
306
- [passing in an HTML element name](#passing-in-an-html-element-name) and
307
- [HTML element class](#passing-in-a-container-class-name).
421
+ > :warning: By passing interval to `render_async`, initial container element
422
+ > will remain in HTML tree, it will not be replaced with request response.
423
+ > You can handle how that container element is rendered and its style by
424
+ > [passing in an HTML element name](#passing-in-an-html-element-name) and
425
+ > [HTML element class](#passing-in-a-container-class-name).
426
+
427
+ ### Controlled polling
428
+
429
+ You can controller `render_async` [polling](#polling) in 2 manners.
430
+ First one is pretty simple, and it involves using the [toggle](#toggle-event)
431
+ feature. To do this, you can follow instructions in the
432
+ [control polling with a toggle section](#control-polling-with-a-toggle).
433
+
434
+ Second option is more advanced and it involves emitting events to the `render_async`'s
435
+ container element. From your code, you can emit following events:
436
+ - 'async-stop' - this will stop polling
437
+ - 'async-start' - this will start polling.
438
+
439
+ > :bulb: Please note that events need to be dispatched to a render_async container.
440
+
441
+ An example of how you can do this looks like this:
442
+
443
+ ```erb
444
+ <%= render_async wave_render_async_path,
445
+ container_id: 'controllable-interval', # set container_id so we can get it later easily
446
+ interval: 3000 %>
447
+
448
+ <button id='stop-polling'>Stop polling</button>
449
+ <button id='start-polling'>Start polling</button>
450
+
451
+ <script>
452
+ var container = document.getElementById('controllable-interval')
453
+ var stopPolling = document.getElementById('stop-polling')
454
+ var startPolling = document.getElementById('start-polling')
455
+
456
+ var triggerEventOnContainer = function(eventName) {
457
+ var event = new Event(eventName);
458
+
459
+ container.dispatchEvent(event)
460
+ }
461
+
462
+ stopPolling.addEventListener('click', function() {
463
+ container.innerHTML = '<p>Polling stopped</p>'
464
+ triggerEventOnContainer('async-stop')
465
+ })
466
+ startPolling.addEventListener('click', function() {
467
+ triggerEventOnContainer('async-start')
468
+ })
469
+ </script>
470
+ ```
471
+
472
+ We are rendering two buttons - "Stop polling" and "Start polling". Then, we
473
+ attach event listener to catch any clicking on the buttons. When the buttons
474
+ are clicked, we either stop the polling, or start the polling, depending which
475
+ button a user clicks.
308
476
 
309
477
  ### Handling errors
310
478
 
@@ -354,10 +522,10 @@ Then, in the partial (e.g. `app/views/comments/_comment_stats.html.erb`):
354
522
  <% end %>
355
523
  ```
356
524
 
357
- * The first time the page renders, it will make the AJAX call.
358
- * Any other times (until the cache expires), it will render from cache
525
+ - The first time the page renders, it will make the AJAX call.
526
+ - Any other times (until the cache expires), it will render from cache
359
527
  instantly, without making the AJAX call.
360
- * You can expire cache simply by passing `:expires_in` in your view where
528
+ - You can expire cache simply by passing `:expires_in` in your view where
361
529
  you cache the partial
362
530
 
363
531
  ### Doing non-GET requests
@@ -386,7 +554,7 @@ away from, and then back to, a page with a `render_async` call on it. This will
386
554
  likely show up as an empty div.
387
555
 
388
556
  If you're using Turbolinks 5 or higher, you can resolve this by setting Turbolinks
389
- configurtion of `render_async` to true:
557
+ configuration of `render_async` to true:
390
558
 
391
559
  ```rb
392
560
  RenderAsync.configure do |config|
@@ -406,7 +574,7 @@ If you want, you can tell Turbolinks to reload your `render_async` call as follo
406
574
 
407
575
  This will reload the whole page with Turbolinks.
408
576
 
409
- Make sure to put `<%= content_for :render_async %>` in your base view file in
577
+ > :bulb: Make sure to put `<%= content_for :render_async %>` in your base view file in
410
578
  the `<head>` and not the `<body>`.
411
579
 
412
580
  ### Using with respond_to and JS format
@@ -464,6 +632,19 @@ For example:
464
632
  <%= content_for :render_async %>
465
633
  ```
466
634
 
635
+ ### Customizing the content_for name
636
+
637
+ The `content_for` name may be customized by passing the `content_for_name`
638
+ option to `render_async`. This option is especially useful when doing [nested async
639
+ renders](#nested-async-renders) to better control the location of the injected JavaScript.
640
+
641
+ For example:
642
+ ```erb
643
+ <%= render_async comment_stats_path, content_for_name: :render_async_comment_stats %>
644
+
645
+ <%= content_for :render_async_comment_stats %>
646
+ ```
647
+
467
648
  ### Configuration
468
649
 
469
650
  `render_async` renders Vanilla JS (regular JavaScript, non-jQuery code)
@@ -487,17 +668,28 @@ Also, you can do it like this:
487
668
  RenderAsync.configuration.jquery = true
488
669
  ```
489
670
 
490
- ## Development
671
+ ## :hammer_and_pick: Development
491
672
 
492
673
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
493
674
  `rake spec` to run the tests. You can also run `bin/console` for an interactive
494
- prompt that will allow you to experiment.
675
+ prompt that will allow you to experiment. To run integration tests, use
676
+ `bin/integration-tests`.
677
+
678
+ Got any questions or comments about development (or anything else)?
679
+ Join [render_async's Discord channel](https://discord.gg/SPfbeRm)
680
+ and let's make `render_async` even better!
681
+
682
+ ## :pray: Contributing
495
683
 
496
- ## Contributing
684
+ Thank you for considering or deciding to contribute, this is much appreciated!
685
+ Any kind of bug reports and pull requests are encouraged and welcome on GitHub at
686
+ https://github.com/renderedtext/render_async.
497
687
 
498
- Bug reports and pull requests are welcome on GitHub at https://github.com/renderedtext/render_async.
688
+ Got any issues or difficulties?
689
+ Join [render_async's Discord channel](https://discord.gg/SPfbeRm)
690
+ and let's make `render_async` even better!
499
691
 
500
- ## License
692
+ ## :memo: License
501
693
 
502
694
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
503
695
 
@@ -507,10 +699,10 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
507
699
 
508
700
  <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
509
701
  <!-- prettier-ignore -->
510
- | [<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") |
702
+ | [<img src="https://avatars2.githubusercontent.com/u/3028124?v=4" width="100px;"/><br /><sub><b>Nikola Đuza</b></sub>](https://nikolalsvk.github.io)<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") |
511
703
  | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
512
704
  | [<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") |
513
- | [<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") | [<img src="https://avatars0.githubusercontent.com/u/6081795?v=4" width="100px;"/><br /><sub><b>Khoa Nguyen</b></sub>](https://github.com/ThanhKhoaIT)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT "Code") [πŸ“–](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/8645918?v=4" width="100px;"/><br /><sub><b>Preet Sethi</b></sub>](https://www.linkedin.com/in/preetsethila/)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=preetsethi "Code") |
705
+ | [<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") | [<img src="https://avatars0.githubusercontent.com/u/6081795?v=4" width="100px;"/><br /><sub><b>Khoa Nguyen</b></sub>](https://github.com/ThanhKhoaIT)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT "Code") [πŸ“–](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/8645918?v=4" width="100px;"/><br /><sub><b>Preet Sethi</b></sub>](https://www.linkedin.com/in/preetsethila/)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=preetsethi "Code") | [<img src="https://avatars3.githubusercontent.com/u/11586335?v=4" width="100px;"/><br /><sub><b>fangxing</b></sub>](https://github.com/fffx)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=fffx "Code") | [<img src="https://avatars3.githubusercontent.com/u/1191418?v=4" width="100px;"/><br /><sub><b>Emmanuel Pire</b></sub>](http://blog.lipsumarium.com)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=lipsumar "Code") [πŸ“–](https://github.com/renderedtext/render_async/commits?author=lipsumar "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/615509?v=4" width="100px;"/><br /><sub><b>Maxim Geerinck</b></sub>](https://github.com/maximgeerinck)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=maximgeerinck "Code") | [<img src="https://avatars1.githubusercontent.com/u/251706?v=4" width="100px;"/><br /><sub><b>Don</b></sub>](https://github.com/vanboom)<br />[πŸ’»](https://github.com/renderedtext/render_async/commits?author=vanboom "Code") |
514
706
  <!-- ALL-CONTRIBUTORS-LIST:END -->
515
707
 
516
708
  This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
@@ -5,38 +5,30 @@
5
5
  <%= placeholder %>
6
6
  </<%= html_element_name %>>
7
7
 
8
- <% content_for :render_async do %>
8
+ <% content_for content_for_name do %>
9
9
  <%= javascript_tag html_options do %>
10
+ <% locals = { container_id: container_id,
11
+ path: path,
12
+ method: method,
13
+ data: data,
14
+ event_name: event_name,
15
+ toggle: toggle,
16
+ headers: headers,
17
+ error_message: error_message,
18
+ error_event_name: error_event_name,
19
+ retry_count: retry_count,
20
+ retry_delay: retry_delay,
21
+ interval: interval,
22
+ turbolinks: RenderAsync.configuration.turbolinks } %>
23
+
10
24
  <% if RenderAsync.configuration.jquery %>
11
25
  <%= render partial: 'render_async/request_jquery',
12
26
  formats: [:js],
13
- locals: { container_id: container_id,
14
- path: path,
15
- method: method,
16
- data: data,
17
- event_name: event_name,
18
- toggle: toggle,
19
- headers: headers,
20
- error_message: error_message,
21
- error_event_name: error_event_name,
22
- retry_count: retry_count,
23
- interval: interval,
24
- turbolinks: RenderAsync.configuration.turbolinks } %>
27
+ locals: locals %>
25
28
  <% else %>
26
29
  <%= render partial: 'render_async/request_vanilla',
27
30
  formats: [:js],
28
- locals: { container_id: container_id,
29
- path: path,
30
- method: method,
31
- data: data,
32
- event_name: event_name,
33
- toggle: toggle,
34
- headers: headers,
35
- error_message: error_message,
36
- error_event_name: error_event_name,
37
- retry_count: retry_count,
38
- interval: interval,
39
- turbolinks: RenderAsync.configuration.turbolinks } %>
31
+ locals: locals %>
40
32
  <% end %>
41
33
  <% end %>
42
34
  <% end %>
@@ -5,8 +5,32 @@ if (window.jQuery) {
5
5
  return;
6
6
  }
7
7
  <% end %>
8
+ function createEvent(name, container) {
9
+ var event = undefined;
10
+ if (typeof(Event) === 'function') {
11
+ event = new Event(name);
12
+ } else {
13
+ event = document.createEvent('Event');
14
+ event.initEvent(name, true, true);
15
+ }
16
+ event.container = container
17
+ return event;
18
+ }
19
+
20
+ function _runAfterDocumentLoaded(callback) {
21
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
22
+ // Handle a case where nested partials get loaded after the document loads
23
+ callback();
24
+ } else {
25
+ <% if turbolinks %>
26
+ $(document).one('turbolinks:load', callback);
27
+ <% else %>
28
+ $(document).ready(callback);
29
+ <% end %>
30
+ }
31
+ }
8
32
 
9
- var _makeRequest = function(currentRetryCount) {
33
+ function _makeRequest(currentRetryCount) {
10
34
  var headers = <%= headers.to_json.html_safe %>;
11
35
  var csrfTokenElement = document.querySelector('meta[name="csrf-token"]')
12
36
  if (csrfTokenElement)
@@ -18,21 +42,19 @@ if (window.jQuery) {
18
42
  data: "<%= escape_javascript(data.to_s.html_safe) %>",
19
43
  headers: headers
20
44
  }).done(function(response) {
45
+ var container = $("#<%= container_id %>");
21
46
  <% if interval %>
22
- $("#<%= container_id %>").empty();
23
- $("#<%= container_id %>").append(response);
47
+ container.empty();
48
+ container.append(response);
24
49
  <% else %>
25
- $("#<%= container_id %>").replaceWith(response);
50
+ container.replaceWith(response);
26
51
  <% end %>
27
52
 
53
+ var loadEvent = createEvent('render_async_load', container);
54
+ document.dispatchEvent(loadEvent);
55
+
28
56
  <% 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
- }
57
+ var event = createEvent("<%= event_name %>", container)
36
58
  document.dispatchEvent(event);
37
59
  <% end %>
38
60
  }).fail(function(response) {
@@ -43,64 +65,93 @@ if (window.jQuery) {
43
65
 
44
66
  if (skipErrorMessage) return;
45
67
 
46
- $("#<%= container_id %>").replaceWith('<%= error_message.try(:html_safe) %>');
68
+ var container = $("#<%= container_id %>");
69
+ container.replaceWith("<%= error_message.try(:html_safe) %>");
47
70
 
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 %>
71
+ var errorEvent = createEvent(
72
+ "<%= error_event_name || 'render_async_error' %>",
73
+ container
74
+ )
75
+ errorEvent.retryCount = currentRetryCount
76
+
77
+ document.dispatchEvent(errorEvent);
58
78
  });
59
79
  };
60
80
 
61
81
  <% if retry_count > 0 %>
62
- var retry = function(currentRetryCount) {
82
+ var _retryMakeRequest = _makeRequest
83
+
84
+ <% if retry_delay %>
85
+ _retryMakeRequest = function(currentRetryCount) {
86
+ setTimeout(function() {
87
+ _makeRequest(currentRetryCount)
88
+ }, <%= retry_delay %>)
89
+ }
90
+ <% end %>
91
+
92
+ function retry(currentRetryCount) {
63
93
  if (typeof(currentRetryCount) === 'number') {
64
94
  if (currentRetryCount >= <%= retry_count %>)
65
95
  return false;
66
96
 
67
- _makeRequest(currentRetryCount + 1);
97
+ _retryMakeRequest(currentRetryCount + 1);
68
98
  return true;
69
99
  }
70
100
 
71
- _makeRequest(1);
101
+ _retryMakeRequest(1);
72
102
  return true;
73
103
  }
74
104
  <% end %>
75
105
 
76
106
  var _renderAsyncFunction = _makeRequest;
77
107
 
78
- <% if interval %>
79
108
  var _interval;
109
+ <% if interval %>
80
110
  var _renderAsyncFunction = function() {
111
+ // If interval is already set, return
112
+ if (typeof(_interval) === 'number') return
113
+
81
114
  _makeRequest();
82
115
  _interval = setInterval(_makeRequest, <%= interval %>);
83
116
  }
84
- <% end %>
85
117
 
86
- <% if toggle %>
87
- $(document).on('<%= toggle[:event] || 'click' %>', '<%= toggle[:selector] %>', function(event) {
88
- event.preventDefault();
89
- if (_interval) {
90
- clearInterval(_interval);
118
+ var _clearRenderAsyncInterval = function() {
119
+ if (typeof(_interval) === 'number'){
120
+ clearInterval(_interval)
91
121
  _interval = undefined;
92
- } else {
93
- _renderAsyncFunction();
94
122
  }
95
- });
123
+ }
124
+
125
+ var container = $("#<%= container_id %>");
126
+
127
+ // Register a stop polling event on the container
128
+ $(container).on('async-stop', _clearRenderAsyncInterval)
129
+
130
+ // Register a start polling event on the container
131
+ $(container).on('async-start', _renderAsyncFunction)
132
+
133
+ <% if turbolinks %>
134
+ $(document).one('turbolinks:visit', _clearRenderAsyncInterval);
135
+ <% end %>
96
136
  <% end %>
97
137
 
98
- <% if turbolinks && !toggle %>
99
- $(document).one('turbolinks:load', _renderAsyncFunction);
138
+ <% if toggle %>
139
+ function _setUpToggle() {
140
+ $(document).<%= toggle[:once] ? 'one' : 'on' %>('<%= toggle[:event] || 'click' %>', '<%= toggle[:selector] %>', function(event) {
141
+ if (typeof(_interval) === 'number') {
142
+ clearInterval(_interval);
143
+ _interval = undefined;
144
+ } else {
145
+ _renderAsyncFunction();
146
+ }
147
+ });
148
+ }
149
+
150
+ _runAfterDocumentLoaded(_setUpToggle);
100
151
  <% elsif !toggle %>
101
- $(document).ready(_renderAsyncFunction);
152
+ _runAfterDocumentLoaded(_renderAsyncFunction)
102
153
  <% end %>
103
154
  }(jQuery));
104
155
  } else {
105
- console.warn("Looks like you've enabled jQuery for render_async, but jQuery is not defined");
156
+ console.warn("Looks like you've enabled jQuery for render_async, but jQuery is not defined on the window object");
106
157
  };
@@ -4,8 +4,30 @@
4
4
  return;
5
5
  }
6
6
  <% end %>
7
+ function createEvent(name, container) {
8
+ var event = undefined;
9
+ if (typeof(Event) === 'function') {
10
+ event = new Event(name);
11
+ } else {
12
+ event = document.createEvent('Event');
13
+ event.initEvent(name, true, true);
14
+ }
15
+ event.container = container
16
+ return event;
17
+ }
18
+
19
+ function _runAfterDocumentLoaded(callback) {
20
+ <% if turbolinks %>
21
+ document.addEventListener("turbolinks:load", function(e) {
22
+ e.target.removeEventListener(e.type, arguments.callee);
23
+ callback();
24
+ });
25
+ <% else %>
26
+ document.addEventListener("DOMContentLoaded", callback);
27
+ <% end %>
28
+ }
7
29
 
8
- var _makeRequest = function(currentRetryCount) {
30
+ function _makeRequest(currentRetryCount) {
9
31
  var request = new XMLHttpRequest();
10
32
  var asyncRequest = true;
11
33
  var SUCCESS = 200;
@@ -22,6 +44,8 @@
22
44
  request.setRequestHeader(key, headers[key]);
23
45
  });
24
46
 
47
+ request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
48
+
25
49
  request.onreadystatechange = function() {
26
50
  if (request.readyState === 4) {
27
51
  if (request.status >= SUCCESS && request.status < ERROR) {
@@ -32,14 +56,11 @@
32
56
  container.outerHTML = request.response;
33
57
  <% end %>
34
58
 
59
+ var loadEvent = createEvent('render_async_load', container);
60
+ document.dispatchEvent(loadEvent);
61
+
35
62
  <% if event_name.present? %>
36
- var event = undefined;
37
- if (typeof(Event) === 'function') {
38
- event = new Event("<%= event_name %>");
39
- } else {
40
- event = document.createEvent('Event');
41
- event.initEvent('<%= event_name %>', true, true);
42
- }
63
+ var event = createEvent('<%= event_name %>', container);
43
64
  document.dispatchEvent(event);
44
65
  <% end %>
45
66
  } else {
@@ -53,16 +74,13 @@
53
74
  var container = document.getElementById('<%= container_id %>');
54
75
  container.outerHTML = '<%= error_message.try(:html_safe) %>';
55
76
 
56
- <% if error_event_name.present? %>
57
- var event = undefined;
58
- if (typeof(Event) === 'function') {
59
- event = new Event("<%= error_event_name %>");
60
- } else {
61
- event = document.createEvent('Event');
62
- event.initEvent('<%= error_event_name %>', true, true);
63
- }
64
- document.dispatchEvent(event);
65
- <% end %>
77
+ var errorEvent = createEvent(
78
+ "<%= error_event_name || 'render_async_error' %>",
79
+ container
80
+ );
81
+ errorEvent.retryCount = currentRetryCount
82
+
83
+ document.dispatchEvent(errorEvent);
66
84
  }
67
85
  }
68
86
  };
@@ -72,52 +90,83 @@
72
90
  };
73
91
 
74
92
  <% if retry_count > 0 %>
75
- var retry = function(currentRetryCount) {
93
+
94
+ <% if retry_delay %>
95
+ _retryMakeRequest = function(currentRetryCount) {
96
+ setTimeout(function() {
97
+ _makeRequest(currentRetryCount)
98
+ }, <%= retry_delay %>)
99
+ }
100
+ <% end %>
101
+
102
+ function retry(currentRetryCount) {
76
103
  if (typeof(currentRetryCount) === 'number') {
77
104
  if (currentRetryCount >= <%= retry_count %>)
78
105
  return false;
79
106
 
80
- _makeRequest(currentRetryCount + 1);
107
+ _retryMakeRequest(currentRetryCount + 1);
81
108
  return true;
82
109
  }
83
110
 
84
- _makeRequest(1);
111
+ _retryMakeRequest(1);
85
112
  return true;
86
113
  }
87
114
  <% end %>
88
115
 
89
116
  var _renderAsyncFunction = _makeRequest;
90
117
 
91
- <% if interval %>
92
118
  var _interval;
119
+ <% if interval %>
93
120
  var _renderAsyncFunction = function() {
121
+ // If interval is already set, return
122
+ if (typeof(_interval) === 'number') return
123
+
94
124
  _makeRequest();
95
125
  _interval = setInterval(_makeRequest, <%= interval %>);
96
126
  }
127
+
128
+ var _clearRenderAsyncInterval = function() {
129
+ if (typeof(_interval) === 'number'){
130
+ clearInterval(_interval)
131
+ _interval = undefined;
132
+ }
133
+ }
134
+
135
+ var container = document.getElementById('<%= container_id %>');
136
+
137
+ // Register a polling stop event on the container
138
+ container.addEventListener("async-stop", _clearRenderAsyncInterval)
139
+
140
+ // Register a start polling event on the container
141
+ container.addEventListener("async-start", _renderAsyncFunction)
142
+
143
+ <% if turbolinks %>
144
+ document.addEventListener("turbolinks:visit", _clearRenderAsyncInterval)
145
+ <% end %>
97
146
  <% end %>
98
147
 
99
148
  <% if toggle %>
100
- var selectors = document.querySelectorAll('<%= toggle[:selector] %>');
101
-
102
- [...selectors].forEach(function(selector) {
103
- selector.addEventListener('<%= toggle[:event] || 'click' %>', function(event) {
104
- event.preventDefault();
105
- if (_interval) {
149
+ function _setUpToggle() {
150
+ var selectors = document.querySelectorAll('<%= toggle[:selector] %>');
151
+ var handler = function(event) {
152
+ if (typeof(_interval) === 'number') {
106
153
  clearInterval(_interval);
107
154
  _interval = undefined;
108
155
  } else {
109
156
  _renderAsyncFunction();
110
157
  }
111
- })
112
- });
113
- <% end %>
158
+ <% if toggle[:once] %>
159
+ this.removeEventListener(event.type, handler);
160
+ <% end %>
161
+ };
162
+
163
+ for (var i = 0; i < selectors.length; ++i) {
164
+ selectors[i].addEventListener('<%= toggle[:event] || 'click' %>', handler)
165
+ }
166
+ }
114
167
 
115
- <% if turbolinks && !toggle %>
116
- document.addEventListener("turbolinks:load", function (e) {
117
- e.target.removeEventListener(e.type, arguments.callee);
118
- _renderAsyncFunction();
119
- });
168
+ _runAfterDocumentLoaded(_setUpToggle);
120
169
  <% elsif !toggle %>
121
- document.addEventListener("DOMContentLoaded", _renderAsyncFunction);
170
+ _runAfterDocumentLoaded(_renderAsyncFunction);
122
171
  <% end %>
123
172
  })();
@@ -1,3 +1,3 @@
1
1
  module RenderAsync
2
- VERSION = "2.1.2".freeze
2
+ VERSION = "2.1.7".freeze
3
3
  end
@@ -20,7 +20,6 @@ module RenderAsync
20
20
  def render_async(path, options = {}, &placeholder)
21
21
  event_name = options.delete(:event_name)
22
22
  placeholder = capture(&placeholder) if block_given?
23
- retry_count = options.delete(:retry_count) || 0
24
23
  html_options = options.delete(:html_options) || {}
25
24
 
26
25
  render 'render_async/render_async', **container_element_options(options),
@@ -30,8 +29,9 @@ module RenderAsync
30
29
  placeholder: placeholder,
31
30
  **request_options(options),
32
31
  **error_handling_options(options),
33
- retry_count: retry_count,
34
- **polling_options(options)
32
+ **retry_options(options),
33
+ **polling_options(options),
34
+ **content_for_options(options)
35
35
  end
36
36
 
37
37
  private
@@ -53,11 +53,24 @@ module RenderAsync
53
53
  error_event_name: options[:error_event_name] }
54
54
  end
55
55
 
56
+ def retry_options(options)
57
+ {
58
+ retry_count: options.delete(:retry_count) || 0,
59
+ retry_delay: options.delete(:retry_delay)
60
+ }
61
+ end
62
+
56
63
  def polling_options(options)
57
64
  { interval: options[:interval],
58
65
  toggle: options[:toggle] }
59
66
  end
60
67
 
68
+ def content_for_options(options)
69
+ {
70
+ content_for_name: options[:content_for_name] || :render_async
71
+ }
72
+ end
73
+
61
74
  private
62
75
 
63
76
  def generate_container_id
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: render_async
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kasper Grubbe
8
8
  - nikolalsvk
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-08-30 00:00:00.000000000 Z
12
+ date: 2020-08-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -61,6 +61,7 @@ extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
63
  - ".all-contributorsrc"
64
+ - ".github/FUNDING.yml"
64
65
  - ".gitignore"
65
66
  - ".gitmodules"
66
67
  - ".rspec"
@@ -85,7 +86,7 @@ homepage: https://github.com/renderedtext/render_async
85
86
  licenses:
86
87
  - MIT
87
88
  metadata: {}
88
- post_install_message:
89
+ post_install_message:
89
90
  rdoc_options: []
90
91
  require_paths:
91
92
  - lib
@@ -100,9 +101,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
101
  - !ruby/object:Gem::Version
101
102
  version: '0'
102
103
  requirements: []
103
- rubyforge_project:
104
- rubygems_version: 2.7.6
105
- signing_key:
104
+ rubygems_version: 3.0.3
105
+ signing_key:
106
106
  specification_version: 4
107
107
  summary: Render parts of the page asynchronously with AJAX
108
108
  test_files: []