From 8b3f9947e6e8af9b0c5baa897aa7963ffcea0c2d Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 21 Jan 2020 12:22:22 +0100 Subject: [PATCH] baseWidget in TS --- api/js/etemplate/et2_core_DOMWidget.js | 1 + api/js/etemplate/et2_core_DOMWidget.ts | 6 +- api/js/etemplate/et2_core_baseWidget.js | 2 - api/js/etemplate/et2_core_baseWidget.ts | 448 ++++++++++++++++++++++++ api/js/etemplate/et2_core_widget.ts | 4 +- api/js/jsapi/egw_global.d.ts | 1 + 6 files changed, 455 insertions(+), 7 deletions(-) create mode 100644 api/js/etemplate/et2_core_baseWidget.ts diff --git a/api/js/etemplate/et2_core_DOMWidget.js b/api/js/etemplate/et2_core_DOMWidget.js index 5bd1f816de..40cf9e3f2f 100644 --- a/api/js/etemplate/et2_core_DOMWidget.js +++ b/api/js/etemplate/et2_core_DOMWidget.js @@ -535,6 +535,7 @@ var et2_DOMWidget = /** @class */ (function (_super) { }; return et2_DOMWidget; }(et2_core_widget_1.et2_widget)); +exports.et2_DOMWidget = et2_DOMWidget; /** * The surroundings manager class allows to append or prepend elements around * an widget node. diff --git a/api/js/etemplate/et2_core_DOMWidget.ts b/api/js/etemplate/et2_core_DOMWidget.ts index cbdf69d55d..21da82fac4 100644 --- a/api/js/etemplate/et2_core_DOMWidget.ts +++ b/api/js/etemplate/et2_core_DOMWidget.ts @@ -31,7 +31,7 @@ import { * * @augments et2_widget */ -abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode +export abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode { static readonly _attributes : any = { "disabled": { @@ -187,8 +187,8 @@ abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode * Detaches the widget from the DOM tree, if it had been attached to the * DOM-Tree using the attachToDOM method. */ - detachFromDOM() { - + detachFromDOM() + { if (this._attachSet.node && this._attachSet.parent) { // Remove the current node from the parent node diff --git a/api/js/etemplate/et2_core_baseWidget.js b/api/js/etemplate/et2_core_baseWidget.js index 017a3e13ba..f453fa1076 100644 --- a/api/js/etemplate/et2_core_baseWidget.js +++ b/api/js/etemplate/et2_core_baseWidget.js @@ -6,8 +6,6 @@ * @subpackage api * @link http://www.egroupware.org * @author Andreas Stöckel - * @copyright Stylite 2011 - * @version $Id$ */ /*egw:uses diff --git a/api/js/etemplate/et2_core_baseWidget.ts b/api/js/etemplate/et2_core_baseWidget.ts new file mode 100644 index 0000000000..f10cb4a1e8 --- /dev/null +++ b/api/js/etemplate/et2_core_baseWidget.ts @@ -0,0 +1,448 @@ +/** + * EGroupware eTemplate2 - JS Widget base class + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link http://www.egroupware.org + * @author Andreas Stöckel + */ + +/*egw:uses + /vendor/bower-asset/jquery/dist/jquery.js; + lib/tooltip; + et2_core_DOMWidget; +*/ + +//import { ClassWithAttributes } from './et2_core_inheritance'; +import './et2_core_interfaces'; +import './et2_core_common'; +import { et2_DOMWidget } from './et2_core_DOMWidget'; +import { ClassWithAttributes } from "./et2_core_inheritance"; +import { et2_widget, et2_createWidget, et2_register_widget, WidgetConfig } from "./et2_core_widget"; + +/** + * Class which manages the DOM node itself. The simpleWidget class is derrived + * from et2_DOMWidget and implements the getDOMNode function. A setDOMNode + * function is provided, which attatches the given node to the DOM if possible. + * + * @augments et2_DOMWidget + */ +class et2_baseWidget extends et2_DOMWidget implements et2_IAligned +{ + static readonly _attributes: any = { + "statustext": { + "name": "Tooltip", + "type": "string", + "description": "Tooltip which is shown for this element", + "translate": true + }, + "statustext_html": { + "name": "Tooltip is html", + "type": "boolean", + "description": "Flag to allow html content in tooltip", + "default": false + }, + "align": { + "name": "Align", + "type": "string", + "default": "left", + "description": "Position of this element in the parent hbox" + }, + "onclick": { + "name": "onclick", + "type": "js", + "default": et2_no_init, + "description": "JS code which is executed when the element is clicked." + } + } + + align: string = 'left'; + node: HTMLElement = null; + statustext: string = ''; + private _messageDiv: JQuery = null; + private _tooltipElem: JQuery = null; + onclick: any; + + /** + * Constructor + */ + constructor(_parent, _attrs? : WidgetConfig, _child? : object) + { + // Call the inherited constructor + super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_DOMWidget._attributes, _child || {})); + } + + destroy() + { + super.destroy(); + + this.node = null; + this._messageDiv = null; + } + + /** + * The setMessage function can be used to attach a small message box to the + * widget. This is e.g. used to display validation errors or success messages + * + * @param _text is the text which should be displayed as a message + * @param _type is an css class which is attached to the message box. + * Currently available are "hint", "success" and "validation_error", defaults + * to "hint" + * @param _floating if true, the object will be in one row with the element, + * defaults to true + * @param _prepend if set, the message is displayed behind the widget node + * instead of before. Defaults to false. + */ + showMessage(_text, _type, _floating, _prepend) + { + // Preset the parameters + if (typeof _type == "undefined") + { + _type = "hint"; + } + + if (typeof _floating == "undefined") + { + _floating = true; + } + + if (typeof _prepend == "undefined") + { + _prepend = false; + } + + var surr = this.getSurroundings(); + + // Remove the message div from the surroundings before creating a new + // one + this.hideMessage(false, true); + + // Create the message div and add it to the "surroundings" manager + this._messageDiv = jQuery(document.createElement("div")) + .addClass("message") + .addClass(_type) + .addClass(_floating ? "floating" : "") + .text(_text.valueOf() + ""); + + // Decide whether to prepend or append the div + if (_prepend) + { + surr.prependDOMNode(this._messageDiv[0]); + } + else + { + surr.appendDOMNode(this._messageDiv[0]); + } + + surr.update(); + } + + /** + * The hideMessage function can be used to hide a previously shown message. + * + * @param _fade if true, the message div will fade out, otherwise the message + * div is removed immediately. Defaults to true. + * @param _noUpdate is used internally to prevent an update of the surroundings + * manager. + */ + hideMessage(_fade, _noUpdate) + { + if (typeof _fade == "undefined") + { + _fade = true; + } + + if (typeof _noUpdate == "undefined") + { + _noUpdate = false; + } + + // Remove the message from the surroundings manager and remove the + // reference to it + if (this._messageDiv != null) + { + var surr = this.getSurroundings(); + var self = this; + var messageDiv = this._messageDiv; + self._messageDiv = null; + + var _done = function() { + surr.removeDOMNode(messageDiv[0]); + + // Update the surroundings manager + if (!_noUpdate) + { + surr.update(); + } + }; + + // Either fade out or directly call the function which removes the div + if (_fade) + { + messageDiv.fadeOut("fast", _done); + } + else + { + _done(); + } + } + } + + detachFromDOM() + { + // Detach this node from the tooltip node + if (this._tooltipElem) + { + this.egw().tooltipUnbind(this._tooltipElem); + this._tooltipElem = null; + } + + // Remove the binding to the click handler + if (this.node) + { + jQuery(this.node).unbind("click.et2_baseWidget"); + } + + return super.detachFromDOM(); + } + + attachToDOM() + { + let ret = super.attachToDOM(); + + // Add the binding for the click handler + if (this.node) + { + jQuery(this.node).bind("click.et2_baseWidget", this, function(e) { + return e.data.click.call(e.data, e, this); + }); + if (typeof this.onclick == 'function') jQuery(this.node).addClass('et2_clickable'); + } + + // Update the statustext + this.set_statustext(this.statustext); + + return ret; + } + + setDOMNode(_node) + { + if (_node != this.node) + { + // Deatch the old node from the DOM + this.detachFromDOM(); + + // Set the new DOM-Node + this.node = _node; + + // Attatch the DOM-Node to the tree + return this.attachToDOM(); + } + + return false; + } + + getDOMNode(_sender?: et2_widget) + { + return this.node; + } + + getTooltipElement() + { + return this.getDOMNode(this); + } + + /** + * Click handler calling custom handler set via onclick attribute to this.onclick + * + * @param _ev + * @returns + */ + click(_ev) { + if(typeof this.onclick == 'function') + { + // Make sure function gets a reference to the widget, splice it in as 2. argument if not + var args = Array.prototype.slice.call(arguments); + if(args.indexOf(this) == -1) args.splice(1, 0, this); + + return this.onclick.apply(this, args); + } + + return true; + } + + set_statustext(_value) { + // Tooltip should not be shown in mobile view + if (egwIsMobile()) return; + // Don't execute the code below, if no tooltip will be attached/detached + if (_value == "" && !this._tooltipElem) + { + return; + } + + // allow statustext to contain multiple translated sub-strings eg: {Firstname}.{Lastname} + if (_value.indexOf('{') !== -1) + { + var egw = this.egw(); + _value = _value.replace(/{([^}]+)}/g, function(str,p1) + { + return egw.lang(p1); + }); + } + + this.statustext = _value; + + //Get the domnode the tooltip should be attached to + var elem = jQuery(this.getTooltipElement()); + + if (elem) + { + //If a tooltip is already attached to the element, remove it first + if (this._tooltipElem) + { + this.egw().tooltipUnbind(this._tooltipElem); + this._tooltipElem = null; + } + + if (_value && _value != '') + { + this.egw().tooltipBind(elem, _value, this.options.statustext_html); + this._tooltipElem = elem; + } + } + } + + set_align(_value) + { + this.align = _value; + } + + get_align() + { + return this.align; + } +} + +/** + * Simple container object + */ +class et2_container extends et2_baseWidget +{ + /** + * Constructor + */ + constructor(_parent, _attrs? : WidgetConfig, _child? : object) + { + // Call the inherited constructor + super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_DOMWidget._attributes, _child || {})); + } + + /** + * The destroy function destroys all children of the widget, removes itself + * from the parents children list. + * Overriden to not try to remove self from parent, as that's not possible. + */ + destroy() + { + // Call the destructor of all children + for (var i = this._children.length - 1; i >= 0; i--) + { + this._children[i].destroy(); + } + + // Free the array managers if they belong to this widget + for (var key in this._mgrs) + { + if (this._mgrs[key] && this._mgrs[key].owner == this) + { + this._mgrs[key].destroy(); + } + } + } +} + +/** + * Container object for not-yet supported widgets + * + * @augments et2_baseWidget + */ +class et2_placeholder extends et2_baseWidget implements et2_IDetachedDOM +{ + /** + * he attrNodes object will hold the DOM nodes which represent the + * values of this object + */ + attrNodes: {}; + visible: boolean = false; + placeDiv: JQuery; + + /** + * Constructor + */ + constructor(_parent, _attrs? : WidgetConfig, _child? : object) + { + // Call the inherited constructor + super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_DOMWidget._attributes, _child || {})); + + this.attrNodes = {}; + + // Create the placeholder div + this.placeDiv = jQuery(document.createElement("span")) + .addClass("et2_placeholder"); + + var headerNode = jQuery(document.createElement("span")) + .text(this.getType() || "") + .addClass("et2_caption") + .appendTo(this.placeDiv); + + var attrsCntr = jQuery(document.createElement("span")) + .appendTo(this.placeDiv) + .hide(); + + headerNode.click(this, function(e) { + e.data.visible = !e.data.visible; + if (e.data.visible) + { + attrsCntr.show(); + } + else + { + attrsCntr.hide(); + } + }); + + for (var key in this.options) + { + if (typeof this.options[key] != "undefined") + { + if (typeof this.attrNodes[key] == "undefined") + { + this.attrNodes[key] = jQuery(document.createElement("span")) + .addClass("et2_attr"); + attrsCntr.append(this.attrNodes[key]); + } + + this.attrNodes[key].text(key + "=" + this.options[key]); + } + } + + this.setDOMNode(this.placeDiv[0]); + } + + getDetachedAttributes(_attrs) + { + _attrs.push("value"); + } + + getDetachedNodes() + { + return [this.placeDiv[0]]; + } + + setDetachedAttributes(_nodes, _values) + { + this.placeDiv = jQuery(_nodes[0]); + } +} + diff --git a/api/js/etemplate/et2_core_widget.ts b/api/js/etemplate/et2_core_widget.ts index 3127c647b2..d7d3f94475 100644 --- a/api/js/etemplate/et2_core_widget.ts +++ b/api/js/etemplate/et2_core_widget.ts @@ -338,7 +338,7 @@ export class et2_widget extends ClassWithAttributes return this._parent; } - private _children = []; + protected _children = []; /** * Returns the list of children of this widget. @@ -893,7 +893,7 @@ export class et2_widget extends ClassWithAttributes this._egw = _egw; } - private _mgrs = {}; + protected _mgrs = {}; /** * Sets all array manager objects - this function can be used to set the diff --git a/api/js/jsapi/egw_global.d.ts b/api/js/jsapi/egw_global.d.ts index 3c77f88d3a..3634df97b8 100644 --- a/api/js/jsapi/egw_global.d.ts +++ b/api/js/jsapi/egw_global.d.ts @@ -1189,6 +1189,7 @@ declare var app : {classes: any}; declare var egw_globalObjectManager : any; declare var framework : any; declare var egw_LAB : any; +declare function egwIsMobile() : boolean; declare var mailvelope : any;