Skip to content
Snippets Groups Projects
Verified Commit 904bc617 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

fix: update updater bind values and select logic #291

parent 19781626
No related branches found
No related tags found
No related merge requests found
...@@ -199,6 +199,7 @@ class SaveButton extends CustomElement { ...@@ -199,6 +199,7 @@ class SaveButton extends CustomElement {
const ignoreChanges = self.getOption("ignoreChanges"); const ignoreChanges = self.getOption("ignoreChanges");
const result = diff(self[originValuesSymbol], currentValues); const result = diff(self[originValuesSymbol], currentValues);
if (isArray(ignoreChanges) && ignoreChanges.length > 0) { if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
const itemsToRemove = []; const itemsToRemove = [];
for (const item of result) { for (const item of result) {
......
...@@ -336,22 +336,13 @@ class Select extends CustomControl { ...@@ -336,22 +336,13 @@ class Select extends CustomControl {
* @fires monster-selected this event is fired when the selection is set * @fires monster-selected this event is fired when the selection is set
*/ */
set value(value) { set value(value) {
let ignoreValues = this.getOption("ignoreValues", []);
if (!isArray(ignoreValues)) {
ignoreValues = [];
}
for (const v of ignoreValues) {
if (value === v) {
return;
}
}
const result = convertValueToSelection.call(this, value); const result = convertValueToSelection.call(this, value);
setSelection setSelection
.call(this, result.selection) .call(this, result.selection)
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addErrorAttribute(this, e); addErrorAttribute(this, e);
}); });
...@@ -410,7 +401,10 @@ class Select extends CustomControl { ...@@ -410,7 +401,10 @@ class Select extends CustomControl {
* @property {String} mapping.labelTemplate template with the label placeholders in the form ${name}, where name is the key (**) * @property {String} mapping.labelTemplate template with the label placeholders in the form ${name}, where name is the key (**)
* @property {String} mapping.valueTemplate template with the value placeholders in the form ${name}, where name is the key * @property {String} mapping.valueTemplate template with the value placeholders in the form ${name}, where name is the key
* @property {function|undefined} mapping.filter Filtering of values via a function * @property {function|undefined} mapping.filter Filtering of values via a function
* @property {Array} ignoreValues Ignore values in the selection and value * @property {Object} empty
* @property {String} empty.defaultValueRadio Default value if you use radio buttons
* @property {Array} empty.defaultValueCheckbox Default value if you use checkboxes
* @property {Array} empty.equivalents Equivalents for empty values
* @property {Object} formatter * @property {Object} formatter
* @property {function|undefined} formatter.selection format selection label * @property {function|undefined} formatter.selection format selection label
*/ */
...@@ -474,7 +468,11 @@ class Select extends CustomControl { ...@@ -474,7 +468,11 @@ class Select extends CustomControl {
valueTemplate: "", valueTemplate: "",
filter: null, filter: null,
}, },
ignoreValues: [undefined, null, ""], empty: {
defaultValueRadio: "",
defaultValueCheckbox: [],
equivalents: [undefined, null, "", NaN],
},
formatter: { formatter: {
selection: buildSelectionLabel, selection: buildSelectionLabel,
}, },
...@@ -540,7 +538,7 @@ class Select extends CustomControl { ...@@ -540,7 +538,7 @@ class Select extends CustomControl {
} }
} }
requestAnimationFrame(() => { setTimeout(() => {
let lastValue = self.value; let lastValue = self.value;
self[internalSymbol].attachObserver( self[internalSymbol].attachObserver(
new Observer(function () { new Observer(function () {
...@@ -551,7 +549,8 @@ class Select extends CustomControl { ...@@ -551,7 +549,8 @@ class Select extends CustomControl {
lastValue = n; lastValue = n;
setSelection setSelection
.call(self, n) .call(self, n)
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addErrorAttribute(self, e); addErrorAttribute(self, e);
}); });
...@@ -561,7 +560,7 @@ class Select extends CustomControl { ...@@ -561,7 +560,7 @@ class Select extends CustomControl {
); );
areOptionsAvailableAndInit.call(self); areOptionsAvailableAndInit.call(self);
}); },0);
return this; return this;
} }
...@@ -742,7 +741,8 @@ class Select extends CustomControl { ...@@ -742,7 +741,8 @@ class Select extends CustomControl {
setTimeout(() => { setTimeout(() => {
setSelection setSelection
.call(this, this.getOption("selection")) .call(this, this.getOption("selection"))
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addErrorAttribute(this, e); addErrorAttribute(this, e);
}); });
...@@ -1036,6 +1036,7 @@ function fetchIt(url, controlOptions) { ...@@ -1036,6 +1036,7 @@ function fetchIt(url, controlOptions) {
} }
result = setSelection.call(this, newValue); result = setSelection.call(this, newValue);
requestAnimationFrame(() => { requestAnimationFrame(() => {
checkOptionState.call(this); checkOptionState.call(this);
setStatusOrRemoveBadges.call(this, "closed"); setStatusOrRemoveBadges.call(this, "closed");
...@@ -1118,7 +1119,7 @@ function attachResizeObserver() { ...@@ -1118,7 +1119,7 @@ function attachResizeObserver() {
}); });
}); });
requestAnimationFrame(() => {
let parent = this.parentNode; let parent = this.parentNode;
while (!(parent instanceof HTMLElement) && parent !== null) { while (!(parent instanceof HTMLElement) && parent !== null) {
parent = parent.parentNode; parent = parent.parentNode;
...@@ -1127,7 +1128,7 @@ function attachResizeObserver() { ...@@ -1127,7 +1128,7 @@ function attachResizeObserver() {
if (parent instanceof HTMLElement) { if (parent instanceof HTMLElement) {
this[resizeObserverSymbol].observe(parent); this[resizeObserverSymbol].observe(parent);
} }
});
} }
/** /**
...@@ -1351,17 +1352,13 @@ function initOptionObserver() { ...@@ -1351,17 +1352,13 @@ function initOptionObserver() {
self.updateI18n(); self.updateI18n();
} catch (e) { } catch (e) {
addErrorAttribute(self, e); addErrorAttribute(self, e);
requestAnimationFrame(() => {
setStatusOrRemoveBadges.call(self, "error"); setStatusOrRemoveBadges.call(self, "error");
});
} }
try { try {
areOptionsAvailableAndInit.call(self); areOptionsAvailableAndInit.call(self);
} catch (e) { } catch (e) {
addErrorAttribute(self, e); addErrorAttribute(self, e);
requestAnimationFrame(() => {
setStatusOrRemoveBadges.call(self, "error"); setStatusOrRemoveBadges.call(self, "error");
});
} }
setSummaryAndControlText.call(self); setSummaryAndControlText.call(self);
...@@ -1382,7 +1379,8 @@ function getDefaultTranslation() { ...@@ -1382,7 +1379,8 @@ function getDefaultTranslation() {
try { try {
const doc = getDocumentTranslations(); const doc = getDocumentTranslations();
translation.locale = doc.locale; translation.locale = doc.locale;
} catch (e) {} } catch (e) {
}
return translation; return translation;
} }
...@@ -2002,7 +2000,8 @@ function gatherState() { ...@@ -2002,7 +2000,8 @@ function gatherState() {
setSelection setSelection
.call(this, selection) .call(this, selection)
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addErrorAttribute(this, e); addErrorAttribute(this, e);
}); });
...@@ -2031,7 +2030,8 @@ function clearSelection() { ...@@ -2031,7 +2030,8 @@ function clearSelection() {
setSelection setSelection
.call(this, []) .call(this, [])
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addErrorAttribute(this, e); addErrorAttribute(this, e);
}); });
...@@ -2239,36 +2239,63 @@ function convertSelectionToValue(selection) { ...@@ -2239,36 +2239,63 @@ function convertSelectionToValue(selection) {
/** /**
* @private * @private
* @param {array|string} selection * @param value
* @return {Promise} * @returns {boolean}
* @throws {Error} no shadow-root is defined */
function isValueIsEmpty(value) {
let equivalents = this.getOption("empty.equivalents");
if (!isArray(equivalents)) {
if (equivalents === undefined) {
return false;
}
equivalents = [equivalents];
}
return equivalents.indexOf(value) !== -1;
}
/**
* @private
* @param value
* @returns {*}
*/
function isValueIsEmptyThenGetNormalize(value) {
let emptyDefault = null
if (this.getOption("type")==="checkbox") {
emptyDefault = this.getOption("empty.defaultValueCheckbox");
} else {
emptyDefault = this.getOption("empty.defaultValueRadio");
}
if (isValueIsEmpty.call(this,value)) {
return emptyDefault;
}
return value;
}
/**
* @private
* @param selection
* @returns {Promise<unknown | void>}
*/ */
function setSelection(selection) { function setSelection(selection) {
if (isString(selection) || isInteger(selection)) { if (isString(selection) || isInteger(selection)) {
const result = convertValueToSelection.call(this, selection); const result = convertValueToSelection.call(this, selection);
selection = result?.selection; selection = result?.selection;
} else if (selection === undefined || selection === null) {
selection = [];
} }
selection = isValueIsEmptyThenGetNormalize.call(this,selection);
validateArray(selection); validateArray(selection);
let ignoreValues = this.getOption("ignoreValues", []);
if (!isArray(ignoreValues)) {
ignoreValues = [];
}
let resultSelection = []; let resultSelection = [];
for (let i = 0; i < selection.length; i++) { for (let i = 0; i < selection.length; i++) {
let ignore = false;
for (const v of ignoreValues) { if(isValueIsEmpty.call(this,selection[i].value)) {
if (selection[i].value === v) { continue
ignore = true;
break;
}
}
if (ignore) {
continue;
} }
let l = getSelectionLabel.call(this, selection[i].value); let l = getSelectionLabel.call(this, selection[i].value);
...@@ -2285,6 +2312,7 @@ function setSelection(selection) { ...@@ -2285,6 +2312,7 @@ function setSelection(selection) {
selection = resultSelection; selection = resultSelection;
this.setOption("selection", selection); this.setOption("selection", selection);
checkOptionState.call(this); checkOptionState.call(this);
setSummaryAndControlText.call(this); setSummaryAndControlText.call(this);
...@@ -2298,7 +2326,7 @@ function setSelection(selection) { ...@@ -2298,7 +2326,7 @@ function setSelection(selection) {
selection, selection,
}); });
//fireEvent(this, "change"); // https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/291 fireEvent(this, "change"); // https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/291
return new Processing(() => { return new Processing(() => {
const CLASSNAME = "selected"; const CLASSNAME = "selected";
......
...@@ -29,7 +29,7 @@ import { ...@@ -29,7 +29,7 @@ import {
} from "./constants.mjs"; } from "./constants.mjs";
import {Base} from "../types/base.mjs"; import {Base} from "../types/base.mjs";
import { isArray, isString, isInstance, isIterable } from "../types/is.mjs"; import {isArray, isInteger, isString, isInstance, isIterable} from "../types/is.mjs";
import {Observer} from "../types/observer.mjs"; import {Observer} from "../types/observer.mjs";
import {ProxyObserver} from "../types/proxyobserver.mjs"; import {ProxyObserver} from "../types/proxyobserver.mjs";
import {validateArray, validateInstance} from "../types/validate.mjs"; import {validateArray, validateInstance} from "../types/validate.mjs";
...@@ -43,9 +43,19 @@ import { ...@@ -43,9 +43,19 @@ import {
import {findTargetElementFromEvent} from "./events.mjs"; import {findTargetElementFromEvent} from "./events.mjs";
import {findDocumentTemplate} from "./template.mjs"; import {findDocumentTemplate} from "./template.mjs";
import {getWindow} from "./util.mjs"; import {getWindow} from "./util.mjs";
import {DeadMansSwitch} from "../util/deadmansswitch.mjs";
import {addErrorAttribute, removeErrorAttribute} from "./error.mjs";
export {Updater, addObjectWithUpdaterToElement}; export {Updater, addObjectWithUpdaterToElement};
/**
* @private
* @type {symbol}
*/
const timerElementEventHandlerSymbol = Symbol("timerElementEventHandler");
/** /**
* The updater class connects an object with the DOM. In this way, structures and contents in the DOM can be * The updater class connects an object with the DOM. In this way, structures and contents in the DOM can be
* programmatically adapted via attributes. * programmatically adapted via attributes.
...@@ -309,11 +319,20 @@ function getControlEventHandler() { ...@@ -309,11 +319,20 @@ function getControlEventHandler() {
return; return;
} }
queueMicrotask(() => { if (this[timerElementEventHandlerSymbol] instanceof DeadMansSwitch) {
try {
this[timerElementEventHandlerSymbol].touch();
return;
} catch (e) {
delete this[timerElementEventHandlerSymbol];
}
}
this[timerElementEventHandlerSymbol] = new DeadMansSwitch(50, () => {
try { try {
retrieveAndSetValue.call(this, element); retrieveAndSetValue.call(this, element);
} catch (e) { } catch (e) {
addAttributeToken(element, ATTRIBUTE_ERRORMESSAGE, e.message || `${e}`); addErrorAttribute(element, e);
} }
}); });
}; };
...@@ -383,7 +402,6 @@ function retrieveAndSetValue(element) { ...@@ -383,7 +402,6 @@ function retrieveAndSetValue(element) {
throw new Error("unsupported object"); throw new Error("unsupported object");
} }
if (isString(value)) {
const type = element.getAttribute(ATTRIBUTE_UPDATER_BIND_TYPE); const type = element.getAttribute(ATTRIBUTE_UPDATER_BIND_TYPE);
switch (type) { switch (type) {
case "number": case "number":
...@@ -398,47 +416,96 @@ function retrieveAndSetValue(element) { ...@@ -398,47 +416,96 @@ function retrieveAndSetValue(element) {
case "boolean": case "boolean":
case "bool": case "bool":
case "checkbox": case "checkbox":
value = value === "true" || value === "1" || value === "on"; value = value === "true" || value === "1" || value === "on" || value === true;
break; break;
case "string[]": case "string[]":
if (value === "") { if (isString(value)) {
if (value.trim() === "") {
value = []; value = [];
} else {
value = value.split(",").map((v) => `${v}`);
}
} else if (isInteger(value)) {
value = [`${value}`];
} else if (value === undefined || value === null) {
value = [];
} else if (isArray(value)) {
value = value.map((v) => `${v}`);
} else {
throw new Error("unsupported value");
} }
value = value.split(",").map((v) => `${v}`);
break; break;
case "int[]": case "int[]":
case "integer[]": case "integer[]":
if (value === "") {
if (isString(value)) {
if (value.trim() === "") {
value = []; value = [];
} else { } else {
value = value value = value.split(",").map((v) => {
.split(",") try {
.map((v) => { return parseInt(v, 10);
} catch (e) {
}
return -1;
}).filter((v) => v !== -1);
}
} else if (isInteger(value)) {
value = [value];
} else if (value === undefined || value === null) {
value = [];
} else if (isArray(value)) {
value = value.split(",").map((v) => {
try { try {
return parseInt(v, 10); return parseInt(v, 10);
} catch (e) {} } catch (e) {
}
return -1; return -1;
}) }).filter((v) => v !== -1);
.filter((v) => v !== -1); } else {
throw new Error("unsupported value");
} }
break; break;
case "[]": case "[]":
case "array": case "array":
case "list": case "list":
if (isString(value)) {
if (value.trim() === "") {
value = [];
} else {
value = value.split(","); value = value.split(",");
}
} else if (isInteger(value)) {
value = [value];
} else if (value === undefined || value === null) {
value = [];
} else if (isArray(value)) {
// nothing to do
} else {
throw new Error("unsupported value for array");
}
break; break;
case "object": case "object":
case "json": case "json":
if (isString(value)) {
value = JSON.parse(value); value = JSON.parse(value);
} else {
throw new Error("unsupported value for object");
}
break; break;
default: default:
break; break;
} }
}
const copy = clone(this[internalSymbol].subject.getRealSubject()); const copy = clone(this[internalSymbol].subject.getRealSubject());
...@@ -560,7 +627,7 @@ function insertElement(change) { ...@@ -560,7 +627,7 @@ function insertElement(change) {
containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE); containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
value = pipe.run(subject); value = pipe.run(subject);
} catch (e) { } catch (e) {
containerElement.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message); addErrorAttribute(containerElement, e);
} }
const dataPath = cmd.split(":").pop(); const dataPath = cmd.split(":").pop();
...@@ -606,12 +673,7 @@ function insertElement(change) { ...@@ -606,12 +673,7 @@ function insertElement(change) {
try { try {
containerElement.removeChild(node); containerElement.removeChild(node);
} catch (e) { } catch (e) {
containerElement.setAttribute( addErrorAttribute(containerElement, e);
ATTRIBUTE_ERRORMESSAGE,
`${containerElement.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${
e.message
}`.trim(),
);
} }
} }
} }
...@@ -662,7 +724,10 @@ function appendNewDocumentFragment(container, key, ref, path) { ...@@ -662,7 +724,10 @@ function appendNewDocumentFragment(container, key, ref, path) {
* @return {void} * @return {void}
*/ */
function applyRecursive(node, key, path) { function applyRecursive(node, key, path) {
if (node instanceof HTMLElement) { if (!(node instanceof HTMLElement)) {
return
}
if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) { if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
const value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE); const value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
node.setAttribute( node.setAttribute(
...@@ -680,9 +745,11 @@ function applyRecursive(node, key, path) { ...@@ -680,9 +745,11 @@ function applyRecursive(node, key, path) {
} }
for (const [, child] of Object.entries(node.childNodes)) { for (const [, child] of Object.entries(node.childNodes)) {
if (child instanceof HTMLElement) {
applyRecursive(child, key, path); applyRecursive(child, key, path);
} }
} }
} }
/** /**
...@@ -770,12 +837,7 @@ function runUpdateContent(container, parts, subject) { ...@@ -770,12 +837,7 @@ function runUpdateContent(container, parts, subject) {
try { try {
element.appendChild(value); element.appendChild(value);
} catch (e) { } catch (e) {
element.setAttribute( addErrorAttribute(element, e);
ATTRIBUTE_ERRORMESSAGE,
`${element.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${
e.message
}`.trim(),
);
} }
} else { } else {
element.innerHTML = value; element.innerHTML = value;
...@@ -856,7 +918,7 @@ function runUpdateAttributes(container, parts, subject) { ...@@ -856,7 +918,7 @@ function runUpdateAttributes(container, parts, subject) {
element.removeAttribute(ATTRIBUTE_ERRORMESSAGE); element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
value = pipe.run(subject); value = pipe.run(subject);
} catch (e) { } catch (e) {
element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message); addErrorAttribute(element, e);
} }
if (value === undefined) { if (value === undefined) {
...@@ -979,18 +1041,13 @@ function addObjectWithUpdaterToElement(elements, symbol, object, config = {}) { ...@@ -979,18 +1041,13 @@ function addObjectWithUpdaterToElement(elements, symbol, object, config = {}) {
if (typeof callback === "function") { if (typeof callback === "function") {
updaterCallbacks.push([name, callback]); updaterCallbacks.push([name, callback]);
} else { } else {
addAttributeToken( addErrorAttribute(this, `onUpdaterPipeCallbacks: ${name} is not a function`);
this,
ATTRIBUTE_ERRORMESSAGE,
`onUpdaterPipeCallbacks: ${name} is not a function`,
);
} }
} }
} else { } else {
addAttributeToken( addErrorAttribute(
this, this,
ATTRIBUTE_ERRORMESSAGE, `onUpdaterPipeCallbacks do not return an object with functions`
`onUpdaterPipeCallbacks do not return an object with functions`,
); );
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment