forked from extern/egroupware
Implemented first version of key-board control over action-objects. For now arrow/page up/down and CTRL-A works.
Known Issues: - Keyboard navigation in egw_grids (like felamimail) may not work correctly when navigating to not-yet loaded items (current implementation for that is more a hack) - short-cuts not yet implemented - not tested in IE, Safari, FF 3.6 - felamimail sometimes loads all/many of the emails you were navigating over
This commit is contained in:
parent
49ece38c6c
commit
e03d416fda
@ -1027,7 +1027,8 @@ egwActionObject.prototype.getIndex = function()
|
||||
*/
|
||||
egwActionObject.prototype.getFocusedObject = function()
|
||||
{
|
||||
var cr = this.getContainerRoot();
|
||||
/*var cr = this.getContainerRoot();*/
|
||||
var cr = this.getRootObject();
|
||||
return cr ? cr.focusedChild : null;
|
||||
}
|
||||
|
||||
@ -1113,6 +1114,115 @@ egwActionObject.prototype._ifaceCallback = function(_newState, _changedBit, _shi
|
||||
return _newState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for key presses
|
||||
*/
|
||||
egwActionObject.prototype.handleKeyPress = function(_keyCode, _shift, _ctrl, _alt) {
|
||||
switch (_keyCode) {
|
||||
case EGW_KEY_ARROW_UP:
|
||||
case EGW_KEY_ARROW_DOWN:
|
||||
case EGW_KEY_PAGE_UP:
|
||||
case EGW_KEY_PAGE_DOWN:
|
||||
var intval =
|
||||
(_keyCode == EGW_KEY_ARROW_UP || _keyCode == EGW_KEY_ARROW_DOWN) ?
|
||||
1 : 10;
|
||||
|
||||
if (this.children.length > 0)
|
||||
{
|
||||
// Get the focused object
|
||||
var focused = this.getFocusedObject();
|
||||
|
||||
// Determine the object which should get selected
|
||||
var selObj = null;
|
||||
if (!focused)
|
||||
{
|
||||
selObj = this.children[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
selObj = (_keyCode == EGW_KEY_ARROW_UP || _keyCode == EGW_KEY_PAGE_UP) ?
|
||||
focused.getPrevious(intval) : focused.getNext(intval);
|
||||
}
|
||||
|
||||
if (selObj != null)
|
||||
{
|
||||
if (!_shift)
|
||||
{
|
||||
this.setAllSelected(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var objs = focused.traversePath(selObj);
|
||||
for (var i = 0; i < objs.length; i++)
|
||||
{
|
||||
objs[i].setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
selObj.setSelected(true);
|
||||
selObj.setFocused(true);
|
||||
|
||||
// Tell the aoi of the object to make it visible
|
||||
selObj.makeVisible();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Handle CTRL-A to select all elements in the current container
|
||||
case EGW_KEY_A:
|
||||
if (_ctrl)
|
||||
{
|
||||
this.setAllSelected(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
egwActionObject.prototype.getPrevious = function(_intval)
|
||||
{
|
||||
if (this.parent != null)
|
||||
{
|
||||
var idx = this.parent.children.indexOf(this);
|
||||
if (idx > 0)
|
||||
{
|
||||
idx = Math.max(0, idx - _intval);
|
||||
return this.parent.children[idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Implement traversal of trees
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
egwActionObject.prototype.getNext = function(_intval)
|
||||
{
|
||||
if (this.parent != null)
|
||||
{
|
||||
var idx = this.parent.children.indexOf(this);
|
||||
if (idx < this.parent.children.length - 1)
|
||||
{
|
||||
idx = Math.min(this.parent.children.length - 1, idx + _intval);
|
||||
return this.parent.children[idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Implement traversal of trees
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the object is currently selected.
|
||||
*/
|
||||
@ -1175,6 +1285,11 @@ egwActionObject.prototype.setFocused = function(_focused)
|
||||
this.parent.updateFocusedChild(this, _focused);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.focusedChild != null && _focused == false)
|
||||
{
|
||||
this.focusedChild.setFocused(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1289,7 +1404,7 @@ egwActionObject.prototype.updateFocusedChild = function(_child, _focused)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.parent && !egwBitIsSet(this.flags, EGW_AO_FLAG_IS_CONTAINER))
|
||||
if (this.parent /*&& !egwBitIsSet(this.flags, EGW_AO_FLAG_IS_CONTAINER)*/)
|
||||
{
|
||||
this.parent.updateFocusedChild(_child, _focused);
|
||||
}
|
||||
@ -1411,6 +1526,15 @@ egwActionObject.prototype.triggerCallback = function()
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the corresponding function of the AOI which tries to make the object
|
||||
* visible.
|
||||
*/
|
||||
egwActionObject.prototype.makeVisible = function()
|
||||
{
|
||||
this.iface.makeVisible();
|
||||
}
|
||||
|
||||
var EGW_AO_EXEC_SELECTED = 0;
|
||||
var EGW_AO_EXEC_THIS = 1;
|
||||
|
||||
@ -1660,6 +1784,8 @@ function egwActionObjectInterface()
|
||||
// or EGW_AI_DRAG_OUT
|
||||
this.doTriggerEvent = function(_event, _data) {return false;}
|
||||
|
||||
this.doMakeVisible = function() {};
|
||||
|
||||
this._state = EGW_AO_STATE_NORMAL || EGW_AO_STATE_VISIBLE;
|
||||
|
||||
this.stateChangeCallback = null;
|
||||
@ -1778,8 +1904,13 @@ egwActionObjectInterface.prototype.triggerEvent = function(_event, _data)
|
||||
return this.doTriggerEvent(_event, _data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Scrolls the element into a visble area if it is currently hidden
|
||||
*/
|
||||
egwActionObjectInterface.prototype.makeVisible = function()
|
||||
{
|
||||
return this.doMakeVisible();
|
||||
}
|
||||
|
||||
/** -- egwActionObjectDummyInterface Class -- **/
|
||||
|
||||
|
@ -445,8 +445,10 @@ egwGridDataElement.prototype.insertElement = function(_index, _id)
|
||||
null);
|
||||
element.index = _index;
|
||||
|
||||
// Create the action object
|
||||
var object = this.actionObject.insertObject(_index, _id, null, 0);
|
||||
// Create the action object with a temporary AOI which can be used to make
|
||||
// the object visible
|
||||
var object = this.actionObject.insertObject(_index, _id,
|
||||
new egwGridTmpAOI(this.getRootElement().gridObject, _index), 0);
|
||||
object.data = element;
|
||||
|
||||
// Link the two together
|
||||
|
@ -127,6 +127,8 @@ function egwGridViewOuter(_parentNode, _dataRoot, _selectColsCallback, _toggleAl
|
||||
// Insert the base grid container into the DOM-Tree
|
||||
this.grid = new egwGridViewGrid(null, null, true, this); // (No parent grid, no height change callback, scrollable)
|
||||
this.grid.insertIntoDOM(this.outer_tr, []);
|
||||
|
||||
this.dataRoot.gridObject = this.grid;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1435,6 +1437,7 @@ function egwGridViewRow_aoiSetup()
|
||||
this.aoi.row = this;
|
||||
this.aoi.doSetState = egwGridViewRow_aoiSetState;
|
||||
this.aoi.doTriggerEvent = egwGridViewRow_aoiTriggerEvent;
|
||||
this.aoi.doMakeVisible = egwGridViewRow_aoiMakeVisible;
|
||||
this.aoi.getDOMNode = egwGridViewRow_aoiGetDOMNode;
|
||||
}
|
||||
|
||||
@ -1473,6 +1476,11 @@ function egwGridViewRow_aoiTriggerEvent(_event, _data)
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewRow_aoiMakeVisible()
|
||||
{
|
||||
egwGridView_scrollToArea(this.row.grid.scrollarea, this.row.getArea());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actionObjectInterface object of this grid item.
|
||||
*/
|
||||
@ -2041,4 +2049,54 @@ function egwGridViewFullRow_doSetViewArea()
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary AOI which has to be assigned to invisible grid objects in order
|
||||
* to give them the possiblity to make them visible when using e.g. keyboard navigation
|
||||
*/
|
||||
function egwGridTmpAOI(_grid, _index)
|
||||
{
|
||||
var aoi = new egwActionObjectDummyInterface();
|
||||
|
||||
// Assign the make visible function
|
||||
aoi.grid = _grid;
|
||||
aoi.index = _index;
|
||||
aoi.doMakeVisible = egwGridTmpAOI_makeVisible;
|
||||
|
||||
return aoi;
|
||||
}
|
||||
|
||||
function egwGridTmpAOI_makeVisible()
|
||||
{
|
||||
// Assume an area for the element (this code is not optimal, but it should
|
||||
// work in most cases - problem is that the elements in the grid may have equal
|
||||
// sizes and the grid is scrolled to some area where the element is not)
|
||||
// TODO: Support for trees
|
||||
var avgHeight = this.grid.getOuter().avgRowHeight;
|
||||
var area = egwArea(this.index * avgHeight, avgHeight);
|
||||
|
||||
egwGridView_scrollToArea(this.grid.scrollarea, area);
|
||||
}
|
||||
|
||||
function egwGridView_scrollToArea(_scrollarea, _visarea)
|
||||
{
|
||||
// Get the current view area
|
||||
var va = egwArea(_scrollarea.scrollTop(), _scrollarea.height());
|
||||
|
||||
// Calculate the assumed position of this element
|
||||
var pos = _visarea;
|
||||
|
||||
// Check whether it is currently (completely) visible, if not scroll the
|
||||
// scroll area to that position
|
||||
if (!(pos.top >= va.top && pos.bottom <= va.bottom))
|
||||
{
|
||||
if (pos.top < va.top)
|
||||
{
|
||||
_scrollarea.scrollTop(pos.top);
|
||||
}
|
||||
else
|
||||
{
|
||||
_scrollarea.scrollTop(va.top + pos.bottom - va.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user