render_async 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml 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
- }