2011-02-23 19:24:16 +01:00
|
|
|
/**
|
|
|
|
* eGroupWare egw_action framework - egw action framework
|
|
|
|
*
|
|
|
|
* @link http://www.egroupware.org
|
|
|
|
* @author Andreas Stöckel <as@stylite.de>
|
|
|
|
* @copyright 2011 by Andreas Stöckel
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package egw_action
|
2011-02-23 21:18:56 +01:00
|
|
|
* @version $Id$
|
2011-02-23 19:24:16 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** egwActionHandler Interface **/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor for the egwActionHandler interface which (at least) should have the
|
|
|
|
* execute function implemented.
|
|
|
|
*/
|
|
|
|
function egwActionHandler(_executeEvent)
|
|
|
|
{
|
|
|
|
//Copy the executeEvent parameter
|
|
|
|
this.execute = _executeEvent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** egwAction Object **/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Associative array where action classes may register themselves
|
|
|
|
*/
|
2011-02-26 19:04:28 +01:00
|
|
|
if (typeof window._egwActionClasses == "undefined")
|
|
|
|
window._egwActionClasses = {}
|
2011-02-23 19:24:16 +01:00
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
_egwActionClasses["default"] = {
|
|
|
|
"actionConstructor": egwAction,
|
|
|
|
"implementation": null
|
|
|
|
};
|
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
function egwAction(_parent, _id, _caption, _iconUrl, _onExecute, _allowOnMultiple)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
|
|
|
//Default and check the values
|
2011-03-23 15:05:39 +01:00
|
|
|
if (_parent && (typeof _id != "string" || !_id))
|
2011-02-23 19:24:16 +01:00
|
|
|
throw "egwAction _id must be a non-empty string!";
|
2011-03-09 23:16:41 +01:00
|
|
|
if (typeof _caption == "undefined")
|
|
|
|
_caption = "";
|
2011-02-26 19:04:28 +01:00
|
|
|
if (typeof _iconUrl == "undefined")
|
|
|
|
_iconUrl = "";
|
2011-02-23 19:24:16 +01:00
|
|
|
if (typeof _onExecute == "undefined")
|
|
|
|
_onExecute = null;
|
|
|
|
if (typeof _allowOnMultiple == "undefined")
|
|
|
|
_allowOnMultiple = true;
|
|
|
|
|
|
|
|
this.id = _id;
|
|
|
|
this.caption = _caption;
|
2011-02-26 19:04:28 +01:00
|
|
|
this.iconUrl = _iconUrl;
|
2011-02-23 19:24:16 +01:00
|
|
|
this.allowOnMultiple = _allowOnMultiple;
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
this.enabled = new egwFnct(this, true);
|
2011-03-23 21:08:33 +01:00
|
|
|
this.hideOnDisabled = false;
|
|
|
|
this.data = null; // Data which can be freely assigned to the action
|
2011-03-23 15:05:39 +01:00
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
this.type = "default"; //All derived classes have to override this!
|
2011-03-23 15:05:39 +01:00
|
|
|
this.canHaveChildren = false; //Has to be overwritten by inherited action classes
|
|
|
|
this.parent = _parent;
|
|
|
|
this.children = [];
|
2011-02-23 19:24:16 +01:00
|
|
|
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
this.onExecute = new egwFnct(this, null, []);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
/**
|
|
|
|
* Searches for a specific action with the given id
|
|
|
|
*/
|
|
|
|
egwAction.prototype.getActionById = function(_id)
|
|
|
|
{
|
|
|
|
// If the current action object has the given id, return this object
|
|
|
|
if (this.id == _id)
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this element is capable of having children, search those for the given
|
|
|
|
// action id
|
|
|
|
if (this.canHaveChildren)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
var elem = this.children[i].getActionById(_id);
|
|
|
|
if (elem)
|
|
|
|
{
|
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-04-27 09:49:46 +02:00
|
|
|
/**
|
|
|
|
* Searches for actions having an attribute with a certain value
|
|
|
|
*
|
|
|
|
* Example: actionManager.getActionsByAttr("checkbox", true) returns all checkbox actions
|
|
|
|
*
|
|
|
|
* @param string _attr attribute name
|
|
|
|
* @param mixed _val attribute value
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
egwAction.prototype.getActionsByAttr = function(_attr, _val)
|
|
|
|
{
|
|
|
|
var _actions = [];
|
|
|
|
|
|
|
|
// If the current action object has the given attr AND value, return it
|
|
|
|
if (typeof this[_attr] != "undefined" && this[_attr] === _val)
|
|
|
|
{
|
|
|
|
_actions.push(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this element is capable of having children, search those too
|
|
|
|
if (this.canHaveChildren)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
_actions = _actions.concat(this.children[i].getActionsByAttr(_attr, _val));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return _actions;
|
|
|
|
}
|
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
/**
|
|
|
|
* Adds a new action to the child elements.
|
|
|
|
*/
|
|
|
|
egwAction.prototype.addAction = function(_type, _id, _caption, _iconUrl,
|
|
|
|
_onExecute, _allowOnMultiple)
|
|
|
|
{
|
|
|
|
//Get the constructor for the given action type
|
|
|
|
if (!_type)
|
|
|
|
{
|
2011-04-17 21:10:46 +02:00
|
|
|
_type = "popup";
|
2011-03-23 15:05:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only allow adding new actions, if this action class allows it.
|
|
|
|
if (this.canHaveChildren)
|
|
|
|
{
|
|
|
|
var constructor = _egwActionClasses[_type].actionConstructor;
|
|
|
|
|
|
|
|
if (typeof constructor == "function")
|
|
|
|
{
|
|
|
|
var action = new constructor(this, _id, _caption, _iconUrl, _onExecute,
|
|
|
|
_allowOnMultiple);
|
|
|
|
this.children.push(action);
|
|
|
|
|
|
|
|
return action;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw "Given action type not registered.";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw "This action does not allow child elements!"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the children of this element
|
|
|
|
*/
|
|
|
|
egwAction.prototype.updateActions = function(_actions)
|
|
|
|
{
|
|
|
|
if (this.canHaveChildren)
|
|
|
|
{
|
|
|
|
for (var i = 0 ; i < _actions.length; i++)
|
|
|
|
{
|
|
|
|
//Check whether the given action is already part of this action manager instance
|
|
|
|
var elem = _actions[i];
|
|
|
|
if (typeof elem == "object" && typeof elem.id == "string" && elem.id)
|
|
|
|
{
|
|
|
|
//Check whether the action already exists, and if no, add it to the
|
|
|
|
//actions list
|
|
|
|
var action = this.getActionById(elem.id);
|
|
|
|
if (!action)
|
|
|
|
{
|
|
|
|
if (typeof elem.type == "undefined")
|
2011-04-17 21:10:46 +02:00
|
|
|
elem.type = "popup";
|
2011-03-23 15:05:39 +01:00
|
|
|
|
|
|
|
var constructor = null;
|
|
|
|
|
|
|
|
// Check whether the given type is inside the "canHaveChildren"
|
|
|
|
// array
|
|
|
|
if (this.canHaveChildren !== true && this.canHaveChildren.indexOf(elem.type) == -1)
|
|
|
|
{
|
|
|
|
throw "This child type '" + elem.type + "' is not allowed!"
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof _egwActionClasses[elem.type] != "undefined")
|
|
|
|
constructor = _egwActionClasses[elem.type].actionConstructor;
|
|
|
|
|
|
|
|
if (typeof constructor == "function" && constructor)
|
|
|
|
action = new constructor(this, elem.id);
|
|
|
|
else
|
|
|
|
throw "Given action type \"" + elem.type + "\" not registered.";
|
|
|
|
|
|
|
|
this.children.push(action);
|
|
|
|
}
|
|
|
|
|
|
|
|
action.updateAction(elem);
|
|
|
|
|
|
|
|
// Add sub-actions to the action
|
|
|
|
if (elem.children)
|
|
|
|
{
|
|
|
|
action.updateActions(elem.children);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-24 18:06:44 +01:00
|
|
|
console.log(this);
|
2011-03-23 15:05:39 +01:00
|
|
|
throw "This action element cannot have children!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
/**
|
|
|
|
* Applys the same onExecute handler to all actions which don't have an execute
|
|
|
|
* handler set.
|
|
|
|
*/
|
|
|
|
egwAction.prototype.setDefaultExecute = function(_value)
|
|
|
|
{
|
|
|
|
// Check whether the onExecute handler of this action should be set
|
|
|
|
if (this.type != "actionManager" && !this.onExecute.hasHandler())
|
|
|
|
{
|
|
|
|
this.onExecute.setValue(_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply the value to all children
|
|
|
|
if (this.canHaveChildren)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
this.children[i].setDefaultExecute(_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
/**
|
|
|
|
* Executes this action by using the method specified in the onExecute setter.
|
|
|
|
*
|
2011-03-24 18:06:44 +01:00
|
|
|
* @param array _senders array with references to the objects which caused the action
|
|
|
|
* @param object _target is an optional parameter which may represent e.g. an drag drop target
|
2011-02-23 19:24:16 +01:00
|
|
|
*/
|
2011-03-24 18:06:44 +01:00
|
|
|
egwAction.prototype.execute = function(_senders, _target)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-03-24 18:06:44 +01:00
|
|
|
if (typeof _target == "undefined")
|
|
|
|
{
|
|
|
|
_target == null;
|
|
|
|
}
|
|
|
|
|
2011-04-17 19:42:04 +02:00
|
|
|
return this.onExecute.exec(this, _senders, _target);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The set_onExecute function is the setter function for the onExecute event of
|
|
|
|
* the egwAction object. There are three possible types the passed "_value" may
|
|
|
|
* take:
|
|
|
|
* 1. _value may be a string with the word "javaScript:" prefixed. The function
|
|
|
|
* which is specified behind the colon and which has to be in the global scope
|
|
|
|
* will be executed.
|
|
|
|
* 2. _value may be a boolean, which specifies whether the external onExecute handler
|
|
|
|
* (passed as "_handler" in the constructor) will be used.
|
|
|
|
* 3. _value may be a JS functino which will then be called.
|
|
|
|
* In all possible situation, the called function will get the following parameters:
|
|
|
|
* 1. A reference to this action
|
|
|
|
* 2. The senders, an array of all objects (JS)/object ids (PHP) which evoked the event
|
|
|
|
*/
|
2011-02-24 20:00:47 +01:00
|
|
|
egwAction.prototype.set_onExecute = function(_value)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
this.onExecute.setValue(_value);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
egwAction.prototype.set_caption = function(_value)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
|
|
|
this.caption = _value;
|
|
|
|
}
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
egwAction.prototype.set_iconUrl = function(_value)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
this.iconUrl = _value;
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
2011-03-21 17:12:28 +01:00
|
|
|
egwAction.prototype.set_enabled = function(_value)
|
|
|
|
{
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
this.enabled.setValue(_value);
|
2011-03-21 17:12:28 +01:00
|
|
|
}
|
|
|
|
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
/**
|
|
|
|
* The allowOnMultiple property may be true, false or "only"
|
|
|
|
*/
|
2011-02-24 20:00:47 +01:00
|
|
|
egwAction.prototype.set_allowOnMultiple = function(_value)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
|
|
|
this.allowOnMultiple = _value;
|
|
|
|
}
|
|
|
|
|
2011-03-23 21:08:33 +01:00
|
|
|
egwAction.prototype.set_hideOnDisabled = function(_value)
|
|
|
|
{
|
|
|
|
this.hideOnDisabled = _value;
|
|
|
|
}
|
|
|
|
|
|
|
|
egwAction.prototype.set_data = function(_value)
|
|
|
|
{
|
|
|
|
this.data = _value;
|
|
|
|
}
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
egwAction.prototype.updateAction = function(_data)
|
|
|
|
{
|
|
|
|
egwActionStoreJSON(_data, this, true);
|
|
|
|
}
|
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
function _egwActionTreeContains(_tree, _elem)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < _tree.length; i++)
|
|
|
|
{
|
|
|
|
if (_tree[i].action == _elem)
|
|
|
|
{
|
|
|
|
return _tree[i];
|
|
|
|
}
|
2011-02-23 19:24:16 +01:00
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
if (typeof _tree[i].children != "undefined")
|
|
|
|
{
|
|
|
|
var elem = _egwActionTreeContains(_tree[i].children, _elem);
|
|
|
|
if (elem)
|
|
|
|
{
|
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
2011-02-23 19:24:16 +01:00
|
|
|
|
|
|
|
/**
|
2011-03-23 15:05:39 +01:00
|
|
|
* The appendToGraph function generates an action tree which automatically contains
|
|
|
|
* all parent elements. If the appendToGraph function is called for a
|
|
|
|
*
|
|
|
|
* @param array _tree contains the tree structure - pass an object containing
|
|
|
|
* the empty array "root" to this function {"root": []}. The result will be stored in
|
|
|
|
* this array.
|
|
|
|
* @param boolean _addChildren is used internally to prevent parent elements from
|
|
|
|
* adding their children automatically to the tree.
|
2011-02-23 19:24:16 +01:00
|
|
|
*/
|
2011-03-23 15:05:39 +01:00
|
|
|
egwAction.prototype.appendToTree = function(_tree, _addChildren)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-03-23 15:05:39 +01:00
|
|
|
if (typeof _addChildren == "undefined")
|
|
|
|
{
|
|
|
|
_addChildren = true;
|
|
|
|
}
|
2011-02-23 19:24:16 +01:00
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
if (typeof _addParent == "undefined")
|
|
|
|
{
|
|
|
|
_addParent = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Preset some variables
|
|
|
|
var root = _tree.root;
|
|
|
|
var parent_cntr = null;
|
|
|
|
var cntr = {
|
|
|
|
"action": this,
|
|
|
|
"children": []
|
|
|
|
};
|
2011-02-23 19:24:16 +01:00
|
|
|
|
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
if (this.parent)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-03-23 15:05:39 +01:00
|
|
|
// Check whether the parent container has already been added to the tree
|
|
|
|
parent_cntr = _egwActionTreeContains(root, this.parent);
|
2011-02-23 19:24:16 +01:00
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
if (!parent_cntr)
|
|
|
|
{
|
|
|
|
parent_cntr = this.parent.appendToTree(_tree, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether this element has already been added to the parent container
|
|
|
|
var added = false;
|
|
|
|
for (var i = 0; i < parent_cntr.children.length; i++)
|
|
|
|
{
|
|
|
|
if (parent_cntr.children[i].action == this)
|
|
|
|
{
|
|
|
|
cntr = parent_cntr.children[i];
|
|
|
|
added = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!added)
|
|
|
|
{
|
|
|
|
parent_cntr.children.push(cntr);
|
|
|
|
}
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-23 15:05:39 +01:00
|
|
|
var added = false;
|
|
|
|
for (var i = 0; i < root.length; i++)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-03-23 15:05:39 +01:00
|
|
|
if (root[i].action == this)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-03-23 15:05:39 +01:00
|
|
|
cntr = root[i];
|
|
|
|
added = true;
|
|
|
|
break;
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
2011-03-23 15:05:39 +01:00
|
|
|
}
|
2011-02-23 19:24:16 +01:00
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
if (!added)
|
|
|
|
{
|
|
|
|
// Add this element to the root if it has no parent
|
|
|
|
root.push(cntr);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
}
|
2011-03-23 15:05:39 +01:00
|
|
|
|
|
|
|
if (_addChildren)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
this.children[i].appendToTree(_tree, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cntr;
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
|
|
|
|
/** egwActionManager Object **/
|
|
|
|
|
2011-03-21 17:12:28 +01:00
|
|
|
/**
|
2011-03-23 15:05:39 +01:00
|
|
|
* egwActionManager manages a list of actions - it overwrites the egwAction class
|
|
|
|
* and allows child actions to be added to it.
|
2011-03-21 17:12:28 +01:00
|
|
|
*/
|
2011-03-23 15:05:39 +01:00
|
|
|
function egwActionManager()
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-03-23 15:05:39 +01:00
|
|
|
var action = new egwAction(null, false);
|
2011-02-23 19:24:16 +01:00
|
|
|
|
2011-03-23 15:05:39 +01:00
|
|
|
action.type = "actionManager";
|
|
|
|
action.canHaveChildren = true;
|
|
|
|
|
|
|
|
return action;
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** egwActionImplementation Interface **/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Abstract interface for the egwActionImplementation object. The egwActionImplementation
|
|
|
|
* object is responsible for inserting the actual action representation (context menu,
|
|
|
|
* drag-drop code) into the DOM Tree by using the egwActionObjectInterface object
|
|
|
|
* supplied by the object.
|
|
|
|
* To write a "class" which derives from this object, simply write a own constructor,
|
|
|
|
* which replaces "this" with a "new egwActionImplementation" and implement your
|
|
|
|
* code in "doRegisterAction" und "doUnregisterAction".
|
|
|
|
* Register your own implementation within the _egwActionClasses object.
|
|
|
|
*/
|
2011-02-26 19:04:28 +01:00
|
|
|
function egwActionImplementation()
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
this.doRegisterAction = function() {throw "Abstract function call: registerAction"};
|
|
|
|
this.doUnregisterAction = function() {throw "Abstract function call: unregisterAction"};
|
|
|
|
this.doExecuteImplementation = function() {throw "Abstract function call: executeImplementation"};
|
|
|
|
this.type = "";
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Injects the implementation code into the DOM tree by using the supplied
|
|
|
|
* actionObjectInterface.
|
|
|
|
*
|
2011-02-26 19:04:28 +01:00
|
|
|
* @param object _actionObjectInterface is the AOI in which the implementation
|
|
|
|
* should be registered.
|
|
|
|
* @param function _triggerCallback is the callback function which will be triggered
|
|
|
|
* when the user triggeres this action implementatino (e.g. starts a drag-drop or
|
|
|
|
* right-clicks on an object.)
|
|
|
|
* @param object context in which the triggerCallback should get executed.
|
2011-02-23 19:24:16 +01:00
|
|
|
* @returns true if the Action had been successfully registered, false if it
|
|
|
|
* had not.
|
|
|
|
*/
|
2011-02-26 19:04:28 +01:00
|
|
|
egwActionImplementation.prototype.registerAction = function(_actionObjectInterface, _triggerCallback, _context)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
if (typeof _context == "undefined")
|
|
|
|
_context = null;
|
|
|
|
|
|
|
|
return this.doRegisterAction(_actionObjectInterface, _triggerCallback, _context);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregister action will be called before an actionObjectInterface is destroyed,
|
|
|
|
* which gives the egwActionImplementation the opportunity to remove the previously
|
|
|
|
* injected code.
|
|
|
|
*
|
|
|
|
* @returns true if the Action had been successfully unregistered, false if it
|
|
|
|
* had not.
|
|
|
|
*/
|
2011-02-26 19:04:28 +01:00
|
|
|
egwActionImplementation.prototype.unregisterAction = function(_actionObjectInterface)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
return this.doUnregisterAction(_actionObjectInterface);
|
|
|
|
}
|
|
|
|
|
|
|
|
egwActionImplementation.prototype.executeImplementation = function(_context, _selected, _links)
|
|
|
|
{
|
|
|
|
return this.doExecuteImplementation(_context, _selected, _links);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** egwActionLink Object **/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The egwActionLink is used to interconnect egwActionObjects and egwActions.
|
|
|
|
* This gives each action object the possibility to decide, whether the action
|
|
|
|
* should be active in this context or not.
|
|
|
|
*
|
|
|
|
* @param _manager is a reference to the egwActionManager whic contains the action
|
|
|
|
* the object wants to link to.
|
|
|
|
*/
|
|
|
|
function egwActionLink(_manager)
|
|
|
|
{
|
|
|
|
this.enabled = true;
|
2011-02-26 19:04:28 +01:00
|
|
|
this.visible = true;
|
2011-02-23 19:24:16 +01:00
|
|
|
this.actionId = "";
|
|
|
|
this.actionObj = null;
|
|
|
|
this.manager = _manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
egwActionLink.prototype.updateLink = function (_data)
|
|
|
|
{
|
|
|
|
egwActionStoreJSON(_data, this, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
egwActionLink.prototype.set_enabled = function(_value)
|
|
|
|
{
|
|
|
|
this.enabled = _value;
|
|
|
|
}
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
egwActionLink.prototype.set_visible = function(_value)
|
|
|
|
{
|
|
|
|
this.visible = _value;
|
|
|
|
}
|
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
egwActionLink.prototype.set_actionId = function(_value)
|
|
|
|
{
|
|
|
|
this.actionId = _value;
|
2011-03-21 17:12:28 +01:00
|
|
|
this.actionObj = this.manager.getActionById(_value);
|
2011-02-23 19:24:16 +01:00
|
|
|
|
|
|
|
if (!this.actionObj)
|
|
|
|
throw "Given action object does not exist!"
|
|
|
|
}
|
|
|
|
|
|
|
|
/** egwActionObject Object **/
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
//State bitmask (only use powers of two for new states!)
|
2011-02-26 19:04:28 +01:00
|
|
|
var EGW_AO_STATE_NORMAL = 0x00;
|
|
|
|
var EGW_AO_STATE_SELECTED = 0x01;
|
|
|
|
var EGW_AO_STATE_FOCUSED = 0x02;
|
2011-03-02 22:18:20 +01:00
|
|
|
var EGW_AO_STATE_VISIBLE = 0x04; //< Can only be set by the AOI, means that the object is attached to the DOM-Tree and visible
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
var EGW_AO_EVENT_DRAG_OVER_ENTER = 0x00;
|
|
|
|
var EGW_AO_EVENT_DRAG_OVER_LEAVE = 0x01;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
// No shift key is pressed
|
2011-02-26 19:04:28 +01:00
|
|
|
var EGW_AO_SHIFT_STATE_NONE = 0x00;
|
2011-02-24 20:00:47 +01:00
|
|
|
// A shift key, which allows multiselection is pressed (usually CTRL on a PC keyboard)
|
2011-02-26 19:04:28 +01:00
|
|
|
var EGW_AO_SHIFT_STATE_MULTI = 0x01;
|
2011-02-24 20:00:47 +01:00
|
|
|
// A shift key is pressed, which forces blockwise selection (SHIFT on a PC keyboard)
|
2011-02-26 19:04:28 +01:00
|
|
|
var EGW_AO_SHIFT_STATE_BLOCK = 0x02;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
|
|
|
// If this flag is set, this object will not be returned as "focused". If this
|
|
|
|
// flag is not applied to container objects, it may lead to some strange behaviour.
|
2011-02-26 19:04:28 +01:00
|
|
|
var EGW_AO_FLAG_IS_CONTAINER = 0x01;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
/**
|
|
|
|
* The egwActionObject represents an abstract object to which actions may be
|
|
|
|
* applied. Communication with the DOM tree is established by using the
|
|
|
|
* egwActionObjectInterface (AOI), which is passed in the constructor.
|
|
|
|
* egwActionObjects are organized in a tree structure.
|
|
|
|
*
|
|
|
|
* @param string _id is the identifier of the object which
|
|
|
|
* @param object _parent is the parent object in the hirachy. This may be set to NULL
|
2011-02-24 20:00:47 +01:00
|
|
|
* @param object _iface is the egwActionObjectInterface which connects the object
|
|
|
|
* to the outer world.
|
2011-02-23 19:24:16 +01:00
|
|
|
* @param object _manager is the action manager this object is connected to
|
2011-02-24 20:00:47 +01:00
|
|
|
* this object to the DOM tree. If the _manager isn't supplied, the parent manager
|
|
|
|
* is taken.
|
|
|
|
* @param int _flags a set of additional flags being applied to the object,
|
|
|
|
* defaults to 0
|
2011-02-23 19:24:16 +01:00
|
|
|
*/
|
2011-02-24 20:00:47 +01:00
|
|
|
function egwActionObject(_id, _parent, _iface, _manager, _flags)
|
2011-02-23 19:24:16 +01:00
|
|
|
{
|
2011-02-24 20:00:47 +01:00
|
|
|
//Preset some parameters
|
|
|
|
if (typeof _manager == "undefined" && typeof _parent == "object" && _parent)
|
|
|
|
_manager = _parent.manager;
|
|
|
|
if (typeof _flags == "undefined")
|
|
|
|
_flags = 0;
|
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
this.id = _id;
|
|
|
|
this.parent = _parent;
|
|
|
|
this.children = [];
|
|
|
|
this.actionLinks = [];
|
|
|
|
this.manager = _manager;
|
2011-02-24 20:00:47 +01:00
|
|
|
this.flags = _flags;
|
2011-03-14 21:11:08 +01:00
|
|
|
this.data = null;
|
2011-03-30 16:28:49 +02:00
|
|
|
this.setSelectedCallback = null;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
this.registeredImpls = [];
|
|
|
|
|
|
|
|
// Two variables which help fast travelling through the object tree, when
|
|
|
|
// searching for the selected/focused object.
|
|
|
|
this.selectedChildren = [];
|
|
|
|
this.focusedChild = null;
|
|
|
|
|
2011-03-09 23:16:41 +01:00
|
|
|
this.setAOI(_iface);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
2011-03-09 23:16:41 +01:00
|
|
|
/**
|
|
|
|
* Sets the action object interface - if "NULL" is given, the iface is set
|
|
|
|
* to a dummy interface which is used to store the temporary data.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.setAOI = function(_aoi)
|
|
|
|
{
|
|
|
|
if (_aoi == null)
|
|
|
|
{
|
|
|
|
_aoi = new egwActionObjectDummyInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the state from the old interface
|
|
|
|
if (this.iface)
|
|
|
|
{
|
|
|
|
_aoi.setState(this.iface.getState());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace the interface object
|
|
|
|
this.iface = _aoi;
|
2011-03-10 21:58:35 +01:00
|
|
|
this.iface.setStateChangeCallback(this._ifaceCallback, this);
|
|
|
|
this.iface.setReconnectActionsCallback(this._reconnectCallback, this);
|
2011-03-09 23:16:41 +01:00
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
|
|
|
* Returns the object from the tree with the given ID
|
|
|
|
*/
|
|
|
|
//TODO: Add search function to egw_action_commons.js
|
|
|
|
egwActionObject.prototype.getObjectById = function(_id)
|
|
|
|
{
|
|
|
|
if (this.id == _id)
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
var obj = this.children[i].getObjectById(_id);
|
|
|
|
if (obj)
|
|
|
|
{
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds an object as child to the actionObject and returns it - if the supplied
|
|
|
|
* parameter is a object, the object will be added directly, otherwise an object
|
|
|
|
* with the given id will be created.
|
|
|
|
*
|
|
|
|
* @param string/object _id Id of the object which will be created or the object
|
|
|
|
* that will be added.
|
|
|
|
* @param object if _id was an string, _interface defines the interface which
|
|
|
|
* will be connected to the newly generated object.
|
|
|
|
* @param int _flags are the flags will which be supplied to the newly generated
|
|
|
|
* object. May be omitted.
|
|
|
|
* @returns object the generated object
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.addObject = function(_id, _interface, _flags)
|
|
|
|
{
|
|
|
|
return this.insertObject(false, _id, _interface, _flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inserts an object as child to the actionObject and returns it - if the supplied
|
|
|
|
* parameter is a object, the object will be added directly, otherwise an object
|
|
|
|
* with the given id will be created.
|
|
|
|
*
|
|
|
|
* @param int _index Position where the object will be inserted, "false" will add it
|
|
|
|
* to the end of the list.
|
|
|
|
* @param string/object _id Id of the object which will be created or the object
|
|
|
|
* that will be added.
|
|
|
|
* @param object _iface if _id was an string, _iface defines the interface which
|
|
|
|
* will be connected to the newly generated object.
|
|
|
|
* @param int _flags are the flags will which be supplied to the newly generated
|
|
|
|
* object. May be omitted.
|
|
|
|
* @returns object the generated object
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.insertObject = function(_index, _id, _iface, _flags)
|
|
|
|
{
|
|
|
|
if (_index === false)
|
|
|
|
_index = this.children.length;
|
|
|
|
|
|
|
|
var obj = null;
|
|
|
|
|
|
|
|
if (typeof _id == "object")
|
|
|
|
{
|
|
|
|
obj = _id;
|
|
|
|
|
|
|
|
// Set the parent to null and reset the focus of the object
|
|
|
|
obj.parent = null;
|
|
|
|
obj.setFocused(false);
|
|
|
|
|
|
|
|
// Set the parent to this object
|
|
|
|
obj.parent = this;
|
|
|
|
}
|
|
|
|
else if (typeof _id == "string")
|
|
|
|
{
|
|
|
|
obj = new egwActionObject(_id, this, _iface, this.manager, _flags)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (obj)
|
|
|
|
{
|
|
|
|
// Add the element to the children
|
|
|
|
this.children.splice(_index, 0, obj);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw "Error while adding new element to the ActionObjects!"
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2011-05-28 17:24:31 +02:00
|
|
|
/**
|
|
|
|
* Deletes all children of the egwActionObject
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.clear = function() {
|
|
|
|
this.children = [];
|
|
|
|
this.selectedChildren = [];
|
|
|
|
this.focusedChild = null;
|
|
|
|
}
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
/**
|
|
|
|
* Searches for the root object in the action object tree and returns it.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getRootObject = function()
|
|
|
|
{
|
|
|
|
if (this.parent === null)
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return this.parent.getRootObject();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a list with all parents of this object.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getParentList = function()
|
|
|
|
{
|
|
|
|
if (this.parent === null)
|
|
|
|
{
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var list = this.parent.getParentList();
|
|
|
|
list.unshift(this.parent);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the first parent which has the container flag
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getContainerRoot = function()
|
|
|
|
{
|
|
|
|
if (egwBitIsSet(this.flags, EGW_AO_FLAG_IS_CONTAINER) || this.parent === null)
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return this.parent.getContainerRoot();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
/**
|
2011-03-02 22:18:20 +01:00
|
|
|
* Returns all selected objects which are in the current subtree.
|
|
|
|
*
|
|
|
|
* @param function _test is a function, which gets an object and checks whether
|
|
|
|
* it will be added to the list.
|
|
|
|
* @param array _list is internally used to fetch all selected elements, please
|
|
|
|
* omit this parameter when calling the function.
|
2011-02-26 19:04:28 +01:00
|
|
|
*/
|
2011-03-02 22:18:20 +01:00
|
|
|
egwActionObject.prototype.getSelectedObjects = function(_test, _list)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
|
|
|
if (typeof _test == "undefined")
|
|
|
|
_test = null;
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
if (typeof _list == "undefined")
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
_list = {"elements": []}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!_test || _test(this)) && this.getSelected())
|
|
|
|
_list.elements.push(this);
|
|
|
|
|
|
|
|
if (this.selectedChildren)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.selectedChildren.length; i++)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this.selectedChildren[i].getSelectedObjects(_test, _list)
|
2011-02-26 19:04:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
return _list.elements;
|
2011-02-26 19:04:28 +01:00
|
|
|
}
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
/**
|
|
|
|
* Returns whether all objects in this tree are selected
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getAllSelected = function()
|
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
if (this.children.length == this.selectedChildren.length)
|
2011-02-26 21:40:27 +01:00
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
if (!this.children[i].getAllSelected())
|
|
|
|
return false;
|
|
|
|
}
|
2011-05-31 19:02:51 +02:00
|
|
|
// If this element is an container *and* does not have any children, we
|
|
|
|
// should return false. If this element is not an container we have to
|
|
|
|
// return true has this is the recursion base case
|
|
|
|
return (!egwBitIsSet(this.flags, EGW_AO_FLAG_IS_CONTAINER)) ||
|
|
|
|
(this.children.length > 0);
|
2011-02-26 21:40:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Toggles the selection of all objects.
|
|
|
|
*
|
|
|
|
* @param _select boolean specifies whether the objects should get selected or not.
|
|
|
|
* If this parameter is not supplied, the selection will be toggled.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.toggleAllSelected = function(_select)
|
|
|
|
{
|
|
|
|
if (typeof _select == "undefined")
|
|
|
|
{
|
|
|
|
_select = !this.getAllSelected();
|
|
|
|
}
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
this.setAllSelected(_select);
|
2011-02-26 21:40:27 +01:00
|
|
|
}
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
/**
|
|
|
|
* Creates a list which contains all items of the element tree.
|
|
|
|
*
|
|
|
|
* @param object _obj is used internally to pass references to the array inside
|
|
|
|
* the object.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.flatList = function(_obj)
|
|
|
|
{
|
|
|
|
if (typeof(_obj) == "undefined")
|
|
|
|
{
|
|
|
|
_obj = {
|
2011-02-24 20:00:47 +01:00
|
|
|
"elements": []
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_obj.elements.push(this);
|
|
|
|
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
this.children[i].flatList(_obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
return _obj.elements;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a traversal list with all objects which are in between the given object
|
|
|
|
* and this one. The operation returns an empty list, if a container object is
|
|
|
|
* found on the way.
|
|
|
|
*/
|
2011-03-02 22:18:20 +01:00
|
|
|
//TODO: Remove flatList here!
|
2011-02-24 17:10:11 +01:00
|
|
|
egwActionObject.prototype.traversePath = function(_to)
|
|
|
|
{
|
|
|
|
var contRoot = this.getContainerRoot();
|
|
|
|
|
|
|
|
if (contRoot)
|
|
|
|
{
|
|
|
|
// Get a flat list of all the hncp elements and search for this object
|
|
|
|
// and the object supplied in the _to parameter.
|
|
|
|
var flatList = contRoot.flatList();
|
2011-02-26 19:04:28 +01:00
|
|
|
var thisId = flatList.indexOf(this);
|
|
|
|
var toId = flatList.indexOf(_to);
|
2011-02-24 17:10:11 +01:00
|
|
|
|
|
|
|
// Check whether both elements have been found in this part of the tree,
|
|
|
|
// return the slice of that list.
|
|
|
|
if (thisId !== -1 && toId !== -1)
|
|
|
|
{
|
|
|
|
var from = Math.min(thisId, toId);
|
|
|
|
var to = Math.max(thisId, toId);
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
return flatList.slice(from, to + 1);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the index of this object in the children list of the parent object.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getIndex = function()
|
|
|
|
{
|
|
|
|
if (this.parent === null)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return this.parent.children.indexOf(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the deepest object which is currently focused. Objects with the
|
|
|
|
* "container"-flag will not be returned.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getFocusedObject = function()
|
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
var cr = this.getContainerRoot();
|
|
|
|
return cr ? cr.focusedChild : null;
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
|
|
|
* Internal function which is connected to the ActionObjectInterface associated
|
|
|
|
* with this object in the constructor. It gets called, whenever the object
|
|
|
|
* gets (de)selected.
|
|
|
|
*
|
|
|
|
* @param int _newState is the new state of the object
|
|
|
|
* @param int _shiftState is the status of extra keys being pressed during the
|
|
|
|
* selection process.
|
|
|
|
*/
|
2011-03-02 22:18:20 +01:00
|
|
|
egwActionObject.prototype._ifaceCallback = function(_newState, _changedBit, _shiftState)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-02-24 22:39:05 +01:00
|
|
|
if (typeof _shiftState == "undefined")
|
|
|
|
_shiftState = EGW_AO_SHIFT_STATE_NONE;
|
2011-03-02 22:18:20 +01:00
|
|
|
|
|
|
|
var selected = egwBitIsSet(_newState, EGW_AO_STATE_SELECTED);
|
|
|
|
var visible = egwBitIsSet(_newState, EGW_AO_STATE_VISIBLE);
|
|
|
|
|
|
|
|
// Check whether the visibility of the object changed
|
|
|
|
if (_changedBit == EGW_AO_STATE_VISIBLE && visible != this.getVisible())
|
|
|
|
{
|
|
|
|
// Deselect the object
|
|
|
|
if (!visible)
|
|
|
|
{
|
|
|
|
this.setSelected(false);
|
|
|
|
this.setFocused(false);
|
|
|
|
return EGW_AO_STATE_NORMAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Auto-register the actions attached to this object
|
|
|
|
this.registerActions();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
// Remove the focus from all children on the same level
|
2011-03-02 22:18:20 +01:00
|
|
|
if (this.parent && visible && _changedBit == EGW_AO_STATE_SELECTED)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
|
|
|
var selected = egwBitIsSet(_newState, EGW_AO_STATE_SELECTED);
|
2011-02-24 22:39:05 +01:00
|
|
|
var objs = [];
|
2011-02-24 17:10:11 +01:00
|
|
|
|
|
|
|
if (selected)
|
|
|
|
{
|
|
|
|
// Search the index of this object
|
|
|
|
var id = this.parent.children.indexOf(this);
|
|
|
|
|
|
|
|
// Deselect all other objects inside this container, if the "MULTI" shift-
|
|
|
|
// state is not set
|
|
|
|
if (!egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_MULTI))
|
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
var lst = this.getContainerRoot().setAllSelected(false);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the LIST state is active, get all objects inbetween this one and the focused one
|
|
|
|
// and set their select state.
|
2011-02-24 20:00:47 +01:00
|
|
|
if (egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_BLOCK))
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-10 21:58:35 +01:00
|
|
|
var focused = this.getFocusedObject();
|
2011-02-24 17:10:11 +01:00
|
|
|
if (focused)
|
|
|
|
{
|
|
|
|
objs = this.traversePath(focused);
|
|
|
|
for (var i = 0; i < objs.length; i++)
|
|
|
|
{
|
|
|
|
objs[i].setSelected(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-24 22:39:05 +01:00
|
|
|
}
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-02-24 22:39:05 +01:00
|
|
|
// If the focused element didn't belong to this container, or the "list"
|
|
|
|
// shift-state isn't active, set the focus to this element.
|
|
|
|
if (objs.length == 0 || !egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_BLOCK))
|
|
|
|
{
|
|
|
|
this.setFocused(true);
|
2011-03-02 22:18:20 +01:00
|
|
|
_newState = egwSetBit(EGW_AO_STATE_FOCUSED, _newState, true);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
|
|
|
|
this.setSelected(selected);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
|
|
|
|
return _newState;
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
|
|
|
* Returns whether the object is currently selected.
|
|
|
|
*/
|
2011-02-24 17:10:11 +01:00
|
|
|
egwActionObject.prototype.getSelected = function()
|
|
|
|
{
|
|
|
|
return egwBitIsSet(this.getState(), EGW_AO_STATE_SELECTED);
|
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
|
|
|
* Returns whether the object is currently focused.
|
|
|
|
*/
|
2011-02-24 17:10:11 +01:00
|
|
|
egwActionObject.prototype.getFocused = function()
|
|
|
|
{
|
2011-02-24 20:00:47 +01:00
|
|
|
return egwBitIsSet(this.getState(), EGW_AO_STATE_FOCUSED);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Returns whether the object currently is visible - visible means, that the
|
|
|
|
* AOI has a dom node and is visible.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getVisible = function()
|
|
|
|
{
|
|
|
|
return egwBitIsSet(this.getState(), EGW_AO_STATE_VISIBLE);
|
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
|
|
|
* Returns the complete state of the object.
|
|
|
|
*/
|
2011-02-24 17:10:11 +01:00
|
|
|
egwActionObject.prototype.getState = function()
|
|
|
|
{
|
2011-02-24 20:00:47 +01:00
|
|
|
return this.iface.getState();
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
|
|
|
* Sets the focus of the element. The formerly focused element in the tree will
|
|
|
|
* be de-focused.
|
|
|
|
*
|
|
|
|
* @param boolean _focused - whether to remove or set the focus. Defaults to true
|
|
|
|
*/
|
2011-03-02 22:18:20 +01:00
|
|
|
egwActionObject.prototype.setFocused = function(_focused)
|
2011-02-24 20:00:47 +01:00
|
|
|
{
|
|
|
|
if (typeof _focused == "undefined")
|
|
|
|
_focused = true;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
var state = this.iface.getState();
|
|
|
|
|
|
|
|
if (egwBitIsSet(state, EGW_AO_STATE_FOCUSED) != _focused)
|
|
|
|
{
|
|
|
|
// Un-focus the currently focused object
|
|
|
|
var currentlyFocused = this.getFocusedObject();
|
|
|
|
if (currentlyFocused && currentlyFocused != this)
|
|
|
|
{
|
|
|
|
currentlyFocused.setFocused(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.iface.setState(egwSetBit(state, EGW_AO_STATE_FOCUSED, _focused));
|
|
|
|
if (this.parent)
|
|
|
|
{
|
|
|
|
this.parent.updateFocusedChild(this, _focused);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Sets the selected state of the element.
|
|
|
|
* TODO: Callback
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.setSelected = function(_selected)
|
|
|
|
{
|
|
|
|
var state = this.iface.getState();
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
if ((egwBitIsSet(state, EGW_AO_STATE_SELECTED) != _selected) &&
|
|
|
|
egwBitIsSet(state, EGW_AO_STATE_VISIBLE))
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this.iface.setState(egwSetBit(state, EGW_AO_STATE_SELECTED, _selected));
|
|
|
|
if (this.parent)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this.parent.updateSelectedChildren(this, _selected || this.selectedChildren.length > 0);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the selected state of all elements, including children
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.setAllSelected = function(_selected, _informParent)
|
|
|
|
{
|
|
|
|
if (typeof _informParent == "undefined")
|
|
|
|
_informParent = true;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
var state = this.iface.getState();
|
|
|
|
|
|
|
|
// Update this element
|
|
|
|
if (egwBitIsSet(state, EGW_AO_STATE_SELECTED) != _selected)
|
|
|
|
{
|
|
|
|
this.iface.setState(egwSetBit(state, EGW_AO_STATE_SELECTED, _selected));
|
|
|
|
if (_informParent && this.parent)
|
2011-02-24 20:00:47 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this.parent.updateSelectedChildren(this, _selected);
|
2011-02-24 20:00:47 +01:00
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update the children if the should be selected or if they should be
|
|
|
|
// deselected and there are selected children.
|
|
|
|
if (_selected || this.selectedChildren.length > 0)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this.children[i].setAllSelected(_selected, false);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the selected children list
|
2011-03-23 15:36:25 +01:00
|
|
|
this.selectedChildren = [];
|
|
|
|
if (_selected)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
this.selectedChildren.push(this.children[i]);
|
|
|
|
}
|
|
|
|
}
|
2011-03-31 14:56:47 +02:00
|
|
|
|
|
|
|
// Call the setSelectedCallback
|
|
|
|
egwQueueCallback(this.setSelectedCallback, [], this, "setSelectedCallback");
|
2011-03-02 22:18:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the selectedChildren array each actionObject has in order to determine
|
|
|
|
* all selected children in a very fast manner.
|
|
|
|
* TODO: Has also to be updated, if an child is added/removed!
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.updateSelectedChildren = function(_child, _selected)
|
|
|
|
{
|
2011-03-10 21:58:35 +01:00
|
|
|
var id = this.selectedChildren.indexOf(_child); // TODO Replace by binary search, insert children sorted by index!
|
2011-03-30 16:28:49 +02:00
|
|
|
var wasEmpty = this.selectedChildren.length == 0;
|
2011-02-24 20:00:47 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
// Add or remove the given child from the selectedChildren list
|
|
|
|
if (_selected && id == -1)
|
|
|
|
{
|
|
|
|
this.selectedChildren.push(_child);
|
|
|
|
}
|
|
|
|
else if (!_selected && id != -1)
|
|
|
|
{
|
|
|
|
this.selectedChildren.splice(id, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the emptieness of the selectedChildren array has changed, update the
|
|
|
|
// parent selected children array.
|
|
|
|
if (wasEmpty != this.selectedChildren.length == 0 && this.parent)
|
|
|
|
{
|
|
|
|
this.parent.updateSelectedChildren(this, wasEmpty);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
2011-03-30 16:28:49 +02:00
|
|
|
|
2011-03-31 14:56:47 +02:00
|
|
|
// Call the setSelectedCallback
|
|
|
|
egwQueueCallback(this.setSelectedCallback, [], this, "setSelectedCallback");
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/**
|
2011-03-02 22:18:20 +01:00
|
|
|
* Updates the focusedChild up to the container boundary.
|
2011-02-24 20:00:47 +01:00
|
|
|
*/
|
2011-03-02 22:18:20 +01:00
|
|
|
egwActionObject.prototype.updateFocusedChild = function(_child, _focused)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
if (_focused)
|
|
|
|
{
|
|
|
|
this.focusedChild = _child;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-09 23:16:41 +01:00
|
|
|
if (this.focusedChild == _child)
|
2011-03-02 22:18:20 +01:00
|
|
|
{
|
|
|
|
this.focusedChild = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.parent && !egwBitIsSet(this.flags, EGW_AO_FLAG_IS_CONTAINER))
|
|
|
|
{
|
|
|
|
this.parent.updateFocusedChild(_child, _focused);
|
|
|
|
}
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the actionLinks of the given ActionObject.
|
|
|
|
*
|
|
|
|
* @param array _actionLinks contains the information about the actionLinks which
|
|
|
|
* should be updated as an array of objects. Example
|
|
|
|
* [
|
|
|
|
* {
|
|
|
|
* "actionId": "file_delete",
|
|
|
|
* "enabled": true
|
|
|
|
* }
|
|
|
|
* ]
|
|
|
|
* If an supplied link doesn't exist yet, it will be created (if _doCreate is true)
|
|
|
|
* and added to the list. Otherwise the information will just be updated.
|
|
|
|
* @param boolean _recursive If true, the settings will be applied to all child
|
|
|
|
* object (default false)
|
|
|
|
* @param boolean _doCreate If true, not yet existing links will be created (default true)
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.updateActionLinks = function(_actionLinks, _recursive, _doCreate)
|
|
|
|
{
|
|
|
|
if (typeof _recursive == "undefined")
|
|
|
|
_recursive = false;
|
|
|
|
if (typeof _doCreate == "undefined")
|
|
|
|
_doCreate = true;
|
|
|
|
|
|
|
|
for (var i = 0; i < _actionLinks.length; i++)
|
|
|
|
{
|
|
|
|
var elem = _actionLinks[i];
|
2011-03-16 18:50:25 +01:00
|
|
|
|
|
|
|
// Allow single strings for simple action links.
|
|
|
|
if (typeof elem == "string")
|
|
|
|
{
|
|
|
|
elem = {"actionId": elem};
|
|
|
|
}
|
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
if (typeof elem.actionId != "undefined" && elem.actionId)
|
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
//Get the action link object, if it doesn't exist yet, create it
|
2011-02-23 19:24:16 +01:00
|
|
|
var actionLink = this.getActionLink(elem.actionId);
|
|
|
|
if (!actionLink && _doCreate)
|
|
|
|
{
|
|
|
|
actionLink = new egwActionLink(this.manager);
|
2011-02-26 19:04:28 +01:00
|
|
|
this.actionLinks.push(actionLink);
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//Set the supplied data
|
|
|
|
if (actionLink)
|
|
|
|
{
|
|
|
|
actionLink.updateLink(elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_recursive)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
this.children[i].updateActionLinks(_actionLinks, true, _doCreate);
|
|
|
|
}
|
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
|
2011-03-14 21:11:08 +01:00
|
|
|
if (this.getVisible() && this.iface != null)
|
2011-03-02 22:18:20 +01:00
|
|
|
{
|
|
|
|
this.registerActions();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reconnects the actions.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype._reconnectCallback = function()
|
|
|
|
{
|
|
|
|
this.registeredImpls = [];
|
2011-03-14 21:11:08 +01:00
|
|
|
this.registerActions();
|
2011-02-23 19:24:16 +01:00
|
|
|
}
|
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
/**
|
|
|
|
* Registers the action implementations inside the DOM-Tree.
|
|
|
|
*/
|
2011-02-26 19:04:28 +01:00
|
|
|
egwActionObject.prototype.registerActions = function()
|
|
|
|
{
|
|
|
|
var groups = this.getActionImplementationGroups();
|
|
|
|
|
2011-04-23 11:07:31 +02:00
|
|
|
for (var group in groups)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
|
|
|
// Get the action implementation for each group
|
|
|
|
if (typeof _egwActionClasses[group] != "undefined" &&
|
|
|
|
_egwActionClasses[group].implementation &&
|
|
|
|
this.iface)
|
|
|
|
{
|
|
|
|
var impl = _egwActionClasses[group].implementation();
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
if (this.registeredImpls.indexOf(impl) == -1)
|
|
|
|
{
|
|
|
|
// Register a handler for that action with the interface of that object,
|
|
|
|
// the callback and this object as context for the callback
|
|
|
|
if (impl.registerAction(this.iface, this.executeActionImplementation, this))
|
|
|
|
{
|
|
|
|
this.registeredImpls.push(impl);
|
|
|
|
}
|
|
|
|
}
|
2011-02-26 19:04:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
/**
|
|
|
|
* Calls the onBeforeTrigger function - if it is set - or returns false.
|
|
|
|
*/
|
2011-02-26 19:04:28 +01:00
|
|
|
egwActionObject.prototype.triggerCallback = function()
|
|
|
|
{
|
|
|
|
if (this.onBeforeTrigger)
|
|
|
|
{
|
|
|
|
return this.onBeforeTrigger();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
var EGW_AO_EXEC_SELECTED = 0;
|
|
|
|
var EGW_AO_EXEC_THIS = 1;
|
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
/**
|
|
|
|
* Executes the action implementation which is associated to the given action type.
|
|
|
|
*
|
|
|
|
* @param object _implContext is data which should be delivered to the action implementation.
|
|
|
|
* E.g. in case of the popup action implementation, the x and y coordinates where the
|
|
|
|
* menu should open are transmitted.
|
|
|
|
* @param string _implType is the action type for which the implementation should be
|
|
|
|
* executed.
|
2011-03-24 18:06:44 +01:00
|
|
|
* @param int _execType specifies in which context the execution should take place.
|
|
|
|
* defaults to EGW_AO_EXEC_SELECTED
|
2011-02-26 21:40:27 +01:00
|
|
|
*/
|
2011-03-24 18:06:44 +01:00
|
|
|
egwActionObject.prototype.executeActionImplementation = function(_implContext, _implType, _execType)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
2011-03-24 18:06:44 +01:00
|
|
|
if (typeof _execType == "undefined")
|
|
|
|
{
|
|
|
|
_execType = EGW_AO_EXEC_SELECTED;
|
|
|
|
}
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
if (typeof _implType == "string")
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
_implType = _egwActionClasses[_implType].implementation();
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
2011-02-26 19:04:28 +01:00
|
|
|
|
|
|
|
if (typeof _implType == "object" && _implType)
|
|
|
|
{
|
2011-03-24 18:06:44 +01:00
|
|
|
if (_execType == EGW_AO_EXEC_SELECTED)
|
|
|
|
{
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
if (!(egwBitIsSet(EGW_AO_FLAG_IS_CONTAINER, this.flags)))
|
|
|
|
{
|
|
|
|
this.forceSelection();
|
|
|
|
}
|
2011-03-24 18:06:44 +01:00
|
|
|
var selectedActions = this.getSelectedLinks(_implType.type);
|
|
|
|
}
|
|
|
|
else if (_execType = EGW_AO_EXEC_THIS)
|
|
|
|
{
|
|
|
|
selectedActions = this._getLinks([this], _implType.type);
|
|
|
|
}
|
|
|
|
|
2011-02-26 19:04:28 +01:00
|
|
|
if (selectedActions.selected.length > 0 && egwObjectLength(selectedActions.links) > 0)
|
|
|
|
{
|
2011-02-26 21:40:27 +01:00
|
|
|
return _implType.executeImplementation(_implContext,
|
2011-02-26 19:04:28 +01:00
|
|
|
selectedActions.selected, selectedActions.links);
|
|
|
|
}
|
|
|
|
}
|
2011-02-26 21:40:27 +01:00
|
|
|
|
|
|
|
return false;
|
2011-02-26 19:04:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-02-26 21:40:27 +01:00
|
|
|
* Forces the object to be inside the currently selected objects. If this is
|
|
|
|
* not the case, the object will select itself and deselect all other objects.
|
2011-02-26 19:04:28 +01:00
|
|
|
*/
|
2011-02-26 21:40:27 +01:00
|
|
|
egwActionObject.prototype.forceSelection = function()
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
var selected = this.getContainerRoot().getSelectedObjects();
|
2011-02-26 19:04:28 +01:00
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
// Check whether this object is in the list
|
|
|
|
var thisInList = selected.indexOf(this) != -1;
|
2011-02-26 19:04:28 +01:00
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
// If not, select it
|
|
|
|
if (!thisInList)
|
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this.getContainerRoot().setAllSelected(false);
|
2011-02-26 21:40:27 +01:00
|
|
|
this.setSelected(true);
|
2011-02-26 19:04:28 +01:00
|
|
|
}
|
2011-03-02 22:18:20 +01:00
|
|
|
|
|
|
|
this.setFocused(true);
|
2011-02-26 21:40:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns all selected objects, and all action links of those objects, which are
|
|
|
|
* of the given implementation type, wheras actionLink properties such as
|
|
|
|
* "enabled" and "visible" are accumulated.
|
|
|
|
*
|
|
|
|
* Objects have the chance to change their action links or to deselect themselves
|
|
|
|
* in the onBeforeTrigger event, which is evaluated by the triggerCallback function.
|
|
|
|
*
|
|
|
|
* @param _actionType is the action type for which the actionLinks should be collected.
|
|
|
|
* @returns object An object which contains a "links" and a "selected" section with
|
|
|
|
* an array of links/selected objects-
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getSelectedLinks = function(_actionType)
|
|
|
|
{
|
|
|
|
// Get all objects in this container which are currently selected
|
2011-03-02 22:18:20 +01:00
|
|
|
var selected = this.getContainerRoot().getSelectedObjects();
|
2011-02-26 19:04:28 +01:00
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
return this._getLinks(selected, _actionType);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype._getLinks = function(_objs, _actionType)
|
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
var actionLinks = {};
|
|
|
|
var testedSelected = [];
|
2011-03-24 18:06:44 +01:00
|
|
|
for (var i = 0; i < _objs.length; i++)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
2011-03-24 18:06:44 +01:00
|
|
|
var obj = _objs[i];
|
2011-05-28 17:24:31 +02:00
|
|
|
if (!egwBitIsSet(obj.flags, EGW_AO_FLAG_IS_CONTAINER) && obj.triggerCallback())
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
|
|
|
testedSelected.push(obj);
|
|
|
|
|
|
|
|
for (var j = 0; j < obj.actionLinks.length; j++)
|
|
|
|
{
|
|
|
|
var olink = obj.actionLinks[j]; //object link
|
|
|
|
|
|
|
|
// Test whether the action type is of the given implementation type
|
2011-02-26 21:40:27 +01:00
|
|
|
if (olink.actionObj.type == _actionType)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
|
|
|
if (typeof actionLinks[olink.actionId] == "undefined")
|
|
|
|
{
|
|
|
|
actionLinks[olink.actionId] = {
|
|
|
|
"actionObj": olink.actionObj,
|
2011-02-26 21:40:27 +01:00
|
|
|
"enabled": (testedSelected.length == 1),
|
2011-02-26 19:04:28 +01:00
|
|
|
"visible": false,
|
|
|
|
"cnt": 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
// Accumulate the action link properties
|
2011-02-26 19:04:28 +01:00
|
|
|
var llink = actionLinks[olink.actionId];
|
2011-04-17 22:27:23 +02:00
|
|
|
llink.enabled = llink.enabled && olink.actionObj.enabled.exec(olink.actionObj, _objs, _objs[i]) &&
|
2011-03-21 17:12:28 +01:00
|
|
|
olink.enabled && olink.visible;
|
2011-03-23 21:08:33 +01:00
|
|
|
llink.visible = (llink.visible || olink.visible);
|
2011-02-26 19:04:28 +01:00
|
|
|
llink.cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-26 21:40:27 +01:00
|
|
|
// Check whether all objects supported the action
|
2011-04-23 11:07:31 +02:00
|
|
|
for (var k in actionLinks)
|
2011-02-26 19:04:28 +01:00
|
|
|
{
|
2011-02-26 21:40:27 +01:00
|
|
|
actionLinks[k].enabled = actionLinks[k].enabled &&
|
|
|
|
(actionLinks[k].cnt >= testedSelected.length) &&
|
Fixed problems with executeActionImplementation when called from a container object, fixed problem with popup menu which did not open in some cases, added the ability to use the 'enabled' property of an action as an callback function (actionObject is passed as parameter), introduced egwFnct-class which consistently handles 'javaScript:fnct' strings, added 'allowOnMultiple':'only' setting, added 'hint', 'checkbox', 'checked', 'radioGroup' properties to popup actions, added 'setDefaultExecute' function to egwAction objects, which applies an handler to all objects which don't have a handler yet
2011-04-17 17:38:46 +02:00
|
|
|
(
|
|
|
|
(actionLinks[k].actionObj.allowOnMultiple === true) ||
|
|
|
|
(actionLinks[k].actionObj.allowOnMultiple == "only" && actionLinks[k].cnt > 1) ||
|
|
|
|
(actionLinks[k].actionObj.allowOnMultiple == false && actionLinks[k].cnt == 1)
|
|
|
|
);
|
2011-03-23 21:08:33 +01:00
|
|
|
actionLinks[k].visible = actionLinks[k].visible &&
|
|
|
|
(actionLinks[k].enabled || !actionLinks[k].actionObj.hideOnDisabled);
|
2011-02-26 19:04:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return an object which contains the accumulated actionLinks and all selected
|
|
|
|
// objects.
|
|
|
|
return {
|
|
|
|
"selected": testedSelected,
|
|
|
|
"links": actionLinks
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-23 19:24:16 +01:00
|
|
|
/**
|
|
|
|
* Returns the action link, which contains the association to the action with
|
|
|
|
* the given actionId.
|
|
|
|
*
|
|
|
|
* @param string _actionId name of the action associated to the link
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getActionLink = function(_actionId)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.actionLinks.length; i++)
|
|
|
|
{
|
|
|
|
if (this.actionLinks[i].actionObj.id == _actionId)
|
|
|
|
{
|
|
|
|
return this.actionLinks[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns all actions associated to the object tree, grouped by type.
|
|
|
|
*
|
|
|
|
* @param function _test gets an egwActionObject and should return, whether the
|
|
|
|
* actions of this object are added to the result. Defaults to a "always true"
|
|
|
|
* function.
|
|
|
|
* @param object _groups is an internally used parameter, may be omitted.
|
|
|
|
*/
|
|
|
|
egwActionObject.prototype.getActionImplementationGroups = function(_test, _groups)
|
|
|
|
{
|
|
|
|
// If the _groups parameter hasn't been given preset it to an empty object
|
|
|
|
// (associative array).
|
|
|
|
if (typeof _groups == "undefined")
|
|
|
|
_groups = {};
|
|
|
|
if (typeof _test == "undefined")
|
|
|
|
_test = function(_obj) {return true};
|
|
|
|
|
|
|
|
for (var i = 0; i < this.actionLinks.length; i++)
|
|
|
|
{
|
2011-02-26 19:04:28 +01:00
|
|
|
var action = this.actionLinks[i].actionObj;
|
2011-02-23 19:24:16 +01:00
|
|
|
if (typeof action != "undefined" && _test(this))
|
|
|
|
{
|
|
|
|
if (typeof _groups[action.type] == "undefined")
|
|
|
|
{
|
|
|
|
_groups[action.type] = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
_groups[action.type].push(
|
|
|
|
{
|
|
|
|
"object": this,
|
|
|
|
"link": this.actionLinks[i]
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
// Recursively add the actions of the children to the result (as _groups is
|
|
|
|
// an object, only the reference is passed).
|
2011-02-23 19:24:16 +01:00
|
|
|
for (var i = 0; i < this.children.length; i++)
|
|
|
|
{
|
|
|
|
this.children[i].getActionImplementationGroups(_test, _groups);
|
|
|
|
}
|
|
|
|
|
|
|
|
return _groups;
|
|
|
|
}
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
|
|
|
|
/** egwActionObjectInterface Interface **/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The egwActionObjectInterface has to be implemented for each actual object in
|
|
|
|
* the browser. E.g. for the object "DataGridRow", there has to be an
|
|
|
|
* egwActionObjectInterface which is responsible for returning the outer DOMNode
|
|
|
|
* of the object to which JS-Events may be attached by the egwActionImplementation
|
|
|
|
* object, and to do object specific stuff like highlighting the object in the
|
|
|
|
* correct way and to route state changes (like: "object has been selected")
|
|
|
|
* to the egwActionObject object the interface is associated to.
|
|
|
|
*/
|
|
|
|
function egwActionObjectInterface()
|
|
|
|
{
|
|
|
|
//Preset the interface functions
|
|
|
|
|
|
|
|
this.doGetDOMNode = function() {return null};
|
|
|
|
|
|
|
|
// _outerCall may be used to determine, whether the state change has been
|
|
|
|
// evoked from the outside and the stateChangeCallback has to be called
|
|
|
|
// or not.
|
|
|
|
this.doSetState = function(_state, _outerCall) {};
|
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
// The doTiggerEvent function may be overritten by the aoi if it wants to
|
|
|
|
// support certain action implementation specific events like EGW_AI_DRAG_OVER
|
|
|
|
// or EGW_AI_DRAG_OUT
|
|
|
|
this.doTriggerEvent = function(_event, _data) {return false;}
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
this._state = EGW_AO_STATE_NORMAL || EGW_AO_STATE_VISIBLE;
|
2011-02-24 17:10:11 +01:00
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
this.stateChangeCallback = null;
|
|
|
|
this.stateChangeContext = null;
|
|
|
|
this.reconnectActionsCallback = null;
|
|
|
|
this.reconnectActionsContext = null;
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the callback function which will be called when a user interaction changes
|
|
|
|
* state of the object.
|
|
|
|
*/
|
2011-02-24 20:00:47 +01:00
|
|
|
egwActionObjectInterface.prototype.setStateChangeCallback = function(_callback, _context)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
|
|
|
this.stateChangeCallback = _callback;
|
|
|
|
this.stateChangeContext = _context;
|
|
|
|
}
|
|
|
|
|
2011-03-02 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Sets the reconnectActions callback, which will be called by the AOI if its
|
|
|
|
* DOM-Node has been replaced and the actions have to be re-registered.
|
|
|
|
*/
|
|
|
|
egwActionObjectInterface.prototype.setReconnectActionsCallback = function(_callback, _context)
|
|
|
|
{
|
|
|
|
this.reconnectActionsCallback = _callback;
|
|
|
|
this.reconnectActionsContext = _context;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Will be called by the aoi if the actions have to be re-registered due to a
|
|
|
|
* DOM-Node exchange.
|
|
|
|
*/
|
|
|
|
egwActionObjectInterface.prototype.reconnectActions = function()
|
|
|
|
{
|
|
|
|
if (this.reconnectActionsCallback)
|
|
|
|
{
|
|
|
|
this.reconnectActionsCallback.call(this.reconnectActionsContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-24 17:10:11 +01:00
|
|
|
/**
|
|
|
|
* Internal function which should be used whenever the select status of the object
|
|
|
|
* has been changed by the user. This will automatically calculate the new state of
|
|
|
|
* the object and call the stateChangeCallback (if it has been set)
|
|
|
|
*
|
2011-03-02 22:18:20 +01:00
|
|
|
* @param int _stateBit is the bit in the state bit which should be changed
|
|
|
|
* @param boolean _set specifies whether the state bit should be set or not
|
2011-02-24 17:10:11 +01:00
|
|
|
*/
|
2011-03-02 22:18:20 +01:00
|
|
|
egwActionObjectInterface.prototype.updateState = function(_stateBit, _set, _shiftState)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
// Calculate the new state
|
|
|
|
var newState = egwSetBit(this._state, _stateBit, _set);
|
|
|
|
|
|
|
|
// Call the stateChangeCallback if the state really changed
|
2011-02-24 22:39:05 +01:00
|
|
|
if (this.stateChangeCallback)
|
2011-02-24 17:10:11 +01:00
|
|
|
{
|
2011-03-02 22:18:20 +01:00
|
|
|
this._state = this.stateChangeCallback.call(this.stateChangeContext, newState,
|
|
|
|
_stateBit, _shiftState);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this._state = newState;
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the DOM-Node the ActionObject is actually a representation of.
|
|
|
|
* Calls the internal "doGetDOMNode" function, which has to be overwritten
|
|
|
|
* by implementations of this class.
|
|
|
|
*/
|
|
|
|
egwActionObjectInterface.prototype.getDOMNode = function()
|
|
|
|
{
|
|
|
|
return this.doGetDOMNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the state of the object.
|
|
|
|
* Calls the internal "doSetState" function, which has to be overwritten
|
|
|
|
* by implementations of this class. The state-change callback must not be evoked!
|
|
|
|
*
|
|
|
|
* @param _state is the state of the object.
|
|
|
|
*/
|
|
|
|
egwActionObjectInterface.prototype.setState = function(_state)
|
|
|
|
{
|
|
|
|
//Call the doSetState function with the new state (if it has changed at all)
|
|
|
|
if (_state != this._state)
|
|
|
|
{
|
|
|
|
this._state = _state;
|
2011-03-02 22:18:20 +01:00
|
|
|
this.doSetState(_state);
|
2011-02-24 17:10:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current state of the object. The state is maintained by the
|
|
|
|
* egwActionObjectInterface and implementations do not have to overwrite this
|
|
|
|
* function as long as they call the _selectChange function.
|
|
|
|
*/
|
|
|
|
egwActionObjectInterface.prototype.getState = function()
|
|
|
|
{
|
|
|
|
return this._state;
|
|
|
|
}
|
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
/**
|
|
|
|
* The trigger event function can be called by the action implementation in order
|
|
|
|
* to tell the AOI to performe some action.
|
|
|
|
* In the drag/drop handler this function is e.g. used for telling the droppable
|
|
|
|
* element that there was a drag over/out event.
|
|
|
|
*/
|
|
|
|
egwActionObjectInterface.prototype.triggerEvent = function(_event, _data)
|
|
|
|
{
|
|
|
|
if (typeof _data == "undefined")
|
|
|
|
{
|
|
|
|
_data = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.doTriggerEvent(_event, _data);
|
|
|
|
}
|
|
|
|
|
2011-03-09 23:16:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** -- egwActionObjectDummyInterface Class -- **/
|
|
|
|
|
|
|
|
var egwActionObjectDummyInterface = egwActionObjectInterface;
|
|
|
|
|
2011-02-24 20:00:47 +01:00
|
|
|
/** egwActionObjectManager Object **/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The egwActionObjectManager is a dummy class which only contains a dummy
|
|
|
|
* AOI. It may be used as root object or as object containers.
|
|
|
|
*/
|
|
|
|
function egwActionObjectManager(_id, _manager)
|
|
|
|
{
|
2011-02-26 21:40:27 +01:00
|
|
|
var ao = new egwActionObject(_id, null, new egwActionObjectInterface(),
|
2011-02-24 22:39:05 +01:00
|
|
|
_manager, EGW_AO_FLAG_IS_CONTAINER);
|
2011-02-26 21:40:27 +01:00
|
|
|
|
|
|
|
// The object manager doesn't allow selections and cannot perform actions
|
|
|
|
ao.triggerCallback = function() {return false;};
|
|
|
|
|
|
|
|
return ao;
|
2011-02-24 20:00:47 +01:00
|
|
|
}
|
|
|
|
|