PluginProbe
Social Media Auto Poster – Schedule & Publish to Buffer / 6.2.5
Social Media Auto Poster – Schedule & Publish to Buffer v6.2.5
6.2.5 6.2.4 6.2.3 6.2.2 6.2.1 6.2.0 6.1.2 6.1.1 6.1.0 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 6.0.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 All 126 releases
wp-to-buffer / lib / shared / js / synchronous-ajax.js

synchronous-ajax.js in Social Media Auto Poster – Schedule & Publish to Buffer 6.2.5, at lib/shared/js/synchronous-ajax.js

360 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Synchronous AJAX Requests.
3 *
4 * This jQuery plugin allows feature rich web applications to send a specified number of requests, sequentially and synchronously,
5 * to a given endpoint, binding the progress feedback to a jQuery UI Progressbar.
6 *
7 * This plugin acts as a wrapper for $.post, with some extra callback functions when each request succeeds or fails, plus a final
8 * callback function when the entire routine completes.
9 *
10 * The advantage of this approach is that the UI is not locked - so updates can be posted to the web page - and the server isn't flooded
11 * with 100 requests at once. Each request must complete before the next one can run.
12 *
13 * Your server-side script will be sent all data as a POST array, including POST['current_index'], telling your script what number this
14 * request is.
15 *
16 * @package WPZincDashboardWidget
17 * @author WP Zinc
18 */
19
20 ( function ( $ ) {
21
22 /**
23 * Init Synchronous Request
24 *
25 * @param object options Override Default Settings
26 */
27 $.fn.synchronous_request = function ( options ) {
28
29 // Default Settings.
30 let settings = $.extend(
31 {
32 // Required.
33 url: '', // AJAX url.
34 number_requests:0, // Total number of requests that will be sent.
35 offset: 0, // The offset to start at.
36 index_increment:1, // The number to increment the current index by after each request.
37 action: '', // The WordPress registered AJAX action name to use for each request.
38 nonce: '', // WordPress nonce, which your AJAX function should validate.
39 ids: '', // Array of IDs or keys to iterate through, sending one with each request.
40 wait: 5000, // Number of milliseconds to wait.
41 stop_on_error: 0, // 1: stop, 0: continue and retry the same request, -1: continue but skip the failed request.
42
43 // Optional.
44 progress_count: '#progress-number', // DOM selector that contains successful request count.
45 log: '#log', // DOM selector for the log.
46 spinner: '#progress .spinner', // DOM selector for the spinner.
47 cancel_button: '.cancel', // DOM selector for the cancel button.
48 type: 'post', // AJAX request type.
49 cache: false, // Whether to cache requests.
50 dataType: 'json', // Response data type.
51
52 /**
53 * Called when an AJAX request returns a successful response.
54 *
55 * @since 1.0.0
56 *
57 * @param object response Response
58 * @param int currentIndex Current Index
59 */
60 onRequestSuccess: function ( response, currentIndex ) {
61
62 // Maybe reset log if it's more than 100 lines, for UI performance.
63 this.maybeResetLog();
64
65 if ( response.success ) {
66 // Output Log.
67 $( 'ul', $( this.log ) ).append( '<li class="success">' + ( currentIndex + 1 ) + '/' + this.number_requests + ': ' + response.data + '</li>' );
68 } else {
69 // Something went wrong.
70 // Define message.
71 let message = ( currentIndex + 1 ) + '/' + this.number_requests + ': Response Error: ' + response.data;
72 switch ( this.stop_on_error ) {
73 // Stop sending any further requests.
74 case 1:
75 break;
76
77 // Continue, reattempting the failed request.
78 case 0:
79 message = message + '. Waiting ' + ( this.stop_on_error_pause / 1000 ) + ' seconds before reattempting this request.';
80 break;
81
82 // Continue, skipping the failed request.
83 case -1:
84 message = message + '. Waiting ' + ( this.stop_on_error_pause / 1000 ) + ' seconds before attempting next request.';
85 break;
86 }
87
88 // Output Log.
89 $( 'ul', $( this.log ) ).append( '<li class="error">' + message + '</li>' );
90 }
91
92 // Run the next request, unless the user clicked the 'Stop Generation' button.
93 if ( this.cancelled == true ) {
94 return false;
95 }
96
97 // Run the next request.
98 return true;
99
100 },
101
102 /**
103 * Called when an AJAX request results in a HTTP or server error.
104 *
105 * @since 1.0.0
106 */
107 onRequestError: function ( xhr, textStatus, e, currentIndex ) {
108
109 // Maybe reset log if it's more than 100 lines, for UI performance.
110 this.maybeResetLog();
111
112 // Output Log.
113 $( '#log ul' ).append( '<li class="error">' + ( currentIndex + 1 ) + '/' + settings.number_requests + ': Request Error: ' + xhr.status + ' ' + xhr.statusText + '</li>' );
114
115 // Run the next request, unless the user clicked the cancel button.
116 if ( this.cancelled == true ) {
117 return false;
118 }
119
120 // Try again.
121 return true;
122
123 },
124
125 /**
126 * Change any settings configuration, which will be included in the next request.
127 *
128 * Called immediately before the next request is made, if the current request
129 * was successful.
130 *
131 * @since 1.0.0
132 *
133 * @param object settings Settings.
134 * @return object Settings
135 */
136 updateSettings: function ( settings ) {
137
138 return settings;
139
140 },
141
142 /**
143 * Called when all requests have completed, or the user cancelled.
144 *
145 * @since 1.0.0
146 */
147 onFinished: function () {
148
149 if ( this.cancelled ) {
150 $( 'ul', $( this.log ) ).append( '<li class="success">Process cancelled by user.</li>' );
151 } else {
152 $( 'ul', $( this.log ) ).append( '<li class="success">Finished.</li>' );
153
154 // Disable the cancel button.
155 $( settings.cancel_button ).attr( 'disabled', 'disabled' );
156 }
157
158 // Remove the spinner.
159 $( this.spinner ).remove();
160
161 },
162
163 /**
164 * If the on screen log exceeds 100 entries, clear it
165 * for UI / browser performance.
166 *
167 * @since 1.0.0
168 */
169 maybeResetLog: function () {
170
171 // If the spinner exists in the log, remove it.
172 if ( $( 'li.spinner', $( this.log ) ).length > 0 ) {
173 $( 'li.spinner', $( this.log ) ).remove();
174 }
175
176 // If the log exceeds 100 items, reset it.
177 if ( $( 'ul li', $( this.log ) ).length >= 100 ) {
178 $( 'ul', $( this.log ) ).html( '' );
179 }
180
181 }
182 },
183 options
184 );
185
186 // Initialize Progress Bar.
187 progressbar = $( this ).progressbar(
188 {
189 value: 0
190 }
191 );
192
193 // Bind a listener to the cancel button.
194 if ( settings.cancel_button ) {
195
196 $( settings.cancel_button ).on(
197 'click',
198 function ( e ) {
199
200 e.preventDefault();
201 settings.cancelled = true;
202
203 // Disable the cancel button.
204 $( settings.cancel_button ).attr( 'disabled', 'disabled' );
205
206 }
207 );
208
209 }
210
211 // Initialize first request.
212 synchronousAjaxRequest( settings, ( -1 + Number( settings.offset ) ), progressbar, settings.progress_count, true );
213
214 };
215
216 /**
217 * Main function to perform an AJAX request.
218 *
219 * @since 1.0.0
220 */
221 function synchronousAjaxRequest( settings, currentIndex, progressbar, progressCounter, isFirstRequest ) {
222
223 if ( isFirstRequest ) {
224 currentIndex++;
225 } else {
226 currentIndex = currentIndex + Number( settings.index_increment );
227 }
228
229 // If currentIndex exceeds or equals settings.number_requests, we have finished
230 // currentIndex is a zero based count.
231 if ( currentIndex > ( Number( settings.offset ) + Number( settings.number_requests ) - 1 ) ) {
232 // Call completion closure.
233 settings.onFinished();
234 return true;
235 }
236
237 // Merge data.
238 let data = {
239 action: settings.action,
240 nonce: settings.nonce,
241 id: settings.ids[ currentIndex ],
242 current_index: currentIndex,
243 index_increment:settings.index_increment,
244 number_requests:settings.number_requests,
245 offset: settings.offset,
246 };
247 let mergedData = {...data, ...settings.data};
248
249 // Send AJAX request.
250 $.ajax(
251 {
252 url: settings.url,
253 type: settings.type,
254 async: true,
255 cache: settings.cache,
256 dataType: settings.dataType,
257 data: mergedData,
258 success: function ( response ) {
259
260 // Call onRequestSuccess closure.
261 let cancelled = settings.onRequestSuccess( response, currentIndex );
262
263 // Define the count, ensuring it doesn't go above the number of requests.
264 let nextIndex = currentIndex + Number( settings.index_increment );
265 if ( nextIndex > settings.number_requests ) {
266 nextIndex = settings.number_requests;
267 }
268
269 // If the response indicates success, update the progress bar and count.
270 if ( response.success ) {
271 // Update progress bar and text count.
272 progressbar.progressbar( 'value', Number( ( nextIndex / settings.number_requests ) * 100 ) );
273 $( progressCounter ).text( nextIndex );
274 } else {
275 // If Stop on Error is enabled, call onFinished closure and exit.
276 if ( settings.stop_on_error == 1 ) {
277 settings.onFinished();
278 return;
279 }
280
281 // If Stop on Error is -1, update the progress bar and count as this request won't be retried.
282 if ( settings.stop_on_error == -1 ) {
283 progressbar.progressbar( 'value', Number( ( nextIndex / settings.number_requests ) * 100 ) );
284 $( progressCounter ).text( nextIndex );
285 }
286
287 // If Stop on Error is zero, decrement the currentIndex so the same request is attempted again.
288 if ( settings.stop_on_error == 0 ) {
289 currentIndex = currentIndex - Number( settings.index_increment );
290 }
291 }
292
293 // If false was returned from the closure, the calling script has requested we stop the loop
294 // Call onFinished closure and exit.
295 if ( ! cancelled ) {
296 settings.onFinished();
297 return;
298 }
299
300 // If the response indicates an error, wait the required period of time before sending the
301 // next request.
302 if ( ! response.success && settings.stop_on_error !== -1 ) {
303 setTimeout(
304 function () {
305 // Start next request.
306 synchronousAjaxRequest( settings, currentIndex, progressbar, progressCounter );
307 return;
308 },
309 settings.wait
310 );
311 } else {
312 // Call updateSettings closure.
313 settings = settings.updateSettings( settings );
314
315 // Start next request.
316 synchronousAjaxRequest( settings, currentIndex, progressbar, progressCounter );
317 return;
318 }
319
320 },
321 error: function (xhr, textStatus, e) {
322
323 // Call closure.
324 let cancelled = settings.onRequestError( xhr, textStatus, e, currentIndex );
325
326 // If Stop on Error is enabled, call onFinished closure and exit.
327 if ( settings.stop_on_error == 1 ) {
328 settings.onFinished();
329 return;
330 }
331
332 // If stop on Error is zero, decrement the currentIndex so the same request is attempted again.
333 if ( settings.stop_on_error == 0 ) {
334 currentIndex--;
335 }
336
337 // If false was returned from the closure, the calling script has requested we stop the loop.
338 // Call onFinished closure and exit.
339 if ( ! cancelled ) {
340 settings.onFinished();
341 return;
342 }
343
344 // Wait the required period of time before sending the next request.
345 setTimeout(
346 function () {
347 // Start next request.
348 synchronousAjaxRequest( settings, currentIndex, progressbar, progressCounter );
349 return;
350 },
351 settings.wait
352 );
353
354 }
355 }
356 );
357 }
358
359 } )( jQuery );
360