Skip to content

Commit 0dea72e

Browse files
committed
Added "autoclear" setting so invalid values persist
To increase usability, add a new setting that keeps invalid values in the input field to give the user a chance to correct a mistake. If the user fat fingers the value on accident and doesn't realize it before tabbing away from the form field, the invalid value will remain so the user can correct the value rather than retyping it. - Added new setting called "autoclear", defaulting to true, to maintain existing behavior. - When autoclear=false, leave invalid values visible so the user can correct their mistake. - Added test coverage for when the mask(...) is first invoked (Init.Spec.js) - Added scenarios to Focus.Spec.js to cover new functionality - Repackaged the distribution version to include this new feature
1 parent ef9f3f3 commit 0dea72e

File tree

6 files changed

+128
-20
lines changed

6 files changed

+128
-20
lines changed

dist/jquery.maskedinput.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
var el = document.createElement('input'),
1010
name = 'onpaste';
1111
el.setAttribute(name, '');
12-
return (typeof el[name] === 'function')?'paste':'input';
12+
return (typeof el[name] === 'function')?'paste':'input';
1313
}
1414

1515
var pasteEventName = getPasteEvent() + ".mask",
@@ -25,6 +25,7 @@ $.mask = {
2525
'a': "[A-Za-z]",
2626
'*': "[A-Za-z0-9]"
2727
},
28+
autoclear: true,
2829
dataName: "rawMaskFn",
2930
placeholder: '_'
3031
};
@@ -79,6 +80,7 @@ $.fn.extend({
7980
return input.data($.mask.dataName)();
8081
}
8182
settings = $.extend({
83+
autoclear: $.mask.autoclear,
8284
placeholder: $.mask.placeholder, // Load default placeholder
8385
completed: null
8486
}, settings);
@@ -251,7 +253,8 @@ $.fn.extend({
251253
var test = input.val(),
252254
lastMatch = -1,
253255
i,
254-
c;
256+
c,
257+
pos;
255258

256259
for (i = 0, pos = 0; i < len; i++) {
257260
if (tests[i]) {
@@ -275,8 +278,14 @@ $.fn.extend({
275278
if (allow) {
276279
writeBuffer();
277280
} else if (lastMatch + 1 < partialPosition) {
278-
input.val("");
279-
clearBuffer(0, len);
281+
if (settings.autoclear) {
282+
input.val("");
283+
clearBuffer(0, len);
284+
} else {
285+
// Invalid value, but we opt to show the value to the
286+
// user and allow them to correct their mistake.
287+
writeBuffer();
288+
}
280289
} else {
281290
writeBuffer();
282291
input.val(input.val().substring(0, lastMatch + 1));
@@ -299,12 +308,12 @@ $.fn.extend({
299308
})
300309
.bind("focus.mask", function() {
301310
clearTimeout(caretTimeoutId);
302-
var pos,
303-
moveCaret;
311+
var pos;
304312

305313
focusText = input.val();
314+
306315
pos = checkVal();
307-
316+
308317
caretTimeoutId = setTimeout(function(){
309318
writeBuffer();
310319
if (pos == mask.length) {
@@ -316,23 +325,25 @@ $.fn.extend({
316325
})
317326
.bind("blur.mask", function() {
318327
checkVal();
328+
319329
if (input.val() != focusText)
320330
input.change();
321331
})
322332
.bind("keydown.mask", keydownEvent)
323333
.bind("keypress.mask", keypressEvent)
324334
.bind(pasteEventName, function() {
325-
setTimeout(function() {
335+
setTimeout(function() {
326336
var pos=checkVal(true);
327-
input.caret(pos);
337+
input.caret(pos);
328338
if (settings.completed && pos == input.val().length)
329339
settings.completed.call(input);
330340
}, 0);
331341
});
332-
checkVal(); //Perform initial check for existing values
342+
343+
checkVal(); //Perform initial check for existing values
333344
});
334345
}
335346
});
336347

337348

338-
})(jQuery);
349+
})(jQuery);

dist/jquery.maskedinput.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spec/Focus.Spec.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@ feature("Focusing A Masked Input",function(){
5050
expect(error).toBeUndefined();
5151
})
5252
});
53+
54+
scenario("Mask contains a partial value with autoclear set to false",function(){
55+
given("the input has a partial value",function(){
56+
input.val("1");
57+
});
58+
given("a mask with two placeholders and autoclear=false",function(){
59+
input.mask("99", { autoclear: false });
60+
});
61+
when("focusing on the input",function(){
62+
input.focus();
63+
});
64+
then("the value should be partially filled out",function(){
65+
expect(input).toHaveValue("1_");
66+
});
67+
then("the input partial value should remain",function(){
68+
expect(input).toHaveValue("1_");
69+
});
70+
});
5371
});
5472

5573
feature("Leaving A Masked Input",function(){
@@ -76,6 +94,20 @@ feature("Leaving A Masked Input",function(){
7694
expect(input).toHaveValue("");
7795
});
7896
});
97+
98+
scenario("Empty placeholders remaining with autoclear set to false",function(){
99+
given("a mask with two placeholders",function(){
100+
input.mask("99", { autoclear: false });
101+
});
102+
when("typing one character and blurring",function(){
103+
input.caret(0);
104+
input.mashKeys("1")
105+
input.blur();
106+
});
107+
then("value should remain visible with placeholders",function(){
108+
expect(input).toHaveValue("1_");
109+
});
110+
});
79111
});
80112

81113
feature("Optional marker",function(){

spec/Init.Spec.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
feature("Initializing a Mask",function(){
2+
scenario("An input with no value",function(){
3+
given("an input with no value",function(){
4+
input.val("");
5+
});
6+
when("setting a mask with two placeholders",function(){
7+
input.mask("99");
8+
});
9+
then("the value should be an empty string",function(){
10+
expect(input).toHaveValue("");
11+
});
12+
});
13+
14+
scenario("An input with a valid value and no placeholders remaining",function(){
15+
given("an input with a valid value",function(){
16+
input.val("5555555555");
17+
});
18+
when("setting a mask",function(){
19+
input.mask("(999) 999-9999");
20+
});
21+
then("the value should be intact",function(){
22+
expect(input).toHaveValue("(555) 555-5555");
23+
});
24+
});
25+
26+
scenario("An input with an invalid value and placeholders remaining",function(){
27+
given("an invalid input value",function(){
28+
input.val("55555555");
29+
});
30+
when("setting a mask",function(){
31+
input.mask("(999) 999-9999");
32+
});
33+
then("the value should be empty",function(){
34+
expect(input).toHaveValue("");
35+
});
36+
});
37+
38+
scenario("An input with an invalid value, placeholders remaining and autoclear set to false",function(){
39+
given("an invalid input value",function(){
40+
input.val("55555555");
41+
});
42+
when("setting a mask with autoclear set to false",function(){
43+
input.mask("(999) 999-9999", { autoclear: false });
44+
});
45+
then("the value be intact with placeholders visible",function(){
46+
expect(input).toHaveValue("(555) 555-55__");
47+
});
48+
});
49+
50+
scenario("An input with an invalid value and placeholders remaining");
51+
});

spec/SpecRunner.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040

4141
<!-- Specs -->
4242
<script type="text/javascript" src="Setup.Spec.js"></script>
43-
<script type="text/javascript" src="Raw.Spec.js"></script>
43+
<script type="text/javascript" src="Init.Spec.js"></script>
44+
<script type="text/javascript" src="Raw.Spec.js"></script>
4445
<script type="text/javascript" src="Focus.Spec.js"></script>
4546
<script type="text/javascript" src="Typing.Spec.js"></script>
4647
<script type="text/javascript" src="Backspace.Spec.js"></script>

src/jquery.maskedinput.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ function getPasteEvent() {
22
var el = document.createElement('input'),
33
name = 'onpaste';
44
el.setAttribute(name, '');
5-
return (typeof el[name] === 'function')?'paste':'input';
5+
return (typeof el[name] === 'function')?'paste':'input';
66
}
77

88
var pasteEventName = getPasteEvent() + ".mask",
@@ -18,6 +18,7 @@ $.mask = {
1818
'a': "[A-Za-z]",
1919
'*': "[A-Za-z0-9]"
2020
},
21+
autoclear: true,
2122
dataName: "rawMaskFn",
2223
placeholder: '_'
2324
};
@@ -72,6 +73,7 @@ $.fn.extend({
7273
return input.data($.mask.dataName)();
7374
}
7475
settings = $.extend({
76+
autoclear: $.mask.autoclear,
7577
placeholder: $.mask.placeholder, // Load default placeholder
7678
completed: null
7779
}, settings);
@@ -269,8 +271,16 @@ $.fn.extend({
269271
if (allow) {
270272
writeBuffer();
271273
} else if (lastMatch + 1 < partialPosition) {
272-
input.val("");
273-
clearBuffer(0, len);
274+
if (settings.autoclear) {
275+
// Invalid value. Remove it and replace it with the
276+
// mask, which is the default behavior.
277+
input.val("");
278+
clearBuffer(0, len);
279+
} else {
280+
// Invalid value, but we opt to show the value to the
281+
// user and allow them to correct their mistake.
282+
writeBuffer();
283+
}
274284
} else {
275285
writeBuffer();
276286
input.val(input.val().substring(0, lastMatch + 1));
@@ -296,8 +306,9 @@ $.fn.extend({
296306
var pos;
297307

298308
focusText = input.val();
309+
299310
pos = checkVal();
300-
311+
301312
caretTimeoutId = setTimeout(function(){
302313
writeBuffer();
303314
if (pos == mask.length) {
@@ -309,20 +320,22 @@ $.fn.extend({
309320
})
310321
.bind("blur.mask", function() {
311322
checkVal();
323+
312324
if (input.val() != focusText)
313325
input.change();
314326
})
315327
.bind("keydown.mask", keydownEvent)
316328
.bind("keypress.mask", keypressEvent)
317329
.bind(pasteEventName, function() {
318-
setTimeout(function() {
330+
setTimeout(function() {
319331
var pos=checkVal(true);
320-
input.caret(pos);
332+
input.caret(pos);
321333
if (settings.completed && pos == input.val().length)
322334
settings.completed.call(input);
323335
}, 0);
324336
});
325-
checkVal(); //Perform initial check for existing values
337+
338+
checkVal(); //Perform initial check for existing values
326339
});
327340
}
328341
});

0 commit comments

Comments
 (0)