Skip to content

Commit d6dc452

Browse files
author
Dominic Tubach
committed
Prevent invalid characters in number input field
1 parent e6909ab commit d6dc452

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

js/number-input.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (C) 2025 SYSTOPIA GmbH
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
/**
19+
* Restricts input of number fields to digits, decimal separator, and minus.
20+
*/
21+
(function (Drupal, once) {
22+
Drupal.behaviors.numberInput = {
23+
attach: function (context, settings) {
24+
// Decimal separator of browser.
25+
const decimalSeparator = Intl.NumberFormat()
26+
.formatToParts(1.1)
27+
.find(part => part.type === 'decimal')
28+
.value;
29+
const digits = '0123456789';
30+
31+
function getElementLang(element) {
32+
if (element.lang) {
33+
return element.lang;
34+
}
35+
36+
return element.parentElement ? getElementLang(element.parentElement) : null;
37+
}
38+
39+
once('json-forms-number-input', 'input[type="number"]', context).forEach((element) => {
40+
let decimalSeparators = decimalSeparator;
41+
const lang = getElementLang(element);
42+
if (lang) {
43+
// Decimal separator of element's language might be different from
44+
// the browser's separator. We allow both in that case. It depends on
45+
// the browser which one is preferred, i.e. the one that is used when
46+
// pressing the buttons to change a number.
47+
decimalSeparators += Intl.NumberFormat(lang)
48+
.formatToParts(1.1)
49+
.find(part => part.type === 'decimal')
50+
.value;
51+
}
52+
53+
element.addEventListener('keydown', function (event) {
54+
if (event.key === 'Backspace' || '0123456789'.indexOf(event.key) !== -1) {
55+
return;
56+
}
57+
58+
if ('-' === event.key) {
59+
if (element.value.indexOf('-') === -1 && (element.min < 0 || element.min === '' || element.min == null)) {
60+
return;
61+
}
62+
}
63+
else if (decimalSeparators.indexOf(event.key) !== -1) {
64+
if (element.value.indexOf('.') === -1 && (element.step === 'any' || element.step < 1)) {
65+
return;
66+
}
67+
}
68+
69+
event.preventDefault();
70+
});
71+
});
72+
}
73+
};
74+
75+
})(Drupal, once);

json_forms.libraries.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ disable_buttons_on_ajax:
1616
dependencies:
1717
- core/jquery
1818

19+
number_input:
20+
version: 0.1.0
21+
js:
22+
js/number-input.js: {}
23+
dependencies:
24+
- core/drupal
25+
- core/once
26+
1927
vertical_tabs:
2028
version: 0.1.0
2129
js:

src/Form/Control/NumberArrayFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function createFormArray(
5050
'#type' => 'number',
5151
'#value_callback' => NumberValueCallback::class . '::convert',
5252
'#_type' => $definition->getType(),
53+
'#attached' => ['library' => ['json_forms/number_input']],
5354
] + BasicFormPropertiesFactory::createFieldProperties($definition, $formState);
5455

5556
if (NULL !== $definition->getExclusiveMinimum()) {

0 commit comments

Comments
 (0)