Commit 294e4799b8a088a7a190f9a1f52cb9b08c412d64

Authored by Akzhan Abdulin
1 parent a1eb6072
Exists in master and in 1 other branch production

Use rails.js from async-confirm branch (at 78cc23f48be30d1804920b8e979ea23167a2dcfb)

Showing 1 changed file with 143 additions and 68 deletions   Show diff stats
public/javascripts/rails.js
@@ -51,8 +51,8 @@ @@ -51,8 +51,8 @@
51 // Link elements bound by jquery-ujs 51 // Link elements bound by jquery-ujs
52 linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]', 52 linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]',
53 53
54 - // Select elements bound by jquery-ujs  
55 - selectChangeSelector: 'select[data-remote]', 54 + // Select elements bound by jquery-ujs
  55 + selectChangeSelector: 'select[data-remote]',
56 56
57 // Form elements bound by jquery-ujs 57 // Form elements bound by jquery-ujs
58 formSubmitSelector: 'form', 58 formSubmitSelector: 'form',
@@ -85,9 +85,22 @@ @@ -85,9 +85,22 @@
85 return event.result !== false; 85 return event.result !== false;
86 }, 86 },
87 87
  88 + resolveOrReject: function(deferred, resolved) {
  89 + if (resolved) {
  90 + deferred.resolve();
  91 + } else {
  92 + deferred.reject();
  93 + }
  94 + return deferred;
  95 + },
  96 +
88 // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm 97 // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
89 confirm: function(message) { 98 confirm: function(message) {
90 - return confirm(message); 99 + var res = confirm(message),
  100 + answer = $.Deferred();
  101 +
  102 + rails.resolveOrReject(answer, res);
  103 + return answer.promise();
91 }, 104 },
92 105
93 // Default ajax function, may be overridden with custom function in $.rails.ajax 106 // Default ajax function, may be overridden with custom function in $.rails.ajax
@@ -97,9 +110,10 @@ @@ -97,9 +110,10 @@
97 110
98 // Submits "remote" forms and links with ajax 111 // Submits "remote" forms and links with ajax
99 handleRemote: function(element) { 112 handleRemote: function(element) {
100 - var method, url, data,  
101 - crossDomain = element.data('cross-domain') || null,  
102 - dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); 113 + var method, url, data, button,
  114 + crossDomain = element.data('cross-domain') || null,
  115 + dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType),
  116 + options;
103 117
104 if (rails.fire(element, 'ajax:before')) { 118 if (rails.fire(element, 'ajax:before')) {
105 119
@@ -108,7 +122,7 @@ @@ -108,7 +122,7 @@
108 url = element.attr('action'); 122 url = element.attr('action');
109 data = element.serializeArray(); 123 data = element.serializeArray();
110 // memoized value from clicked submit button 124 // memoized value from clicked submit button
111 - var button = element.data('ujs:submit-button'); 125 + button = element.data('ujs:submit-button');
112 if (button) { 126 if (button) {
113 data.push(button); 127 data.push(button);
114 element.data('ujs:submit-button', null); 128 element.data('ujs:submit-button', null);
@@ -119,9 +133,9 @@ @@ -119,9 +133,9 @@
119 data = element.serialize(); 133 data = element.serialize();
120 if (element.data('params')) data = data + "&" + element.data('params'); 134 if (element.data('params')) data = data + "&" + element.data('params');
121 } else { 135 } else {
122 - method = element.data('method');  
123 - url = element.attr('href');  
124 - data = element.data('params') || null; 136 + method = element.data('method');
  137 + url = element.attr('href');
  138 + data = element.data('params') || null;
125 } 139 }
126 140
127 options = { 141 options = {
@@ -143,8 +157,8 @@ @@ -143,8 +157,8 @@
143 element.trigger('ajax:error', [xhr, status, error]); 157 element.trigger('ajax:error', [xhr, status, error]);
144 } 158 }
145 }; 159 };
146 - // Do not pass url to `ajax` options if blank  
147 - if (url) { $.extend(options, { url: url }); } 160 + // Only pass url to `ajax` options if not blank
  161 + if (url) { options.url = url; }
148 162
149 rails.ajax(options); 163 rails.ajax(options);
150 } 164 }
@@ -154,14 +168,19 @@ @@ -154,14 +168,19 @@
154 // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a> 168 // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
155 handleMethod: function(link) { 169 handleMethod: function(link) {
156 var href = link.attr('href'), 170 var href = link.attr('href'),
157 - method = link.data('method'),  
158 - csrf_token = $('meta[name=csrf-token]').attr('content'),  
159 - csrf_param = $('meta[name=csrf-param]').attr('content'),  
160 - form = $('<form method="post" action="' + href + '"></form>'),  
161 - metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';  
162 -  
163 - if (csrf_param !== undefined && csrf_token !== undefined) {  
164 - metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />'; 171 + method = link.data('method') || 'GET',
  172 + csrf_token = $('meta[name=csrf-token]').attr('content'),
  173 + csrf_param = $('meta[name=csrf-param]').attr('content'),
  174 + form = $('<form></form>', { action: href, method: method, 'data-ujs-generated': 'true' }),
  175 + metadata_input = '';
  176 +
  177 + if (method !== 'GET') {
  178 + form.attr('method', 'POST');
  179 + metadata_input += '<input name="_method" value="' + method + '" type="hidden" />';
  180 +
  181 + if (csrf_param !== undefined && csrf_token !== undefined) {
  182 + metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
  183 + }
165 } 184 }
166 185
167 form.hide().append(metadata_input).appendTo('body'); 186 form.hide().append(metadata_input).appendTo('body');
@@ -175,7 +194,9 @@ @@ -175,7 +194,9 @@
175 */ 194 */
176 disableFormElements: function(form) { 195 disableFormElements: function(form) {
177 form.find(rails.disableSelector).each(function() { 196 form.find(rails.disableSelector).each(function() {
178 - var element = $(this), method = element.is('button') ? 'html' : 'val'; 197 + var element = $(this),
  198 + method = element.is('button') ? 'html' : 'val';
  199 +
179 element.data('ujs:enable-with', element[method]()); 200 element.data('ujs:enable-with', element[method]());
180 element[method](element.data('disable-with')); 201 element[method](element.data('disable-with'));
181 element.attr('disabled', 'disabled'); 202 element.attr('disabled', 'disabled');
@@ -188,7 +209,9 @@ @@ -188,7 +209,9 @@
188 */ 209 */
189 enableFormElements: function(form) { 210 enableFormElements: function(form) {
190 form.find(rails.enableSelector).each(function() { 211 form.find(rails.enableSelector).each(function() {
191 - var element = $(this), method = element.is('button') ? 'html' : 'val'; 212 + var element = $(this),
  213 + method = element.is('button') ? 'html' : 'val';
  214 +
192 if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with')); 215 if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
193 element.removeAttr('disabled'); 216 element.removeAttr('disabled');
194 }); 217 });
@@ -206,20 +229,36 @@ @@ -206,20 +229,36 @@
206 */ 229 */
207 allowAction: function(element) { 230 allowAction: function(element) {
208 var message = element.data('confirm'), 231 var message = element.data('confirm'),
209 - answer = false, callback;  
210 - if (!message) { return true; } 232 + confirmAnswer,
  233 + answer = $.Deferred();
  234 +
  235 + if (!message) { return $.when(true); }
211 236
212 if (rails.fire(element, 'confirm')) { 237 if (rails.fire(element, 'confirm')) {
213 - answer = rails.confirm(message);  
214 - callback = rails.fire(element, 'confirm:complete', [answer]); 238 + confirmAnswer = rails.confirm(message);
  239 + confirmAnswer.then(
  240 + function() {
  241 + var callbackOk = rails.fire(element, 'confirm:complete', [ true ]);
  242 + rails.resolveOrReject(answer, callbackOk);
  243 + },
  244 + function() {
  245 + rails.fire(element, 'confirm:complete', [ false ]);
  246 + answer.reject();
  247 + }
  248 + );
  249 + return answer.promise();
  250 + // If `confirm` event handler returned false...
  251 + } else {
  252 + answer.reject();
  253 + return answer.promise();
215 } 254 }
216 - return answer && callback;  
217 }, 255 },
218 256
219 // Helper function which checks for blank inputs in a form that match the specified CSS selector 257 // Helper function which checks for blank inputs in a form that match the specified CSS selector
220 blankInputs: function(form, specifiedSelector, nonBlank) { 258 blankInputs: function(form, specifiedSelector, nonBlank) {
221 var inputs = $(), input, 259 var inputs = $(), input,
222 - selector = specifiedSelector || 'input,textarea'; 260 + selector = specifiedSelector || 'input,textarea';
  261 +
223 form.find(selector).each(function() { 262 form.find(selector).each(function() {
224 input = $(this); 263 input = $(this);
225 // Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs 264 // Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs
@@ -246,6 +285,7 @@ @@ -246,6 +285,7 @@
246 // manually invoke them. If anyone returns false then stop the loop 285 // manually invoke them. If anyone returns false then stop the loop
247 callFormSubmitBindings: function(form) { 286 callFormSubmitBindings: function(form) {
248 var events = form.data('events'), continuePropagation = true; 287 var events = form.data('events'), continuePropagation = true;
  288 +
249 if (events !== undefined && events['submit'] !== undefined) { 289 if (events !== undefined && events['submit'] !== undefined) {
250 $.each(events['submit'], function(i, obj){ 290 $.each(events['submit'], function(i, obj){
251 if (typeof obj.handler === 'function') return continuePropagation = obj.handler(obj.data); 291 if (typeof obj.handler === 'function') return continuePropagation = obj.handler(obj.data);
@@ -259,65 +299,99 @@ @@ -259,65 +299,99 @@
259 299
260 $(rails.linkClickSelector).live('click.rails', function(e) { 300 $(rails.linkClickSelector).live('click.rails', function(e) {
261 var link = $(this); 301 var link = $(this);
262 - if (!rails.allowAction(link)) return rails.stopEverything(e);  
263 302
264 - if (link.data('remote') !== undefined) {  
265 - rails.handleRemote(link);  
266 - return false;  
267 - } else if (link.data('method')) {  
268 - rails.handleMethod(link);  
269 - return false;  
270 - } 303 + rails.allowAction(link).then(
  304 + function() {
  305 + if (link.data('remote') !== undefined) {
  306 + rails.handleRemote(link);
  307 + } else {
  308 + rails.handleMethod(link);
  309 + }
  310 + },
  311 + function() {
  312 + rails.stopEverything(e);
  313 + }
  314 + );
  315 +
  316 + e.preventDefault();
271 }); 317 });
272 318
273 - $(rails.selectChangeSelector).live('change.rails', function(e) { 319 + $(rails.selectChangeSelector).live('change.rails', function(e) {
274 var link = $(this); 320 var link = $(this);
275 - if (!rails.allowAction(link)) return rails.stopEverything(e);  
276 321
277 - rails.handleRemote(link);  
278 - return false;  
279 - }); 322 + rails.allowAction(link).then(
  323 + function() {
  324 + rails.handleRemote(link);
  325 + },
  326 + function() {
  327 + rails.stopEverything(e);
  328 + }
  329 + );
  330 +
  331 + e.preventDefault();
  332 + });
280 333
281 $(rails.formSubmitSelector).live('submit.rails', function(e) { 334 $(rails.formSubmitSelector).live('submit.rails', function(e) {
282 var form = $(this), 335 var form = $(this),
283 - remote = form.data('remote') !== undefined,  
284 - blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),  
285 - nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); 336 + remote = (form.data('remote') !== undefined),
  337 + blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
  338 + nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
  339 +
  340 + rails.allowAction(form).then(
  341 + function() {
  342 + // skip other logic when required values are missing or file upload is present
  343 + if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
  344 + return rails.stopEverything(e);
  345 + }
286 346
287 - if (!rails.allowAction(form)) return rails.stopEverything(e); 347 + if (remote) {
  348 + if (nonBlankFileInputs) {
  349 + return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
  350 + }
288 351
289 - // skip other logic when required values are missing or file upload is present  
290 - if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {  
291 - return rails.stopEverything(e);  
292 - } 352 + // If browser does not support submit bubbling, then this live-binding will be called before direct
  353 + // bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
  354 + if (!$.support.submitBubbles && rails.callFormSubmitBindings(form) === false) return rails.stopEverything(e);
293 355
294 - if (remote) {  
295 - if (nonBlankFileInputs) {  
296 - return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]); 356 + rails.handleRemote(form);
  357 + } else {
  358 + // slight timeout so that the submit button gets properly serialized
  359 + setTimeout(function() {
  360 + rails.disableFormElements(form);
  361 + // Submit the form from dom-level js (i.e. *not* via jquery),
  362 + // which will skip all submit bindings (including this live-binding),
  363 + // since they have already been called.
  364 + form.get(0).submit();
  365 + }, 13);
  366 + }
  367 + },
  368 + function() {
  369 + rails.stopEverything(e);
297 } 370 }
  371 + );
298 372
299 - // If browser does not support submit bubbling, then this live-binding will be called before direct  
300 - // bindings. Therefore, we should directly call any direct bindings before remotely submitting form.  
301 - if (!$.support.submitBubbles && rails.callFormSubmitBindings(form) === false) return rails.stopEverything(e);  
302 -  
303 - rails.handleRemote(form);  
304 - return false;  
305 - } else {  
306 - // slight timeout so that the submit button gets properly serialized  
307 - setTimeout(function(){ rails.disableFormElements(form); }, 13);  
308 - } 373 + e.preventDefault();
309 }); 374 });
310 375
311 $(rails.formInputClickSelector).live('click.rails', function(event) { 376 $(rails.formInputClickSelector).live('click.rails', function(event) {
312 var button = $(this); 377 var button = $(this);
313 378
314 - if (!rails.allowAction(button)) return rails.stopEverything(event);  
315 -  
316 - // register the pressed submit button  
317 - var name = button.attr('name'),  
318 - data = name ? {name:name, value:button.val()} : null; 379 + rails.allowAction(button).then(
  380 + function() {
  381 + // register the pressed submit button
  382 + var name = button.attr('name'), form,
  383 + data = name ? {name:name, value:button.val()} : null;
  384 +
  385 + form = button.closest('form');
  386 + form.data('ujs:submit-button', data);
  387 + form.submit();
  388 + },
  389 + function() {
  390 + rails.stopEverything(event);
  391 + }
  392 + );
319 393
320 - button.closest('form').data('ujs:submit-button', data); 394 + e.preventDefault();
321 }); 395 });
322 396
323 $(rails.formSubmitSelector).live('ajax:beforeSend.rails', function(event) { 397 $(rails.formSubmitSelector).live('ajax:beforeSend.rails', function(event) {
@@ -329,3 +403,4 @@ @@ -329,3 +403,4 @@
329 }); 403 });
330 404
331 })( jQuery ); 405 })( jQuery );
  406 +