From d7adf26ce64ac8982cd34b173a7074d722f81767 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 1 Mar 2022 16:56:58 -0700 Subject: [PATCH] Implement splitting up widget label using %s --- api/js/etemplate/Et2Button/Et2Button.ts | 17 ++-- api/js/etemplate/Et2Iframe/Et2Iframe.ts | 5 +- api/js/etemplate/Et2Widget/Et2Widget.ts | 111 +++++++++++++++++++++--- 3 files changed, 113 insertions(+), 20 deletions(-) diff --git a/api/js/etemplate/Et2Button/Et2Button.ts b/api/js/etemplate/Et2Button/Et2Button.ts index af32982aaf..aabecf37ec 100644 --- a/api/js/etemplate/Et2Button/Et2Button.ts +++ b/api/js/etemplate/Et2Button/Et2Button.ts @@ -9,9 +9,8 @@ */ -import {css, html} from "@lion/core"; +import {css, html, SlotMixin} from "@lion/core"; import {LionButton} from "@lion/button"; -import {SlotMixin} from "@lion/core"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {buttonStyles} from "./ButtonStyles"; @@ -143,6 +142,8 @@ export class Et2Button extends Et2InputWidget(SlotMixin(LionButton)) // ignore click on readonly button if(this.disabled || this.readonly) { + event.preventDefault(); + event.stopImmediatePropagation(); return false; } @@ -206,11 +207,15 @@ export class Et2Button extends Et2InputWidget(SlotMixin(LionButton)) } this._iconNode.src = this._image; - if (!this._label) this._iconNode.classList.add('imageOnly'); + if(!this.label) + { + this._iconNode.classList.add('imageOnly'); + } return html` -
- - ${this._label} +
+ + ${this.label}
`; } diff --git a/api/js/etemplate/Et2Iframe/Et2Iframe.ts b/api/js/etemplate/Et2Iframe/Et2Iframe.ts index bc49f7590b..4b70a954cd 100644 --- a/api/js/etemplate/Et2Iframe/Et2Iframe.ts +++ b/api/js/etemplate/Et2Iframe/Et2Iframe.ts @@ -63,8 +63,9 @@ export class Et2Iframe extends Et2Widget(SlotMixin(LitElement)) render() { return html` - - ${this._label} + + ${this.label} `; } diff --git a/api/js/etemplate/Et2Widget/Et2Widget.ts b/api/js/etemplate/Et2Widget/Et2Widget.ts index d518bd83df..47201ba564 100644 --- a/api/js/etemplate/Et2Widget/Et2Widget.ts +++ b/api/js/etemplate/Et2Widget/Et2Widget.ts @@ -7,7 +7,7 @@ import {et2_cloneObject, et2_csvSplit} from "../et2_core_common"; // @ts-ignore import type {IegwAppLocal} from "../../jsapi/egw_global"; import {ClassWithAttributes, ClassWithInterfaces} from "../et2_core_inheritance"; -import {css, dedupeMixin, unsafeCSS} from "@lion/core"; +import {css, dedupeMixin, PropertyValues, unsafeCSS} from "@lion/core"; import type {et2_container} from "../et2_core_baseWidget"; import type {et2_DOMWidget} from "../et2_core_DOMWidget"; @@ -74,7 +74,6 @@ const Et2WidgetMixin = (superClass) => */ protected _widget_id : string = ""; protected _dom_id : string = ""; - protected _label : string = ""; private statustext : string = ""; @@ -215,8 +214,6 @@ const Et2WidgetMixin = (superClass) => { super.connectedCallback(); - this.set_label(this._label); - if(this.statustext) { this.egw().tooltipBind(this, this.statustext); @@ -240,7 +237,7 @@ const Et2WidgetMixin = (superClass) => */ set_label(value : string) { - let oldValue = this._label; + let oldValue = this.label; // Remove old let oldLabels = this.getElementsByClassName("et2_label"); @@ -249,18 +246,18 @@ const Et2WidgetMixin = (superClass) => this.removeChild(oldLabels[0]); } - this._label = value; + this.__label = value; if(value) { if(this._labelNode) { - this._labelNode.textContent = this._label; + this._labelNode.textContent = this.__label; } else { let label = document.createElement("span"); label.classList.add("et2_label"); - label.textContent = this._label; + label.textContent = this.__label; // We should have a slot in the template for the label //label.slot="label"; this.appendChild(label); @@ -329,11 +326,59 @@ const Et2WidgetMixin = (superClass) => return this._widget_id; } - set label(value : string) + /** + * A property has changed, and we want to make adjustments to other things + * based on that + * + * @param {import('@lion/core').PropertyValues } changedProperties + */ + updated(changedProperties : PropertyValues) { - let oldValue = this.label; - this._label = value; - this.requestUpdate('label', oldValue); + super.updated(changedProperties); + + // required changed, add / remove validator + if(changedProperties.has('label')) + { + this._set_label(this.label); + } + } + + /** + * Do some fancy stuff on the label, splitting it up if there's a %s in it + * + * Normally called from updated(), the "normal" setter stuff has already been run before + * this is called. We only override our special cases (%s) because the normal label has + * been set by the parent + * + * @param value + * @protected + */ + protected _set_label(value : string) + { + if(!this._labelNode) + { + return; + } + // Remove any existing post label + let existing = (Array.from(this.children)).find( + (el : Element) => el.slot === "after" && el.tagName === "LABEL", + ) + if(existing) + { + this.removeChild(existing); + } + + // Split the label at the "%s" + let parts = et2_csvSplit(value, 2, "%s"); + if(parts.length > 1) + { + let after = document.createElement("label"); + after.slot = "after"; + after.textContent = parts[1]; + this.appendChild(after); + + this._labelNode.textContent = parts[0]; + } } set class(value : string) @@ -388,6 +433,35 @@ const Et2WidgetMixin = (superClass) => return true; } + /** + * Get property-values as object + * + * @deprecated use widget methods + */ + get options() : object + { + const options : { [key : string] : any } = {}; + // @ts-ignore not sure how to tell TS this is a ReactiveElement and properties is a static getter + for(const name in this.constructor.properties) + { + options[name] = this[name]; + } + // adding attributes too + this.getAttributeNames().forEach(name => + { + options[name] = this.getAttribute(name); + }); + // add some (not declared) known properties + if(typeof this.get_value === 'function') + { + options.value = this.get_value(); + } + console.groupCollapsed("Deprecated widget.options use") + console.trace("Something called widget.options on ", this); + console.groupEnd(); + return options; + } + /** * Loads the widget tree from an XML node * @@ -1188,6 +1262,12 @@ function transformAttributes(widget, mgr : et2_arrayMgr, attributes) { attribute = "required"; } + // Skip these ones + // options is legacy / read-only + if(["options"].indexOf(attribute) > -1) + { + continue; + } const property = widget_class.getPropertyOptions(attribute); @@ -1226,6 +1306,13 @@ function transformAttributes(widget, mgr : et2_arrayMgr, attributes) break; } + // TODO: Figure out how to bind handlers directly, since we can do that now + /* (handlers can only be bound _after_ the widget is added to the DOM + if(attribute.startsWith("on") && typeof attrValue == "function") + { + widget.addEventListener(attribute, attrValue); + } + */ // Set as attribute or property, as appropriate. Don't set missing attributes. if(widget.getAttributeNames().indexOf(attribute) >= 0 || property.reflect && attrValue) {