diff --git a/CHANGELOG.md b/CHANGELOG.md index b4772ad0868c379530427e4727620e70916906cf..c838aa90e65e90ce67cd9a60f958c124e503defb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### +* `form_elements` module: New `pattern` option for form fields of `type="text"`. +* `form_panel` new `auto_focus` parameter for the `create_show_form_callback`. * The file-upload module from the [CaosDB WebUI Legacy Adapter](https://gitlab.com/caosdb/caosdb-webui-legacy-adapter) has been added. The new file-upload add a "+" button to the file-system view for diff --git a/src/core/js/form_elements.js b/src/core/js/form_elements.js index 5099971e402ddf3f9bb94580fad737c5b30594e9..63c76807a3d0462a2b6701dc47c2d83c72a134fc 100644 --- a/src/core/js/form_elements.js +++ b/src/core/js/form_elements.js @@ -1337,14 +1337,26 @@ var form_elements = new function () { return this._make_input(config); } + /** + * Field config for a text field (config.type = 'text'). + * + * @augments {FieldConfig} + * + * @property {string} pattern - a regex pattern which validates the value of the text field. + */ + /** * Return a new text field. * - * @param {FieldConfig} config + * @param {TextFieldConfig} config * @return {HTMLElement} */ this.make_text_input = function (config) { - return this._make_input(config); + const input = this._make_input(config); + if (config.pattern) { + $(input).find("input").attr("pattern", config.pattern); + } + return input; } @@ -1528,6 +1540,19 @@ var form_elements = new function () { } + /** + * Check form validity and return if the form is valid. + * + * @param {HTMLElement} form - the form elemeng. + * @return {boolean} true iff the form is valid. + */ + this.check_form_validity = function (form) { + const is_valid = form.checkValidity(); + form.reportValidity(); + return is_valid; + } + + this.all_required_fields_set = function (form) { const req = form_elements.get_enabled_required_fields(form); for (const field of req) { @@ -1542,7 +1567,7 @@ var form_elements = new function () { * @param {HTMLElement} form - the form be validated. */ this.is_valid = function (form) { - return form_elements.all_required_fields_set(form); + return form_elements.all_required_fields_set(form) && form_elements.check_form_validity(form); } diff --git a/src/core/js/form_panel.js b/src/core/js/form_panel.js index a745f949f98d6219e377783d7ca6c854908df573..fc1cbc7d947833f83c1ef3c39aff19117f76cc27 100644 --- a/src/core/js/form_panel.js +++ b/src/core/js/form_panel.js @@ -71,9 +71,12 @@ var form_panel = new function () { * You may supply 'undefined' as form_config and use form_creator * instead which is supposed to be a function without argument that * return the form to be added to the panel + * + * The first input element will be focused unless you specify `false` as + * fifths parameter. */ this.create_show_form_callback = function ( - panel_id, title, form_config, form_creator=undefined + panel_id, title, form_config, form_creator=undefined, auto_focus=true ) { return (e) => { logger.trace("enter show_form_panel", e); @@ -100,6 +103,11 @@ var form_panel = new function () { true ); } + if (typeof auto_focus === "undefined" || !!auto_focus === true) { + if (panel.find("form")[0].length>0) { + panel.find("form")[0][0].focus(); + } + } } }; diff --git a/test/core/js/modules/form_elements.js.js b/test/core/js/modules/form_elements.js.js index f93fde0db2d69156312b2a34c3748112619b68eb..c1fa09ddbca3708d82a68c8ec4351c7951e81b16 100644 --- a/test/core/js/modules/form_elements.js.js +++ b/test/core/js/modules/form_elements.js.js @@ -786,3 +786,24 @@ QUnit.test("make_file_input", function (assert) { assert.ok(file_input.find(":input").prop("multiple"), "is multiple"); assert.equal(file_input.find(":input").attr("accept"), ".tsv, .csv", "accept there"); }); + +QUnit.test("pattern", function (assert) { + const config = { + "name": "test-form", + "fields": [{ + "required": true, + "name": "text_field", + "type": "text", + "pattern": "[a-f]*" + }, ], + } + const form_wrapper = $(form_elements.make_form(config)); + const form = form_wrapper.find("form")[0]; + + assert.notOk(form_elements.check_form_validity(form), "empty -> invalid"); + form_wrapper.find(":input[name='text_field']").val("ghi") + assert.notOk(form_elements.check_form_validity(form), "ghi -> invalid"); + + form_wrapper.find(":input[name='text_field']").val("abc") + assert.ok(form_elements.check_form_validity(form), "abc -> valid"); +}); diff --git a/test/core/js/modules/form_panel.js.js b/test/core/js/modules/form_panel.js.js index a810fb8711f14bc3b3637297c9f937884022fc15..0203e0b50a1f11bca653ffb8ff6e8b36824b73e3 100644 --- a/test/core/js/modules/form_panel.js.js +++ b/test/core/js/modules/form_panel.js.js @@ -67,6 +67,16 @@ QUnit.test("create_show_form_callback ", function (assert) { ); assert.equal(typeof cb2, "function", "function created"); cb2() + assert.notOk(document.querySelector(`#${panel_id}`), "panel is being appended to nav, but there is no nav"); + document.body.appendChild(document.createElement("nav")); + + cb2() + assert.ok(document.querySelector(`#${panel_id}`), "panel was appended to nav"); + console.log(document.activeElement, "here"); + assert.equal(document.activeElement.name, "csv_file", "first form field is being focussed"); + + document.querySelector(`#${panel_id} form`).dispatchEvent(form_elements.cancel_form_event); + assert.notOk(document.querySelector(`#${panel_id}`), "query panel removed"); });