Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

### Fixed

- Auto-complete select error when input is empty (TypeError: Cannot read properties of undefined (reading 'length'))
- Minus is being deleted with the first digit #2860
- Problems with deleting static chars in alternator mask #2648
- Backspace on controlled input adds "backspace" text to the value #2865
Expand Down
15 changes: 12 additions & 3 deletions lib/eventhandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,9 +508,18 @@ const EventHandlers = {
}, 0);
break;
case "deleteContentBackward":
var keydown = new $.Event("keydown");
keydown.key = keys.Backspace;
EventHandlers.keyEvent.call(input, keydown);
if (e.inputType && e.inputType.startsWith("insert")) {
// e.inputType indicates an insert operation (e.g. browser autocomplete
// with insertReplacementText) but analyseChanges incorrectly detected
// a deletion due to caret position / buffer length mismatch.
// Apply the value directly instead of dispatching a backspace event.
applyInputValue(input, inputValue);
caret.call(inputmask, input, caretPos.begin, caretPos.end, true);
} else {
var keydown = new $.Event("keydown");
keydown.key = keys.Backspace;
EventHandlers.keyEvent.call(input, keydown);
}
break;
default:
applyInputValue(input, inputValue);
Expand Down
14 changes: 14 additions & 0 deletions qunit/simulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,18 @@ export default function ($, Inputmask) {
}
$(input).trigger("input");
};

// Simulate a browser autocomplete selection on a masked input.
// Sets the native value and fires an input event with inputType "insertReplacementText",
// matching the browser behavior when the user selects a suggestion from the autocomplete list.
$.fn.autocomplete = function (value, caretBegin, caretEnd) {
const input = this.nodeName ? this : this[0];
input.inputmask.__valueSet.call(input, value);
if (caretBegin !== undefined) {
$.caret(input, caretBegin, caretEnd !== undefined ? caretEnd : caretBegin);
}
const evt = $.Event("input");
evt.inputType = "insertReplacementText";
$(input).trigger(evt);
};
}
38 changes: 38 additions & 0 deletions qunit/tests_inputeventonly.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,42 @@ export default function (qunit, Inputmask) {
done();
}, 0);
});

// Regression test: selecting a browser autocomplete suggestion on an empty masked input
// must not throw TypeError. analyseChanges can misdetect the insertion as a deletion
// (deleteContentBackward) when caret is at 0 and the autocomplete value is shorter than
// the mask template. The fix guards against this contradiction by checking e.inputType.
qunit.test(
"(999) 999-9999 - autocomplete on empty input (insertReplacementText)",
function (assert) {
const done = assert.async(),
$fixture = $("#qunit-fixture");
$fixture.append('<input type="text" id="testmask" />');
const testmask = document.getElementById("testmask");
Inputmask("(999) 999-9999", { inputEventOnly: true }).mask(testmask);

testmask.focus();
setTimeout(function () {
// Simulate browser autocomplete: native value set to "1231231234", caret at 0,
// input event fires with inputType "insertReplacementText".
assert.ok(
(function () {
try {
$(testmask).autocomplete("1231231234", 0, 0);
return true;
} catch (e) {
return false;
}
})(),
"No error thrown on autocomplete"
);
assert.equal(
testmask.value,
"(123) 123-1234",
"Result " + testmask.value
);
done();
}, 0);
}
);
}