diff --git a/etemplate/js/et2_core_DOMWidget.js b/etemplate/js/et2_core_DOMWidget.js index f9b6a997ac..9befec8301 100644 --- a/etemplate/js/et2_core_DOMWidget.js +++ b/etemplate/js/et2_core_DOMWidget.js @@ -151,7 +151,7 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { } // Append this node at its index - var idx = this._parent ? this._parent.getChildren().indexOf(this) : -1; + var idx = this.getDOMIndex(); if (idx < 0 || idx >= this.parentNode.childNodes.length - 1) { this.parentNode.appendChild(node); @@ -210,6 +210,31 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { return this.parentNode; }, + /** + * Returns the index of this element in the DOM tree + */ + getDOMIndex: function() { + if (this._parent) + { + var idx = 0; + var children = this._parent.getChildren(); + + for (var i = 0; i < children.length; i++) + { + if (children[i] == this) + { + return idx; + } + else if (children[i].isInTree()) + { + idx++; + } + } + } + + return -1; + }, + /** * Sets the id of the DOM-Node. */ diff --git a/etemplate/js/et2_core_arrayMgr.js b/etemplate/js/et2_core_arrayMgr.js index a2397c9d74..bded44d73b 100644 --- a/etemplate/js/et2_core_arrayMgr.js +++ b/etemplate/js/et2_core_arrayMgr.js @@ -43,7 +43,6 @@ var et2_arrayMgr = Class.extend({ this.perspectiveData = { "owner": null, "key": null, - "col": 0, "row": 0 } }, @@ -217,7 +216,7 @@ var et2_arrayMgr = Class.extend({ return et2_evalBool(val); }, - openPerspective: function(_owner, _root, _col, _row) + openPerspective: function(_owner, _root, _row) { // Get the root node var root = typeof _root == "string" ? this.data[_root] : @@ -235,10 +234,9 @@ var et2_arrayMgr = Class.extend({ mgr.perspectiveData.key = _root; } - // Set the _col and _row parameter - if (typeof _col != "undefined" && typeof _row != "undefined") + // Set _row parameter + if (typeof _row != "undefined") { - mgr.perspectiveData.col = _col; mgr.perspectiveData.row = _row; } @@ -283,4 +281,26 @@ var et2_readonlysArrayMgr = et2_arrayMgr.extend({ }); +/** + * Creates a new set of array managers + */ +function et2_arrayMgrs_expand(_owner, _mgrs, _data, _row) +{ + // Create a copy of the given _mgrs associative array + var result = {}; + + // Merge the given data associative array into the existing array managers + for (var key in _data) + { + if (typeof _mgrs[key] != "undefined") + { + // Open a perspective for the given data row + result[key] = _mgrs[key].openPerspective(_owner, + _data[key], _row); + } + } + + // Return the resulting managers object + return result; +} diff --git a/etemplate/js/et2_core_widget.js b/etemplate/js/et2_core_widget.js index 8738ca446b..27f36f3613 100644 --- a/etemplate/js/et2_core_widget.js +++ b/etemplate/js/et2_core_widget.js @@ -229,10 +229,14 @@ var et2_widget = Class.extend({ this._parent.removeChild(this); } - // Delete all references to other objects - this._children = []; - this._parent = null; - this._mgrs = {}; + // Free the array managers if they belong to this widget + for (var key in this._mgrs) + { + if (this._mgrs[key] && this._mgrs[key].owner == this) + { + this._mgrs[key].free(); + } + } }, /** diff --git a/etemplate/js/et2_dataview_model_dataProvider.js b/etemplate/js/et2_dataview_model_dataProvider.js index 5567e4daca..eb58451188 100644 --- a/etemplate/js/et2_dataview_model_dataProvider.js +++ b/etemplate/js/et2_dataview_model_dataProvider.js @@ -19,12 +19,16 @@ var et2_dataview_dataProvider = Class.extend({ + init: function() { + this.updateQueue = 0; + }, + getCount: function() { return 10000; }, - registerDataRow: function(_idx, _dataRow) { - var row = { + registerDataRow: function(_dataRow, _idx) { +/* var row = { "type": "dataRow", "data": { "ts_title": "Row " + _idx @@ -41,7 +45,12 @@ var et2_dataview_dataProvider = Class.extend({ } window.setTimeout(function() {_dataRow.updateData(row); }, - Math.round(rnd / 2)); + Math.round(rnd / 2));*/ + + + // All data rows are updated independently of all others - this allows + // user input between generation of the widgets. + window.setTimeout(function() {_dataRow.updateData({"readonlys": {"__ALL__": true}});}, 0); }, unregisterDataRow: function(_dataRow) { diff --git a/etemplate/js/et2_dataview_view_grid.js b/etemplate/js/et2_dataview_view_grid.js index e7a0ba3721..c4b76c3f28 100644 --- a/etemplate/js/et2_dataview_view_grid.js +++ b/etemplate/js/et2_dataview_view_grid.js @@ -28,7 +28,7 @@ var ET2_GRID_VIEW_EXT = 25; /** * Determines the timeout after which the scroll-event is processed. */ -var ET2_GRID_SCROLL_TIMEOUT = 25; +var ET2_GRID_SCROLL_TIMEOUT = 100; var partitionTree = null; @@ -46,7 +46,8 @@ var et2_dataview_grid = Class.extend(et2_dataview_IViewRange, { * classes. * @param _avgHeight is the starting average height of the column rows. */ - init: function(_parent, _outerId, _columnIds, _dataProvider, _avgHeight) { + init: function(_parent, _outerId, _columnIds, _dataProvider, _rowProvider, + _avgHeight) { // If the parent is given, copy all other parameters from it if (_parent != null) @@ -63,12 +64,9 @@ var et2_dataview_grid = Class.extend(et2_dataview_IViewRange, { this._outerId = _outerId; this._columnIds = _columnIds; this._dataProvider = _dataProvider; + this._rowProvider = _rowProvider; this._avgHeight = _avgHeight; - // Create the row provider - this._rowProvider = new et2_dataview_rowProvider(_outerId, - _columnIds); - this._scrollHeight = 0; this._scrollTimeout = null; } @@ -112,9 +110,8 @@ var et2_dataview_grid = Class.extend(et2_dataview_IViewRange, { // Stop the rebuild timer window.clearInterval(this._rebuildTimer); - // Free the partition tree and the row provider + // Free the partition tree this._partitionTree.free(); - this._rowProvider.free(); }, /** diff --git a/etemplate/js/et2_dataview_view_gridContainer.js b/etemplate/js/et2_dataview_view_gridContainer.js index 342e14b369..77ce7b6163 100644 --- a/etemplate/js/et2_dataview_view_gridContainer.js +++ b/etemplate/js/et2_dataview_view_gridContainer.js @@ -52,6 +52,7 @@ var et2_dataview_gridContainer = Class.extend({ this.columnNodes = []; // Array with the header containers this.columns = []; this.columnMgr = null; + this.rowProvider = null; this.grid = null; @@ -80,6 +81,12 @@ var et2_dataview_gridContainer = Class.extend({ this.grid.free(); } + // Free the row provider + if (this.rowProvider) + { + this.rowProvider.free(); + } + // Detatch the outer element this.table.remove(); }, @@ -375,9 +382,17 @@ var et2_dataview_gridContainer = Class.extend({ 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, this.uniqueId, colIds, - this.dataProvider, 19); + this.dataProvider, this.rowProvider, 19); // Insert the grid into the DOM-Tree this.containerTr.append(this.grid.getJNode()); diff --git a/etemplate/js/et2_dataview_view_partitionContainerNodes.js b/etemplate/js/et2_dataview_view_partitionContainerNodes.js index 2e2a34e1f4..d29d282a00 100644 --- a/etemplate/js/et2_dataview_view_partitionContainerNodes.js +++ b/etemplate/js/et2_dataview_view_partitionContainerNodes.js @@ -236,11 +236,9 @@ var et2_dataview_partitionRowNode = et2_dataview_partitionContainerNode.extend({ init: function(_root, _avgHeight) { var container = new et2_dataview_row(_root.getDataProvider(), - _root.getRowProvider(), this); + _root.getRowProvider(), this, _avgHeight); this._super(_root, container); - - this._avgHeight = _avgHeight; }, initializeContainer: function() { diff --git a/etemplate/js/et2_dataview_view_row.js b/etemplate/js/et2_dataview_view_row.js index c8023d9573..e490818664 100644 --- a/etemplate/js/et2_dataview_view_row.js +++ b/etemplate/js/et2_dataview_view_row.js @@ -24,19 +24,66 @@ var et2_dataview_row = et2_dataview_container.extend(et2_dataview_IDataRow, { this._avgHeight = _avgHeight; + this.rowWidget = null; + this.hasAvgHeight = false; + + // Get the default row object and scale the row to the average height this.tr = this.rowProvider.getPrototype("default"); + + // Append the row this.appendNode(this.tr); }, + destroy: function() { + + // Unregister the row from the data provider + this.dataProvider.unregisterDataRow(this); + + // Free the row widget first, if it has been set + if (this.rowWidget) + { + this.rowWidget.free(); + } + + this._super(); + }, + setIdx: function(_idx) { this._idx = _idx; - $j("div:first", this.tr) - .text(_idx + ":") - .height((_idx % 10) * 10 + 20); + // Register the row in the data provider + this.dataProvider.registerDataRow(this, _idx); + + // Set the default height of the rowWidget has not been immediately + // created + if (!this.rowWidget) + { + $j("td:first", this.tr).height(this._avgHeight); + this.hasAvgHeight = true; + } }, updateData: function(_data) { + + // Reset the height + if (this.hasAvgHeight) + { + $j("td:first", this.tr).height("auto"); + this.hasAvgHeight = false; + } + + // Free the row widget if it already existed + if (this.rowWidget != null) + { + this.rowWidget.free(); + } + + // Create the row widget - it automatically generates the widgets and + // attaches the given data to them + this.rowWidget = this.rowProvider.getDataRow(_data, this.tr, this._idx); + + // Invalidate this element + this.invalidate(); } }); diff --git a/etemplate/js/et2_dataview_view_rowProvider.js b/etemplate/js/et2_dataview_view_rowProvider.js index 429228380b..04830a0ced 100644 --- a/etemplate/js/et2_dataview_view_rowProvider.js +++ b/etemplate/js/et2_dataview_view_rowProvider.js @@ -13,6 +13,9 @@ /*egw:uses jquery.jquery; et2_core_inheritance; + et2_core_interfaces; + et2_core_arrayMgr; + et2_core_widget; */ /** @@ -27,6 +30,10 @@ var et2_dataview_rowProvider = Class.extend({ this._columnIds = _columnIds; this._prototypes = {}; + this._dataRowTemplate = null; + this._mgrs = null; + this._rootWidget = null; + // Create the default row "prototypes" this._createFullRowPrototype(); this._createDefaultPrototype(); @@ -55,6 +62,25 @@ var et2_dataview_rowProvider = Class.extend({ return this._prototypes[_name].clone(); }, + setDataRowTemplate: function(_template, _rootWidget) { + this._dataRowTemplate = _template; + this._rootWidget = _rootWidget; + }, + + getDataRow: function(_data, _row, _idx) { + // Create the row widget + var rowWidget = new et2_dataview_rowWidget(this._rootWidget, _row[0]); + + // Create array managers with the given data merged in + var mgrs = et2_arrayMgrs_expand(rowWidget, this._rootWidget.getArrayMgrs(), + _data, _idx); + + // Let the row widget create the widgets + rowWidget.createWidgets(mgrs, this._dataRowTemplate); + + return rowWidget; + }, + /* ---- PRIVATE FUNCTIONS ---- */ _createFullRowPrototype: function() { @@ -93,3 +119,56 @@ var et2_dataview_rowProvider = Class.extend({ }); +var et2_dataview_rowWidget = et2_widget.extend(et2_IDOMNode, { + + init: function(_parent, _row) { + // Call the parent constructor with some dummy attributes + this._super(_parent, {"id": "", "type": "rowWidget"}); + + // Initialize some variables + this._widgets = []; + + // Copy the given DOM node + this._row = _row; + }, + + /** + * Copies the given array manager and clones the given widgets and inserts + * them into the row which has been passed in the constructor. + */ + createWidgets: function(_mgrs, _widgets) { + // Set the array managers - don't use setArrayMgrs here as this creates + // an unnecessary copy of the object + this._mgrs = _mgrs; + + // Clone the given the widgets with this element as parent + this._widgets = new Array(_widgets.length); + for (var i = 0; i < _widgets.length; i++) + { + this._widgets[i] = _widgets[i].clone(this); + this._widgets[i].loadingFinished(); + } + }, + + /** + * Returns the column node for the given sender + */ + getDOMNode: function(_sender) { + + if (typeof _sender == "undefined" || !_sender) + { + return this.row; + } + + for (var i = 0; i < this._widgets.length; i++) + { + if (this._widgets[i] == _sender) + { + return this._row.childNodes[i]; // Return the i-th td tag + } + } + } + +}); + + diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index cbe6c5806b..e91b68af6d 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -214,6 +214,27 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, { }, + _parseDataRow: function(_row, _colData) { + var columnWidgets = new Array(this.columns.length); + + for (var x = 0; x < columnWidgets.length; x++) + { + if (typeof _row[x] != "undefined" && _row[x].widget) + { + columnWidgets[x] = _row[x].widget; + + // Append the widget to this container + this.addChild(_row[x].widget); + } + else + { + columnWidgets[x] = _row[x].widget; + } + } + + this.dataviewContainer.rowProvider.setDataRowTemplate(columnWidgets, this); + }, + _parseGrid: function(_grid) { // Search the rows for a header-row - if one is found, parse it for (var y = 0; y < _grid.rowData.length; y++) @@ -222,6 +243,10 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, { { this._parseHeaderRow(_grid.cells[y], _grid.colData); } + else + { + this._parseDataRow(_grid.cells[y], _grid.colData); + } } }, diff --git a/etemplate/js/test/et2_test_nextmatch.xet b/etemplate/js/test/et2_test_nextmatch.xet index 62fd8c63a9..7b4e189061 100644 --- a/etemplate/js/test/et2_test_nextmatch.xet +++ b/etemplate/js/test/et2_test_nextmatch.xet @@ -62,6 +62,71 @@ + + + +