- Reduce duplication with loadWebComponent() by making it a function & exporting

- Start to implement readonly attribute
This commit is contained in:
nathan 2021-08-19 10:54:32 -06:00
parent 0ea5e2e35f
commit b4a13037e2
5 changed files with 102 additions and 126 deletions

View File

@ -31,6 +31,9 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton))
border-radius: 3px; border-radius: 3px;
background-color: #e6e6e6; background-color: #e6e6e6;
} }
:host([readonly]) {
display: none;
}
/* Set size for icon */ /* Set size for icon */
::slotted([slot="icon"]) { ::slotted([slot="icon"]) {
width: 20px; width: 20px;
@ -78,8 +81,6 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton))
this._created_icon_node.src = egw.image(this.image); this._created_icon_node.src = egw.image(this.image);
this.appendChild(this._created_icon_node); 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; debugger;
// ignore click on readonly button // ignore click on readonly button
if(this.disabled) return false; if(this.disabled || this.readonly) return false;
this.clicked = true; this.clicked = true;
@ -110,6 +111,8 @@ export class Et2Button extends Et2InputWidget(Et2Widget(LionButton))
render() render()
{ {
if(this.readonly) return '';
return html` return html`
<div class="button-content et2_button" id="${this._buttonId}"> <div class="button-content et2_button" id="${this._buttonId}">
<slot name="icon"></slot> <slot name="icon"></slot>

View File

@ -38,9 +38,7 @@ export class Et2Textbox extends Et2InputWidget(Et2Widget(LionInput))
constructor() constructor()
{ {
debugger;
super(); super();
} }
connectedCallback() connectedCallback()

View File

@ -39,10 +39,11 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
private _legacy_children : et2_widget[] = []; private _legacy_children : et2_widget[] = [];
/** /**
* Properties * Properties - default values, and actually creating them as fields
*/ */
private label : string = ""; private label : string = "";
private statustext : string = ""; private statustext : string = "";
private disabled : Boolean = false;
/** WebComponent **/ /** WebComponent **/
@ -51,6 +52,15 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
return { return {
...super.properties, ...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 * Tooltip which is shown for this element on hover
*/ */
@ -90,11 +100,17 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
{ {
this.egw().tooltipBind(this, this.statustext); this.egw().tooltipBind(this, this.statustext);
} }
if(this.onclick && !this.disabled)
{
this.addEventListener("click", this._handleClick.bind(this));
}
} }
disconnectedCallback() disconnectedCallback()
{ {
this.egw().tooltipUnbind(this); this.egw().tooltipUnbind(this);
this.removeEventListener("click", this._handleClick.bind(this));
} }
/** /**
@ -217,12 +233,12 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
// Parse the "readonly" and "type" flag for this element here, as they // Parse the "readonly" and "type" flag for this element here, as they
// determine which constructor is used // 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(); _node.getAttribute("type") : _node.nodeName.toLowerCase();
var readonly = attributes["readonly"] = this.getArrayMgr("readonlys") ? const readonly = attributes["readonly"] = this.getArrayMgr("readonlys") ?
(<any>this.getArrayMgr("readonlys")).isReadOnly( (<any>this.getArrayMgr("readonlys")).isReadOnly(
_node.getAttribute("id"), _node.getAttribute("readonly"), _node.getAttribute("id"), _node.getAttribute("readonly"),
typeof this.readonly !== "undefined" ? this.readonly : false) : false; typeof this.readonly !== "undefined" ? this.readonly : false) : false;
// Check to see if modifications change type // Check to see if modifications change type
var modifications = this.getArrayMgr("modifications"); var modifications = this.getArrayMgr("modifications");
@ -284,7 +300,11 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
} }
else 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) if(this.addChild)
{ {
@ -295,62 +315,6 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
return widget; return widget;
} }
/**
* Load a Web Component
* @param _nodeName
* @param _node
*/
loadWebComponent(_nodeName : string, _node) : HTMLElement
{
let widget = <Et2WidgetClass>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 * The parseXMLAttrs function takes an XML DOM attributes object
@ -806,4 +770,67 @@ export const Et2Widget = <T extends Constructor<LitElement>>(superClass : T) =>
applyMixins(Et2WidgetClass, [ClassWithInterfaces]); applyMixins(Et2WidgetClass, [ClassWithInterfaces]);
return Et2WidgetClass as unknown as Constructor<et2_IDOMNode> & T; return Et2WidgetClass as unknown as Constructor<et2_IDOMNode> & T;
}
/**
* Load a Web Component
* @param _nodeName
* @param _template_node
*/
export function loadWebComponent(_nodeName : string, _template_node, parent : Et2WidgetClass | et2_widget) : HTMLElement
{
let widget = <Et2WidgetClass>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") ?
(<any>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;
} }

View File

@ -415,6 +415,10 @@ export const Et2InputWidget = <T extends Constructor>(superClass: T) =>
{ {
return { return {
...super.properties, ...super.properties,
readonly: {
type: Boolean,
reflect: true
},
value: {attribute: false} value: {attribute: false}
}; };
} }

View File

@ -22,6 +22,7 @@ import {egw, IegwAppLocal} from "../jsapi/egw_global";
import {et2_cloneObject, et2_csvSplit} from "./et2_core_common"; import {et2_cloneObject, et2_csvSplit} from "./et2_core_common";
import {et2_compileLegacyJS} from "./et2_core_legacyJSFunctions"; import {et2_compileLegacyJS} from "./et2_core_legacyJSFunctions";
import {et2_IDOMNode, et2_IInputNode} from "./et2_core_interfaces"; import {et2_IDOMNode, et2_IInputNode} from "./et2_core_interfaces";
import {loadWebComponent} from "./Et2Widget";
// fixing circular dependencies by only importing type // fixing circular dependencies by only importing type
import type {et2_container} from "./et2_core_baseWidget"; import type {et2_container} from "./et2_core_baseWidget";
import type {et2_inputWidget} from "./et2_core_inputWidget"; import type {et2_inputWidget} from "./et2_core_inputWidget";
@ -802,7 +803,7 @@ export class et2_widget extends ClassWithAttributes
} }
else else
{ {
widget = this.loadWebComponent(_nodeName, _node); widget = loadWebComponent(_nodeName, _node, this);
if (this.addChild) if (this.addChild)
{ {
@ -813,63 +814,6 @@ export class et2_widget extends ClassWithAttributes
return widget; return widget;
} }
/**
* Load a Web Component
* @param _nodeName
* @param _node
*/
loadWebComponent(_nodeName: string, _node): HTMLElement
{
let widget = <Et2WidgetClass>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 * Loads the widget tree from an XML node
* *