From 55d9278aeac8c64d3bc341b2b44138a894d1e202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johnny=20Bl=C3=A4sta?= Date: Wed, 23 Oct 2024 09:52:37 +0200 Subject: [PATCH] feature: multiple choice checkbox in editor --- src/controls/editor/editform.js | 30 ++++++++++- src/controls/editor/edithandler.js | 81 ++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 11 deletions(-) diff --git a/src/controls/editor/editform.js b/src/controls/editor/editform.js index a16c250df..dfa970d6f 100644 --- a/src/controls/editor/editform.js +++ b/src/controls/editor/editform.js @@ -19,6 +19,7 @@ const createForm = function createForm(obj) { const disabled = obj.readonly ? ' disabled' : ''; const required = obj.required ? ' required' : ''; const name = obj.name ? obj.name : ''; + const options = obj.options || []; let el; let firstOption; let checked; @@ -31,8 +32,33 @@ const createForm = function createForm(obj) { el = `
`; break; case 'checkbox': - checked = (obj.config && obj.config.uncheckedValue ? obj.config.uncheckedValue !== val : val) ? ' checked' : ''; - el = `
`; + // Check if this is a multi choice checkbox + if (options.length) { + el = `

`; + options.forEach((opt, index) => { + const option = opt.split(':')[0]; + const subtype = opt.split(':')[1]; + let textboxVal; + let disable; + + // If this is choice with possibility of adding free text add a text input else only a checkbox + if (subtype === 'textbox') { + checked = val[val.length - 1] && options.indexOf(val[val.length - 1]) === -1 ? ' checked' : ''; + textboxVal = checked ? val[val.length - 1] : ''; + disable = checked ? '' : ' disabled'; + el += ` ${option}: `; + el += ``; + el += '
'; + } else { + checked = val.indexOf(option) > -1 ? ' checked' : ''; + el += ` ${option}
`; + } + }); + el += '
'; + } else { + checked = (obj.config && obj.config.uncheckedValue ? obj.config.uncheckedValue !== val : val) ? ' checked' : ''; + el = `
`; + } break; case 'dropdown': if (val) { diff --git a/src/controls/editor/edithandler.js b/src/controls/editor/edithandler.js index 3b5038a10..48088a30b 100644 --- a/src/controls/editor/edithandler.js +++ b/src/controls/editor/edithandler.js @@ -888,17 +888,21 @@ function onAttributesSave(features, attrs) { document.getElementById(`o-save-button-${currentLayer}`).addEventListener('click', (e) => { const editEl = {}; const valid = {}; + let checkboxValues = []; attrs.forEach((attribute) => { // Get the input container class const containerClass = `.${attribute.elId}`; // Get the input attributes // FIXME: Don't have to get from DOM, the same values are in 'attribute' // and it would be enough to call getElementId once anyway (called numerous times later on). - const inputType = document.getElementById(attribute.elId).getAttribute('type'); - const inputValue = document.getElementById(attribute.elId).value; - const inputName = document.getElementById(attribute.elId).getAttribute('name'); - const inputId = document.getElementById(attribute.elId).getAttribute('id'); - const inputRequired = document.getElementById(attribute.elId).required; + + let inputType = attribute.type ? attribute.type : ''; + // Check again for not missing when checkbox is part of multiple choice checkboxes + inputType = document.getElementById(`${attribute.elId}-0`) ? document.getElementById(`${attribute.elId}-0`).getAttribute('type') : inputType; + const inputValue = document.getElementById(attribute.elId) ? document.getElementById(attribute.elId).value : ''; + const inputName = attribute.name ? attribute.name : ''; + const inputId = attribute.elId ? attribute.elId : ''; + const inputRequired = document.getElementById(attribute.elId) ? document.getElementById(attribute.elId).required : ''; // If hidden element it should be excluded // By sheer luck, this prevents attributes to be changed in batch edit mode when checkbox is not checked. @@ -906,9 +910,31 @@ function onAttributesSave(features, attrs) { if (!document.querySelector(containerClass) || document.querySelector(containerClass).classList.contains('o-hidden') === false) { // Check if checkbox. If checkbox read state. if (inputType === 'checkbox') { - const checkedValue = (attribute.config && attribute.config.checkedValue) || 1; - const uncheckedValue = (attribute.config && attribute.config.uncheckedValue) || 0; - editEl[attribute.name] = document.getElementById(attribute.elId).checked ? checkedValue : uncheckedValue; + // Check if this is a multi choice checkbox + if (document.getElementById(`${attribute.elId}-0`)) { + if (document.getElementById(`${attribute.elId}-0`).getAttribute('type') === 'checkbox') { + if (attribute.options && attribute.options.length > 0) { + Array.from(document.getElementsByName(attribute.name)).forEach((element) => { + if (element.tagName === 'INPUT' && element.getAttribute("type") === 'checkbox' && element.checked === true) { + // Check if this is a free text checkbox + if (element.nextElementSibling.getAttribute("type") === 'text') { + checkboxValues.push(element.nextElementSibling.value.trim()); + } else { + checkboxValues.push(element.getAttribute("value")); + } + } + }); + + editEl[attribute.name] = checkboxValues.join('; '); + } else { + editEl[attribute.name] = $(attribute.elId).is(':checked') ? 1 : 0; + } + } + } else { // Read value from input text, textarea or select + const checkedValue = (attribute.config && attribute.config.checkedValue) || 1; + const uncheckedValue = (attribute.config && attribute.config.uncheckedValue) || 0; + editEl[attribute.name] = document.getElementById(attribute.elId).checked ? checkedValue : uncheckedValue; + } } else if (attribute.type === 'searchList') { // SearchList may have its value in another place than the input element itself. Query the "Component" instead. // Note that inputValue still contains the value of the input element, which is used to validate required. @@ -1060,6 +1086,7 @@ function onAttributesSave(features, attrs) { default: } valid.validates = !Object.values(valid).includes(false); + checkboxValues = []; }); // If valid, continue @@ -1097,6 +1124,35 @@ function addListener() { return fn; } +/** + * Returns a function that adds an event handler to enable/disable the textbox for a free text checkbox + * + * @function + * @name addCheckboxListener + * @kind function + * @param {any} ): (obj + * @returns {void} + */ +function addCheckboxListener() { + const fn = (obj) => { + Array.from(document.getElementsByName(obj.name)).forEach((element) => { + // Add a listener on the checkbox if it has input text as next element + if (element.tagName === 'INPUT' && element.getAttribute("type") === 'checkbox' && element.nextElementSibling.getAttribute("type") === 'text') { + element.addEventListener('change', (e) => { + if (element.checked === true) { + element.nextElementSibling.disabled = false; + } else { + element.nextElementSibling.value = ''; + element.nextElementSibling.disabled = true; + } + }); + } + }); + }; + + return fn; +} + /** * Returns a function that adds an event handler to read an image file when user selects a file. * */ @@ -1235,7 +1291,14 @@ function editAttributes(feat) { } else { alert('Villkor verkar inte vara rätt formulerat. Villkor formuleras enligt principen change:attribute:value'); } - } else if (obj.type === 'image') { + } else if (obj.type === 'checkbox') { + if (obj.options && obj.options.length > 0 && obj.val) { + obj.val = obj.val.split('; '); + } + obj.isVisible = true; + obj.elId = `input-${obj.name}`; + obj.addListener = addCheckboxListener(); + } else if (obj.type === 'image') { obj.isVisible = true; obj.elId = `input-${currentLayer}-${obj.name}`; obj.addListener = addImageListener();