|
22 | 22 |
|
23 | 23 | $.rails = rails = {
|
24 | 24 | // Link elements bound by jquery-ujs
|
25 |
| - linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]', |
| 25 | + linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with], a[data-disable]', |
26 | 26 |
|
27 | 27 | // Button elements bound by jquery-ujs
|
28 |
| - buttonClickSelector: 'button[data-remote]', |
| 28 | + buttonClickSelector: 'button[data-remote], button[data-confirm]', |
29 | 29 |
|
30 | 30 | // Select elements bound by jquery-ujs
|
31 | 31 | inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
|
|
37 | 37 | formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])',
|
38 | 38 |
|
39 | 39 | // Form input elements disabled during form submission
|
40 |
| - disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]', |
| 40 | + disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled', |
41 | 41 |
|
42 | 42 | // Form input elements re-enabled after form submission
|
43 |
| - enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled', |
| 43 | + enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled', |
44 | 44 |
|
45 | 45 | // Form required input elements
|
46 | 46 | requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
|
|
49 | 49 | fileInputSelector: 'input[type=file]',
|
50 | 50 |
|
51 | 51 | // Link onClick disable selector with possible reenable after remote submission
|
52 |
| - linkDisableSelector: 'a[data-disable-with]', |
| 52 | + linkDisableSelector: 'a[data-disable-with], a[data-disable]', |
| 53 | + |
| 54 | + // Button onClick disable selector with possible reenable after remote submission |
| 55 | + buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]', |
53 | 56 |
|
54 | 57 | // Make sure that every Ajax request sends the CSRF token
|
55 | 58 | CSRFProtection: function(xhr) {
|
|
129 | 132 | if (settings.dataType === undefined) {
|
130 | 133 | xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
|
131 | 134 | }
|
132 |
| - return rails.fire(element, 'ajax:beforeSend', [xhr, settings]); |
| 135 | + if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) { |
| 136 | + element.trigger('ajax:send', xhr); |
| 137 | + } else { |
| 138 | + return false; |
| 139 | + } |
133 | 140 | },
|
134 | 141 | success: function(data, status, xhr) {
|
135 | 142 | element.trigger('ajax:success', [data, status, xhr]);
|
|
154 | 161 | // Only pass url to `ajax` options if not blank
|
155 | 162 | if (url) { options.url = url; }
|
156 | 163 |
|
157 |
| - var jqxhr = rails.ajax(options); |
158 |
| - element.trigger('ajax:send', jqxhr); |
159 |
| - return jqxhr; |
| 164 | + return rails.ajax(options); |
160 | 165 | } else {
|
161 | 166 | return false;
|
162 | 167 | }
|
|
183 | 188 | form.submit();
|
184 | 189 | },
|
185 | 190 |
|
| 191 | + // Helper function that returns form elements that match the specified CSS selector |
| 192 | + // If form is actually a "form" element this will return associated elements outside the from that have |
| 193 | + // the html form attribute set |
| 194 | + formElements: function(form, selector) { |
| 195 | + return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector); |
| 196 | + }, |
| 197 | + |
186 | 198 | /* Disables form elements:
|
187 | 199 | - Caches element value in 'ujs:enable-with' data store
|
188 | 200 | - Replaces element text with value of 'data-disable-with' attribute
|
189 | 201 | - Sets disabled property to true
|
190 | 202 | */
|
191 | 203 | disableFormElements: function(form) {
|
192 |
| - form.find(rails.disableSelector).each(function() { |
193 |
| - var element = $(this), method = element.is('button') ? 'html' : 'val'; |
194 |
| - element.data('ujs:enable-with', element[method]()); |
195 |
| - element[method](element.data('disable-with')); |
196 |
| - element.prop('disabled', true); |
| 204 | + rails.formElements(form, rails.disableSelector).each(function() { |
| 205 | + rails.disableFormElement($(this)); |
197 | 206 | });
|
198 | 207 | },
|
199 | 208 |
|
| 209 | + disableFormElement: function(element) { |
| 210 | + var method, replacement; |
| 211 | + |
| 212 | + method = element.is('button') ? 'html' : 'val'; |
| 213 | + replacement = element.data('disable-with'); |
| 214 | + |
| 215 | + element.data('ujs:enable-with', element[method]()); |
| 216 | + if (replacement !== undefined) { |
| 217 | + element[method](replacement); |
| 218 | + } |
| 219 | + |
| 220 | + element.prop('disabled', true); |
| 221 | + }, |
| 222 | + |
200 | 223 | /* Re-enables disabled form elements:
|
201 | 224 | - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
|
202 | 225 | - Sets disabled property to false
|
203 | 226 | */
|
204 | 227 | enableFormElements: function(form) {
|
205 |
| - form.find(rails.enableSelector).each(function() { |
206 |
| - var element = $(this), method = element.is('button') ? 'html' : 'val'; |
207 |
| - if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with')); |
208 |
| - element.prop('disabled', false); |
| 228 | + rails.formElements(form, rails.enableSelector).each(function() { |
| 229 | + rails.enableFormElement($(this)); |
209 | 230 | });
|
210 | 231 | },
|
211 | 232 |
|
| 233 | + enableFormElement: function(element) { |
| 234 | + var method = element.is('button') ? 'html' : 'val'; |
| 235 | + if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with')); |
| 236 | + element.prop('disabled', false); |
| 237 | + }, |
| 238 | + |
212 | 239 | /* For 'data-confirm' attribute:
|
213 | 240 | - Fires `confirm` event
|
214 | 241 | - Shows the confirmation dialog
|
|
269 | 296 | // replace element's html with the 'data-disable-with' after storing original html
|
270 | 297 | // and prevent clicking on it
|
271 | 298 | disableElement: function(element) {
|
| 299 | + var replacement = element.data('disable-with'); |
| 300 | + |
272 | 301 | element.data('ujs:enable-with', element.html()); // store enabled state
|
273 |
| - element.html(element.data('disable-with')); // set to disabled state |
| 302 | + if (replacement !== undefined) { |
| 303 | + element.html(replacement); |
| 304 | + } |
| 305 | + |
274 | 306 | element.bind('click.railsDisable', function(e) { // prevent further clicking
|
275 | 307 | return rails.stopEverything(e);
|
276 | 308 | });
|
|
284 | 316 | }
|
285 | 317 | element.unbind('click.railsDisable'); // enable element
|
286 | 318 | }
|
287 |
| - |
288 | 319 | };
|
289 | 320 |
|
290 | 321 | if (rails.fire($document, 'rails:attachBindings')) {
|
|
295 | 326 | rails.enableElement($(this));
|
296 | 327 | });
|
297 | 328 |
|
| 329 | + $document.delegate(rails.buttonDisableSelector, 'ajax:complete', function() { |
| 330 | + rails.enableFormElement($(this)); |
| 331 | + }); |
| 332 | + |
298 | 333 | $document.delegate(rails.linkClickSelector, 'click.rails', function(e) {
|
299 | 334 | var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
|
300 | 335 | if (!rails.allowAction(link)) return rails.stopEverything(e);
|
|
323 | 358 | var button = $(this);
|
324 | 359 | if (!rails.allowAction(button)) return rails.stopEverything(e);
|
325 | 360 |
|
326 |
| - rails.handleRemote(button); |
| 361 | + if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button); |
| 362 | + |
| 363 | + var handleRemote = rails.handleRemote(button); |
| 364 | + // response from rails.handleRemote() will either be false or a deferred object promise. |
| 365 | + if (handleRemote === false) { |
| 366 | + rails.enableFormElement(button); |
| 367 | + } else { |
| 368 | + handleRemote.error( function() { rails.enableFormElement(button); } ); |
| 369 | + } |
327 | 370 | return false;
|
328 | 371 | });
|
329 | 372 |
|
|
338 | 381 | $document.delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
|
339 | 382 | var form = $(this),
|
340 | 383 | remote = form.data('remote') !== undefined,
|
341 |
| - blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector), |
342 |
| - nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); |
| 384 | + blankRequiredInputs, |
| 385 | + nonBlankFileInputs; |
343 | 386 |
|
344 | 387 | if (!rails.allowAction(form)) return rails.stopEverything(e);
|
345 | 388 |
|
346 | 389 | // skip other logic when required values are missing or file upload is present
|
347 |
| - if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { |
348 |
| - return rails.stopEverything(e); |
| 390 | + if (form.attr('novalidate') == undefined) { |
| 391 | + blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector); |
| 392 | + if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { |
| 393 | + return rails.stopEverything(e); |
| 394 | + } |
349 | 395 | }
|
350 | 396 |
|
351 | 397 | if (remote) {
|
| 398 | + nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); |
352 | 399 | if (nonBlankFileInputs) {
|
353 | 400 | // slight timeout so that the submit button gets properly serialized
|
354 | 401 | // (make it easy for event handler to serialize form without disabled values)
|
|
382 | 429 | button.closest('form').data('ujs:submit-button', data);
|
383 | 430 | });
|
384 | 431 |
|
385 |
| - $document.delegate(rails.formSubmitSelector, 'ajax:beforeSend.rails', function(event) { |
| 432 | + $document.delegate(rails.formSubmitSelector, 'ajax:send.rails', function(event) { |
386 | 433 | if (this == event.target) rails.disableFormElements($(this));
|
387 | 434 | });
|
388 | 435 |
|
|
0 commit comments