forked from extern/egroupware
Moved most code of the JS actionManager class to the action object itself, so that every action object might have child object if the action implementation allows that. Added support for sub-actions for actions representet as popup menus
This commit is contained in:
parent
e33aa2978c
commit
e0d40e649b
@ -35,13 +35,11 @@ _egwActionClasses["default"] = {
|
||||
"implementation": null
|
||||
};
|
||||
|
||||
function egwAction(_id, _handler, _caption, _iconUrl, _onExecute, _allowOnMultiple)
|
||||
function egwAction(_parent, _id, _caption, _iconUrl, _onExecute, _allowOnMultiple)
|
||||
{
|
||||
//Default and check the values
|
||||
if (typeof _id != "string" || !_id)
|
||||
if (_parent && (typeof _id != "string" || !_id))
|
||||
throw "egwAction _id must be a non-empty string!";
|
||||
if (typeof _handler == "undefined")
|
||||
this.handler = null;
|
||||
if (typeof _caption == "undefined")
|
||||
_caption = "";
|
||||
if (typeof _iconUrl == "undefined")
|
||||
@ -56,13 +54,138 @@ function egwAction(_id, _handler, _caption, _iconUrl, _onExecute, _allowOnMultip
|
||||
this.iconUrl = _iconUrl;
|
||||
this.allowOnMultiple = _allowOnMultiple;
|
||||
this.enabled = true;
|
||||
|
||||
this.type = "default"; //All derived classes have to override this!
|
||||
this.canHaveChildren = false; //Has to be overwritten by inherited action classes
|
||||
this.parent = _parent;
|
||||
this.children = [];
|
||||
|
||||
this.execJSFnct = null;
|
||||
this.execHandler = false;
|
||||
this.set_onExecute(_onExecute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
_type = "default";
|
||||
}
|
||||
|
||||
// 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")
|
||||
elem.type = "default";
|
||||
|
||||
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
|
||||
{
|
||||
throw "This action element cannot have children!";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes this action by using the method specified in the onExecute setter.
|
||||
*
|
||||
@ -77,7 +200,7 @@ egwAction.prototype.execute = function(_senders)
|
||||
}
|
||||
else if (this.execHandler)
|
||||
{
|
||||
this.handler.execute(this, _senders);
|
||||
//this.handler.execute(this, _senders); TODO
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,89 +277,132 @@ egwAction.prototype.updateAction = function(_data)
|
||||
}
|
||||
|
||||
|
||||
function _egwActionTreeContains(_tree, _elem)
|
||||
{
|
||||
for (var i = 0; i < _tree.length; i++)
|
||||
{
|
||||
if (_tree[i].action == _elem)
|
||||
{
|
||||
return _tree[i];
|
||||
}
|
||||
|
||||
if (typeof _tree[i].children != "undefined")
|
||||
{
|
||||
var elem = _egwActionTreeContains(_tree[i].children, _elem);
|
||||
if (elem)
|
||||
{
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
egwAction.prototype.appendToTree = function(_tree, _addChildren)
|
||||
{
|
||||
if (typeof _addChildren == "undefined")
|
||||
{
|
||||
_addChildren = true;
|
||||
}
|
||||
|
||||
if (typeof _addParent == "undefined")
|
||||
{
|
||||
_addParent = true;
|
||||
}
|
||||
|
||||
// Preset some variables
|
||||
var root = _tree.root;
|
||||
var parent_cntr = null;
|
||||
var cntr = {
|
||||
"action": this,
|
||||
"children": []
|
||||
};
|
||||
|
||||
|
||||
if (this.parent)
|
||||
{
|
||||
// Check whether the parent container has already been added to the tree
|
||||
parent_cntr = _egwActionTreeContains(root, this.parent);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var added = false;
|
||||
for (var i = 0; i < root.length; i++)
|
||||
{
|
||||
if (root[i].action == this)
|
||||
{
|
||||
cntr = root[i];
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added)
|
||||
{
|
||||
// Add this element to the root if it has no parent
|
||||
root.push(cntr);
|
||||
}
|
||||
}
|
||||
|
||||
if (_addChildren)
|
||||
{
|
||||
for (var i = 0; i < this.children.length; i++)
|
||||
{
|
||||
this.children[i].appendToTree(_tree, true);
|
||||
}
|
||||
}
|
||||
|
||||
return cntr;
|
||||
}
|
||||
|
||||
|
||||
/** egwActionManager Object **/
|
||||
|
||||
/**
|
||||
* egwActionManager manages a list of actions, provides functions to add new
|
||||
* actions or to update them via JSON.
|
||||
* egwActionManager manages a list of actions - it overwrites the egwAction class
|
||||
* and allows child actions to be added to it.
|
||||
*/
|
||||
function egwActionManager(_handler)
|
||||
function egwActionManager()
|
||||
{
|
||||
//Preset the handler parameter to null
|
||||
if (typeof _handler == "undefined")
|
||||
_handler = null;
|
||||
var action = new egwAction(null, false);
|
||||
|
||||
this.handler = _handler;
|
||||
this.actions = [];
|
||||
}
|
||||
action.type = "actionManager";
|
||||
action.canHaveChildren = true;
|
||||
|
||||
egwActionManager.prototype.addAction = function(_type, _id, _caption, _iconUrl,
|
||||
_onExecute, _allowOnMultiple)
|
||||
{
|
||||
//Get the constructor for the given action type
|
||||
if (!_type)
|
||||
_type = "default";
|
||||
var constructor = _egwActionClasses[_type].actionConstructor;
|
||||
|
||||
if (typeof constructor == "function")
|
||||
{
|
||||
var action = new constructor(_id, this.handler, _caption, _iconUrl, _onExecute,
|
||||
_allowOnMultiple);
|
||||
this.actions.push[action];
|
||||
|
||||
return action;
|
||||
}
|
||||
else
|
||||
throw "Given action type not registered.";
|
||||
}
|
||||
|
||||
egwActionManager.prototype.updateActions = function(_actions)
|
||||
{
|
||||
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")
|
||||
elem.type = "default";
|
||||
|
||||
var constructor = null;
|
||||
|
||||
if (typeof _egwActionClasses[elem.type] != "undefined")
|
||||
constructor = _egwActionClasses[elem.type].actionConstructor;
|
||||
|
||||
if (typeof constructor == "function" && constructor)
|
||||
action = new constructor(elem.id, this.handler);
|
||||
else
|
||||
throw "Given action type \"" + elem.type + "\" not registered.";
|
||||
|
||||
this.actions.push(action);
|
||||
}
|
||||
|
||||
action.updateAction(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action inside the action manager which has the given id.
|
||||
*/
|
||||
egwActionManager.prototype.getActionById = function(_id)
|
||||
{
|
||||
for (var i = 0; i < this.actions.length; i++)
|
||||
{
|
||||
if (this.actions[i].id == _id)
|
||||
return this.actions[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,7 @@ function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMult
|
||||
var action = new egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple);
|
||||
|
||||
action.type = "popup";
|
||||
action.canHaveChildren = ["popup"];
|
||||
action["default"] = false;
|
||||
action.order = 0;
|
||||
action.group = 0;
|
||||
@ -163,33 +164,52 @@ function egwPopupActionImplementation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the context menu from the given action links
|
||||
* Groups and sorts the given action tree layer
|
||||
*/
|
||||
ai._buildMenu = function(_links, _selected)
|
||||
ai._groupLayers = function(_layer, _links, _parentGroup)
|
||||
{
|
||||
var menu = new egwMenu();
|
||||
|
||||
//Sort the links in ordered groups
|
||||
// Seperate the multiple groups out of the layer
|
||||
var link_groups = {};
|
||||
for (k in _links)
|
||||
|
||||
for (var i = 0; i < _layer.children.length; i++)
|
||||
{
|
||||
var actionObj = _layer.children[i].action;
|
||||
|
||||
// Check whether the link group of the current element already exists,
|
||||
// if not, create the group
|
||||
var grp = _links[k].actionObj.group;
|
||||
var grp = actionObj.group;
|
||||
if (typeof link_groups[grp] == "undefined")
|
||||
{
|
||||
link_groups[grp] = [];
|
||||
}
|
||||
|
||||
// Search the link data for this action object if none is found,
|
||||
// visible and enabled = true is assumed
|
||||
var visible = true;
|
||||
var enabled = true;
|
||||
|
||||
if (typeof _links[actionObj.id] != "undefined")
|
||||
{
|
||||
visible = _links[actionObj.id].visible;
|
||||
enabled = _links[actionObj.id].enabled;
|
||||
}
|
||||
|
||||
// Insert the element in order
|
||||
var inserted = false;
|
||||
for (var i = 0; i < link_groups[grp].length; i++)
|
||||
var groupObj = {
|
||||
"actionObj": actionObj,
|
||||
"visible": visible,
|
||||
"enabled": enabled,
|
||||
"groups": []
|
||||
};
|
||||
|
||||
for (var j = 0; j < link_groups[grp].length; j++)
|
||||
{
|
||||
var elem = link_groups[grp][i];
|
||||
if (elem.actionObj.order > _links[k].actionObj.order)
|
||||
var elem = link_groups[grp][j].actionObj;
|
||||
if (elem.order > actionObj.order)
|
||||
{
|
||||
inserted = true;
|
||||
link_groups[grp].splice(i, 0, _links[k]);
|
||||
link_groups[grp].splice(j, 0, groupObj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -197,37 +217,65 @@ function egwPopupActionImplementation()
|
||||
// If the object hasn't been inserted, add it to the end of the list
|
||||
if (!inserted)
|
||||
{
|
||||
link_groups[grp].push(_links[k]);
|
||||
link_groups[grp].push(groupObj);
|
||||
}
|
||||
|
||||
// If this child itself has children, group those elements too
|
||||
if (_layer.children[i].children.length > 0)
|
||||
{
|
||||
this._groupLayers(_layer.children[i], _links, groupObj);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the link groups sorted into an array
|
||||
// Transform the link_groups object into an sorted array
|
||||
var groups = [];
|
||||
|
||||
for (k in link_groups)
|
||||
{
|
||||
groups.push({"grp": k, "links": link_groups[k]});
|
||||
}
|
||||
|
||||
groups.sort(function(a, b) {
|
||||
return (a.grp > b.grp) ? 1 : ((a.grp < b.grp) ? -1 : 0);
|
||||
var ia = parseInt(a.grp);
|
||||
var ib = parseInt(b.grp);
|
||||
return (ia > ib) ? 1 : ((ia < ib) ? -1 : 0);
|
||||
});
|
||||
|
||||
for (var i = 0; i < groups.length; i++)
|
||||
// Append the groups to the groups2 array
|
||||
var groups2 = [];
|
||||
for (k in groups)
|
||||
{
|
||||
groups2.push(groups[k].links);
|
||||
}
|
||||
|
||||
_parentGroup.groups = groups2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the menu layers
|
||||
*/
|
||||
ai._buildMenuLayer = function(_menu, _groups, _selected, _enabled)
|
||||
{
|
||||
for (var i = 0; i < _groups.length; i++)
|
||||
{
|
||||
// Add an seperator after each group
|
||||
if (i != 0)
|
||||
{
|
||||
menu.addItem("", "-");
|
||||
_menu.addItem("", "-");
|
||||
}
|
||||
|
||||
// Go through the elements of each group
|
||||
for (var j = 0; j < groups[i].links.length; j++)
|
||||
for (var j = 0; j < _groups[i].length; j++)
|
||||
{
|
||||
var link = groups[i].links[j];
|
||||
var link = _groups[i][j];
|
||||
|
||||
if (link.visible)
|
||||
{
|
||||
var item = menu.addItem(link.actionObj.id, link.actionObj.caption,
|
||||
var item = _menu.addItem(link.actionObj.id, link.actionObj.caption,
|
||||
link.actionObj.iconUrl);
|
||||
item["default"] = link.actionObj["default"];
|
||||
item.data = link.actionObj;
|
||||
if (link.enabled)
|
||||
if (link.enabled && _enabled)
|
||||
{
|
||||
item.set_onClick(function(elem) {
|
||||
elem.data.execute(_selected);
|
||||
@ -237,9 +285,48 @@ function egwPopupActionImplementation()
|
||||
{
|
||||
item.set_enabled(false);
|
||||
}
|
||||
|
||||
// Append the parent groups
|
||||
if (link.groups)
|
||||
{
|
||||
this._buildMenuLayer(item, link.groups, _selected, link.enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the context menu from the given action links
|
||||
*/
|
||||
ai._buildMenu = function(_links, _selected)
|
||||
{
|
||||
// Build a tree containing all actions
|
||||
var tree = {"root": []};
|
||||
|
||||
for (k in _links)
|
||||
{
|
||||
_links[k].actionObj.appendToTree(tree);
|
||||
}
|
||||
|
||||
var groups = {
|
||||
"groups": []
|
||||
};
|
||||
|
||||
if (tree.root.length > 0)
|
||||
{
|
||||
// Sort every action object layer by the given sort position and grouping
|
||||
this._groupLayers(tree.root[0], _links, groups);
|
||||
}
|
||||
|
||||
var menu = new egwMenu();
|
||||
|
||||
// We needed the dummy object container in order to pass the array as
|
||||
// reference - this is not needed anymore
|
||||
groups = groups.groups;
|
||||
|
||||
// Build the menu layers
|
||||
this._buildMenuLayer(menu, groups, _selected, true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
@ -175,7 +175,6 @@
|
||||
"onExecute": alertClicked,
|
||||
"allowOnMultiple": false,
|
||||
"type": "popup",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"id": "file_delete",
|
||||
@ -219,6 +218,40 @@
|
||||
"type": "popup",
|
||||
"group": 1,
|
||||
"order": 2
|
||||
},
|
||||
{
|
||||
"id": "send_to",
|
||||
"caption": "Send to",
|
||||
"type": "popup",
|
||||
"group": 10,
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"id": "send_to_1",
|
||||
"caption": "Folder 1",
|
||||
"onExecute": alertClicked,
|
||||
"type": "popup"
|
||||
},
|
||||
{
|
||||
"id": "send_to_2",
|
||||
"caption": "Folder 2",
|
||||
"onExecute": alertClicked,
|
||||
"type": "popup"
|
||||
},
|
||||
{
|
||||
"id": "send_to_3",
|
||||
"caption": "Folder 3",
|
||||
"onExecute": alertClicked,
|
||||
"type": "popup"
|
||||
},
|
||||
{
|
||||
"id": "send_to_add",
|
||||
"caption": "Add target",
|
||||
"onExecute": alertClicked,
|
||||
"type": "popup",
|
||||
"group": -1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
);
|
||||
@ -231,14 +264,16 @@
|
||||
{"actionId": "file_email", "enabled": true},
|
||||
{"actionId": "file_compress_email", "enabled": true},
|
||||
{"actionId": "file_compress", "enabled": true},
|
||||
{"actionId": "file_delete", "enabled": true}
|
||||
{"actionId": "file_delete", "enabled": true},
|
||||
{"actionId": "send_to", "enabled": true}
|
||||
];
|
||||
|
||||
var listboxFolderLinks = [
|
||||
{"actionId": "folder_open", "enabled": true},
|
||||
{"actionId": "file_compress_email", "enabled": true},
|
||||
{"actionId": "file_compress", "enabled": true},
|
||||
{"actionId": "file_delete", "enabled": true}
|
||||
{"actionId": "file_delete", "enabled": true},
|
||||
"send_to"
|
||||
];
|
||||
|
||||
$('#lb1 tr:odd').addClass('odd');
|
||||
|
Loading…
Reference in New Issue
Block a user