Skip to content

Commit 1c84b33

Browse files
committed
Add support for the data-disable attribute.
This gives the same behavior as the `data-disable-with` attribute, but instead of using a replacement String from the `data-disable-with` attribute the disabled state will use the origin text/value of the element.
1 parent f8d4be4 commit 1c84b33

File tree

5 files changed

+340
-87
lines changed

5 files changed

+340
-87
lines changed

src/rails.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
$.rails = rails = {
2424
// 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]',
2626

2727
// Button elements bound by jquery-ujs
2828
buttonClickSelector: 'button[data-remote]',
@@ -37,10 +37,10 @@
3737
formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])',
3838

3939
// 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], button[data-disable-with], textarea[data-disable-with], input[data-disable], button[data-disable], textarea[data-disable]',
4141

4242
// 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',
4444

4545
// Form required input elements
4646
requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
@@ -49,7 +49,7 @@
4949
fileInputSelector: 'input[type=file]',
5050

5151
// 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]',
5353

5454
// Make sure that every Ajax request sends the CSRF token
5555
CSRFProtection: function(xhr) {
@@ -190,9 +190,13 @@
190190
*/
191191
disableFormElements: function(form) {
192192
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'));
193+
var element, method, enabledState;
194+
element = $(this);
195+
method = element.is('button') ? 'html' : 'val';
196+
enabledState = element[method]();
197+
198+
element.data('ujs:enable-with', enabledState);
199+
element[method](element.data('disable-with') || enabledState);
196200
element.prop('disabled', true);
197201
});
198202
},
@@ -269,8 +273,9 @@
269273
// replace element's html with the 'data-disable-with' after storing original html
270274
// and prevent clicking on it
271275
disableElement: function(element) {
272-
element.data('ujs:enable-with', element.html()); // store enabled state
273-
element.html(element.data('disable-with')); // set to disabled state
276+
var enabledState = element.html();
277+
element.data('ujs:enable-with', enabledState); // store enabled state
278+
element.html(element.data('disable-with') || enabledState); // set to disabled state
274279
element.bind('click.railsDisable', function(e) { // prevent further clicking
275280
return rails.stopEverything(e);
276281
});
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
module('data-disable-with', {
2+
setup: function() {
3+
$('#qunit-fixture').append($('<form />', {
4+
action: '/echo',
5+
'data-remote': 'true',
6+
method: 'post'
7+
}))
8+
.find('form')
9+
.append($('<input type="text" data-disable-with="processing ..." name="user_name" value="john" />'));
10+
11+
$('#qunit-fixture').append($('<form />', {
12+
action: '/echo',
13+
method: 'post'
14+
}))
15+
.find('form:last')
16+
// WEEIRDD: the form won't submit to an iframe if the button is name="submit" (??!)
17+
.append($('<input type="submit" data-disable-with="submitting ..." name="submit2" value="Submit" />'));
18+
19+
$('#qunit-fixture').append($('<a />', {
20+
text: 'Click me',
21+
href: '/echo',
22+
'data-disable-with': 'clicking...'
23+
}));
24+
},
25+
teardown: function() {
26+
$(document).unbind('iframe:loaded');
27+
}
28+
});
29+
30+
31+
asyncTest('form input field with "data-disable-with" attribute', 7, function() {
32+
var form = $('form[data-remote]'), input = form.find('input[type=text]');
33+
34+
App.checkEnabledState(input, 'john');
35+
36+
form.bind('ajax:success', function(e, data) {
37+
setTimeout(function() {
38+
App.checkEnabledState(input, 'john');
39+
equal(data.params.user_name, 'john');
40+
start();
41+
}, 13)
42+
})
43+
form.trigger('submit');
44+
45+
App.checkDisabledState(input, 'processing ...');
46+
});
47+
48+
asyncTest('form button with "data-disable-with" attribute', 6, function() {
49+
var form = $('form[data-remote]'), button = $('<button data-disable-with="submitting ..." name="submit2">Submit</button>');
50+
form.append(button);
51+
52+
App.checkEnabledState(button, 'Submit');
53+
54+
form.bind('ajax:success', function(e, data) {
55+
setTimeout(function() {
56+
App.checkEnabledState(button, 'Submit');
57+
start();
58+
}, 13)
59+
})
60+
form.trigger('submit');
61+
62+
App.checkDisabledState(button, 'submitting ...');
63+
});
64+
65+
asyncTest('form input[type=submit][data-disable-with] disables', 6, function(){
66+
var form = $('form:not([data-remote])'), input = form.find('input[type=submit]');
67+
68+
App.checkEnabledState(input, 'Submit');
69+
70+
// WEEIRDD: attaching this handler makes the test work in IE7
71+
$(document).bind('iframe:loading', function(e, form) {});
72+
73+
$(document).bind('iframe:loaded', function(e, data) {
74+
setTimeout(function() {
75+
App.checkDisabledState(input, 'submitting ...');
76+
start();
77+
}, 30);
78+
});
79+
form.trigger('submit');
80+
81+
setTimeout(function() {
82+
App.checkDisabledState(input, 'submitting ...');
83+
}, 30);
84+
});
85+
86+
asyncTest('form[data-remote] input[type=submit][data-disable-with] is replaced in ajax callback', 2, function(){
87+
var form = $('form:not([data-remote])').attr('data-remote', 'true'), origFormContents = form.html();
88+
89+
form.bind('ajax:success', function(){
90+
form.html(origFormContents);
91+
92+
setTimeout(function(){
93+
var input = form.find('input[type=submit]');
94+
App.checkEnabledState(input, 'Submit');
95+
start();
96+
}, 30);
97+
}).trigger('submit');
98+
});
99+
100+
asyncTest('form[data-remote] input[data-disable-with] is replaced with disabled field in ajax callback', 2, function(){
101+
var form = $('form:not([data-remote])').attr('data-remote', 'true'), input = form.find('input[type=submit]'),
102+
newDisabledInput = input.clone().attr('disabled', 'disabled');
103+
104+
form.bind('ajax:success', function(){
105+
input.replaceWith(newDisabledInput);
106+
107+
setTimeout(function(){
108+
App.checkEnabledState(newDisabledInput, 'Submit');
109+
start();
110+
}, 30);
111+
}).trigger('submit');
112+
});
113+
114+
asyncTest('form[data-remote] textarea[data-disable-with] attribute', 3, function() {
115+
var form = $('form[data-remote]'),
116+
textarea = $('<textarea data-disable-with="processing ..." name="user_bio">born, lived, died.</textarea>').appendTo(form);
117+
118+
form.bind('ajax:success', function(e, data) {
119+
setTimeout(function() {
120+
equal(data.params.user_bio, 'born, lived, died.');
121+
start();
122+
}, 13)
123+
})
124+
form.trigger('submit');
125+
126+
App.checkDisabledState(textarea, 'processing ...');
127+
});
128+
129+
asyncTest('a[data-disable-with] disables', 4, function() {
130+
var link = $('a[data-disable-with]');
131+
132+
App.checkEnabledState(link, 'Click me');
133+
134+
link.trigger('click');
135+
App.checkDisabledState(link, 'clicking...');
136+
start();
137+
});
138+
139+
asyncTest('a[data-remote][data-disable-with] disables and re-enables', 6, function() {
140+
var link = $('a[data-disable-with]').attr('data-remote', true);
141+
142+
App.checkEnabledState(link, 'Click me');
143+
144+
link
145+
.bind('ajax:beforeSend', function() {
146+
App.checkDisabledState(link, 'clicking...');
147+
})
148+
.bind('ajax:complete', function() {
149+
setTimeout( function() {
150+
App.checkEnabledState(link, 'Click me');
151+
start();
152+
}, 15);
153+
})
154+
.trigger('click');
155+
});
156+
157+
asyncTest('a[data-remote][data-disable-with] re-enables when `ajax:before` event is cancelled', 6, function() {
158+
var link = $('a[data-disable-with]').attr('data-remote', true);
159+
160+
App.checkEnabledState(link, 'Click me');
161+
162+
link
163+
.bind('ajax:before', function() {
164+
App.checkDisabledState(link, 'clicking...');
165+
return false;
166+
})
167+
.trigger('click');
168+
169+
setTimeout(function() {
170+
App.checkEnabledState(link, 'Click me');
171+
start();
172+
}, 30);
173+
});
174+
175+
asyncTest('a[data-remote][data-disable-with] re-enables when `ajax:beforeSend` event is cancelled', 6, function() {
176+
var link = $('a[data-disable-with]').attr('data-remote', true);
177+
178+
App.checkEnabledState(link, 'Click me');
179+
180+
link
181+
.bind('ajax:beforeSend', function() {
182+
App.checkDisabledState(link, 'clicking...');
183+
return false;
184+
})
185+
.trigger('click');
186+
187+
setTimeout(function() {
188+
App.checkEnabledState(link, 'Click me');
189+
start();
190+
}, 30);
191+
});
192+
193+
asyncTest('a[data-remote][data-disable-with] re-enables when `ajax:error` event is triggered', 6, function() {
194+
var link = $('a[data-disable-with]').attr('data-remote', true).attr('href', '/error');
195+
196+
App.checkEnabledState(link, 'Click me');
197+
198+
link
199+
.bind('ajax:beforeSend', function() {
200+
App.checkDisabledState(link, 'clicking...');
201+
})
202+
.trigger('click');
203+
204+
setTimeout(function() {
205+
App.checkEnabledState(link, 'Click me');
206+
start();
207+
}, 30);
208+
});
209+
210+
asyncTest('form[data-remote] input|button|textarea[data-disable-with] does not disable when `ajax:beforeSend` event is cancelled', 8, function() {
211+
var form = $('form[data-remote]'),
212+
input = form.find('input:text'),
213+
button = $('<button data-disable-with="submitting ..." name="submit2">Submit</button>').appendTo(form),
214+
textarea = $('<textarea data-disable-with="processing ..." name="user_bio">born, lived, died.</textarea>').appendTo(form),
215+
submit = $('<input type="submit" data-disable-with="submitting ..." name="submit2" value="Submit" />').appendTo(form);
216+
217+
form
218+
.bind('ajax:beforeSend', function() {
219+
return false;
220+
})
221+
.trigger('submit');
222+
223+
App.checkEnabledState(input, 'john');
224+
App.checkEnabledState(button, 'Submit');
225+
App.checkEnabledState(textarea, 'born, lived, died.');
226+
App.checkEnabledState(submit, 'Submit');
227+
228+
start();
229+
230+
});
231+
232+
asyncTest('ctrl-clicking on a link does not disables the link', 6, function() {
233+
var link = $('a[data-disable-with]'), e;
234+
e = $.Event('click');
235+
e.metaKey = true;
236+
237+
App.checkEnabledState(link, 'Click me');
238+
239+
link.trigger(e);
240+
App.checkEnabledState(link, 'Click me');
241+
242+
e = $.Event('click');
243+
e.ctrlKey = true;
244+
245+
link.trigger(e);
246+
App.checkEnabledState(link, 'Click me');
247+
start();
248+
});

0 commit comments

Comments
 (0)