From d6dc452a8e2b7624f57f61497a4ce04aedd839a9 Mon Sep 17 00:00:00 2001 From: Dominic Tubach Date: Thu, 10 Jul 2025 17:03:27 +0200 Subject: [PATCH 1/2] Prevent invalid characters in number input field --- js/number-input.js | 75 +++++++++++++++++++++++++ json_forms.libraries.yml | 8 +++ src/Form/Control/NumberArrayFactory.php | 1 + 3 files changed, 84 insertions(+) create mode 100644 js/number-input.js diff --git a/js/number-input.js b/js/number-input.js new file mode 100644 index 0000000..eb34b13 --- /dev/null +++ b/js/number-input.js @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2025 SYSTOPIA GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Restricts input of number fields to digits, decimal separator, and minus. + */ +(function (Drupal, once) { + Drupal.behaviors.numberInput = { + attach: function (context, settings) { + // Decimal separator of browser. + const decimalSeparator = Intl.NumberFormat() + .formatToParts(1.1) + .find(part => part.type === 'decimal') + .value; + const digits = '0123456789'; + + function getElementLang(element) { + if (element.lang) { + return element.lang; + } + + return element.parentElement ? getElementLang(element.parentElement) : null; + } + + once('json-forms-number-input', 'input[type="number"]', context).forEach((element) => { + let decimalSeparators = decimalSeparator; + const lang = getElementLang(element); + if (lang) { + // Decimal separator of element's language might be different from + // the browser's separator. We allow both in that case. It depends on + // the browser which one is preferred, i.e. the one that is used when + // pressing the buttons to change a number. + decimalSeparators += Intl.NumberFormat(lang) + .formatToParts(1.1) + .find(part => part.type === 'decimal') + .value; + } + + element.addEventListener('keydown', function (event) { + if (event.key === 'Backspace' || '0123456789'.indexOf(event.key) !== -1) { + return; + } + + if ('-' === event.key) { + if (element.value.indexOf('-') === -1 && (element.min < 0 || element.min === '' || element.min == null)) { + return; + } + } + else if (decimalSeparators.indexOf(event.key) !== -1) { + if (element.value.indexOf('.') === -1 && (element.step === 'any' || element.step < 1)) { + return; + } + } + + event.preventDefault(); + }); + }); + } + }; + +})(Drupal, once); diff --git a/json_forms.libraries.yml b/json_forms.libraries.yml index 5d35ec2..b965146 100644 --- a/json_forms.libraries.yml +++ b/json_forms.libraries.yml @@ -16,6 +16,14 @@ disable_buttons_on_ajax: dependencies: - core/jquery +number_input: + version: 0.1.0 + js: + js/number-input.js: {} + dependencies: + - core/drupal + - core/once + vertical_tabs: version: 0.1.0 js: diff --git a/src/Form/Control/NumberArrayFactory.php b/src/Form/Control/NumberArrayFactory.php index 0d60940..5f3f267 100644 --- a/src/Form/Control/NumberArrayFactory.php +++ b/src/Form/Control/NumberArrayFactory.php @@ -50,6 +50,7 @@ public function createFormArray( '#type' => 'number', '#value_callback' => NumberValueCallback::class . '::convert', '#_type' => $definition->getType(), + '#attached' => ['library' => ['json_forms/number_input']], ] + BasicFormPropertiesFactory::createFieldProperties($definition, $formState); if (NULL !== $definition->getExclusiveMinimum()) { From 22598ad51060630cc97cb4855104fc1469027882 Mon Sep 17 00:00:00 2001 From: Dominic Tubach Date: Mon, 14 Jul 2025 15:05:02 +0200 Subject: [PATCH 2/2] Add namespace to Drupal JS behavior --- js/number-input.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/number-input.js b/js/number-input.js index eb34b13..3abf48c 100644 --- a/js/number-input.js +++ b/js/number-input.js @@ -19,7 +19,7 @@ * Restricts input of number fields to digits, decimal separator, and minus. */ (function (Drupal, once) { - Drupal.behaviors.numberInput = { + Drupal.behaviors.json_forms_numberInput = { attach: function (context, settings) { // Decimal separator of browser. const decimalSeparator = Intl.NumberFormat()