forked from extern/egroupware
reverting r53406, r53423: using JSON instead of XML for templates on client-side to improve IE performace, as it did not give any performance improvement
This commit is contained in:
parent
177083c730
commit
f57b4580a5
@ -166,11 +166,9 @@ class etemplate_new extends etemplate_widget_template
|
||||
|
||||
// Info required to load the etemplate client-side
|
||||
$dom_id = str_replace('.','-',$this->dom_id);
|
||||
$filename = etemplate_widget_template::rel2path(etemplate_widget_template::relPath($name));
|
||||
$load_array = array(
|
||||
'name' => $this->name,
|
||||
'url' => egw_framework::link('/etemplate/template.php', array('name' => $this->name, 'download' => filemtime($filename))),
|
||||
// etemplate_widget_template::rel2url($this->rel_path),
|
||||
'url' => etemplate_widget_template::rel2url($this->rel_path),
|
||||
'data' => $data,
|
||||
'DOMNodeID' => $dom_id,
|
||||
);
|
||||
|
@ -35,13 +35,6 @@ class etemplate_widget_template extends etemplate_widget
|
||||
*/
|
||||
protected static $cache = array();
|
||||
|
||||
/**
|
||||
* Tell egw framework it's ok to call this
|
||||
*/
|
||||
public $public_functions = array(
|
||||
'ajaxtoJSON' => true
|
||||
);
|
||||
|
||||
/**
|
||||
* Get instance of template specified by name, template(-set) and version
|
||||
*
|
||||
|
@ -471,15 +471,16 @@ var et2_widget = ClassWithAttributes.extend(
|
||||
},
|
||||
|
||||
/**
|
||||
* The parseJSONAttrs function takes a JSON object
|
||||
* 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 JSON object
|
||||
* @param _attrsObj is the XML DOM attributes object
|
||||
* @param {object} _target is the object to which the attributes should be written.
|
||||
* @param {et2_widget} _proto prototype with attributes and legacyOptions attribute
|
||||
*/
|
||||
parseJSONAttrs: function(_attrsObj, _target, _proto) {
|
||||
parseXMLAttrs: function(_attrsObj, _target, _proto) {
|
||||
|
||||
// Check whether the attributes object is really existing, if not abort
|
||||
if (typeof _attrsObj == "undefined")
|
||||
{
|
||||
@ -487,62 +488,71 @@ var et2_widget = ClassWithAttributes.extend(
|
||||
}
|
||||
|
||||
// Iterate over the given attributes and parse them
|
||||
for (var name in _attrsObj)
|
||||
{
|
||||
this._parseAttr(name, _attrsObj[name], _target, _proto);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a single attribute
|
||||
*
|
||||
* @param {string} attrName Attribute name
|
||||
* @param {object} attrValue Attribute value
|
||||
* @param {object} _target is the object to which the attributes should be written.
|
||||
* @param {et2_widget} _proto prototype with attributes and legacyOptions attribute
|
||||
*/
|
||||
_parseAttr: function(attrName, attrValue, _target, _proto)
|
||||
{
|
||||
var mgr = this.getArrayMgr("content");
|
||||
// Special handling for the legacy options
|
||||
if (attrName == "options" && _proto.legacyOptions.length > 0)
|
||||
for (var i = 0; i < _attrsObj.length; i++)
|
||||
{
|
||||
// Check for modifications on legacy options here. Normal modifications
|
||||
// are handled in widget constructor, but it's too late for legacy options then
|
||||
if(_target.id && this.getArrayMgr("modifications").getEntry(_target.id))
|
||||
{
|
||||
var mod = this.getArrayMgr("modifications").getEntry(_target.id);
|
||||
if(typeof mod.options != "undefined") attrValue = attrValue = mod.options;
|
||||
}
|
||||
// expand legacyOptions with content
|
||||
if(attrValue.charAt(0) == '@' || attrValue.indexOf('$') != -1)
|
||||
{
|
||||
attrValue = mgr.expandName(attrValue);
|
||||
}
|
||||
var attrName = _attrsObj[i].name;
|
||||
var attrValue = _attrsObj[i].value;
|
||||
|
||||
// Parse the legacy options (as a string, other types not allowed)
|
||||
var splitted = et2_csvSplit(attrValue+"");
|
||||
|
||||
for (var j = 0; j < splitted.length && j < _proto.legacyOptions.length; j++)
|
||||
// Special handling for the legacy options
|
||||
if (attrName == "options" && _proto.legacyOptions.length > 0)
|
||||
{
|
||||
// Blank = not set
|
||||
if(splitted[j].trim().length == 0) continue;
|
||||
|
||||
// Check to make sure we don't overwrite a current option with a legacy option
|
||||
if(typeof _target[_proto.legacyOptions[j]] === "undefined")
|
||||
// Check for modifications on legacy options here. Normal modifications
|
||||
// are handled in widget constructor, but it's too late for legacy options then
|
||||
if(_target.id && this.getArrayMgr("modifications").getEntry(_target.id))
|
||||
{
|
||||
attrValue = splitted[j];
|
||||
var mod = this.getArrayMgr("modifications").getEntry(_target.id);
|
||||
if(typeof mod.options != "undefined") attrValue = _attrsObj[i].value = mod.options;
|
||||
}
|
||||
// expand legacyOptions with content
|
||||
if(attrValue.charAt(0) == '@' || attrValue.indexOf('$') != -1)
|
||||
{
|
||||
attrValue = mgr.expandName(attrValue);
|
||||
}
|
||||
|
||||
/**
|
||||
If more legacy options than expected, stuff them all in the last legacy option
|
||||
Some legacy options take a comma separated list.
|
||||
*/
|
||||
if(j == _proto.legacyOptions.length - 1 && splitted.length > _proto.legacyOptions.length)
|
||||
// Parse the legacy options (as a string, other types not allowed)
|
||||
var splitted = et2_csvSplit(attrValue+"");
|
||||
|
||||
for (var j = 0; j < splitted.length && j < _proto.legacyOptions.length; j++)
|
||||
{
|
||||
// Blank = not set
|
||||
if(splitted[j].trim().length == 0) continue;
|
||||
|
||||
// Check to make sure we don't overwrite a current option with a legacy option
|
||||
if(typeof _target[_proto.legacyOptions[j]] === "undefined")
|
||||
{
|
||||
attrValue = splitted.slice(j);
|
||||
}
|
||||
attrValue = splitted[j];
|
||||
|
||||
var attr = _proto.attributes[_proto.legacyOptions[j]];
|
||||
/**
|
||||
If more legacy options than expected, stuff them all in the last legacy option
|
||||
Some legacy options take a comma separated list.
|
||||
*/
|
||||
if(j == _proto.legacyOptions.length - 1 && splitted.length > _proto.legacyOptions.length)
|
||||
{
|
||||
attrValue = splitted.slice(j);
|
||||
}
|
||||
|
||||
var attr = _proto.attributes[_proto.legacyOptions[j]];
|
||||
|
||||
// If the attribute is marked as boolean, parse the
|
||||
// expression as bool expression.
|
||||
if (attr.type == "boolean")
|
||||
{
|
||||
attrValue = mgr.parseBoolExpression(attrValue);
|
||||
}
|
||||
else if (typeof attrValue != "object")
|
||||
{
|
||||
attrValue = mgr.expandName(attrValue);
|
||||
}
|
||||
_target[_proto.legacyOptions[j]] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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.
|
||||
@ -550,34 +560,15 @@ var et2_widget = ClassWithAttributes.extend(
|
||||
{
|
||||
attrValue = mgr.parseBoolExpression(attrValue);
|
||||
}
|
||||
else if (typeof attrValue != "object")
|
||||
else
|
||||
{
|
||||
attrValue = mgr.expandName(attrValue);
|
||||
}
|
||||
_target[_proto.legacyOptions[j]] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Set the attribute
|
||||
_target[attrName] = attrValue;
|
||||
}
|
||||
},
|
||||
|
||||
@ -631,51 +622,47 @@ var et2_widget = ClassWithAttributes.extend(
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a et2_widget from a JSON object.
|
||||
* Create a et2_widget from an XML node.
|
||||
*
|
||||
* First the type and attributes are read from the node. Then the readonly & modifications
|
||||
* arrays are checked for changes specific to the loaded data. Then the appropriate
|
||||
* constructor is called. After the constructor returns, the widget has a chance to
|
||||
* further initialize itself from the object when the widget's loadFromObject() method
|
||||
* is called with the object.
|
||||
* further initialize itself from the XML node when the widget's loadFromXML() method
|
||||
* is called with the node.
|
||||
*
|
||||
* @param _node Object to read
|
||||
* @param _node XML node to read
|
||||
*
|
||||
* @return et2_widget
|
||||
*/
|
||||
createElementFromObject: function(_node) {
|
||||
createElementFromNode: function(_node) {
|
||||
var attributes = {};
|
||||
if(typeof _node.attributes === 'undefined')
|
||||
{
|
||||
_node.attributes = {};
|
||||
}
|
||||
|
||||
// Parse the "readonly" and "type" flag for this element here, as they
|
||||
// determine which constructor is used
|
||||
var _nodeName = attributes["type"] = _node.attributes.type ?
|
||||
_node.attributes.type : _node.tag;
|
||||
var _nodeName = attributes["type"] = _node.getAttribute("type") ?
|
||||
_node.getAttribute("type") : _node.nodeName.toLowerCase();
|
||||
var readonly = attributes["readonly"] =
|
||||
this.getArrayMgr("readonlys").isReadOnly(
|
||||
_node.attributes.id, _node.attributes.readonly,
|
||||
_node.getAttribute("id"), _node.getAttribute("readonly"),
|
||||
typeof this.readonly !== 'undefined' ? this.readonly : this.options.readonly );
|
||||
|
||||
// Check to see if modifications change type
|
||||
var modifications = this.getArrayMgr("modifications");
|
||||
if(modifications && _node.attributes.id) {
|
||||
var entry = modifications.getEntry(_node.attributes.id);
|
||||
if(modifications && _node.getAttribute("id")) {
|
||||
var entry = modifications.getEntry(_node.getAttribute("id"));
|
||||
if(entry == null)
|
||||
{
|
||||
// Try again, but skip the fancy stuff
|
||||
// TODO: Figure out why the getEntry() call doesn't always work
|
||||
var entry = modifications.data[_node.attributes.id];
|
||||
var entry = modifications.data[_node.getAttribute("id")];
|
||||
if(entry)
|
||||
{
|
||||
this.egw().debug("warn", "getEntry("+_node.attributes.id+") failed, but the data is there.", modifications, entry);
|
||||
this.egw().debug("warn", "getEntry("+_node.getAttribute("id")+") failed, but the data is there.", modifications, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try the root, in case a namespace got missed
|
||||
var entry = modifications.getRoot().getEntry(_node.attributes.id);
|
||||
var entry = modifications.getRoot().getEntry(_node.getAttribute("id"));
|
||||
}
|
||||
}
|
||||
if(entry && entry.type)
|
||||
@ -702,7 +689,7 @@ var et2_widget = ClassWithAttributes.extend(
|
||||
}
|
||||
|
||||
// Parse the attributes from the given XML attributes object
|
||||
this.parseJSONAttrs(_node.attributes, attributes, constructor.prototype);
|
||||
this.parseXMLAttrs(_node.attributes, attributes, constructor.prototype);
|
||||
|
||||
// Do an sanity check for the attributes
|
||||
constructor.prototype.generateAttributeSet(attributes);
|
||||
@ -712,31 +699,39 @@ var et2_widget = ClassWithAttributes.extend(
|
||||
var widget = new constructor(this, attributes);
|
||||
|
||||
// Load the widget itself from XML
|
||||
widget.loadFromJSON(_node);
|
||||
widget.loadFromXML(_node);
|
||||
|
||||
return widget;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the widget tree from JSON object
|
||||
* Loads the widget tree from an XML node
|
||||
*
|
||||
* @param {Object} _content
|
||||
* @param _node xml node
|
||||
*/
|
||||
loadFromJSON: function(object)
|
||||
{
|
||||
if(object.content)
|
||||
{
|
||||
this.loadContent(object.content);
|
||||
}
|
||||
if(!object.children) return;
|
||||
loadFromXML: function(_node) {
|
||||
// Load the child nodes.
|
||||
for (var i = 0; i < object.children.length; i++)
|
||||
for (var i = 0; i < _node.childNodes.length; i++)
|
||||
{
|
||||
var node = object.children[i];
|
||||
node.parentNode = object;
|
||||
|
||||
var node = _node.childNodes[i];
|
||||
var widgetType = node.nodeName.toLowerCase();
|
||||
|
||||
if (widgetType == "#comment")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (widgetType == "#text")
|
||||
{
|
||||
if (node.data.replace(/^\s+|\s+$/g, ''))
|
||||
{
|
||||
this.loadContent(node.data);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the new element
|
||||
this.createElementFromObject(node);
|
||||
this.createElementFromNode(node);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -64,14 +64,11 @@ function et2_directChildrenByTagName(_node, _tagName)
|
||||
_tagName = _tagName.toLowerCase();
|
||||
|
||||
var result = [];
|
||||
var children = _node.childNodes || _node.children || [];
|
||||
for (var i = 0; i < children.length; i++)
|
||||
for (var i = 0; i < _node.childNodes.length; i++)
|
||||
{
|
||||
var child = children[i];
|
||||
child.parentNode = _node;
|
||||
if (child.nodeName && _tagName === child.nodeName.toLowerCase() || child.tag && _tagName === child.tag)
|
||||
if (_tagName == _node.childNodes[i].nodeName.toLowerCase())
|
||||
{
|
||||
result.push(child);
|
||||
result.push(_node.childNodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,12 +77,10 @@ function et2_directChildrenByTagName(_node, _tagName)
|
||||
|
||||
function et2_filteredNodeIterator(_node, _callback, _context)
|
||||
{
|
||||
if(!_node.children) return;
|
||||
for (var i = 0; i < _node.children.length; i++)
|
||||
for (var i = 0; i < _node.childNodes.length; i++)
|
||||
{
|
||||
var node = _node.children[i];
|
||||
node.parentNode = _node;
|
||||
var nodeName = node.tag;
|
||||
var node = _node.childNodes[i];
|
||||
var nodeName = node.nodeName.toLowerCase();
|
||||
if (nodeName.charAt(0) != "#")
|
||||
{
|
||||
_callback.call(_context, node, nodeName);
|
||||
@ -95,15 +90,9 @@ function et2_filteredNodeIterator(_node, _callback, _context)
|
||||
|
||||
function et2_readAttrWithDefault(_node, _name, _default)
|
||||
{
|
||||
if( _node.getAttribute)
|
||||
{
|
||||
var val = _node.getAttribute(_name);
|
||||
}
|
||||
else if (_node.attributes)
|
||||
{
|
||||
var val = _node.attributes[_name];
|
||||
}
|
||||
return (val === null || typeof val === 'undefined') ? _default : val;
|
||||
|
||||
return (val === null) ? _default : val;
|
||||
}
|
||||
|
||||
|
||||
|
@ -328,13 +328,13 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput
|
||||
}
|
||||
},
|
||||
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
this.loadFields();
|
||||
|
||||
// Load the nodes as usual
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
|
||||
set_value: function(_value) {
|
||||
if(!this.options.customfields) return;
|
||||
for(var field_name in this.options.customfields)
|
||||
|
@ -53,7 +53,7 @@ var et2_box = et2_baseWidget.extend([et2_IDetachedDOM],
|
||||
*
|
||||
* @param {object} _node
|
||||
*/
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
if(this._type != "box")
|
||||
{
|
||||
return this._super.apply(this, arguments);
|
||||
@ -61,16 +61,30 @@ var et2_box = et2_baseWidget.extend([et2_IDetachedDOM],
|
||||
// Load the child nodes.
|
||||
var childIndex = 0;
|
||||
var repeatNode = null;
|
||||
for (var i=0; i < _node.children.length; i++)
|
||||
for (var i=0; i < _node.childNodes.length; i++)
|
||||
{
|
||||
var node = _node.children[i];
|
||||
var widgetType = node.tag;
|
||||
var node = _node.childNodes[i];
|
||||
var widgetType = node.nodeName.toLowerCase();
|
||||
|
||||
if (widgetType == "#comment")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (widgetType == "#text")
|
||||
{
|
||||
if (node.data.replace(/^\s+|\s+$/g, ''))
|
||||
{
|
||||
this.loadContent(node.data);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the new element, if no expansion needed
|
||||
var id = et2_readAttrWithDefault(node, "id", "");
|
||||
if(id.indexOf('$') < 0 || widgetType != 'box')
|
||||
{
|
||||
this.createElementFromObject(node);
|
||||
this.createElementFromNode(node);
|
||||
childIndex++;
|
||||
}
|
||||
else
|
||||
@ -95,7 +109,7 @@ var et2_box = et2_baseWidget.extend([et2_IDetachedDOM],
|
||||
}
|
||||
}
|
||||
|
||||
this.createElementFromObject(repeatNode);
|
||||
this.createElementFromNode(repeatNode);
|
||||
}
|
||||
|
||||
// Reset
|
||||
|
@ -86,7 +86,7 @@ var et2_entry = et2_valueWidget.extend(
|
||||
this.setDOMNode(document.createElement('span'));
|
||||
},
|
||||
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
// Load the nodes as usual
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
|
@ -352,9 +352,9 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
var cell = this._getCell(cells, x, y);
|
||||
|
||||
// Read the span value of the element
|
||||
if (node.attributes.span)
|
||||
if (node.getAttribute("span"))
|
||||
{
|
||||
cell.rowSpan = node.attributes.span;
|
||||
cell.rowSpan = node.getAttribute("span");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -423,9 +423,9 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
var cell = this._getCell(cells, x, y);
|
||||
|
||||
// Read the span value of the element
|
||||
if (node.attributes && node.attributes.span)
|
||||
if (node.getAttribute("span"))
|
||||
{
|
||||
cell.colSpan = node.attributes.span;
|
||||
cell.colSpan = node.getAttribute("span");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -441,20 +441,20 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
var span = cell.colSpan = this._forceNumber(cell.colSpan);
|
||||
|
||||
// Read the align value of the element
|
||||
if (node.attributes && node.attributes.align)
|
||||
if (node.getAttribute("align"))
|
||||
{
|
||||
cell.align = node.attributes.align;
|
||||
cell.align = node.getAttribute("align");
|
||||
}
|
||||
|
||||
// store id of nextmatch-*headers, so it is available for disabled widgets, which get not instanciated
|
||||
if (nodeName.substr(0, 10) == 'nextmatch-')
|
||||
{
|
||||
cell.nm_id = node.attributes.id;
|
||||
cell.nm_id = node.getAttribute('id');
|
||||
}
|
||||
// Apply widget's class to td, for backward compatability
|
||||
if(node.attributes && node.attributes.class)
|
||||
if(node.getAttribute("class"))
|
||||
{
|
||||
cell.class += (cell.class ? " " : "") + node.attributes.class;
|
||||
cell.class += (cell.class ? " " : "") + node.getAttribute("class");
|
||||
}
|
||||
|
||||
// Create the element
|
||||
@ -480,7 +480,7 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
|
||||
}
|
||||
|
||||
var widget = this.createElementFromObject(node, nodeName);
|
||||
var widget = this.createElementFromNode(node, nodeName);
|
||||
}
|
||||
|
||||
// Fill all cells the widget is spanning
|
||||
@ -520,7 +520,7 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
}
|
||||
// If row disabled, just skip it
|
||||
var disabled = false;
|
||||
if(et2_readAttrWithDefault(node, "disabled", false) == "1")
|
||||
if(node.getAttribute("disabled") == "1")
|
||||
{
|
||||
disabled = true;
|
||||
}
|
||||
@ -595,23 +595,23 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
|
||||
/**
|
||||
* As the does not fit very well into the default widget structure, we're
|
||||
* overwriting the loadFromJSON function and doing a two-pass reading -
|
||||
* overwriting the loadFromXML function and doing a two-pass reading -
|
||||
* in the first step the
|
||||
*
|
||||
* @param {object} _node xml node to process
|
||||
*/
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
// Keep the node for later changing / reloading
|
||||
this.template_node = _node;
|
||||
|
||||
// Get the columns and rows tag
|
||||
var rowsElems = _node.children[1];
|
||||
var columnsElems = _node.children[0];
|
||||
var rowsElems = et2_directChildrenByTagName(_node, "rows");
|
||||
var columnsElems = et2_directChildrenByTagName(_node, "columns");
|
||||
|
||||
if (rowsElems && columnsElems)
|
||||
if (rowsElems.length == 1 && columnsElems.length == 1)
|
||||
{
|
||||
var columns = columnsElems;
|
||||
var rows = rowsElems;
|
||||
var columns = columnsElems[0];
|
||||
var rows = rowsElems[0];
|
||||
var colData = [];
|
||||
var rowData = [];
|
||||
|
||||
@ -870,7 +870,7 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
||||
}
|
||||
|
||||
// Rebuild grid
|
||||
this.loadFromJSON(this.template_node);
|
||||
this.loadFromXML(this.template_node);
|
||||
|
||||
// New widgets need to finish
|
||||
this.loadingFinished();
|
||||
|
@ -96,15 +96,15 @@ var et2_hbox = et2_baseWidget.extend(
|
||||
},
|
||||
|
||||
/**
|
||||
* The overwritten function checks whether any child element has
|
||||
* The overwritten loadFromXML function checks whether any child element has
|
||||
* a special align value.
|
||||
*
|
||||
* @param {object} _node
|
||||
*/
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
// Check whether any child node has an alignment tag
|
||||
et2_filteredNodeIterator(_node, function(_node) {
|
||||
var align = et2_readAttrWithDefault(_node, 'align','');
|
||||
var align = _node.getAttribute("align");
|
||||
|
||||
if (!align)
|
||||
{
|
||||
|
@ -398,9 +398,9 @@ var et2_selectbox = et2_inputWidget.extend(
|
||||
return true;
|
||||
},
|
||||
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
// Handle special case where legacy option for empty label is used (conflicts with rows), and rows is set as an attribute
|
||||
var legacy = _node.attributes.options || false;
|
||||
var legacy = _node.getAttribute("options");
|
||||
if(legacy)
|
||||
{
|
||||
var legacy = legacy.split(",");
|
||||
|
@ -114,7 +114,7 @@ var et2_split = et2_DOMWidget.extend([et2_IResizeable,et2_IPrint],
|
||||
* Tap in here to check if we have real children, because all children should be created
|
||||
* by this point. If there are, replace the placeholders.
|
||||
*/
|
||||
loadFromJSON: function() {
|
||||
loadFromXML: function() {
|
||||
this._super.apply(this, arguments);
|
||||
if(this._children.length > 0)
|
||||
{
|
||||
|
@ -132,7 +132,7 @@ var et2_tabbox = et2_valueWidget.extend([et2_IInput,et2_IResizeable],
|
||||
"contentDiv": null,
|
||||
"flagDiv": null,
|
||||
"hidden": hide,
|
||||
"JSON": null,
|
||||
"XMLNode": null,
|
||||
"promise": null
|
||||
});
|
||||
}
|
||||
@ -157,7 +157,7 @@ var et2_tabbox = et2_valueWidget.extend([et2_IInput,et2_IResizeable],
|
||||
if (i < tabData.length)
|
||||
{
|
||||
// Store node for later evaluation
|
||||
tabData[i].JSON = node;
|
||||
tabData[i].XMLNode = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -167,7 +167,7 @@ var et2_tabbox = et2_valueWidget.extend([et2_IInput,et2_IResizeable],
|
||||
}, this);
|
||||
},
|
||||
|
||||
loadFromJSON: function(_node) {
|
||||
loadFromXML: function(_node) {
|
||||
// Get the tabs and tabpanels tags
|
||||
var tabsElems = et2_directChildrenByTagName(_node, "tabs");
|
||||
var tabpanelsElems = et2_directChildrenByTagName(_node, "tabpanels");
|
||||
@ -219,7 +219,7 @@ var et2_tabbox = et2_valueWidget.extend([et2_IInput,et2_IResizeable],
|
||||
"contentDiv": null,
|
||||
"flagDiv": null,
|
||||
"hidden": typeof tab.hidden != "undefined" ? tab.hidden : readonly[tab_id] || false,
|
||||
"JSON": null,
|
||||
"XMLNode": null,
|
||||
"promise": null
|
||||
});
|
||||
}
|
||||
@ -274,12 +274,12 @@ var et2_tabbox = et2_valueWidget.extend([et2_IInput,et2_IResizeable],
|
||||
_loadTab: function(index,promises) {
|
||||
var tabData = this.tabData[index];
|
||||
if(!tabData || tabData.loaded) return;
|
||||
if(tabData.JSON != null)
|
||||
if(tabData.XMLNode != null)
|
||||
{
|
||||
tabData.widget = this.createElementFromObject(tabData.JSON,tabData.JSON.tag);
|
||||
tabData.widget = this.createElementFromNode(tabData.XMLNode,tabData.XMLNode.nodeName.toLowerCase());
|
||||
|
||||
// Release the JSON object
|
||||
tabData.JSON = null;
|
||||
// Release the XML node
|
||||
tabData.XMLNode = null;
|
||||
}
|
||||
else if (tabData.widget_options)
|
||||
{
|
||||
|
@ -86,9 +86,10 @@ var et2_template = et2_DOMWidget.extend(
|
||||
var cache_buster = parts.length > 1 ? parts.pop() : null;
|
||||
var template_name = parts.pop();
|
||||
|
||||
// Check to see if the template is known
|
||||
var template = etemplate2.prototype.get_template_cache(template_name);
|
||||
if(!template)
|
||||
// Check to see if XML is known
|
||||
var xml = null;
|
||||
var templates = etemplate2.prototype.templates; // use global eTemplate cache
|
||||
if(!(xml = templates[template_name]))
|
||||
{
|
||||
// Check to see if ID is short form --> prepend parent/top-level name
|
||||
if(template_name.indexOf('.') < 0)
|
||||
@ -97,52 +98,42 @@ var et2_template = et2_DOMWidget.extend(
|
||||
var top_name = root && root._inst ? root._inst.name : null;
|
||||
if (top_name && template_name.indexOf('.') < 0) template_name = top_name+'.'+template_name;
|
||||
}
|
||||
template = etemplate2.prototype.get_template_cache(template_name);
|
||||
if(!template)
|
||||
xml = templates[template_name];
|
||||
if(!xml)
|
||||
{
|
||||
// Ask server
|
||||
var splitted = template_name.split('.');
|
||||
// use template base url from initial template, to continue using webdav, if that was loaded via webdav
|
||||
var path = this.getRoot()._inst.template_base_url +
|
||||
splitted.join('.') + (cache_buster ? '&download='+cache_buster :
|
||||
var path = this.getRoot()._inst.template_base_url + splitted.shift() + "/templates/default/" +
|
||||
splitted.join('.')+ ".xet" + (cache_buster ? '?download='+cache_buster :
|
||||
// if server did not give a cache-buster, fall back to current time
|
||||
'&download='+(new Date).valueOf());
|
||||
'?download='+(new Date).valueOf());
|
||||
|
||||
if(splitted.length)
|
||||
{
|
||||
jQuery.ajax({
|
||||
url: path,
|
||||
context: this,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(_data, _status, _xmlhttp){
|
||||
for(var i = 0; i < _data.children.length; i++)
|
||||
{
|
||||
var template = _data.children[i];
|
||||
if(template.tag !== "template") continue;
|
||||
etemplate2.prototype.set_template_cache(template.attributes.id, template);
|
||||
}// Read the structure of the requested template
|
||||
if (template.id == template_name) this.loadFromJSON(template);
|
||||
|
||||
// Update flag
|
||||
this.loading.resolve();
|
||||
},
|
||||
error: function(_xmlhttp, _err) {
|
||||
egw().debug('error', 'Loading eTemplate from '+_url+' failed! '+_xmlhttp.status+' '+_xmlhttp.statusText);
|
||||
et2_loadXMLFromURL(path, function(_xmldoc) {
|
||||
// Scan for templates and store them
|
||||
for(var i = 0; i < _xmldoc.childNodes.length; i++) {
|
||||
var template = _xmldoc.childNodes[i];
|
||||
if(template.nodeName.toLowerCase() != "template") continue;
|
||||
templates[template.getAttribute("id")] = template;
|
||||
}
|
||||
});
|
||||
|
||||
// Read the XML structure of the requested template
|
||||
if (typeof templates[template_name] != 'undefined') this.loadFromXML(templates[template_name]);
|
||||
|
||||
// Update flag
|
||||
this.loading.resolve();
|
||||
|
||||
}, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(template !== null && typeof template !== "undefined")
|
||||
if(xml !== null && typeof xml !== "undefined")
|
||||
{
|
||||
this.egw().debug("log", "Loading template: ", template_name);
|
||||
if(template.tag)
|
||||
{
|
||||
this.loadFromJSON(template);
|
||||
}
|
||||
|
||||
this.egw().debug("log", "Loading template from XML: ", template_name);
|
||||
this.loadFromXML(xml);
|
||||
// Don't call this here - done by caller, or on whole widget tree
|
||||
//this.loadingFinished();
|
||||
|
||||
@ -151,7 +142,7 @@ var et2_template = et2_DOMWidget.extend(
|
||||
}
|
||||
else
|
||||
{
|
||||
this.egw().debug("warn", "Unable to find ", template_name);
|
||||
this.egw().debug("warn", "Unable to find XML for ", template_name);
|
||||
this.loading.reject();
|
||||
}
|
||||
}
|
||||
|
@ -100,67 +100,22 @@ function etemplate2(_container, _menuaction)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return template from global cache, or undefined if not cached
|
||||
*
|
||||
* @param {string} _name
|
||||
* @returns {object|undefined}
|
||||
*/
|
||||
etemplate2.prototype.get_template_cache = function(_name)
|
||||
// List of templates (XML) that are known, not always used. Indexed by id.
|
||||
// We share list of templates with iframes and popups
|
||||
try {
|
||||
if (opener && opener.etemplate2)
|
||||
{
|
||||
etemplate2.prototype.templates = opener.etemplate2.prototype.templates;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// catch security exception if opener is from a different domain
|
||||
}
|
||||
if (typeof etemplate2.prototype.templates == "undefined")
|
||||
{
|
||||
try {
|
||||
if (opener && opener.etemplate2)
|
||||
{
|
||||
return opener.etemplate2.prototype.get_template_cache(_name);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// catch security exception if opener is from a different domain
|
||||
}
|
||||
// use top window, if we are in an iframe
|
||||
if (top !== window)
|
||||
{
|
||||
return top.etemplate2.prototype.get_template_cache(_name);
|
||||
}
|
||||
// we are the top window
|
||||
if (typeof etemplate2.prototype.templates == "undefined")
|
||||
{
|
||||
etemplate2.prototype.templates = {};
|
||||
}
|
||||
return etemplate2.prototype.templates[_name];
|
||||
};
|
||||
etemplate2.prototype.templates = top.etemplate2.prototype.templates || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store template object in global cache
|
||||
*
|
||||
* @param {string} _name
|
||||
* @param {object} _template
|
||||
*/
|
||||
etemplate2.prototype.set_template_cache = function(_name, _template)
|
||||
{
|
||||
try {
|
||||
if (opener && opener.etemplate2)
|
||||
{
|
||||
return opener.etemplate2.prototype.set_template_cache(_name, _template);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// catch security exception if opener is from a different domain
|
||||
}
|
||||
// use top window, if we are in an iframe
|
||||
if (top !== window)
|
||||
{
|
||||
return top.etemplate2.prototype.set_template_cache(_name, _template);
|
||||
}
|
||||
// we are the top window
|
||||
if (typeof etemplate2.prototype.templates == "undefined")
|
||||
{
|
||||
etemplate2.prototype.templates = {};
|
||||
}
|
||||
// for IE we need to do a clone of template-object, as it might be from context of a different window
|
||||
// and will become unavailable if that window closes
|
||||
etemplate2.prototype.templates[_name] = jQuery.extend(true, {}, _template);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls the resize event of all widgets
|
||||
@ -247,8 +202,9 @@ etemplate2.prototype.clear = function()
|
||||
$j(this.DOMContainer).empty();
|
||||
|
||||
// Remove self from the index
|
||||
for(name in etemplate2._byTemplate)
|
||||
for(name in this.templates)
|
||||
{
|
||||
if(typeof etemplate2._byTemplate[name] == "undefined") continue;
|
||||
for(var i = 0; i < etemplate2._byTemplate[name].length; i++)
|
||||
{
|
||||
if(etemplate2._byTemplate[name][i] == this)
|
||||
@ -490,12 +446,8 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback)
|
||||
}
|
||||
etemplate2._byTemplate[_name].push(this);
|
||||
|
||||
// Read the structure of the requested template
|
||||
var template = this.get_template_cache(this.name);
|
||||
if (template && template.children)
|
||||
{
|
||||
this.widgetContainer.loadFromJSON(template);
|
||||
}
|
||||
// Read the XML structure of the requested template
|
||||
this.widgetContainer.loadFromXML(this.templates[this.name]);
|
||||
|
||||
// List of Promises from widgets that are not quite fully loaded
|
||||
var deferred = [];
|
||||
@ -589,28 +541,20 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback)
|
||||
|
||||
|
||||
// Load & process
|
||||
var template = this.get_template_cache(_name);
|
||||
if(!template)
|
||||
if(!this.templates[_name])
|
||||
{
|
||||
jQuery.ajax({
|
||||
url: _url,
|
||||
context: this,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(_data, _status, _xmlhttp){
|
||||
for(var i = 0; i < _data.children.length; i++)
|
||||
{
|
||||
var template = _data.children[i];
|
||||
if(template.tag !== "template") continue;
|
||||
this.set_template_cache(template.attributes.id, template);
|
||||
if(!_name) this.name = template.attributes.id;
|
||||
}
|
||||
_load.apply(this,[]);
|
||||
},
|
||||
error: function(_xmlhttp, _err) {
|
||||
egw().debug('error', 'Loading eTemplate from '+_url+' failed! '+_xmlhttp.status+' '+_xmlhttp.statusText);
|
||||
// Asynchronously load the XET file
|
||||
et2_loadXMLFromURL(_url, function(_xmldoc) {
|
||||
|
||||
// Scan for templates and store them
|
||||
for(var i = 0; i < _xmldoc.childNodes.length; i++) {
|
||||
var template = _xmldoc.childNodes[i];
|
||||
if(template.nodeName.toLowerCase() != "template") continue;
|
||||
this.templates[template.getAttribute("id")] = template;
|
||||
if(!_name) this.name = template.getAttribute("id");
|
||||
}
|
||||
});
|
||||
_load.apply(this,[]);
|
||||
}, this);
|
||||
|
||||
// Split the given data into array manager objects and pass those to the
|
||||
// widget container - do this here because file is loaded async
|
||||
|
@ -1,123 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Egroupware
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package etemplate
|
||||
* @subpackage api
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
const CACHE_TIME = 3600;
|
||||
|
||||
//Set all necessary info and fire up egroupware
|
||||
$GLOBALS['egw_info']['flags'] = array(
|
||||
'currentapp' => 'etemplate',
|
||||
'noheader' => true,
|
||||
'nonavbar' => true
|
||||
);
|
||||
include ('../header.inc.php');
|
||||
|
||||
if (!ajaxtoJSON($_GET['name']))
|
||||
{
|
||||
header('404 Not found');
|
||||
http_response_code(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the specified template XML file converted to JSON representation
|
||||
*
|
||||
* @param String $name
|
||||
* @return JSON
|
||||
*/
|
||||
function ajaxtoJSON($name)
|
||||
{
|
||||
if(!$name)
|
||||
{
|
||||
$name = get_var('name');
|
||||
}
|
||||
$filename = etemplate_widget_template::rel2path(etemplate_widget_template::relPath($name));
|
||||
// Bad template name
|
||||
if(trim($filename) == '')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$mtime = filemtime($filename);
|
||||
|
||||
// First, check cache
|
||||
$cached = egw_cache::getInstance('etemplate', $name);
|
||||
|
||||
// Not found, or modified
|
||||
if(!$cached || !is_array($cached) || is_array($cached) && $cached['mtime'] != $mtime)
|
||||
{
|
||||
// Load XML & parse into JSON
|
||||
$reader = simplexml_load_file($filename);
|
||||
$template = json_encode(nodeToArray($reader));
|
||||
$cached = array(
|
||||
'template' => $template,
|
||||
'mtime' => $mtime
|
||||
);
|
||||
}
|
||||
else if ($cached);
|
||||
{
|
||||
$template = $cached['template'];
|
||||
}
|
||||
if($cached)
|
||||
{
|
||||
// Keep in instance cache so we don't have to regenerate it
|
||||
egw_cache::setInstance('etemplate', $name, $cached, CACHE_TIME);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Should set some headers so the browser can cache it too
|
||||
header('Cache-Control: public, max-age='.CACHE_TIME);
|
||||
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+CACHE_TIME) . ' GMT');
|
||||
header('Content-type: application/json');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime));
|
||||
header('Content-Length: ' . mb_strlen($template));
|
||||
|
||||
echo $template;
|
||||
return true;
|
||||
}
|
||||
|
||||
function nodeToArray($xmlnode, &$jsnode = false)
|
||||
{
|
||||
if(!($xmlnode instanceof SimpleXMLElement) && trim($xmlnode))
|
||||
{
|
||||
$jsnode['content'] = $xmlnode;
|
||||
return;
|
||||
}
|
||||
$nodename = $xmlnode->getName();
|
||||
$node =& $jsnode ? $jsnode : array();
|
||||
$node['tag'] = strtolower($nodename);
|
||||
$node['attributes'] = array();
|
||||
|
||||
if (count($xmlnode->attributes()) > 0)
|
||||
{
|
||||
$node["attributes"] = array();
|
||||
foreach($xmlnode->attributes() as $key => $value)
|
||||
{
|
||||
$node["attributes"][$key] = (string)$value;
|
||||
}
|
||||
}
|
||||
|
||||
if(trim($xmlnode->__toString()) != '')
|
||||
{
|
||||
$node['content'] = $xmlnode->__toString();
|
||||
}
|
||||
|
||||
// Load children
|
||||
$child_index = 0;
|
||||
foreach ($xmlnode->children() as $childxmlnode)
|
||||
{
|
||||
$node['children'][$child_index] = array('tag' => $childxmlnode->getName());
|
||||
nodeToArray($childxmlnode, $node['children'][$child_index++]);
|
||||
}
|
||||
return $node;
|
||||
}
|
Loading…
Reference in New Issue
Block a user