Skip to content

Commit fe93e3b

Browse files
committed
Merge branch 'master' into data-disable
Conflicts: src/rails.js test/public/test/data-disable.js
2 parents d717eeb + 2dfe6ec commit fe93e3b

File tree

6 files changed

+2227
-1166
lines changed

6 files changed

+2227
-1166
lines changed

src/rails.js

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
// Link onClick disable selector with possible reenable after remote submission
5252
linkDisableSelector: 'a[data-disable-with], a[data-disable]',
5353

54+
// Button onClick disable selector with possible reenable after remote submission
55+
buttonDisableSelector: 'button[data-remote][data-disable-with]',
56+
5457
// Make sure that every Ajax request sends the CSRF token
5558
CSRFProtection: function(xhr) {
5659
var token = $('meta[name="csrf-token"]').attr('content');
@@ -189,7 +192,7 @@
189192
// If form is actually a "form" element this will return associated elements outside the from that have
190193
// the html form attribute set
191194
formElements: function(form, selector) {
192-
return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector)
195+
return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector);
193196
},
194197

195198
/* Disables form elements:
@@ -199,19 +202,22 @@
199202
*/
200203
disableFormElements: function(form) {
201204
rails.formElements(form, rails.disableSelector).each(function() {
202-
var element, method, replacement;
205+
rails.disableFormElement($(this));
206+
});
207+
},
203208

204-
element = $(this);
205-
method = element.is('button') ? 'html' : 'val';
206-
replacement = element.data('disable-with');
209+
disableFormElement: function(element) {
210+
var method, replacement;
207211

208-
element.data('ujs:enable-with', element[method]());
209-
if (replacement !== undefined) {
210-
element[method](replacement);
211-
}
212+
method = element.is('button') ? 'html' : 'val';
213+
replacement = element.data('disable-with');
212214

213-
element.prop('disabled', true);
214-
});
215+
element.data('ujs:enable-with', element[method]());
216+
if (replacement !== undefined) {
217+
element[method](replacement);
218+
}
219+
220+
element.prop('disabled', true);
215221
},
216222

217223
/* Re-enables disabled form elements:
@@ -220,12 +226,16 @@
220226
*/
221227
enableFormElements: function(form) {
222228
rails.formElements(form, rails.enableSelector).each(function() {
223-
var element = $(this), method = element.is('button') ? 'html' : 'val';
224-
if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
225-
element.prop('disabled', false);
229+
rails.enableFormElement($(this));
226230
});
227231
},
228232

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+
229239
/* For 'data-confirm' attribute:
230240
- Fires `confirm` event
231241
- Shows the confirmation dialog
@@ -306,7 +316,6 @@
306316
}
307317
element.unbind('click.railsDisable'); // enable element
308318
}
309-
310319
};
311320

312321
if (rails.fire($document, 'rails:attachBindings')) {
@@ -317,6 +326,10 @@
317326
rails.enableElement($(this));
318327
});
319328

329+
$document.delegate(rails.buttonDisableSelector, 'ajax:complete', function() {
330+
rails.enableFormElement($(this));
331+
});
332+
320333
$document.delegate(rails.linkClickSelector, 'click.rails', function(e) {
321334
var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
322335
if (!rails.allowAction(link)) return rails.stopEverything(e);
@@ -345,7 +358,15 @@
345358
var button = $(this);
346359
if (!rails.allowAction(button)) return rails.stopEverything(e);
347360

348-
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+
}
349370
return false;
350371
});
351372

test/public/test/data-disable-with.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ module('data-disable-with', {
3131
name: 'submit3',
3232
value: 'Form Attr Submit'
3333
}));
34+
35+
$('#qunit-fixture').append($('<button />', {
36+
text: 'Click me',
37+
'data-remote': true,
38+
'data-url': '/echo',
39+
'data-disable-with': 'clicking...'
40+
}));
3441
},
3542
teardown: function() {
3643
$(document).unbind('iframe:loaded');
@@ -275,3 +282,74 @@ asyncTest('ctrl-clicking on a link does not disables the link', 6, function() {
275282
App.checkEnabledState(link, 'Click me');
276283
start();
277284
});
285+
286+
asyncTest('button[data-remote][data-disable-with] disables and re-enables', 6, function() {
287+
var button = $('button[data-remote][data-disable-with]');
288+
289+
checkEnabledState(button, 'Click me');
290+
291+
button
292+
.bind('ajax:send', function() {
293+
checkDisabledState(button, 'clicking...');
294+
})
295+
.bind('ajax:complete', function() {
296+
setTimeout( function() {
297+
checkEnabledState(button, 'Click me');
298+
start();
299+
}, 15);
300+
})
301+
.trigger('click');
302+
});
303+
304+
asyncTest('button[data-remote][data-disable-with] re-enables when `ajax:before` event is cancelled', 6, function() {
305+
var button = $('button[data-remote][data-disable-with]');
306+
307+
checkEnabledState(button, 'Click me');
308+
309+
button
310+
.bind('ajax:before', function() {
311+
checkDisabledState(button, 'clicking...');
312+
return false;
313+
})
314+
.trigger('click');
315+
316+
setTimeout(function() {
317+
checkEnabledState(button, 'Click me');
318+
start();
319+
}, 30);
320+
});
321+
322+
asyncTest('button[data-remote][data-disable-with] re-enables when `ajax:beforeSend` event is cancelled', 6, function() {
323+
var button = $('button[data-remote][data-disable-with]');
324+
325+
checkEnabledState(button, 'Click me');
326+
327+
button
328+
.bind('ajax:beforeSend', function() {
329+
checkDisabledState(button, 'clicking...');
330+
return false;
331+
})
332+
.trigger('click');
333+
334+
setTimeout(function() {
335+
checkEnabledState(button, 'Click me');
336+
start();
337+
}, 30);
338+
});
339+
340+
asyncTest('button[data-remote][data-disable-with] re-enables when `ajax:error` event is triggered', 6, function() {
341+
var button = $('a[data-disable-with]').attr('data-remote', true).attr('href', '/error');
342+
343+
checkEnabledState(button, 'Click me');
344+
345+
button
346+
.bind('ajax:send', function() {
347+
checkDisabledState(button, 'clicking...');
348+
})
349+
.trigger('click');
350+
351+
setTimeout(function() {
352+
checkEnabledState(button, 'Click me');
353+
start();
354+
}, 30);
355+
});

test/public/test/data-disable.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ module('data-disable', {
2121
href: '/echo',
2222
'data-disable': 'true'
2323
}));
24+
25+
$('#qunit-fixture').append($('<button />', {
26+
text: 'Click me',
27+
'data-remote': true,
28+
'data-url': '/echo',
29+
'data-disable-with': 'clicking...'
30+
}));
2431
},
2532
teardown: function() {
2633
$(document).unbind('iframe:loaded');

0 commit comments

Comments
 (0)