From 4ed888476c0df8d5b59c5d697199c8ad36b2c31a Mon Sep 17 00:00:00 2001 From: nathan Date: Wed, 5 Jan 2022 13:14:28 -0700 Subject: [PATCH] Deal with some IDE warnings better documentation of things tried --- .../etemplate/Et2Select/Et2SelectReadonly.ts | 12 + api/js/etemplate/Et2Widget/Et2Widget.ts | 97 ++++---- api/js/etemplate/et2_core_arrayMgr.ts | 226 ++++++++++++------ 3 files changed, 216 insertions(+), 119 deletions(-) diff --git a/api/js/etemplate/Et2Select/Et2SelectReadonly.ts b/api/js/etemplate/Et2Select/Et2SelectReadonly.ts index 6c0e9c29aa..959959e44a 100644 --- a/api/js/etemplate/Et2Select/Et2SelectReadonly.ts +++ b/api/js/etemplate/Et2Select/Et2SelectReadonly.ts @@ -45,6 +45,18 @@ export class Et2SelectReadonly extends Et2Widget(LitElement) implements et2_IDet transformAttributes(_attrs) { + /* + TODO: Check with more / different nextmatch data to see if this becomes faster. + Currently it's faster for the nextmatch to re-do transformAttributes() and find_select_options() + on every row than it is to use widget.clone() + + // If there's no parent, there's a good chance we're in a nextmatch row so skip the transform + if(!this.getParent()) + { + return; + } + */ + super.transformAttributes(_attrs); let sel_options = find_select_options(this, _attrs['select_options'], _attrs); diff --git a/api/js/etemplate/Et2Widget/Et2Widget.ts b/api/js/etemplate/Et2Widget/Et2Widget.ts index 06ea06cbec..10566b8595 100644 --- a/api/js/etemplate/Et2Widget/Et2Widget.ts +++ b/api/js/etemplate/Et2Widget/Et2Widget.ts @@ -41,11 +41,13 @@ const Et2WidgetMixin = (superClass) => class Et2WidgetClass extends superClass implements et2_IDOMNode { - /** et2_widget compatability **/ protected _mgrs : et2_arrayMgr[] = []; protected _parent : Et2WidgetClass | et2_widget | null = null; private _inst : etemplate2 | null = null; - private supportedWidgetClasses = []; + + /** et2_widget compatability **/ + // @ts-ignore Some legacy widgets check their parent to see whats allowed + public supportedWidgetClasses = []; /** * If we put the widget somewhere other than as a child of its parent, we need to record that so @@ -297,7 +299,6 @@ const Et2WidgetMixin = (superClass) => */ set id(value) { - let oldValue = this._widget_id; this._widget_id = value; let dom_id = ""; if(this._widget_id) @@ -358,7 +359,7 @@ const Et2WidgetMixin = (superClass) => 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); + let args = Array.prototype.slice.call(arguments); if(args.indexOf(this) == -1) { args.splice(1, 0, this); @@ -390,10 +391,10 @@ const Et2WidgetMixin = (superClass) => loadFromXML(_node) { // Load the child nodes. - for(var i = 0; i < _node.childNodes.length; i++) + for(let i = 0; i < _node.childNodes.length; i++) { - var node = _node.childNodes[i]; - var widgetType = node.nodeName.toLowerCase(); + let node = _node.childNodes[i]; + let widgetType = node.nodeName.toLowerCase(); if(widgetType == "#comment") { @@ -430,7 +431,7 @@ const Et2WidgetMixin = (superClass) => */ createElementFromNode(_node, _name?) { - var attributes = {}; + let attributes = {}; // Parse the "readonly" and "type" flag for this element here, as they // determine which constructor is used @@ -442,7 +443,7 @@ const Et2WidgetMixin = (superClass) => typeof this.readonly !== "undefined" ? this.readonly : false) : false; // Check to see if modifications change type - var modifications = this.getArrayMgr("modifications"); + let modifications = this.getArrayMgr("modifications"); if(modifications && _node.getAttribute("id")) { let entry : any = modifications.getEntry(_node.getAttribute("id")); @@ -475,12 +476,12 @@ const Et2WidgetMixin = (superClass) => _nodeName = attributes["type"] = this.getArrayMgr('content').expandName(_nodeName); } - let widget = null; + let widget; if(undefined == window.customElements.get(_nodeName)) { // Get the constructor - if the widget is readonly, use the special "_ro" // constructor if it is available - var constructor = et2_registry[typeof et2_registry[_nodeName] == "undefined" ? 'placeholder' : _nodeName]; + let constructor = et2_registry[typeof et2_registry[_nodeName] == "undefined" ? 'placeholder' : _nodeName]; if(readonly === true && typeof et2_registry[_nodeName + "_ro"] != "undefined") { constructor = et2_registry[_nodeName + "_ro"]; @@ -522,6 +523,9 @@ const Et2WidgetMixin = (superClass) => * and adds the given attributes to the _target associative array. This * function also parses the legacyOptions. * + * N.B. This is only used for legacy widgets. WebComponents use transformAttributes() and + * do their own handling of attributes. + * * @param _attrsObj is the XML DOM attributes object * @param {object} _target is the object to which the attributes should be written. * @param {et2_widget} _proto prototype with attributes and legacyOptions attribute @@ -535,22 +539,21 @@ const Et2WidgetMixin = (superClass) => } // Iterate over the given attributes and parse them - var mgr = this.getArrayMgr("content"); - for(var i = 0; i < _attrsObj.length; i++) + let mgr = this.getArrayMgr("content"); + for(let i = 0; i < _attrsObj.length; i++) { - var attrName = _attrsObj[i].name; - var attrValue = _attrsObj[i].value; + let attrName = _attrsObj[i].name; + let attrValue = _attrsObj[i].value; // Special handling for the legacy options if(attrName == "options" && _proto.constructor.legacyOptions && _proto.constructor.legacyOptions.length > 0) { let legacy = _proto.constructor.legacyOptions || []; - let attrs = et2_attribute_registry[Object.getPrototypeOf(_proto).constructor.name] || {}; // Check for modifications on legacy options here. Normal modifications // are handled in widget constructor, but it's too late for legacy options then if(_target.id && this.getArrayMgr("modifications").getEntry(_target.id)) { - var mod : any = this.getArrayMgr("modifications").getEntry(_target.id); + let mod : any = this.getArrayMgr("modifications").getEntry(_target.id); if(typeof mod.options != "undefined") { attrValue = _attrsObj[i].value = mod.options; @@ -563,9 +566,9 @@ const Et2WidgetMixin = (superClass) => } // Parse the legacy options (as a string, other types not allowed) - var splitted = et2_csvSplit(attrValue + ""); + let splitted = et2_csvSplit(attrValue + ""); - for(var j = 0; j < splitted.length && j < legacy.length; j++) + for(let j = 0; j < splitted.length && j < legacy.length; j++) { // Blank = not set, unless there's more legacy options provided after if(splitted[j].trim().length === 0 && legacy.length >= splitted.length) @@ -587,7 +590,7 @@ const Et2WidgetMixin = (superClass) => attrValue = splitted.slice(j); } - var attr = et2_attribute_registry[_proto.constructor.name][legacy[j]] || {}; + let attr = et2_attribute_registry[_proto.constructor.name][legacy[j]] || {}; // If the attribute is marked as boolean, parse the // expression as bool expression. @@ -612,7 +615,7 @@ const Et2WidgetMixin = (superClass) => let attrs = et2_attribute_registry[_proto.constructor.name] || {}; if(mgr != null && typeof attrs[attrName] != "undefined") { - var attr = attrs[attrName]; + let attr = attrs[attrName]; // If the attribute is marked as boolean, parse the // expression as bool expression. @@ -673,9 +676,11 @@ const Et2WidgetMixin = (superClass) => * rest themselves with their normal lifecycle (especially connectedCallback(), which is kind * of the equivalent of doLoadingFinished() */ + // @ts-ignore this is not an et2_widget, so getDOMNode(this) is bad if(!this._parent_node && this.getParent() instanceof et2_widget && (this.getParent()).getDOMNode(this) != this.parentNode) { - this.getParent().getDOMNode(this).append(this); + // @ts-ignore this is not an et2_widget, and Et2Widget is not a Node + (this.getParent()).getDOMNode(this).append(this); } // An empty text node causes problems with legacy widget children @@ -708,9 +713,9 @@ const Et2WidgetMixin = (superClass) => let check_children = children => { - for(var i = 0; i < children.length; i++) + for(let i = 0; i < children.length; i++) { - var elem = children[i].getWidgetById(_id); + let elem = children[i].getWidgetById(_id); if(elem != null) { @@ -719,9 +724,9 @@ const Et2WidgetMixin = (superClass) => } if(this.id && _id.indexOf('[') > -1 && children.length) { - var ids = (new et2_arrayMgr()).explodeKey(_id); - var widget : Et2WidgetClass = this; - for(var i = 0; i < ids.length && widget !== null; i++) + let ids = (new et2_arrayMgr()).explodeKey(_id); + let widget : Et2WidgetClass = this; + for(let i = 0; i < ids.length && widget !== null; i++) { widget = widget.getWidgetById(ids[i]); } @@ -746,7 +751,7 @@ const Et2WidgetMixin = (superClass) => } if(parent) { - parent.append(this); + parent.append(this); this._parent_node = parent; } } @@ -763,14 +768,12 @@ const Et2WidgetMixin = (superClass) => this.checkCreateNamespace(); } } + // @ts-ignore this._parent.addChild(this); } getParent() : Et2WidgetClass | et2_widget { - let parentNode = this.parentNode; - - // If parent is an old et2_widget, use it if(this._parent) { return this._parent; @@ -787,6 +790,9 @@ const Et2WidgetMixin = (superClass) => } if(child instanceof et2_widget) { + // Type of et2_widget._parent is et2_widget, not Et2Widget. This might cause problems, but they + // should be fixed by getting rid of the legacy widget with problems + // @ts-ignore child._parent = this; // During legacy widget creation, the child's DOM node won't be available yet. @@ -794,6 +800,7 @@ const Et2WidgetMixin = (superClass) => let child_node = null; try { + //@ts-ignore Technically getDOMNode() is from et2_DOMWidget child_node = typeof child.getDOMNode !== "undefined" ? child.getDOMNode(child) : null; } catch(e) @@ -846,7 +853,7 @@ const Et2WidgetMixin = (superClass) => } // Create the copy - var copy = this.cloneNode(); + let copy = this.cloneNode(); copy.id = this._widget_id; if(_parent) @@ -870,7 +877,7 @@ const Et2WidgetMixin = (superClass) => } // Create a clone of all child widgets of the given object - for(var i = 0; i < this.getChildren().length; i++) + for(let i = 0; i < this.getChildren().length; i++) { this.getChildren()[i].clone(copy); } @@ -934,7 +941,7 @@ const Et2WidgetMixin = (superClass) => // Add all managers of this object to the result, if they have not already // been set in the result - for(var key in this._mgrs) + for(let key in this._mgrs) { if(typeof _mgrs[key] == "undefined") { @@ -961,11 +968,11 @@ const Et2WidgetMixin = (superClass) => checkCreateNamespace() { // Get the content manager - var mgrs = this.getArrayMgrs(); + let mgrs = this.getArrayMgrs(); - for(var key in mgrs) + for(let key in mgrs) { - var mgr = mgrs[key]; + let mgr = mgrs[key]; // Get the original content manager if we have already created a // perspective for this node @@ -975,7 +982,7 @@ const Et2WidgetMixin = (superClass) => } // Check whether the manager has a namespace for the id of this object - var entry = mgr.getEntry(this.id); + let entry = mgr.getEntry(this.id); if(typeof entry === 'object' && entry !== null || this.id) { // The content manager has an own node for this object, so @@ -1042,7 +1049,7 @@ const Et2WidgetMixin = (superClass) => */ getPath() { - var path = this.getArrayMgr("content")?.getPath() ?? []; + let path = this.getArrayMgr("content")?.getPath() ?? []; // Prevent namespaced widgets with value from going an extra layer deep if(this.id && this._createNamespace() && path[path.length - 1] == this.id) @@ -1066,11 +1073,11 @@ const Et2WidgetMixin = (superClass) => } // Get the window this object belongs to - var wnd = null; + let wnd = null; // @ts-ignore Technically this doesn't have implements(), but it's mixed in if(this.implements(et2_IDOMNode)) { - var node = (this).getDOMNode(); + let node = (this).getDOMNode(); if(node && node.ownerDocument) { wnd = node.ownerDocument.parentNode || node.ownerDocument.defaultView; @@ -1080,7 +1087,7 @@ const Et2WidgetMixin = (superClass) => // If we're the root object, return the phpgwapi API instance return typeof egw === "function" ? egw('phpgwapi', wnd) : null; } - }; + } // Add some more stuff in applyMixins(Et2WidgetClass, [ClassWithInterfaces]); @@ -1093,7 +1100,9 @@ export const Et2Widget = dedupeMixin(Et2WidgetMixin); * Load a Web Component * @param _nodeName * @param _template_node + * @param parent Parent widget */ +// @ts-ignore Et2Widget is I guess not the right type export function loadWebComponent(_nodeName : string, _template_node, parent : Et2Widget | et2_widget) : HTMLElement { // @ts-ignore @@ -1106,7 +1115,6 @@ export function loadWebComponent(_nodeName : string, _template_node, parent : Et 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") ? @@ -1222,7 +1230,8 @@ function transformAttributes(widget, mgr : et2_arrayMgr, attributes) * } * `]; * } - * @param image_name + * @param image_name Name of the image + * @param app_name Optional, image is from an app instead of api * @returns {CSSResult} */ export function cssImage(image_name : string, app_name? : string) diff --git a/api/js/etemplate/et2_core_arrayMgr.ts b/api/js/etemplate/et2_core_arrayMgr.ts index b6367ed257..8d0e2d16a9 100644 --- a/api/js/etemplate/et2_core_arrayMgr.ts +++ b/api/js/etemplate/et2_core_arrayMgr.ts @@ -26,17 +26,17 @@ import {et2_compilePHPExpression} from "./et2_core_phpExpressionCompiler"; */ export class et2_arrayMgr { - splitIds: boolean = true; - public data: object; + splitIds : boolean = true; + public data : object; // Holds information about the current perspective - public perspectiveData: { owner: et2_widget; row: number; key: string } = { + public perspectiveData : { owner : et2_widget; row : number; key : string } = { "owner": null, "key": null, "row": null }; - protected static compiledExpressions: object = {}; - private readonly _parentMgr: et2_arrayMgr; - protected readOnly: boolean = false; + protected static compiledExpressions : object = {}; + private readonly _parentMgr : et2_arrayMgr; + protected readOnly : boolean = false; /** * Constructor @@ -45,8 +45,10 @@ export class et2_arrayMgr * @param _data * @param _parentMgr */ - constructor(_data: object = {}, _parentMgr?: et2_arrayMgr) { - if (typeof _parentMgr == "undefined") { + constructor(_data : object = {}, _parentMgr? : et2_arrayMgr) + { + if(typeof _parentMgr == "undefined") + { _parentMgr = null; } @@ -55,7 +57,8 @@ export class et2_arrayMgr this._parentMgr = _parentMgr; // Hold a reference to the data - if (typeof _data == "undefined" || !_data) { + if(typeof _data == "undefined" || !_data) + { egw.debug("log", "No data passed to content array manager. Probably a mismatch between template namespaces and data."); _data = {}; } @@ -63,19 +66,24 @@ export class et2_arrayMgr // Expand sub-arrays that have been shmushed together, so further perspectives work // Shmushed keys look like: ${row}[info_cat] // Expanded: ${row}: Object{info_cat: ..value} - if (this.splitIds) { + if(this.splitIds) + { // For each index, we need a key: {..} sub array - for (let key in _data) { + for(let key in _data) + { // Split up indexes const indexes = key.replace(/[/g, "[").split('['); // Put data in the proper place - if (indexes.length > 1) { + if(indexes.length > 1) + { const value = _data[key]; let target = _data; - for (let i = 0; i < indexes.length; i++) { + for(let i = 0; i < indexes.length; i++) + { indexes[i] = indexes[i].replace(/]/g, '').replace(']', ''); - if (typeof target[indexes[i]] == "undefined" || target[indexes[i]] === null) { + if(typeof target[indexes[i]] == "undefined" || target[indexes[i]] === null) + { target[indexes[i]] = i == indexes.length - 1 ? value : {}; } target = target[indexes[i]]; @@ -91,27 +99,33 @@ export class et2_arrayMgr /** * Returns the root content array manager object */ - getRoot(): et2_arrayMgr { - if (this._parentMgr != null) { + getRoot() : et2_arrayMgr + { + if(this._parentMgr != null) + { return this._parentMgr.getRoot(); } return this; } - getParentMgr(): et2_arrayMgr { + getParentMgr() : et2_arrayMgr + { return this._parentMgr; } - getPerspectiveData(): { owner: et2_widget; row: number; key: string } { + getPerspectiveData() : { owner : et2_widget; row : number; key : string } + { return this.perspectiveData; } - setPerspectiveData(new_perspective: { owner: et2_widget; row: number; key: string }) { + setPerspectiveData(new_perspective : { owner : et2_widget; row : number; key : string }) + { this.perspectiveData = new_perspective; } - setRow(new_row: number) { + setRow(new_row : number) + { this.perspectiveData.row = new_row; } @@ -127,21 +141,28 @@ export class et2_arrayMgr * * @return {string[]} */ - explodeKey(_key: string): string[] { - if(!_key || typeof _key == 'string' && _key.trim() === "") return []; + explodeKey(_key : string) : string[] + { + if(!_key || typeof _key == 'string' && _key.trim() === "") + { + return []; + } // Parse the given key by removing the "]"-chars and splitting at "[" let indexes = [_key]; - if (typeof _key === "string") { + if(typeof _key === "string") + { _key = _key.replace(/[/g, "[").replace(/]/g, "]"); indexes = _key.split('['); } - if (indexes.length > 1) { + if(indexes.length > 1) + { indexes = [indexes.shift(), indexes.join('[')]; indexes[1] = indexes[1].substring(0, indexes[1].length - 1); const children = indexes[1].split(']['); - if (children.length) { + if(children.length) + { indexes = jQuery.merge([indexes[0]], children); } } @@ -154,17 +175,21 @@ export class et2_arrayMgr * * @param _path is used internally, do not supply it manually. */ - getPath(_path?: string[]): string[] { - if (typeof _path == "undefined") { + getPath(_path? : string[]) : string[] + { + if(typeof _path == "undefined") + { _path = []; } - if (this.perspectiveData.key != null) { + if(this.perspectiveData.key != null) + { // prepend components of this.perspectiveData.key to path, can be more then one eg. "nm[rows]" _path = this.perspectiveData.key.replace(/]/g, '').split('[').concat(_path); } - if (this._parentMgr != null) { + if(this._parentMgr != null) + { _path = this._parentMgr.getPath(_path); } @@ -182,31 +207,40 @@ export class et2_arrayMgr * @param _skipEmpty returns null if _key is not present in this content array. * Defaults to false. */ - getEntry(_key: string, _referenceInto?: boolean, _skipEmpty?: boolean): any { - if (typeof _referenceInto == "undefined") { + getEntry(_key : string, _referenceInto? : boolean, _skipEmpty? : boolean) : any + { + if(typeof _referenceInto == "undefined") + { _referenceInto = false; } - if (typeof _skipEmpty == "undefined") { + if(typeof _skipEmpty == "undefined") + { _skipEmpty = false; } // Parse the given key by removing the "]"-chars and splitting at "[" const indexes = this.explodeKey(_key); - if(indexes.length == 0 && _skipEmpty) return null; + if(indexes.length == 0 && _skipEmpty) + { + return null; + } let entry = this.data; - for (let i = 0; i < indexes.length; i++) { + for(let i = 0; i < indexes.length; i++) + { // Abort if the current entry is not an object (associative array) and // we should descend further into it. const isObject = typeof entry === 'object'; - if (!isObject && !_referenceInto || entry == null || jQuery.isEmptyObject(entry)) { + if(!isObject && !_referenceInto || entry == null || jQuery.isEmptyObject(entry)) + { return null; } // Check whether the entry actually exists const idx = indexes[i]; - if (_skipEmpty && (!isObject || typeof entry[idx] == "undefined")) { + if(_skipEmpty && (!isObject || typeof entry[idx] == "undefined")) + { return null; } @@ -225,16 +259,18 @@ export class et2_arrayMgr * @param {string} _ident Key used to reference into managed array * @return {*} */ - expandName(_ident: string): string | object { + expandName(_ident : string) : string | object + { // Check whether the identifier refers to an index in the content array const is_index_in_content = _ident.charAt(0) == '@'; // Check whether "$" occurs in the given identifier const pos_var = _ident.indexOf('$'); - if (pos_var >= 0 && (this.perspectiveData.row != null || !_ident.match(/\$\{?row\}?/)) + if(pos_var >= 0 && (this.perspectiveData.row != null || !_ident.match(/\$\{?row\}?/)) // Avoid messing with regex in validators && pos_var !== _ident.indexOf("$/") - ) { + ) + { // Get the content array for the current row const row = typeof this.perspectiveData.row == 'number' ? this.perspectiveData.row : ''; const row_cont = this.data[row] || {}; @@ -245,19 +281,26 @@ export class et2_arrayMgr // Check whether the expression has already been compiled - if not, // try to compile it first. If an error occurs, the identifier // function is set to null - if (typeof et2_arrayMgr.compiledExpressions[_ident] == "undefined") { - try { - if (this.perspectiveData.row == null) { + if(typeof et2_arrayMgr.compiledExpressions[_ident] == "undefined") + { + try + { + if(this.perspectiveData.row == null) + { // No row, compile for only top level content // @ts-ignore et2_arrayMgr.compiledExpressions[_ident] = et2_compilePHPExpression( _ident, ["cont", "_cont"]); - } else { + } + else + { // @ts-ignore et2_arrayMgr.compiledExpressions[_ident] = et2_compilePHPExpression( _ident, ["row", "cont", "row_cont", "_cont"]); } - } catch (e) { + } + catch(e) + { et2_arrayMgr.compiledExpressions[_ident] = null; egw.debug("error", "Error while compiling PHP->JS ", e); } @@ -266,15 +309,22 @@ export class et2_arrayMgr // Execute the previously compiled expression, if it is not "null" // because compilation failed. The parameters have to be in the same // order as defined during compilation. - if (et2_arrayMgr.compiledExpressions[_ident]) { - try { - if (this.perspectiveData.row == null) { + if(et2_arrayMgr.compiledExpressions[_ident]) + { + try + { + if(this.perspectiveData.row == null) + { // No row, exec with only top level content _ident = et2_arrayMgr.compiledExpressions[_ident](cont, _cont); - } else { + } + else + { _ident = et2_arrayMgr.compiledExpressions[_ident](row, cont, row_cont, _cont); } - } catch (e) { + } + catch(e) + { // only log error, as they are no real errors but missing data egw.debug("log", typeof e == 'object' ? e.message : e); _ident = null; @@ -282,12 +332,16 @@ export class et2_arrayMgr } } - if (is_index_in_content && _ident) { + if(is_index_in_content && _ident) + { // If an additional "@" is specified, this means that we have to return // the entry from the root element - if (_ident.charAt(1) == '@') { + if(_ident.charAt(1) == '@') + { return this.getRoot().getEntry(_ident.substr(2)); - } else { + } + else + { return this.getEntry(_ident.substr(1)); } } @@ -295,10 +349,12 @@ export class et2_arrayMgr return _ident; } - parseBoolExpression(_expression: string) { + parseBoolExpression(_expression : string) + { // If the first char of the expression is a '!' this means, that the value // is to be negated. - if (_expression.charAt(0) == '!') { + if(_expression.charAt(0) == '!') + { return !this.parseBoolExpression(_expression.substr(1)); } @@ -307,16 +363,18 @@ export class et2_arrayMgr // Expand the first value let val = this.expandName(parts[0]); - val = (typeof val == "undefined" || val === null) ? '' : '' + val; + val = (typeof val == "undefined" || val === null) ? '' : '' + val; // If a second expression existed, test that one - if (typeof parts[1] != "undefined") { + if(typeof parts[1] != "undefined") + { // Expand the second value const checkVal = '' + this.expandName(parts[1]); // Values starting with / are treated as regular expression. It is // checked whether the first value matches the regular expression - if (checkVal.charAt(0) == '/') { + if(checkVal.charAt(0) == '/') + { return (new RegExp(checkVal.substr(1, checkVal.length - 2))) .test(val); } @@ -335,11 +393,15 @@ export class et2_arrayMgr * @param {(string|null|object)} _root string with key, null for whole data or object with data * @param {number?} _row key for into the _root for the desired row */ - openPerspective(_owner: et2_widget, _root: (string | null | object), _row: number | null): et2_arrayMgr { + openPerspective(_owner : et2_widget, _root : (string | null | object), _row? : number | null) : et2_arrayMgr + { // Get the root node let root = typeof _root == "string" ? this.data[_root] : - (_root == null ? this.data : _root); - if (typeof root == "undefined" && typeof _root == "string") root = this.getEntry(_root); + (_root == null ? this.data : _root); + if(typeof root == "undefined" && typeof _root == "string") + { + root = this.getEntry(_root); + } // Create a new content array manager with the given root const constructor = this.readOnly ? et2_readonlysArrayMgr : et2_arrayMgr; @@ -349,12 +411,14 @@ export class et2_arrayMgr mgr.perspectiveData.owner = _owner; // Set the root key - if (typeof _root == "string") { + if(typeof _root == "string") + { mgr.perspectiveData.key = _root; } // Set _row parameter - if (typeof _row != "undefined") { + if(typeof _row != "undefined") + { mgr.perspectiveData.row = _row; } @@ -366,7 +430,8 @@ export class et2_arrayMgr /** * @augments et2_arrayMgr */ -export class et2_readonlysArrayMgr extends et2_arrayMgr { +export class et2_readonlysArrayMgr extends et2_arrayMgr +{ readOnly : boolean = true; @@ -379,36 +444,43 @@ export class et2_readonlysArrayMgr extends et2_arrayMgr { * @param _parent * @returns */ - isReadOnly(_id: string, _attr: string, _parent?: et2_arrayMgr): boolean | string { + isReadOnly(_id : string, _attr : string, _parent? : et2_arrayMgr) : boolean | string + { let entry = null; - if (_id != null) { - if (_id.indexOf('$') >= 0 || _id.indexOf('@') >= 0) { + if(_id != null) + { + if(_id.indexOf('$') >= 0 || _id.indexOf('@') >= 0) + { _id = this.expandName(_id); } // readonlys was not namespaced in old eTemplate, therefore if we dont find data // under current namespace, we look into parent // (if there is anything namespaced, we will NOT look for parent!) - let mgr: et2_arrayMgr = this; - while (mgr.getParentMgr() && jQuery.isEmptyObject(mgr.data)) { + let mgr : et2_arrayMgr = this; + while(mgr.getParentMgr() && jQuery.isEmptyObject(mgr.data)) + { mgr = mgr.getParentMgr(); } entry = mgr.getEntry(_id); } // Let the array entry override the read only attribute entry - if (typeof entry != "undefined" && !(typeof entry === 'object')) { + if(typeof entry != "undefined" && !(typeof entry === 'object')) + { return entry; } // If the attribute is set, return that - if (typeof _attr != "undefined" && _attr !== null) { + if(typeof _attr != "undefined" && _attr !== null) + { // Accept 'editable', but otherwise boolean return this.expandName(_attr) === 'editable' ? 'editable' : et2_evalBool(_attr); } // Otherwise take into accounf whether the parent is readonly - if (typeof _parent != "undefined" && _parent) { + if(typeof _parent != "undefined" && _parent) + { return true; } @@ -426,7 +498,8 @@ export class et2_readonlysArrayMgr extends et2_arrayMgr { * @param {string} ident Key for searching into the array. * @returns {*} */ - expandName(ident: string): any { + expandName(ident : string) : any + { return this.perspectiveData.owner.getArrayMgr('content').expandName(ident); } } @@ -442,15 +515,18 @@ export class et2_readonlysArrayMgr extends et2_arrayMgr { * existing array managers. * @param _row is the row for which the array managers will be opened. */ -export function et2_arrayMgrs_expand(_owner: et2_widget, _mgrs: object, _data: object, _row: number) { +export function et2_arrayMgrs_expand(_owner : et2_widget, _mgrs : object, _data : object, _row : number) +{ // Create a copy of the given _mgrs associative array let result = {}; // Merge the given data associative array into the existing array managers - for (let key in _mgrs) { + for(let key in _mgrs) + { result[key] = _mgrs[key]; - if (typeof _data[key] != "undefined") { + if(typeof _data[key] != "undefined") + { // Open a perspective for the given data row let rowData = {}; rowData[_row] = _data[key];