render_async 2.1.5 → 2.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,38 +5,32 @@
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
+ replace_container: replace_container,
12
+ path: path,
13
+ method: method,
14
+ data: data,
15
+ event_name: event_name,
16
+ toggle: toggle,
17
+ headers: headers,
18
+ error_message: error_message,
19
+ error_event_name: error_event_name,
20
+ retry_count: retry_count,
21
+ retry_delay: retry_delay,
22
+ interval: interval,
23
+ turbolinks: RenderAsync.configuration.turbolinks,
24
+ turbo: RenderAsync.configuration.turbo} %>
25
+
10
26
  <% if RenderAsync.configuration.jquery %>
11
27
  <%= render partial: 'render_async/request_jquery',
12
28
  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 } %>
29
+ locals: locals %>
25
30
  <% else %>
26
31
  <%= render partial: 'render_async/request_vanilla',
27
32
  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 } %>
33
+ locals: locals %>
40
34
  <% end %>
41
35
  <% end %>
42
36
  <% end %>
@@ -5,6 +5,11 @@ if (window.jQuery) {
5
5
  return;
6
6
  }
7
7
  <% end %>
8
+ <% if turbo %>
9
+ if (document.documentElement.hasAttribute("data-turbo-preview")) {
10
+ return;
11
+ }
12
+ <% end %>
8
13
  function createEvent(name, container) {
9
14
  var event = undefined;
10
15
  if (typeof(Event) === 'function') {
@@ -18,11 +23,18 @@ if (window.jQuery) {
18
23
  }
19
24
 
20
25
  function _runAfterDocumentLoaded(callback) {
21
- <% if turbolinks %>
22
- $(document).one('turbolinks:load', callback);
23
- <% else %>
24
- $(document).ready(callback);
25
- <% end %>
26
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
27
+ // Handle a case where nested partials get loaded after the document loads
28
+ callback();
29
+ } else {
30
+ <% if turbolinks %>
31
+ $(document).one('turbolinks:load', callback);
32
+ <% elsif turbo %>
33
+ $(document).one('turbo:load', callback);
34
+ <% else %>
35
+ $(document).ready(callback);
36
+ <% end %>
37
+ }
26
38
  }
27
39
 
28
40
  function _makeRequest(currentRetryCount) {
@@ -38,11 +50,15 @@ if (window.jQuery) {
38
50
  headers: headers
39
51
  }).done(function(response) {
40
52
  var container = $("#<%= container_id %>");
41
- <% if interval %>
53
+
54
+ // If user navigated away before the request completed
55
+ if (!container.length) return;
56
+
57
+ <% if !interval && replace_container %>
58
+ container.replaceWith(response);
59
+ <% else %>
42
60
  container.empty();
43
61
  container.append(response);
44
- <% else %>
45
- container.replaceWith(response);
46
62
  <% end %>
47
63
 
48
64
  var loadEvent = createEvent('render_async_load', container);
@@ -61,48 +77,97 @@ if (window.jQuery) {
61
77
  if (skipErrorMessage) return;
62
78
 
63
79
  var container = $("#<%= container_id %>");
80
+ if (!container.length) return;
81
+
64
82
  container.replaceWith("<%= error_message.try(:html_safe) %>");
65
83
 
66
- var errorEvent = createEvent('render_async_error', container);
67
- errorEvent.container = container;
68
- document.dispatchEvent(errorEvent);
84
+ var errorEvent = createEvent(
85
+ "<%= error_event_name || 'render_async_error' %>",
86
+ container
87
+ )
88
+ errorEvent.retryCount = currentRetryCount
69
89
 
70
- <% if error_event_name.present? %>
71
- var event = createEvent("<%= error_event_name %>", container)
72
- document.dispatchEvent(event);
73
- <% end %>
90
+ document.dispatchEvent(errorEvent);
74
91
  });
75
92
  };
76
93
 
77
94
  <% if retry_count > 0 %>
95
+ var _retryMakeRequest = _makeRequest
96
+
97
+ <% if retry_delay %>
98
+ _retryMakeRequest = function(currentRetryCount) {
99
+ setTimeout(function() {
100
+ _makeRequest(currentRetryCount)
101
+ }, <%= retry_delay %>)
102
+ }
103
+ <% end %>
104
+
78
105
  function retry(currentRetryCount) {
79
106
  if (typeof(currentRetryCount) === 'number') {
80
107
  if (currentRetryCount >= <%= retry_count %>)
81
108
  return false;
82
109
 
83
- _makeRequest(currentRetryCount + 1);
110
+ _retryMakeRequest(currentRetryCount + 1);
84
111
  return true;
85
112
  }
86
113
 
87
- _makeRequest(1);
114
+ _retryMakeRequest(1);
88
115
  return true;
89
116
  }
90
117
  <% end %>
91
118
 
92
119
  var _renderAsyncFunction = _makeRequest;
93
120
 
94
- <% if interval %>
95
121
  var _interval;
122
+ <% if interval %>
96
123
  var _renderAsyncFunction = function() {
124
+ // If interval is already set, return
125
+ if (typeof(_interval) === 'number') return
126
+
97
127
  _makeRequest();
98
128
  _interval = setInterval(_makeRequest, <%= interval %>);
99
129
  }
130
+
131
+ var _clearRenderAsyncInterval = function() {
132
+ if (typeof(_interval) === 'number'){
133
+ clearInterval(_interval)
134
+ _interval = undefined;
135
+ }
136
+ }
137
+
138
+ function _setUpControlEvents() {
139
+ var container = $("#<%= container_id %>");
140
+
141
+ // Register a stop polling event on the container
142
+ $(container).on('async-stop', _clearRenderAsyncInterval)
143
+
144
+ // Register a start polling event on the container
145
+ $(container).on('async-start', _renderAsyncFunction)
146
+ }
147
+
148
+ _runAfterDocumentLoaded(_setUpControlEvents)
149
+
150
+ <% if turbolinks %>
151
+ $(document).one('turbolinks:visit', _clearRenderAsyncInterval);
152
+ <% end %>
153
+ <% if turbo %>
154
+ $(document).one('turbo:visit', _clearRenderAsyncInterval);
155
+ <% end %>
156
+ <% end %>
157
+
158
+ <% if !replace_container %>
159
+ function _setUpRefreshEvent() {
160
+ var container = $("#<%= container_id %>");
161
+
162
+ $(container).on('refresh', _renderAsyncFunction)
163
+ }
164
+
165
+ _runAfterDocumentLoaded(_setUpRefreshEvent)
100
166
  <% end %>
101
167
 
102
168
  <% if toggle %>
103
169
  function _setUpToggle() {
104
170
  $(document).<%= toggle[:once] ? 'one' : 'on' %>('<%= toggle[:event] || 'click' %>', '<%= toggle[:selector] %>', function(event) {
105
- event.preventDefault();
106
171
  if (typeof(_interval) === 'number') {
107
172
  clearInterval(_interval);
108
173
  _interval = undefined;
@@ -110,13 +175,17 @@ if (window.jQuery) {
110
175
  _renderAsyncFunction();
111
176
  }
112
177
  });
178
+
179
+ <% if toggle[:start] %>
180
+ _renderAsyncFunction()
181
+ <% end %>
113
182
  }
114
183
 
115
- _runAfterDocumentLoaded(_setUpToggle)
184
+ _runAfterDocumentLoaded(_setUpToggle);
116
185
  <% elsif !toggle %>
117
186
  _runAfterDocumentLoaded(_renderAsyncFunction)
118
187
  <% end %>
119
188
  }(jQuery));
120
189
  } else {
121
- console.warn("Looks like you've enabled jQuery for render_async, but jQuery is not defined");
190
+ console.warn("Looks like you've enabled jQuery for render_async, but jQuery is not defined on the window object");
122
191
  };
@@ -4,6 +4,11 @@
4
4
  return;
5
5
  }
6
6
  <% end %>
7
+ <% if turbo %>
8
+ if (document.documentElement.hasAttribute("data-turbo-preview")) {
9
+ return;
10
+ }
11
+ <% end %>
7
12
  function createEvent(name, container) {
8
13
  var event = undefined;
9
14
  if (typeof(Event) === 'function') {
@@ -22,6 +27,11 @@
22
27
  e.target.removeEventListener(e.type, arguments.callee);
23
28
  callback();
24
29
  });
30
+ <% elsif turbo %>
31
+ document.addEventListener("turbo:load", function(e) {
32
+ e.target.removeEventListener(e.type, arguments.callee);
33
+ callback();
34
+ });
25
35
  <% else %>
26
36
  document.addEventListener("DOMContentLoaded", callback);
27
37
  <% end %>
@@ -44,14 +54,20 @@
44
54
  request.setRequestHeader(key, headers[key]);
45
55
  });
46
56
 
57
+ request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
58
+
47
59
  request.onreadystatechange = function() {
48
60
  if (request.readyState === 4) {
49
61
  if (request.status >= SUCCESS && request.status < ERROR) {
50
62
  var container = document.getElementById('<%= container_id %>');
51
- <% if interval %>
52
- container.innerHTML = request.response;
53
- <% else %>
63
+
64
+ // If user navigated away before the request completed
65
+ if (!container) return;
66
+
67
+ <% if !interval && replace_container %>
54
68
  container.outerHTML = request.response;
69
+ <% else %>
70
+ container.innerHTML = request.response;
55
71
  <% end %>
56
72
 
57
73
  var loadEvent = createEvent('render_async_load', container);
@@ -70,16 +86,17 @@
70
86
  if (skipErrorMessage) return;
71
87
 
72
88
  var container = document.getElementById('<%= container_id %>');
89
+ if (!container) return;
90
+
73
91
  container.outerHTML = '<%= error_message.try(:html_safe) %>';
74
92
 
75
- console.log(container)
76
- var errorEvent = createEvent('render_async_error', container);
77
- document.dispatchEvent(errorEvent);
93
+ var errorEvent = createEvent(
94
+ "<%= error_event_name || 'render_async_error' %>",
95
+ container
96
+ );
97
+ errorEvent.retryCount = currentRetryCount
78
98
 
79
- <% if error_event_name.present? %>
80
- var event = createEvent('<%= error_event_name %>', container);
81
- document.dispatchEvent(event);
82
- <% end %>
99
+ document.dispatchEvent(errorEvent);
83
100
  }
84
101
  }
85
102
  };
@@ -89,35 +106,82 @@
89
106
  };
90
107
 
91
108
  <% if retry_count > 0 %>
109
+
110
+ <% if retry_delay %>
111
+ _retryMakeRequest = function(currentRetryCount) {
112
+ setTimeout(function() {
113
+ _makeRequest(currentRetryCount)
114
+ }, <%= retry_delay %>)
115
+ }
116
+ <% end %>
117
+
92
118
  function retry(currentRetryCount) {
93
119
  if (typeof(currentRetryCount) === 'number') {
94
120
  if (currentRetryCount >= <%= retry_count %>)
95
121
  return false;
96
122
 
97
- _makeRequest(currentRetryCount + 1);
123
+ _retryMakeRequest(currentRetryCount + 1);
98
124
  return true;
99
125
  }
100
126
 
101
- _makeRequest(1);
127
+ _retryMakeRequest(1);
102
128
  return true;
103
129
  }
104
130
  <% end %>
105
131
 
106
132
  var _renderAsyncFunction = _makeRequest;
107
133
 
108
- <% if interval %>
109
134
  var _interval;
135
+ <% if interval %>
110
136
  var _renderAsyncFunction = function() {
137
+ // If interval is already set, return
138
+ if (typeof(_interval) === 'number') return
139
+
111
140
  _makeRequest();
112
141
  _interval = setInterval(_makeRequest, <%= interval %>);
113
142
  }
143
+
144
+ var _clearRenderAsyncInterval = function() {
145
+ if (typeof(_interval) === 'number'){
146
+ clearInterval(_interval)
147
+ _interval = undefined;
148
+ }
149
+ }
150
+
151
+ function _setUpControlEvents() {
152
+ var container = document.getElementById('<%= container_id %>');
153
+
154
+ // Register a polling stop event on the container
155
+ container.addEventListener("async-stop", _clearRenderAsyncInterval)
156
+
157
+ // Register a start polling event on the container
158
+ container.addEventListener("async-start", _renderAsyncFunction)
159
+ }
160
+
161
+ _runAfterDocumentLoaded(_setUpControlEvents)
162
+
163
+ <% if turbolinks %>
164
+ document.addEventListener("turbolinks:visit", _clearRenderAsyncInterval)
165
+ <% end %>
166
+ <% if turbo %>
167
+ document.addEventListener("turbo:visit", _clearRenderAsyncInterval)
168
+ <% end %>
169
+ <% end %>
170
+
171
+ <% if !replace_container %>
172
+ function _setUpRefreshEvent() {
173
+ var container = document.getElementById('<%= container_id %>');
174
+
175
+ container.addEventListener('refresh', _renderAsyncFunction)
176
+ }
177
+
178
+ _runAfterDocumentLoaded(_setUpRefreshEvent)
114
179
  <% end %>
115
180
 
116
181
  <% if toggle %>
117
182
  function _setUpToggle() {
118
- var selectors = document.querySelectorAll('<%= toggle[:selector] %>'), i;
183
+ var selectors = document.querySelectorAll('<%= toggle[:selector] %>');
119
184
  var handler = function(event) {
120
- event.preventDefault();
121
185
  if (typeof(_interval) === 'number') {
122
186
  clearInterval(_interval);
123
187
  _interval = undefined;
@@ -129,7 +193,11 @@
129
193
  <% end %>
130
194
  };
131
195
 
132
- for (i = 0; i < selectors.length; ++i) {
196
+ <% if toggle[:start] %>
197
+ _renderAsyncFunction()
198
+ <% end %>
199
+
200
+ for (var i = 0; i < selectors.length; ++i) {
133
201
  selectors[i].addEventListener('<%= toggle[:event] || 'click' %>', handler)
134
202
  }
135
203
  }
@@ -11,3 +11,10 @@ cd spec/fixtures/rails-5-base-app
11
11
  ls
12
12
  bundle install
13
13
  bundle exec cucumber
14
+
15
+ cd ../../../spec/fixtures/rails-6-base-app
16
+ ls
17
+ bundle install
18
+ yarn install
19
+ RAILS_ENV=test bundle exec rails webpacker:compile
20
+ bundle exec cucumber
@@ -1,10 +1,13 @@
1
1
  module RenderAsync
2
2
  class Configuration
3
- attr_accessor :jquery, :turbolinks
3
+ attr_accessor :jquery, :turbolinks, :turbo, :replace_container, :nonces
4
4
 
5
5
  def initialize
6
6
  @jquery = false
7
7
  @turbolinks = false
8
+ @turbo = false
9
+ @replace_container = true
10
+ @nonces = false
8
11
  end
9
12
  end
10
13
  end
@@ -1,3 +1,3 @@
1
1
  module RenderAsync
2
- VERSION = "2.1.5".freeze
2
+ VERSION = "2.1.10".freeze
3
3
  end
@@ -2,7 +2,6 @@ require 'securerandom'
2
2
 
3
3
  module RenderAsync
4
4
  module ViewHelper
5
-
6
5
  def render_async_cache_key(path)
7
6
  "render_async_#{path}"
8
7
  end
@@ -20,18 +19,17 @@ module RenderAsync
20
19
  def render_async(path, options = {}, &placeholder)
21
20
  event_name = options.delete(:event_name)
22
21
  placeholder = capture(&placeholder) if block_given?
23
- retry_count = options.delete(:retry_count) || 0
24
- html_options = options.delete(:html_options) || {}
25
22
 
26
23
  render 'render_async/render_async', **container_element_options(options),
27
24
  path: path,
28
- html_options: html_options,
25
+ html_options: html_options(options),
29
26
  event_name: event_name,
30
27
  placeholder: placeholder,
31
28
  **request_options(options),
32
29
  **error_handling_options(options),
33
- retry_count: retry_count,
34
- **polling_options(options)
30
+ **retry_options(options),
31
+ **polling_options(options),
32
+ **content_for_options(options)
35
33
  end
36
34
 
37
35
  private
@@ -39,7 +37,16 @@ module RenderAsync
39
37
  def container_element_options(options)
40
38
  { html_element_name: options[:html_element_name] || 'div',
41
39
  container_id: options[:container_id] || generate_container_id,
42
- container_class: options[:container_class] }
40
+ container_class: options[:container_class],
41
+ replace_container: replace_container(options) }
42
+ end
43
+
44
+ def html_options(options)
45
+ set_options = options.delete(:html_options) || {}
46
+
47
+ set_options[:nonce] = configuration.nonces if set_options[:nonce].nil?
48
+
49
+ set_options
43
50
  end
44
51
 
45
52
  def request_options(options)
@@ -53,15 +60,36 @@ module RenderAsync
53
60
  error_event_name: options[:error_event_name] }
54
61
  end
55
62
 
63
+ def retry_options(options)
64
+ {
65
+ retry_count: options.delete(:retry_count) || 0,
66
+ retry_delay: options.delete(:retry_delay)
67
+ }
68
+ end
69
+
56
70
  def polling_options(options)
57
71
  { interval: options[:interval],
58
72
  toggle: options[:toggle] }
59
73
  end
60
74
 
61
- private
75
+ def content_for_options(options)
76
+ {
77
+ content_for_name: options[:content_for_name] || :render_async
78
+ }
79
+ end
62
80
 
63
81
  def generate_container_id
64
82
  "render_async_#{SecureRandom.hex(5)}#{Time.now.to_i}"
65
83
  end
84
+
85
+ def replace_container(options)
86
+ return options[:replace_container] unless options[:replace_container].nil?
87
+
88
+ configuration.replace_container
89
+ end
90
+
91
+ def configuration
92
+ RenderAsync.configuration
93
+ end
66
94
  end
67
95
  end