mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-08 09:05:16 +01:00
Got selection working; only problem left with popup menus is, that entries don't get focused on rightclick
This commit is contained in:
parent
b55250b81a
commit
0ae151e638
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
et2_dataview_interfaces;
|
et2_dataview_interfaces;
|
||||||
et2_dataview_controller_selection;
|
et2_dataview_controller_selection;
|
||||||
et2_dataview_view_aoi;
|
|
||||||
et2_dataview_view_row;
|
et2_dataview_view_row;
|
||||||
|
|
||||||
egw_action.egw_action;
|
egw_action.egw_action;
|
||||||
@ -64,7 +63,6 @@ var et2_dataview_controller = Class.extend({
|
|||||||
this._rowCallback = _rowCallback;
|
this._rowCallback = _rowCallback;
|
||||||
this._linkCallback = _linkCallback;
|
this._linkCallback = _linkCallback;
|
||||||
this._context = _context;
|
this._context = _context;
|
||||||
this._actionObjectManager = _actionObjectManager;
|
|
||||||
|
|
||||||
// Initialize the "index map" which contains all currently displayed
|
// Initialize the "index map" which contains all currently displayed
|
||||||
// containers hashed by the "index"
|
// containers hashed by the "index"
|
||||||
@ -81,13 +79,14 @@ var et2_dataview_controller = Class.extend({
|
|||||||
this._grid.setDataCallback(this._gridCallback, this);
|
this._grid.setDataCallback(this._gridCallback, this);
|
||||||
|
|
||||||
// Create the selection manager
|
// Create the selection manager
|
||||||
// this._selectionMgr = new et2_dataview_selectionManager(this._indexMap);
|
this._selectionMgr = new et2_dataview_selectionManager(this._indexMap,
|
||||||
|
_actionObjectManager, this._selectionFetchRange, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
|
|
||||||
// Destroy the selection manager
|
// Destroy the selection manager
|
||||||
// this._selectionMgr.free();
|
this._selectionMgr.free();
|
||||||
|
|
||||||
// Clear the selection timeout
|
// Clear the selection timeout
|
||||||
this._clearTimer();
|
this._clearTimer();
|
||||||
@ -171,8 +170,7 @@ var et2_dataview_controller = Class.extend({
|
|||||||
{
|
{
|
||||||
this._indexMap[_idx] = {
|
this._indexMap[_idx] = {
|
||||||
"row": null,
|
"row": null,
|
||||||
"uid": null,
|
"uid": null
|
||||||
"ao": null
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,30 +450,23 @@ var et2_dataview_controller = Class.extend({
|
|||||||
this.entry
|
this.entry
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we have an object manager, create a new action object for this
|
var links = null;
|
||||||
// row and a new row AOI
|
|
||||||
|
// Get the action links if the links callback is set
|
||||||
if (this.self._linkCallback)
|
if (this.self._linkCallback)
|
||||||
{
|
{
|
||||||
// Call the link callback
|
links = this.self._linkCallback.call(
|
||||||
var links = this.self._linkCallback.call(
|
this.self._context,
|
||||||
this.self._context,
|
_data,
|
||||||
_data,
|
this.entry.idx,
|
||||||
this.entry.idx,
|
this.entry.uid
|
||||||
this.entry.uid
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the action object interface
|
|
||||||
var aoi = new et2_dataview_rowAOI(tr);
|
|
||||||
|
|
||||||
// Create the action object
|
|
||||||
var ao = this.entry.ao =
|
|
||||||
this.self._actionObjectManager.addObject(this.entry.uid, aoi);
|
|
||||||
ao.updateActionLinks(links);
|
|
||||||
|
|
||||||
// Hook the row into the selection manager
|
|
||||||
// this.self._selectionMgr.hook(ao, aoi, this.entry.uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register the row in the selection manager
|
||||||
|
this.self._selectionMgr.registerRow(this.entry.uid, this.entry.idx,
|
||||||
|
tr, links);
|
||||||
|
|
||||||
// Invalidate the current row entry
|
// Invalidate the current row entry
|
||||||
this.entry.row.invalidate();
|
this.entry.row.invalidate();
|
||||||
}
|
}
|
||||||
@ -485,8 +476,13 @@ var et2_dataview_controller = Class.extend({
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_destroyCallback: function (_row) {
|
_destroyCallback: function (_row) {
|
||||||
// Remove the action object that corresponds to that row
|
|
||||||
this.entry.ao.remove();
|
// Unregister the row from the selection manager
|
||||||
|
if (this.entry.row)
|
||||||
|
{
|
||||||
|
var tr = this.entry.row.getDOMNode();
|
||||||
|
this.self._selectionMgr.unregisterRow(this.entry.uid, tr);
|
||||||
|
}
|
||||||
|
|
||||||
// There is no further row connected to the entry
|
// There is no further row connected to the entry
|
||||||
this.entry.row = null;
|
this.entry.row = null;
|
||||||
@ -621,6 +617,12 @@ var et2_dataview_controller = Class.extend({
|
|||||||
entry.idx = newIdx;
|
entry.idx = newIdx;
|
||||||
newMap[newIdx] = entry;
|
newMap[newIdx] = entry;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Make sure the old entry gets invalidated
|
||||||
|
entry.idx = null;
|
||||||
|
entry.row = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the new index map the current index map
|
// Make the new index map the current index map
|
||||||
@ -656,6 +658,16 @@ var et2_dataview_controller = Class.extend({
|
|||||||
|
|
||||||
// Update the total element count in the grid
|
// Update the total element count in the grid
|
||||||
this.self._grid.setTotalCount(_response.total);
|
this.self._grid.setTotalCount(_response.total);
|
||||||
|
},
|
||||||
|
|
||||||
|
_selectionFetchRange: function (_range, _callback, _context) {
|
||||||
|
this._dataProvider.dataFetch(
|
||||||
|
{ "start": _range.top, "num_rows": _range.bottom - _range.top + 1,
|
||||||
|
"no_data": true },
|
||||||
|
function (_response) {
|
||||||
|
_callback.call(_context, _response.order);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -10,21 +10,28 @@
|
|||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*egw:uses
|
||||||
|
et2_dataview_view_aoi;
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The selectioManager is internally used by the et2_dataview_controller class
|
* The selectioManager is internally used by the et2_dataview_controller class
|
||||||
* to manage the row selection.
|
* to manage the row selection.
|
||||||
*/
|
*/
|
||||||
var et2_dataview_selectionManager = Class.extend({
|
var et2_dataview_selectionManager = Class.extend({
|
||||||
|
|
||||||
init: function (_indexMap) {
|
init: function (_indexMap, _actionObjectManager, _queryRangeCallback,
|
||||||
// Copy the reference to the index map
|
_context) {
|
||||||
|
// Copy the arguments
|
||||||
this._indexMap = _indexMap;
|
this._indexMap = _indexMap;
|
||||||
|
this._actionObjectManager = _actionObjectManager;
|
||||||
|
this._queryRangeCallback = _queryRangeCallback;
|
||||||
|
this._context = _context;
|
||||||
|
|
||||||
// Internal map which contains all curently selected uids
|
// Internal map which contains all curently selected uids and their
|
||||||
this._selectedUids = {};
|
// state
|
||||||
|
this._registeredRows = {};
|
||||||
// Controls whether the selection is currently inverted (e.g. after
|
this._focusedEntry = null;
|
||||||
// selectAll)
|
|
||||||
this._invertSelection = false;
|
this._invertSelection = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -32,86 +39,247 @@ var et2_dataview_selectionManager = Class.extend({
|
|||||||
this._indexMap = _indexMap;
|
this._indexMap = _indexMap;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
registerRow: function (_uid, _idx, _tr, _links) {
|
||||||
* Resets the selection state of all selected elements.
|
|
||||||
*/
|
// Get the corresponding entry from the registered rows array
|
||||||
resetSelection: function () {
|
var entry = this._getRegisteredRowsEntry(_uid);
|
||||||
// Iterate over the index map and reset the selection flag of all rows
|
|
||||||
for (var key in this._indexMap)
|
// Create the AOI for the tr
|
||||||
|
if (!entry.tr)
|
||||||
{
|
{
|
||||||
if (this._indexMap[key].ao)
|
// Create the AOI which is used internally in the selection manager
|
||||||
|
// this AOI is not connected to the AO, as the selection manager
|
||||||
|
// cares about selection etc.
|
||||||
|
entry.aoi = new et2_dataview_rowAOI(_tr);
|
||||||
|
entry.aoi.setStateChangeCallback(
|
||||||
|
function (_newState, _changedBit, _shiftState) {
|
||||||
|
if (_changedBit === EGW_AO_STATE_SELECTED)
|
||||||
|
{
|
||||||
|
// Call the select handler
|
||||||
|
this._handleSelect(
|
||||||
|
_uid,
|
||||||
|
entry,
|
||||||
|
egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_BLOCK),
|
||||||
|
egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_MULTI)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Create AOI
|
||||||
|
if (_links)
|
||||||
{
|
{
|
||||||
this._indexMap[key].ao.setSelected(false);
|
var dummyAOI = new egwActionObjectInterface();
|
||||||
|
dummyAOI.getDOMNode = function () {return _tr};
|
||||||
|
|
||||||
|
// Create an action object for the tr and connect it to a dummy AOI
|
||||||
|
entry.ao = this._actionObjectManager.addObject(_uid, dummyAOI);
|
||||||
|
entry.ao.updateActionLinks(_links);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the internal representation and the inversion flag
|
// Update the entry
|
||||||
this._selectedUids = {};
|
entry.idx = _idx;
|
||||||
|
entry.tr = _tr;
|
||||||
|
|
||||||
|
// Update the visible state of the _tr
|
||||||
|
this._updateEntryState(entry, entry.state);
|
||||||
|
},
|
||||||
|
|
||||||
|
unregisterRow: function (_uid, _tr) {
|
||||||
|
if (typeof this._registeredRows[_uid] !== "undefined"
|
||||||
|
&& this._registeredRows[_uid].tr === _tr)
|
||||||
|
{
|
||||||
|
this._registeredRows[_uid].tr = null;
|
||||||
|
this._registeredRows[_uid].aoi = null;
|
||||||
|
|
||||||
|
// Remove the action object from its container
|
||||||
|
if (this._registeredRows[_uid].ao)
|
||||||
|
{
|
||||||
|
this._registeredRows[_uid].ao.remove();
|
||||||
|
this._registeredRows[_uid].ao = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._registeredRows[_uid].state === EGW_AO_STATE_NORMAL)
|
||||||
|
{
|
||||||
|
delete this._registeredRows[_uid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetSelection: function () {
|
||||||
this._invertSelection = false;
|
this._invertSelection = false;
|
||||||
|
|
||||||
|
for (var key in this._registeredRows)
|
||||||
|
{
|
||||||
|
this.setSelected(key, false);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
setSelected: function (_uid, _selected) {
|
||||||
* Marks the given uid as selected.
|
var entry = this._getRegisteredRowsEntry(_uid);
|
||||||
*/
|
this._updateEntryState(entry,
|
||||||
uidAddSelection: function (_uid) {
|
egwSetBit(entry.state, EGW_AO_STATE_SELECTED, _selected));
|
||||||
this._selectedUids[_uid] = true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
setFocused: function (_uid, _focused) {
|
||||||
* Removes the selection from the given uid.
|
// Reset the state of the currently focused entry
|
||||||
*/
|
if (this._focusedEntry)
|
||||||
uidRemoveSelection: function (_uid) {
|
{
|
||||||
delete this._selectedUids[_uid];
|
this._updateEntryState(this._focusedEntry,
|
||||||
|
egwSetBit(this._focusedEntry.state, EGW_AO_STATE_FOCUSED,
|
||||||
|
false));
|
||||||
|
this._focusedEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the new given uid as focused
|
||||||
|
if (_focused)
|
||||||
|
{
|
||||||
|
var entry = this._focusedEntry = this._getRegisteredRowsEntry(_uid);
|
||||||
|
this._updateEntryState(entry,
|
||||||
|
egwSetBit(entry.state, EGW_AO_STATE_FOCUSED, true));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
selectAll: function () {
|
||||||
* Returns whether the given uid is selected or not.
|
// Reset the selection
|
||||||
*/
|
this.resetSelection();
|
||||||
uidIsSelected: function (_uid) {
|
|
||||||
return (!this._invertSelection) ===
|
// Set the "invert selection" flag
|
||||||
(this._selectedUids[_uid] ? true : false);
|
this._invertSelection = true;
|
||||||
|
|
||||||
|
// Update the selection
|
||||||
|
for (var key in this._registeredRows)
|
||||||
|
{
|
||||||
|
var entry = this._registeredRows[key];
|
||||||
|
this._updateEntryState(entry, entry.state);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Hooks into the given action object / action object interface in order
|
|
||||||
* to handle selection.
|
|
||||||
*/
|
|
||||||
hook: function (_ao, _aoi, _uid) {
|
|
||||||
|
|
||||||
// Hook into the action object state change handler, as we need
|
/** -- PRIVATE FUNCTIONS -- **/
|
||||||
// our own selection code
|
|
||||||
// Big TODO: Remove the old selection handling code from
|
|
||||||
// egwAction once it is no longer used outside et2 applications
|
|
||||||
_aoi.setStateChangeCallback(
|
|
||||||
function (_newState, _changedBit, _shiftState) {
|
|
||||||
|
|
||||||
var selected = egwBitIsSet(_newState, EGW_AO_STATE_SELECTED);
|
|
||||||
|
|
||||||
// Deselect all other objects inside this container, if the "MULTI" shift-
|
_updateState: function (_uid, _state) {
|
||||||
// state is not set
|
var entry = this._getRegisteredRowsEntry(_uid);
|
||||||
if (!egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_MULTI))
|
|
||||||
{
|
this._updateEntryState(_entry, _state);
|
||||||
this.resetSelection();
|
|
||||||
|
return entry;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateEntryState: function (_entry, _state) {
|
||||||
|
|
||||||
|
// Update the state of the entry
|
||||||
|
_entry.state = _state;
|
||||||
|
|
||||||
|
if (this._invertSelection)
|
||||||
|
{
|
||||||
|
_state ^= EGW_AO_STATE_SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the state if it has changed
|
||||||
|
if ((_entry.aoi && _entry.aoi.getState() !== _state) || _entry.state != _state)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Update the visual state
|
||||||
|
if (_entry.aoi)
|
||||||
|
{
|
||||||
|
_entry.aoi.setState(_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the element if state was set to "NORMAL" and there is
|
||||||
|
// no tr
|
||||||
|
if (_state === EGW_AO_STATE_NORMAL && !_entry.tr)
|
||||||
|
{
|
||||||
|
delete this._registeredRows[_entry.uid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getRegisteredRowsEntry: function (_uid) {
|
||||||
|
if (typeof this._registeredRows[_uid] === "undefined")
|
||||||
|
{
|
||||||
|
this._registeredRows[_uid] = {
|
||||||
|
"uid": _uid,
|
||||||
|
"idx": null,
|
||||||
|
"state": EGW_AO_STATE_NORMAL,
|
||||||
|
"tr": null,
|
||||||
|
"aoi": null,
|
||||||
|
"ao": null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._registeredRows[_uid];
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleSelect: function (_uid, _entry, _shift, _ctrl) {
|
||||||
|
// If not "_ctrl" is set, reset the selection
|
||||||
|
if (!_ctrl)
|
||||||
|
{
|
||||||
|
this.resetSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the element that was clicked as selected
|
||||||
|
var entry = this._getRegisteredRowsEntry(_uid);
|
||||||
|
this.setSelected(_uid,
|
||||||
|
!_ctrl || !egwBitIsSet(entry.state, EGW_AO_STATE_SELECTED));
|
||||||
|
|
||||||
|
// Focus the element if shift is not pressed
|
||||||
|
if (!_shift)
|
||||||
|
{
|
||||||
|
this.setFocused(_uid, true);
|
||||||
|
}
|
||||||
|
else if (this._focusedEntry)
|
||||||
|
{
|
||||||
|
this._selectRange(this._focusedEntry.idx, _entry.idx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_selectRange: function (_start, _stop) {
|
||||||
|
// Contains ranges that are not currently in the index map and that have
|
||||||
|
// to be queried
|
||||||
|
var queryRanges = [];
|
||||||
|
|
||||||
|
// Iterate over the given range and select the elements in the range
|
||||||
|
// from _start to _stop
|
||||||
|
var naStart = false;
|
||||||
|
var s = Math.min(_start, _stop);
|
||||||
|
var e = Math.max(_stop, _start);
|
||||||
|
for (var i = s; i <= e; i++)
|
||||||
|
{
|
||||||
|
if (typeof this._indexMap[i] !== "undefined" &&
|
||||||
|
this._indexMap[i].uid)
|
||||||
|
{
|
||||||
|
// Add the range to the "queryRanges"
|
||||||
|
if (naStart !== false) {
|
||||||
|
queryRanges.push(et2_bounds(naStart, i - 1));
|
||||||
|
naStart = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the internal status of the uid
|
// Select the element
|
||||||
if (selected)
|
this.setSelected(this._indexMap[i].uid, true);
|
||||||
{
|
} else if (naStart === false) {
|
||||||
this.uidAddSelection(_uid);
|
naStart = i;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
this.uidRemoveSelection(_uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ao.setSelected(selected);
|
// Add the last range to the "queryRanges"
|
||||||
|
if (naStart !== false) {
|
||||||
|
queryRanges.push(et2_bounds(naStart, i - 1));
|
||||||
|
naStart = false;
|
||||||
|
}
|
||||||
|
|
||||||
return _newState;
|
// Query all unknown ranges from the server
|
||||||
|
for (var i = 0; i < queryRanges.length; i++)
|
||||||
}, this);
|
{
|
||||||
|
this._queryRangeCallback.call(this._context, queryRanges[i],
|
||||||
// Set the selection state of the ao
|
function (_order) {
|
||||||
_ao.setSelected(this.uidIsSelected(_uid));
|
for (var j = 0; j < _order.length; j++)
|
||||||
|
{
|
||||||
|
this.setSelected(_order[j], true);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
.egwGridView_grid tr.focused td {
|
.egwGridView_grid tr.focused td {
|
||||||
background-image: url(gfx/focused_hatching.png);
|
background-image: url(gfx/focused_hatching.png);
|
||||||
|
background-color: #ad98e8 !important;
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) {
|
|||||||
_filters,
|
_filters,
|
||||||
_widgetId,
|
_widgetId,
|
||||||
egw.dataKnownUIDs(_app),
|
egw.dataKnownUIDs(_app),
|
||||||
lastModification
|
_queriedRange["no_data"] ? 0xFFFFFFFFFFFF : lastModification
|
||||||
],
|
],
|
||||||
function(result) {
|
function(result) {
|
||||||
parseServerResponse(result, _callback, _context);
|
parseServerResponse(result, _callback, _context);
|
||||||
|
Loading…
Reference in New Issue
Block a user