egroupware/etemplate/js/et2_core_DOMWidget.js

558 lines
12 KiB
JavaScript
Raw Normal View History

/**
* eGroupWare eTemplate2 - JS DOM Widget 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
* @copyright Stylite 2011
* @version $Id$
*/
"use strict";
/*egw:uses
et2_core_interfaces;
et2_core_widget;
*/
/**
* Abstract widget class which can be inserted into the DOM. All widget classes
* deriving from this class have to care about implementing the "getDOMNode"
* function which has to return the DOM-Node.
*/
var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, {
attributes: {
"disabled": {
"name": "Disabled",
"type": "boolean",
"description": "Defines whether this widget is visible. Not to be confused with an input widget's HTML attribute 'disabled'.",
"default": false
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.
2011-08-19 18:00:44 +02:00
},
"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'"
},
"class": {
"name": "CSS Class",
"type": "string",
"default": et2_no_init,
"description": "CSS Class which is applied to the dom element of this node"
},
"overflow": {
"name": "Overflow",
"type": "string",
"default": et2_no_init,
"description": "If set, the css-overflow attribute is set to that value"
},
"parent_node": {
"name": "DOM parent",
"type": "string",
"default": et2_no_init,
"description": "Insert into the target DOM node instead of the normal location"
}
},
/**
* When the DOMWidget is initialized, it grabs the DOM-Node of the parent
* object (if available) and passes it to its own "createDOMNode" function
*/
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.
2011-08-19 18:00:44 +02:00
init: function() {
// Call the inherited constructor
this._super.apply(this, arguments);
this.parentNode = null;
this._attachSet = {
"node": null,
"parent": null
};
this.disabled = false;
this._surroundingsMgr = null;
},
/**
* Detatches the node from the DOM and clears all references to the parent
* node or the dom node of this widget.
*/
destroy: function() {
this.detatchFromDOM();
this.parentNode = null;
this._attachSet = {};
if (this._surroundingsMgr)
{
this._surroundingsMgr.free();
this._surroundingsMgr = null;
}
this._super();
},
/**
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.
2011-08-19 18:00:44 +02:00
* Attaches the container node of this widget to the DOM-Tree
*/
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.
2011-08-19 18:00:44 +02:00
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)) {
if(this.options.parent_node)
{
this.set_parent_node(this.options.parent_node);
}
else
{
this.setParentDOMNode(this._parent.getDOMNode(this));
}
}
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.
2011-08-19 18:00:44 +02:00
return true;
},
/**
* Detaches the widget from the DOM tree, if it had been attached to the
* DOM-Tree using the attachToDOM method.
*/
detatchFromDOM: function() {
if (this._attachSet.node && this._attachSet.parent)
{
// Remove the current node from the parent node
this._attachSet.parent.removeChild(this._attachSet.node);
// Reset the "attachSet"
this._attachSet = {
"node": null,
"parent": null
};
return true;
}
return false;
},
/**
* Attaches the widget to the DOM tree. Fails if the widget is already
* attached to the tree or no parent node or no node for this widget is
* defined.
*/
attachToDOM: function() {
// Attach the DOM node of this widget (if existing) to the new parent
var node = this.getDOMNode(this);
if (node && this.parentNode &&
(node != this._attachSet.node ||
this.parentNode != this._attachSet.parent))
{
// If the surroundings manager exists, surround the DOM-Node of this
// widget with the DOM-Nodes inside the surroundings manager.
if (this._surroundingsMgr)
{
node = this._surroundingsMgr.getDOMNode(node);
}
// Append this node at its index
var idx = this.getDOMIndex();
if (idx < 0 || idx >= this.parentNode.childNodes.length - 1)
{
this.parentNode.appendChild(node);
}
else
{
this.parentNode.insertBefore(node, this.parentNode.childNodes[idx]);
}
// Store the currently attached nodes
this._attachSet = {
"node": node,
"parent": this.parentNode
};
return true;
}
return false;
},
isAttached: function() {
return this.parentNode != null;
},
getSurroundings: function() {
if (!this._surroundingsMgr)
{
this._surroundingsMgr = new et2_surroundingsMgr(this);
}
return this._surroundingsMgr;
},
/**
* Set the parent DOM node of this element. Takes a wider variety of types
* than setParentDOMNode(), and matches the set_<attribute> naming convention.
*
* @param _node String|DOMNode DOM node to contain the widget, or the ID of the DOM node.
*/
set_parent_node: function(_node) {
if(typeof _node == "string")
{
this.setParentDOMNode($j('#'+_node).get(0));
}
else
{
this.setParentDOMNode(_node);
}
},
/**
* Set the parent DOM node of this element. If another parent node is already
* set, this widget removes itself from the DOM tree
*/
setParentDOMNode: function(_node) {
if (_node != this.parentNode)
{
// Detatch this element from the DOM tree
this.detatchFromDOM();
this.parentNode = _node;
// And attatch the element to the DOM tree
this.attachToDOM();
}
},
/**
* Returns the parent node.
*/
getParentDOMNode: function() {
return this.parentNode;
},
/**
* Returns the index of this element in the DOM tree
*/
getDOMIndex: function() {
if (this._parent)
{
var idx = 0;
var children = this._parent.getChildren();
for (var i = 0; i < children.length; i++)
{
if (children[i] == this)
{
return idx;
}
else if (children[i].isInTree())
{
idx++;
}
}
}
return -1;
},
/**
* Sets the id of the DOM-Node.
*/
set_id: function(_value) {
this.id = _value;
var node = this.getDOMNode(this);
if (node)
{
if (_value != "")
{
node.setAttribute("id", _value);
}
else
{
node.removeAttribute("id");
}
}
},
set_disabled: function(_value) {
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.
2011-08-19 18:00:44 +02:00
var node = this.getDOMNode(this);
if (node && this.disabled != _value)
{
2011-08-17 19:48:39 +02:00
this.disabled = _value;
if (_value)
{
$j(node).hide();
}
else
{
$j(node).show();
}
}
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.
2011-08-19 18:00:44 +02:00
},
set_width: function(_value) {
this.width = _value;
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.
2011-08-19 18:00:44 +02:00
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);
}
},
set_class: function(_value) {
var node = this.getDOMNode(this);
if (node)
{
if (this["class"])
{
$j(node).removeClass(this["class"]);
}
$j(node).addClass(_value);
}
this["class"] = _value;
},
set_overflow: function(_value) {
this.overflow = _value;
var node = this.getDOMNode(this);
if (node)
{
$j(node).css("overflow", _value);
}
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.
2011-08-19 18:00:44 +02:00
}
});
/**
* The surroundings manager class allows to append or prepend elements around
* an widget node.
*/
var et2_surroundingsMgr = Class.extend({
init: function(_widget) {
this.widget = _widget;
this._widgetContainer = null;
this._widgetSurroundings = [];
this._widgetPlaceholder = null;
this._widgetNode = null;
this._ownPlaceholder = true;
},
destroy: function() {
this._widgetContainer = null;
this._widgetSurroundings = null;
this._widgetPlaceholder = null;
this._widgetNode = null;
},
prependDOMNode: function(_node) {
this._widgetSurroundings.unshift(_node);
this._surroundingsUpdated = true;
},
appendDOMNode: function(_node) {
// Append an placeholder first if none is existing yet
if (this._ownPlaceholder && this._widgetPlaceholder == null)
{
this._widgetPlaceholder = document.createElement("span");
this._widgetSurroundings.push(this._widgetPlaceholder);
}
// Append the given node
this._widgetSurroundings.push(_node);
this._surroundingsUpdated = true;
},
insertDOMNode: function(_node) {
if (!this._ownPlaceholder || this._widgetPlaceholder == null)
{
this.appendDOMNode(_node);
return;
}
// Get the index of the widget placeholder and delete it, insert the
// given node instead
var idx = this._widgetSurroundings.indexOf(this._widgetPlaceholder);
this._widgetSurroundings.splice(idx, 1, _node);
// Delete the reference to the own placeholder
this._widgetPlaceholder = null;
this._ownPlaceholder = false;
},
removeDOMNode: function(_node) {
for (var i = 0; i < this._widgetSurroundings.length; i++)
{
if (this._widgetSurroundings[i] == _node)
{
this._widgetSurroundings.splice(i, 1);
this._surroundingsUpdated = true;
break;
}
}
},
setWidgetPlaceholder: function(_node) {
if (_node != this._widgetPlaceholder)
{
if (_node != null && this._ownPlaceholder && this._widgetPlaceholder != null)
{
// Delete the current placeholder which was created by the
// widget itself
var idx = this._widgetSurroundings.indexOf(this._widgetPlaceholder);
this._widgetSurroundings.splice(idx, 1);
// Delete any reference to the own placeholder and set the
// _ownPlaceholder flag to false
this._widgetPlaceholder = null;
this._ownPlaceholder = false;
}
this._ownPlaceholder = (_node == null);
this._widgetPlaceholder = _node;
this._surroundingsUpdated = true;
}
},
_rebuildContainer: function() {
// Return if there has been no change in the "surroundings-data"
if (!this._surroundingsUpdated)
{
return false;
}
// Build the widget container
if (this._widgetSurroundings.length > 0)
{
// Check whether the widgetPlaceholder is really inside the DOM-Tree
var hasPlaceholder = et2_hasChild(this._widgetSurroundings,
this._widgetPlaceholder);
// If not, append another widget placeholder
if (!hasPlaceholder)
{
this._widgetPlaceholder = document.createElement("span");
this._widgetSurroundings.push(this._widgetPlaceholder);
this._ownPlaceholder = true;
}
// If the surroundings array only contains one element, set this one
// as the widget container
if (this._widgetSurroundings.length == 1)
{
if (this._widgetSurroundings[0] == this._widgetPlaceholder)
{
this._widgetContainer = null;
}
else
{
this._widgetContainer = this._widgetSurroundings[0];
}
}
else
{
// Create an outer "span" as widgetContainer
this._widgetContainer = document.createElement("span");
// Append the children inside the widgetSurroundings array to
// the widget container
for (var i = 0; i < this._widgetSurroundings.length; i++)
{
this._widgetContainer.appendChild(this._widgetSurroundings[i]);
}
}
}
else
{
this._widgetContainer = null;
this._widgetPlaceholder = null;
}
this._surroundingsUpdated = false;
return true;
},
update: function() {
if (this._surroundingsUpdated)
{
var attached = this.widget ? this.widget.isAttached() : false;
// Reattach the widget - this will call the "getDOMNode" function
// and trigger the _rebuildContainer function.
if (attached && this.widget)
{
this.widget.detatchFromDOM();
this.widget.attachToDOM();
}
}
},
getDOMNode: function(_widgetNode) {
// Update the whole widgetContainer if this is not the first time this
// function has been called but the widget node has changed.
if (this._widgetNode != null && this._widgetNode != _widgetNode)
{
this._surroundingsUpdated = true;
}
// Copy a reference to the given node
this._widgetNode = _widgetNode;
// Build the container if it didn't exist yet.
var updated = this._rebuildContainer();
// Return the widget node itself if there are no surroundings arround
// it
if (this._widgetContainer == null)
{
return _widgetNode;
}
// Replace the widgetPlaceholder with the given widget node if the
// widgetContainer has been updated
if (updated)
{
this._widgetPlaceholder.parentNode.replaceChild(_widgetNode,
this._widgetPlaceholder);
if (!this._ownPlaceholder)
{
this._widgetPlaceholder = _widgetNode;
}
}
// Return the widget container
return this._widgetContainer;
}
});