diff --git a/README.md b/README.md
index 727a90f83..c3fd472b6 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,9 @@ It also highlights a DOM-based custom external editor triggered via hypergrid ev
* [Roadmap](#roadmap)
* [Contributing](#contributors)
-### Current Release (2.1.4 - 20 February 2018)
+### Current Release (2.1.5 - 6 March 2018)
-**Hypergrid 2.1.4** includes bug fixes and new properties and methods that offer new capabilities.
+**Hypergrid 2.1.5** includes bug fixes.
_For a complete list of changes, see the [release notes](https://github.com/fin-hypergrid/core/releases)._
diff --git a/demo/index.html b/demo/index.html
index 18560fdf6..6873d555b 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -12,7 +12,7 @@
-
Dashboard
diff --git a/demo/multiple-grids.html b/demo/multiple-grids.html
index 9d47339e7..88767161e 100644
--- a/demo/multiple-grids.html
+++ b/demo/multiple-grids.html
@@ -5,7 +5,7 @@
-
Hypergrid 2.1.4 multiple grids demo
+
Hypergrid 2.1.5 multiple grids demo
diff --git a/demo/row-props.html b/demo/row-props.html
index 3451a1bf9..940fdaec8 100644
--- a/demo/row-props.html
+++ b/demo/row-props.html
@@ -38,7 +38,7 @@
-
Hypergrid 2.1.4 performance workbench
+
Hypergrid 2.1.5 performance workbench
diff --git a/package-lock.json b/package-lock.json
index c88156287..157c76fb9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "fin-hypergrid",
- "version": "2.1.4",
+ "version": "2.1.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index dbd4661c6..f7d943b82 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "fin-hypergrid",
- "version": "2.1.4",
+ "version": "2.1.5",
"description": "Canvas-based high-performance grid",
"repository": {
"type": "git",
diff --git a/src/Hypergrid.js b/src/Hypergrid.js
index c51c4a643..07e50de49 100644
--- a/src/Hypergrid.js
+++ b/src/Hypergrid.js
@@ -121,6 +121,8 @@ var Hypergrid = Base.extend('Hypergrid', {
*/
this.cellEditors = new CellEditors({ grid: this });
+ this.initCanvas();
+
if (this.options.Behavior) {
this.setBehavior(this.options); // also sets this.options.pipeline and this.options.data
} else if (this.options.data) {
@@ -797,7 +799,6 @@ var Hypergrid = Base.extend('Hypergrid', {
// 2. Called from `setData` _and_ wasn't called explicitly since instantiation
var Behavior = options.Behavior || behaviorJSON;
this.behavior = new Behavior(this, options);
- this.initCanvas();
this.initScrollbars();
this.refreshProperties();
this.behavior.reindex();
@@ -1029,14 +1030,16 @@ var Hypergrid = Base.extend('Hypergrid', {
/**
* @memberOf Hypergrid#
* @desc Switch the cursor for a grid instance.
- * @param {string} cursorName - A well know cursor name.
+ * @param {string|string[]} cursorName - A well know cursor name.
* @see [cursor names](http://www.javascripter.net/faq/stylesc.htm)
*/
beCursor: function(cursorName) {
if (!cursorName) {
- cursorName = 'default';
+ cursorName = ['default'];
+ } else if (!Array.isArray(cursorName)) {
+ cursorName = [cursorName];
}
- this.div.style.cursor = cursorName;
+ cursorName.forEach(function(name) { this.cursor = name; }, this.div.style);
},
/**
@@ -1768,6 +1771,22 @@ var Hypergrid = Base.extend('Hypergrid', {
return this.behavior.getHeaderRowCount();
},
+ /**
+ * @returns {number} The total number of rows of all subgrids following the data subgrid.
+ * @memberOf Hypergrid#
+ */
+ getFooterRowCount: function() {
+ return this.behavior.getFooterRowCount();
+ },
+
+ /**
+ * @returns {number} The total number of logical rows of all subgrids.
+ * @memberOf Hypergrid#
+ */
+ getLogicalRowCount: function() {
+ return this.behavior.getLogicalRowCount();
+ },
+
isShowFilterRow: function() {
return this.deprecated('isShowFilterRow()', 'properties.showFilterRow', 'v1.2.10');
},
diff --git a/src/behaviors/Behavior.js b/src/behaviors/Behavior.js
index 673a5ec6d..12543f2da 100644
--- a/src/behaviors/Behavior.js
+++ b/src/behaviors/Behavior.js
@@ -539,11 +539,12 @@ var Behavior = Base.extend('Behavior', {
*/
getValue: function(xOrCellEvent, y, dataModel) {
if (typeof xOrCellEvent !== 'object') {
+ var x = xOrCellEvent;
xOrCellEvent = new this.CellEvent;
if (dataModel) {
- xOrCellEvent.resetDataXY(xOrCellEvent, y, dataModel);
+ xOrCellEvent.resetDataXY(x, y, dataModel);
} else {
- xOrCellEvent.resetGridCY(xOrCellEvent, y);
+ xOrCellEvent.resetGridCY(x, y);
}
}
return xOrCellEvent.value;
@@ -575,11 +576,12 @@ var Behavior = Base.extend('Behavior', {
if (typeof xOrCellEvent === 'object') {
value = y;
} else {
+ var x = xOrCellEvent;
xOrCellEvent = new this.CellEvent;
if (dataModel) {
- xOrCellEvent.resetDataXY(xOrCellEvent, y, dataModel);
+ xOrCellEvent.resetDataXY(x, y, dataModel);
} else {
- xOrCellEvent.resetGridCY(xOrCellEvent, y);
+ xOrCellEvent.resetGridCY(x, y);
}
}
xOrCellEvent.value = value;
@@ -605,7 +607,7 @@ var Behavior = Base.extend('Behavior', {
getCellOwnProperties: function(xOrCellEvent, y, dataModel) {
switch (arguments.length) {
case 1: // xOrCellEvent is cellEvent
- return xOrCellEvent.column.getCellOwnProperties(xOrCellEvent.dataCell.y, xOrCellEvent.visibleRow.subgrid);
+ return xOrCellEvent.column.getCellOwnProperties(xOrCellEvent.dataCell.y, xOrCellEvent.subgrid);
case 2: case 3: // xOrCellEvent is x
return this.getColumn(xOrCellEvent).getCellOwnProperties(y, dataModel);
}
@@ -661,9 +663,9 @@ var Behavior = Base.extend('Behavior', {
setCellProperties: function(xOrCellEvent, y, properties, dataModel) {
if (typeof xOrCellEvent === 'object') {
properties = y;
- xOrCellEvent.column.setCellProperties(xOrCellEvent.dataCell.y, properties, xOrCellEvent.visibleRow.subgrid);
+ return xOrCellEvent.column.setCellProperties(xOrCellEvent.dataCell.y, properties, xOrCellEvent.subgrid);
} else {
- this.getColumn(xOrCellEvent).setCellProperties(y, properties, dataModel);
+ return this.getColumn(xOrCellEvent).setCellProperties(y, properties, dataModel);
}
},
@@ -678,9 +680,9 @@ var Behavior = Base.extend('Behavior', {
addCellProperties: function(xOrCellEvent, y, properties, dataModel) {
if (typeof xOrCellEvent === 'object') {
properties = y;
- xOrCellEvent.column.addCellProperties(xOrCellEvent.dataCell.y, properties, xOrCellEvent.visibleRow.subgrid); // y omitted so y here is actually properties
+ return xOrCellEvent.column.addCellProperties(xOrCellEvent.dataCell.y, properties, xOrCellEvent.subgrid); // y omitted so y here is actually properties
} else {
- this.getColumn(xOrCellEvent).addCellProperties(y, properties, dataModel);
+ return this.getColumn(xOrCellEvent).addCellProperties(y, properties, dataModel);
}
},
@@ -754,8 +756,8 @@ var Behavior = Base.extend('Behavior', {
*/
getRowProperties: function(yOrCellEvent, properties, dataModel) {
if (typeof yOrCellEvent === 'object') {
- yOrCellEvent = yOrCellEvent.dataCell.y;
dataModel = yOrCellEvent.subgrid;
+ yOrCellEvent = yOrCellEvent.dataCell.y;
}
var metadata = (dataModel || this.dataModel).getRowMetadata(yOrCellEvent, properties && {});
@@ -771,8 +773,8 @@ var Behavior = Base.extend('Behavior', {
*/
setRowProperties: function(yOrCellEvent, properties, dataModel) {
if (typeof yOrCellEvent === 'object') {
- yOrCellEvent = yOrCellEvent.dataCell.y;
dataModel = yOrCellEvent.subgrid;
+ yOrCellEvent = yOrCellEvent.dataCell.y;
}
(dataModel || this.dataModel).getRowMetadata(yOrCellEvent, {}, dataModel).__ROW = properties;
@@ -1186,7 +1188,7 @@ var Behavior = Base.extend('Behavior', {
*/
getFixedRowCount: function() {
return (
- this.grid.getHeaderRowCount() +
+ this.getHeaderRowCount() +
this.grid.properties.fixedRowCount
);
},
diff --git a/src/behaviors/subgrids.js b/src/behaviors/subgrids.js
index 6623b0990..084256063 100644
--- a/src/behaviors/subgrids.js
+++ b/src/behaviors/subgrids.js
@@ -99,7 +99,7 @@ module.exports = {
/**
* @summary Gets the number of "header rows".
- * @desc Defined as the sum of all rows of all subgrids before the (first) data subgrid.
+ * @desc Defined as the sum of all rows in all subgrids before the (first) data subgrid.
* @memberOf behaviors.JSON.prototype
*/
getHeaderRowCount: function() {
@@ -113,6 +113,34 @@ module.exports = {
});
return result;
+ },
+
+ /**
+ * @summary Gets the number of "footer rows".
+ * @desc Defined as the sum of all rows in all subgrids after the (last) data subgrid.
+ * @memberOf behaviors.JSON.prototype
+ */
+ getFooterRowCount: function() {
+ var gotData;
+ return this.subgrids.reduce(function(rows, subgrid) {
+ if (gotData && !subgrid.isData) {
+ rows += subgrid.getRowCount();
+ } else {
+ gotData = subgrid.isData;
+ }
+ return rows;
+ }, 0);
+ },
+
+ /**
+ * @summary Gets the total number of logical rows.
+ * @desc Defined as the sum of all rows in all subgrids.
+ * @memberOf behaviors.JSON.prototype
+ */
+ getLogicalRowCount: function() {
+ return this.subgrids.reduce(function(rows, subgrid) {
+ return (rows += subgrid.getRowCount());
+ }, 0);
}
};
diff --git a/src/features/ColumnMoving.js b/src/features/ColumnMoving.js
index 31f25114b..3f6579d17 100644
--- a/src/features/ColumnMoving.js
+++ b/src/features/ColumnMoving.js
@@ -8,8 +8,9 @@
var Feature = require('./Feature');
-var canDragCursorName = '-webkit-grab',
- draggingCursorName = '-webkit-grabbing';
+var GRAB = ['grab', '-moz-grab', '-webkit-grab'],
+ GRABBING = ['grabbing', '-moz-grabbing', '-webkit-grabbing'],
+ setName = function(name) { this.cursor = name; };
var columnAnimationTime = 150;
var dragger;
@@ -163,7 +164,7 @@ var ColumnMoving = Feature.extend('ColumnMoving', {
) {
if (event.isHeaderCell) {
this.dragArmed = true;
- this.cursor = draggingCursorName;
+ this.cursor = GRABBING;
grid.clearSelections();
}
}
@@ -213,7 +214,7 @@ var ColumnMoving = Feature.extend('ColumnMoving', {
event.isHeaderCell &&
event.mousePoint.y < grid.properties.columnGrabMargin
) {
- this.cursor = canDragCursorName;
+ this.cursor = GRAB;
} else {
this.cursor = null;
}
@@ -223,7 +224,7 @@ var ColumnMoving = Feature.extend('ColumnMoving', {
}
if (event.isHeaderCell && this.dragging) {
- this.cursor = draggingCursorName; //move';
+ this.cursor = GRABBING;
}
},
@@ -386,7 +387,7 @@ var ColumnMoving = Feature.extend('ColumnMoving', {
style.zIndex = '4';
this.setCrossBrowserProperty(d, 'transform', 'translate(' + startX + 'px, ' + -2 + 'px)');
- style.cursor = draggingCursorName;
+ GRABBING.forEach(setName, style);
grid.repaint();
},
@@ -472,7 +473,7 @@ var ColumnMoving = Feature.extend('ColumnMoving', {
this.setCrossBrowserProperty(d, 'transform', 'translate(' + x + 'px, -5px)');
style.zIndex = '5';
- style.cursor = draggingCursorName;
+ GRABBING.forEach(setName, style);
grid.repaint();
},
diff --git a/src/lib/events.js b/src/lib/events.js
index aecb00244..d4aca0e4a 100644
--- a/src/lib/events.js
+++ b/src/lib/events.js
@@ -335,7 +335,7 @@ module.exports = {
var self = this;
function handleMouseEvent(e, cb) {
- if (self.getRowCount() === 0) {
+ if (self.getLogicalRowCount() === 0) {
return;
}
diff --git a/src/lib/selection.js b/src/lib/selection.js
index 5d75ac77e..0fc3fa08b 100644
--- a/src/lib/selection.js
+++ b/src/lib/selection.js
@@ -394,10 +394,14 @@ module.exports = {
},
selectViewportCell: function(x, y) {
- var headerRowCount = this.getHeaderRowCount();
- x = this.renderer.visibleColumns[x].columnIndex;
- if (this.getRowCount() > 0) {
- y = this.renderer.visibleRows[y + headerRowCount].rowIndex;
+ var vc, vr;
+ if (
+ this.getRowCount() &&
+ (vc = this.renderer.visibleColumns[x]) &&
+ (vr = this.renderer.visibleRows[y + this.getHeaderRowCount()])
+ ) {
+ x = vc.columnIndex;
+ y = vr.rowIndex;
this.clearSelections();
this.select(x, y, 0, 0);
this.setMouseDown(this.newPoint(x, y));
@@ -407,78 +411,87 @@ module.exports = {
},
selectToViewportCell: function(x, y) {
- var selections = this.getSelections();
- if (selections && selections.length) {
- var headerRowCount = this.getHeaderRowCount(),
- selection = selections[0],
- origin = selection.origin;
- x = this.renderer.visibleColumns[x].columnIndex;
- y = this.renderer.visibleRows[y + headerRowCount].rowIndex;
+ var selections, vc, vr;
+ if (
+ (selections = this.getSelections()) && selections.length &&
+ (vc = this.renderer.visibleColumns[x]) &&
+ (vr = this.renderer.visibleRows[y + this.getHeaderRowCount()])
+ ) {
+ var origin = selections[0].origin;
+ x = vc.columnIndex;
+ y = vr.rowIndex;
this.setDragExtent(this.newPoint(x - origin.x, y - origin.y));
this.select(origin.x, origin.y, x - origin.x, y - origin.y);
this.repaint();
}
},
- selectFinalCellOfCurrentRow: function() {
- var x = this.getColumnCount() - 1,
- y = this.getSelectedRows()[0],
- headerRowCount = this.getHeaderRowCount();
- this.clearSelections();
- this.scrollBy(this.getColumnCount(), 0);
- this.select(x, y + headerRowCount, 0, 0);
- this.setMouseDown(this.newPoint(x, y + headerRowCount));
- this.setDragExtent(this.newPoint(0, 0));
- this.repaint();
+ selectToFinalCellOfCurrentRow: function() {
+ this.selectFinalCellOfCurrentRow(true);
},
- selectToFinalCellOfCurrentRow: function() {
+ selectFinalCellOfCurrentRow: function(to) {
+ if (!this.getRowCount()) {
+ return;
+ }
var selections = this.getSelections();
if (selections && selections.length) {
var selection = selections[0],
origin = selection.origin,
extent = selection.extent,
columnCount = this.getColumnCount();
+
this.scrollBy(columnCount, 0);
this.clearSelections();
- this.select(origin.x, origin.y, columnCount - origin.x - 1, extent.y);
+ if (to) {
+ this.select(origin.x, origin.y, columnCount - origin.x - 1, extent.y);
+ } else {
+ this.select(columnCount - 1, origin.y, 0, 0);
+ }
this.repaint();
}
},
- selectFirstCellOfCurrentRow: function() {
- var x = 0,
- y = this.getSelectedRows()[0],
- headerRowCount = this.getHeaderRowCount();
- this.clearSelections();
- this.setHScrollValue(0);
- this.select(x, y + headerRowCount, 0, 0);
- this.setMouseDown(this.newPoint(x, y + headerRowCount));
- this.setDragExtent(this.newPoint(0, 0));
- this.repaint();
+ selectToFirstCellOfCurrentRow: function() {
+ this.selectFirstCellOfCurrentRow(true);
},
- selectToFirstCellOfCurrentRow: function() {
+ selectFirstCellOfCurrentRow: function(to) {
+ if (!this.getRowCount()) {
+ return;
+ }
var selections = this.getSelections();
if (selections && selections.length) {
var selection = selections[0],
origin = selection.origin,
extent = selection.extent;
+
this.clearSelections();
- this.select(origin.x, origin.y, -origin.x, extent.y);
+ if (to) {
+ this.select(origin.x, origin.y, -origin.x, extent.y);
+ } else {
+ this.select(0, origin.y, 0, 0);
+ }
+
this.setHScrollValue(0);
this.repaint();
}
},
selectFinalCell: function() {
+ if (!this.getRowCount()) {
+ return;
+ }
this.selectCellAndScrollToMakeVisible(this.getColumnCount() - 1, this.getRowCount() - 1);
this.repaint();
},
selectToFinalCell: function() {
+ if (!this.getRowCount()) {
+ return;
+ }
var selections = this.getSelections();
if (selections && selections.length) {
var selection = selections[0],
@@ -488,7 +501,7 @@ module.exports = {
this.clearSelections();
this.select(origin.x, origin.y, columnCount - origin.x - 1, rowCount - origin.y - 1);
- this.scrollBy(columnCount, rowCount);
+ // this.scrollBy(columnCount, rowCount);
this.repaint();
}
},
@@ -705,15 +718,8 @@ module.exports = {
* @memberOf Hypergrid#
*/
getGridCellFromLastSelection: function(useAllCells) {
- var cellEvent,
- sel = this.selectionModel.getLastSelection();
-
- if (sel) {
- cellEvent = new this.behavior.CellEvent;
- cellEvent.resetGridXDataY(sel.origin.x, sel.origin.y, null, useAllCells);
- }
-
- return cellEvent;
+ var sel = this.selectionModel.getLastSelection();
+ return sel && (new this.behavior.CellEvent).resetGridXDataY(sel.origin.x, sel.origin.y, null, useAllCells);
}
};
diff --git a/src/renderer/index.js b/src/renderer/index.js
index 20e1f828f..37956b216 100644
--- a/src/renderer/index.js
+++ b/src/renderer/index.js
@@ -1282,15 +1282,7 @@ function computeCellsBounds() {
}
// get height of total number of rows in all subgrids following the data subgrid
- footerHeight = gridProps.defaultRowHeight *
- subgrids.reduce(function(rows, subgrid) {
- if (scrollableSubgrid) {
- rows += subgrid.getRowCount();
- } else {
- scrollableSubgrid = subgrid.isData;
- }
- return rows;
- }, 0);
+ footerHeight = gridProps.defaultRowHeight * behavior.getFooterRowCount();
for (
base = r = g = y = 0, G = subgrids.length, Y = bounds.height - footerHeight;