diff --git a/phpgwapi/js/egw_action/egw_action.js b/phpgwapi/js/egw_action/egw_action.js
index d2c4087813..a1a944cab6 100644
--- a/phpgwapi/js/egw_action/egw_action.js
+++ b/phpgwapi/js/egw_action/egw_action.js
@@ -27,16 +27,15 @@ function egwActionHandler(_executeEvent)
/**
* Associative array where action classes may register themselves
*/
-var _egwActionClasses =
- {
- "default":
- {
- "actionConstructor": egwAction,
- "implementationConstructor": null
- }
- }
+if (typeof window._egwActionClasses == "undefined")
+ window._egwActionClasses = {}
-function egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
+_egwActionClasses["default"] = {
+ "actionConstructor": egwAction,
+ "implementation": null
+};
+
+function egwAction(_id, _handler, _caption, _iconUrl, _onExecute, _allowOnMultiple)
{
//Default and check the values
if (typeof _id != "string" || !_id)
@@ -45,8 +44,8 @@ function egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
this.handler = null;
if (typeof _label == "undefined")
_label = "";
- if (typeof _icon == "undefined")
- _icon = "";
+ if (typeof _iconUrl == "undefined")
+ _iconUrl = "";
if (typeof _onExecute == "undefined")
_onExecute = null;
if (typeof _allowOnMultiple == "undefined")
@@ -54,7 +53,7 @@ function egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
this.id = _id;
this.caption = _caption;
- this.icon = _icon;
+ this.iconUrl = _iconUrl;
this.allowOnMultiple = _allowOnMultiple;
this.type = "default"; //All derived classes have to override this!
@@ -133,9 +132,9 @@ egwAction.prototype.set_caption = function(_value)
this.caption = _value;
}
-egwAction.prototype.set_icon = function(_value)
+egwAction.prototype.set_iconUrl = function(_value)
{
- this.icon = _value;
+ this.iconUrl = _value;
}
egwAction.prototype.set_allowOnMultiple = function(_value)
@@ -143,6 +142,12 @@ egwAction.prototype.set_allowOnMultiple = function(_value)
this.allowOnMultiple = _value;
}
+egwAction.prototype.updateAction = function(_data)
+{
+ egwActionStoreJSON(_data, this, true);
+}
+
+
/** egwActionManager Object **/
@@ -160,7 +165,7 @@ function egwActionManager(_handler)
this.actions = [];
}
-egwActionManager.prototype.addAction = function(_type, _id, _caption, _icon,
+egwActionManager.prototype.addAction = function(_type, _id, _caption, _iconUrl,
_onExecute, _allowOnMultiple)
{
//Get the constructor for the given action type
@@ -170,7 +175,7 @@ egwActionManager.prototype.addAction = function(_type, _id, _caption, _icon,
if (typeof constructor == "function")
{
- var action = new constructor(_id, this.handler, _caption, _icon, _onExecute,
+ var action = new constructor(_id, this.handler, _caption, _iconUrl, _onExecute,
_allowOnMultiple);
this.actions.push[action];
@@ -196,22 +201,20 @@ egwActionManager.prototype.updateActions = function(_actions)
if (typeof elem.type == "undefined")
elem.type = "default";
- var constructor = _egwActionClasses[elem.type].actionConstructor;
+ var constructor = null;
- if (typeof constructor == "function")
+ 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 not registered.";
+ throw "Given action type \"" + elem.type + "\" not registered.";
this.actions.push(action);
}
- //Update the actions by calling the corresponding setter functions
- //TODO: Hirachical actions will need a reference to their parent -
- // this parent is has to be translated to a js object
- //TODO: Maby the setter, JSON, update stuff should somehow be moved
- // to a own base class.
- egwActionStoreJSON(elem, action, true);
+ action.updateAction(elem);
}
}
}
@@ -239,34 +242,34 @@ egwActionManager.prototype.getAction = function(_id)
* which replaces "this" with a "new egwActionImplementation" and implement your
* code in "doRegisterAction" und "doUnregisterAction".
* Register your own implementation within the _egwActionClasses object.
- *
- * @param object _action is the parent egwAction object for that instance.
*/
-function egwActionImplementation(_action)
+function egwActionImplementation()
{
- this.action = _action;
-
- this.doRegisterAction = null;
- this.doUnregisterAction = null;
+ 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 = "";
}
/**
* Injects the implementation code into the DOM tree by using the supplied
* actionObjectInterface.
*
+ * @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.
* @returns true if the Action had been successfully registered, false if it
* had not.
*/
-egwActionImplementation.registerAction = function(_actionObjectInterface)
+egwActionImplementation.prototype.registerAction = function(_actionObjectInterface, _triggerCallback, _context)
{
- if (this.doRegisterAction == null)
- {
- throw "Abstract function call: registerAction";
- }
- else
- {
- return this.doRegisterAction(_action, _actionObjectInterface);
- }
+ if (typeof _context == "undefined")
+ _context = null;
+
+ return this.doRegisterAction(_actionObjectInterface, _triggerCallback, _context);
}
/**
@@ -277,16 +280,14 @@ egwActionImplementation.registerAction = function(_actionObjectInterface)
* @returns true if the Action had been successfully unregistered, false if it
* had not.
*/
-egwActionImplementation.unregisterAction = function(_actionObjectInterface)
+egwActionImplementation.prototype.unregisterAction = function(_actionObjectInterface)
{
- if (this.doUnregisterAction == null)
- {
- throw "Abstract function call: unregisterAction";
- }
- else
- {
- return this.doUnregisterAction(_action, _actionObjectInterface);
- }
+ return this.doUnregisterAction(_actionObjectInterface);
+}
+
+egwActionImplementation.prototype.executeImplementation = function(_context, _selected, _links)
+{
+ return this.doExecuteImplementation(_context, _selected, _links);
}
@@ -303,6 +304,7 @@ egwActionImplementation.unregisterAction = function(_actionObjectInterface)
function egwActionLink(_manager)
{
this.enabled = true;
+ this.visible = true;
this.actionId = "";
this.actionObj = null;
this.manager = _manager;
@@ -318,6 +320,11 @@ egwActionLink.prototype.set_enabled = function(_value)
this.enabled = _value;
}
+egwActionLink.prototype.set_visible = function(_value)
+{
+ this.visible = _value;
+}
+
egwActionLink.prototype.set_actionId = function(_value)
{
this.actionId = _value;
@@ -327,27 +334,26 @@ egwActionLink.prototype.set_actionId = function(_value)
throw "Given action object does not exist!"
}
-
/** egwActionObject Object **/
//State bitmask (only use powers of two for new states!)
-const EGW_AO_STATE_NORMAL = 0x00;
-const EGW_AO_STATE_SELECTED = 0x01;
-const EGW_AO_STATE_FOCUSED = 0x02;
+var EGW_AO_STATE_NORMAL = 0x00;
+var EGW_AO_STATE_SELECTED = 0x01;
+var EGW_AO_STATE_FOCUSED = 0x02;
-const EGW_AO_EVENT_DRAG_OVER_ENTER = 0x00;
-const EGW_AO_EVENT_DRAG_OVER_LEAVE = 0x01;
+var EGW_AO_EVENT_DRAG_OVER_ENTER = 0x00;
+var EGW_AO_EVENT_DRAG_OVER_LEAVE = 0x01;
// No shift key is pressed
-const EGW_AO_SHIFT_STATE_NONE = 0x00;
+var EGW_AO_SHIFT_STATE_NONE = 0x00;
// A shift key, which allows multiselection is pressed (usually CTRL on a PC keyboard)
-const EGW_AO_SHIFT_STATE_MULTI = 0x01;
+var EGW_AO_SHIFT_STATE_MULTI = 0x01;
// A shift key is pressed, which forces blockwise selection (SHIFT on a PC keyboard)
-const EGW_AO_SHIFT_STATE_BLOCK = 0x02;
+var EGW_AO_SHIFT_STATE_BLOCK = 0x02;
// 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.
-const EGW_AO_FLAG_IS_CONTAINER = 0x01;
+var EGW_AO_FLAG_IS_CONTAINER = 0x01;
/**
* The egwActionObject represents an abstract object to which actions may be
@@ -524,6 +530,26 @@ egwActionObject.prototype.getContainerRoot = function()
}
}
+/**
+ * Returns all selected objects which are in the current container.
+ */
+egwActionObject.prototype.getSelectedObjects = function(_test)
+{
+ if (typeof _test == "undefined")
+ _test = null;
+
+ var result = [];
+ var list = this.getContainerRoot().flatList();
+ for (var i = 0; i < list.length; i++)
+ {
+ if (list[i].getSelected() && (!_test || _test(list[i])))
+ {
+ result.push(list[i]);
+ }
+ }
+
+ return result;
+}
/**
* Creates a list which contains all items of the element tree.
@@ -564,8 +590,8 @@ egwActionObject.prototype.traversePath = function(_to)
// 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();
- var thisId = contRoot.indexOf(this);
- var toId = contRoot.indexOf(_to);
+ var thisId = flatList.indexOf(this);
+ var toId = flatList.indexOf(_to);
// Check whether both elements have been found in this part of the tree,
// return the slice of that list.
@@ -574,7 +600,7 @@ egwActionObject.prototype.traversePath = function(_to)
var from = Math.min(thisId, toId);
var to = Math.max(thisId, toId);
- return this.slice(from, to + 1);
+ return flatList.slice(from, to + 1);
}
}
@@ -745,10 +771,10 @@ egwActionObject.prototype.setFocused = function(_focused, _recPrev)
//If the object is not focused, reset the focus state of all children
for (var i = 0; i < this.children.length; i++)
{
-// if (this.children[i] != _recPrev)
-// {
+ if (this.children[i] != _recPrev)
+ {
this.children[i].setFocused(false, _recPrev);
-// }
+ }
}
}
else
@@ -805,11 +831,12 @@ egwActionObject.prototype.updateActionLinks = function(_actionLinks, _recursive,
var elem = _actionLinks[i];
if (typeof elem.actionId != "undefined" && elem.actionId)
{
- //Get the action link object, if it doesn't exists yet, create it
+ //Get the action link object, if it doesn't exist yet, create it
var actionLink = this.getActionLink(elem.actionId);
if (!actionLink && _doCreate)
{
actionLink = new egwActionLink(this.manager);
+ this.actionLinks.push(actionLink);
}
//Set the supplied data
@@ -829,6 +856,131 @@ egwActionObject.prototype.updateActionLinks = function(_actionLinks, _recursive,
}
}
+egwActionObject.prototype.registerActions = function()
+{
+ var groups = this.getActionImplementationGroups();
+
+ for (group in groups)
+ {
+ // Get the action implementation for each group
+ if (typeof _egwActionClasses[group] != "undefined" &&
+ _egwActionClasses[group].implementation &&
+ this.iface)
+ {
+ var impl = _egwActionClasses[group].implementation();
+
+ // Register a handler for that action with the interface of that object,
+ // the callback and this object as context for the callback
+ impl.registerAction(this.iface, this.executeActionImplementation, this);
+ }
+ }
+}
+
+egwActionObject.prototype.triggerCallback = function()
+{
+ if (this.onBeforeTrigger)
+ {
+ return this.onBeforeTrigger();
+ }
+ return true;
+}
+
+egwActionObject.prototype.executeActionImplementation = function(_implContext, _implType)
+{
+ if (typeof _implType == "string")
+ _implType = _egwActionClasses[_implType].implementation();
+
+ if (typeof _implType == "object" && _implType)
+ {
+ var selectedActions = this.getSelectedLinks(_implType.type, true);
+ if (selectedActions.selected.length > 0 && egwObjectLength(selectedActions.links) > 0)
+ {
+ _implType.executeImplementation(_implContext,
+ selectedActions.selected, selectedActions.links);
+ }
+ }
+}
+
+/**
+ * Returns all selected objects, which returned true in their triggerCallback and
+ * all action links of those objects, which are of the given implementation type,
+ * wheras actionLink properties such as "enabled" and "visible" are accumuleted.
+ */
+egwActionObject.prototype.getSelectedLinks = function(_implType, _includeThis)
+{
+ // Get all objects in this container which are currently selected
+ var selected = this.getSelectedObjects();
+
+ if (_includeThis)
+ {
+ var thisInList = false;
+ for (var i = 0; i < selected.length; i++)
+ {
+ if (selected[i] == this)
+ {
+ thisInList = true;
+ break;
+ }
+ }
+
+ if (!thisInList)
+ {
+ this.setSelected(true);
+ this._ifaceCallback(egwSetBit(this.getState(), EGW_AO_STATE_SELECTED, true),
+ EGW_AO_SHIFT_STATE_NONE);
+ selected = [this];
+ }
+ }
+
+ var actionLinks = {};
+ var testedSelected = [];
+ for (var i = 0; i < selected.length; i++)
+ {
+ var obj = selected[i];
+ if (obj.triggerCallback())
+ {
+ 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
+ if (olink.actionObj.type == _implType)
+ {
+ if (typeof actionLinks[olink.actionId] == "undefined")
+ {
+ actionLinks[olink.actionId] = {
+ "actionObj": olink.actionObj,
+ "enabled": i == 0 && (olink.actionObj.allowOnMultiple || selected.length == 1),
+ "visible": false,
+ "cnt": 0
+ }
+ }
+
+ var llink = actionLinks[olink.actionId];
+ llink.enabled = llink.enabled && olink.enabled && olink.visible;
+ llink.visible = llink.visible || olink.visible;
+ llink.cnt++;
+ }
+ }
+ }
+ }
+
+ for (k in actionLinks)
+ {
+ actionLinks[k].enabled = actionLinks[k].enabled && (actionLinks[k].cnt >= selected.length);
+ }
+
+
+ // Return an object which contains the accumulated actionLinks and all selected
+ // objects.
+ return {
+ "selected": testedSelected,
+ "links": actionLinks
+ }
+}
+
/**
* Returns the action link, which contains the association to the action with
* the given actionId.
@@ -867,7 +1019,7 @@ egwActionObject.prototype.getActionImplementationGroups = function(_test, _group
for (var i = 0; i < this.actionLinks.length; i++)
{
- var action = this.actionsLink[i].actionObj;
+ var action = this.actionLinks[i].actionObj;
if (typeof action != "undefined" && _test(this))
{
if (typeof _groups[action.type] == "undefined")
diff --git a/phpgwapi/js/egw_action/egw_action_common.js b/phpgwapi/js/egw_action/egw_action_common.js
index 422a1e4c19..baeb36f17a 100644
--- a/phpgwapi/js/egw_action/egw_action_common.js
+++ b/phpgwapi/js/egw_action/egw_action_common.js
@@ -61,3 +61,25 @@ function egwBitIsSet(_set, _bit)
return (_set & _bit) > 0;
}
+function egwObjectLength(_obj)
+{
+ var len = 0;
+ for (k in _obj) len++;
+ return len;
+}
+
+/**
+ * IE Fix for array.indexOf
+ */
+if (typeof Array.prototype.indexOf == "undefined")
+{
+ Array.prototype.indexOf = function(_elem) {
+ for (var i = 0; i < this.length; i++)
+ {
+ if (this[i] === _elem)
+ return i;
+ }
+ return -1;
+ };
+}
+
diff --git a/phpgwapi/js/egw_action/egw_menu.js b/phpgwapi/js/egw_action/egw_menu.js
index 899527eaa9..34c7d69f33 100644
--- a/phpgwapi/js/egw_action/egw_menu.js
+++ b/phpgwapi/js/egw_action/egw_menu.js
@@ -18,15 +18,15 @@ var _egw_active_menu = null;
* in e.g. the egwMenu.addItem function.
*/
//TODO Icons: write PHP GD script which is cabable of generating the menu icons in various states (disabled, highlighted)
-function _egwGenMenuItem(_parent, _id, _label, _iconUrl, _onClick)
+function _egwGenMenuItem(_parent, _id, _caption, _iconUrl, _onClick)
{
//Preset the parameters
if (typeof _parent == "undefined")
_parent = null;
if (typeof _id == "undefined")
_id = "";
- if (typeof _label == "undefined")
- _label = "";
+ if (typeof _caption == "undefined")
+ _caption = "";
if (typeof _iconUrl == "undefined")
_iconUrl = "";
if (typeof _onClick == "undefined")
@@ -34,7 +34,7 @@ function _egwGenMenuItem(_parent, _id, _label, _iconUrl, _onClick)
//Create a menu item with no parent (null) and set the given parameters
var item = new egwMenuItem(_parent, _id);
- item.set_caption(_label);
+ item.set_caption(_caption);
item.set_iconUrl(_iconUrl);
item.set_onClick(_onClick);
@@ -217,7 +217,7 @@ egwMenu.prototype.hide = function()
* the getItem function to search a specific menu item inside the menu tree. The
* id may also be false, null or "", which makes sense for items like seperators,
* which you don't want to access anymore after adding them to the menu tree.
- * @param string _label is the label of the newly generated menu item. Set the label
+ * @param string _caption is the caption of the newly generated menu item. Set the caption
* to "-" in order to create a sperator.
* @param string _iconUrl is the URL of the icon which should be prepended to the
* menu item. It may be false, null or "" if you don't want a icon to be displayed.
@@ -226,10 +226,10 @@ egwMenu.prototype.hide = function()
* @returns egwMenuItem the newly generated menu item, which had been appended to the
* menu item list.
*/
-egwMenu.prototype.addItem = function(_id, _label, _iconUrl, _onClick)
+egwMenu.prototype.addItem = function(_id, _caption, _iconUrl, _onClick)
{
//Append the item to the list
- var item = _egwGenMenuItem(this, _id, _label, _iconUrl, _onClick);
+ var item = _egwGenMenuItem(this, _id, _caption, _iconUrl, _onClick);
this.children.push(item);
return item;
@@ -287,7 +287,8 @@ function egwMenuItem(_parent, _id)
this.enabled = true;
this.iconUrl = "";
this.onClick = null;
- this.default = false;
+ this["default"] = false;
+ this.data = null;
this.children = [];
this.parent = _parent;
@@ -314,6 +315,32 @@ egwMenuItem.prototype.setGlobalOnClick = function(_onClick)
_egwSetMenuOnClick(this.children, _onClick);
}
+/**
+ * Adds a new menu item to the list and returns a reference to that object.
+ *
+ * @param string _id is a unique identifier of the menu item. You can use the
+ * the getItem function to search a specific menu item inside the menu tree. The
+ * id may also be false, null or "", which makes sense for items like seperators,
+ * which you don't want to access anymore after adding them to the menu tree.
+ * @param string _caption is the caption of the newly generated menu item. Set the caption
+ * to "-" in order to create a sperator.
+ * @param string _iconUrl is the URL of the icon which should be prepended to the
+ * menu item. It may be false, null or "" if you don't want a icon to be displayed.
+ * @param function _onClick is the JS function which is being executed when the
+ * menu item is clicked.
+ * @returns egwMenuItem the newly generated menu item, which had been appended to the
+ * menu item list.
+ */
+egwMenuItem.prototype.addItem = function(_id, _caption, _iconUrl, _onClick)
+{
+ //Append the item to the list
+ var item = _egwGenMenuItem(this, _id, _caption, _iconUrl, _onClick);
+ this.children.push(item);
+
+ return item;
+}
+
+
//Setter functions for the menuitem properties
egwMenuItem.prototype.set_id = function(_value)
@@ -371,7 +398,11 @@ egwMenuItem.prototype.set_iconUrl = function(_value)
egwMenuItem.prototype.set_default = function(_value)
{
- this.default = _value;
+ this["default"] = _value;
}
+egwMenuItem.prototype.set_data = function(_value)
+{
+ this.data = _value;
+}
diff --git a/phpgwapi/js/egw_action/egw_menu_dhtmlx.js b/phpgwapi/js/egw_action/egw_menu_dhtmlx.js
index 03fd75d08b..a0d3914e22 100644
--- a/phpgwapi/js/egw_action/egw_menu_dhtmlx.js
+++ b/phpgwapi/js/egw_action/egw_menu_dhtmlx.js
@@ -101,7 +101,7 @@ egwMenuImpl.prototype._translateStructure = function(_structure, _parentId, _idC
else
{
var caption = elem.caption;
- if (elem.default)
+ if (elem["default"])
caption = "" + caption + ""
this.dhtmlxmenu.addNewChild(_parentId, i, id, caption, !elem.enabled,
elem.iconUrl, elem.iconUrl);
diff --git a/phpgwapi/js/egw_action/test/test_action.html b/phpgwapi/js/egw_action/test/test_action.html
index 755b8f66f7..23b3c86b13 100644
--- a/phpgwapi/js/egw_action/test/test_action.html
+++ b/phpgwapi/js/egw_action/test/test_action.html
@@ -1,9 +1,21 @@
Test page for the egw action stuff
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
File 1
-
-
-
-
-
File 2
-
-
-
-
-
File 3
-
-
-
+
+
Folder 1
+
File 1
+
File 2
+
File 3
+
File 4
+
File 5
+
diff --git a/phpgwapi/js/egw_action/test/test_menu.html b/phpgwapi/js/egw_action/test/test_menu.html
index 04d29a93b3..4c8a629321 100644
--- a/phpgwapi/js/egw_action/test/test_menu.html
+++ b/phpgwapi/js/egw_action/test/test_menu.html
@@ -163,7 +163,6 @@ function getPageXY(event)
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft :
document.documentElement.scrollLeft;
- // hide the menu first to avoid an "up-then-over" visual effect
return {'x': (event.clientX + scrollLeft), 'y': (event.clientY + scrollTop)};
}
diff --git a/phpgwapi/js/egw_json.js b/phpgwapi/js/egw_json.js
index 57717b92de..8cc899153e 100644
--- a/phpgwapi/js/egw_json.js
+++ b/phpgwapi/js/egw_json.js
@@ -91,8 +91,8 @@ function egw_json_encode(input)
var buf = [];
for (var k in input)
{
- //Filter the remove function, which is added to arrays in egw_fw_classes
- if (k != 'remove')
+ //Filter non numeric entries
+ if (!isNaN(k))
buf.push(egw_json_encode(input[k]));
}
return '[' + buf.join(',') + ']';