Work on getting nextmatch going

This commit is contained in:
nathangray 2020-01-24 04:14:08 -07:00
parent 3b2f3e50de
commit 22780e5629
11 changed files with 11585 additions and 6224 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,664 @@
/**
* EGroupware eTemplate2 - dataview code
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
* @subpackage dataview
* @link http://www.egroupware.org
* @author Andreas Stöckel
* @copyright Stylite 2011-2012
* @version $Id$
*/
/*egw:uses
/vendor/bower-asset/jquery/dist/jquery.js;
et2_core_common;
et2_dataview_model_columns;
et2_dataview_view_rowProvider;
et2_dataview_view_grid;
et2_dataview_view_resizeable;
*/
/**
* The et2_dataview class is the main class for displaying a dataview. The
* dataview class manages the creation of the outer html nodes (like the table,
* header, etc.) and contains the root container: an instance of
* et2_dataview_view_grid, which can be accessed using the "grid" property of
* this object.
*
* @augments Class
*/
export class et2_dataview
{
/**
* Constant which regulates the column padding.
*/
columnPadding: number;
/**
* Some browser dependant variables which will be calculated on creation of
* the first gridContainer object.
*/
scrollbarWidth: number;
headerBorderWidth: number;
columnBorderWidth: number;
private width: number;
private height: number;
private uniqueId: string;
/**
* Hooks to allow parent to keep up to date if things change
*/
onUpdateColumns: Function;
selectColumnsClick: Function;
private parentNode: JQuery;
egw: any;
private columnNodes: any[];
private columns: any[];
private columnMgr: et2_dataview_columns;
private rowProvider: et2_dataview_rowProvider;
private grid: et2_dataview_grid;
// DOM stuff
private selectColIcon: JQuery;
private headTr: any;
private containerTr: JQuery;
private selectCol: JQuery;
private thead: JQuery;
private tbody: JQuery;
private table: JQuery;
private visibleColumnCount: number;
/**
* Constructor for the grid container
*
* @param {DOMElement} _parentNode is the DOM-Node into which the grid view will be inserted
* @param {egw} _egw
* @memberOf et2_dataview
*/
constructor(_parentNode, _egw) {
// Copy the arguments
this.parentNode = jQuery(_parentNode);
this.egw = _egw;
// Initialize some variables
this.columnNodes = []; // Array with the header containers
this.columns = [];
this.columnMgr = null;
this.rowProvider = null;
this.width = 0;
this.height = 0;
this.uniqueId = "gridCont_" + this.egw.uid();
// Build the base nodes
this._createElements();
// Read the browser dependant variables
this._getDepVars();
}
/**
* Destroys the object, removes all dom nodes and clears all references.
*/
destroy()
{
// Clear the columns
this._clearHeader();
// Free the grid
if (this.grid)
{
this.grid.free();
}
// Free the row provider
if (this.rowProvider)
{
this.rowProvider.free();
}
// Detatch the outer element
this.table.remove();
}
/**
* Clears all data rows and reloads them
*/
clear()
{
if (this.grid)
{
this.grid.clear();
}
}
/**
* Returns the column container node for the given column index
*
* @param _columnIdx the integer column index
*/
getHeaderContainerNode(_columnIdx)
{
if (typeof this.columnNodes[_columnIdx] != "undefined")
{
return this.columnNodes[_columnIdx].container[0];
}
return null;
}
/**
* Sets the column descriptors and creates the column header according to it.
* The inner grid will be emptied if it has already been built.
*/
setColumns(_columnData)
{
// Free all column objects which have been created till this moment
this._clearHeader();
// Copy the given column data
this.columnMgr = new et2_dataview_columns(_columnData);
// Create the stylesheets
this.updateColumns();
// Build the header row
this._buildHeader();
// Build the grid
this._buildGrid();
}
/**
* Resizes the grid
*/
resize(_w: number, _h: number)
{
// Not fully initialized yet...
if (!this.columnMgr) return;
if (this.width != _w)
{
this.width = _w;
// Take grid border width into account
_w -= (this.table.outerWidth(true) - this.table.innerWidth());
// Take grid header border's width into account. eg. category colors may add extra pixel into width
_w = _w - (this.thead.find('tr').outerWidth() - this.thead.find('tr').innerWidth());
// Rebuild the column stylesheets
this.columnMgr.setTotalWidth(_w - this.scrollbarWidth);
this._updateColumns();
}
if (this.height != _h)
{
this.height = _h;
// Set the height of the grid.
if (this.grid)
{
this.grid.setScrollHeight(this.height -
this.headTr.outerHeight(true));
}
}
}
/**
* Returns the column manager object. You can use it to set the visibility
* of columns etc. Call "updateHeader" if you did any changes.
*/
getColumnMgr() {
return this.columnMgr;
}
/**
* Recalculates the stylesheets which determine the column visibility and
* width.
*
* @param setDefault boolean Allow admins to save current settings as default for all users
*/
updateColumns(setDefault : boolean = false)
{
if (this.columnMgr)
{
this._updateColumns();
}
// Ability to notify parent / someone else
if (this.onUpdateColumns)
{
this.onUpdateColumns(setDefault);
}
}
/* --- PRIVATE FUNCTIONS --- */
/* --- Code for building the grid container DOM-Tree elements ---- */
/**
* Builds the base DOM-Tree elements
*/
private _createElements()
{
/*
Structure:
<table class="egwGridView_outer">
<thead>
<tr> [HEAD] </tr>
</thead>
<tbody>
<tr> [GRID CONTAINER] </tr>
</tbody>
</table>
*/
this.containerTr = jQuery(document.createElement("tr"));
this.headTr = jQuery(document.createElement("tr"));
this.thead = jQuery(document.createElement("thead"))
.append(this.headTr);
this.tbody = jQuery(document.createElement("tbody"))
.append(this.containerTr);
this.table = jQuery(document.createElement("table"))
.addClass("egwGridView_outer")
.append(this.thead, this.tbody)
.appendTo(this.parentNode);
}
/* --- Code for building the header row --- */
/**
* Clears the header row
*/
private _clearHeader ()
{
if (this.columnMgr)
{
this.columnMgr.free();
this.columnMgr = null;
}
// Remove dynamic CSS,
for (var i = 0; i < this.columns.length; i++)
{
if(this.columns[i].tdClass)
{
this.egw.css('.'+this.columns[i].tdClass);
}
if(this.columns[i].divClass)
{
this.egw.css('.'+this.columns[i].divClass);
this.egw.css(".egwGridView_outer ." + this.columns[i].divClass);
this.egw.css(".egwGridView_grid ." + this.columns[i].divClass);
}
}
this.egw.css(".egwGridView_grid ." + this.uniqueId + "_div_fullRow");
this.egw.css(".egwGridView_outer ." + this.uniqueId + "_td_fullRow");
this.egw.css(".egwGridView_outer ." + this.uniqueId + "_spacer_fullRow");
// Reset the headerColumns array and empty the table row
this.columnNodes = [];
this.columns = [];
this.headTr.empty();
}
/**
* Sets the column data which is retrieved by calling egwGridColumns.getColumnData.
* The columns will be updated.
*/
private _updateColumns()
{
// Copy the columns data
this.columns = this.columnMgr.getColumnData();
// Count the visible rows
var total_cnt = 0;
for (var i = 0; i < this.columns.length; i++)
{
if (this.columns[i].visible)
{
total_cnt++;
}
}
// Set the grid column styles
var first = true;
var vis_col = this.visibleColumnCount = 0;
var totalWidth = 0;
for (var i = 0; i < this.columns.length; i++)
{
var col = this.columns[i];
col.tdClass = this.uniqueId + "_td_" + col.id;
col.divClass = this.uniqueId + "_div_" + col.id;
if (col.visible)
{
vis_col++;
this.visibleColumnCount++;
// Update the visibility of the column
this.egw.css("." + col.tdClass,
"display: table-cell; " +
"!important;");
// Ugly browser dependant code - each browser seems to treat the
// right (collapsed) border of the row differently
var subBorder = 0;
var subHBorder = 0;
/*
if (jQuery.browser.mozilla)
{
var maj = jQuery.browser.version.split(".")[0];
if (maj < 2) {
subBorder = 1; // Versions <= FF 3.6
}
}
if (jQuery.browser.webkit)
{
if (!first)
{
subBorder = 1;
}
subHBorder = 1;
}
if ((jQuery.browser.msie || jQuery.browser.opera) && first)
{
subBorder = -1;
}
*/
// Make the last columns one pixel smaller, to prevent a horizontal
// scrollbar from showing up
if (vis_col == total_cnt)
{
subBorder += 1;
}
// Write the width of the header columns
var headerWidth = Math.max(0, (col.width - this.headerBorderWidth - subHBorder));
this.egw.css(".egwGridView_outer ." + col.divClass,
"width: " + headerWidth + "px;");
// Write the width of the body-columns
var columnWidth = Math.max(0, (col.width - this.columnBorderWidth - subBorder));
this.egw.css(".egwGridView_grid ." + col.divClass,
"width: " + columnWidth + "px;");
totalWidth += col.width;
first = false;
}
else
{
this.egw.css("." + col.tdClass, "display: none;");
}
}
// Add the full row and spacer class
this.egw.css(".egwGridView_grid ." + this.uniqueId + "_div_fullRow",
"width: " + (totalWidth - this.columnBorderWidth - 2) + "px; border-right-width: 0 !important;");
this.egw.css(".egwGridView_outer ." + this.uniqueId + "_td_fullRow",
"border-right-width: 0 !important;");
this.egw.css(".egwGridView_outer ." + this.uniqueId + "_spacer_fullRow",
"width: " + (totalWidth - 1) + "px; border-right-width: 0 !important;");
}
/**
* Builds the containers for the header row
*/
private _buildHeader()
{
var self = this;
var handler = function(event) {
};
for (var i = 0; i < this.columns.length; i++)
{
var col = this.columns[i];
// Create the column header and the container element
var cont = jQuery(document.createElement("div"))
.addClass("innerContainer")
.addClass(col.divClass);
var column = jQuery(document.createElement("th"))
.addClass(col.tdClass)
.attr("align", "left")
.append(cont)
.appendTo(this.headTr);
if(this.columnMgr && this.columnMgr.columns[i])
{
column.addClass(this.columnMgr.columns[i].fixedWidth ? 'fixedWidth' : 'relativeWidth');
if(this.columnMgr.columns[i].visibility === et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT)
{
column.addClass('noResize');
}
}
// make column resizable
var enc_column = self.columnMgr.getColumnById(col.id);
if(enc_column.visibility !== et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT)
{
et2_dataview_view_resizable.makeResizeable(column, function(_w) {
// User wants the column to stay where they put it, even for relative
// width columns, so set it explicitly first and adjust other relative
// columns to match.
if(this.relativeWidth)
{
// Set to selected width
this.set_width(_w + "px");
self.columnMgr.updated = true;
// Just triggers recalculation
self.columnMgr.getColumnWidth(0);
// Set relative widths to match
var relative = self.columnMgr.totalWidth - self.columnMgr.totalFixed + _w;
this.set_width(_w / relative);
for(var i = 0; i < self.columnMgr.columns.length; i++)
{
var col = self.columnMgr.columns[i];
if(col == this || col.fixedWidth) continue;
col.set_width(self.columnMgr.columnWidths[i] / relative);
}
// Triggers column change callback, which saves
self.updateColumns();
}
else
{
this.set_width(this.relativeWidth ? (_w / self.columnMgr.totalWidth) : _w + "px");
self.columnMgr.updated = true;
self.updateColumns();
}
}, enc_column);
}
// Store both nodes in the columnNodes array
this.columnNodes.push({
"column": column,
"container": cont
});
}
this._buildSelectCol();
}
/**
* Builds the select cols column
*/
private _buildSelectCol()
{
// Build the "select columns" icon
this.selectColIcon = jQuery(document.createElement("span"))
.addClass("selectcols")
.css('display', 'inline-block'); // otherwise jQuery('span.selectcols',this.dataview.headTr).show() set it to "inline" causing it to not show up because 0 height
// Build the option column
this.selectCol = jQuery(document.createElement("th"))
.addClass("optcol")
.append(this.selectColIcon)
// Toggle display of option popup
.click(this, function(e) {if(e.data.selectColumnsClick) e.data.selectColumnsClick(e);})
.appendTo(this.headTr);
this.selectCol.css("width", this.scrollbarWidth - this.selectCol.outerWidth()
+ this.selectCol.width() + 1);
}
/**
* Builds the inner grid class
*/
private _buildGrid()
{
// Create the collection of column ids
var colIds = new Array(this.columns.length);
for (var i = 0; i < this.columns.length; i++)
{
colIds[i] = this.columns[i].id;
}
// Create the row provider
if (this.rowProvider)
{
this.rowProvider.free();
}
this.rowProvider = new et2_dataview_rowProvider(this.uniqueId, colIds);
// Create the grid class and pass "19" as the starting average row height
this.grid = new et2_dataview_grid(null, null, this.egw, this.rowProvider, 19);
// Insert the grid into the DOM-Tree
var tr = jQuery(this.grid._nodes[0]);
this.containerTr.replaceWith(tr);
this.containerTr = tr;
}
/* --- Code for calculating the browser/css depending widths --- */
/**
* Reads the browser dependant variables
*/
private _getDepVars()
{
if (typeof this.scrollbarWidth === 'undefined')
{
// Clone the table and attach it to the outer body tag
var clone = this.table.clone();
jQuery(window.top.document.getElementsByTagName("body")[0])
.append(clone);
// Read the scrollbar width
this.scrollbarWidth = this.constructor.prototype.scrollbarWidth =
this._getScrollbarWidth(clone);
// Read the header border width
this.headerBorderWidth = this.constructor.prototype.headerBorderWidth =
this._getHeaderBorderWidth(clone);
// Read the column border width
this.columnBorderWidth = this.constructor.prototype.columnBorderWidth =
this._getColumnBorderWidth(clone);
// Remove the cloned DOM-Node again from the outer body
clone.remove();
}
}
/**
* Reads the scrollbar width
*/
private _getScrollbarWidth(_table: JQuery)
{
// Create a temporary td and two divs, which are inserted into the
// DOM-Tree. The outer div has a fixed size and "overflow" set to auto.
// When the second div is inserted, it will be forced to display a scrollbar.
var div_inner = jQuery(document.createElement("div"))
.css("height", "1000px");
var div_outer = jQuery(document.createElement("div"))
.css("height", "100px")
.css("width", "100px")
.css("overflow", "auto")
.append(div_inner);
var td = jQuery(document.createElement("td"))
.append(div_outer);
// Store the scrollbar width statically.
jQuery("tbody tr", _table).append(td);
var width = Math.max(10, div_outer.outerWidth() - div_inner.outerWidth());
// Remove the elements again
div_outer.remove();
return width;
}
/**
* Calculates the total width of the header column border
*/
private _getHeaderBorderWidth(_table: JQuery)
{
// Create a temporary th which is appended to the outer thead row
var cont = jQuery(document.createElement("div"))
.addClass("innerContainer");
var th = jQuery(document.createElement("th"))
.append(cont);
// Insert the th into the document tree
jQuery("thead tr", _table).append(th);
// Calculate the total border width
var width = th.outerWidth(true) - cont.width();
// Remove the appended element again
th.remove();
return width;
}
/**
* Calculates the total width of the column border
*/
private _getColumnBorderWidth(_table: JQuery)
{
// Create a temporary th which is appended to the outer thead row
var cont = jQuery(document.createElement("div"))
.addClass("innerContainer");
var td = jQuery(document.createElement("td"))
.append(cont);
// Insert the th into the document tree
jQuery("tbody tr", _table).append(td);
// Calculate the total border width
_table.addClass("egwGridView_grid");
var width = td.outerWidth(true) - cont.width();
// Remove the appended element again
td.remove();
return width;
}
}

View File

@ -1,3 +1,4 @@
"use strict";
/**
* EGroupware eTemplate2 - Contains interfaces used inside the dataview
*
@ -9,89 +10,5 @@
* @copyright Stylite 2011
* @version $Id$
*/
/*egw:uses
et2_core_inheritance;
*/
var et2_dataview_IInvalidatable = new Interface({
invalidate: function() {}
});
var et2_dataview_IViewRange = new Interface({
setViewRange: function(_range) {}
});
/**
* Interface a data provider has to implement. The data provider functions are
* called by the et2_dataview_controller class. The data provider basically acts
* like the egw api egw_data extension, but some etemplate specific stuff has
* been stripped away -- the implementation (for the nextmatch widget that is
* et2_extension_nextmatch_dataprovider) has to take care of that.
*/
var et2_IDataProvider = new Interface({
/**
* This function is used by the et2_dataview_controller to fetch data for
* a certain range. The et2_dataview_controller provides data which allows
* to only update elements which really have changed.
*
* @param queriedRange is an object of the following form:
* {
* start: <START INDEX>,
* num_rows: <COUNT OF ENTRIES>
* }
* @param knownRange is an array of the above form and informs the
* implementation which range is already known to the client. This parameter
* may be null in order to indicate that the client currently has no valid
* data.
* @param lastModification is the last timestamp that was returned from the
* data provider and for which the client has data. It may be null in order
* to indicate, that the client currently has no data or needs a complete
* refresh.
* @param callback is the function that should get called, once the data
* is available. The data passed to the callback function has the
* following form:
* {
* order: [uid, ...],
* total: <TOTAL COUNT>,
* lastModification: <LAST MODIFICATION TIMESTAMP>
* }
* @param context is the context in which the callback function will get
* called.
*/
dataFetch: function (_queriedRange, _lastModification, _callback, _context) {},
/**
* Registers the intrest in a certain uid for a callback function. If
* the data for that uid changes or gets loaded, the given callback
* function is called. If the data for the given uid is available at the
* time of registering the callback, the callback is called immediately.
*
* @param _uid is the uid for which the callback should be registered.
* @param _callback is the callback which should get called.
* @param _context is an optional parameter which can
*/
dataRegisterUID: function (_uid, _callback, _context) {},
/**
* Unregisters the intrest of updates for a certain data uid.
*
* @param _uid is the data uid for which the callbacks should be
* unregistered.
* @param _callback specifies the specific callback that should be
* unregistered. If it evaluates to false, all callbacks (or those
* matching the optionally given context) are removed.
* @param _context specifies the callback context that should be
* unregistered. If it evaluates to false, all callbacks (or those
* matching the optionally given callback function) are removed.
*/
dataUnregisterUID: function (_uid, _callback, _context) {}
});
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=et2_dataview_interfaces.js.map

View File

@ -0,0 +1,100 @@
/**
* EGroupware eTemplate2 - Contains interfaces used inside the dataview
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
* @subpackage dataview
* @link http://www.egroupware.org
* @author Andreas Stöckel
* @copyright Stylite 2011
* @version $Id$
*/
/*egw:uses
et2_core_inheritance;
*/
export interface et2_dataview_IInvalidatable
{
invalidate()
}
export interface et2_dataview_IViewRange
{
setViewRange(_range)
}
/**
* Interface a data provider has to implement. The data provider functions are
* called by the et2_dataview_controller class. The data provider basically acts
* like the egw api egw_data extension, but some etemplate specific stuff has
* been stripped away -- the implementation (for the nextmatch widget that is
* et2_extension_nextmatch_dataprovider) has to take care of that.
*/
export interface et2_IDataProvider
{
/**
* This function is used by the et2_dataview_controller to fetch data for
* a certain range. The et2_dataview_controller provides data which allows
* to only update elements which really have changed.
*
* @param _queriedRange is an object of the following form:
* {
* start: <START INDEX>,
* num_rows: <COUNT OF ENTRIES>
* }
* @param _knownRange is an array of the above form and informs the
* implementation which range is already known to the client. This parameter
* may be null in order to indicate that the client currently has no valid
* data.
* @param _lastModification is the last timestamp that was returned from the
* data provider and for which the client has data. It may be null in order
* to indicate, that the client currently has no data or needs a complete
* refresh.
* @param _callback is the function that should get called, once the data
* is available. The data passed to the callback function has the
* following form:
* {
* order: [uid, ...],
* total: <TOTAL COUNT>,
* lastModification: <LAST MODIFICATION TIMESTAMP>
* }
* @param _context is the context in which the callback function will get
* called.
*/
dataFetch (_queriedRange : {start: number, num_rows:number}, _lastModification, _callback : Function, _context : object)
/**
* Registers the intrest in a certain uid for a callback function. If
* the data for that uid changes or gets loaded, the given callback
* function is called. If the data for the given uid is available at the
* time of registering the callback, the callback is called immediately.
*
* @param _uid is the uid for which the callback should be registered.
* @param _callback is the callback which should get called.
* @param _context is an optional parameter which can
*/
dataRegisterUID (_uid : string, _callback : Function, _context : object)
/**
* Unregisters the intrest of updates for a certain data uid.
*
* @param _uid is the data uid for which the callbacks should be
* unregistered.
* @param _callback specifies the specific callback that should be
* unregistered. If it evaluates to false, all callbacks (or those
* matching the optionally given context) are removed.
* @param _context specifies the callback context that should be
* unregistered. If it evaluates to false, all callbacks (or those
* matching the optionally given callback function) are removed.
*/
dataUnregisterUID (_uid : string, _callback : Function, _context : object)
}

View File

@ -1,3 +1,4 @@
"use strict";
/**
* EGroupware eTemplate2 - dataview code
*
@ -9,12 +10,7 @@
* @copyright Stylite 2012
* @version $Id$
*/
/*egw:uses
/vendor/bower-asset/jquery/dist/jquery.js;
et2_dataview_interfaces;
*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* The et2_dataview_container class is the main object each dataview consits of.
* Each row, spacer as well as the grid itself are containers. A container is
@ -31,352 +27,287 @@
*
* @augments Class
*/
var et2_dataview_container = (function(){ "use strict"; return Class.extend(et2_dataview_IInvalidatable,
{
/**
* Initializes the container object.
*
* @param _parent is an object which implements the IInvalidatable
* interface. _parent may not be null.
* @memberOf et2_dataview_container
*/
init: function(_parent) {
// Copy the given invalidation element
this._parent = _parent;
this._nodes = []; // contains all DOM-Nodes this container exists of
this._inTree = false; //
this._attachData = {"node": null, "prepend": false};
this._destroyCallback = null;
this._destroyContext = null;
this._height = false;
this._index = 0;
this._top = 0;
},
/**
* Destroys this container. Classes deriving from et2_dataview_container
* should override this method and take care of unregistering all event
* handlers etc.
*/
destroy: function() {
// Remove the nodes from the tree
this.removeFromTree();
// Call the callback function (if one is registered)
if (this._destroyCallback)
{
this._destroyCallback.call(this._destroyContext, this);
}
},
/**
* Sets the "destroyCallback" -- the given function gets called whenever
* the container is destroyed. This instance is passed as an parameter to
* the callback.
*
* @param {function} _callback
* @param {object} _context
*/
setDestroyCallback: function(_callback, _context) {
this._destroyCallback = _callback;
this._destroyContext = _context;
},
/**
* Inserts all container nodes into the DOM tree after or before the given
* element.
*
* @param _node is the node after/before which the container "tr"s should
* get inserted. _node should be a simple DOM node, not a jQuery object.
* @param _prepend specifies whether the container should be inserted before
* or after the given node. Inserting before is needed for inserting the
* first element in front of an spacer.
*/
insertIntoTree: function(_node, _prepend) {
if (!this._inTree && _node != null && this._nodes.length > 0)
{
// Store the parent node and indicate that this element is now in
// the tree.
this._attachData = {"node": _node, "prepend": _prepend};
this._inTree = true;
for (var i = 0; i < this._nodes.length; i++)
{
if (i == 0)
{
if (_prepend)
{
_node.before(this._nodes[0]);
}
else
{
_node.after(this._nodes[0]);
}
}
else
{
// Insert all following nodes after the previous node
this._nodes[i - 1].after(this._nodes[i]);
}
}
// Invalidate this element in order to update the height of the
// parent
this.invalidate();
}
},
/**
* Removes all container nodes from the tree.
*/
removeFromTree: function() {
if (this._inTree)
{
// Call the jQuery remove function to remove all nodes from the tree
// again.
for (var i = 0; i < this._nodes.length; i++)
{
this._nodes[i].remove();
}
// Reset the "attachData"
this._inTree = false;
this._attachData = {"node": null, "prepend": false};
}
},
/**
* Appends a node to the container.
*
* @param _node is the DOM-Node which should be appended.
*/
appendNode: function(_node) {
// Add the given node to the "nodes" array
this._nodes.push(_node);
// If the container is already in the tree, attach the given node to the
// tree.
if (this._inTree)
{
if (this._nodes.length === 1)
{
if (this._attachData.prepend)
{
this._attachData.node.before(_node);
}
else
{
this._attachData.node.after(_node);
}
}
else
{
this._nodes[this._nodes.length - 2].after(_node);
}
this.invalidate();
}
},
/**
* Removes a certain node from the container
*
* @param {DOMElement} _node
*/
removeNode: function(_node) {
// Get the index of the node in the nodes array
var idx = this._nodes.indexOf(_node);
if (idx >= 0)
{
// Remove the node if the container is currently attached
if (this._inTree)
{
_node.parentNode.removeChild(_node);
}
// Remove the node from the nodes array
this._nodes.splice(idx, 1);
}
},
/**
* Returns the last node of the container - new nodes have to be appended
* after it.
*/
getLastNode: function() {
if (this._nodes.length > 0)
{
return this._nodes[this._nodes.length - 1];
}
return null;
},
/**
* Returns the first node of the container.
*/
getFirstNode: function() {
return this._nodes.length > 0 ? this._nodes[0] : null;
},
/**
* Returns the accumulated height of all container nodes. Only visible nodes
* (without "display: none" etc.) are taken into account.
*/
getHeight: function() {
if (this._height === false && this._inTree)
{
this._height = 0;
// Setting this before measuring height helps with issues getting the
// wrong height due to margins & collapsed borders
this.tr.css('display','block');
// Increment the height value for each visible container node
for (var i = 0; i < this._nodes.length; i++)
{
if (this._isVisible(this._nodes[i][0]))
{
this._height += this._nodeHeight(this._nodes[i][0]);
}
}
this.tr.css('display','');
}
return this._height === false ? 0 : this._height;
},
/**
* Returns a datastructure containing information used for calculating the
* average row height of a grid.
* The datastructure has the
* {
* avgHeight: <the calculated average height of this element>,
* avgCount: <the element count this calculation was based on>
* }
*/
getAvgHeightData: function() {
return {
"avgHeight": this.getHeight(),
"avgCount": 1
};
},
/**
* Returns the previously set "pixel top" of the container.
*/
getTop: function() {
return this._top;
},
/**
* Returns the "pixel bottom" of the container.
*/
getBottom: function() {
return this._top + this.getHeight();
},
/**
* Returns the range of the element.
*/
getRange: function() {
return et2_bounds(this.getTop(), this.getBottom());
},
/**
* Returns the index of the element.
*/
getIndex: function() {
return this._index;
},
/**
* Returns how many elements this container represents.
*/
getCount: function() {
return 1;
},
/**
* Sets the top of the element.
*
* @param {number} _value
*/
setTop: function(_value) {
this._top = _value;
},
/**
* Sets the index of the element.
*
* @param {number} _value
*/
setIndex: function(_value) {
this._index = _value;
},
/* -- et2_dataview_IInvalidatable -- */
/**
* Broadcasts an invalidation through the container tree. Marks the own
* height as invalid.
*/
invalidate: function() {
// Abort if this element is already marked as invalid.
if (this._height !== false)
{
// Delete the own, probably computed height
this._height = false;
// Broadcast the invalidation to the parent element
this._parent.invalidate();
}
},
/* -- PRIVATE FUNCTIONS -- */
/**
* Used to check whether an element is visible or not (non recursive).
*
* @param _obj is the element which should be checked for visibility, it is
* only checked whether some stylesheet makes the element invisible, not if
* the given object is actually inside the DOM.
*/
_isVisible: function(_obj) {
// Check whether the element is localy invisible
if (_obj.style && (_obj.style.display === "none"
|| _obj.style.visiblity === "none"))
{
return false;
}
// Get the computed style of the element
var style = window.getComputedStyle ? window.getComputedStyle(_obj, null)
: _obj.currentStyle;
if (style.display === "none" || style.visibility === "none")
{
return false;
}
return true;
},
/**
* Returns the height of a node in pixels and zero if the element is not
* visible. The height is clamped to positive values.
*
* @param {DOMElement} _node
*/
_nodeHeight: function(_node)
{
return _node.offsetHeight;
}
});}).call(this);
var et2_dataview_container = /** @class */ (function () {
/**
* Initializes the container object.
*
* @param _parent is an object which implements the IInvalidatable
* interface. _parent may not be null.
* @memberOf et2_dataview_container
*/
function et2_dataview_container(_parent) {
// Copy the given invalidation element
this._parent = _parent;
this._nodes = [];
this._inTree = false;
this._attachData = { "node": null, "prepend": false };
this._destroyCallback = null;
this._destroyContext = null;
this._height = -1;
this._index = 0;
this._top = 0;
}
/**
* Destroys this container. Classes deriving from et2_dataview_container
* should override this method and take care of unregistering all event
* handlers etc.
*/
et2_dataview_container.prototype.destroy = function () {
// Remove the nodes from the tree
this.removeFromTree();
// Call the callback function (if one is registered)
if (this._destroyCallback) {
this._destroyCallback.call(this._destroyContext, this);
}
};
/**
* Sets the "destroyCallback" -- the given function gets called whenever
* the container is destroyed. This instance is passed as an parameter to
* the callback.
*
* @param {function} _callback
* @param {object} _context
*/
et2_dataview_container.prototype.setDestroyCallback = function (_callback, _context) {
this._destroyCallback = _callback;
this._destroyContext = _context;
};
/**
* Inserts all container nodes into the DOM tree after or before the given
* element.
*
* @param _node is the node after/before which the container "tr"s should
* get inserted. _node should be a simple DOM node, not a jQuery object.
* @param _prepend specifies whether the container should be inserted before
* or after the given node. Inserting before is needed for inserting the
* first element in front of an spacer.
*/
et2_dataview_container.prototype.insertIntoTree = function (_node, _prepend) {
if (!this._inTree && _node != null && this._nodes.length > 0) {
// Store the parent node and indicate that this element is now in
// the tree.
this._attachData = { node: _node, prepend: _prepend };
this._inTree = true;
for (var i = 0; i < this._nodes.length; i++) {
if (i == 0) {
if (_prepend) {
_node.before(this._nodes[0]);
}
else {
_node.after(this._nodes[0]);
}
}
else {
// Insert all following nodes after the previous node
this._nodes[i - 1].after(this._nodes[i]);
}
}
// Invalidate this element in order to update the height of the
// parent
this.invalidate();
}
};
/**
* Removes all container nodes from the tree.
*/
et2_dataview_container.prototype.removeFromTree = function () {
if (this._inTree) {
// Call the jQuery remove function to remove all nodes from the tree
// again.
for (var i = 0; i < this._nodes.length; i++) {
this._nodes[i].remove();
}
// Reset the "attachData"
this._inTree = false;
this._attachData = { "node": null, "prepend": false };
}
};
/**
* Appends a node to the container.
*
* @param _node is the DOM-Node which should be appended.
*/
et2_dataview_container.prototype.appendNode = function (_node) {
// Add the given node to the "nodes" array
this._nodes.push(_node);
// If the container is already in the tree, attach the given node to the
// tree.
if (this._inTree) {
if (this._nodes.length === 1) {
if (this._attachData.prepend) {
this._attachData.node.before(_node);
}
else {
this._attachData.node.after(_node);
}
}
else {
this._nodes[this._nodes.length - 2].after(_node);
}
this.invalidate();
}
};
/**
* Removes a certain node from the container
*
* @param {HTMLElement} _node
*/
et2_dataview_container.prototype.removeNode = function (_node) {
// Get the index of the node in the nodes array
var idx = this._nodes.indexOf(_node);
if (idx >= 0) {
// Remove the node if the container is currently attached
if (this._inTree) {
_node.parentNode.removeChild(_node);
}
// Remove the node from the nodes array
this._nodes.splice(idx, 1);
}
};
/**
* Returns the last node of the container - new nodes have to be appended
* after it.
*/
et2_dataview_container.prototype.getLastNode = function () {
if (this._nodes.length > 0) {
return this._nodes[this._nodes.length - 1];
}
return null;
};
/**
* Returns the first node of the container.
*/
et2_dataview_container.prototype.getFirstNode = function () {
return this._nodes.length > 0 ? this._nodes[0] : null;
};
/**
* Returns the accumulated height of all container nodes. Only visible nodes
* (without "display: none" etc.) are taken into account.
*/
et2_dataview_container.prototype.getHeight = function () {
if (this._height === -1 && this._inTree) {
this._height = 0;
// Setting this before measuring height helps with issues getting the
// wrong height due to margins & collapsed borders
this.tr.css('display', 'block');
// Increment the height value for each visible container node
for (var i = 0; i < this._nodes.length; i++) {
if (et2_dataview_container._isVisible(this._nodes[i][0])) {
this._height += et2_dataview_container._nodeHeight(this._nodes[i][0]);
}
}
this.tr.css('display', '');
}
return (this._height === -1) ? 0 : this._height;
};
/**
* Returns a datastructure containing information used for calculating the
* average row height of a grid.
* The datastructure has the
* {
* avgHeight: <the calculated average height of this element>,
* avgCount: <the element count this calculation was based on>
* }
*/
et2_dataview_container.prototype.getAvgHeightData = function () {
return {
"avgHeight": this.getHeight(),
"avgCount": 1
};
};
/**
* Returns the previously set "pixel top" of the container.
*/
et2_dataview_container.prototype.getTop = function () {
return this._top;
};
/**
* Returns the "pixel bottom" of the container.
*/
et2_dataview_container.prototype.getBottom = function () {
return this._top + this.getHeight();
};
/**
* Returns the range of the element.
*/
et2_dataview_container.prototype.getRange = function () {
return et2_bounds(this.getTop(), this.getBottom());
};
/**
* Returns the index of the element.
*/
et2_dataview_container.prototype.getIndex = function () {
return this._index;
};
/**
* Returns how many elements this container represents.
*/
et2_dataview_container.prototype.getCount = function () {
return 1;
};
/**
* Sets the top of the element.
*
* @param {number} _value
*/
et2_dataview_container.prototype.setTop = function (_value) {
this._top = _value;
};
/**
* Sets the index of the element.
*
* @param {number} _value
*/
et2_dataview_container.prototype.setIndex = function (_value) {
this._index = _value;
};
/* -- et2_dataview_IInvalidatable -- */
/**
* Broadcasts an invalidation through the container tree. Marks the own
* height as invalid.
*/
et2_dataview_container.prototype.invalidate = function () {
// Abort if this element is already marked as invalid.
if (this._height !== -1) {
// Delete the own, probably computed height
this._height = -1;
// Broadcast the invalidation to the parent element
this._parent.invalidate();
}
};
/* -- PRIVATE FUNCTIONS -- */
/**
* Used to check whether an element is visible or not (non recursive).
*
* @param _obj is the element which should be checked for visibility, it is
* only checked whether some stylesheet makes the element invisible, not if
* the given object is actually inside the DOM.
*/
et2_dataview_container._isVisible = function (_obj) {
// Check whether the element is localy invisible
if (_obj.style && (_obj.style.display === "none"
|| _obj.style.visibility === "none")) {
return false;
}
// Get the computed style of the element
var style = window.getComputedStyle ? window.getComputedStyle(_obj, null)
// @ts-ignore
: _obj.currentStyle;
if (style.display === "none" || style.visibility === "none") {
return false;
}
return true;
};
/**
* Returns the height of a node in pixels and zero if the element is not
* visible. The height is clamped to positive values.
*
* @param {HTMLElement} _node
*/
et2_dataview_container._nodeHeight = function (_node) {
return _node.offsetHeight;
};
return et2_dataview_container;
}());
exports.et2_dataview_container = et2_dataview_container;
//# sourceMappingURL=et2_dataview_view_container.js.map

View File

@ -0,0 +1,421 @@
/**
* EGroupware eTemplate2 - dataview code
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
* @subpackage dataview
* @link http://www.egroupware.org
* @author Andreas Stöckel
* @copyright Stylite 2012
* @version $Id$
*/
/*egw:uses
/vendor/bower-asset/jquery/dist/jquery.js;
et2_dataview_interfaces;
*/
import {et2_dataview_IInvalidatable} from "./et2_dataview_interfaces";
/**
* The et2_dataview_container class is the main object each dataview consits of.
* Each row, spacer as well as the grid itself are containers. A container is
* described by its parent element and a certain height. On the DOM-Level a
* container may consist of multiple "tr" nodes, which are treated as a unit.
* Some containers (like grid containers) are capable of managing a set of child
* containers. Each container can indicate, that it thinks that it's height
* might have changed. In that case it informs its parent element about that.
* The only requirement for the parent element is, that it implements the
* et2_dataview_IInvalidatable interface.
* A container does not know where it resides inside the grid, or whether it is
* currently visible or not -- this information is efficiently managed by the
* et2_dataview_grid container.
*
* @augments Class
*/
export class et2_dataview_container implements et2_dataview_IInvalidatable
{
protected _parent: any;
// contains all DOM-Nodes this container exists of
private _nodes: any[];
private _inTree: boolean;
private _attachData: { node: JQuery; prepend: boolean };
private _destroyCallback: Function;
_destroyContext: any;
private _height: number;
private _index: number;
private _top: number;
protected tr: any;
/**
* Initializes the container object.
*
* @param _parent is an object which implements the IInvalidatable
* interface. _parent may not be null.
* @memberOf et2_dataview_container
*/
constructor(_parent)
{
// Copy the given invalidation element
this._parent = _parent;
this._nodes = [];
this._inTree = false;
this._attachData = {"node": null, "prepend": false};
this._destroyCallback = null;
this._destroyContext = null;
this._height = -1;
this._index = 0;
this._top = 0;
}
/**
* Destroys this container. Classes deriving from et2_dataview_container
* should override this method and take care of unregistering all event
* handlers etc.
*/
destroy()
{
// Remove the nodes from the tree
this.removeFromTree();
// Call the callback function (if one is registered)
if (this._destroyCallback)
{
this._destroyCallback.call(this._destroyContext, this);
}
}
/**
* Sets the "destroyCallback" -- the given function gets called whenever
* the container is destroyed. This instance is passed as an parameter to
* the callback.
*
* @param {function} _callback
* @param {object} _context
*/
setDestroyCallback(_callback : Function, _context : object) {
this._destroyCallback = _callback;
this._destroyContext = _context;
}
/**
* Inserts all container nodes into the DOM tree after or before the given
* element.
*
* @param _node is the node after/before which the container "tr"s should
* get inserted. _node should be a simple DOM node, not a jQuery object.
* @param _prepend specifies whether the container should be inserted before
* or after the given node. Inserting before is needed for inserting the
* first element in front of an spacer.
*/
insertIntoTree(_node: JQuery, _prepend: boolean)
{
if (!this._inTree && _node != null && this._nodes.length > 0)
{
// Store the parent node and indicate that this element is now in
// the tree.
this._attachData = {node: _node, prepend: _prepend};
this._inTree = true;
for (let i = 0; i < this._nodes.length; i++)
{
if (i == 0)
{
if (_prepend)
{
_node.before(this._nodes[0]);
}
else
{
_node.after(this._nodes[0]);
}
}
else
{
// Insert all following nodes after the previous node
this._nodes[i - 1].after(this._nodes[i]);
}
}
// Invalidate this element in order to update the height of the
// parent
this.invalidate();
}
}
/**
* Removes all container nodes from the tree.
*/
removeFromTree()
{
if (this._inTree)
{
// Call the jQuery remove function to remove all nodes from the tree
// again.
for (let i = 0; i < this._nodes.length; i++)
{
this._nodes[i].remove();
}
// Reset the "attachData"
this._inTree = false;
this._attachData = {"node": null, "prepend": false};
}
}
/**
* Appends a node to the container.
*
* @param _node is the DOM-Node which should be appended.
*/
appendNode(_node : JQuery | HTMLElement)
{
// Add the given node to the "nodes" array
this._nodes.push(_node);
// If the container is already in the tree, attach the given node to the
// tree.
if (this._inTree)
{
if (this._nodes.length === 1)
{
if (this._attachData.prepend)
{
this._attachData.node.before(_node);
}
else
{
this._attachData.node.after(_node);
}
}
else
{
this._nodes[this._nodes.length - 2].after(_node);
}
this.invalidate();
}
}
/**
* Removes a certain node from the container
*
* @param {HTMLElement} _node
*/
removeNode(_node: HTMLElement)
{
// Get the index of the node in the nodes array
const idx = this._nodes.indexOf(_node);
if (idx >= 0)
{
// Remove the node if the container is currently attached
if (this._inTree)
{
_node.parentNode.removeChild(_node);
}
// Remove the node from the nodes array
this._nodes.splice(idx, 1);
}
}
/**
* Returns the last node of the container - new nodes have to be appended
* after it.
*/
getLastNode()
{
if (this._nodes.length > 0)
{
return this._nodes[this._nodes.length - 1];
}
return null;
}
/**
* Returns the first node of the container.
*/
getFirstNode()
{
return this._nodes.length > 0 ? this._nodes[0] : null;
}
/**
* Returns the accumulated height of all container nodes. Only visible nodes
* (without "display: none" etc.) are taken into account.
*/
getHeight()
{
if (this._height === -1 && this._inTree)
{
this._height = 0;
// Setting this before measuring height helps with issues getting the
// wrong height due to margins & collapsed borders
this.tr.css('display','block');
// Increment the height value for each visible container node
for (let i = 0; i < this._nodes.length; i++)
{
if (et2_dataview_container._isVisible(this._nodes[i][0]))
{
this._height += et2_dataview_container._nodeHeight(this._nodes[i][0]);
}
}
this.tr.css('display','');
}
return ( this._height === -1 ) ? 0 : this._height;
}
/**
* Returns a datastructure containing information used for calculating the
* average row height of a grid.
* The datastructure has the
* {
* avgHeight: <the calculated average height of this element>,
* avgCount: <the element count this calculation was based on>
* }
*/
getAvgHeightData()
{
return {
"avgHeight": this.getHeight(),
"avgCount": 1
};
}
/**
* Returns the previously set "pixel top" of the container.
*/
getTop()
{
return this._top;
}
/**
* Returns the "pixel bottom" of the container.
*/
getBottom()
{
return this._top + this.getHeight();
}
/**
* Returns the range of the element.
*/
getRange()
{
return et2_bounds(this.getTop(), this.getBottom());
}
/**
* Returns the index of the element.
*/
getIndex()
{
return this._index;
}
/**
* Returns how many elements this container represents.
*/
getCount()
{
return 1;
}
/**
* Sets the top of the element.
*
* @param {number} _value
*/
setTop(_value)
{
this._top = _value;
}
/**
* Sets the index of the element.
*
* @param {number} _value
*/
setIndex(_value)
{
this._index = _value;
}
/* -- et2_dataview_IInvalidatable -- */
/**
* Broadcasts an invalidation through the container tree. Marks the own
* height as invalid.
*/
invalidate()
{
// Abort if this element is already marked as invalid.
if ( this._height !== -1)
{
// Delete the own, probably computed height
this._height = -1;
// Broadcast the invalidation to the parent element
this._parent.invalidate();
}
}
/* -- PRIVATE FUNCTIONS -- */
/**
* Used to check whether an element is visible or not (non recursive).
*
* @param _obj is the element which should be checked for visibility, it is
* only checked whether some stylesheet makes the element invisible, not if
* the given object is actually inside the DOM.
*/
private static _isVisible(_obj : HTMLElement)
{
// Check whether the element is localy invisible
if (_obj.style && (_obj.style.display === "none"
|| _obj.style.visibility === "none"))
{
return false;
}
// Get the computed style of the element
const style = window.getComputedStyle ? window.getComputedStyle(_obj, null)
// @ts-ignore
: _obj.currentStyle;
if (style.display === "none" || style.visibility === "none")
{
return false;
}
return true;
}
/**
* Returns the height of a node in pixels and zero if the element is not
* visible. The height is clamped to positive values.
*
* @param {HTMLElement} _node
*/
private static _nodeHeight(_node : HTMLElement)
{
return _node.offsetHeight;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,9 @@ declare class et2_DOMWidget extends et2_widget{}
declare class et2_baseWidget extends et2_DOMWidget{}
declare class et2_valueWidget extends et2_baseWidget{}
declare class et2_inputWidget extends et2_valueWidget{
getInputNode() : HTMLElement
getInputNode() : HTMLElement;
public set_value(value: string | object | number);
public getValue() : any;
}
declare class et2_tabbox extends et2_valueWidget {
tabData : any;
@ -49,7 +51,13 @@ declare var et2_dataview_row : any;
declare var et2_dataview_rowProvider : any;
declare var et2_dataview_spacer : any;
declare var et2_dataview_tile : any;
declare var et2_customfields_list : any;
declare class et2_customfields_list extends et2_valueWidget {
constructor(_parent: any, _attrs: WidgetConfig, object: object);
public static readonly prefix : string;
public customfields : any;
set_visible(visible : boolean);
}
declare var et2_INextmatchHeader : any;
declare var et2_INextmatchSortable : any;
declare var et2_nextmatch : any;
@ -116,12 +124,16 @@ declare var et2_selectAccount_ro : any;
declare class et2_selectbox extends et2_inputWidget {
protected options : any;
public createInputWidget();
public set_multiple(boolean);
public set_select_options(options: any);
}
declare var et2_selectbox_ro : any;
declare var et2_menulist : any;
declare var et2_split : any;
declare var et2_styles : any;
declare class et2_taglist extends et2_selectbox {}
declare class et2_taglist extends et2_selectbox {
protected div : JQuery;
}
declare var et2_taglist_account : any;
declare var et2_taglist_email : any;
declare var et2_taglist_category : any;