diff --git a/etemplate/js/et2_DOMWidget.js b/etemplate/js/et2_DOMWidget.js index b35e3046ff..4429e10107 100644 --- a/etemplate/js/et2_DOMWidget.js +++ b/etemplate/js/et2_DOMWidget.js @@ -52,6 +52,18 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { "type": "boolean", "description": "Defines whether this widget is visible.", "default": false + }, + "width": { + "name": "Width", + "type": "dimension", + "default": et2_no_init, + "description": "Width of the element in pixels, percentage or 'auto'" + }, + "height": { + "name": "Height", + "type": "dimension", + "default": et2_no_init, + "description": "Height of the element in pixels, percentage or 'auto'" } }, @@ -59,7 +71,10 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { * When the DOMWidget is initialized, it grabs the DOM-Node of the parent * object (if available) and passes it to its own "createDOMNode" function */ - init: function(_parent, _type) { + init: function() { + // Call the inherited constructor + this._super.apply(this, arguments); + this.parentNode = null; this._attachSet = { @@ -67,10 +82,7 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { "parent": null }; - this.disabled = false; - - // Call the inherited constructor - this._super.apply(this, arguments); + this._disabled = false; }, /** @@ -87,14 +99,16 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { }, /** - * Automatically tries to attach this node to the parent widget. + * Attaches the container node of this widget to the DOM-Tree */ - onSetParent: function() { + doLoadingFinished: function() { // Check whether the parent implements the et2_IDOMNode interface. If // yes, grab the DOM node and create our own. if (this._parent && this._parent.implements(et2_IDOMNode)) { this.setParentDOMNode(this._parent.getDOMNode(this)); } + + return true; }, /** @@ -192,7 +206,7 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { }, set_disabled: function(_value) { - var node = this.getDOMNode(); + var node = this.getDOMNode(this); if (node) { this.disabled = _value; @@ -206,8 +220,27 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { $j(node).show(); } } - } + }, + set_width: function(_value) { + this.width = _value; + + var node = this.getDOMNode(this); + if (node) + { + $j(node).css("width", _value); + } + }, + + set_height: function(_value) { + this.height = _value; + + var node = this.getDOMNode(this); + if (node) + { + $j(node).css("height", _value); + } + } }); diff --git a/etemplate/js/et2_baseWidget.js b/etemplate/js/et2_baseWidget.js index 3fe711cd8b..c3e16dc895 100644 --- a/etemplate/js/et2_baseWidget.js +++ b/etemplate/js/et2_baseWidget.js @@ -128,16 +128,8 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned, { } }, - // XXX I really don't like this - I think I'll move attaching the DOM-Nodes - // to the loadFinished function - this should also be faster... set_align: function(_value) { - if (_value != this.align) - { - this.align = _value; - - // Reattach this node to the DOM - this.onSetParent(); - } + this.align = _value; }, get_align: function(_value) { @@ -171,32 +163,49 @@ var et2_placeholder = et2_baseWidget.extend({ // values of this object this.attrNodes = {}; + this.visible = false; + // Create the placeholder div this.placeDiv = $j(document.createElement("span")) .addClass("et2_placeholder"); var headerNode = $j(document.createElement("span")) - .text(this.type) + .text(this._type) .addClass("et2_caption") .appendTo(this.placeDiv); - this.setDOMNode(this.placeDiv[0]); - }, + var attrsCntr = $j(document.createElement("span")) + .appendTo(this.placeDiv) + .hide(); - loadAttributes: function(_attrs) { - for (var i = 0; i < _attrs.length; i++) - { - var attr = _attrs[i]; - - if (typeof this.attrNodes[attr.name] == "undefined") + headerNode.click(this, function(e) { + e.data.visible = !e.data.visible; + if (e.data.visible) { - this.attrNodes[attr.name] = $j(document.createElement("span")) - .addClass("et2_attr"); - this.placeDiv.append(this.attrNodes[attr.name]); + attrsCntr.show(); } + else + { + attrsCntr.hide(); + } + }); - this.attrNodes[attr.name].text(attr.name + "=" + attr.value); + for (var key in this.options) + { + if (typeof this.options[key] != "undefined") + { + if (typeof this.attrNodes[key] == "undefined") + { + this.attrNodes[key] = $j(document.createElement("span")) + .addClass("et2_attr"); + attrsCntr.append(this.attrNodes[key]); + } + + this.attrNodes[key].text(key + "=" + this.options[key]); + } } + + this.setDOMNode(this.placeDiv[0]); } }); diff --git a/etemplate/js/et2_box.js b/etemplate/js/et2_box.js index 17ddcc68c1..4ccf97d0dc 100644 --- a/etemplate/js/et2_box.js +++ b/etemplate/js/et2_box.js @@ -22,21 +22,16 @@ */ var et2_box = et2_baseWidget.extend({ - init: function(_parent, _type) { + createNamespace: true, + + init: function() { this._super.apply(this, arguments); this.div = $j(document.createElement("div")) - .addClass("et2_" + _type) + .addClass("et2_" + this._type) .addClass("et2_box_widget"); this.setDOMNode(this.div[0]); - }, - - set_id: function(_value) { - this._super.apply(this, arguments); - - // Check whether a namespace exists for this element - this.checkCreateNamespace(); } }); diff --git a/etemplate/js/et2_checkbox.js b/etemplate/js/et2_checkbox.js index 50c719ad0f..d29f419582 100644 --- a/etemplate/js/et2_checkbox.js +++ b/etemplate/js/et2_checkbox.js @@ -109,9 +109,6 @@ var et2_checkbox_ro = et2_checkbox.extend({ } }, - init: function(_parent) { - }, - init: function() { this._super.apply(this, arguments); diff --git a/etemplate/js/et2_common.js b/etemplate/js/et2_common.js index 0f345ae24b..8a4428b4b1 100644 --- a/etemplate/js/et2_common.js +++ b/etemplate/js/et2_common.js @@ -71,7 +71,7 @@ function et2_debug(_level) /** * Array with all types supported by the et2_checkType function. */ -var et2_validTypes = ["boolean", "string", "float", "integer", "any", "js"]; +var et2_validTypes = ["boolean", "string", "float", "integer", "any", "js", "dimension"]; /** * Object whith default values for the above types. Do not specify array or @@ -84,7 +84,8 @@ var et2_typeDefaults = { "js": null, "float": 0.0, "integer": 0, - "any": null + "any": null, + "dimension": "auto" }; function et2_evalBool(_val) @@ -144,7 +145,7 @@ function et2_checkType(_val, _type, _attr) if (_type == "js") { // Handle the default case - if (_val === null) + if (_val === null || _val instanceof Function) { return null; } @@ -204,6 +205,32 @@ function et2_checkType(_val, _type, _attr) return _err(); } + // Parse the given dimension value + if (_type == "dimension") + { + // Case 1: The value is "auto" + if (_val == "auto") + { + return _val; + } + + // Case 2: The value is simply a number, attach "px" + if (!isNaN(_val)) + { + return parseFloat(_val) + "px"; + } + + // Case 3: The value is already a valid css pixel value or a percentage + if (typeof _val == "string" && + ((_val.indexOf("px") == _val.length - 2 && !isNaN(_val.split("px")[0])) || + (_val.indexOf("%") == _val.length - 1 && !isNaN(_val.split("%")[0])))) + { + return _val; + } + + return _err(); + } + // We should never come here throw("Invalid type identifier supplied."); } diff --git a/etemplate/js/et2_grid.js b/etemplate/js/et2_grid.js index 2e13265808..140f274364 100644 --- a/etemplate/js/et2_grid.js +++ b/etemplate/js/et2_grid.js @@ -402,9 +402,6 @@ var et2_grid = et2_DOMWidget.extend({ "widget": cell.widget }); - // Trigger the "onSetParent" event of the widget - cell.widget.onSetParent(); - // Set the span values of the cell var cs = (x == w - 1) ? w - x : Math.min(w - x, cell.colSpan); var rs = (y == h - 1) ? h - y : Math.min(h - y, cell.rowSpan); diff --git a/etemplate/js/et2_hbox.js b/etemplate/js/et2_hbox.js index 2c5f3932ad..e9419ea6db 100644 --- a/etemplate/js/et2_hbox.js +++ b/etemplate/js/et2_hbox.js @@ -22,7 +22,11 @@ */ var et2_hbox = et2_baseWidget.extend({ - init: function(_parent, _type) { + createNamespace: true, + + init: function(_parent) { + this._super.apply(this, arguments); + this.alignData = { "hasAlign": false, "hasLeft": false, @@ -34,10 +38,8 @@ var et2_hbox = et2_baseWidget.extend({ this.leftDiv = null; this.rightDiv = null; - this._super.apply(this, arguments); - this.div = $j(document.createElement("div")) - .addClass("et2_" + _type) + .addClass("et2_" + this._type) .addClass("et2_box_widget"); this.setDOMNode(this.div[0]); @@ -159,15 +161,7 @@ var et2_hbox = et2_baseWidget.extend({ // Normally simply return the hbox-div return this._super.apply(this, arguments); - }, - - set_id: function(_value) { - this._super.apply(this, arguments); - - // Check whether a namespace exists for this element - this.checkCreateNamespace(); } - }); et2_register_widget(et2_hbox, ["hbox"]); diff --git a/etemplate/js/et2_inheritance.js b/etemplate/js/et2_inheritance.js index e053cdcd4e..330c94ea0a 100644 --- a/etemplate/js/et2_inheritance.js +++ b/etemplate/js/et2_inheritance.js @@ -261,12 +261,6 @@ { this.init.apply(this, arguments); } - - // Initialize the attributes - if (typeof this._attrsInitialized == "undefined") - { - this.initAttributes(); - } } } @@ -353,23 +347,67 @@ } } + /** + * generateAttributeSet sanitizes the given associative array of attributes + * (by passing each entry to "et2_checkType" and checking for existance of + * the attribute) and adds the default values to the associative array. + * + * @param _attrs is the associative array containing the attributes. + */ + Class.prototype.generateAttributeSet = function(_attrs) { + + // Sanity check and validation + for (var key in _attrs) + { + if (typeof this.attributes[key] != "undefined") + { + if (!this.attributes[key].ignore) + { + _attrs[key] = et2_checkType(_attrs[key], this.attributes[key].type, + key); + } + } + else + { + // Key does not exist - delete it and issue a warning + delete(_attrs[key]); + et2_debug("warn", this, "Attribute '" + key + + "' does not exist!"); + } + } + + // Include default values or already set values for this attribute + for (var key in this.attributes) + { + if (typeof _attrs[key] == "undefined") + { + var _default = this.attributes[key]["default"]; + if (_default == et2_no_init) + { + _default = undefined; + } + + _attrs[key] = _default; + } + } + + return _attrs; + } + /** * The initAttributes function sets the attributes to their default * values. The attributes are not overwritten, which means, that the * default is only set, if either a setter exists or this[propName] does * not exist yet. */ - Class.prototype.initAttributes = function() { - for (var key in this.attributes) + Class.prototype.initAttributes = function(_attrs) { + for (var key in _attrs) { - if (!this.attributes[key].ignore && this.attributes[key]["default"] !== et2_no_init) + if (!this.attributes[key].ignore && !(_attrs[key] == undefined)) { - this.setAttribute(key, this.attributes[key]["default"], - false); + this.setAttribute(key, _attrs[key], false); } } - - this._attrsInitialized = true; } /** diff --git a/etemplate/js/et2_inputWidget.js b/etemplate/js/et2_inputWidget.js index 087c95bb51..e553846932 100644 --- a/etemplate/js/et2_inputWidget.js +++ b/etemplate/js/et2_inputWidget.js @@ -71,6 +71,7 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, { $j(this.getInputNode()).attr("novalidate","novalidate"); // Stop browser from getting involved $j(this.getInputNode()).validator(); }, + detatchFromDOM: function() { if(this.getInputNode()) { $j(this.getInputNode()).data("validator").destroy(); diff --git a/etemplate/js/et2_tabs.js b/etemplate/js/et2_tabs.js index 84782c5677..b6817a359f 100644 --- a/etemplate/js/et2_tabs.js +++ b/etemplate/js/et2_tabs.js @@ -134,18 +134,13 @@ var et2_tabbox = et2_DOMWidget.extend({ entry.contentDiv = $j(document.createElement("div")) .addClass("et2_tabcntr") - .hide() .appendTo(this.tabContainer); - - // Let the widget appear on its corresponding page - entry.widget.onSetParent(); } this.setActiveTab(0); }, setActiveTab: function(_idx) { - console.log(_idx); // Remove the "active" flag from all tabs-flags $j(".et2_tabflag", this.flagContainer).removeClass("active"); @@ -175,6 +170,12 @@ var et2_tabbox = et2_DOMWidget.extend({ return null; } + }, + + set_height: function(_value) { + this.height = _value; + + this.tabContainer.css("height", _value); } }); diff --git a/etemplate/js/et2_template.js b/etemplate/js/et2_template.js index 9ade66ce3b..1820b12d2a 100644 --- a/etemplate/js/et2_template.js +++ b/etemplate/js/et2_template.js @@ -44,26 +44,60 @@ var et2_template = et2_DOMWidget.extend({ } }, + createNamespace: true, + /** * Initializes this template widget as a simple container. */ init: function(_parent) { + this._super.apply(this, arguments); + this.proxiedTemplate = null; this.isProxied = false; this.div = document.createElement("div"); - this.id = ""; - this._super.apply(this, arguments); + if (this.id != "") + { + this.createProxy(); + } + }, + + createProxy: function() { + // Check whether a template with the given name already exists and + // is not a proxy. + var tmpl = this.getRoot().getWidgetById(this.id); + if (tmpl instanceof et2_template && tmpl.proxiedTemplate == null && + tmpl != this) + { + // Detatch the proxied template from the DOM to and set its + // isProxied property to true + tmpl.makeProxied(); + + // Do not copy the id when cloning as this leads to infinit + // recursion + tmpl.options.id = ""; + + // Create a clone of the template and add it as child of this + // template (done by passing "this" to the clone function) + this.proxiedTemplate = tmpl.clone(this); + + // Reset the "ignore" flag and manually copy the id + tmpl.options.id = this.id; + this.proxiedTemplate.id = tmpl.id; + this.proxiedTemplate.isProxied = true; + + // Disallow adding any new node to this template + this.supportedWidgetClasses = []; + } }, /** * If the parent node is changed, either the DOM-Node of the proxied template * or the DOM-Node of this template is connected to the parent DOM-Node. */ - onSetParent: function() { - // Check whether the parent implements the et2_IDOMNode interface. If - // yes, grab the DOM node and create our own. + doLoadingFinished: function() { + // Check whether the parent implements the et2_IDOMNode interface. if (this._parent && this._parent.implements(et2_IDOMNode)) { var parentNode = this._parent.getDOMNode(this); @@ -72,6 +106,8 @@ var et2_template = et2_DOMWidget.extend({ if (this.proxiedTemplate) { this.proxiedTemplate.setParentDOMNode(parentNode); + this.proxiedTemplate.loadingFinished(); + return false; } else if (!this.isProxied) { @@ -79,6 +115,8 @@ var et2_template = et2_DOMWidget.extend({ } } } + + return true; }, makeProxied: function() { @@ -92,59 +130,7 @@ var et2_template = et2_DOMWidget.extend({ this.isProxied = true; }, - set_id: function(_value) { - if (_value != this.id) - { - // Check whether a template with the given name already exists and - // is not a proxy. - var tmpl = this.getRoot().getWidgetById(_value); - if (tmpl instanceof et2_template && tmpl.proxiedTemplate == null && - tmpl != this) - { - // Check whether we still have a proxied template, if yes, - // destroy it - if (this.proxiedTemplate != null) - { - this.proxiedTemplate.destroy(); - this.proxiedTemplate = null; - } - - // This element does not have a node in the tree - this.detatchFromDOM(); - - // Detatch the proxied template from the DOM to and set its - // isProxied property to true - tmpl.makeProxied(); - - // Do not copy the id when cloning as this leads to infinit - // recursion - tmpl.attributes["id"].ignore = true; - - // Create a clone of the template and add it as child of this - // template (done by passing "this" to the clone function) - this.proxiedTemplate = tmpl.clone(this); - - // Reset the "ignore" flag and manually copy the id - tmpl.attributes["id"].ignore = false; - this.proxiedTemplate.id = tmpl.id; - - // Disallow adding any new node to this template - this.supportedWidgetClasses = []; - - // Call the parent change event function - this.onSetParent(); - } - else - { - this._super(_value); - - // Check whether a namespace exists for this element - this.checkCreateNamespace(); - } - } - }, - - getDOMNode: function(_fromProxy) { + getDOMNode: function() { return this.div; }, diff --git a/etemplate/js/et2_textbox.js b/etemplate/js/et2_textbox.js index b6074fa4bb..e9fd98bc9a 100644 --- a/etemplate/js/et2_textbox.js +++ b/etemplate/js/et2_textbox.js @@ -41,13 +41,13 @@ var et2_textbox = et2_inputWidget.extend({ "rows": { "name": "Rows", "type": "integer", - "default": et2_no_init, + "default": 1, "description": "Multiline field height - better to use CSS" }, "cols": { "name": "Size", "type": "integer", - "default": et2_no_init, + "default": 1, "description": "Multiline field width - better to use CSS" }, }, @@ -56,16 +56,16 @@ var et2_textbox = et2_inputWidget.extend({ this._super.apply(this, arguments); this.input = null; - this.id = ""; this.createInputWidget(); - }, createInputWidget: function() { - if (this.multiline) + if (this.options.multiline || this.options.rows > 1 || this.options.cols > 1) { - this.input = $j(document.createElement("textarea")); + this.input = $j(document.createElement("textarea")) + .attr("rows", this.options.rows) + .attr("cols", this.options.cols); } else { @@ -80,44 +80,6 @@ var et2_textbox = et2_inputWidget.extend({ this.setDOMNode(this.input[0]); }, - set_multiline: function(_value) { - if (_value != this.multiline) - { - this.multiline = _value; - - this.createInputWidget(); - - // Write all settings again - this.update(); - } - }, - - set_rows: function(_value) { - if (_value != this.rows) - { - this.rows = _value; - if(this.rows > 1) - { - this.set_multiline(true); - this.input.attr("rows", this.rows); - } else { - this.set_multiline(false); - } - } - }, - set_cols: function(_value) { - if (_value != this.cols) - { - this.cols = _value; - if(this.cols > 1) - { - this.set_multiline(true); - this.input.attr("cols", this.cols); - } else { - this.set_multiline(false); - } - } - }, /** * Set input widget size diff --git a/etemplate/js/et2_valueWidget.js b/etemplate/js/et2_valueWidget.js index 778a970017..0fdf35ed81 100644 --- a/etemplate/js/et2_valueWidget.js +++ b/etemplate/js/et2_valueWidget.js @@ -33,18 +33,18 @@ var et2_valueWidget = et2_baseWidget.extend({ } }, - loadingFinished: function() { + parseArrayMgrAttrs: function(_attrs) { this._super.call(this, arguments); if (this.id != "") { // Set the value for this element var contentMgr = this.getArrayMgr("content"); - if(contentMgr != null) { + if (contentMgr != null) { var val = contentMgr.getValueForID(this.id); if (val !== null) { - this.setAttribute("value", val) + _attrs["value"] = val; } } } diff --git a/etemplate/js/et2_widget.js b/etemplate/js/et2_widget.js index 3bd3507954..af7884fadf 100644 --- a/etemplate/js/et2_widget.js +++ b/etemplate/js/et2_widget.js @@ -89,6 +89,11 @@ var et2_widget = Class.extend({ // attribute defines. legacyOptions: [], + /** + * Set this variable to true if this widget can have namespaces + */ + createNamespace: false, + /** * The init function is the constructor of the widget. When deriving new * classes from the widget base class, always call this constructor unless @@ -97,37 +102,54 @@ var et2_widget = Class.extend({ * @param _parent is the parent object from the XML tree which contains this * object. The default constructor always adds the new instance to the * children list of the given parent object. _parent may be NULL. - * @param _type is the node name with which the widget has been created. This - * is usefull if a single widget class implements multiple XET-Node widgets. + * @param _attrs is an associative array of attributes. */ - init: function(_parent, _type, _readonly) { + init: function(_parent, _attrs) { - if (typeof _type == "undefined") + // Check whether all attributes are available + if (typeof _parent == "undefined") { - _type = "widget"; + _parent = null; } - this.id = ""; + if (typeof _attrs == "undefined") + { + _attrs = {}; + } + + // Initialize all important parameters this._mgrs = {}; this._inst = null; + this._children = []; + this._type = _attrs["type"]; + this.id = _attrs["id"]; - // Copy the parent parameter and add this widget to its parent children - // list. + // Add this widget to the given parent widget this._parent = _parent; - this.onSetParent(); - if (_parent != null) { this._parent.addChild(this); } - this._children = []; - this.type = _type; - this.readonly = _readonly; - // The supported widget classes array defines a whitelist for all widget // classes or interfaces child widgets have to support. this.supportedWidgetClasses = [et2_widget]; + + if (_attrs["id"]) + { + // Create a namespace for this object + if (this.createNamespace) + { + this.checkCreateNamespace(); + } + + // Add all attributes hidden in the content arrays to the attributes + // parameter + this.parseArrayMgrAttrs(_attrs); + } + + // Create a local copy of the options object + this.options = et2_cloneObject(_attrs); }, /** @@ -156,7 +178,6 @@ var et2_widget = Class.extend({ this._children = []; this._parent = null; this._mgrs = {}; - this.onSetParent(); }, /** @@ -164,7 +185,7 @@ var et2_widget = Class.extend({ * constructor of the copied object. If the parameters are omitted, _parent * is defaulted to null */ - clone: function(_parent, _type) { + clone: function(_parent) { // Default _parent to null if (typeof _parent == "undefined") @@ -173,7 +194,7 @@ var et2_widget = Class.extend({ } // Create the copy - var copy = new (this.constructor)(_parent, _type, this.readonly); + var copy = new (this.constructor)(_parent, this.options); // Assign this element to the copy copy.assign(this); @@ -185,22 +206,7 @@ var et2_widget = Class.extend({ // Create a clone of all child elements of the given object for (var i = 0; i < _obj._children.length; i++) { - _obj._children[i].clone(this, _obj._children[i].type); - } - - // Copy all properties - for (var key in _obj.attributes) - { - if (!_obj.attributes[key].ignore) - { - var value = _obj.getAttribute(key); - - // Check whether the attribute is undefined - if (typeof value != "undefined") - { - this.setAttribute(key, value); - } - } + _obj._children[i].clone(this); } // Copy a reference to the content array manager @@ -214,14 +220,6 @@ var et2_widget = Class.extend({ return this._parent; }, - /** - * The set parent event is called, whenever the parent of the widget is set. - * Child classes can overwrite this function. Whe onSetParent is called, - * the change of the parent has already taken place. - */ - onSetParent: function() { - }, - /** * Returns the list of children of this widget. */ @@ -269,7 +267,7 @@ var et2_widget = Class.extend({ } else { - throw("_node is not supported by this widget class!"); + throw(_node, " is not supported by this widget class!"); } }, @@ -284,7 +282,6 @@ var et2_widget = Class.extend({ { // This element is no longer parent of the child _node._parent = null; - _node.onSetParent(); this._children.splice(idx, 1); } @@ -375,46 +372,103 @@ var et2_widget = Class.extend({ return false; }, - createElementFromNode: function(_node, _nodeName) { + /** + * The parseXMLAttrs function takes an XML DOM attributes object + * and adds the given attributes to the _target associative array. This + * function also parses the legacyOptions. + * + * @param _attrsObj is the XML DOM attributes object + * @param _target is the object to which the attributes should be written. + */ + parseXMLAttrs: function(_attrsObj, _target, _proto) { - // Check whether the type attribute exists - if yes pass it instead of - // the nodeName - if (_node.getAttribute("type")) + // Check whether the attributes object is really existing, if not abort + if (typeof _attrsObj == "undefined") { - _nodeName = _node.getAttribute("type"); + return; } - if (typeof _nodeName == "undefined") + // Iterate over the given attributes and parse them + for (var i = 0; i < _attrsObj.length; i++) { - _nodeName = _node.nodeName.toLowerCase(); - } + var attrName = _attrsObj[i].name; + var attrValue = _attrsObj[i].value; - // Get the constructor for that widget + // Special handling for the legacy options + if (attrName == "options") + { + // Parse the legacy options + var splitted = et2_csvSplit(attrValue); + + for (var j = 0; j < splitted.length && j < _proto.legacyOptions.length; j++) + { + _target[_proto.legacyOptions[j]] = splitted[j]; + } + } + else + { + var mgr = this.getArrayMgr("content"); + if (mgr != null && typeof _proto.attributes[attrName] != "undefined") + { + var attr = _proto.attributes[attrName]; + + // If the attribute is marked as boolean, parse the + // expression as bool expression. + if (attr.type == "boolean") + { + attrValue = mgr.parseBoolExpression(attrValue); + } + else + { + attrValue = mgr.expandName(attrValue); + } + } + + // Set the attribute + _target[attrName] = attrValue; + } + } + }, + + parseArrayMgrAttrs: function() { + }, + + createElementFromNode: function(_node) { + + // Fetch all attributes for this element from the XML node + var attributes = {}; + + // Parse the "readonly" and "type" flag for this element here, as they + // determine which constructor is used + var _nodeName = attributes["type"] = _node.getAttribute("type") ? + _node.getAttribute("type") : _node.nodeName.toLowerCase(); + var readonly = attributes["readonly"] = + this.getArrayMgr("readonlys").isReadOnly( + _node.getAttribute("id"), _node.getAttribute("readonly"), + this.readonly); + + // Get the constructor - if the widget is readonly, use the special "_ro" + // constructor if it is available var constructor = typeof et2_registry[_nodeName] == "undefined" ? et2_placeholder : et2_registry[_nodeName]; - - // Check whether the widget is marked as readonly and whether a special - // readonly type (suffixed with "_ro") is registered - var mgr = this.getArrayMgr("readonlys"); - var readonly = false; - if(mgr != null) { - readonly = mgr.isReadOnly( - _node.getAttribute("id"), _node.getAttribute("readonly"), this.readonly); - } if (readonly && typeof et2_registry[_nodeName + "_ro"] != "undefined") { constructor = et2_registry[_nodeName + "_ro"]; } + // Parse the attributes from the given XML attributes object + this.parseXMLAttrs(_node.attributes, attributes, constructor.prototype); + + // Do an sanity check for the attributes + constructor.prototype.generateAttributeSet(attributes); + // Creates the new widget, passes this widget as an instance and // passes the widgetType. Then it goes on loading the XML for it. - var widget = new constructor(this, _nodeName, readonly); + var widget = new constructor(this, attributes); + // Load the widget itself from XML widget.loadFromXML(_node); - // Call the "loadFinished" function of the widget - widget.loadingFinished(); - return widget; }, @@ -422,12 +476,6 @@ var et2_widget = Class.extend({ * Loads the widget tree from an XML node */ loadFromXML: function(_node) { - // Try to load the attributes of the current node - if (_node.attributes) - { - this.loadAttributes(_node.attributes); - } - // Load the child nodes. for (var i = 0; i < _node.childNodes.length; i++) { @@ -453,51 +501,6 @@ var et2_widget = Class.extend({ } }, - /** - * Loads the widget attributes from the passed DOM attributes array. - */ - loadAttributes: function(_attrs) { - for (var i = 0; i < _attrs.length; i++) - { - // Special handling for the legacy options - if (_attrs[i].name == "options") - { - // Parse the legacy options - var splitted = et2_csvSplit(_attrs[i].value); - - for (var j = 0; j < splitted.length && j < this.legacyOptions.length; j++) - { - this.setAttribute(this.legacyOptions[j], splitted[j]); - } - } - else - { - var attrName = _attrs[i].name; - var attrValue = _attrs[i].value; - - var mgr = this.getArrayMgr("content"); - if (mgr != null && typeof this.attributes[attrName] != "undefined") - { - var attr = this.attributes[attrName]; - - // If the attribute is marked as boolean, parse the - // expression as bool expression. - if (attr.type == "boolean") - { - attrValue = mgr.parseBoolExpression(attrValue); - } - else - { - attrValue = mgr.expandName(attrValue); - } - } - - // Set the attribute - this.setAttribute(attrName, attrValue); - } - } - }, - /** * Called whenever textNodes are loaded from the XML tree */ @@ -505,34 +508,28 @@ var et2_widget = Class.extend({ }, /** - * Called when loading of the widget from XML node is finished. This - * function can be used to load the data from the data arrays (content, - * readonlys, sel_options etc.) + * Called when loading the widget (sub-tree) is finished. First when this + * function is called, the DOM-Tree is created. loadingFinished is + * recursively called for all child elements. Do not directly override this + * function but the doLoadingFinished function which is executed before + * descending deeper into the DOM-Tree */ loadingFinished: function() { - }, + // Call all availble setters + this.initAttributes(this.options); - /** - * Calls the setter of each property with its current value, calls the - * update function of all child nodes. - */ - update: function() { - - // Go through every property of this object and check whether a - // corresponding setter function exists. If yes, it is called. - for (var key in this.attributes) + if (this.doLoadingFinished()) { - if (!this.attributes[key].ignore) + // Descend recursively into the tree + for (var i = 0; i < this._children.length; i++) { - this.setAttribute(key, this.getAttribute(key)); + this._children[i].loadingFinished(); } } + }, - // Call the update function of all children. - for (var i = 0; i < this._children.length; i++) - { - this._children[i].update(); - } + doLoadingFinished: function() { + return true; }, /** diff --git a/etemplate/js/etemplate2.js b/etemplate/js/etemplate2.js index c30b5c7c77..b5203bddc6 100644 --- a/etemplate/js/etemplate2.js +++ b/etemplate/js/etemplate2.js @@ -20,7 +20,7 @@ et2_description; et2_textbox; et2_number; - et2_selectbox; +// et2_selectbox; et2_checkbox; et2_radiobox; et2_styles; @@ -64,7 +64,7 @@ etemplate2.prototype.clear = function() { if (this.widgetContainer != null) { - $j(':input',this.DOMContainer).validator().data("validator").destroy(); +// $j(':input',this.DOMContainer).validator().data("validator").destroy(); this.widgetContainer.destroy(); this.widgetContainer = null; } @@ -121,7 +121,10 @@ etemplate2.prototype.load = function(_url, _data) // Asynchronously load the XET file (code below is executed ahead of the // code in the callback function) et2_loadXMLFromURL(_url, function(_xmldoc) { + // Read the XML structure this.widgetContainer.loadFromXML(_xmldoc); + // Inform the widget tree that it has been successfully loaded. + this.widgetContainer.loadingFinished(); }, this); // Clear any existing instance @@ -152,13 +155,13 @@ etemplate2.prototype.load = function(_url, _data) etemplate2.prototype.submit = function() { // Validator - var valid = true; + /*var valid = true; var inputs = $j(':input',this.DOMContainer).each(function() { if(typeof $j(this).data("validator") == "undefined") return true; valid = valid && $j(this).data("validator").checkValidity(); return true; }); - if(!valid) return false; + if(!valid) return false;*/ // Get the form values var values = this.widgetContainer.getValues(); @@ -263,7 +266,7 @@ function etemplate2_handle_response(_type, _response) throw("Error while parsing et2_load response"); } else if (_type == "et2_validation_error") { // Display validation errors - $j(':input',this.DOMContainer).data("validator").invalidate(_response.data); +// $j(':input',this.DOMContainer).data("validator").invalidate(_response.data); } return false; diff --git a/etemplate/js/test/et2_test_tabbox.xet b/etemplate/js/test/et2_test_tabbox.xet index aa310f721b..cc6eb75b03 100644 --- a/etemplate/js/test/et2_test_tabbox.xet +++ b/etemplate/js/test/et2_test_tabbox.xet @@ -1,6 +1,6 @@ - + @@ -8,10 +8,18 @@ - diff --git a/etemplate/js/test/test.css b/etemplate/js/test/test.css index 7960d0359b..cfe6cf1e38 100644 --- a/etemplate/js/test/test.css +++ b/etemplate/js/test/test.css @@ -86,6 +86,7 @@ div.et2_hbox_right { margin: 0 0 5px 0; font-weight: bold; color: #2E2E2E; + cursor: pointer; text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; } diff --git a/etemplate/js/test/test_xml.html b/etemplate/js/test/test_xml.html index b7fedc28b7..b2b24ec75e 100644 --- a/etemplate/js/test/test_xml.html +++ b/etemplate/js/test/test_xml.html @@ -20,7 +20,7 @@ - +