forked from extern/egroupware
Moved 'getValues' function to etemplate2 class, added 'et2_surroundingsMgr' class, which is capable of managing DOM-Nodes which are inserted around an widget (see set_label function in et2_input and showMessage function in et2_baseWidget as an example of how to use it), added parsing server side validation errors
This commit is contained in:
parent
24e34f7927
commit
86414e7daa
@ -95,6 +95,7 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, {
|
||||
};
|
||||
|
||||
this._disabled = false;
|
||||
this._surroundingsMgr = null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -107,6 +108,12 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, {
|
||||
this.parentNode = null;
|
||||
this._attachSet = {};
|
||||
|
||||
if (this._surroundingsMgr)
|
||||
{
|
||||
this._surroundingsMgr.destroy();
|
||||
this._surroundingsMgr = null;
|
||||
}
|
||||
|
||||
this._super();
|
||||
},
|
||||
|
||||
@ -158,6 +165,13 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, {
|
||||
(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);
|
||||
}
|
||||
|
||||
this.parentNode.appendChild(node);
|
||||
|
||||
// Store the currently attached nodes
|
||||
@ -176,6 +190,15 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, {
|
||||
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. If another parent node is already
|
||||
* set, this widget removes itself from the DOM tree
|
||||
@ -283,4 +306,210 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 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(true);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -58,10 +58,7 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned, {
|
||||
|
||||
this.node = null;
|
||||
this.statustext = "";
|
||||
|
||||
this._labelContainer = null;
|
||||
this._widgetPlaceholder = null;
|
||||
|
||||
this._messageDiv = null;
|
||||
this._tooltipElem = null;
|
||||
},
|
||||
|
||||
@ -69,6 +66,113 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned, {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this.node = null;
|
||||
this._messageDiv = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* The setMessage function can be used to attach a small message box to the
|
||||
* widget. This is e.g. used to display validation errors or success messages
|
||||
*
|
||||
* @param _text is the text which should be displayed as a message
|
||||
* @param _type is an css class which is attached to the message box.
|
||||
* Currently available are "hint", "success" and "validation_error", defaults
|
||||
* to "hint"
|
||||
* @param _floating if true, the object will be in one row with the element,
|
||||
* defaults to true
|
||||
* @param _prepend if set, the message is displayed behind the widget node
|
||||
* instead of before. Defaults to false.
|
||||
*/
|
||||
showMessage: function(_text, _type, _floating, _prepend) {
|
||||
|
||||
// Preset the parameters
|
||||
if (typeof _type == "undefined")
|
||||
{
|
||||
_type = "hint"
|
||||
}
|
||||
|
||||
if (typeof _floating == "undefined")
|
||||
{
|
||||
_floating = true;
|
||||
}
|
||||
|
||||
if (typeof _prepend == "undefined")
|
||||
{
|
||||
_prepend = false;
|
||||
}
|
||||
|
||||
var surr = this.getSurroundings();
|
||||
|
||||
// Remove the message div from the surroundings before creating a new
|
||||
// one
|
||||
this.hideMessgae(false, true);
|
||||
|
||||
// Create the message div and add it to the "surroundings" manager
|
||||
this._messageDiv = $j(document.createElement("div"))
|
||||
.addClass("message")
|
||||
.addClass(_type)
|
||||
.addClass(_floating ? "floating" : "")
|
||||
.text(_text);
|
||||
|
||||
// Decide whether to prepend or append the div
|
||||
if (_prepend)
|
||||
{
|
||||
surr.prependDOMNode(this._messageDiv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
surr.appendDOMNode(this._messageDiv[0]);
|
||||
}
|
||||
|
||||
surr.update();
|
||||
},
|
||||
|
||||
/**
|
||||
* The hideMessgae function can be used to hide a previously shown message.
|
||||
*
|
||||
* @param _fade if true, the message div will fade out, otherwise the message
|
||||
* div is removed immediately. Defaults to true.
|
||||
* @param _noUpdate is used internally to prevent an update of the surroundings
|
||||
* manager.
|
||||
*/
|
||||
hideMessgae: function(_fade, _noUpdate) {
|
||||
if (typeof _fade == "undefined")
|
||||
{
|
||||
_fade = true;
|
||||
}
|
||||
|
||||
if (typeof _noUpdate == "undefined")
|
||||
{
|
||||
_noUpdate = false;
|
||||
}
|
||||
|
||||
// Remove the message from the surroundings manager and remove the
|
||||
// reference to it
|
||||
if (this._messageDiv != null)
|
||||
{
|
||||
var surr = this.getSurroundings();
|
||||
var self = this;
|
||||
|
||||
var _done = function() {
|
||||
surr.removeDOMNode(self._messageDiv[0]);
|
||||
self._messageDiv = null;
|
||||
|
||||
// Update the surroundings manager
|
||||
if (!_noUpdate)
|
||||
{
|
||||
surr.update();
|
||||
}
|
||||
}
|
||||
|
||||
// Either fade out or directly call the function which removes the div
|
||||
if (_fade)
|
||||
{
|
||||
this._messageDiv.fadeOut("fast", _done);
|
||||
}
|
||||
else
|
||||
{
|
||||
_done();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
detatchFromDOM: function() {
|
||||
@ -127,6 +231,15 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned, {
|
||||
return this.getDOMNode(this);
|
||||
},
|
||||
|
||||
click: function(_node) {
|
||||
if (this.onclick)
|
||||
{
|
||||
return this.onclick.call(_node);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
set_statustext: function(_value) {
|
||||
// Don't execute the code below, if no tooltip will be attached/detached
|
||||
if (_value == "" && !this._tooltipElem)
|
||||
@ -156,15 +269,6 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned, {
|
||||
}
|
||||
},
|
||||
|
||||
click: function(_node) {
|
||||
if (this.onclick)
|
||||
{
|
||||
return this.onclick.call(_node);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
set_align: function(_value) {
|
||||
this.align = _value;
|
||||
},
|
||||
|
@ -566,3 +566,29 @@ function et2_cloneObject(_obj)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given array of nodes or their children contains the given
|
||||
* child node.
|
||||
*/
|
||||
function et2_hasChild(_nodes, _child)
|
||||
{
|
||||
for (var i = 0; i < _nodes.length; i++)
|
||||
{
|
||||
if (_nodes[i] == _child)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_nodes[i].childNodes)
|
||||
{
|
||||
var res = et2_hasChild(_nodes[i].childNodes, _child);
|
||||
|
||||
if (res)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,12 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
"name": "onchange",
|
||||
"type": "js",
|
||||
"description": "JS code which is executed when the value changes."
|
||||
},
|
||||
"validation_error": {
|
||||
"name": "Validation Error",
|
||||
"type": "string",
|
||||
"default": et2_no_init,
|
||||
"description": "Used internally to store the validation error that came from the server."
|
||||
}
|
||||
},
|
||||
|
||||
@ -70,7 +76,6 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
|
||||
this._oldValue = "";
|
||||
this._labelContainer = null;
|
||||
this._widgetPlaceholder = null;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -83,34 +88,23 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this._labelContainer = null;
|
||||
this._widgetPlaceholder = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the validation errors from the server
|
||||
*/
|
||||
transformAttributes: function(_attrs) {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
// Check whether an validation error entry exists
|
||||
var val = this.getArrayMgr("validation_errors").getValueForID(this.id);
|
||||
if (val)
|
||||
{
|
||||
_attrs["validation_error"] = val;
|
||||
}
|
||||
},
|
||||
|
||||
attachToDOM: function() {
|
||||
if (this._labelContainer)
|
||||
{
|
||||
// Get the DOM Node without the labelContainer - that's why null is
|
||||
// passed here.
|
||||
var node = this.getDOMNode(null);
|
||||
|
||||
if (node)
|
||||
{
|
||||
// Recreate the widget placeholder and return, as the set_label
|
||||
// function will call attachToDOM again
|
||||
if (!this._widgetPlaceholder)
|
||||
{
|
||||
this.set_label(this.label);
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert the widget at the position of the placeholder
|
||||
this._labelContainer.replaceChild(node, this._widgetPlaceholder);
|
||||
|
||||
// Set the widgetPlaceholder to null
|
||||
this._widgetPlaceholder = null;
|
||||
}
|
||||
}
|
||||
|
||||
var node = this.getInputNode();
|
||||
if (node)
|
||||
{
|
||||
@ -121,14 +115,14 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
|
||||
this._super.apply(this,arguments);
|
||||
|
||||
$j(this.getInputNode()).attr("novalidate","novalidate"); // Stop browser from getting involved
|
||||
$j(this.getInputNode()).validator();
|
||||
// $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();
|
||||
}
|
||||
// if(this.getInputNode()) {
|
||||
// $j(this.getInputNode()).data("validator").destroy();
|
||||
// }
|
||||
this._super.apply(this,arguments);
|
||||
},
|
||||
|
||||
@ -171,14 +165,10 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
},
|
||||
|
||||
set_label: function(_value) {
|
||||
// Copy the given value
|
||||
this.label = _value;
|
||||
|
||||
// Detach the current element from the DOM
|
||||
var attached = this.isAttached();
|
||||
if (attached)
|
||||
// Abort if ther was no change in the label
|
||||
if (_value == this.label)
|
||||
{
|
||||
this.detatchFromDOM();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_value)
|
||||
@ -186,46 +176,49 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
// Create the label container if it didn't exist yet
|
||||
if (this._labelContainer == null)
|
||||
{
|
||||
this._labelContainer = document.createElement("label");
|
||||
this._labelContainer.setAttribute("class", "et2_label");
|
||||
this._labelContainer = $j(document.createElement("label"))
|
||||
.addClass("et2_label");
|
||||
this.getSurroundings().insertDOMNode(this._labelContainer[0]);
|
||||
}
|
||||
|
||||
// Clear the label container.
|
||||
for (;this._labelContainer.childNodes.length > 0;)
|
||||
{
|
||||
this._labelContainer.removeChild(this._labelContainer.childNodes[0]);
|
||||
}
|
||||
this._labelContainer.empty();
|
||||
|
||||
// Create the placeholder element
|
||||
this._widgetPlaceholder = document.createElement("span");
|
||||
// Create the placeholder element and set it
|
||||
var ph = document.createElement("span");
|
||||
this.getSurroundings().setWidgetPlaceholder(ph);
|
||||
|
||||
// Split the label at the "%s"
|
||||
var parts = et2_csvSplit(_value, 2, "%s");
|
||||
|
||||
// Create the content of the label container
|
||||
// Update the content of the label container
|
||||
for (var i = 0; i < parts.length; i++)
|
||||
{
|
||||
if (parts[i])
|
||||
{
|
||||
this._labelContainer.appendChild(document.createTextNode(parts[i]));
|
||||
this._labelContainer.append(document.createTextNode(parts[i]));
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
this._labelContainer.appendChild(this._widgetPlaceholder);
|
||||
this._labelContainer.append(ph);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delete the labelContainer from the surroundings object
|
||||
if (this._labelContainer)
|
||||
{
|
||||
this.getSurroundings().deleteDOMNode(this._labelContainer[0]);
|
||||
}
|
||||
this._labelContainer = null;
|
||||
this._widgetPlaceholder = null;
|
||||
}
|
||||
|
||||
// Attach the current element to the DOM again
|
||||
if (attached)
|
||||
{
|
||||
this.attachToDOM();
|
||||
}
|
||||
// Update the surroundings in order to reflect the change in the label
|
||||
this.getSurroundings().update();
|
||||
|
||||
// Copy the given value
|
||||
this.label = _value;
|
||||
},
|
||||
|
||||
set_required: function(_value) {
|
||||
@ -241,13 +234,21 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput, {
|
||||
|
||||
},
|
||||
|
||||
getDOMNode: function(_sender) {
|
||||
if (_sender == this && this._labelContainer)
|
||||
set_validation_error: function(_value) {
|
||||
var node = this.getInputNode();
|
||||
if (node)
|
||||
{
|
||||
return this._labelContainer;
|
||||
if (_value === false)
|
||||
{
|
||||
this.hideMessage();
|
||||
$j(node).removeClass("invalid");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.showMessage(_value, "validation_error");
|
||||
$j(node).addClass("invalid");
|
||||
}
|
||||
}
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
getInputNode: function() {
|
||||
|
@ -585,77 +585,6 @@ var et2_widget = Class.extend({
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetches all input element values and returns them in an associative
|
||||
* array. Widgets which introduce namespacing can use the internal _target
|
||||
* parameter to add another layer.
|
||||
*/
|
||||
getValues: function() {
|
||||
var result = {};
|
||||
|
||||
// Iterate over the widget tree
|
||||
this.iterateOver(function(_widget) {
|
||||
|
||||
// The widget must have an id to be included in the values array
|
||||
if (_widget.id == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the path to the node we have to store the value at
|
||||
var path = _widget.getArrayMgr("content").getPath();
|
||||
|
||||
// check if id contains a hierachical name, eg. "button[save]"
|
||||
var id = _widget.id;
|
||||
if (_widget.id.indexOf('[') != -1)
|
||||
{
|
||||
var parts = _widget.id.replace(/]/g,'').split('[');
|
||||
id = parts.pop();
|
||||
path = path.concat(parts);
|
||||
}
|
||||
|
||||
// Set the _target variable to that node
|
||||
var _target = result;
|
||||
for (var i = 0; i < path.length; i++)
|
||||
{
|
||||
// Create a new object for not-existing path nodes
|
||||
if (typeof _target[path[i]] == "undefined")
|
||||
{
|
||||
_target[path[i]] = {};
|
||||
}
|
||||
|
||||
// Check whether the path node is really an object
|
||||
if (_target[path[i]] instanceof Object)
|
||||
{
|
||||
_target = _target[path[i]];
|
||||
}
|
||||
else
|
||||
{
|
||||
et2_debug("error", "ID collision while writing at path " +
|
||||
"node '" + path[i] + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the entry is really undefined
|
||||
if (typeof _target[id] != "undefined")
|
||||
{
|
||||
et2_debug("error", _widget, "Overwriting value of '" + _widget.id +
|
||||
"', id exists twice!");
|
||||
}
|
||||
|
||||
// Store the value of the widget and reset its dirty flag
|
||||
var value = _widget.getValue();
|
||||
if (value !== null)
|
||||
{
|
||||
_target[id] = value;
|
||||
}
|
||||
_widget.resetDirty();
|
||||
|
||||
}, this, et2_IInput);
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets all array manager objects - this function can be used to set the
|
||||
* root array managers of the container object.
|
||||
|
@ -166,7 +166,7 @@ etemplate2.prototype.submit = function()
|
||||
if(!valid) return false;*/
|
||||
|
||||
// Get the form values
|
||||
var values = this.widgetContainer.getValues();
|
||||
var values = this.getValues(this.widgetContainer);
|
||||
|
||||
// Trigger the submit event
|
||||
if (this.fireEvent("submit", [values]))
|
||||
@ -184,6 +184,78 @@ etemplate2.prototype.submit = function()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all input element values and returns them in an associative
|
||||
* array. Widgets which introduce namespacing can use the internal _target
|
||||
* parameter to add another layer.
|
||||
*/
|
||||
etemplate2.prototype.getValues = function(_root)
|
||||
{
|
||||
var result = {};
|
||||
|
||||
// Iterate over the widget tree
|
||||
_root.iterateOver(function(_widget) {
|
||||
|
||||
// The widget must have an id to be included in the values array
|
||||
if (_widget.id == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the path to the node we have to store the value at
|
||||
var path = _widget.getArrayMgr("content").getPath();
|
||||
|
||||
// check if id contains a hierachical name, eg. "button[save]"
|
||||
var id = _widget.id;
|
||||
if (_widget.id.indexOf('[') != -1)
|
||||
{
|
||||
var parts = _widget.id.replace(/]/g,'').split('[');
|
||||
id = parts.pop();
|
||||
path = path.concat(parts);
|
||||
}
|
||||
|
||||
// Set the _target variable to that node
|
||||
var _target = result;
|
||||
for (var i = 0; i < path.length; i++)
|
||||
{
|
||||
// Create a new object for not-existing path nodes
|
||||
if (typeof _target[path[i]] == "undefined")
|
||||
{
|
||||
_target[path[i]] = {};
|
||||
}
|
||||
|
||||
// Check whether the path node is really an object
|
||||
if (_target[path[i]] instanceof Object)
|
||||
{
|
||||
_target = _target[path[i]];
|
||||
}
|
||||
else
|
||||
{
|
||||
et2_debug("error", "ID collision while writing at path " +
|
||||
"node '" + path[i] + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the entry is really undefined
|
||||
if (typeof _target[id] != "undefined")
|
||||
{
|
||||
et2_debug("error", _widget, "Overwriting value of '" + _widget.id +
|
||||
"', id exists twice!");
|
||||
}
|
||||
|
||||
// Store the value of the widget and reset its dirty flag
|
||||
var value = _widget.getValue();
|
||||
if (value !== null)
|
||||
{
|
||||
_target[id] = value;
|
||||
}
|
||||
_widget.resetDirty();
|
||||
|
||||
}, this, et2_IInput);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an callback function to the given event slot
|
||||
*
|
||||
|
@ -74,6 +74,9 @@ var timesheet_data = {
|
||||
"tabs":{
|
||||
"customfields":true
|
||||
}
|
||||
}
|
||||
},
|
||||
"validation_errors": {
|
||||
"ts_title": "Please enter some meaningful title here!"
|
||||
}
|
||||
}
|
||||
|
||||
|
BIN
etemplate/js/test/gfx/error.png
Normal file
BIN
etemplate/js/test/gfx/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 701 B |
BIN
etemplate/js/test/gfx/hint.png
Normal file
BIN
etemplate/js/test/gfx/hint.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 778 B |
BIN
etemplate/js/test/gfx/tick.png
Normal file
BIN
etemplate/js/test/gfx/tick.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 537 B |
@ -219,8 +219,8 @@ input[required] {
|
||||
background-color: #ffffd0;
|
||||
}
|
||||
input.invalid {
|
||||
border-style: dotted;
|
||||
border-color: red;
|
||||
border: 1px solid #a6261d;
|
||||
background-color: #faecec;
|
||||
}
|
||||
.error {
|
||||
-moz-border-radius: 0 4px 4px 0;
|
||||
@ -268,3 +268,52 @@ label input, label span, label div, label select, label textarea {
|
||||
margin-right: 1ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message styles
|
||||
*/
|
||||
|
||||
/* Style used for a generic message (such as success messages or validation errors) */
|
||||
.message {
|
||||
display: block;
|
||||
border: 1px solid gray;
|
||||
padding: 3px 3px 3px 22px;
|
||||
margin: 5px 0px 5px 0px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 3px center;
|
||||
clear: left;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.message.floating {
|
||||
display: inline;
|
||||
margin: 0px 5px 0px 5px;
|
||||
}
|
||||
|
||||
.message.validation_error {
|
||||
color: #a93030;
|
||||
font-style: italic;
|
||||
background-color: #f3d4d0;
|
||||
border-color: #a93030;
|
||||
background-image:url(gfx/error.png);
|
||||
}
|
||||
|
||||
.message.success {
|
||||
font-style: normal;
|
||||
background-color: #e5f3d0;
|
||||
color: #98a930;
|
||||
border-color: #9ea930;
|
||||
background-image:url(gfx/tick.png);
|
||||
}
|
||||
|
||||
.message.hint {
|
||||
font-style: normal;
|
||||
background-color: #d9e2ed;
|
||||
border-color: #56729a;
|
||||
color: #56729a;
|
||||
background-image:url(gfx/hint.png);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user