forked from extern/egroupware
Implemented framework for dynamically inserting grid rows into the DOM tree and a very simple test for it
This commit is contained in:
parent
b0b4c8bf6a
commit
dd8a8eab45
@ -104,9 +104,27 @@ function egwPreventSelect(e)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function egwResetPreventSelect(elem)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
function egwCallAbstract(_obj, _fn, _args)
|
||||
{
|
||||
if (_fn)
|
||||
{
|
||||
return _fn.apply(_obj, _args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "egw_action Exception: Abstract function call in JS code.";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
792
phpgwapi/js/egw_action/egw_grid_view.js
Normal file
792
phpgwapi/js/egw_action/egw_grid_view.js
Normal file
@ -0,0 +1,792 @@
|
||||
/**
|
||||
* eGroupWare egw_action framework - egw action framework
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Andreas Stöckel <as@stylite.de>
|
||||
* @copyright 2011 by Andreas Stöckel
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package egw_action
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* View Classes for the egw grid component.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Common functions used in all classes
|
||||
*/
|
||||
|
||||
function egwArea(_top, _height)
|
||||
{
|
||||
return {
|
||||
"top": _top,
|
||||
"bottom": _top + _height
|
||||
}
|
||||
}
|
||||
|
||||
function egwAreaIntersect(_ar1, _ar2)
|
||||
{
|
||||
return ! (_ar1.bottom < _ar2.top || _ar1.top > _ar2.bottom);
|
||||
}
|
||||
|
||||
function egwAreaIntersectDir(_ar1, _ar2)
|
||||
{
|
||||
if (_ar1.bottom < _ar2.top)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (_ar1.top > _ar2.bottom)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** -- egwGridViewOuter Class -- **/
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
function egwGridViewOuter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** -- egwGridViewContainer Interface -- **/
|
||||
|
||||
/**
|
||||
* Constructor for the abstract egwGridViewContainer class. A grid view container
|
||||
* represents a chunk of data which is inserted into a grid. As the grid itself
|
||||
* is a container, hirachical structures can be realised. All containers are inserted
|
||||
* into the DOM tree directly after creation.
|
||||
*
|
||||
* @param object _grid is the parent grid this container is inserted into.
|
||||
*/
|
||||
function egwGridViewContainer(_grid, _heightChangeProc)
|
||||
{
|
||||
this.grid = _grid;
|
||||
this.visible = true;
|
||||
this.position = 0;
|
||||
this.heightChangeProc = _heightChangeProc;
|
||||
this.parentNode = null;
|
||||
this.columns = [];
|
||||
this.height = false;
|
||||
this.index = 0;
|
||||
this.viewArea = false;
|
||||
|
||||
this.doInsertIntoDOM = null;
|
||||
this.doUpdateColumns = null;
|
||||
this.doSetViewArea = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the heightChangeProc (if set) in the context of the parent grid (if set)
|
||||
*/
|
||||
egwGridViewContainer.prototype.callHeightChangeProc = function()
|
||||
{
|
||||
if (this.heightChangeProc && this.grid)
|
||||
{
|
||||
// Pass this element as parameter
|
||||
this.heightChangeProc.call(this.grid, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of the container. Setting the visibility only takes place
|
||||
* if the parentNode is set and the visible state has changed or the _force
|
||||
* parameter is set to true.
|
||||
*/
|
||||
egwGridViewContainer.prototype.setVisible = function(_visible, _force)
|
||||
{
|
||||
// Default the _force parameter to force
|
||||
if (typeof _force == "undefined")
|
||||
{
|
||||
_force = false;
|
||||
}
|
||||
|
||||
if ((_visible != this.visible || _force) && this.parentNode)
|
||||
{
|
||||
$(this.parentNode).toggleClass("hidden", !_visible);
|
||||
|
||||
// While the element has been invisible, the viewarea might have changed,
|
||||
// so check it now
|
||||
this.checkViewArea();
|
||||
|
||||
// As the element is now (in)visible, its height has changed. Inform the
|
||||
// parent about it.
|
||||
this.callHeightChangeProc();
|
||||
}
|
||||
|
||||
this.visible = _visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the container is visible. The element is not visible as long
|
||||
* as it isn't implemented into the DOM-Tree.
|
||||
*/
|
||||
egwGridViewContainer.prototype.getVisible = function()
|
||||
{
|
||||
return this.parentNode && this.visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the container into the given _parentNode. This method may only be
|
||||
* called once after the creation of the container.
|
||||
*
|
||||
* @param object _parentNode is the parentDOM-Node into which the container should
|
||||
* be inserted.
|
||||
* @param array _columns is an array of columns which will be generated
|
||||
*/
|
||||
egwGridViewContainer.prototype.insertIntoDOM = function(_parentNode, _columns)
|
||||
{
|
||||
if (_parentNode && !this.parentNode)
|
||||
{
|
||||
// Copy the function arguments
|
||||
this.columns = _columns;
|
||||
this.parentNode = $(_parentNode);
|
||||
|
||||
// Call the interface function of the implementation which will insert its data
|
||||
// into the parent node.
|
||||
return egwCallAbstract(this, this.doInsertIntoDOM, arguments);
|
||||
|
||||
this.setVisible(this.visible);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "egw_action Exception: egwGridViewContainer::insertIntoDOM called more than once for a container object or parent node not specified.";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.updateColumns = function(_columns)
|
||||
{
|
||||
this.columns = _columns;
|
||||
if (_parentNode)
|
||||
{
|
||||
return egwCallAbstract(this, this.doUpdateColumns, arguments);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.setViewArea = function(_area, _force)
|
||||
{
|
||||
// Calculate the relative coordinates and pass those to the implementation
|
||||
var relArea = {
|
||||
"top": _area.top - this.position,
|
||||
"bottom": _area.bottom - this.position
|
||||
};
|
||||
|
||||
this.viewArea = relArea;
|
||||
|
||||
this.checkViewArea(_force);
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.getViewArea = function()
|
||||
{
|
||||
if (this.viewArea && this.visible)
|
||||
{
|
||||
return this.viewArea;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.setPosition = function(_top)
|
||||
{
|
||||
// Recalculate the relative view area
|
||||
if (this.viewArea)
|
||||
{
|
||||
var at = this.position + this.viewArea.top;
|
||||
this.viewArea = {
|
||||
"top": at - _top,
|
||||
"bottom": at - _top + (this.viewArea.bottom - this.viewArea.top)
|
||||
};
|
||||
|
||||
this.checkViewArea();
|
||||
}
|
||||
|
||||
this.position = _top;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the height of the container in pixels and zero if the element is not
|
||||
* visible. The height is clamped to positive values.
|
||||
*/
|
||||
egwGridViewContainer.prototype.getHeight = function()
|
||||
{
|
||||
if (this.visible && this.parentNode)
|
||||
{
|
||||
if (this.height === false)
|
||||
{
|
||||
this.height = this.parentNode.outerHeight();
|
||||
}
|
||||
return this.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.invalidateHeightCache = function()
|
||||
{
|
||||
this.height = false;
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.offsetPosition = function(_offset)
|
||||
{
|
||||
this.position += _offset;
|
||||
|
||||
// Offset the view area in the oposite direction
|
||||
if (this.viewArea)
|
||||
{
|
||||
this.viewArea.top -= _offset;
|
||||
this.viewArea.bottom -= _offset;
|
||||
|
||||
this.checkViewArea();
|
||||
}
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.inArea = function(_area)
|
||||
{
|
||||
return egwAreaIntersect(this.getArea(), _area);
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.checkViewArea = function(_force)
|
||||
{
|
||||
if (typeof _force == "undefined")
|
||||
{
|
||||
_force = false;
|
||||
}
|
||||
|
||||
if (this.visible && this.viewArea)
|
||||
{
|
||||
if (!this.grid || !this.grid.inUpdate || _force)
|
||||
{
|
||||
return egwCallAbstract(this, this.doSetViewArea, [this.viewArea]);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
egwGridViewContainer.prototype.getArea = function()
|
||||
{
|
||||
return egwArea(this.position, this.getHeight());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** -- egwGridViewGrid Class -- **/
|
||||
|
||||
/**
|
||||
* egwGridViewGrid is the container for egwGridViewContainer objects, but itself
|
||||
* implements the egwGridViewContainer interface.
|
||||
*/
|
||||
function egwGridViewGrid(_grid, _heightChangeProc, _scrollable)
|
||||
{
|
||||
if (typeof _scrollable == "undefined")
|
||||
{
|
||||
_scrollable = false;
|
||||
}
|
||||
|
||||
var container = new egwGridViewContainer(_grid, _heightChangeProc);
|
||||
|
||||
// Introduce new functions to the container interface
|
||||
container.outerNode = null;
|
||||
container.innerNode = null;
|
||||
container.scrollarea = null;
|
||||
container.scrollable = _scrollable;
|
||||
container.scrollHeight = 100;
|
||||
container.scrollEvents = 0;
|
||||
container.didUpdate = false;
|
||||
container.setupContainer = egwGridViewGrid_setupContainer;
|
||||
container.insertContainer = egwGridViewGrid_insertContainer;
|
||||
container.removeContainer = egwGridViewGrid_removeContainer;
|
||||
container.addContainer = egwGridViewGrid_addContainer;
|
||||
container.heightChangeHandler = egwGridViewGrid_heightChangeHandler;
|
||||
container.setScrollHeight = egwGridViewGrid_setScrollHeight;
|
||||
container.scrollCallback = egwGridViewGrid_scrollCallback;
|
||||
container.children = [];
|
||||
|
||||
// Overwrite the abstract container interface functions
|
||||
container.invalidateHeightCache = egwGridViewGrid_invalidateHeightCache;
|
||||
container.getHeight = egwGridViewGrid_getHeight;
|
||||
container.doUpdateColumns = egwGridViewGrid_doUpdateColumns;
|
||||
container.doInsertIntoDOM = egwGridViewGrid_doInsertIntoDOM;
|
||||
container.doSetViewArea = egwGridViewGrid_doSetviewArea;
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function egwGridViewGrid_setupContainer()
|
||||
{
|
||||
/*
|
||||
Structure:
|
||||
<td colspan="[columncount]">
|
||||
[<div class="egwGridView_scrollarea">]
|
||||
<table class="egwGridView_grid">
|
||||
<tbody>
|
||||
[Container 1]
|
||||
[Container 2]
|
||||
[...]
|
||||
[Container n]
|
||||
</tbody>
|
||||
</table>
|
||||
[</div>]
|
||||
</td>
|
||||
*/
|
||||
|
||||
this.outerNode = $(document.createElement("td"));
|
||||
|
||||
if (this.scrollable)
|
||||
{
|
||||
this.scrollarea = $(document.createElement("div"));
|
||||
this.scrollarea.addClass("egwGridView_scrollarea");
|
||||
this.scrollarea.css("height", this.scrollHeight + "px");
|
||||
this.scrollarea.scroll(this, function(e) {
|
||||
window.setTimeout(function() {
|
||||
e.data.scrollEvents++;
|
||||
e.data.scrollCallback(e.data.scrollEvents);
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
var table = $(document.createElement("table"));
|
||||
table.addClass("egwGridView_grid");
|
||||
|
||||
this.innerNode = $(document.createElement("tbody"));
|
||||
|
||||
if (this.scrollable)
|
||||
{
|
||||
this.outerNode.append(this.scrollarea);
|
||||
this.scrollarea.append(table);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.outerNode.append(table);
|
||||
}
|
||||
|
||||
table.append(this.innerNode);
|
||||
}
|
||||
|
||||
function egwGridViewGrid_setScrollHeight(_value)
|
||||
{
|
||||
this.scrollHeight = _value;
|
||||
|
||||
if (this.scrollarea)
|
||||
{
|
||||
this.scrollarea.css("height", _value + "px");
|
||||
this.scrollCallback();
|
||||
}
|
||||
}
|
||||
|
||||
var
|
||||
EGW_GRID_VIEW_EXT = 50;
|
||||
EGW_GRID_MAX_CYCLES = 10;
|
||||
|
||||
function egwGridViewGrid_scrollCallback(_event)
|
||||
{
|
||||
if ((typeof _event == "undefined" || _event == this.scrollEvents) && this.scrollarea)
|
||||
{
|
||||
var cnt = 0;
|
||||
var area = egwArea(this.scrollarea.scrollTop() - EGW_GRID_VIEW_EXT,
|
||||
this.scrollHeight + EGW_GRID_VIEW_EXT * 2);
|
||||
do {
|
||||
cnt++;
|
||||
this.didUpdate = false;
|
||||
this.setViewArea(area);
|
||||
} while (this.didUpdate && cnt < EGW_GRID_MAX_CYCLES);
|
||||
|
||||
// console.log(cnt);
|
||||
|
||||
if (cnt == EGW_GRID_MAX_CYCLES)
|
||||
{
|
||||
if (this.console && this.console.info)
|
||||
{
|
||||
this.console.info("Too many update cycles. Aborting.")
|
||||
}
|
||||
}
|
||||
|
||||
this.scrollEvents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewGrid_insertContainer(_after, _class, _params)
|
||||
{
|
||||
this.didUpdate = true;
|
||||
|
||||
var container = new _class(this, this.heightChangeHandler, _params);
|
||||
|
||||
var idx = this.children.length;
|
||||
if (typeof _after == "number")
|
||||
{
|
||||
idx = Math.max(-1, Math.min(this.children.length, _after)) + 1;
|
||||
}
|
||||
else if (typeof _after == "object" && _after)
|
||||
{
|
||||
idx = _after.index + 1;
|
||||
}
|
||||
|
||||
// Insert the element at the given position
|
||||
this.children.splice(idx, 0, container);
|
||||
|
||||
// Create a table row for that element
|
||||
var tr = $(document.createElement("tr"));
|
||||
|
||||
// Insert the table row after the container specified in the _after parameter
|
||||
// and set the top position of the node
|
||||
container.index = idx;
|
||||
|
||||
if (idx == 0)
|
||||
{
|
||||
this.innerNode.prepend(tr);
|
||||
container.setPosition(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.insertAfter(this.children[idx - 1].parentNode);
|
||||
container.setPosition(this.children[idx - 1].getArea().bottom);
|
||||
}
|
||||
|
||||
// Insert the container into the table row
|
||||
container.insertIntoDOM(tr, this.columns);
|
||||
|
||||
// Offset the position of all following elements by the height of the container
|
||||
// and move the index of those elements
|
||||
var height = container.getHeight();
|
||||
for (var i = idx + 1; i < this.children.length; i++)
|
||||
{
|
||||
this.children[i].offsetPosition(height);
|
||||
this.children[i].index++;
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function egwGridViewGrid_removeContainer(_container)
|
||||
{
|
||||
this.didUpdate = true;
|
||||
|
||||
var idx = _container.index;
|
||||
|
||||
// Offset the position of the folowing children back
|
||||
var height = _container.getHeight();
|
||||
for (var i = idx + 1; i < this.children.length; i++)
|
||||
{
|
||||
this.children[i].offsetPosition(-height);
|
||||
this.children[i].index--;
|
||||
}
|
||||
|
||||
// Delete the parent node of the container object
|
||||
if (_container.parentNode)
|
||||
{
|
||||
_container.parentNode.remove();
|
||||
_container.parentNode = null;
|
||||
}
|
||||
|
||||
this.children.splice(idx, 1);
|
||||
}
|
||||
|
||||
function egwGridViewGrid_addContainer(_class)
|
||||
{
|
||||
// Insert the container at the beginning of the list.
|
||||
this.insertContainer(false, _class);
|
||||
return container;
|
||||
}
|
||||
|
||||
function egwGridViewGrid_invalidateHeightCache(_children)
|
||||
{
|
||||
if (typeof _children == "undefined")
|
||||
{
|
||||
_children = true;
|
||||
}
|
||||
|
||||
this.height = false;
|
||||
|
||||
if (_children)
|
||||
{
|
||||
for (var i = 0; i < this.children.length; i++)
|
||||
{
|
||||
this.children[i].invalidateHeightCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewGrid_getHeight()
|
||||
{
|
||||
if (this.visible && this.parentNode)
|
||||
{
|
||||
if (this.height === false)
|
||||
{
|
||||
this.height = this.innerNode.outerHeight();
|
||||
}
|
||||
return this.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewGrid_heightChangeHandler(_elem)
|
||||
{
|
||||
this.didUpdate = true;
|
||||
|
||||
// Get the height-change
|
||||
var oldHeight = _elem.height === false ? 0 : _elem.height;
|
||||
_elem.invalidateHeightCache(false);
|
||||
var newHeight = _elem.getHeight();
|
||||
var offs = newHeight - oldHeight;
|
||||
|
||||
// Set the offset of all elements succeding the given element correctly
|
||||
for (var i = _elem.index + 1; i < this.children.length; i++)
|
||||
{
|
||||
this.children[i].offsetPosition(offs);
|
||||
}
|
||||
|
||||
// As a result of the height of one of the children, the height of this element
|
||||
// has changed too - inform the parent grid about it.
|
||||
this.callHeightChangeProc();
|
||||
}
|
||||
|
||||
|
||||
function egwGridViewGrid_doInsertIntoDOM()
|
||||
{
|
||||
// Generate the DOM Nodes and append the outer node to the parent node
|
||||
this.setupContainer();
|
||||
this.parentNode.append(this.outerNode);
|
||||
|
||||
this.doUpdateColumns();
|
||||
}
|
||||
|
||||
function egwGridViewGrid_doUpdateColumns(_columns)
|
||||
{
|
||||
this.outerNode.attr("colspan", this.columns.length);
|
||||
|
||||
for (var i = 0; i < this.children.length; i++)
|
||||
{
|
||||
this.children[i].doUpdateColumns(_columns)
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewGrid_doSetviewArea(_area)
|
||||
{
|
||||
// Do a binary search for elements which are inside the given area
|
||||
var elem = null;
|
||||
var elems = [];
|
||||
|
||||
var bordertop = 0;
|
||||
var borderbot = this.children.length - 1;
|
||||
var idx = 0;
|
||||
while ((borderbot - bordertop >= 0) && !elem)
|
||||
{
|
||||
idx = Math.round((borderbot + bordertop) / 2);
|
||||
|
||||
var ar = this.children[idx].getArea();
|
||||
|
||||
var dir = egwAreaIntersectDir(_area, ar);
|
||||
|
||||
if (dir == 0)
|
||||
{
|
||||
elem = this.children[idx];
|
||||
}
|
||||
else if (dir == -1)
|
||||
{
|
||||
borderbot = idx - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bordertop = idx + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (elem)
|
||||
{
|
||||
elems.push(elem);
|
||||
|
||||
// Search upwards for elements in the area from the matched element on
|
||||
for (var i = idx - 1; i >= 0; i--)
|
||||
{
|
||||
if (this.children[i].inArea(_area))
|
||||
{
|
||||
elems.unshift(this.children[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Search downwards for elemwnts in the area from the matched element on
|
||||
for (var i = idx + 1; i < this.children.length; i++)
|
||||
{
|
||||
if (this.children[i].inArea(_area))
|
||||
{
|
||||
elems.push(this.children[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.inUpdate = true;
|
||||
|
||||
// Call the setViewArea function of visible child elements
|
||||
// Imporant: The setViewArea function has to work on a copy of children,
|
||||
// as the container may start to remove themselves or add new elements using
|
||||
// the insertAfter function.
|
||||
for (var i = 0; i < elems.length; i++)
|
||||
{
|
||||
elems[i].setViewArea(_area, true);
|
||||
}
|
||||
|
||||
this.inUpdate = false;
|
||||
}
|
||||
|
||||
/** -- egwGridViewRow Class -- **/
|
||||
|
||||
function egwGridViewRow(_grid, _heightChangeProc, _item)
|
||||
{
|
||||
var container = new egwGridViewContainer(_grid, _heightChangeProc);
|
||||
|
||||
// Copy the item parameter, which is used when fetching data from the data
|
||||
// source
|
||||
container.item = _item;
|
||||
|
||||
// Overwrite the inherited abstract functions
|
||||
container.doInsertIntoDOM = egwGridViewRow_doInsertIntoDOM;
|
||||
container.doSetViewArea = egwGridViewRow_doSetViewArea;
|
||||
container.doUpdateColumns = egwGridViewRow_doUpdateColumns;
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function egwGridViewRow_doInsertIntoDOM()
|
||||
{
|
||||
this.doUpdateColumns();
|
||||
}
|
||||
|
||||
function egwGridViewRow_doUpdateColumns()
|
||||
{
|
||||
this.parentNode.empty();
|
||||
|
||||
for (var i = 0; i < this.columns.length; i++)
|
||||
{
|
||||
var td = $(document.createElement("td"));
|
||||
td.text(this.item + ", col" + i);
|
||||
|
||||
this.parentNode.append(td);
|
||||
}
|
||||
|
||||
this.checkViewArea();
|
||||
}
|
||||
|
||||
function egwGridViewRow_doSetViewArea()
|
||||
{
|
||||
//TODO: Load the data for the columns and load it.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** -- egwGridViewSpacer Class -- **/
|
||||
|
||||
function egwGridViewSpacer(_grid, _heightChangeProc, _itemHeight)
|
||||
{
|
||||
if (typeof _itemHeight == "undefined")
|
||||
{
|
||||
_itemHeight = 20;
|
||||
}
|
||||
|
||||
var container = new egwGridViewContainer(_grid, _heightChangeProc);
|
||||
|
||||
// Add some new functions/properties to the container
|
||||
container.itemHeight = _itemHeight;
|
||||
container.domNode = null;
|
||||
container.items = [];
|
||||
container.setItemList = egwGridViewSpacer_setItemList;
|
||||
|
||||
// Overwrite the inherited functions
|
||||
container.doInsertIntoDOM = egwGridViewSpacer_doInsertIntoDOM;
|
||||
container.doSetViewArea = egwGridViewSpacer_doSetViewArea;
|
||||
container.doUpdateColumns = egwGridViewSpacer_doUpdateColumns;
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
function egwGridViewSpacer_setItemList(_items)
|
||||
{
|
||||
this.items = _items;
|
||||
|
||||
if (this.domNode)
|
||||
{
|
||||
this.domNode.css("height", (this.items.length * this.itemHeight) + "px");
|
||||
this.callHeightChangeProc();
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewSpacer_doInsertIntoDOM()
|
||||
{
|
||||
this.domNode = $(document.createElement("td"));
|
||||
this.domNode.addClass("egwGridView_spacer");
|
||||
this.domNode.css("height", (this.items.length * this.itemHeight) + "px");
|
||||
|
||||
this.parentNode.append(this.domNode);
|
||||
|
||||
this.doUpdateColumns();
|
||||
}
|
||||
|
||||
function egwGridViewSpacer_doSetViewArea()
|
||||
{
|
||||
// Get all items which are in the view area
|
||||
var top = Math.max(0, Math.floor(this.viewArea.top / this.itemHeight));
|
||||
var bot = Math.min(this.items.length, Math.ceil(this.viewArea.bottom / this.itemHeight));
|
||||
|
||||
// Split the item list into three parts
|
||||
var it_top = this.items.slice(0, top);
|
||||
var it_mid = this.items.slice(top, bot);
|
||||
var it_bot = this.items.slice(bot, this.items.length);
|
||||
|
||||
this.items = [];
|
||||
var idx = this.index;
|
||||
|
||||
// Insert the new rows in the parent grid in front of the spacer container
|
||||
for (var i = it_mid.length - 1; i >= 0; i--)
|
||||
{
|
||||
this.grid.insertContainer(idx - 1, egwGridViewRow, it_mid[i]);
|
||||
}
|
||||
|
||||
// If top was greater than 0, insert a new spacer in front of the
|
||||
if (it_top.length > 0)
|
||||
{
|
||||
var spacer = this.grid.insertContainer(idx - 1, egwGridViewSpacer, this.itemHeight);
|
||||
spacer.setItemList(it_top)
|
||||
}
|
||||
|
||||
// If there are items left at the bottom of the spacer, set theese as items of this spacer
|
||||
if (it_bot.length > 0)
|
||||
{
|
||||
this.setItemList(it_bot);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.grid.removeContainer(this);
|
||||
}
|
||||
}
|
||||
|
||||
function egwGridViewSpacer_doUpdateColumns()
|
||||
{
|
||||
this.domNode.attr("colspan", this.columns.length);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@ -10,9 +8,101 @@ body, td, th {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
table.egwGridView_grid {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.egwGridView_scrollarea {
|
||||
width: 100%;
|
||||
border-spacing: 0px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.egwGridView_spacer {
|
||||
display: block;
|
||||
background-image: url(imgs/non_loaded_bg.png);
|
||||
background-position: top left;
|
||||
}
|
||||
|
||||
.egwGridView_outer {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.egwGridView_outer td, .egwGridView_outer tr {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.egwGridView_grid td, .egwGridView_grid tr {
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.egwGridView_outer thead 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_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;
|
||||
height: 9px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
background-image: url(imgs/selectcols.png);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.grid {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
|
||||
.grid th.optcol {
|
||||
width: 6px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid tr.hidden {
|
||||
@ -66,10 +156,22 @@ body, td, th {
|
||||
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;
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.grid td {
|
||||
padding: 0 5px 0 5px;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
BIN
phpgwapi/js/egw_action/test/imgs/non_loaded_bg.png
Normal file
BIN
phpgwapi/js/egw_action/test/imgs/non_loaded_bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 408 B |
147
phpgwapi/js/egw_action/test/imgs/non_loaded_bg.svg
Normal file
147
phpgwapi/js/egw_action/test/imgs/non_loaded_bg.svg
Normal file
@ -0,0 +1,147 @@
|
||||
<?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="64"
|
||||
height="64"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="non_loaded_bg.svg"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/non_loaded_bg.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="3.959798"
|
||||
inkscape:cx="32.98408"
|
||||
inkscape:cy="37.795705"
|
||||
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="8"
|
||||
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,-988.36218)">
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M -8,72 72,-8"
|
||||
id="path3792"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M -8,56 56,-8"
|
||||
id="path3794"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 40,-8 -8,40"
|
||||
id="path3796"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M -8,24 24,-8"
|
||||
id="path3798"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 8,-8 -8,8"
|
||||
id="path3800"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 72,8 8,72"
|
||||
id="path3802"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 24,72 72,24"
|
||||
id="path3804"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 72,40 40,72"
|
||||
id="path3806"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-filename="/home/andreas/source/egroupware/trunk/egroupware/phpgwapi/js/egw_action/test/imgs/path3808.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:none;stroke:#f5f5f5;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 56,72 72,56"
|
||||
id="path3808"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
Loading…
Reference in New Issue
Block a user