render_async 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7348b088d336af949c92c6132a741fac0d1ccdda790d216fcd4a8bfba852dc0
4
- data.tar.gz: 0ad8ed64d193321f04d6c623e4ed18992cd5638f0302a8736242c135dabb17ef
3
+ metadata.gz: 301c0dec3cac35c32dd7946334151d2c968fe8f182006b1e67e4fc21655e1899
4
+ data.tar.gz: 0df8c63b19c81621726efb95c993377caa81c554ba29d29d782451f5a4116d21
5
5
  SHA512:
6
- metadata.gz: 68b8ebb7fa1bc91b5dcb51f7f86bde67fa404cb4159f73e98c1d75bb54ee9775f2cf13ef5373d2c1d8750ff9130dfa28fab3a85bffe1649eb529becba0006f32
7
- data.tar.gz: 3809facb7cb728243aaed8d215dd29607c88baec7781b2df109cc7b91223d2fc919903db3a72c6b5ba2222739323964785e7cb34c0dff8b9e841113756095e2c
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 'Sender_async'
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, :controller => :comments
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 :partial => "comment_stats"
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 HTML options
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` takes two arguments, `path` and `html_options`.
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
- * `path` is the AJAX-capable controller action you're looking to call via
91
- `GET`. e.g. `comments_stats_path`, `posts_path`, etc.
92
- * `html_options` is an optional hash that gets passed to a rails
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, :event_name => "users-loaded" %>
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), :skip_digest => true do %>
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 :partial => "comment_stats"
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 :partial => "comment_stats", :content_type => 'text/html'
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 %> id="<%= container_id %>">
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
- <%= render partial: 'render_async/request',
8
- formats: [:js],
9
- locals: { container_id: container_id,
10
- path: path,
11
- method: method,
12
- data: data,
13
- event_name: event_name,
14
- headers: headers } %>
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
@@ -0,0 +1,9 @@
1
+ module RenderAsync
2
+ class Configuration
3
+ attr_accessor :jquery
4
+
5
+ def initialize
6
+ @jquery = false
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module RenderAsync
2
- VERSION = "1.3.0".freeze
2
+ VERSION = "1.4.0".freeze
3
3
  end
@@ -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 = "render_async_#{SecureRandom.hex(5)}#{Time.now.to_i}"
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.3.0
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/_request.js.erb
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
- }