From ddd72fd51a2db20ebafc4100a5b1ec274f1b93e1 Mon Sep 17 00:00:00 2001 From: nathan Date: Fri, 15 Jul 2022 12:56:24 -0600 Subject: [PATCH] Et2Select: Fix selects with static options from the server would not consistently keep any additional options set. Creation / lifecycle would sometimes set the extra options several times, and depending on the timing of the server response they might get overwritten, or overwrite the server options. Now keeping them separate to avoid this. --- api/js/etemplate/Et2Select/Et2Select.ts | 44 +++++++++-------- .../etemplate/Et2Select/Et2SelectCategory.ts | 7 +-- .../etemplate/Et2Select/Et2SelectCountry.ts | 9 ++-- api/js/etemplate/Et2Select/StaticOptions.ts | 49 ++++++++++++++++++- 4 files changed, 80 insertions(+), 29 deletions(-) diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts index cc577627b4..59e56f1776 100644 --- a/api/js/etemplate/Et2Select/Et2Select.ts +++ b/api/js/etemplate/Et2Select/Et2Select.ts @@ -9,7 +9,7 @@ import {css, html, PropertyValues, TemplateResult} from "@lion/core"; -import {StaticOptions} from "./StaticOptions"; +import {Et2StaticSelectMixin, StaticOptions} from "./StaticOptions"; import {Et2widgetWithSelectMixin} from "./Et2WidgetWithSelectMixin"; import {SelectOption} from "./FindSelectOptions"; import {SlMenuItem, SlSelect} from "@shoelace-style/shoelace"; @@ -537,20 +537,20 @@ if(typeof customElements.get("lion-validation-feedback") === "undefined") const so = new StaticOptions(); -export class Et2SelectApp extends Et2Select +export class Et2SelectApp extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.app(this, {other: this.other || []}); + this.static_options = so.app(this, {other: this.other || []}); } } // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-app", Et2SelectApp); -export class Et2SelectBitwise extends Et2Select +export class Et2SelectBitwise extends Et2StaticSelectMixin(Et2Select) { set value(new_value) { @@ -574,13 +574,13 @@ export class Et2SelectBitwise extends Et2Select // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-bitwise", Et2SelectBitwise); -export class Et2SelectBool extends Et2Select +export class Et2SelectBool extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.bool(this); + this.static_options = so.bool(this); } } @@ -588,59 +588,59 @@ export class Et2SelectBool extends Et2Select customElements.define("et2-select-bool", Et2SelectBool); -export class Et2SelectDay extends Et2Select +export class Et2SelectDay extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.day(this, {other: this.other || []}); + this.static_options = so.day(this, {other: this.other || []}); } } // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-day", Et2SelectDay); -export class Et2SelectDayOfWeek extends Et2Select +export class Et2SelectDayOfWeek extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.dow(this, {other: this.other || []}); + this.static_options = so.dow(this, {other: this.other || []}); } } // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-dow", Et2SelectDayOfWeek); -export class Et2SelectHour extends Et2Select +export class Et2SelectHour extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.hour(this, {other: this.other || []}); + this.static_options = so.hour(this, {other: this.other || []}); } } // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-hour", Et2SelectHour); -export class Et2SelectMonth extends Et2Select +export class Et2SelectMonth extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.month(this); + this.static_options = so.month(this); } } // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-month", Et2SelectMonth); -export class Et2SelectNumber extends Et2Select +export class Et2SelectNumber extends Et2StaticSelectMixin(Et2Select) { static get properties() { @@ -681,7 +681,8 @@ export class Et2SelectNumber extends Et2Select if(changedProperties.has('min') || changedProperties.has('max') || changedProperties.has('interval') || changedProperties.has('suffix')) { - this.select_options = so.number(this); + this.static_options = so.number(this); + this.requestUpdate("select_options"); } } } @@ -704,20 +705,20 @@ export class Et2SelectPercent extends Et2SelectNumber // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-percent", Et2SelectPercent); -export class Et2SelectPriority extends Et2Select +export class Et2SelectPriority extends Et2StaticSelectMixin(Et2Select) { constructor() { super(); - this.select_options = so.priority(this); + this.static_options = so.priority(this); } } // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-priority", Et2SelectPriority); -export class Et2SelectState extends Et2Select +export class Et2SelectState extends Et2StaticSelectMixin(Et2Select) { /** * Two-letter ISO country code @@ -747,7 +748,8 @@ export class Et2SelectState extends Et2Select set country_code(code : string) { this.__country_code = code; - this.select_options = so.state(this, {country_code: this.__country_code}); + this.static_options = so.state(this, {country_code: this.__country_code}); + this.requestUpdate("select_options"); } set_country_code(code) @@ -759,7 +761,7 @@ export class Et2SelectState extends Et2Select // @ts-ignore TypeScript is not recognizing that this widget is a LitElement customElements.define("et2-select-state", Et2SelectState); -export class Et2SelectTimezone extends Et2Select +export class Et2SelectTimezone extends Et2StaticSelectMixin(Et2Select) { constructor() { diff --git a/api/js/etemplate/Et2Select/Et2SelectCategory.ts b/api/js/etemplate/Et2Select/Et2SelectCategory.ts index 9dac3856d8..418fe4bf9a 100644 --- a/api/js/etemplate/Et2Select/Et2SelectCategory.ts +++ b/api/js/etemplate/Et2Select/Et2SelectCategory.ts @@ -10,13 +10,13 @@ import {css, PropertyValues} from "@lion/core"; import {Et2Select} from "./Et2Select"; -import {StaticOptions} from "./StaticOptions"; +import {Et2StaticSelectMixin, StaticOptions} from "./StaticOptions"; /** * Customised Select widget for categories * This widget gives us category colors and icons in the options and selected value. */ -export class Et2SelectCategory extends Et2Select +export class Et2SelectCategory extends Et2StaticSelectMixin(Et2Select) { static get styles() { @@ -77,7 +77,8 @@ export class Et2SelectCategory extends Et2Select { so.cat(this).then(options => { - this.select_options = options + this.static_options = options + this.requestUpdate("select_options"); }); } } diff --git a/api/js/etemplate/Et2Select/Et2SelectCountry.ts b/api/js/etemplate/Et2Select/Et2SelectCountry.ts index 59dc3df5e9..1b0def85b8 100644 --- a/api/js/etemplate/Et2Select/Et2SelectCountry.ts +++ b/api/js/etemplate/Et2Select/Et2SelectCountry.ts @@ -9,9 +9,9 @@ import {Et2Select} from "./Et2Select"; -import {StaticOptions} from "./StaticOptions"; -import {SelectOption} from "./FindSelectOptions"; +import {Et2StaticSelectMixin, StaticOptions} from "./StaticOptions"; import {egw} from "../../jsapi/egw_global"; +import {SelectOption} from "./FindSelectOptions"; /** * Customised Select widget for countries @@ -19,7 +19,7 @@ import {egw} from "../../jsapi/egw_global"; */ egw(window).includeCSS("api/templates/default/css/flags.css") -export class Et2SelectCountry extends Et2Select +export class Et2SelectCountry extends Et2StaticSelectMixin(Et2Select) { static get properties() { @@ -38,7 +38,8 @@ export class Et2SelectCountry extends Et2Select (>so.country(this, {}, true)).then(options => { - this.select_options = options + this.static_options = options + this.requestUpdate("select_options"); }); } } diff --git a/api/js/etemplate/Et2Select/StaticOptions.ts b/api/js/etemplate/Et2Select/StaticOptions.ts index 74154f507f..5a02adfa8a 100644 --- a/api/js/etemplate/Et2Select/StaticOptions.ts +++ b/api/js/etemplate/Et2Select/StaticOptions.ts @@ -14,6 +14,46 @@ import {Et2Select, Et2SelectNumber, Et2WidgetWithSelect} from "./Et2Select"; export type Et2SelectWidgets = Et2Select | Et2WidgetWithSelect | Et2SelectReadonly; +// Export the Interface for TypeScript +type Constructor = new (...args : any[]) => T; + +/** + * Base class for things that have static options + * + * We keep static options separate and concatenate them in to allow for extra options without + * overwriting them when we get static options from the server + */ + +export const Et2StaticSelectMixin = >(superclass : T) => +{ + class Et2StaticSelectOptions extends (superclass) + { + + protected static_options : SelectOption[]; + + constructor(...args) + { + super(...args); + + this.static_options = []; + } + + get select_options() : SelectOption[] + { + // @ts-ignore + return [...super.select_options, ...this.static_options]; + } + + set select_options(new_options) + { + // @ts-ignore IDE doesn't recognise property + super.select_options = new_options; + } + } + + return Et2StaticSelectOptions; +} + /** * Some options change, or are too complicated to have twice, so we get the * options from the server once, then keep them to use if they're needed again. @@ -68,7 +108,14 @@ export class StaticOptions // Avoid errors if widget is destroyed before the timeout if(widget && typeof widget.id !== 'undefined') { - widget.set_select_options(find_select_options(widget, {}, cache)); + if(typeof widget.set_static_options == "function") + { + widget.set_static_options(cache); + } + else if(typeof widget.set_select_options == "function") + { + widget.set_select_options(find_select_options(widget, {}, cache)); + } } }); return return_promise ? promise : [];