Major update of the et2_widget internal structure. The following changes were made:

- All attributes of the widgets are now parsed from XML before the widget itself is created.
These attributes plus all default values are then added to an associative array. The associative array is passed as second parameter to the init function of et2_widget, but is also available as this.options *after* the constructor of the et2_widget baseclass has been called.
The et2_widget constructor also calls a function parseArrayMgrAttrs(_attrs) - in this function widget implementations can read the values from e.g. the content and validation_errors array and merge it into the given _attrs associative array.
After the complete internal widgettree is completely loaded and created the "loadingFinished" function gets called and invokes all given setter functions. After that it "glues" the DOM tree together. This should also (I didn't measure it) be a bit faster than before, when the DOM-Tree was created on the fly. 

Please have a look at the changes of the et2_textbox widget to see how this affects writing widgets.

Note: The "id" property is copied to the object scope on the top of the et2_widget constructor.

- When widgets are cloned the "options" array gets passed along to the newly created widget. This means that changes made on the widgets during runtime are not automatically copied to the clone - as this didn't happen anyhow it is not a really disadvantage.
On the other side there should be no difference between widgets directly inside the "overlay" xet tag and widgets which are inside instanciated templates.

- The selbox widget doesn't work anymore - it relied on the loadAttributes function which isn't available anymore. et2_selbox should use the parseArrayMgrAttrs function to access

- I've commented out some of the "validator"-code in etemplate2.js as it created some error messages when destroying the widget tree.
This commit is contained in:
Andreas Stöckel 2011-08-19 16:00:44 +00:00
parent a572007f1c
commit 5af5594f60
18 changed files with 377 additions and 328 deletions

View File

@ -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);
}
}
});

View File

@ -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]);
}
});

View File

@ -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();
}
});

View File

@ -109,9 +109,6 @@ var et2_checkbox_ro = et2_checkbox.extend({
}
},
init: function(_parent) {
},
init: function() {
this._super.apply(this, arguments);

View File

@ -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.");
}

View File

@ -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);

View File

@ -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"]);

View File

@ -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;
}
/**

View File

@ -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();

View File

@ -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);
}
});

View File

@ -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;
},

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
},
/**

View File

@ -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;

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<overlay>
<tabbox>
<tabbox width="100%">
<tabs>
<tab label="Test1" />
<tab label="Test2" />
@ -8,10 +8,18 @@
<tab label="Test4" />
</tabs>
<tabpanels>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 2"/>
<label value="This is the content of tab 3"/>
<label value="This is the content of tab 4"/>
<vbox>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 1"/>
<label value="This is the content of tab 1"/>
</vbox>
</tabpanels>
</tabbox>
</overlay>

View File

@ -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;
}

View File

@ -20,7 +20,7 @@
<script src="../et2_hbox.js"></script>
<script src="../et2_textbox.js"></script>
<script src="../et2_number.js"></script>
<script src="../et2_selectbox.js"></script>
<!-- <script src="../et2_selectbox.js"></script>-->
<script src="../et2_checkbox.js"></script>
<script src="../et2_radiobox.js"></script>
<script src="../et2_styles.js"></script>