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 51 // Link elements bound by jquery-ujs
52 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 57 // Form elements bound by jquery-ujs
58 58 formSubmitSelector: 'form',
... ... @@ -85,9 +85,22 @@
85 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 97 // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
89 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 106 // Default ajax function, may be overridden with custom function in $.rails.ajax
... ... @@ -97,9 +110,10 @@
97 110  
98 111 // Submits "remote" forms and links with ajax
99 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 118 if (rails.fire(element, 'ajax:before')) {
105 119  
... ... @@ -108,7 +122,7 @@
108 122 url = element.attr('action');
109 123 data = element.serializeArray();
110 124 // memoized value from clicked submit button
111   - var button = element.data('ujs:submit-button');
  125 + button = element.data('ujs:submit-button');
112 126 if (button) {
113 127 data.push(button);
114 128 element.data('ujs:submit-button', null);
... ... @@ -119,9 +133,9 @@
119 133 data = element.serialize();
120 134 if (element.data('params')) data = data + "&" + element.data('params');
121 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 141 options = {
... ... @@ -143,8 +157,8 @@
143 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 163 rails.ajax(options);
150 164 }
... ... @@ -154,14 +168,19 @@
154 168 // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
155 169 handleMethod: function(link) {
156 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 186 form.hide().append(metadata_input).appendTo('body');
... ... @@ -175,7 +194,9 @@
175 194 */
176 195 disableFormElements: function(form) {
177 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 200 element.data('ujs:enable-with', element[method]());
180 201 element[method](element.data('disable-with'));
181 202 element.attr('disabled', 'disabled');
... ... @@ -188,7 +209,9 @@
188 209 */
189 210 enableFormElements: function(form) {
190 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 215 if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
193 216 element.removeAttr('disabled');
194 217 });
... ... @@ -206,20 +229,36 @@
206 229 */
207 230 allowAction: function(element) {
208 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 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 257 // Helper function which checks for blank inputs in a form that match the specified CSS selector
220 258 blankInputs: function(form, specifiedSelector, nonBlank) {
221 259 var inputs = $(), input,
222   - selector = specifiedSelector || 'input,textarea';
  260 + selector = specifiedSelector || 'input,textarea';
  261 +
223 262 form.find(selector).each(function() {
224 263 input = $(this);
225 264 // Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs
... ... @@ -246,6 +285,7 @@
246 285 // manually invoke them. If anyone returns false then stop the loop
247 286 callFormSubmitBindings: function(form) {
248 287 var events = form.data('events'), continuePropagation = true;
  288 +
249 289 if (events !== undefined && events['submit'] !== undefined) {
250 290 $.each(events['submit'], function(i, obj){
251 291 if (typeof obj.handler === 'function') return continuePropagation = obj.handler(obj.data);
... ... @@ -259,65 +299,99 @@
259 299  
260 300 $(rails.linkClickSelector).live('click.rails', function(e) {
261 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 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 334 $(rails.formSubmitSelector).live('submit.rails', function(e) {
282 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 376 $(rails.formInputClickSelector).live('click.rails', function(event) {
312 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 397 $(rails.formSubmitSelector).live('ajax:beforeSend.rails', function(event) {
... ... @@ -329,3 +403,4 @@
329 403 });
330 404  
331 405 })( jQuery );
  406 +
... ...