mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 16:48:49 +01:00
Dynamic loading of content tested and optimized, resolved bugs, implemented support for data trees in the view classes. The whole progess can be seen in the test/test_grid_view.html file.
This commit is contained in:
parent
d7356a350f
commit
57aaf6d756
@ -395,8 +395,6 @@ function egwActionObject(_id, _parent, _iface, _manager, _flags)
|
||||
this.focusedChild = null;
|
||||
|
||||
this.setAOI(_iface);
|
||||
this.iface.setStateChangeCallback(this._ifaceCallback, this);
|
||||
this.iface.setReconnectActionsCallback(this._reconnectCallback, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,6 +416,8 @@ egwActionObject.prototype.setAOI = function(_aoi)
|
||||
|
||||
// Replace the interface object
|
||||
this.iface = _aoi;
|
||||
this.iface.setStateChangeCallback(this._ifaceCallback, this);
|
||||
this.iface.setReconnectActionsCallback(this._reconnectCallback, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -764,7 +764,7 @@ egwActionObject.prototype._ifaceCallback = function(_newState, _changedBit, _shi
|
||||
// and set their select state.
|
||||
if (egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_BLOCK))
|
||||
{
|
||||
var focused = this.getRootObject().getFocusedObject();
|
||||
var focused = this.getFocusedObject();
|
||||
if (focused)
|
||||
{
|
||||
objs = this.traversePath(focused);
|
||||
@ -915,7 +915,7 @@ egwActionObject.prototype.setAllSelected = function(_selected, _informParent)
|
||||
*/
|
||||
egwActionObject.prototype.updateSelectedChildren = function(_child, _selected)
|
||||
{
|
||||
var id = this.selectedChildren.indexOf(_child);
|
||||
var id = this.selectedChildren.indexOf(_child); // TODO Replace by binary search, insert children sorted by index!
|
||||
var wasEmpty = this.selectedChildren.length == 0;
|
||||
|
||||
// Add or remove the given child from the selectedChildren list
|
||||
|
@ -91,6 +91,7 @@ function egwGetShiftState(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;
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ function egwGridDataElement(_id, _parent, _columns, _readQueue, _objectManager)
|
||||
this.canHaveChildren = false;
|
||||
this.type = egwGridViewRow;
|
||||
this.userData = null;
|
||||
this.updatedGrid = null;
|
||||
|
||||
this.gridViewObj = null;
|
||||
}
|
||||
@ -132,7 +133,8 @@ egwGridDataElement.prototype.set_data = function(_value)
|
||||
|
||||
this.data[col_id] = {
|
||||
"data": data,
|
||||
"sortData": sortData
|
||||
"sortData": sortData,
|
||||
"queued": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,8 +170,13 @@ egwGridDataElement.prototype.set_data = function(_value)
|
||||
* "canHaveChildren": [true|false] // Specifies whether the row "open/close" button is displayed
|
||||
* }
|
||||
*/
|
||||
egwGridDataElement.prototype.loadData = function(_data)
|
||||
egwGridDataElement.prototype.loadData = function(_data, _doCallUpdate)
|
||||
{
|
||||
if (typeof _doCallUpdate == "undefined")
|
||||
{
|
||||
_doCallUpdate = false;
|
||||
}
|
||||
|
||||
if (_data.constructor == Array)
|
||||
{
|
||||
var virgin = this.children.length == 0;
|
||||
@ -197,6 +204,7 @@ egwGridDataElement.prototype.loadData = function(_data)
|
||||
{
|
||||
var count = typeof entry.count == "number" && entry.count >= 0 ? entry.count : 1;
|
||||
var prefix = typeof entry.prefix == "string" ? entry.prefix : "elem_";
|
||||
var canHaveChildren = typeof entry.canHaveChildren == "boolean" ? entry.canHaveChildren : false;
|
||||
var index = last_element ? last_element.index + 1 : 0;
|
||||
|
||||
for (var j = 0; j < count; j++)
|
||||
@ -204,6 +212,7 @@ egwGridDataElement.prototype.loadData = function(_data)
|
||||
var id = prefix + (index + j);
|
||||
element = this.insertElement(index + j, id);
|
||||
element.type = type; // Type can only be set directly after creation
|
||||
element.canHaveChildren = canHaveChildren;
|
||||
}
|
||||
}
|
||||
else if (entryType == EGW_DATA_TYPE_ELEMENT)
|
||||
@ -240,7 +249,12 @@ egwGridDataElement.prototype.loadData = function(_data)
|
||||
this.loadData(_data.children);
|
||||
}
|
||||
|
||||
this.gridViewObj.callGridViewObjectUpdate();
|
||||
if (_doCallUpdate)
|
||||
{
|
||||
this.callBeginUpdate();
|
||||
}
|
||||
|
||||
this.callGridViewObjectUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +342,7 @@ egwGridDataElement.prototype.getElementById = function(_id, _depth)
|
||||
{
|
||||
for (var i = 0; i < this.children.length; i++)
|
||||
{
|
||||
var elem = this.children.getElementById(_id, _depth - 1);
|
||||
var elem = this.children[i].getElementById(_id, _depth - 1);
|
||||
|
||||
if (elem)
|
||||
{
|
||||
@ -348,13 +362,13 @@ egwGridDataElement.prototype.getChildren = function(_callback, _context)
|
||||
{
|
||||
if (this.children.length > 0)
|
||||
{
|
||||
_callback.call(_context, this.children);
|
||||
_callback.call(_context, this.children, true);
|
||||
}
|
||||
else if (this.canHaveChildren)
|
||||
{
|
||||
// If the children havn't been loaded yet, request them via queue call.
|
||||
this.readQueue.queue(this, EGW_DATA_QUEUE_CHILDREN, function() {
|
||||
_callback.call(_context, this.children);
|
||||
this.readQueue.queueCall(this, EGW_DATA_QUEUE_CHILDREN, function() {
|
||||
_callback.call(_context, this.children, false);
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
@ -386,16 +400,21 @@ egwGridDataElement.prototype.hasColumn = function(_columnId, _returnData)
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_returnData && typeof (this.data[_columnId]) != "undefined" && this.data[_columnId].queued)
|
||||
{
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check whether the column data of this column has been read,
|
||||
// if yes, return it.
|
||||
if (typeof this.data[_columnIds] != "undefined")
|
||||
if (typeof this.data[_columnId] != "undefined")
|
||||
{
|
||||
if (_returnData)
|
||||
if (_returnData && typeof this.data[_columnId].data != "undefined")
|
||||
{
|
||||
res = this.data[_columnIds].data;
|
||||
res = this.data[_columnId].data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -456,7 +475,7 @@ egwGridDataElement.prototype.getData = function(_columnIds)
|
||||
// in the readQueue
|
||||
if (queryList.length > 0)
|
||||
{
|
||||
this.readQueue.queue(this, queryList);
|
||||
this.readQueue.queueCall(this, queryList);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -467,11 +486,16 @@ egwGridDataElement.prototype.getData = function(_columnIds)
|
||||
* Calls the row object update function - checks whether the row object implements
|
||||
* this interface and whether it is set.
|
||||
*/
|
||||
egwGridDataElement.prototype.callGridViewObjectUpdate = function()
|
||||
egwGridDataElement.prototype.callGridViewObjectUpdate = function(_immediate)
|
||||
{
|
||||
if (typeof _immediate == "undefined")
|
||||
{
|
||||
_immediate = false;
|
||||
}
|
||||
|
||||
if (this.gridViewObj && typeof this.gridViewObj.doUpdateData == "function")
|
||||
{
|
||||
this.gridViewObj.doUpdateData();
|
||||
this.gridViewObj.doUpdateData(_immediate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -516,7 +540,63 @@ egwGridDataElement.prototype.setGridViewObj = function(_obj)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root element
|
||||
*/
|
||||
egwGridDataElement.prototype.getRootElement = function()
|
||||
{
|
||||
if (!this.parent)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.parent.getRootElement();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the depth of this element in the document tree
|
||||
*/
|
||||
egwGridDataElement.prototype.getDepth = function()
|
||||
{
|
||||
return (this.parent) ? (this.parent.getDepth() + 1) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the beginUpdate function of the grid associated to the grid view object
|
||||
*/
|
||||
egwGridDataElement.prototype.callBeginUpdate = function()
|
||||
{
|
||||
if (this.gridViewObj)
|
||||
{
|
||||
var root = this.getRootElement();
|
||||
|
||||
if (root.updatedGrid != this.gridViewObj.grid)
|
||||
{
|
||||
if (root.updatedGrid)
|
||||
{
|
||||
root.updatedGrid.endUpdate();
|
||||
}
|
||||
root.updatedGrid = this.gridViewObj.grid;
|
||||
root.updatedGrid.beginUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the end update function of the currently active updated grid
|
||||
*/
|
||||
egwGridDataElement.prototype.callEndUpdate = function()
|
||||
{
|
||||
var root = this.getRootElement();
|
||||
|
||||
if (root.updatedGrid)
|
||||
{
|
||||
root.updatedGrid.endUpdate();
|
||||
root.updatedGrid = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** - egwGridDataReadQueue -- **/
|
||||
@ -558,27 +638,56 @@ egwGridDataQueue.prototype.setDataRoot = function(_dataRoot)
|
||||
*/
|
||||
egwGridDataQueue.prototype._queue = function(_obj)
|
||||
{
|
||||
this.timeoutId++;
|
||||
|
||||
// Push the queue object onto the queue
|
||||
this.queue.push(_obj);
|
||||
|
||||
if (this.queue.length > EGW_DATA_QUEUE_MAX_ELEM_COUNT)
|
||||
{
|
||||
this.flushQueue();
|
||||
this.flushQueue(false);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Specify that the element data is queued
|
||||
for (var i = 0; i < this.queueColumns.length; i++)
|
||||
{
|
||||
if (typeof _obj.elem.data[this.queueColumns[i]] == "undefined")
|
||||
{
|
||||
_obj.elem.data[this.queueColumns[i]] = {
|
||||
"queued": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the flush queue timeout
|
||||
var tid = this.timeoutId;
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
if (self.timeoutId == tid)
|
||||
{
|
||||
self.flushQueue(true);
|
||||
}
|
||||
}, EGW_DATA_QUEUE_FLUSH_TIMEOUT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
egwGridDataQueue.prototype.inQueue = function(_elem)
|
||||
egwGridDataQueue.prototype._accumulateQueueColumns = function(_columns)
|
||||
{
|
||||
for (var i = 0; i < this.queue.length; i++)
|
||||
if (this.dataRoot.columns.columns.length > this.queueColumns.length)
|
||||
{
|
||||
if (this.queue[i].elem == _elem)
|
||||
// Merge the specified columns into the queueColumns variable
|
||||
for (var i = 0; i < _columns.length; i++)
|
||||
{
|
||||
return true;
|
||||
if (this.queueColumns.indexOf(_columns[i]) == -1)
|
||||
{
|
||||
this.queueColumns.push(_columns[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -594,7 +703,7 @@ egwGridDataQueue.prototype.inQueue = function(_elem)
|
||||
* @param object _context is the context in which the callback function will
|
||||
* be executed.
|
||||
*/
|
||||
egwGridDataQueue.prototype.queue = function(_elem, _columns, _callback, _context)
|
||||
egwGridDataQueue.prototype.queueCall = function(_elem, _columns, _callback, _context)
|
||||
{
|
||||
if (typeof _callback == "undefined")
|
||||
{
|
||||
@ -610,7 +719,7 @@ egwGridDataQueue.prototype.queue = function(_elem, _columns, _callback, _context
|
||||
if (!this._queue({
|
||||
"elem": _elem,
|
||||
"type": EGW_DATA_QUEUE_CHILDREN,
|
||||
"proc": _callback,
|
||||
"callback": _callback,
|
||||
"context": _context
|
||||
}))
|
||||
{
|
||||
@ -619,73 +728,125 @@ egwGridDataQueue.prototype.queue = function(_elem, _columns, _callback, _context
|
||||
}
|
||||
else
|
||||
{
|
||||
// Merge the specified columns into the queueColumns variable
|
||||
for (var i = 0; i < _columns.length; i++)
|
||||
{
|
||||
if (this.queueColumns.indexOf(_columns[i]) == -1)
|
||||
{
|
||||
this.queueColumns.push(_columns[i]);
|
||||
}
|
||||
}
|
||||
// Accumulate the queue columns ids
|
||||
this._accumulateQueueColumns(_columns);
|
||||
|
||||
// Queue the element and search in the elements around the given one for
|
||||
// elements whose data isn't loaded yet.
|
||||
var done = !this._queue({
|
||||
this._queue({
|
||||
"elem": _elem,
|
||||
"type": EGW_DATA_QUEUE_ELEM,
|
||||
"proc": _callback,
|
||||
"callback": _callback,
|
||||
"context": _context
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Prefetch other elements around the given element
|
||||
var parent = _elem.parent;
|
||||
if (parent)
|
||||
egwGridDataQueue.prototype._getQueuePlanes = function()
|
||||
{
|
||||
// Initialize the start prefetch index and the max prefetch count
|
||||
var prefetch = EGW_DATA_QUEUE_PREFETCH_COUNT;
|
||||
var idx = Math.floor(Math.max(0, _elem.index - prefetch / 2));
|
||||
var planes = [];
|
||||
var curPlane = null;
|
||||
|
||||
while (!done && prefetch > 0 && idx < parent.children.length)
|
||||
for (var i = 0; i < this.queue.length; i++)
|
||||
{
|
||||
var elem = this.queue[i].elem;
|
||||
|
||||
// Don't prefetch the element itself
|
||||
if (idx != _elem.idx)
|
||||
if (!curPlane || elem.parent != curPlane.parent)
|
||||
{
|
||||
// Fetch the element with the current index from the children
|
||||
// of the parent of the element.
|
||||
var elem = parent.children[idx];
|
||||
|
||||
// Check whether this element has all data columns loaded and is
|
||||
// not already in the queue
|
||||
if (!this.inQueue(elem))
|
||||
curPlane = null;
|
||||
for (var j = 0; j < planes.length; j++)
|
||||
{
|
||||
var hasColumns = true;
|
||||
for (var j = 0; j < this.queueColumns.length; j++)
|
||||
if (planes[j].parent == elem.parent)
|
||||
{
|
||||
var res = elem.hasColumn(this.queueColumns[i], false);
|
||||
if (!res)
|
||||
{
|
||||
hasColumns = false;
|
||||
curPlane = planes[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasColumns)
|
||||
if (!curPlane)
|
||||
{
|
||||
done = !this._queue({
|
||||
"elem": elem,
|
||||
"type": EGW_DATA_QUEUE_ELEM,
|
||||
"proc": null,
|
||||
"context": null
|
||||
});
|
||||
prefetch--;
|
||||
}
|
||||
curPlane = {
|
||||
"parent": elem.parent,
|
||||
"cnt": 0,
|
||||
"min": 0,
|
||||
"max": 0,
|
||||
"idx": 0,
|
||||
"done": false
|
||||
};
|
||||
planes.push(curPlane);
|
||||
}
|
||||
}
|
||||
|
||||
idx++;
|
||||
if (curPlane.cnt == 0 || elem.index < curPlane.min)
|
||||
{
|
||||
curPlane.min = elem.index;
|
||||
}
|
||||
if (curPlane.cnt == 0 || elem.index > curPlane.max)
|
||||
{
|
||||
curPlane.max = elem.index;
|
||||
}
|
||||
|
||||
curPlane.cnt++;
|
||||
}
|
||||
|
||||
return planes;
|
||||
}
|
||||
|
||||
egwGridDataQueue.prototype.prefetch = function(_cnt)
|
||||
{
|
||||
var cnt = _cnt;
|
||||
var planes = this._getQueuePlanes();
|
||||
|
||||
// Set the start indices
|
||||
for (var i = 0; i < planes.length; i++)
|
||||
{
|
||||
planes[i].idx = Math.max(0, Math.ceil(planes[i].min - _cnt / (2 * planes.length)));
|
||||
}
|
||||
|
||||
// Add as many elements as specified to the prefetched elements
|
||||
var done = 0;
|
||||
var plane = 0;
|
||||
while (cnt > 0 && done < planes.length)
|
||||
{
|
||||
if (!planes[plane].done)
|
||||
{
|
||||
var idx = planes[plane].idx;
|
||||
|
||||
if (idx == planes[plane].parent.children.length)
|
||||
{
|
||||
planes[plane].done = true;
|
||||
done++;
|
||||
}
|
||||
else
|
||||
{
|
||||
var hasData = true;
|
||||
var elem = planes[plane].parent.children[idx];
|
||||
for (var j = 0; j < this.queueColumns.length; j++)
|
||||
{
|
||||
if (!elem.hasColumn(this.queueColumns[i], false))
|
||||
{
|
||||
hasData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasData)
|
||||
{
|
||||
this._queue({
|
||||
"elem": elem,
|
||||
"type": EGW_DATA_QUEUE_ELEM,
|
||||
"callback": null,
|
||||
"context": null
|
||||
});
|
||||
cnt--;
|
||||
}
|
||||
|
||||
planes[plane].idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the next plane
|
||||
plane = (plane + 1) % planes.length;
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,14 +854,32 @@ egwGridDataQueue.prototype.queue = function(_elem, _columns, _callback, _context
|
||||
* Empties the queue and calls the fetch callback which cares about retrieving
|
||||
* the data from the server.
|
||||
*/
|
||||
egwGridDataQueue.prototype.flushQueue = function()
|
||||
egwGridDataQueue.prototype.flushQueue = function(_doPrefetch)
|
||||
{
|
||||
var ids = [];
|
||||
|
||||
if (_doPrefetch)
|
||||
{
|
||||
// Get the count of elements which will be dynamically added to the list, "prefetched"
|
||||
var prefetch_cnt = Math.min(EGW_DATA_QUEUE_PREFETCH_COUNT,
|
||||
Math.max(0, EGW_DATA_QUEUE_MAX_ELEM_COUNT - this.queue.length));
|
||||
|
||||
this.prefetch(prefetch_cnt);
|
||||
}
|
||||
|
||||
// Generate a list of element ids
|
||||
for (var i = 0; i < this.queue.length; i++)
|
||||
{
|
||||
ids.push(this.queue[i].elem.id);
|
||||
var id = this.queue[i].elem.id;
|
||||
if (id == this.queue[i].elem.id)
|
||||
{
|
||||
if (this.queue[i].type == EGW_DATA_QUEUE_CHILDREN)
|
||||
{
|
||||
id = "[CHILDREN]" + id;
|
||||
}
|
||||
}
|
||||
|
||||
ids.push(id);
|
||||
}
|
||||
|
||||
// Call the fetch callback and save a snapshot of the current queue
|
||||
@ -711,16 +890,19 @@ egwGridDataQueue.prototype.flushQueue = function()
|
||||
|
||||
this.queue = [];
|
||||
this.queueColumns = [];
|
||||
this.timeoutId = 0;
|
||||
}
|
||||
|
||||
egwGridDataQueue.prototype.dataCallback = function(_data, _queue)
|
||||
{
|
||||
var rootData = [];
|
||||
|
||||
try
|
||||
{
|
||||
// Iterate over the given data and check whether the data coresponds to one
|
||||
// of the queue elements - if yes, call their (probably) specified callback.
|
||||
// All elements for which no queue element can be found are added to the
|
||||
// "rootData" list, which is then loaded by the "dataRoot" data object.
|
||||
var i = 0;
|
||||
for (var i = 0; i < _data.length; i++)
|
||||
{
|
||||
var hasTarget = false;
|
||||
@ -734,8 +916,7 @@ egwGridDataQueue.prototype.dataCallback = function(_data, _queue)
|
||||
{
|
||||
if (_queue[j].elem.id == id)
|
||||
{
|
||||
// The element has been found, update its data
|
||||
_queue[j].elem.loadData(_data[i]);
|
||||
_queue[j].elem.loadData(_data[i], true);
|
||||
|
||||
// Call the queue object callback (if specified)
|
||||
if (_queue[j].callback)
|
||||
@ -744,7 +925,7 @@ egwGridDataQueue.prototype.dataCallback = function(_data, _queue)
|
||||
}
|
||||
|
||||
// Delete this queue element
|
||||
_queue.splice(i, 1);
|
||||
_queue.splice(j, 1);
|
||||
|
||||
hasTarget = true;
|
||||
break;
|
||||
@ -754,10 +935,15 @@ egwGridDataQueue.prototype.dataCallback = function(_data, _queue)
|
||||
|
||||
if (!hasTarget)
|
||||
{
|
||||
rootData.push(_queue[i]);
|
||||
rootData.push(_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.dataRoot.loadData(rootData);
|
||||
this.dataRoot.loadData(rootData, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.dataRoot.callEndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ function egwGridViewOuter(_parentNode, _dataRoot)
|
||||
this.scrollbarWidth = Math.max(10, this.getScrollbarWidth());
|
||||
|
||||
// Start value for the average row height
|
||||
this.avgRowHeight = 23.0;
|
||||
this.avgRowHeight = 19.0;
|
||||
this.avgRowCnt = 1;
|
||||
|
||||
// Insert the base grid container into the DOM-Tree
|
||||
@ -121,6 +121,19 @@ egwGridViewOuter.prototype.addHeightToAvg = function(_value)
|
||||
this.avgRowHeight = this.avgRowHeight * (1 - frac) + _value * frac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the height from the average container height
|
||||
*/
|
||||
egwGridViewOuter.prototype.remHeightFromAvg = function(_value)
|
||||
{
|
||||
if (this.avgRowCnt > 1)
|
||||
{
|
||||
var sum = this.avgRowHeight * this.avgRowCnt - _value;
|
||||
this.avgRowCnt--;
|
||||
this.avgRowCount = sum / this.avgRowCnt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all containers from the base grid and replaces it with spacers again.
|
||||
* As only partial data is displayed, this method is faster than updating every
|
||||
@ -287,6 +300,8 @@ function egwGridViewContainer(_grid, _heightChangeProc)
|
||||
this.assumedHeight = false;
|
||||
this.index = 0;
|
||||
this.viewArea = false;
|
||||
this.containerClass = "";
|
||||
this.heightInAvg = false;
|
||||
|
||||
this.doInsertIntoDOM = null;
|
||||
this.doSetViewArea = null;
|
||||
@ -323,7 +338,10 @@ egwGridViewContainer.prototype.setVisible = function(_visible, _force)
|
||||
|
||||
// While the element has been invisible, the viewarea might have changed,
|
||||
// so check it now
|
||||
if (this.visible)
|
||||
{
|
||||
this.checkViewArea();
|
||||
}
|
||||
|
||||
// As the element is now (in)visible, its height has changed. Inform the
|
||||
// parent about it.
|
||||
@ -514,8 +532,10 @@ function egwGridViewGrid(_grid, _heightChangeProc, _scrollable, _outer)
|
||||
container.scrollable = _scrollable;
|
||||
container.scrollHeight = 100;
|
||||
container.scrollEvents = 0;
|
||||
container.inUpdate = 0;
|
||||
container.didUpdate = false;
|
||||
container.updateIndex = 0;
|
||||
container.triggerID = 0;
|
||||
container.setupContainer = egwGridViewGrid_setupContainer;
|
||||
container.insertContainer = egwGridViewGrid_insertContainer;
|
||||
container.removeContainer = egwGridViewGrid_removeContainer;
|
||||
@ -526,8 +546,12 @@ function egwGridViewGrid(_grid, _heightChangeProc, _scrollable, _outer)
|
||||
container.empty = egwGridViewGrid_empty;
|
||||
container.getOuter = egwGridViewGrid_getOuter;
|
||||
container.updateAssumedHeights = egwGridViewGrid_updateAssumedHeights;
|
||||
container.beginUpdate = egwGridViewGrid_beginUpdate;
|
||||
container.endUpdate = egwGridViewGrid_endUpdate;
|
||||
container.triggerUpdateAssumedHeights = egwGridViewGrid_triggerUpdateAssumedHeights;
|
||||
container.children = [];
|
||||
container.outer = _outer;
|
||||
container.containerClass = "grid";
|
||||
|
||||
// Overwrite the abstract container interface functions
|
||||
container.invalidateHeightCache = egwGridViewGrid_invalidateHeightCache;
|
||||
@ -538,6 +562,67 @@ function egwGridViewGrid(_grid, _heightChangeProc, _scrollable, _outer)
|
||||
return container;
|
||||
}
|
||||
|
||||
function egwGridViewGrid_beginUpdate()
|
||||
{
|
||||
if (this.inUpdate == 0)
|
||||
{
|
||||
this.didUpdate = false;
|
||||
|
||||
if (this.grid)
|
||||
{
|
||||
this.grid.beginUpdate();
|
||||
}
|
||||
}
|
||||
this.inUpdate++;
|
||||
}
|
||||
|
||||
function egwGridViewGrid_triggerUpdateAssumedHeights()
|
||||
{
|
||||
this.triggerID++;
|
||||
var self = this;
|
||||
var id = this.triggerID;
|
||||
window.setTimeout(function() {
|
||||
if (id = self.triggerID)
|
||||
{
|
||||
self.triggerID = 0;
|
||||
self.updateAssumedHeights(20);
|
||||
}
|
||||
},
|
||||
EGW_GRID_UPDATE_HEIGHTS_TIMEOUT);
|
||||
}
|
||||
|
||||
function egwGridViewGrid_endUpdate(_recPrev)
|
||||
{
|
||||
if (typeof _recPrev == "undefined")
|
||||
{
|
||||
_recPrev = false;
|
||||
}
|
||||
|
||||
if (this.inUpdate > 0)
|
||||
{
|
||||
this.inUpdate--;
|
||||
|
||||
if (this.inUpdate == 0 && this.grid)
|
||||
{
|
||||
this.grid.endUpdate();
|
||||
}
|
||||
|
||||
if (this.inUpdate == 0 && this.didUpdate)
|
||||
{
|
||||
// If an update has been done, check whether any height assumptions have been
|
||||
// done. This procedure is executed with some delay, as this gives the browser
|
||||
// the time to insert the newly generated objects into the DOM-Tree and allows
|
||||
// us to read their height at a very fast rate.
|
||||
if (this.didUpdate && !_recPrev)
|
||||
{
|
||||
this.triggerUpdateAssumedHeights();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.didUpdate = false;
|
||||
}
|
||||
|
||||
function egwGridViewGrid_getOuter()
|
||||
{
|
||||
if (this.outer)
|
||||
@ -571,6 +656,7 @@ function egwGridViewGrid_setupContainer()
|
||||
*/
|
||||
|
||||
this.outerNode = $(document.createElement("td"));
|
||||
this.outerNode.addClass("frame");
|
||||
|
||||
if (this.scrollable)
|
||||
{
|
||||
@ -623,7 +709,6 @@ function egwGridViewGrid_scrollCallback(_event)
|
||||
var area = egwArea(this.scrollarea.scrollTop() - EGW_GRID_VIEW_EXT,
|
||||
this.scrollHeight + EGW_GRID_VIEW_EXT * 2);
|
||||
|
||||
// Set view area sets the "didUpdate" variable to false
|
||||
this.setViewArea(area);
|
||||
|
||||
this.scrollEvents = 0;
|
||||
@ -638,7 +723,7 @@ function egwGridViewGrid_updateAssumedHeights(_maxCount)
|
||||
|
||||
try
|
||||
{
|
||||
this.inUpdate = true;
|
||||
this.beginUpdate();
|
||||
|
||||
while (traversed < this.children.length && cnt > 0)
|
||||
{
|
||||
@ -658,7 +743,16 @@ function egwGridViewGrid_updateAssumedHeights(_maxCount)
|
||||
var oldHeight = child.assumedHeight;
|
||||
child.invalidateHeightCache();
|
||||
var newHeight = child.getHeight();
|
||||
|
||||
if (child.containerClass == "row")
|
||||
{
|
||||
if (child.heightInAvg)
|
||||
{
|
||||
outer.remHeightFromAvg(oldHeight);
|
||||
}
|
||||
outer.addHeightToAvg(newHeight);
|
||||
child.heightInAvg = true;
|
||||
}
|
||||
|
||||
// Offset the position of all following elements by the delta.
|
||||
var delta = newHeight - oldHeight;
|
||||
@ -682,7 +776,7 @@ function egwGridViewGrid_updateAssumedHeights(_maxCount)
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.inUpdate = false;
|
||||
this.endUpdate(true);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
@ -690,9 +784,7 @@ function egwGridViewGrid_updateAssumedHeights(_maxCount)
|
||||
if (cnt == 0)
|
||||
{
|
||||
// If the maximum-update-count has been exhausted, retrigger this function
|
||||
window.setTimeout(function() {
|
||||
self.updateAssumedHeights(_maxCount);
|
||||
}, EGW_GRID_UPDATE_HEIGHTS_TIMEOUT);
|
||||
this.triggerUpdateAssumedHeights();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -705,6 +797,9 @@ function egwGridViewGrid_updateAssumedHeights(_maxCount)
|
||||
}
|
||||
|
||||
function egwGridViewGrid_insertContainer(_after, _class, _params)
|
||||
{
|
||||
this.beginUpdate();
|
||||
try
|
||||
{
|
||||
this.didUpdate = true;
|
||||
|
||||
@ -713,7 +808,7 @@ function egwGridViewGrid_insertContainer(_after, _class, _params)
|
||||
var idx = this.children.length;
|
||||
if (typeof _after == "number")
|
||||
{
|
||||
idx = Math.max(-1, Math.min(this.children.length, _after)) + 1;
|
||||
idx = Math.min(this.children.length, Math.max(-1, _after)) + 1;
|
||||
}
|
||||
else if (typeof _after == "object" && _after)
|
||||
{
|
||||
@ -746,7 +841,7 @@ function egwGridViewGrid_insertContainer(_after, _class, _params)
|
||||
|
||||
// Offset the position of all following elements by the height of the container
|
||||
// and move the index of those elements
|
||||
var height = this.getOuter().avgRowHeight; //container.getHeight(); // This took a lot of time.
|
||||
var height = this.getOuter().avgRowHeight;
|
||||
container.assumedHeight = height;
|
||||
for (var i = idx + 1; i < this.children.length; i++)
|
||||
{
|
||||
@ -756,11 +851,22 @@ function egwGridViewGrid_insertContainer(_after, _class, _params)
|
||||
|
||||
return container;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.endUpdate();
|
||||
}
|
||||
|
||||
this.callHeightChangeProc();
|
||||
}
|
||||
|
||||
function egwGridViewGrid_removeContainer(_container)
|
||||
{
|
||||
this.didUpdate = true;
|
||||
|
||||
try
|
||||
{
|
||||
this.beginUpdate();
|
||||
|
||||
var idx = _container.index;
|
||||
|
||||
// Offset the position of the folowing children back
|
||||
@ -780,6 +886,13 @@ function egwGridViewGrid_removeContainer(_container)
|
||||
|
||||
this.children.splice(idx, 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.endUpdate();
|
||||
}
|
||||
|
||||
this.callHeightChangeProc();
|
||||
}
|
||||
|
||||
function egwGridViewGrid_empty(_newColumns)
|
||||
{
|
||||
@ -807,6 +920,7 @@ function egwGridViewGrid_invalidateHeightCache(_children)
|
||||
}
|
||||
|
||||
this.height = false;
|
||||
this.assumedHeight = false;
|
||||
|
||||
if (_children)
|
||||
{
|
||||
@ -837,17 +951,17 @@ function egwGridViewGrid_heightChangeHandler(_elem)
|
||||
{
|
||||
this.didUpdate = true;
|
||||
|
||||
// Get the height-change
|
||||
// The old height of the element is now only an assumed height - the next
|
||||
// time the "updateAssumedHeights" functions is triggered, this will be
|
||||
// updated.
|
||||
var oldHeight = _elem.assumedHeight !== false ? _elem.assumedHeight :
|
||||
(_elem.height === false ? 0 : _elem.height);
|
||||
(_elem.height === false ? this.getOuter().avgRowHeight : _elem.height);
|
||||
_elem.invalidateHeightCache(false);
|
||||
var newHeight = _elem.getHeight();
|
||||
var offs = newHeight - oldHeight;
|
||||
_elem.assumedHeight = oldHeight;
|
||||
|
||||
// Set the offset of all elements succeding the given element correctly
|
||||
for (var i = _elem.index + 1; i < this.children.length; i++)
|
||||
if (_elem.containerClass == "grid" && !this.inUpdate)
|
||||
{
|
||||
this.children[i].offsetPosition(offs);
|
||||
this.triggerUpdateAssumedHeights();
|
||||
}
|
||||
|
||||
// As a result of the height of one of the children, the height of this element
|
||||
@ -864,8 +978,13 @@ function egwGridViewGrid_doInsertIntoDOM()
|
||||
this.outerNode.attr("colspan", this.columns.length + (this.scrollable ? 1 : 0));
|
||||
}
|
||||
|
||||
function egwGridViewGrid_doSetviewArea(_area)
|
||||
function egwGridViewGrid_doSetviewArea(_area, _recPrev)
|
||||
{
|
||||
if (typeof _recPrev == "undefined")
|
||||
{
|
||||
_recPrev == false;
|
||||
}
|
||||
|
||||
// Do a binary search for elements which are inside the given area
|
||||
this.didUpdate = false;
|
||||
var elem = null;
|
||||
@ -927,7 +1046,9 @@ function egwGridViewGrid_doSetviewArea(_area)
|
||||
}
|
||||
}
|
||||
|
||||
this.inUpdate = true;
|
||||
try
|
||||
{
|
||||
this.beginUpdate();
|
||||
|
||||
// Call the setViewArea function of visible child elements
|
||||
// Imporant: The setViewArea function has to work on a copy of children,
|
||||
@ -937,19 +1058,10 @@ function egwGridViewGrid_doSetviewArea(_area)
|
||||
{
|
||||
elems[i].setViewArea(_area, true);
|
||||
}
|
||||
|
||||
this.inUpdate = false;
|
||||
|
||||
// If an update has been done, check whether any height assumptions have been
|
||||
// done. This procedure is executed with some delay, as this gives the browser
|
||||
// the time to insert the newly generated objects into the DOM-Tree and allows
|
||||
// us to read their height at a very fast rate.
|
||||
if (this.didUpdate)
|
||||
}
|
||||
finally
|
||||
{
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
self.updateAssumedHeights(20);
|
||||
}, EGW_GRID_UPDATE_HEIGHTS_TIMEOUT);
|
||||
this.endUpdate(_recPrev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -968,10 +1080,17 @@ function egwGridViewRow(_grid, _heightChangeProc, _item)
|
||||
container.aoiSetup = egwGridViewRow_aoiSetup;
|
||||
container.getAOI = egwGridViewRow_getAOI;
|
||||
container.checkOdd = egwGridViewRow_checkOdd;
|
||||
container._columnClick = egwGridViewRow__columnClick;
|
||||
container.setOpen = egwGridViewRow_setOpen;
|
||||
container.tdObjects = [];
|
||||
container.containerClass = "row";
|
||||
container.childGrid = null;
|
||||
container.opened = false;
|
||||
|
||||
// Overwrite the inherited abstract functions
|
||||
container.doInsertIntoDOM = egwGridViewRow_doInsertIntoDOM;
|
||||
container.doSetViewArea = egwGridViewRow_doSetViewArea;
|
||||
container.doUpdateData = egwGridViewRow_doUpdateData;
|
||||
|
||||
return container;
|
||||
}
|
||||
@ -1015,6 +1134,16 @@ function egwGridViewRow_getAOI()
|
||||
return this.aoi;
|
||||
}
|
||||
|
||||
function egwGridViewRow__columnClick(_shiftState, _column)
|
||||
{
|
||||
var state = this.aoi.getState();
|
||||
var isSelected = egwBitIsSet(state, EGW_AO_STATE_SELECTED);
|
||||
|
||||
this.aoi.updateState(EGW_AO_STATE_SELECTED,
|
||||
!egwBitIsSet(_shiftState, EGW_AO_SHIFT_STATE_MULTI) || !isSelected,
|
||||
_shiftState);
|
||||
}
|
||||
|
||||
var
|
||||
EGW_GRID_VIEW_ROW_BORDER = false;
|
||||
|
||||
@ -1032,26 +1161,25 @@ function egwGridViewRow_doInsertIntoDOM()
|
||||
// Check whether this element is odd
|
||||
this.checkOdd();
|
||||
|
||||
// Read the column data
|
||||
/*var ids = [];
|
||||
for (var i = 0; i < this.columns.length; i++)
|
||||
{
|
||||
ids.push(this.columns[i].id);
|
||||
}
|
||||
|
||||
data = this.item.getData(ids);*/
|
||||
|
||||
for (var i = 0; i < this.columns.length; i++)
|
||||
{
|
||||
var col = this.columns[i];
|
||||
var td = $(document.createElement("td"));
|
||||
|
||||
//if (typeof data[this.columns[i].id] != "undefined")
|
||||
{
|
||||
td.html("col" + i);
|
||||
}
|
||||
this.parentNode.append(td);
|
||||
|
||||
// Assign the click event to the column
|
||||
td.mousedown(egwPreventSelect);
|
||||
td.click({"item": this, "col": col.id}, function(e) {
|
||||
this.onselectstart = null;
|
||||
e.data.item._columnClick(egwGetShiftState(e), e.data.col);
|
||||
});
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
td.addClass("first");
|
||||
}
|
||||
|
||||
// Set the column width
|
||||
if (EGW_GRID_VIEW_ROW_BORDER === false)
|
||||
{
|
||||
@ -1059,11 +1187,117 @@ function egwGridViewRow_doInsertIntoDOM()
|
||||
}
|
||||
td.css("width", col.drawnWidth - EGW_GRID_VIEW_ROW_BORDER);
|
||||
|
||||
// Store the column in the td object array
|
||||
this.tdObjects.push({
|
||||
"col": col,
|
||||
"td": td
|
||||
});
|
||||
}
|
||||
|
||||
this.doUpdateData(true);
|
||||
|
||||
this.checkViewArea();
|
||||
}
|
||||
|
||||
function egwGridViewRow_doUpdateData(_immediate)
|
||||
{
|
||||
var ids = [];
|
||||
for (var i = 0; i < this.columns.length; i++)
|
||||
{
|
||||
ids.push(this.columns[i].id);
|
||||
}
|
||||
|
||||
data = this.item.getData(ids);
|
||||
|
||||
for (var i = 0; i < this.tdObjects.length; i++)
|
||||
{
|
||||
var td = this.tdObjects[i].td;
|
||||
var col = this.tdObjects[i].col;
|
||||
if (typeof data[col.id] != "undefined")
|
||||
{
|
||||
td.empty();
|
||||
if (col.type == EGW_COL_TYPE_NAME_ICON_FIXED)
|
||||
{
|
||||
// Insert the indentation spacer
|
||||
var depth = this.item.getDepth() - 1;
|
||||
if (depth > 0)
|
||||
{
|
||||
// Build the indentation object
|
||||
var indentation = $(document.createElement("span"));
|
||||
indentation.addClass("indentation");
|
||||
indentation.css("width", (depth * 12) + "px");
|
||||
td.append(indentation);
|
||||
}
|
||||
|
||||
// Insert the open/close arrow
|
||||
if (this.item.canHaveChildren)
|
||||
{
|
||||
var arrow = $(document.createElement("span"));
|
||||
arrow.addClass("arrow");
|
||||
arrow.addClass(this.item.opened ? "opened" : "closed");
|
||||
arrow.click(this, function(e) {
|
||||
$this = $(this);
|
||||
|
||||
if (!e.data.opened)
|
||||
{
|
||||
$this.addClass("opened");
|
||||
$this.removeClass("closed");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this.addClass("closed");
|
||||
$this.removeClass("opened");
|
||||
}
|
||||
|
||||
e.data.setOpen(!e.data.opened);
|
||||
});
|
||||
td.append(arrow);
|
||||
}
|
||||
|
||||
// Insert the icon
|
||||
if (data[col.id].iconUrl)
|
||||
{
|
||||
// Build the icon element
|
||||
var icon = $(document.createElement("img"));
|
||||
icon.attr("src", data[col.id].iconUrl);
|
||||
icon.load(this, function(e) {
|
||||
e.data.callHeightChangeProc();
|
||||
});
|
||||
icon.addClass("icon");
|
||||
td.append(icon);
|
||||
}
|
||||
|
||||
// Build the caption
|
||||
if (data[col.id].caption)
|
||||
{
|
||||
var caption = $(document.createElement("span"));
|
||||
caption.html(data[col.id].caption);
|
||||
td.append(caption);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
td.html(data[col.id]);
|
||||
}
|
||||
td.toggleClass("queued", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
td.toggleClass("queued", true);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the open state
|
||||
this.setOpen(this.item.opened);
|
||||
|
||||
// If the call is not from inside the doInsertIntoDOM function, we have to
|
||||
// inform the parent about a possible height change
|
||||
if (!_immediate)
|
||||
{
|
||||
this.callHeightChangeProc();
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewRow_checkOdd()
|
||||
{
|
||||
if (this.item && this.parentNode)
|
||||
@ -1084,6 +1318,44 @@ function egwGridViewRow_doSetViewArea()
|
||||
this.checkOdd();
|
||||
}
|
||||
|
||||
function egwGridViewRow_setOpen(_open)
|
||||
{
|
||||
if (_open != this.opened)
|
||||
{
|
||||
if (_open)
|
||||
{
|
||||
if (!this.childGrid)
|
||||
{
|
||||
// Get the arrow and put it to "loading" state
|
||||
var arrow = $(".arrow", this.parentNode);
|
||||
arrow.removeClass("closed");
|
||||
arrow.addClass("loading");
|
||||
|
||||
// Create the "child grid"
|
||||
this.childGrid = this.grid.insertContainer(this.index, egwGridViewGrid,
|
||||
false);
|
||||
this.childGrid.setVisible(false);
|
||||
var spacer = this.childGrid.insertContainer(-1, egwGridViewSpacer,
|
||||
this.grid.getOuter().avgRowHeight);
|
||||
this.item.getChildren(function(_children) {
|
||||
arrow.removeClass("loading");
|
||||
arrow.removeClass("closed");
|
||||
arrow.addClass("opened");
|
||||
spacer.setItemList(_children);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.childGrid)
|
||||
{
|
||||
this.childGrid.setVisible(_open);
|
||||
}
|
||||
|
||||
this.opened = _open;
|
||||
this.item.opend = _open;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** -- egwGridViewSpacer Class -- **/
|
||||
|
||||
@ -1138,6 +1410,8 @@ function egwGridViewSpacer_doInsertIntoDOM()
|
||||
* creates those.
|
||||
*/
|
||||
function egwGridViewSpacer_doSetViewArea()
|
||||
{
|
||||
if (this.items.length > 0)
|
||||
{
|
||||
var avgHeight = this.grid.getOuter().avgRowHeight;
|
||||
|
||||
@ -1159,7 +1433,8 @@ function egwGridViewSpacer_doSetViewArea()
|
||||
this.grid.insertContainer(idx - 1, it_mid[i].type, it_mid[i]);
|
||||
}
|
||||
|
||||
// If top was greater than 0, insert a new spacer in front of the
|
||||
// If top was greater than 0, insert a new spacer in front of the newly
|
||||
// created elements.
|
||||
if (it_top.length > 0)
|
||||
{
|
||||
var spacer = this.grid.insertContainer(idx - 1, egwGridViewSpacer, avgHeight);
|
||||
@ -1177,5 +1452,6 @@ function egwGridViewSpacer_doSetViewArea()
|
||||
this.grid.removeContainer(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,6 +14,26 @@ body, td, th {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.egwGridView_outer td.queued {
|
||||
background-image: url(imgs/ajax-loader.gif);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
height: 19px;
|
||||
}
|
||||
|
||||
.egwGridView_grid tr.focused td {
|
||||
background-image: url(imgs/focused_hatching.png);
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
.egwGridView_grid tr.selected td {
|
||||
background-color: #b7c3ff;
|
||||
}
|
||||
|
||||
.egwGridView_grid tr.selected.odd td {
|
||||
background-color: #9dadff;
|
||||
}
|
||||
|
||||
.egwGridView_scrollarea {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
@ -37,16 +57,71 @@ body, td, th {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.egwGridView_grid td, .egwGridView_grid tr {
|
||||
.egwGridView_grid td {
|
||||
border-right: 1px solid silver;
|
||||
padding: 4px 3px 4px 4px;
|
||||
padding: 2px 3px 2px 4px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.egwGridView_grid tr {
|
||||
padding: 2px 3px 2px 4px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.egwGridView_grid tr.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.egwGridView_grid tr.odd {
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
.egwGridView_grid span.indentation {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.egwGridView_grid span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.egwGridView_grid img.icon {
|
||||
vertical-align: middle;
|
||||
margin: 2px 5px 2px 2px;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.egwGridView_grid span.arrow {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-repeat: no-repeat;
|
||||
margin-right: 2px;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.egwGridView_grid span.arrow.opened {
|
||||
cursor: pointer;
|
||||
background-image: url(imgs/arrows.png);
|
||||
background-position: -8px 0;
|
||||
}
|
||||
|
||||
.egwGridView_grid span.arrow.closed {
|
||||
cursor: pointer;
|
||||
background-image: url(imgs/arrows.png);
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.egwGridView_grid span.arrow.loading {
|
||||
cursor: pointer;
|
||||
background-image: url(imgs/ajax-loader.gif);
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.egwGridView_outer thead th {
|
||||
background-color: #E0E0E0;
|
||||
font-weight: normal;
|
||||
@ -66,32 +141,6 @@ body, td, th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
.grid_outer {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.grid_outer div.scrollarea {
|
||||
overflow: auto;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.grid_outer td, .grid_outer tr {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.horizontal_spacer {
|
||||
display: block;
|
||||
background-image: url(imgs/non_loaded_bg.png);
|
||||
background-position: top left;
|
||||
}
|
||||
|
||||
.selectcols {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
@ -104,99 +153,9 @@ body, td, th {
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.grid {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
.frame {
|
||||
padding: 0 !important;
|
||||
border-right: 0 none silver !important;
|
||||
}
|
||||
|
||||
|
||||
.grid th.optcol {
|
||||
width: 6px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid tr.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.grid td, .grid th {
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.grid tr.focused td {
|
||||
border: 1px dotted black;
|
||||
}
|
||||
|
||||
.grid tr.selected td {
|
||||
background-image: url(imgs/select_overlay.png);
|
||||
background-position: center;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.grid span.arrow {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-repeat: no-repeat;
|
||||
margin-right: 2px;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.grid span.arrow.opened {
|
||||
cursor: pointer;
|
||||
background-image: url(imgs/arrows.png);
|
||||
background-position: -8px 0;
|
||||
}
|
||||
|
||||
.grid span.arrow.closed {
|
||||
cursor: pointer;
|
||||
background-image: url(imgs/arrows.png);
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.grid tr.odd {
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
.grid th {
|
||||
background-color: #E0E0E0;
|
||||
font-weight: normal;
|
||||
padding: 5px;
|
||||
text-align: left;
|
||||
border-left: 1px solid silver;
|
||||
border-top: 1px solid silver;
|
||||
border-right: 1px solid gray;
|
||||
border-bottom: 1px solid gray;
|
||||
background-image: url(imgs/header_overlay.png);
|
||||
background-position: center;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.grid td {
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.grid th.front {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.grid span.caption {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.grid span.indentation {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.grid img.icon {
|
||||
vertical-align: middle;
|
||||
margin: 2px 5px 2px 2px;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
BIN
phpgwapi/js/egw_action/test/imgs/ajax-loader.gif
Normal file
BIN
phpgwapi/js/egw_action/test/imgs/ajax-loader.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
phpgwapi/js/egw_action/test/imgs/focused_hatching.png
Normal file
BIN
phpgwapi/js/egw_action/test/imgs/focused_hatching.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 202 B |
169
phpgwapi/js/egw_action/test/imgs/focused_hatching.svg
Normal file
169
phpgwapi/js/egw_action/test/imgs/focused_hatching.svg
Normal file
@ -0,0 +1,169 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32"
|
||||
height="32"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="focused_hatching.svg"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/focused_hatching.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="7.9195959"
|
||||
inkscape:cx="8.8135677"
|
||||
inkscape:cy="16.76308"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="823"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2985"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1020.3622)">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M -2,34 34,-2"
|
||||
id="path2987"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M -2,30 30,-2"
|
||||
id="path2989"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M 26,-2 -2,26"
|
||||
id="path2991"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M 22,-2 -2,22"
|
||||
id="path2993"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M 18,-2 -2,18"
|
||||
id="path2995"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M -2,14 14,-2"
|
||||
id="path2997"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M 10,-2 -2,10"
|
||||
id="path2999"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M -2,6 6,-2"
|
||||
id="path3001"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M 2,-2 -2,2"
|
||||
id="path3003"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M 34,2 2,34"
|
||||
id="path3005"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M 6,34 34,6"
|
||||
id="path3007"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M 34,10 10,34"
|
||||
id="path3009"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M 14,34 34,14"
|
||||
id="path3011"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="M 34,18 18,34"
|
||||
id="path3013"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="M 22,34 34,22"
|
||||
id="path3015"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.05801105"
|
||||
d="m 34,26 -8,8"
|
||||
id="path3017"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.18232045"
|
||||
d="m 30,34 4,-4"
|
||||
id="path3019"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,1020.3622)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
@ -17,7 +17,8 @@
|
||||
<link rel="stylesheet" href="grid.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test for dynamically displaying and loading grid lines (0,1 Mio Entries)</h1>
|
||||
<h1>Test for dynamically displaying and loading grid lines</h1>
|
||||
<b>Simulates network trafic by using window.setTimeout(), 100ms network latency</b>
|
||||
<div id="container"></div>
|
||||
<script>
|
||||
var grid = null;
|
||||
@ -27,8 +28,9 @@
|
||||
var columns =
|
||||
[
|
||||
{
|
||||
"id": "name",
|
||||
"caption": "Name",
|
||||
"width": "33%",
|
||||
"width": "20%",
|
||||
"type": EGW_COL_TYPE_NAME_ICON_FIXED
|
||||
},
|
||||
{
|
||||
@ -37,8 +39,7 @@
|
||||
},
|
||||
{
|
||||
"id": "rights",
|
||||
"caption": "UNIX Filerights",
|
||||
"default": "---------"
|
||||
"caption": "UNIX Filerights"
|
||||
},
|
||||
{
|
||||
"id": "mime",
|
||||
@ -46,29 +47,81 @@
|
||||
},
|
||||
{
|
||||
"id": "atime",
|
||||
"caption": "atime"
|
||||
"caption": "atime",
|
||||
"width": "15%"
|
||||
},
|
||||
{
|
||||
"id": "ctime",
|
||||
"caption": "ctime"
|
||||
"caption": "ctime",
|
||||
"width": "15%"
|
||||
},
|
||||
{
|
||||
"id": "mtime",
|
||||
"caption": "mtime"
|
||||
"caption": "mtime",
|
||||
"width": "15%"
|
||||
},
|
||||
{
|
||||
"id": "owner",
|
||||
"caption": "owner"
|
||||
"caption": "owner",
|
||||
"width": "10%"
|
||||
},
|
||||
{
|
||||
"id": "group",
|
||||
"caption": "group"
|
||||
"caption": "group",
|
||||
"width": "10%"
|
||||
}
|
||||
];
|
||||
|
||||
function fetchDataProc(_elems, _columns)
|
||||
function fetchDataProc(_elems, _columns, _callback, _context)
|
||||
{
|
||||
console.log("Fetch Data Proc: ", _elems, _columns);
|
||||
// Delay the result a bit to simulate real network traffic
|
||||
window.setTimeout(function() {
|
||||
var result = [];
|
||||
for (var i = 0; i < _elems.length; i++)
|
||||
{
|
||||
// console.log(_elems[i]);
|
||||
if (_elems[i].substr(0, "[CHILDREN]".length) == "[CHILDREN]")
|
||||
{
|
||||
var id = _elems[i].substr("[CHILDREN]".length);
|
||||
var children = [
|
||||
{
|
||||
"entryType": EGW_DATA_TYPE_RANGE,
|
||||
"prefix": id + "_child_",
|
||||
"canHaveChildren": true,
|
||||
"count": 20
|
||||
}
|
||||
];
|
||||
|
||||
result.push({
|
||||
"id": id,
|
||||
"children": children,
|
||||
"opened": true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = {};
|
||||
|
||||
data["size"] = Math.floor(Math.random() * 1024) + "KiB";
|
||||
data["rights"] = "rwxr-xr--";
|
||||
data["mime"] = "image/png";
|
||||
data["atime"] = (new Date).toUTCString();
|
||||
data["mtime"] = (new Date).toUTCString();
|
||||
data["ctime"] = (new Date).toUTCString();
|
||||
data["owner"] = "as";
|
||||
data["group"] = "stylitedevs";
|
||||
|
||||
result.push({
|
||||
"id": _elems[i],
|
||||
"data": data,
|
||||
"caption": _elems[i],
|
||||
"iconUrl": "imgs/folder.png"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_callback.call(_context, result);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
@ -82,11 +135,12 @@
|
||||
{
|
||||
"entryType": EGW_DATA_TYPE_RANGE,
|
||||
"prefix": "root_elem_",
|
||||
"count": 100000
|
||||
"canHaveChildren": true,
|
||||
"count": 10000
|
||||
}
|
||||
]
|
||||
);
|
||||
grid.resize(1500, 650);
|
||||
grid.resize(1500, 500);
|
||||
});
|
||||
|
||||
function check_positions()
|
||||
|
Loading…
Reference in New Issue
Block a user