Implemented egw_popup_action, tested, got it working with IE

This commit is contained in:
Andreas Stöckel 2011-02-26 18:04:28 +00:00
parent ce20a2f3ff
commit 1f751b452a
7 changed files with 452 additions and 129 deletions

View File

@ -27,16 +27,15 @@ function egwActionHandler(_executeEvent)
/** /**
* Associative array where action classes may register themselves * Associative array where action classes may register themselves
*/ */
var _egwActionClasses = if (typeof window._egwActionClasses == "undefined")
{ window._egwActionClasses = {}
"default":
{
"actionConstructor": egwAction,
"implementationConstructor": null
}
}
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 //Default and check the values
if (typeof _id != "string" || !_id) if (typeof _id != "string" || !_id)
@ -45,8 +44,8 @@ function egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
this.handler = null; this.handler = null;
if (typeof _label == "undefined") if (typeof _label == "undefined")
_label = ""; _label = "";
if (typeof _icon == "undefined") if (typeof _iconUrl == "undefined")
_icon = ""; _iconUrl = "";
if (typeof _onExecute == "undefined") if (typeof _onExecute == "undefined")
_onExecute = null; _onExecute = null;
if (typeof _allowOnMultiple == "undefined") if (typeof _allowOnMultiple == "undefined")
@ -54,7 +53,7 @@ function egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
this.id = _id; this.id = _id;
this.caption = _caption; this.caption = _caption;
this.icon = _icon; this.iconUrl = _iconUrl;
this.allowOnMultiple = _allowOnMultiple; this.allowOnMultiple = _allowOnMultiple;
this.type = "default"; //All derived classes have to override this! this.type = "default"; //All derived classes have to override this!
@ -133,9 +132,9 @@ egwAction.prototype.set_caption = function(_value)
this.caption = _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) egwAction.prototype.set_allowOnMultiple = function(_value)
@ -143,6 +142,12 @@ egwAction.prototype.set_allowOnMultiple = function(_value)
this.allowOnMultiple = _value; this.allowOnMultiple = _value;
} }
egwAction.prototype.updateAction = function(_data)
{
egwActionStoreJSON(_data, this, true);
}
/** egwActionManager Object **/ /** egwActionManager Object **/
@ -160,7 +165,7 @@ function egwActionManager(_handler)
this.actions = []; this.actions = [];
} }
egwActionManager.prototype.addAction = function(_type, _id, _caption, _icon, egwActionManager.prototype.addAction = function(_type, _id, _caption, _iconUrl,
_onExecute, _allowOnMultiple) _onExecute, _allowOnMultiple)
{ {
//Get the constructor for the given action type //Get the constructor for the given action type
@ -170,7 +175,7 @@ egwActionManager.prototype.addAction = function(_type, _id, _caption, _icon,
if (typeof constructor == "function") 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); _allowOnMultiple);
this.actions.push[action]; this.actions.push[action];
@ -196,22 +201,20 @@ egwActionManager.prototype.updateActions = function(_actions)
if (typeof elem.type == "undefined") if (typeof elem.type == "undefined")
elem.type = "default"; 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); action = new constructor(elem.id, this.handler);
else else
throw "Given action type not registered."; throw "Given action type \"" + elem.type + "\" not registered.";
this.actions.push(action); this.actions.push(action);
} }
//Update the actions by calling the corresponding setter functions action.updateAction(elem);
//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);
} }
} }
} }
@ -239,34 +242,34 @@ egwActionManager.prototype.getAction = function(_id)
* which replaces "this" with a "new egwActionImplementation" and implement your * which replaces "this" with a "new egwActionImplementation" and implement your
* code in "doRegisterAction" und "doUnregisterAction". * code in "doRegisterAction" und "doUnregisterAction".
* Register your own implementation within the _egwActionClasses object. * 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 = function() {throw "Abstract function call: registerAction"};
this.doUnregisterAction = function() {throw "Abstract function call: unregisterAction"};
this.doRegisterAction = null; this.doExecuteImplementation = function() {throw "Abstract function call: executeImplementation"};
this.doUnregisterAction = null; this.type = "";
} }
/** /**
* Injects the implementation code into the DOM tree by using the supplied * Injects the implementation code into the DOM tree by using the supplied
* actionObjectInterface. * 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 * @returns true if the Action had been successfully registered, false if it
* had not. * had not.
*/ */
egwActionImplementation.registerAction = function(_actionObjectInterface) egwActionImplementation.prototype.registerAction = function(_actionObjectInterface, _triggerCallback, _context)
{ {
if (this.doRegisterAction == null) if (typeof _context == "undefined")
{ _context = null;
throw "Abstract function call: registerAction";
} return this.doRegisterAction(_actionObjectInterface, _triggerCallback, _context);
else
{
return this.doRegisterAction(_action, _actionObjectInterface);
}
} }
/** /**
@ -277,16 +280,14 @@ egwActionImplementation.registerAction = function(_actionObjectInterface)
* @returns true if the Action had been successfully unregistered, false if it * @returns true if the Action had been successfully unregistered, false if it
* had not. * had not.
*/ */
egwActionImplementation.unregisterAction = function(_actionObjectInterface) egwActionImplementation.prototype.unregisterAction = function(_actionObjectInterface)
{ {
if (this.doUnregisterAction == null) return this.doUnregisterAction(_actionObjectInterface);
{ }
throw "Abstract function call: unregisterAction";
} egwActionImplementation.prototype.executeImplementation = function(_context, _selected, _links)
else {
{ return this.doExecuteImplementation(_context, _selected, _links);
return this.doUnregisterAction(_action, _actionObjectInterface);
}
} }
@ -303,6 +304,7 @@ egwActionImplementation.unregisterAction = function(_actionObjectInterface)
function egwActionLink(_manager) function egwActionLink(_manager)
{ {
this.enabled = true; this.enabled = true;
this.visible = true;
this.actionId = ""; this.actionId = "";
this.actionObj = null; this.actionObj = null;
this.manager = _manager; this.manager = _manager;
@ -318,6 +320,11 @@ egwActionLink.prototype.set_enabled = function(_value)
this.enabled = _value; this.enabled = _value;
} }
egwActionLink.prototype.set_visible = function(_value)
{
this.visible = _value;
}
egwActionLink.prototype.set_actionId = function(_value) egwActionLink.prototype.set_actionId = function(_value)
{ {
this.actionId = _value; this.actionId = _value;
@ -327,27 +334,26 @@ egwActionLink.prototype.set_actionId = function(_value)
throw "Given action object does not exist!" throw "Given action object does not exist!"
} }
/** egwActionObject Object **/ /** egwActionObject Object **/
//State bitmask (only use powers of two for new states!) //State bitmask (only use powers of two for new states!)
const EGW_AO_STATE_NORMAL = 0x00; var EGW_AO_STATE_NORMAL = 0x00;
const EGW_AO_STATE_SELECTED = 0x01; var EGW_AO_STATE_SELECTED = 0x01;
const EGW_AO_STATE_FOCUSED = 0x02; var EGW_AO_STATE_FOCUSED = 0x02;
const EGW_AO_EVENT_DRAG_OVER_ENTER = 0x00; var EGW_AO_EVENT_DRAG_OVER_ENTER = 0x00;
const EGW_AO_EVENT_DRAG_OVER_LEAVE = 0x01; var EGW_AO_EVENT_DRAG_OVER_LEAVE = 0x01;
// No shift key is pressed // 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) // 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) // 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 // 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. // 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 * 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. * 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 // Get a flat list of all the hncp elements and search for this object
// and the object supplied in the _to parameter. // and the object supplied in the _to parameter.
var flatList = contRoot.flatList(); var flatList = contRoot.flatList();
var thisId = contRoot.indexOf(this); var thisId = flatList.indexOf(this);
var toId = contRoot.indexOf(_to); var toId = flatList.indexOf(_to);
// Check whether both elements have been found in this part of the tree, // Check whether both elements have been found in this part of the tree,
// return the slice of that list. // return the slice of that list.
@ -574,7 +600,7 @@ egwActionObject.prototype.traversePath = function(_to)
var from = Math.min(thisId, toId); var from = Math.min(thisId, toId);
var to = Math.max(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 //If the object is not focused, reset the focus state of all children
for (var i = 0; i < this.children.length; i++) 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); this.children[i].setFocused(false, _recPrev);
// } }
} }
} }
else else
@ -805,11 +831,12 @@ egwActionObject.prototype.updateActionLinks = function(_actionLinks, _recursive,
var elem = _actionLinks[i]; var elem = _actionLinks[i];
if (typeof elem.actionId != "undefined" && elem.actionId) 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); var actionLink = this.getActionLink(elem.actionId);
if (!actionLink && _doCreate) if (!actionLink && _doCreate)
{ {
actionLink = new egwActionLink(this.manager); actionLink = new egwActionLink(this.manager);
this.actionLinks.push(actionLink);
} }
//Set the supplied data //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 * Returns the action link, which contains the association to the action with
* the given actionId. * the given actionId.
@ -867,7 +1019,7 @@ egwActionObject.prototype.getActionImplementationGroups = function(_test, _group
for (var i = 0; i < this.actionLinks.length; i++) 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 action != "undefined" && _test(this))
{ {
if (typeof _groups[action.type] == "undefined") if (typeof _groups[action.type] == "undefined")

View File

@ -61,3 +61,25 @@ function egwBitIsSet(_set, _bit)
return (_set & _bit) > 0; 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;
};
}

View File

@ -18,15 +18,15 @@ var _egw_active_menu = null;
* in e.g. the egwMenu.addItem function. * 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) //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 //Preset the parameters
if (typeof _parent == "undefined") if (typeof _parent == "undefined")
_parent = null; _parent = null;
if (typeof _id == "undefined") if (typeof _id == "undefined")
_id = ""; _id = "";
if (typeof _label == "undefined") if (typeof _caption == "undefined")
_label = ""; _caption = "";
if (typeof _iconUrl == "undefined") if (typeof _iconUrl == "undefined")
_iconUrl = ""; _iconUrl = "";
if (typeof _onClick == "undefined") 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 //Create a menu item with no parent (null) and set the given parameters
var item = new egwMenuItem(_parent, _id); var item = new egwMenuItem(_parent, _id);
item.set_caption(_label); item.set_caption(_caption);
item.set_iconUrl(_iconUrl); item.set_iconUrl(_iconUrl);
item.set_onClick(_onClick); 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 * 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, * 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. * 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. * to "-" in order to create a sperator.
* @param string _iconUrl is the URL of the icon which should be prepended to the * @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. * 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 * @returns egwMenuItem the newly generated menu item, which had been appended to the
* menu item list. * 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 //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); this.children.push(item);
return item; return item;
@ -287,7 +287,8 @@ function egwMenuItem(_parent, _id)
this.enabled = true; this.enabled = true;
this.iconUrl = ""; this.iconUrl = "";
this.onClick = null; this.onClick = null;
this.default = false; this["default"] = false;
this.data = null;
this.children = []; this.children = [];
this.parent = _parent; this.parent = _parent;
@ -314,6 +315,32 @@ egwMenuItem.prototype.setGlobalOnClick = function(_onClick)
_egwSetMenuOnClick(this.children, _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 //Setter functions for the menuitem properties
egwMenuItem.prototype.set_id = function(_value) egwMenuItem.prototype.set_id = function(_value)
@ -371,7 +398,11 @@ egwMenuItem.prototype.set_iconUrl = function(_value)
egwMenuItem.prototype.set_default = function(_value) egwMenuItem.prototype.set_default = function(_value)
{ {
this.default = _value; this["default"] = _value;
} }
egwMenuItem.prototype.set_data = function(_value)
{
this.data = _value;
}

View File

@ -101,7 +101,7 @@ egwMenuImpl.prototype._translateStructure = function(_structure, _parentId, _idC
else else
{ {
var caption = elem.caption; var caption = elem.caption;
if (elem.default) if (elem["default"])
caption = "<b>" + caption + "</b>" caption = "<b>" + caption + "</b>"
this.dhtmlxmenu.addNewChild(_parentId, i, id, caption, !elem.enabled, this.dhtmlxmenu.addNewChild(_parentId, i, id, caption, !elem.enabled,
elem.iconUrl, elem.iconUrl); elem.iconUrl, elem.iconUrl);

View File

@ -1,9 +1,21 @@
<html> <html>
<head> <head>
<title>Test page for the egw action stuff</title> <title>Test page for the egw action stuff</title>
<!-- Basic action stuff -->
<script src="../egw_action.js"></script> <script src="../egw_action.js"></script>
<script src="../egw_action_common.js"></script> <script src="../egw_action_common.js"></script>
<script src="js/jquery.js"></script> <script src="js/jquery.js"></script>
<!-- Popup stuff -->
<link rel="stylesheet" type="text/css" href="skins/dhtmlxmenu_egw.css">
<script src="js/dhtmlxcommon.js"></script>
<script src="js/dhtmlxmenu.js"></script>
<script src="js/dhtmlxmenu_ext.js"></script>
<script src="../egw_action_popup.js"></script>
<script src="../egw_menu.js"></script>
<script src="../egw_menu_dhtmlx.js"></script>
<style> <style>
body, table { body, table {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
@ -11,7 +23,7 @@
} }
.listbox { .listbox {
width: 250px; width: 250px;
border: 1px solid gray; border: 2px groove gray;
margin: 5px; margin: 5px;
border-collapse: collapse; border-collapse: collapse;
} }
@ -24,34 +36,33 @@
padding: 2px; padding: 2px;
} }
.listbox .selected { .listbox tr.odd {
background-color: #eeeeee;
}
.listbox tr.selected {
background-color: #2b5d9b; background-color: #2b5d9b;
color: white; color: white;
} }
.listbox tr.odd.selected {
background-color: #234b7d !important;
}
.listbox .focused { .listbox .focused {
border: 1px dashed black; border: 1px dotted black;
padding: 2px; padding: 1px;
} }
</style> </style>
</head> </head>
<body> <body>
<table class="listbox" id="lb1"> <table class="listbox" id="lb1">
<tr id="le1"> <tr id="folder1"><td><img src="imgs/folder.png"/></td><td style="width: 200px">Folder 1</td><td><input type="checkbox"></td></tr>
<td><img src="imgs/page.png"/></td> <tr id="file1"><td><img src="imgs/page.png"/></td><td style="width: 200px">File 1</td><td><input type="checkbox"></td></tr>
<td style="width: 200px">File 1</td> <tr id="file2"><td><img src="imgs/page.png"/></td><td style="width: 200px">File 2</td><td><input type="checkbox"></td></tr>
<td><input type="checkbox"></td> <tr id="file3"><td><img src="imgs/page.png"/></td><td style="width: 200px">File 3</td><td><input type="checkbox"></td></tr>
</tr> <tr id="file4"><td><img src="imgs/page.png"/></td><td style="width: 200px">File 4</td><td><input type="checkbox"></td></tr>
<tr id="le2"> <tr id="file5"><td><img src="imgs/page.png"/></td><td style="width: 200px">File 5</td><td><input type="checkbox"></td></tr>
<td><img src="imgs/page.png"/></td>
<td style="width: 200px">File 2</td>
<td><input type="checkbox"></td>
</tr>
<tr id="le3">
<td><img src="imgs/page.png"/></td>
<td style="width: 200px">File 3</td>
<td><input type="checkbox"></td>
</tr>
</table> </table>
<script> <script>
var actionManager = null; var actionManager = null;
@ -69,11 +80,43 @@
aoi.node = _node; aoi.node = _node;
aoi.checkBox = ($(":checkbox", aoi.node))[0]; aoi.checkBox = ($(":checkbox", aoi.node))[0];
aoi.checkBox.checked = false;
aoi.doGetDOMNode = function() { aoi.doGetDOMNode = function() {
return self.node; return aoi.node;
} }
function getShiftState(e)
{
var state = EGW_AO_SHIFT_STATE_NONE;
state = egwSetBit(state, EGW_AO_SHIFT_STATE_MULTI, e.ctrkKey || e.metaKey);
state = egwSetBit(state, EGW_AO_SHIFT_STATE_BLOCK, e.shiftKey);
return state;
}
// Now append some action code to the node
$(_node).click(function(e) {
if (e.target != aoi.checkBox)
{
var selected = egwBitIsSet(aoi.getState(), EGW_AO_STATE_SELECTED);
var state = getShiftState(e);
// "Normal" Listbox behaviour
aoi.doSetState(egwSetBit(aoi.getState(), EGW_AO_STATE_SELECTED,
!egwBitIsSet(state, EGW_AO_SHIFT_STATE_MULTI) || !selected),
false, state);
// "PHPMyAdmin" Listbox behaviour
// aoi.doSetState(egwSetBit(aoi.getState(), EGW_AO_STATE_SELECTED,
// !selected), false, EGW_AO_SHIFT_STATE_MULTI);
}
});
$(aoi.checkBox).change(function() {
aoi.doSetState(egwSetBit(aoi.getState(), EGW_AO_STATE_SELECTED,
this.checked), false, EGW_AO_SHIFT_STATE_MULTI);
});
aoi.doSetState = function(_state, _outerCall, _shiftState) { aoi.doSetState = function(_state, _outerCall, _shiftState) {
var selected = egwBitIsSet(_state, EGW_AO_STATE_SELECTED); var selected = egwBitIsSet(_state, EGW_AO_STATE_SELECTED);
this.checkBox.checked = selected; this.checkBox.checked = selected;
@ -88,30 +131,18 @@
} }
} }
// Now append some action code to the node
$(_node).click(function(e) {
if (e.target != aoi.checkBox)
{
// "Normal" Listbox behaviour
// aoi.doSetState(egwSetBit(aoi.getState(), EGW_AO_STATE_SELECTED,
// true), false, EGW_AO_SHIFT_STATE_NONE);
// "PHPMyAdmin" Listbox behaviour
var selected = egwBitIsSet(aoi.getState(), EGW_AO_STATE_SELECTED);
aoi.doSetState(egwSetBit(aoi.getState(), EGW_AO_STATE_SELECTED,
!selected), false, EGW_AO_SHIFT_STATE_MULTI);
}
});
$(aoi.checkBox).change(function() {
aoi.doSetState(egwSetBit(aoi.getState(), EGW_AO_STATE_SELECTED,
this.checked), false, EGW_AO_SHIFT_STATE_MULTI);
});
return aoi; return aoi;
} }
function alertClicked(_action, _senders)
{
var ids = "";
for (var i = 0; i < _senders.length; i++)
ids += _senders[i].id + ((i < _senders.length - 1) ? ", " : "");
alert("Action '" + _action.caption + "' executed on elements '"
+ ids + "'");
}
function init() function init()
{ {
@ -121,22 +152,110 @@
actionManager.updateActions( actionManager.updateActions(
[ [
{
"id": "folder_open",
"iconUrl": "imgs/folder.png",
"caption": "Open folder",
"onExecute": alertClicked,
// "allowOnMultiple": false,
"type": "popup",
"default": true
},
{ {
"id": "file_view", "id": "file_view",
"icon": "imgs/view.png", "iconUrl": "imgs/view.png",
"caption": "View",
"onExecute": alertClicked,
"allowOnMultiple": false, "allowOnMultiple": false,
"caption": "Datei anzeigen" "type": "popup",
"default": true
},
{
"id": "file_preview",
"iconUrl": "imgs/preview.png",
"caption": "Preview",
"onExecute": alertClicked,
"allowOnMultiple": false,
"type": "popup",
"default": true
}, },
{ {
"id": "file_delete", "id": "file_delete",
"icon": "imgs/delete.png", "iconUrl": "imgs/delete.png",
"caption": "Datei löschen" "caption": "Delete",
"onExecute": alertClicked,
"type": "popup",
"group": 2
},
{
"id": "file_edit",
"iconUrl": "imgs/edit.png",
"caption": "Edit file",
"onExecute": alertClicked,
"allowOnMultiple": false,
"type": "popup"
},
{
"id": "file_compress",
"iconUrl": "imgs/compress.png",
"caption": "Create ZIP archive",
"onExecute": alertClicked,
"type": "popup",
"group": 1,
"order": 1
},
{
"id": "file_email",
"iconUrl": "imgs/email.png",
"caption": "E-Mail",
"onExecute": alertClicked,
"allowOnMultiple": false,
"type": "popup",
"group": 1,
"order": 0
},
{
"id": "file_compress_email",
"caption": "Create ZIP and E-Mail",
"onExecute": alertClicked,
"type": "popup",
"group": 1,
"order": 2
} }
] ]
); );
//Links which will be assigned to each listbox item
var listboxFileLinks = [
{"actionId": "file_view", "enabled": true},
{"actionId": "file_preview", "enabled": true},
{"actionId": "file_edit", "enabled": true},
{"actionId": "file_email", "enabled": true},
{"actionId": "file_compress_email", "enabled": true},
{"actionId": "file_compress", "enabled": true},
{"actionId": "file_delete", "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}
];
$('#lb1 tr:odd').addClass('odd');
//Create an object representation for each listbox-row and append
//each to its own listboxItemAOI
$('#lb1 tr').each(function(index, elem) { $('#lb1 tr').each(function(index, elem) {
objectManager.addObject(elem.id, new listboxItemAOI(elem)); var obj = objectManager.addObject(elem.id, new listboxItemAOI(elem));
//Apply the links to the actions
if (elem.id.substr(0,4) == "file")
obj.updateActionLinks(listboxFileLinks);
else
obj.updateActionLinks(listboxFolderLinks);
obj.registerActions();
}) })
} }
</script> </script>

View File

@ -163,7 +163,6 @@ function getPageXY(event)
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft :
document.documentElement.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)}; return {'x': (event.clientX + scrollLeft), 'y': (event.clientY + scrollTop)};
} }

View File

@ -91,8 +91,8 @@ function egw_json_encode(input)
var buf = []; var buf = [];
for (var k in input) for (var k in input)
{ {
//Filter the remove function, which is added to arrays in egw_fw_classes //Filter non numeric entries
if (k != 'remove') if (!isNaN(k))
buf.push(egw_json_encode(input[k])); buf.push(egw_json_encode(input[k]));
} }
return '[' + buf.join(',') + ']'; return '[' + buf.join(',') + ']';