From b4a13037e21362ffea618272df277b78717aa22a Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 19 Aug 2021 10:54:32 -0600 Subject: [PATCH] - Reduce duplication with loadWebComponent() by making it a function & exporting - Start to implement readonly attribute --- api/js/etemplate/Et2Button.ts | 9 +- api/js/etemplate/Et2Textbox.ts | 2 - api/js/etemplate/Et2Widget.ts | 153 +++++++++++++---------- api/js/etemplate/et2_core_inputWidget.ts | 4 + api/js/etemplate/et2_core_widget.ts | 60 +-------- 5 files changed, 102 insertions(+), 126 deletions(-) diff --git a/api/js/etemplate/Et2Button.ts b/api/js/etemplate/Et2Button.ts index a303620bd5..e415b36cd4 100644 --- a/api/js/etemplate/Et2Button.ts +++ b/api/js/etemplate/Et2Button.ts @@ -31,6 +31,9 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton)) border-radius: 3px; background-color: #e6e6e6; } + :host([readonly]) { + display: none; + } /* Set size for icon */ ::slotted([slot="icon"]) { width: 20px; @@ -78,8 +81,6 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton)) this._created_icon_node.src = egw.image(this.image); this.appendChild(this._created_icon_node); } - - this.addEventListener("click", this._handleClick.bind(this)); } @@ -87,7 +88,7 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton)) { debugger; // ignore click on readonly button - if(this.disabled) return false; + if(this.disabled || this.readonly) return false; this.clicked = true; @@ -110,6 +111,8 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton)) render() { + if(this.readonly) return ''; + return html`
diff --git a/api/js/etemplate/Et2Textbox.ts b/api/js/etemplate/Et2Textbox.ts index 09d86f37e6..cc464f6e77 100644 --- a/api/js/etemplate/Et2Textbox.ts +++ b/api/js/etemplate/Et2Textbox.ts @@ -38,9 +38,7 @@ export class Et2Textbox extends Et2InputWidget(Et2Widget(LionInput)) constructor() { - debugger; super(); - } connectedCallback() diff --git a/api/js/etemplate/Et2Widget.ts b/api/js/etemplate/Et2Widget.ts index 1a3a9a98b4..b5a474b988 100644 --- a/api/js/etemplate/Et2Widget.ts +++ b/api/js/etemplate/Et2Widget.ts @@ -39,10 +39,11 @@ export const Et2Widget = >(superClass : T) => private _legacy_children : et2_widget[] = []; /** - * Properties + * Properties - default values, and actually creating them as fields */ private label : string = ""; private statustext : string = ""; + private disabled : Boolean = false; /** WebComponent **/ @@ -51,6 +52,15 @@ export const Et2Widget = >(superClass : T) => return { ...super.properties, + /** + * Defines whether this widget is visible. + * Not to be confused with an input widget's HTML attribute 'disabled'.", + */ + disabled: { + type: Boolean, + reflect: true + }, + /** * Tooltip which is shown for this element on hover */ @@ -90,11 +100,17 @@ export const Et2Widget = >(superClass : T) => { this.egw().tooltipBind(this, this.statustext); } + if(this.onclick && !this.disabled) + { + this.addEventListener("click", this._handleClick.bind(this)); + } } disconnectedCallback() { this.egw().tooltipUnbind(this); + + this.removeEventListener("click", this._handleClick.bind(this)); } /** @@ -217,12 +233,12 @@ export const Et2Widget = >(superClass : T) => // Parse the "readonly" and "type" flag for this element here, as they // determine which constructor is used - var _nodeName = attributes["type"] = _node.getAttribute("type") ? + let _nodeName = attributes["type"] = _node.getAttribute("type") ? _node.getAttribute("type") : _node.nodeName.toLowerCase(); - var readonly = attributes["readonly"] = this.getArrayMgr("readonlys") ? - (this.getArrayMgr("readonlys")).isReadOnly( - _node.getAttribute("id"), _node.getAttribute("readonly"), - typeof this.readonly !== "undefined" ? this.readonly : false) : false; + const readonly = attributes["readonly"] = this.getArrayMgr("readonlys") ? + (this.getArrayMgr("readonlys")).isReadOnly( + _node.getAttribute("id"), _node.getAttribute("readonly"), + typeof this.readonly !== "undefined" ? this.readonly : false) : false; // Check to see if modifications change type var modifications = this.getArrayMgr("modifications"); @@ -284,7 +300,11 @@ export const Et2Widget = >(superClass : T) => } else { - widget = this.loadWebComponent(_nodeName, _node); + if(readonly === true && typeof window.customElements.get(_nodeName + "_ro") != "undefined") + { + _nodeName += "_ro"; + } + widget = loadWebComponent(_nodeName, _node, this); if(this.addChild) { @@ -295,62 +315,6 @@ export const Et2Widget = >(superClass : T) => return widget; } - /** - * Load a Web Component - * @param _nodeName - * @param _node - */ - loadWebComponent(_nodeName : string, _node) : HTMLElement - { - let widget = document.createElement(_nodeName); - widget.textContent = _node.textContent; - - const widget_class = window.customElements.get(_nodeName); - if(!widget_class) - { - throw Error("Unknown or unregistered WebComponent '" + _nodeName + "', could not find class"); - } - widget.setParent(this); - var mgr = widget.getArrayMgr("content"); - - // Apply any set attributes - widget will do its own coercion - _node.getAttributeNames().forEach(attribute => - { - let attrValue = _node.getAttribute(attribute); - - // If there is not attribute set, ignore it. Widget sets its own default. - if(typeof attrValue === "undefined") return; - - // If the attribute is marked as boolean, parse the - // expression as bool expression. - if(widget_class.getPropertyOptions(attribute).type == "Boolean") - { - attrValue = mgr.parseBoolExpression(attrValue); - } - else - { - attrValue = mgr.expandName(attrValue); - } - widget.setAttribute(attribute, attrValue); - }); - - if(widget_class.getPropertyOptions("value") && widget.set_value) - { - if(mgr != null) - { - let val = mgr.getEntry(widget.id, false, true); - if(val !== null) - { - widget.set_value(val); - } - } - } - - // Children need to be loaded - widget.loadFromXML(_node); - - return widget; - } /** * The parseXMLAttrs function takes an XML DOM attributes object @@ -806,4 +770,67 @@ export const Et2Widget = >(superClass : T) => applyMixins(Et2WidgetClass, [ClassWithInterfaces]); return Et2WidgetClass as unknown as Constructor & T; +} + +/** + * Load a Web Component + * @param _nodeName + * @param _template_node + */ +export function loadWebComponent(_nodeName : string, _template_node, parent : Et2WidgetClass | et2_widget) : HTMLElement +{ + let widget = document.createElement(_nodeName); + widget.textContent = _template_node.textContent; + + const widget_class = window.customElements.get(_nodeName); + if(!widget_class) + { + throw Error("Unknown or unregistered WebComponent '" + _nodeName + "', could not find class"); + } + widget.setParent(parent); + var mgr = widget.getArrayMgr("content"); + + // Set read-only. Doesn't really matter if it's a ro widget, but otherwise it needs set + widget.readonly = parent.getArrayMgr("readonlys") ? + (parent.getArrayMgr("readonlys")).isReadOnly( + _template_node.getAttribute("id"), _template_node.getAttribute("readonly"), + typeof parent.readonly !== "undefined" ? parent.readonly : false) : false; + + // Apply any set attributes - widget will do its own coercion + _template_node.getAttributeNames().forEach(attribute => + { + let attrValue = _template_node.getAttribute(attribute); + + // If there is not attribute set, ignore it. Widget sets its own default. + if(typeof attrValue === "undefined") return; + + // If the attribute is marked as boolean, parse the + // expression as bool expression. + if(widget_class.getPropertyOptions(attribute).type == "Boolean") + { + attrValue = mgr.parseBoolExpression(attrValue); + } + else + { + attrValue = mgr.expandName(attrValue); + } + widget.setAttribute(attribute, attrValue); + }); + + if(widget_class.getPropertyOptions("value") && widget.set_value) + { + if(mgr != null) + { + let val = mgr.getEntry(widget.id, false, true); + if(val !== null) + { + widget.set_value(val); + } + } + } + + // Children need to be loaded + widget.loadFromXML(_template_node); + + return widget; } \ No newline at end of file diff --git a/api/js/etemplate/et2_core_inputWidget.ts b/api/js/etemplate/et2_core_inputWidget.ts index bfb57a449a..b06e22f467 100644 --- a/api/js/etemplate/et2_core_inputWidget.ts +++ b/api/js/etemplate/et2_core_inputWidget.ts @@ -415,6 +415,10 @@ export const Et2InputWidget = (superClass: T) => { return { ...super.properties, + readonly: { + type: Boolean, + reflect: true + }, value: {attribute: false} }; } diff --git a/api/js/etemplate/et2_core_widget.ts b/api/js/etemplate/et2_core_widget.ts index 1a54eafc4f..8f55602550 100644 --- a/api/js/etemplate/et2_core_widget.ts +++ b/api/js/etemplate/et2_core_widget.ts @@ -22,6 +22,7 @@ import {egw, IegwAppLocal} from "../jsapi/egw_global"; import {et2_cloneObject, et2_csvSplit} from "./et2_core_common"; import {et2_compileLegacyJS} from "./et2_core_legacyJSFunctions"; import {et2_IDOMNode, et2_IInputNode} from "./et2_core_interfaces"; +import {loadWebComponent} from "./Et2Widget"; // fixing circular dependencies by only importing type import type {et2_container} from "./et2_core_baseWidget"; import type {et2_inputWidget} from "./et2_core_inputWidget"; @@ -802,7 +803,7 @@ export class et2_widget extends ClassWithAttributes } else { - widget = this.loadWebComponent(_nodeName, _node); + widget = loadWebComponent(_nodeName, _node, this); if (this.addChild) { @@ -813,63 +814,6 @@ export class et2_widget extends ClassWithAttributes return widget; } - /** - * Load a Web Component - * @param _nodeName - * @param _node - */ - loadWebComponent(_nodeName: string, _node): HTMLElement - { - let widget = document.createElement(_nodeName); - widget.textContent = _node.textContent; - - const widget_class = window.customElements.get(_nodeName); - if (!widget_class) - { - throw Error("Unknown or unregistered WebComponent '" + _nodeName + "', could not find class"); - } - widget.setParent(this); - var mgr = widget.getArrayMgr("content"); - debugger; - // Apply any set attributes - widget will do its own coercion - _node.getAttributeNames().forEach(attribute => - { - let attrValue = _node.getAttribute(attribute); - - // If there is not attribute set, ignore it. Widget sets its own default. - if (typeof attrValue === "undefined") return; - - // If the attribute is marked as boolean, parse the - // expression as bool expression. - if (widget_class.getPropertyOptions(attribute).type == "Boolean") - { - attrValue = mgr.parseBoolExpression(attrValue); - } - else - { - attrValue = mgr.expandName(attrValue); - } - widget.setAttribute(attribute, attrValue); - }); - - if (widget_class.getPropertyOptions("value") && widget.set_value) - { - if (mgr != null) - { - let val = mgr.getEntry(widget.id, false, true); - if (val !== null) - { - widget.setAttribute("value", val); - } - } - } - - // Children need to be loaded - widget.loadFromXML(_node); - - return widget; - } - /** * Loads the widget tree from an XML node *