diff --git a/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts b/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts index 7b2795f3eb..6a16d398ae 100644 --- a/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts +++ b/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts @@ -86,6 +86,8 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select) // Select options are based off abilities registered with link system this._reset_select_options(); + + this._handleChange = this._handleChange.bind(this); } connectedCallback() @@ -104,20 +106,13 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select) this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar"); // Register to - this.addEventListener("sl-change", () => - { - // Set icon - this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar"); + this.addEventListener("change", this._handleChange); + } - // update preference - let appname = ""; - if(typeof this.value != 'undefined' && this.parentNode && this.parentNode.to_app) - { - appname = this.parentNode.to_app; - } - this.egw().set_preference(appname || this.egw().app_name(), 'link_app', this.value); - this.dispatchEvent(new Event("change")); - }); + disconnectedCallback() + { + super.disconnectedCallback(); + this.removeEventListener("change", this._handleChange); } /** @@ -135,6 +130,20 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select) } } + private _handleChange(e) + { + // Set icon + this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar"); + + // update preference + let appname = ""; + if(typeof this.value != 'undefined' && this.parentNode && this.parentNode.to_app) + { + appname = this.parentNode.to_app; + } + this.egw().set_preference(appname || this.egw().app_name(), 'link_app', this.value); + } + /** * Limited select options here * This method will check properties and set select options appropriately diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts index a6605bedcb..f7398afd47 100644 --- a/api/js/etemplate/Et2Select/Et2Select.ts +++ b/api/js/etemplate/Et2Select/Et2Select.ts @@ -67,45 +67,6 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect) ]; } - get slots() - { - return { - ...super.slots, - input: () => - { - return document.createElement("select"); - } - } - } - - connectedCallback() - { - super.connectedCallback(); - //MOVE options that were set as children inside SELECT: - //this.querySelector('select').append(...this.querySelectorAll('option')); - } - - firstUpdated(changedProperties) - { - super.firstUpdated(changedProperties); - - // if _inputNode was not available by the time set_value() got called - if(this.getValue() !== this.value) - { - this.set_value(this.modelValue); - } - } - - /** - * Get the node where we're putting the selection options - * - * @returns {HTMLElement} - */ - get _optionTargetNode() : HTMLElement - { - return this; - } - static get properties() { return { @@ -126,6 +87,70 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect) } } + get slots() + { + return { + ...super.slots, + input: () => + { + return document.createElement("select"); + } + } + } + + constructor() + { + super(); + this._triggerChange = this._triggerChange.bind(this); + } + + connectedCallback() + { + super.connectedCallback(); + //MOVE options that were set as children inside SELECT: + //this.querySelector('select').append(...this.querySelectorAll('option')); + + this.getUpdateComplete().then(() => + { + this.addEventListener("sl-clear", this._triggerChange) + this.addEventListener("sl-select", this._triggerChange); + }); + } + + disconnectedCallback() + { + super.disconnectedCallback(); + + this.removeEventListener("sl-clear", this._triggerChange) + this.removeEventListener("sl-select", this._triggerChange); + } + + firstUpdated(changedProperties) + { + super.firstUpdated(changedProperties); + + // if _inputNode was not available by the time set_value() got called + if(this.getValue() !== this.value) + { + this.set_value(this.modelValue); + } + } + + _triggerChange(e) + { + this.dispatchEvent(new Event("change")); + } + + /** + * Get the node where we're putting the selection options + * + * @returns {HTMLElement} + */ + get _optionTargetNode() : HTMLElement + { + return this; + } + /** * @deprecated use this.multiple = multi * @@ -136,64 +161,9 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect) this.multiple = multi; } - /** - * Reimplemented to return string[] for multiple - */ - get value() : string|string[] + set_value(val) { - if (!this._inputNode || !this.select_options.length) - { - return this.__value || ''; - } - if (!this.multiple) - { - return this._inputNode.value || this.__value || ''; - } - // multi-selection value - const selected = this._inputNode.querySelectorAll('option:checked'); - return Array.from(selected).map(el => (el).value); - } - - /** - * Reimplemented to select options for multiple - * - * @param value - */ - set value(value: string|string[]) - { - // if not yet connected to dom can't change the value - if (this._inputNode && this.select_options.length) - { - // split multiple comma-separated values for multiple or expand_multiple_rows - if (typeof value === 'string' && (this.multiple || this.expand_multiple_rows) && value.indexOf(',') !== -1) - { - value = value.split(','); - } - // if we get more than one value AND expand_multiple_rows is set --> switch to multiple - if (!this.multiple && this.expand_multiple_rows && Array.isArray(value) && value.length > 1) - { - this.multiple = true; - this.size = this.expand_multiple_rows; - } - if (!this.multiple) - { - this._inputNode.value = value; - } - else - { - this._inputNode.multiple = true; // in case property is not yet set, selectbox will unselect all other options - this._inputNode.querySelectorAll('option').forEach((el : HTMLOptionElement) => - { - el.selected = [].concat(value).find(val => val == el.value); - }); - } - /** @type {string | undefined} */ - this.__value = undefined; - } - else - { - this.__value = value; - } + this.value = val; } /** @@ -203,7 +173,7 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect) */ _callParser(value = this.formattedValue) { - if (this.multiple && Array.isArray(value)) + if(this.multiple && Array.isArray(value)) { return value; } diff --git a/api/js/etemplate/Styles/shoelace.ts b/api/js/etemplate/Styles/shoelace.ts index 5dc34eeb9f..15d453a5bb 100644 --- a/api/js/etemplate/Styles/shoelace.ts +++ b/api/js/etemplate/Styles/shoelace.ts @@ -12,7 +12,8 @@ registerIconLibrary('default', { }); /** - * Override some shoelace icons with EGroupware + * Override some shoelace icons with EGroupware icons + * In particular, the data: ones give errors with our CSP */ const egw_icons = {'chevron-down': 'arrow_down'} registerIconLibrary("system", {