diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts
index a7ac9e3b42..88b60207e3 100644
--- a/api/js/etemplate/Et2Select/Et2Select.ts
+++ b/api/js/etemplate/Et2Select/Et2Select.ts
@@ -17,7 +17,7 @@ import {RowLimitedMixin} from "../Layout/RowLimitedMixin";
import {Et2Tag} from "./Tag/Et2Tag";
import {Et2WithSearchMixin} from "./SearchMixin";
import {property} from "lit/decorators/property.js";
-import {SlChangeEvent, SlSelect} from "@shoelace-style/shoelace";
+import {SlChangeEvent, SlOption, SlSelect} from "@shoelace-style/shoelace";
import {repeat} from "lit/directives/repeat.js";
// export Et2WidgetWithSelect which is used as type in other modules
@@ -556,59 +556,6 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
}
*/
- _emptyLabelTemplate() : TemplateResult
- {
- if(!this.emptyLabel || this.multiple)
- {
- return html``;
- }
- return html`
- v == "")}
- >
- ${this.emptyLabel}
- `;
- }
-
- protected _optionsTemplate() : TemplateResult
- {
- return html`${repeat(this.select_options
- // Filter out empty values if we have empty label to avoid duplicates
- .filter(o => this.emptyLabel ? o.value !== '' : o), this._groupTemplate.bind(this))
- }`;
- }
-
- /**
- * Used to render each option into the select
- *
- * @param {SelectOption} option
- * @returns {TemplateResult}
- */
- protected _optionTemplate(option : SelectOption) : TemplateResult
- {
- // Exclude non-matches when searching
- if(typeof option.isMatch == "boolean" && !option.isMatch)
- {
- return html``;
- }
-
- // Tag used must match this.optionTag, but you can't use the variable directly.
- // Pass option along so SearchMixin can grab it if needed
- const value = (option.value).replaceAll(" ", "___");
- return html`
- v == value)}
- ?disabled=${option.disabled}
- >
- ${this._iconTemplate(option)}
- ${this.noLang ? option.label : this.egw().lang(option.label)}
- `;
- }
-
/**
* Tag used for rendering tags when multiple=true
* Used for creating, finding & filtering options.
@@ -620,54 +567,6 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
return literal`et2-tag`;
}
- /**
- * Custom tag
- * @param {Et2Option} option
- * @param {number} index
- * @returns {TemplateResult}
- * @protected
- */
- protected _tagTemplate(option : Et2Option, index : number) : TemplateResult
- {
- const readonly = (this.readonly || option && typeof (option.disabled) != "undefined" && option.disabled);
- const isEditable = this.editModeEnabled && !readonly;
- const image = this._createImage(option);
- const tagName = this.tagTag;
- return html`
- <${tagName}
- part="tag"
- exportparts="
- base:tag__base,
- content:tag__content,
- remove-button:tag__remove-button,
- remove-button__base:tag__remove-button__base,
- icon:icon
- "
- class=${"search_tag " + option.classList.value}
- ?pill=${this.pill}
- size=${this.size}
- ?removable=${!readonly}
- ?readonly=${readonly}
- ?editable=${isEditable}
- .value=${option.value.replaceAll("___", " ")}
- @dblclick=${this._handleDoubleClick}
- @click=${typeof this.onTagClick == "function" ? (e) => this.onTagClick(e, e.target) : nothing}
- >
- ${image ?? nothing}
- ${option.getTextLabel().trim()}
- ${tagName}>
- `;
- }
-
- /**
- * Additional customisation template
- * @returns {*}
- * @protected
- */
- protected _extraTemplate()
- {
- return typeof super._extraTemplate == "function" ? super._extraTemplate() : nothing;
- }
/**
* Customise how tags are rendered. This overrides what SlSelect
@@ -867,6 +766,141 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
return this.shadowRoot?.querySelector("sl-select");
}
+ /**
+ * Custom, dynamic styling
+ *
+ * Put as much as you can in static styles for performance reasons
+ * Override this for custom dynamic styles
+ *
+ * @returns {TemplateResult}
+ * @protected
+ */
+ protected _styleTemplate() : TemplateResult
+ {
+ return null;
+ }
+
+ /**
+ * Used for the "no value" option for single select
+ * Placeholder is used for multi-select with no value
+ *
+ * @returns {TemplateResult}
+ */
+ _emptyLabelTemplate() : TemplateResult
+ {
+ if(!this.emptyLabel || this.multiple)
+ {
+ return html``;
+ }
+ return html`
+ v == "")}
+ >
+ ${this.emptyLabel}
+ `;
+ }
+
+ /**
+ * Iterate over all the options
+ * @returns {TemplateResult}
+ * @protected
+ */
+ protected _optionsTemplate() : TemplateResult
+ {
+ return html`${repeat(this.select_options
+ // Filter out empty values if we have empty label to avoid duplicates
+ .filter(o => this.emptyLabel ? o.value !== '' : o), this._groupTemplate.bind(this))
+ }`;
+ }
+
+ /**
+ * Used to render each option into the select
+ * Override for custom select options. Note that spaces are not allowed in option values,
+ * and sl-select _requires_ options to be
+ *
+ * @param {SelectOption} option
+ * @returns {TemplateResult}
+ */
+ protected _optionTemplate(option : SelectOption) : TemplateResult
+ {
+ // Exclude non-matches when searching
+ if(typeof option.isMatch == "boolean" && !option.isMatch)
+ {
+ return html``;
+ }
+
+ // Tag used must match this.optionTag, but you can't use the variable directly.
+ // Pass option along so SearchMixin can grab it if needed
+ const value = (option.value).replaceAll(" ", "___");
+ return html`
+ v == value)}
+ ?disabled=${option.disabled}
+ >
+ ${this._iconTemplate(option)}
+ ${this.noLang ? option.label : this.egw().lang(option.label)}
+ `;
+ }
+
+
+ /**
+ * Custom tag
+ *
+ * Override this to customise display when multiple=true.
+ * There is no restriction on the tag used, unlike _optionTemplate()
+ *
+ * @param {Et2Option} option
+ * @param {number} index
+ * @returns {TemplateResult}
+ * @protected
+ */
+ protected _tagTemplate(option : SlOption, index : number) : TemplateResult
+ {
+ const readonly = (this.readonly || option && typeof (option.disabled) != "undefined" && option.disabled);
+ const isEditable = this.editModeEnabled && !readonly;
+ const image = this._createImage(option);
+ const tagName = this.tagTag;
+ return html`
+ <${tagName}
+ part="tag"
+ exportparts="
+ base:tag__base,
+ content:tag__content,
+ remove-button:tag__remove-button,
+ remove-button__base:tag__remove-button__base,
+ icon:icon
+ "
+ class=${"search_tag " + option.classList.value}
+ ?pill=${this.pill}
+ size=${this.size || "medium"}
+ ?removable=${!readonly}
+ ?readonly=${readonly}
+ ?editable=${isEditable}
+ .value=${option.value.replaceAll("___", " ")}
+ @dblclick=${this._handleDoubleClick}
+ @click=${typeof this.onTagClick == "function" ? (e) => this.onTagClick(e, e.target) : nothing}
+ >
+ ${image ?? nothing}
+ ${option.getTextLabel().trim()}
+ ${tagName}>
+ `;
+ }
+
+ /**
+ * Additional customisation template
+ * Override if needed. Added after select options.
+ *
+ * @protected
+ */
+ protected _extraTemplate() : TemplateResult | typeof nothing
+ {
+ return typeof super._extraTemplate == "function" ? super._extraTemplate() : nothing;
+ }
+
public render()
{
const value = Array.isArray(this.value) ?
@@ -883,12 +917,13 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
}
}
return html`
+ ${this._styleTemplate()}
}
}
- protected _extraTemplate()
+ protected _extraTemplate() : TemplateResult | typeof nothing
{
if(!this.searchEnabled && !this.editModeEnabled && !this.allowFreeEntries || this.readonly)
{
diff --git a/api/js/etemplate/Et2Select/Select/Et2SelectAccount.ts b/api/js/etemplate/Et2Select/Select/Et2SelectAccount.ts
index 537d0cb213..6a77e3d55f 100644
--- a/api/js/etemplate/Et2Select/Select/Et2SelectAccount.ts
+++ b/api/js/etemplate/Et2Select/Select/Et2SelectAccount.ts
@@ -70,14 +70,6 @@ export class Et2SelectAccount extends SelectAccountMixin(Et2StaticSelectMixin(Et
this.fetchComplete = Promise.all(fetch);
}
-
- firstUpdated(changedProperties?)
- {
- super.firstUpdated(changedProperties);
- // Due to the different way Et2SelectAccount handles options, we call this explicitly
- this._renderOptions();
- }
-
set accountType(type : AccountType)
{
this.__accountType = type;
diff --git a/api/js/etemplate/Et2Select/Select/Et2SelectCategory.ts b/api/js/etemplate/Et2Select/Select/Et2SelectCategory.ts
index c462612b1e..084627bcc5 100644
--- a/api/js/etemplate/Et2Select/Select/Et2SelectCategory.ts
+++ b/api/js/etemplate/Et2Select/Select/Et2SelectCategory.ts
@@ -105,15 +105,15 @@ export class Et2SelectCategory extends Et2StaticSelectMixin(Et2Select)
}
/**
- * Used to render each option into the select
- * Overridden for colors
+ * Custom, dynamic styling
+ *
+ * CSS variables are not making it through to options, re-declaring them here works
*
- * @param {SelectOption} option
* @returns {TemplateResult}
+ * @protected
*/
- public render() : TemplateResult
+ protected _styleTemplate() : TemplateResult
{
- /** CSS variables are not making it through to options, re-declaring them here works */
return html`
- ${super.render()}
`;
}
@@ -141,20 +140,6 @@ export class Et2SelectCategory extends Et2StaticSelectMixin(Et2Select)
{
return literal`et2-category-tag`;
}
-
- /**
- * Customise how tags are rendered.
- * This overrides parent to set application
- *
- * @param item
- * @protected
- */
- protected _createTagNode(item)
- {
- let tag = super._createTagNode(item);
- tag.application = this.application;
- return tag;
- }
}
customElements.define("et2-select-cat", Et2SelectCategory);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts b/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts
index 98f4abe300..32fec1bd8e 100644
--- a/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts
+++ b/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts
@@ -243,16 +243,6 @@ export class Et2SelectEmail extends Et2Select
`;
}
- /**
- * Override image to skip it, we add images in Et2EmailTag using CSS
- * @param item
- * @protected
- */
- protected _createImage(item)
- {
- return this.multiple ? "" : super._createImage(item);
- }
-
/**
* Overwritten to NOT split RFC822 addresses containing a comma in quoted name part
*
diff --git a/api/js/etemplate/Et2Select/Tag/Et2Tag.ts b/api/js/etemplate/Et2Select/Tag/Et2Tag.ts
index 24fbbe26d0..1eab4fca40 100644
--- a/api/js/etemplate/Et2Select/Tag/Et2Tag.ts
+++ b/api/js/etemplate/Et2Select/Tag/Et2Tag.ts
@@ -35,6 +35,9 @@ export class Et2Tag extends Et2Widget(SlTag)
width: 20px;
}
+ .tag__prefix {
+ line-height: normal;
+ }
.tag__content {
padding: 0px 0.2rem;
flex: 1 2 auto;