Implemented usage of mutliple array-manager objects (the object which cares about proper namespacing etc.) for each supplied data manager part (like 'content', 'readonlys' etc.), renamed et2_contentArrayMgr.js to et2_arrayMgr.js, renamed et2_all.js to etemplate2.js and added an top-level object which cares about loading the template, creating the array managers etc.

This commit is contained in:
Andreas Stöckel 2011-08-15 12:34:00 +00:00
parent be34748b32
commit 8c9fd0f636
11 changed files with 231 additions and 154 deletions

View File

@ -92,7 +92,7 @@ class etemplate_new
} }
else // first call else // first call
*/ { */ {
egw_framework::validate_file('.','et2_all','etemplate'); egw_framework::validate_file('.','etemplate2','etemplate');
egw_framework::includeCSS('/etemplate/js/test/test.css'); egw_framework::includeCSS('/etemplate/js/test/test.css');
common::egw_header(); common::egw_header();
@ -103,24 +103,8 @@ class etemplate_new
echo ' echo '
<div id="container"></div> <div id="container"></div>
<script> <script>
var container = null; var et2 = new etemplate2(document.getElementById("container"), "");
et2.load("'.$GLOBALS['egw_info']['server']['webserver_url'].$this->rel_path.'",'.json_encode(array(
function open_xet(file, content) {
et2_loadXMLFromURL(file,
function(_xmldoc) {
if (container != null)
{
container.destroy();
container = null;
}
container = new et2_container(null);
container.setParentDOMNode(document.getElementById("container"));
container.setContentMgr(new et2_contentArrayMgr(content));
container.loadFromXML(_xmldoc);
});
}
open_xet("'.$GLOBALS['egw_info']['server']['webserver_url'].$this->rel_path.'",'.json_encode(array(
'content' => $content, 'content' => $content,
'sel_options' => $sel_options, 'sel_options' => $sel_options,
'readonlys' => $readonlys, 'readonlys' => $readonlys,

View File

@ -1,27 +0,0 @@
/**
* eGroupWare eTemplate2 - JS file which contains the complete et2 module
*
* @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$
*/
/**
* Only include the actual widget class files here, all other dependencies are
* included in those files.
*/
/*egw:uses
et2_template;
et2_grid;
et2_box;
// et2_tabs;
et2_button;
et2_description;
et2_textbox;
*/

View File

@ -12,7 +12,7 @@
"use strict"; "use strict";
function et2_contentArrayMgr(_data, _parentMgr) function et2_arrayMgr(_data, _parentMgr)
{ {
if (typeof _parentMgr == "undefined") if (typeof _parentMgr == "undefined")
{ {
@ -44,7 +44,7 @@ function et2_contentArrayMgr(_data, _parentMgr)
/** /**
* Returns the root content array manager object * Returns the root content array manager object
*/ */
et2_contentArrayMgr.prototype.getRoot = function() et2_arrayMgr.prototype.getRoot = function()
{ {
if (this.parentMgr != null) if (this.parentMgr != null)
{ {
@ -54,7 +54,7 @@ et2_contentArrayMgr.prototype.getRoot = function()
return this; return this;
} }
et2_contentArrayMgr.prototype.getValueForID = function(_id) et2_arrayMgr.prototype.getValueForID = function(_id)
{ {
if (typeof this.data[_id] != "undefined") if (typeof this.data[_id] != "undefined")
{ {
@ -70,7 +70,7 @@ et2_contentArrayMgr.prototype.getValueForID = function(_id)
* *
* @param _path is used internally, do not supply it manually. * @param _path is used internally, do not supply it manually.
*/ */
et2_contentArrayMgr.prototype.getPath = function(_path) et2_arrayMgr.prototype.getPath = function(_path)
{ {
if (typeof _path == "undefined") if (typeof _path == "undefined")
{ {
@ -101,7 +101,7 @@ et2_contentArrayMgr.prototype.getPath = function(_path)
* @param _skipEmpty returns false if _key is not present in this content array. * @param _skipEmpty returns false if _key is not present in this content array.
* Defaults to false. * Defaults to false.
*/ */
et2_contentArrayMgr.prototype.getEntry = function(_key, _referenceInto, et2_arrayMgr.prototype.getEntry = function(_key, _referenceInto,
_skipEmpty) _skipEmpty)
{ {
if (typeof _referenceInto == "undefined") if (typeof _referenceInto == "undefined")
@ -147,7 +147,7 @@ et2_contentArrayMgr.prototype.getEntry = function(_key, _referenceInto,
* Expands variables inside the given identifier to their values inside the * Expands variables inside the given identifier to their values inside the
* content array. * content array.
*/ */
et2_contentArrayMgr.prototype.expandName = function(_ident) et2_arrayMgr.prototype.expandName = function(_ident)
{ {
// Check whether the identifier refers to an index in the content array // Check whether the identifier refers to an index in the content array
var is_index_in_content = _ident.charAt(0) == '@'; var is_index_in_content = _ident.charAt(0) == '@';
@ -176,7 +176,7 @@ et2_contentArrayMgr.prototype.expandName = function(_ident)
return _ident; return _ident;
} }
et2_contentArrayMgr.prototype.parseBoolExpression = function(_expression) et2_arrayMgr.prototype.parseBoolExpression = function(_expression)
{ {
// If the first char of the expression is a '!' this means, that the value // If the first char of the expression is a '!' this means, that the value
// is to be negated. // is to be negated.
@ -212,14 +212,14 @@ et2_contentArrayMgr.prototype.parseBoolExpression = function(_expression)
return val != '' && (typeof val != "string" || val.toLowerCase() != "false"); return val != '' && (typeof val != "string" || val.toLowerCase() != "false");
} }
et2_contentArrayMgr.prototype.openPerspective = function(_owner, _root, _col, _row) et2_arrayMgr.prototype.openPerspective = function(_owner, _root, _col, _row)
{ {
// Get the root node // Get the root node
var root = typeof _root == "string" ? this.data[_root] : var root = typeof _root == "string" ? this.data[_root] :
(_root == null ? this.data : _root); (_root == null ? this.data : _root);
// Create a new content array manager with the given root // Create a new content array manager with the given root
var mgr = new et2_contentArrayMgr(root, this); var mgr = new et2_arrayMgr(root, this);
// Set the owner // Set the owner
mgr.perspectiveData.owner = _owner; mgr.perspectiveData.owner = _owner;

View File

@ -353,4 +353,18 @@ function et2_csvSplit(_str, _num, _delimiter, _enclosure)
return parts; return parts;
} }
/**
* Creates a copy of the given object (non recursive)
*/
function et2_cloneObject(_obj)
{
var result = {};
for (var key in _obj)
{
result[key] = _obj[key];
}
return result;
}

View File

@ -88,7 +88,7 @@ var et2_inputWidget = et2_baseWidget.extend(et2_IInput, {
} }
// Set the value for this element // Set the value for this element
var mgr = this.getContentMgr(); var mgr = this.getArrayMgr("content");
if (_value != '' && mgr != null) if (_value != '' && mgr != null)
{ {
var val = mgr.getValueForID(this.id); var val = mgr.getValueForID(this.id);

View File

@ -16,7 +16,7 @@
et2_xml; et2_xml;
et2_common; et2_common;
et2_inheritance; et2_inheritance;
et2_contentArrayMgr; et2_arrayMgr;
*/ */
/** /**
@ -100,7 +100,7 @@ var et2_widget = Class.extend({
} }
this.id = ""; this.id = "";
this._mgr = null; this._mgrs = {};
// Copy the parent parameter and add this widget to its parent children // Copy the parent parameter and add this widget to its parent children
// list. // list.
@ -145,7 +145,7 @@ var et2_widget = Class.extend({
// Delete all references to other objects // Delete all references to other objects
this._children = []; this._children = [];
this._parent = null; this._parent = null;
this._mgr = null; this._mgrs = {};
this.onSetParent(); this.onSetParent();
}, },
@ -188,10 +188,7 @@ var et2_widget = Class.extend({
} }
// Copy a reference to the content array manager // Copy a reference to the content array manager
if (_obj._mgr) this.setArrayMgrs(_obj.mgrs);
{
this._mgr = _obj._mgr;
}
}, },
/** /**
@ -453,12 +450,12 @@ var et2_widget = Class.extend({
// expression as bool expression. // expression as bool expression.
if (attr.type == "boolean") if (attr.type == "boolean")
{ {
attrValue = this.getContentMgr() attrValue = this.getArrayMgr("content")
.parseBoolExpression(attrValue); .parseBoolExpression(attrValue);
} }
else else
{ {
attrValue = this.getContentMgr().expandName(attrValue); attrValue = this.getArrayMgr("content").expandName(attrValue);
} }
} }
@ -497,23 +494,6 @@ var et2_widget = Class.extend({
} }
}, },
setContentMgr: function(_mgr) {
this._mgr = _mgr;
},
getContentMgr: function() {
if (this._mgr != null)
{
return this._mgr;
}
else if (this._parent)
{
return this._parent.getContentMgr();
}
return null;
},
/** /**
* Fetches all input element values and returns them in an associative * Fetches all input element values and returns them in an associative
* array. Widgets which introduce namespacing can use the internal _target * array. Widgets which introduce namespacing can use the internal _target
@ -566,6 +546,67 @@ var et2_widget = Class.extend({
return result; return result;
}, },
/**
* Sets all array manager objects - this function can be used to set the
* root array managers of the container object.
*/
setArrayMgrs: function(_mgrs) {
this._mgrs = et2_cloneObject(_mgrs);
},
/**
* Returns an associative array containing the top-most array managers.
*
* @param _mgrs is used internally and should not be supplied.
*/
getArrayMgrs: function(_mgrs) {
if (typeof _mgrs == "undefined")
{
_mgrs = {};
}
// Add all managers of this object to the result, if they have not already
// been set in the result
for (var key in this._mgrs)
{
if (typeof _mgrs[key] == "undefined")
{
_mgrs[key] = this._mgrs[key];
}
}
// Recursively applies this function to the parent widget
if (this._parent)
{
this._parent.getArrayMgrs(_mgrs);
}
return _mgrs;
},
/**
* Sets the array manager for the given part
*/
setArrayMgr: function(_part, _mgr) {
this._mgrs[_part] = _mgr;
},
/**
* Returns the array manager object for the given part
*/
getArrayMgr: function(_part) {
if (typeof this._mgrs[_part] != "undefined")
{
return this._mgrs[_part];
}
else if (this._parent)
{
return this._parent.getArrayMgr(_part);
}
return null;
},
/** /**
* Checks whether a namespace exists for this element in the content array. * Checks whether a namespace exists for this element in the content array.
* If yes, an own perspective of the content array is created. If not, the * If yes, an own perspective of the content array is created. If not, the
@ -573,27 +614,32 @@ var et2_widget = Class.extend({
*/ */
checkCreateNamespace: function() { checkCreateNamespace: function() {
// Get the content manager // Get the content manager
var mgr = this.getContentMgr(); var mgrs = this.getArrayMgrs();
// Get the original content manager if we have already created a for (var key in mgrs)
// perspective for this node
if (this._mgr != null && this._mgr.perspectiveData.owner == this)
{ {
mgr = mgr.parentMgr; var mgr = mgrs[key];
}
// Check whether the manager has a namespace for the id of this object // Get the original content manager if we have already created a
if (mgr.getEntry(this.id) instanceof Object) // perspective for this node
{ if (typeof this._mgrs[key] != "undefined" && mgr.perspectiveData.owner == this)
// The content manager has a own node for this object, so create {
// an own perspective. mgr = mgr.parentMgr;
this._mgr = mgr.openPerspective(this, this.id); }
}
else // Check whether the manager has a namespace for the id of this object
{ if (mgr.getEntry(this.id) instanceof Object)
// The current content manager does not have an own namespace for {
// this element, so use the content manager of the parent. // The content manager has an own node for this object, so
this._mgr = null; // create an own perspective.
this._mgrs[key] = mgr.openPerspective(this, this.id);
}
else
{
// The current content manager does not have an own namespace for
// this element, so use the content manager of the parent.
delete(this._mgrs[key]);
}
} }
} }
}); });

View File

@ -0,0 +1,97 @@
/**
* eGroupWare eTemplate2 - JS file which contains the complete et2 module
*
* @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$
*/
/*egw:uses
// Include all widget classes here
et2_template;
et2_grid;
et2_box;
et2_button;
et2_description;
et2_textbox;
// Requirements for the etemplate2 object
et2_xml;
et2_arrayMgr;
*/
/**
* The etemplate2 class manages a certain etemplate2 instance.
*
* @param _container is the DOM-Node into which the DOM-Nodes of this instance
* should be inserted
* @param _submitURL is the URL to which the form data should be submitted.
*/
function etemplate2(_container, _submitURL)
{
// Copy the given parameters
this.DOMContainer = _container;
this.submitURL = _submitURL;
// Preset the object variable
this.widgetContainer = null;
}
/**
* Clears the current instance.
*/
etemplate2.prototype.clear = function()
{
if (this.widgetContainer != null)
{
this.widgetContainer.destroy();
this.widgetContainer = null;
}
}
/**
* Creates an associative array containing the data array managers for each part
* of the associative data array. A part is something like "content", "readonlys"
* or "sel_options".
*/
etemplate2.prototype._createArrayManagers = function(_data)
{
var result = {};
// Create an array manager object for each part of the _data array.
for (var key in _data)
{
result[key] = new et2_arrayMgr(_data[key]);
}
return result;
}
/**
* Loads the template from the given URL and sets the data object
*/
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) {
this.widgetContainer.loadFromXML(_xmldoc);
}, this);
// Clear any existing instance
this.clear();
// Create the basic widget container and attach it to the DOM
this.widgetContainer = new et2_container(null);
this.widgetContainer.setParentDOMNode(this.DOMContainer);
// Split the given data into array manager objects and pass those to the
// widget container
this.widgetContainer.setArrayMgrs(this._createArrayManagers(_data));
}

View File

@ -1,9 +1,11 @@
var expression_test_data = { var expression_test_data = {
"test": { "content": {
"display_text": "true", "test": {
"textbox": "And this is the inner textbox." "display_text": "true",
}, "textbox": "And this is the inner textbox."
"display_text": "false", },
"textbox": "This is the outer textbox." "display_text": "false",
"textbox": "This is the outer textbox."
}
}; };

View File

@ -2,7 +2,7 @@
<overlay> <overlay>
<template id="test"> <template id="test">
<vbox> <vbox>
<description disabled="!@display_text" value="Dies ist nur ein test!" /> <description disabled="!@@display_text" value="Dies ist nur ein test!" />
<textbox id="textbox" /> <textbox id="textbox" />
</vbox> </vbox>
</template> </template>

View File

@ -70,26 +70,6 @@ var timesheet_data = {
"tabs":{ "tabs":{
"customfields":true "customfields":true
} }
},
"preserv":{
"ts_id":"1",
"ts_project":null,
"ts_title":"Test geschrieben",
"ts_description":null,
"ts_start":1307030400,
"ts_duration":"150",
"ts_quantity":"2.5",
"ts_unitprice":null,
"cat_id":null,
"ts_owner":"5",
"ts_modified":1307039479,
"ts_modifier":"5",
"pl_id":null,
"ts_status":null,
"user_timezone_read":"Europe/Berlin",
"view":false,
"referer":"timesheet.timesheet_ui.index",
"ts_title_blur":null
} }
} }

View File

@ -6,6 +6,7 @@
<script src="../et2_xml.js"></script> <script src="../et2_xml.js"></script>
<script src="../et2_inheritance.js"></script> <script src="../et2_inheritance.js"></script>
<script src="../et2_common.js"></script> <script src="../et2_common.js"></script>
<script src="../et2_arrayMgr.js"></script>
<script src="../et2_widget.js"></script> <script src="../et2_widget.js"></script>
<script src="../et2_DOMWidget.js"></script> <script src="../et2_DOMWidget.js"></script>
<script src="../et2_baseWidget.js"></script> <script src="../et2_baseWidget.js"></script>
@ -16,7 +17,9 @@
<script src="../et2_button.js"></script> <script src="../et2_button.js"></script>
<script src="../et2_box.js"></script> <script src="../et2_box.js"></script>
<script src="../et2_textbox.js"></script> <script src="../et2_textbox.js"></script>
<script src="../et2_contentArrayMgr.js"></script>
<script src="../etemplate2.js"></script>
<!--<script src="../et2_tabs.js"></script>--> <!--<script src="../et2_tabs.js"></script>-->
<script src="../lib/tooltip.js"></script> <script src="../lib/tooltip.js"></script>
@ -28,7 +31,7 @@
<h1>EGroupware ETemplate2 Test</h1> <h1>EGroupware ETemplate2 Test</h1>
<div class="header">Choose one of the following tests:</div> <div class="header">Choose one of the following tests:</div>
<div id="linklist"> <div id="linklist">
<a href="#" onclick="open_xet('et2_test_timesheet_edit.xet', timesheet_data.content);">Timesheet edit dialog</a> <a href="#" onclick="open_xet('et2_test_timesheet_edit.xet', timesheet_data);">Timesheet edit dialog</a>
<a href="#" onclick="open_xet('et2_test_template.xet');">Template proxy test</a> <a href="#" onclick="open_xet('et2_test_template.xet');">Template proxy test</a>
<a href="#" onclick="open_xet('et2_test_grid.xet');">Grid test</a> <a href="#" onclick="open_xet('et2_test_grid.xet');">Grid test</a>
<a href="#" onclick="open_xet('et2_test_tabbox.xet');">Tabs test</a> <a href="#" onclick="open_xet('et2_test_tabbox.xet');">Tabs test</a>
@ -40,33 +43,11 @@
<div id="time"></div> <div id="time"></div>
<div id="container"></div> <div id="container"></div>
<script> <script>
var container = null; var et2 = new etemplate2(document.getElementById("container"), "");
function open_xet(file, content) { function open_xet(file, content) {
if (typeof content == "undefined") et2.load(file, content);
{ }
content = {};
}
et2_loadXMLFromURL(file,
function(_xmldoc) {
if (container != null)
{
container.destroy();
container = null;
}
var t1 = (new Date).getTime();
container = new et2_container(null);
container.setParentDOMNode(document.getElementById("container"));
container.setContentMgr(new et2_contentArrayMgr(content));
container.loadFromXML(_xmldoc);
var t2 = (new Date).getTime();
$j("#time").text("Building the template took " + (t2 - t1) + "ms");
});
}
</script> </script>
</body> </body>
</html> </html>