diff --git a/api/js/etemplate/et2_core_DOMWidget.ts b/api/js/etemplate/et2_core_DOMWidget.ts index 21da82fac4..f0b5115ff0 100644 --- a/api/js/etemplate/et2_core_DOMWidget.ts +++ b/api/js/etemplate/et2_core_DOMWidget.ts @@ -215,7 +215,8 @@ export abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode * attached to the tree or no parent node or no node for this widget is * defined. */ - attachToDOM() { + attachToDOM() + { // Attach the DOM node of this widget (if existing) to the new parent var node = this.getDOMNode(this); if (node && this.parentNode && diff --git a/api/js/etemplate/et2_core_baseWidget.js b/api/js/etemplate/et2_core_baseWidget.js index 690264cadf..ee23d8a281 100644 --- a/api/js/etemplate/et2_core_baseWidget.js +++ b/api/js/etemplate/et2_core_baseWidget.js @@ -27,7 +27,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); lib/tooltip; et2_core_DOMWidget; */ -//import { ClassWithAttributes } from './et2_core_inheritance'; require("./et2_core_interfaces"); require("./et2_core_common"); var et2_core_DOMWidget_1 = require("./et2_core_DOMWidget"); diff --git a/api/js/etemplate/et2_core_baseWidget.ts b/api/js/etemplate/et2_core_baseWidget.ts index 6999728606..f9d020c9b7 100644 --- a/api/js/etemplate/et2_core_baseWidget.ts +++ b/api/js/etemplate/et2_core_baseWidget.ts @@ -14,7 +14,6 @@ et2_core_DOMWidget; */ -//import { ClassWithAttributes } from './et2_core_inheritance'; import './et2_core_interfaces'; import './et2_core_common'; import { et2_DOMWidget } from './et2_core_DOMWidget'; @@ -94,7 +93,7 @@ export class et2_baseWidget extends et2_DOMWidget implements et2_IAligned * @param _prepend if set, the message is displayed behind the widget node * instead of before. Defaults to false. */ - showMessage(_text, _type, _floating, _prepend) + showMessage(_text, _type?, _floating?, _prepend?) { // Preset the parameters if (typeof _type == "undefined") @@ -146,7 +145,7 @@ export class et2_baseWidget extends et2_DOMWidget implements et2_IAligned * @param _noUpdate is used internally to prevent an update of the surroundings * manager. */ - hideMessage(_fade, _noUpdate) + hideMessage(_fade? : boolean, _noUpdate? : boolean) { if (typeof _fade == "undefined") { @@ -259,7 +258,8 @@ export class et2_baseWidget extends et2_DOMWidget implements et2_IAligned * @param _ev * @returns */ - click(_ev) { + click(_ev) + { if(typeof this.onclick == 'function') { // Make sure function gets a reference to the widget, splice it in as 2. argument if not @@ -272,7 +272,8 @@ export class et2_baseWidget extends et2_DOMWidget implements et2_IAligned return true; } - set_statustext(_value) { + 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 diff --git a/api/js/etemplate/et2_core_inputWidget.ts b/api/js/etemplate/et2_core_inputWidget.ts new file mode 100644 index 0000000000..819cdbc9e0 --- /dev/null +++ b/api/js/etemplate/et2_core_inputWidget.ts @@ -0,0 +1,343 @@ +/** + * 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; + et2_core_interfaces; + et2_core_valueWidget; +*/ + +import './et2_core_common'; +import { ClassWithAttributes } from "./et2_core_inheritance"; +import { et2_widget, et2_createWidget, et2_register_widget, WidgetConfig } from "./et2_core_widget"; +import { et2_DOMWidget } from './et2_core_DOMWidget' +import { et2_valueWidget } from './et2_core_valueWidget' +import './et2_types'; + +/** + * et2_inputWidget derrives from et2_simpleWidget and implements the IInput + * interface. When derriving from this class, call setDOMNode with an input + * DOMNode. + */ +export class et2_inputWidget extends et2_valueWidget implements et2_IInput, et2_ISubmitListener +{ + static readonly _attributes : any = { + "needed": { + "name": "Required", + "default": false, + "type": "boolean", + "description": "If required, the user must enter a value before the form can be submitted" + }, + "onchange": { + "name": "onchange", + "type": "js", + "default": et2_no_init, + "description": "JS code which is executed when the value changes." + }, + "onfocus": { + "name": "onfocus", + "type": "js", + "default": et2_no_init, + "description": "JS code which get executed when wiget receives focus." + }, + "validation_error": { + "name": "Validation Error", + "type": "string", + "default": et2_no_init, + "description": "Used internally to store the validation error that came from the server." + }, + "tabindex": { + "name": "Tab index", + "type": "integer", + "default": et2_no_init, + "description": "Specifies the tab order of a widget when the 'tab' button is used for navigating." + }, + readonly: { + name: "readonly", + type: "boolean", + "default": false, + description: "Does NOT allow user to enter data, just displays existing data" + } + } + + private _oldValue: any; + onchange: Function; + + /** + * Constructor + */ + constructor(_parent, _attrs? : WidgetConfig, _child? : object) + { + // Call the inherited constructor + super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_DOMWidget._attributes, _child || {})); + + // mark value as not initialised, so set_value can determine if it is necessary to trigger change event + this._oldValue = et2_no_init; + this._labelContainer = null; + } + + destroy() + { + var node = this.getInputNode(); + if (node) + { + jQuery(node).unbind("change.et2_inputWidget"); + jQuery(node).unbind("focus"); + } + + super.destroy(); + + this._labelContainer = null; + } + + /** + * Load the validation errors from the server + * + * @param {object} _attrs + */ + transformAttributes(_attrs) + { + super.transformAttributes(_attrs); + + // Check whether an validation error entry exists + if (this.id && this.getArrayMgr("validation_errors")) + { + var val = this.getArrayMgr("validation_errors").getEntry(this.id); + if (val) + { + _attrs["validation_error"] = val; + } + } + } + + attachToDOM() + { + var node = this.getInputNode(); + if (node) + { + jQuery(node) + .off('.et2_inputWidget') + .bind("change.et2_inputWidget", this, function(e) { + e.data.change.call(e.data, this); + }) + .bind("focus.et2_inputWidget", this, function(e) { + e.data.focus.call(e.data, this); + }); + } + + return super.attachToDOM(); + +// jQuery(this.getInputNode()).attr("novalidate","novalidate"); // Stop browser from getting involved +// jQuery(this.getInputNode()).validator(); + } + + detatchFromDOM() + { +// if(this.getInputNode()) { +// jQuery(this.getInputNode()).data("validator").destroy(); +// } + super.detachFromDOM(); + } + + change(_node) + { + var messages = []; + var valid = this.isValid(messages); + + // Passing false will clear any set messages + this.set_validation_error(valid ? false : messages); + + if (valid && this.onchange) + { + if(typeof this.onchange == 'function') + { + // Make sure function gets a reference to the widget + var args = Array.prototype.slice.call(arguments); + if(args.indexOf(this) == -1) args.push(this); + + return this.onchange.apply(this, args); + } else { + return (et2_compileLegacyJS(this.options.onchange, this, _node))(); + } + } + return valid; + } + + focus(_node) + { + if(typeof this.options.onfocus == 'function') + { + // Make sure function gets a reference to the widget + var args = Array.prototype.slice.call(arguments); + if(args.indexOf(this) == -1) args.push(this); + + return this.options.onfocus.apply(this, args); + } + } + + /** + * Set value of widget and trigger for real changes a change event + * + * First initialisation (_oldValue === et2_no_init) is NOT considered a change! + * + * @param {string} _value value to set + */ + set_value(_value) + { + var node = this.getInputNode(); + if (node) + { + jQuery(node).val(_value); + if(this.isAttached() && this._oldValue !== et2_no_init && this._oldValue !== _value) + { + jQuery(node).change(); + } + } + this._oldValue = _value; + } + + set_id(_value) + { + this.id = _value; + this.dom_id = _value && this.getInstanceManager() ? this.getInstanceManager().uniqueId+'_'+this.id : _value; + + // Set the id of the _input_ node (in contrast to the default + // implementation, which sets the base node) + var node = this.getInputNode(); + if (node) + { + // Unique ID to prevent DOM collisions across multiple templates + if (_value != "") + { + node.setAttribute("id", this.dom_id); + node.setAttribute("name", _value); + } + else + { + node.removeAttribute("id"); + node.removeAttribute("name"); + } + } + } + + set_needed(_value) + { + var node = this.getInputNode(); + if (node) + { + if(_value && !this.options.readonly) { + jQuery(node).attr("required", "required"); + } else { + node.removeAttribute("required"); + } + } + } + + set_validation_error(_value) + { + var node = this.getInputNode(); + if (node) + { + if (_value === false) + { + this.hideMessage(); + jQuery(node).removeClass("invalid"); + } + else + { + this.showMessage(_value, "validation_error"); + jQuery(node).addClass("invalid"); + + // If on a tab, switch to that tab so user can see it + let widget : et2_widget = this; + while(widget.getParent() && widget.getType() != 'tabbox') + { + widget = widget.getParent(); + } + if (widget.getType() == 'tabbox') (widget).activateTab(this); + } + } + } + + /** + * Set tab index + * + * @param {number} index + */ + set_tabindex(index) + { + jQuery(this.getInputNode()).attr("tabindex", index); + } + + getInputNode() + { + return this.node; + } + + get_value() + { + return this.getValue(); + } + + getValue() + { + var node = this.getInputNode(); + if (node) + { + var val = jQuery(node).val(); + + return val; + } + + return this._oldValue; + } + + isDirty() + { + return this._oldValue != this.getValue(); + } + + resetDirty() + { + this._oldValue = this.getValue(); + } + + isValid(messages) + { + var ok = true; + + // Check for required + if (this.options && this.options.needed && !this.options.readonly && !this.disabled && + (this.getValue() == null || this.getValue().valueOf() == '')) + { + messages.push(this.egw().lang('Field must not be empty !!!')); + ok = false; + } + return ok; + } + + /** + * Called whenever the template gets submitted. We return false if the widget + * is not valid, which cancels the submission. + * + * @param _values contains the values which will be sent to the server. + * Listeners may change these values before they get submitted. + */ + submit(_values) + { + var messages = []; + var valid = this.isValid(messages); + + // Passing false will clear any set messages + this.set_validation_error(valid ? false : messages); + return valid; + } +} + diff --git a/api/js/etemplate/et2_core_valueWidget.js b/api/js/etemplate/et2_core_valueWidget.js index 6e176b4996..e9d484dc4b 100644 --- a/api/js/etemplate/et2_core_valueWidget.js +++ b/api/js/etemplate/et2_core_valueWidget.js @@ -34,8 +34,6 @@ require("./et2_core_common"); * et2_valueWidget is the base class for et2_inputWidget - valueWidget introduces * the "value" attribute and automatically loads it from the "content" array * after loading from XML. - * - * @augments et2_baseWidget */ var et2_valueWidget = /** @class */ (function (_super) { __extends(et2_valueWidget, _super); diff --git a/api/js/etemplate/et2_core_valueWidget.ts b/api/js/etemplate/et2_core_valueWidget.ts index f562550e48..221a19c16c 100644 --- a/api/js/etemplate/et2_core_valueWidget.ts +++ b/api/js/etemplate/et2_core_valueWidget.ts @@ -22,8 +22,6 @@ import './et2_core_common'; * et2_valueWidget is the base class for et2_inputWidget - valueWidget introduces * the "value" attribute and automatically loads it from the "content" array * after loading from XML. - * - * @augments et2_baseWidget */ export class et2_valueWidget extends et2_baseWidget { @@ -44,7 +42,7 @@ export class et2_valueWidget extends et2_baseWidget }; label: string = ''; - private _labelContainer: JQuery = null; + protected _labelContainer: JQuery = null; /** * diff --git a/api/js/etemplate/et2_types.d.ts b/api/js/etemplate/et2_types.d.ts index 25c966a0a5..6383250267 100644 --- a/api/js/etemplate/et2_types.d.ts +++ b/api/js/etemplate/et2_types.d.ts @@ -10,6 +10,10 @@ declare class et2_valueWidget extends et2_baseWidget{} declare class et2_inputWidget{ getInputNode() : HTMLElement } +declare class et2_tabbox extends et2_valueWidget { + tabData : any; + activateTab(et2_widget); +} declare var et2_surroundingsMgr : any; declare var et2_arrayMgr : any; declare var et2_readonlysArrayMgr : any; @@ -117,9 +121,6 @@ declare var et2_selectbox_ro : any; declare var et2_menulist : any; declare var et2_split : any; declare var et2_styles : any; -declare class et2_tabbox extends et2_widget { - tabData : any; -} declare var et2_taglist : any; declare var et2_taglist_account : any; declare var et2_taglist_email : any;