fin-hypergrid
Advanced tools
Comparing version 2.1.5 to 2.1.6
{ | ||
"name": "fin-hypergrid", | ||
"version": "2.1.5", | ||
"version": "2.1.6", | ||
"description": "Canvas-based high-performance grid", | ||
@@ -19,3 +19,3 @@ "repository": { | ||
"chai": "^3.5.0", | ||
"extend-me": "^2.3", | ||
"extend-me": "^2.7.0", | ||
"fin-hypergrid-data-source-base": "^0.4.10", | ||
@@ -29,3 +29,4 @@ "fin-hypergrid-event-logger": "^1.0.3", | ||
"rectangular": "1.0.1", | ||
"sparse-boolean-array": "1.0.1" | ||
"sparse-boolean-array": "1.0.1", | ||
"synonomous": "^1.0.1" | ||
}, | ||
@@ -32,0 +33,0 @@ "devDependencies": { |
@@ -19,5 +19,5 @@ [![Build Status](https://travis-ci.org/openfin/fin-hypergrid.svg?branch=develop)](https://travis-ci.org/openfin/fin-hypergrid) | ||
### Current Release (2.1.5 - 6 March 2018) | ||
### Current Release (2.1.6 - 16 March 2018) | ||
**Hypergrid 2.1.5** includes bug fixes. | ||
**Hypergrid 2.1.6** includes bug fixes. | ||
@@ -24,0 +24,0 @@ _For a complete list of changes, see the [release notes](https://github.com/fin-hypergrid/core/releases)._ |
@@ -8,4 +8,6 @@ 'use strict'; | ||
var cellEventFactory = require('../lib/cellEventFactory'); | ||
var Features = require('../features'); | ||
var featureRegistry = require('../features'); | ||
var Synonomous = require('synonomous'); | ||
var propClassEnum = require('../defaults.js').propClassEnum; | ||
var assignOrDelete = require('../lib/misc').assignOrDelete; | ||
@@ -46,2 +48,4 @@ | ||
this.synonomous = new Synonomous; | ||
this.initializeFeatureChain(); | ||
@@ -77,3 +81,3 @@ | ||
this.featureRegistry = this.featureRegistry || new Features; | ||
this.featureRegistry = this.featureRegistry || featureRegistry; | ||
@@ -137,2 +141,5 @@ if (this.grid.properties.features) { | ||
this.rowPropertiesPrototype = Object.create(this.grid.properties, | ||
require('./rowProperties').rowPropertiesPrototypeDescriptors); | ||
this.clearColumns(); | ||
@@ -208,3 +215,3 @@ this.createColumns(); | ||
/** | ||
* The "grid index" given a "data index" (or column object) | ||
* The "grid index" of an active column given a "data index" (number), column name (string), or column object | ||
* @param {Column|number} columnOrIndex | ||
@@ -214,9 +221,7 @@ * @returns {undefined|number} The grid index of the column or undefined if column not in grid. | ||
*/ | ||
getActiveColumnIndex: function(columnOrIndex) { | ||
var index = columnOrIndex instanceof Column ? columnOrIndex.index : columnOrIndex; | ||
for (var i = 0; i < this.columns.length; ++i) { | ||
if (this.columns[i].index === index) { | ||
return i; | ||
} | ||
} | ||
getActiveColumnIndex: function(columnOrIndexOrName) { | ||
var value = columnOrIndexOrName instanceof Column ? columnOrIndexOrName.index : columnOrIndexOrName, | ||
key = typeof index === 'number' ? 'index' : 'name'; | ||
return this.columns.findIndex(function(column) { return column[key] === value; }); | ||
}, | ||
@@ -246,5 +251,12 @@ | ||
addColumn: function(options) { | ||
var column = this.newColumn(options); | ||
this.columns.push(column); | ||
this.allColumns.push(column); | ||
var column = this.newColumn(options), | ||
columns = this.columns, | ||
allColumns = this.allColumns; | ||
columns.push(column); | ||
this.synonomous.decorateList(columns.length - 1, columns); | ||
allColumns.push(column); | ||
this.synonomous.decorateList(allColumns.length - 1, allColumns); | ||
return column; | ||
@@ -255,3 +267,2 @@ }, | ||
this.clearColumns(); | ||
this.clearAllCellProperties(); | ||
//concrete implementation here | ||
@@ -338,3 +349,4 @@ }, | ||
clearState: function() { | ||
this.grid.clearState(); | ||
this.grid.clearState(); | ||
this.createColumns(); | ||
}, | ||
@@ -346,28 +358,55 @@ | ||
* See the [memento pattern](http://c2.com/cgi/wiki?MementoPattern). | ||
* @param {Object} memento - an encapsulated representation of table state | ||
* @param {Object} properties - assignable grid properties | ||
*/ | ||
setState: function(memento) { | ||
setState: function(properties) { | ||
this.addState(properties, true); | ||
}, | ||
if (memento.rowHeights) { | ||
this.deprecated('rowHeights', 'rowHeights, the hash of row heights you provided to setState method, is no longer supported as of v1.2.0 and will be ignored. Instead, for each row height you wish to set, use `rows: { subgrid: { y: { height: heightInPixels } } }` substituting the name (or type) of the subgrid for `subgrid`, the local zero-based rowIndex within the subgrid for `y`, and the row height in pixels for `heightInPixels`; or make individual calls to `setRowHeight(y, heightInPixels, dataModel)`. The dataModel arg is optional and defaults to this.dataModel (the data subgrid); specify to set row heights in other data models, such as header row, filter cell row, individual summary rows, etc.'); | ||
/** | ||
* | ||
* @param {Object} properties - assignable grid properties | ||
* @param {boolean} [settingState] - Clear properties object before assignments. | ||
*/ | ||
addState: function(properties, settingState) { | ||
if (settingState) { | ||
this.clearState(); | ||
} | ||
this.createColumns(); | ||
var gridProps = this.grid.properties; | ||
var state = this.grid.properties; | ||
Object.keys(memento).forEach(function(key) { | ||
state[key] = memento[key]; | ||
}, this); | ||
gridProps.settingState = settingState; | ||
assignOrDelete(gridProps, properties); | ||
delete gridProps.settingState; | ||
this.setAllColumnProperties(memento.columnProperties); | ||
this.reindex(); | ||
}, | ||
this.dataModel.reindex(); | ||
/** | ||
* @summary Sets properties for active columns. | ||
* @desc Sets multiple columns' properties from elements of given array or collection. Keys may be column indexes or column names. The properties collection is cleared first. Falsy elements are ignored. | ||
* @param {object[]|undefined} columnsHash - If undefined, this call is a no-op. | ||
*/ | ||
setAllColumnProperties: function(columnsHash) { | ||
this.addAllColumnProperties(columnsHash, true); | ||
}, | ||
setAllColumnProperties: function(columnProperties) { | ||
if (columnProperties) { | ||
columnProperties.forEach(function(properties, i) { | ||
this.getColumn(i).properties = properties; | ||
}, this); | ||
/** | ||
* @summary Adds properties for multiple columns. | ||
* @desc Adds . The properties collection is optionally cleared first. Falsy elements are ignored. | ||
* @param {object[]|undefined} columnsHash - If undefined, this call is a no-op. | ||
* @param {boolean} [settingState] - Clear columns' properties objects before copying properties. | ||
*/ | ||
addAllColumnProperties: function(columnsHash, settingState) { | ||
if (!columnsHash) { | ||
return; | ||
} | ||
var columns = this.grid.behavior.getColumns(); | ||
Object.keys(columnsHash).forEach(function(key) { | ||
var column = columns[key]; | ||
if (column) { | ||
column.addProperties(columnsHash[key], settingState); | ||
} | ||
}); | ||
}, | ||
@@ -377,6 +416,23 @@ | ||
if (Array.isArray(columnIndexes)){ | ||
this.columns.length = columnIndexes.length; | ||
columnIndexes.forEach(function(index, i) { | ||
this.columns[i] = this.allColumns[index]; | ||
}, this); | ||
var columns = this.columns, | ||
allColumns = this.allColumns; | ||
// avoid recreating the array to keep refs valid; just empty it (including name dictionary) | ||
columns.length = 0; | ||
var tc = this.treeColumnIndex.toString(), rc = this.rowColumnIndex.toString(); | ||
Object.keys(columns).forEach(function(key) { | ||
switch (key) { | ||
case tc: | ||
case rc: | ||
break; | ||
default: | ||
delete columns[key]; | ||
} | ||
}); | ||
columnIndexes.forEach(function(index) { | ||
columns.push(allColumns[index]); | ||
}); | ||
this.synonomous.decorateList(columns); | ||
} | ||
@@ -386,9 +442,5 @@ }, | ||
setColumnOrderByName: function(columnNames) { | ||
if (Array.isArray(columnNames)){ | ||
this.columns.length = columnNames.length; | ||
columnNames.forEach(function(columnName, i) { | ||
this.columns[i] = this.allColumns.find(function(column) { | ||
return column.name === columnName; | ||
}); | ||
}, this); | ||
if (Array.isArray(columnNames)) { | ||
var allColumns = this.allColumns; | ||
this.setColumnOrder(columnNames.map(function(name) { return allColumns[name].index; })); | ||
} | ||
@@ -735,101 +787,3 @@ }, | ||
/** | ||
* @summary The total height of the "fixed rows." | ||
* @desc The total height of all (non-scrollable) rows preceding the (scrollable) data subgrid. | ||
* @memberOf Behavior# | ||
* @return {number} The height in pixels of the fixed rows area of the hypergrid, the total height of: | ||
* 1. All rows of all subgrids preceding the data subgrid. | ||
* 2. The first `fixedRowCount` rows of the data subgrid. | ||
*/ | ||
getFixedRowsHeight: function() { | ||
var dataModel, isData, r, R, | ||
subgrids = this.subgrids, | ||
height = 0; | ||
for (var i = 0; i < subgrids.length && !isData; ++i) { | ||
dataModel = subgrids[i]; | ||
isData = dataModel.isData; | ||
R = isData ? this.grid.properties.fixedRowCount : dataModel.getRowCount(); | ||
for (r = 0; r < R; ++r) { | ||
height += this.getRowHeight(r, dataModel); | ||
} | ||
} | ||
return height; | ||
}, | ||
/** | ||
* @memberOf Behavior# | ||
* @param {number|CellEvent} yOrCellEvent - Data row index local to `dataModel`; or a `CellEvent` object. | ||
* @param {boolean} [properties] - New properties object when one does not already exist. If you don't provide this and one does not already exist, this call will return `undefined`. _(Required when 3rd param provided.)_ | ||
* @param {dataModelAPI} [dataModel=this.dataModel] - This is the subgrid. You only need to provide the subgrid when it is not the data subgrid _and_ you did not give a `CellEvent` object in the first param (which already knows what subgrid it's in). | ||
* @returns {object|undefined} The row properties object which will be one of: | ||
* * The row properties object if it existed. | ||
* * The value you provided in `properties` if the row properties for a new row properties object when the object did not already exist in the metadata | ||
* * `undefined` if the row properties object did not exist _and_ you did not provide a value in `properties`. | ||
*/ | ||
getRowProperties: function(yOrCellEvent, properties, dataModel) { | ||
if (typeof yOrCellEvent === 'object') { | ||
dataModel = yOrCellEvent.subgrid; | ||
yOrCellEvent = yOrCellEvent.dataCell.y; | ||
} | ||
var metadata = (dataModel || this.dataModel).getRowMetadata(yOrCellEvent, properties && {}); | ||
return metadata && (metadata.__ROW || properties && (metadata.__ROW = properties)); | ||
}, | ||
/** | ||
* Reset the row properties in its entirety to the given row properties object. | ||
* @memberOf Behavior# | ||
* @param {number|CellEvent} yOrCellEvent - Data row index local to `dataModel`; or a `CellEvent` object. | ||
* @param {object} properties - The new row properties object. | ||
* @param {dataModelAPI} [dataModel=this.dataModel] - This is the subgrid. You only need to provide the subgrid when it is not the data subgrid _and_ you did not give a `CellEvent` object in the first param (which already knows what subgrid it's in). | ||
*/ | ||
setRowProperties: function(yOrCellEvent, properties, dataModel) { | ||
if (typeof yOrCellEvent === 'object') { | ||
dataModel = yOrCellEvent.subgrid; | ||
yOrCellEvent = yOrCellEvent.dataCell.y; | ||
} | ||
(dataModel || this.dataModel).getRowMetadata(yOrCellEvent, {}, dataModel).__ROW = properties; | ||
this.stateChanged(); | ||
}, | ||
/** | ||
* Sets a single row property on a specific individual row. | ||
* @memberOf Behavior# | ||
* @param {number|CellEvent} yOrCellEvent - Data row index local to `dataModel`; or a `CellEvent` object. | ||
* @param {string} key - The property name. | ||
* @param value - The new property value. | ||
* @param {dataModelAPI} [dataModel=this.dataModel] - This is the subgrid. You only need to provide the subgrid when it is not the data subgrid _and_ you did not give a `CellEvent` object in the first param (which already knows what subgrid it's in). | ||
*/ | ||
setRowProperty: function(yOrCellEvent, key, value, dataModel) { | ||
this.getRowProperties(yOrCellEvent, {}, dataModel)[key] = value; | ||
this.stateChanged(); | ||
}, | ||
/** | ||
* Add all the properties in the given row properties object to the row properties. | ||
* @memberOf Behavior# | ||
* @param {number|CellEvent} yOrCellEvent - Data row index local to `dataModel`; or a `CellEvent` object. | ||
* @param {object} properties - An object containing new property values(s) to assign to the row properties. | ||
* @param {dataModelAPI} [dataModel=this.dataModel] - This is the subgrid. You only need to provide the subgrid when it is not the data subgrid _and_ you did not give a `CellEvent` object in the first param (which already knows what subgrid it's in). | ||
*/ | ||
addRowProperties: function(yOrCellEvent, properties, dataModel) { | ||
Object.assign(this.getRowProperties(yOrCellEvent, {}, dataModel), properties); | ||
this.stateChanged(); | ||
}, | ||
/** | ||
* @memberOf Behavior# | ||
* @param {number} yOrCellEvent - Data row index local to `dataModel`. | ||
* @param {dataModelAPI} [dataModel=this.dataModel] | ||
*/ | ||
getRowHeight: function(yOrCellEvent, dataModel) { | ||
var rowProps = this.getRowProperties(yOrCellEvent, undefined, dataModel); | ||
return rowProps && rowProps.height || this.grid.properties.defaultRowHeight; | ||
}, | ||
/** | ||
* @memberOf Behavior# | ||
* @desc The value is lazily initialized and comes from the properties mechanism for '`defaultRowHeight`', which should be ~20px. | ||
@@ -844,20 +798,2 @@ * @returns {number} The row height in pixels. | ||
* @memberOf Behavior# | ||
* @desc set the pixel height of a specific row | ||
* @param {number} yOrCellEvent - Data row index local to dataModel. | ||
* @param {number} height - pixel height | ||
* @param {dataModelAPI} [dataModel=this.dataModel] | ||
*/ | ||
setRowHeight: function(yOrCellEvent, height, dataModel) { | ||
var rowProps = this.getRowProperties(yOrCellEvent, {}, dataModel), | ||
oldHeight = rowProps.height; | ||
rowProps.height = Math.max(5, Math.ceil(height)); | ||
if (rowProps.height !== oldHeight) { | ||
this.stateChanged(); | ||
} | ||
}, | ||
/** | ||
* @memberOf Behavior# | ||
* @return {number} The width of the fixed column area in the hypergrid. | ||
@@ -1572,4 +1508,5 @@ */ | ||
Behavior.prototype.mixIn(require('./subgrids')); | ||
Behavior.prototype.mixIn(require('./rowProperties').mixin); | ||
module.exports = Behavior; |
@@ -5,2 +5,5 @@ /* eslint-env bro wser */ | ||
var assignOrDelete = require('../lib/misc').assignOrDelete; | ||
/** | ||
@@ -27,3 +30,3 @@ * Column.js mixes this module into its prototype. | ||
* @param {number} rowIndex - Data row coordinate. | ||
* @param {Object} properties - Hash of cell properties. | ||
* @param {object|undefined} properties - Hash of cell properties. If `undefined`, this call is a no-op. | ||
* @returns {*} | ||
@@ -33,3 +36,5 @@ * @memberOf Column# | ||
setCellProperties: function(rowIndex, properties, dataModel) { | ||
return Object.assign(newCellPropertiesObject.call(this, rowIndex, dataModel), properties); | ||
if (properties) { | ||
return assignOrDelete(newCellPropertiesObject.call(this, rowIndex, dataModel), properties); | ||
} | ||
}, | ||
@@ -39,9 +44,10 @@ | ||
* @param {number} rowIndex - Data row coordinate. | ||
* @param {Object} properties - Hash of cell properties. | ||
* @param {boolean} [preserve=false] - Falsy creates new object; truthy copies `properties` members into existing object. | ||
* @returns {*} | ||
* @param {object|undefined} properties - Hash of cell properties. If `undefined`, this call is a no-op. | ||
* @returns {object} Cell's own properties object, which will be created by this call if it did not already exist. | ||
* @memberOf Column# | ||
*/ | ||
addCellProperties: function(rowIndex, properties, dataModel) { | ||
return Object.assign(getCellPropertiesObject.call(this, rowIndex, dataModel), properties); | ||
if (properties) { | ||
return assignOrDelete(getCellPropertiesObject.call(this, rowIndex, dataModel), properties); | ||
} | ||
}, | ||
@@ -48,0 +54,0 @@ |
@@ -9,16 +9,24 @@ /* eslint-env browser */ | ||
var toFunction = require('../lib/toFunction'); | ||
var assignOrDelete = require('../lib/misc').assignOrDelete; | ||
var HypergridError = require('../lib/error'); | ||
var images = require('../../images/index'); | ||
var images = require('../../images'); | ||
var warned = {}; | ||
/** @summary Create a new `Column` object. | ||
* @see {@link module:Cell} is mixed into Column.prototype. | ||
* @mixes cellProperties.columnMixin | ||
* @mixes columnProperties.mixin | ||
* @constructor | ||
* @param behavior | ||
* @param {number|string|object} indexOrOptions - One of: | ||
* * If a positive number, valid index into `fields` array. | ||
* * If a string, a name in the `fields` array. | ||
* * If an object, must contain either an `index` or a `name` property. | ||
* @param {Behavior} behavior | ||
* @param {object} columnSchema | ||
* @param {number} columnSchema.index | ||
* @param {string} columnSchema.name | ||
* @param {string} [columnSchema.header] - Displayed in column headers. If not defined, name is used. | ||
* @param {function} [columnSchema.calculator] - Define to make a computed column. | ||
* @param {string} [columnSchema.type] - For possible data model use. (Not used in core.) | ||
* | ||
* Positive values of `index` are "real" fields; see also {@link Column#setProperties|setProperties} which is called to set the remaining properties specified in `options`. | ||
* Positive values of `index` are "real" fields. | ||
* | ||
@@ -31,51 +39,82 @@ * Negative values of `index` are special cases: | ||
*/ | ||
function Column(behavior, indexOrOptions) { | ||
var index, schema, options, icon; | ||
this.behavior = behavior; | ||
this.dataModel = behavior.dataModel; | ||
schema = this.behavior.dataModel.schema; | ||
switch (typeof indexOrOptions) { | ||
function Column(behavior, columnSchema) { | ||
switch (typeof columnSchema) { | ||
case 'number': | ||
index = indexOrOptions; | ||
options = {}; | ||
if (!warned.number) { | ||
console.warn('Column(behavior: object, index: number) overload has been deprecated as of v2.1.6 in favor of Column(behavior: object, columnSchema: object) overload with defined columnSchema.index. (Will be removed in a future release.)'); | ||
warned.number = true; | ||
} | ||
columnSchema = { | ||
index: columnSchema | ||
}; | ||
break; | ||
case 'string': | ||
index = getIndexFromName(indexOrOptions); | ||
options = {}; | ||
if (!warned.string) { | ||
console.warn('Column(behavior:object, name: string) overload (where name is sought in schema) has been deprecated as of v2.1.6 in favor of Column(behavior: object, columnSchema: object) overload with defined columnSchema.index. (Will be removed in a future release.)'); | ||
warned.string = true; | ||
} | ||
var name, index; | ||
name = columnSchema; | ||
index = behavior.dataModel.schema.findIndex(function(columnSchema) { | ||
return columnSchema.name === name; | ||
}); | ||
if (index < 0) { | ||
throw new ReferenceError('Column named "' + name + '" not found in schema.'); | ||
} | ||
columnSchema = { | ||
name: name, | ||
index: index | ||
}; | ||
break; | ||
case 'object': | ||
options = indexOrOptions; | ||
index = options.index !== undefined | ||
? options.index | ||
: getIndexFromName(options.name); | ||
if (columnSchema.index === undefined) { | ||
if (!warned.object) { | ||
console.warn('Column(behavior:object, columnSchema: object) overload (where columnSchema.index is undefined but columnSchema.name is sought in schema) has been deprecated as of v2.1.6 in favor of defined columnSchema.index. (Will be removed in a future release.)'); | ||
warned.object = true; | ||
} | ||
name = columnSchema.name; | ||
index = behavior.dataModel.schema.findIndex(function(columnSchema) { | ||
return columnSchema.name === name; | ||
}); | ||
if (index < 0) { | ||
throw new ReferenceError('Column named "' + name + '" not found in schema.'); | ||
} | ||
columnSchema.index = index; | ||
} | ||
break; | ||
} | ||
function getIndexFromName(name) { | ||
return schema.findIndex(function(columnSchema, i) { | ||
return columnSchema.name === name; | ||
}); | ||
if (columnSchema.index === undefined) { | ||
throw new HypergridError('Column index required.'); | ||
} | ||
if (index === undefined) { | ||
throw 'Column not found in data.'; | ||
} | ||
this.behavior = behavior; | ||
this.dataModel = behavior.dataModel; | ||
this._index = index; | ||
// set `index` and `name` as read-only properties | ||
Object.defineProperties(this, { | ||
index: { | ||
value: columnSchema.index | ||
}, | ||
name: { | ||
enumerable: true, | ||
value: columnSchema.name || columnSchema.index.toString() | ||
} | ||
}); | ||
this.properties = options; | ||
this.properties = this.schema = columnSchema; // see {@link Column#properties properties} setter | ||
switch (index) { | ||
switch (columnSchema.index) { | ||
case this.behavior.treeColumnIndex: | ||
// Width of icon + 3-pixel spacer (checked and unchecked should be same width) | ||
icon = images[Object.create(this.properties.treeHeader, { isDataRow: { value: true } }).leftIcon]; | ||
var icon = images[Object.create(this.properties.treeHeader, { isDataRow: { value: true } }).leftIcon]; | ||
this.properties.minimumColumnWidth = icon ? icon.width + 3 : 0; | ||
break; | ||
case this.behavior.rowColumnIndex: | ||
break; | ||
default: | ||
if (index < 0) { | ||
throw '`index` out of range'; | ||
if (columnSchema.index < 0) { | ||
throw new RangeError('New column index ' + columnSchema.index + ' out of range.'); | ||
} | ||
@@ -99,19 +138,2 @@ } | ||
/** | ||
* @summary Index of this column in the `fields` array. | ||
* @returns {number} | ||
*/ | ||
get index() { // read-only (no setter) | ||
return this._index; | ||
}, | ||
/** | ||
* @summary Name of this column from the `fields` array. | ||
* @returns {string|undefined} Returns `undefined` if the column is not in the schema (such as for handle column). | ||
*/ | ||
get name() { // read-only (no setter) | ||
var columnSchema = this.dataModel.schema[this._index]; | ||
return columnSchema && columnSchema.name; | ||
}, | ||
/** | ||
* @summary Get or set the text of the column's header. | ||
@@ -121,13 +143,13 @@ * @desc The _header_ is the label at the top of the column. | ||
* Setting the header updates both: | ||
* * the `fields` (aka, header) array in the underlying data source; and | ||
* * the `schema` (aka, header) array in the underlying data source; and | ||
* * the filter. | ||
* @type {string} | ||
*/ | ||
set header(headerText) { | ||
this.dataModel.schema[this.index].header = headerText; | ||
this.dataModel.prop(null, this.index, 'header', headerText); | ||
set header(header) { | ||
this.schema.header = header; | ||
this.dataModel.prop(null, this.index, 'header', header); | ||
this.behavior.grid.repaint(); | ||
}, | ||
get header() { | ||
return this.dataModel.schema[this.index].header; | ||
return this.schema.header; | ||
}, | ||
@@ -145,18 +167,10 @@ | ||
set calculator(calculator) { | ||
var schema = this.dataModel.schema; | ||
calculator = resolveCalculator.call(this, calculator); | ||
if (calculator !== schema[this.index].calculator) { | ||
if (calculator === undefined) { | ||
delete schema[this.index].calculator; | ||
} else { | ||
schema[this.index].calculator = calculator; | ||
} | ||
this.behavior.prop(null, this.index, 'calculator', calculator); | ||
this.behavior.applyAnalytics(); | ||
if (calculator !== this.schema.calculator) { | ||
this.schema.calculator = calculator; | ||
this.behavior.grid.reindex(); // deferred reindex as there may be several of these calls at instantiation | ||
} | ||
}, | ||
get calculator() { | ||
return this.dataModel.schema[this.index].calculator; | ||
return this.schema.calculator; | ||
}, | ||
@@ -172,3 +186,3 @@ | ||
set type(type) { | ||
this._type = type; | ||
this.schema.type = type; | ||
//TODO: This is calling reindex for every column during grid init. Maybe defer all reindex calls until after an grid 'ready' event | ||
@@ -179,3 +193,3 @@ this.dataModel.prop(null, this.index, 'type', type); | ||
get type() { | ||
return this._type; | ||
return this.schema.type; | ||
}, | ||
@@ -284,7 +298,23 @@ | ||
}, | ||
set properties(ownProperties) { | ||
this._properties = this.createColumnProperties(); | ||
this.addProperties(ownProperties); | ||
set properties(properties) { | ||
this.addProperties(properties, true); | ||
}, | ||
/** | ||
* Copy a properties collection to this column's properties object. | ||
* | ||
* When a value is `undefined` or `null`, the property is deleted except when a setter or non-configurable in which case it's set to `undefined`. | ||
* @param {object|undefined} properties - Properties to copy to column's properties object. If `undefined`, this call is a no-op. | ||
* @param {boolean} [settingState] - Clear column's properties object before copying properties. | ||
*/ | ||
addProperties: function(properties, settingState) { | ||
if (!properties) { | ||
return; | ||
} | ||
if (settingState || !this._properties) { | ||
this._properties = this.createColumnProperties(); | ||
} | ||
assignOrDelete(this._properties, properties); | ||
}, | ||
getProperties: function() { | ||
@@ -317,15 +347,2 @@ return this.deprecated('getProperties()', 'properties', '1.2.0'); | ||
addProperties: function(properties) { | ||
var key, descriptor, obj = this.properties; | ||
for (key in properties) { | ||
if (properties.hasOwnProperty(key)) { | ||
descriptor = Object.getOwnPropertyDescriptor(obj, key); | ||
if (!descriptor || descriptor.writable || descriptor.set) { | ||
obj[key] = properties[key]; | ||
} | ||
} | ||
} | ||
}, | ||
/** | ||
@@ -371,3 +388,5 @@ * @summary Get a new cell editor. | ||
var REGEX_ARROW_FUNC = /^(\(.*\)|\w+)\s*=>/; | ||
var REGEX_ARROW_FUNC = /^(\(.*\)|\w+)\s*=>/, | ||
REGEX_NAMED_FUNC = /^function\s+(\w+)\(/, | ||
REGEX_ANON_FUNC = /^function\s*\(/; | ||
@@ -392,6 +411,8 @@ /** | ||
var forColumnName = ' (for column "' + this.name + '").'; | ||
if (typeof calculator === 'function') { | ||
calculator = calculator.toString(); | ||
} else if (typeof calculator !== 'string') { | ||
throw new HypergridError('Expected function OR string containing function OR function name the "' + this.name + '" column calculator.'); | ||
throw new HypergridError('Expected calculator function OR string containing calculator function OR calculator name' + forColumnName); | ||
} | ||
@@ -405,22 +426,18 @@ | ||
if (!calculators[key]) { | ||
throw new HypergridError('Unknown function name "' + key + '" for "' + this.name + '" column calculator.'); | ||
throw new HypergridError('Unknown calculator name "' + key + forColumnName); | ||
} | ||
} else { | ||
matches = calculator.match(/^function\s*(\w+)\(/); | ||
} else if ((matches = calculator.match(REGEX_NAMED_FUNC))) { | ||
key = matches[1]; // function name extracted from stringified function | ||
} else if (calculator.test(REGEX_ANON_FUNC)) { | ||
key = calculator; // anonymous stringified function | ||
} else if (REGEX_ARROW_FUNC.test(calculator)) { | ||
throw new HypergridError('Arrow function not permitted as column calculator ' + forColumnName); | ||
} | ||
if (matches) { | ||
key = matches[1]; // function name extracted from stringified function | ||
} else { | ||
key = calculator; // anonymous stringified function | ||
} | ||
if (!calculators[key]) { // neither a string nor a function (previoulsy functionified string)? | ||
if (REGEX_ARROW_FUNC.test(calculator)) { | ||
throw new HypergridError('Arrow function not permitted as column calculator (for column "' + this.name + '").'); | ||
} | ||
calculators[key] = calculator; | ||
} | ||
if (!calculators[key]) { // neither a string nor a function (previously functionified string)? | ||
calculators[key] = calculator; | ||
} | ||
calculators[key] = toFunction(calculators[key]); // functionifies existing `calculators` entries as well as new entries | ||
// functionify existing entries as well as new `calculators` entries | ||
calculators[key] = toFunction(calculators[key]); | ||
@@ -427,0 +444,0 @@ return calculators[key]; |
@@ -446,2 +446,2 @@ 'use strict'; | ||
module.exports.createColumnProperties = createColumnProperties; | ||
exports.createColumnProperties = createColumnProperties; |
@@ -43,8 +43,7 @@ 'use strict'; | ||
this.dataModel.schema.forEach(function(columnSchema, index) { | ||
this.addColumn({ | ||
index: index, | ||
header: columnSchema.header, | ||
calculator: columnSchema.calculator | ||
}); | ||
if (typeof columnSchema === 'string') { | ||
this.dataModel.schema[index] = columnSchema = { name: columnSchema }; | ||
} | ||
columnSchema.index = index; | ||
this.addColumn(columnSchema); | ||
columnEnum[this.columnEnumKey(columnSchema.name)] = index; | ||
@@ -51,0 +50,0 @@ }, this); |
@@ -6,12 +6,6 @@ 'use strict'; | ||
var deprecated = { | ||
celleditor: undefined, | ||
CellEditor: undefined | ||
}; | ||
var warnedBaseClass; | ||
/** | ||
* @classdesc Registry of cell editor constructors. | ||
* @param {Hypergrid} options.grid | ||
* @param {boolean} [options.private=false] - This instance will use a private registry. | ||
* @constructor | ||
@@ -23,29 +17,26 @@ */ | ||
items: {}, // shared cell editor registry (when !options.private) | ||
initialize: function(options) { | ||
initialize: function() { | ||
// preregister the standard cell editors | ||
if (options && options.private || !this.items.celleditor) { | ||
this.add(require('./Color')); | ||
this.add(require('./Date')); | ||
this.add(require('./Number')); | ||
this.add(require('./Slider')); | ||
this.add(require('./Spinner')); | ||
this.add(require('./Textfield')); | ||
} | ||
this.add(require('./Color')); | ||
this.add(require('./Date')); | ||
this.add(require('./Number')); | ||
this.add(require('./Slider')); | ||
this.add(require('./Spinner')); | ||
this.add(require('./Textfield')); | ||
}, | ||
construct: function(Constructor, options) { | ||
return new Constructor(this.options.grid, options); | ||
}, | ||
get: function(name) { | ||
if (name in deprecated) { | ||
if (!deprecated.warned) { | ||
if (name && name.toLowerCase() === 'celleditor') { | ||
if (!warnedBaseClass) { | ||
console.warn('grid.cellEditors.get("' + name + '") method call has been deprecated as of v2.1.0 in favor of grid.cellEditors.BaseClass property. (Will be removed in a future release.)'); | ||
deprecated.warned = true; | ||
warnedBaseClass = true; | ||
} | ||
return this.BaseClass; | ||
} | ||
return this.super.get.call(this, name, true); | ||
try { | ||
var CellEditor = Registry.prototype.get.call(this, name); | ||
} catch (err) { | ||
// fail silently | ||
} | ||
return CellEditor; | ||
} | ||
@@ -55,4 +46,2 @@ | ||
CellEditors.add = Registry.prototype.add.bind(CellEditors); | ||
module.exports = CellEditors; | ||
module.exports = new CellEditors; |
@@ -6,11 +6,6 @@ 'use strict'; | ||
var deprecated = { | ||
emptycell: undefined, | ||
EmptyCell: undefined | ||
}; | ||
var warnedBaseClass; | ||
/** | ||
* @classdesc Registry of cell renderer singletons. | ||
* @param {boolean} [privateRegistry=false] - This instance will use a private registry. | ||
* @constructor | ||
@@ -22,17 +17,21 @@ */ | ||
items: {}, // shared cell renderer registry (when !options.private) | ||
initialize: function() { | ||
// preregister the standard cell renderers | ||
this.add(require('./Button')); | ||
this.add(require('./SimpleCell')); | ||
this.add(require('./SliderCell')); | ||
this.add(require('./SparkBar')); | ||
this.add(require('./LastSelection')); | ||
this.add(require('./SparkLine')); | ||
this.add(require('./ErrorCell')); | ||
this.add(require('./TreeCell')); | ||
}, | ||
singletons: true, | ||
initialize: function(options) { | ||
// preregister the standard cell renderers | ||
if (options && options.private || !this.items.simplecell) { | ||
this.add(require('./Button')); | ||
this.add(require('./SimpleCell')); | ||
this.add(require('./SliderCell')); | ||
this.add(require('./SparkBar')); | ||
this.add(require('./LastSelection')); | ||
this.add(require('./SparkLine')); | ||
this.add(require('./ErrorCell')); | ||
this.add(require('./TreeCell')); | ||
// for better performance, instantiate at add time rather than render time. | ||
add: function(name, Constructor) { | ||
if (arguments.length === 1) { | ||
Constructor = name; | ||
return Registry.prototype.add.call(this, new Constructor); | ||
} else { | ||
return Registry.prototype.add.call(this, name, new Constructor); | ||
} | ||
@@ -42,6 +41,6 @@ }, | ||
get: function(name) { | ||
if (name in deprecated) { | ||
if (!deprecated.warned) { | ||
if (name && name.toLowerCase() === 'emptycell') { | ||
if (!warnedBaseClass) { | ||
console.warn('grid.cellRenderers.get("' + name + '").constructor has been deprecated as of v2.1.0 in favor of grid.cellRenderers.BaseClass property. (Will be removed in a future release.)'); | ||
deprecated.warned = true; | ||
warnedBaseClass = true; | ||
} | ||
@@ -51,3 +50,3 @@ this.BaseClass.constructor = this.BaseClass; | ||
} | ||
return this.super.get.call(this, name); | ||
return Registry.prototype.get.call(this, name); | ||
} | ||
@@ -57,4 +56,2 @@ | ||
CellRenderers.add = Registry.prototype.add.bind(CellRenderers); | ||
module.exports = CellRenderers; | ||
module.exports = new CellRenderers; |
@@ -22,5 +22,5 @@ 'use strict'; | ||
getRowMetadata: function(rowIndex, metadata) { | ||
getRowMetadata: function(rowIndex, prototype) { | ||
var dataRow = this.getRow(rowIndex); | ||
return dataRow && (dataRow.__META || (dataRow.__META = metadata)); | ||
return dataRow && (dataRow.__META || (prototype !== undefined && (dataRow.__META = Object.create(prototype)))); | ||
}, | ||
@@ -30,3 +30,10 @@ | ||
var dataRow = this.getRow(rowIndex); | ||
return dataRow && (dataRow.__META = metadata); | ||
if (dataRow) { | ||
if (metadata) { | ||
dataRow.__META = metadata; | ||
} else { | ||
delete dataRow.__META; | ||
} | ||
} | ||
return !!dataRow; | ||
}, | ||
@@ -33,0 +40,0 @@ |
@@ -222,3 +222,4 @@ 'use strict'; | ||
reindex: function(options) { | ||
var selectedRowSourceIndexes = getUnderlyingIndexesOfSelectedRows.call(this); | ||
var selectedRowSourceIndexes = getSelectedDataRowIndexes.call(this), | ||
selectedColumnNames = getSelectedColumNames.call(this); | ||
@@ -233,3 +234,6 @@ this.pipeline.forEach(function(dataSource) { | ||
this.grid.selectionModel.reset(); | ||
reselectRowsByUnderlyingIndexes.call(this, selectedRowSourceIndexes); | ||
reselectColumnsByNames.call(this, selectedColumnNames); | ||
}, | ||
@@ -726,13 +730,20 @@ | ||
*/ | ||
function getUnderlyingIndexesOfSelectedRows() { | ||
var sourceIndexes = [], | ||
dataSource = this.dataSource; | ||
function getSelectedDataRowIndexes() { | ||
if (this.grid.properties.restoreRowSelections) { | ||
var dataSource = this.dataSource; | ||
if (this.grid.properties.checkboxOnlyRowSelections) { | ||
this.grid.getSelectedRows().forEach(function(selectedRowIndex) { | ||
sourceIndexes.push(dataSource.getDataIndex(selectedRowIndex)); | ||
return this.grid.getSelectedRows().map(function(selectedRowIndex) { | ||
return dataSource.getDataIndex(selectedRowIndex); | ||
}); | ||
} | ||
} | ||
return sourceIndexes; | ||
function getSelectedColumNames() { | ||
if (this.grid.properties.restoreColumnSelections) { | ||
var behavior = this.grid.behavior; | ||
return this.grid.getSelectedColumns().map(function(selectedColumnIndex) { | ||
return behavior.getActiveColumn(selectedColumnIndex).name; | ||
}); | ||
} | ||
} | ||
@@ -744,19 +755,19 @@ | ||
* @this {dataModels.JSON} | ||
* @param {number[]} [dataRowIndexes] - List of underlying data row indexes. If omitted, this function is a no-op. | ||
* @returns {number} Number of rows reselected or `undefined` if `dataRowIndexes` was undefined. | ||
* @memberOf dataModels.JSON~ | ||
*/ | ||
function reselectRowsByUnderlyingIndexes(sourceIndexes) { | ||
var i, r, | ||
rowCount = this.getRowCount(), | ||
selectedRowCount = sourceIndexes.length, | ||
rowIndexes = [], | ||
selectionModel = this.grid.selectionModel; | ||
function reselectRowsByUnderlyingIndexes(dataRowIndexes) { | ||
if (dataRowIndexes) { | ||
var i, r, | ||
rowCount = this.getRowCount(), | ||
selectedRowCount = dataRowIndexes.length, | ||
gridRowIndexes = [], | ||
selectionModel = this.grid.selectionModel; | ||
selectionModel.clearRowSelection(); | ||
if (this.grid.properties.checkboxOnlyRowSelections) { | ||
for (r = 0; selectedRowCount && r < rowCount; ++r) { | ||
i = sourceIndexes.indexOf(this.dataSource.getDataIndex(r)); | ||
i = dataRowIndexes.indexOf(this.dataSource.getDataIndex(r)); | ||
if (i >= 0) { | ||
rowIndexes.push(r); | ||
delete sourceIndexes[i]; // might make indexOf increasingly faster as deleted elements are not enumerable | ||
gridRowIndexes.push(r); | ||
delete dataRowIndexes[i]; // might make indexOf increasingly faster as deleted elements are not enumerable | ||
selectedRowCount--; // count down so we can bail early if all found | ||
@@ -766,8 +777,24 @@ } | ||
rowIndexes.forEach(function(rowIndex) { | ||
gridRowIndexes.forEach(function(rowIndex) { | ||
selectionModel.selectRow(rowIndex); | ||
}); | ||
return gridRowIndexes.length; | ||
} | ||
} | ||
return rowIndexes.length; | ||
function reselectColumnsByNames(sourceColumnNames) { | ||
if (sourceColumnNames) { | ||
var behavior = this.grid.behavior, | ||
selectionModel = this.grid.selectionModel; | ||
return sourceColumnNames.reduce(function(reselectedCount, columnName) { | ||
var activeColumnIndex = behavior.getActiveColumnIndex(columnName); | ||
if (activeColumnIndex) { | ||
selectionModel.selectColumn(activeColumnIndex); | ||
reselectedCount++; | ||
} | ||
return reselectedCount; | ||
}, 0); | ||
} | ||
} | ||
@@ -774,0 +801,0 @@ |
@@ -1095,6 +1095,5 @@ 'use strict'; | ||
/** @summary Name of a formatter for cell text. | ||
* @desc The default (`undefined`) falls back to `column.type`. | ||
* The value `null` does no formatting. | ||
* @desc Unknown formatter falls back to the `string` formatter (simple conversion to string with `+ ''`). | ||
* @default undefined | ||
* @type {undefined|null|string} | ||
* @type {string} | ||
* @memberOf module:defaults | ||
@@ -1108,3 +1107,3 @@ * @tutorial localization | ||
* @default undefined | ||
* @type {undefined|null|string} | ||
* @type {string} | ||
* @memberOf module:defaults | ||
@@ -1359,2 +1358,18 @@ * @tutorial cell-editors | ||
/** @summary Restore row selections across data transformations (`reindex` calls). | ||
* @desc The restoration is based on the underlying data row indexes. | ||
* @type {boolean} | ||
* @default | ||
* @memberOf module:defaults | ||
*/ | ||
restoreRowSelections: true, | ||
/** @summary Restore column selections across data transformations (`reindex` calls). | ||
* @desc The restoration is based on the column names. | ||
* @type {boolean} | ||
* @default | ||
* @memberOf module:defaults | ||
*/ | ||
restoreColumnSelections: true, | ||
/** @summary How to truncate text. | ||
@@ -1361,0 +1376,0 @@ * @desc A "quaternary" value, one of: |
@@ -15,21 +15,17 @@ 'use strict'; | ||
items: {}, // shared feature registry (when !options.private) | ||
initialize: function(options) { | ||
initialize: function() { | ||
// preregister the standard cell renderers | ||
if (options && options.private || !this.items.cellclick) { | ||
this.add(require('./CellClick')); | ||
this.add(require('./CellEditing')); | ||
this.add(require('./CellSelection')); | ||
this.add(require('./ColumnMoving')); | ||
this.add(require('./ColumnResizing')); | ||
this.add(require('./ColumnSelection')); | ||
this.add(require('./ColumnSorting')); | ||
this.add(require('./Filters')); | ||
this.add(require('./KeyPaging')); | ||
this.add(require('./OnHover')); | ||
// this.add(require('./RowResizing')); | ||
this.add(require('./RowSelection')); | ||
this.add(require('./ThumbwheelScrolling')); | ||
} | ||
this.add(Features.CellClick); | ||
this.add(Features.CellEditing); | ||
this.add(Features.CellSelection); | ||
this.add(Features.ColumnMoving); | ||
this.add(Features.ColumnResizing); | ||
this.add(Features.ColumnSelection); | ||
this.add(Features.ColumnSorting); | ||
this.add(Features.Filters); | ||
this.add(Features.KeyPaging); | ||
this.add(Features.OnHover); | ||
// this.add(require('./RowResizing')); | ||
this.add(Features.RowSelection); | ||
this.add(Features.ThumbwheelScrolling); | ||
} | ||
@@ -39,9 +35,7 @@ | ||
Features.add = Registry.prototype.add.bind(Features); | ||
// Following shared props provided solely in support of build file usage, e.g., `fin.Hypergrid.features.yada`, | ||
// and are not meant to be used elsewhere. | ||
// presumably for overriding built-in features, and are not meant to be used elsewhere. | ||
Features.Feature = require('./Feature'); // abstract base class | ||
Features.BaseClass = require('./Feature'); // abstract base class | ||
Features.CellClick = require('./CellClick'); | ||
@@ -62,2 +56,2 @@ Features.CellEditing = require('./CellEditing'); | ||
module.exports = Features; | ||
module.exports = new Features; |
@@ -114,3 +114,3 @@ 'use strict'; | ||
get: function() { | ||
return this.behavior.getRowProperties(this); | ||
return this.behavior.getRowProperties(this, undefined, this.subgrid); | ||
} | ||
@@ -121,7 +121,7 @@ }, | ||
// use carefully! creates new object as needed; only use when object definitely needed: for setting prop with `.rowProperties[key] = value` or `Object.assign(.rowProperties, {...})`; use getRowProperty(key) instead for getting a property that may not exist because it will not create a new object | ||
return this.behavior.getRowProperties(this, {}); | ||
return this.behavior.getRowProperties(this, null, this.subgrid); | ||
}, | ||
set: function(properties) { | ||
// for resetting whole row properties object: `.rowProperties = {...}` | ||
this.behavior.setRowProperties(this, properties); // calls `stateChanged()` | ||
this.behavior.setRowProperties(this, properties, this.subgrid); // calls `stateChanged()` | ||
} | ||
@@ -128,0 +128,0 @@ }, |
@@ -11,3 +11,3 @@ 'use strict'; | ||
var regexIsMethod = /^\w+\(.*\)$/; | ||
var regexIsMethod = /^[\w\.]+\(.*\)$/; | ||
@@ -48,3 +48,3 @@ /** | ||
memberType = regexIsMethod.test(dotProps) ? 'method' : 'property'; | ||
warning = 'The .' + methodName + ' method is deprecated as of v' + since + | ||
warning = 'The .' + methodName + ' method has been deprecated as of v' + since + | ||
' in favor of the .' + chain.join('.') + ' ' + memberType + '.' + | ||
@@ -51,0 +51,0 @@ ' (Will be removed in a future release.)'; |
@@ -133,6 +133,6 @@ 'use strict'; | ||
enumerable: true, | ||
get: getColumnPropertiesByColumnName, | ||
get: getColumnPropertiesByColumnIndexOrName, | ||
set: function(columnsHash) { | ||
if (columnsHash) { | ||
setColumnPropertiesByColumnName.call(this, columnsHash); | ||
setColumnPropertiesByColumnIndexOrName.call(this, columnsHash); | ||
this.grid.behavior.changed(); | ||
@@ -235,5 +235,12 @@ } | ||
/** | ||
* @name module:dynamicPropertyDescriptors.columnProperties | ||
*/ | ||
dynamicPropertyDescriptors.columnProperties = dynamicPropertyDescriptors.columns; | ||
function getRowPropertiesBySubgridAndRowIndex() { // to be called with grid.properties as context | ||
var subgrids = {}; | ||
var behavior = this.grid.behavior; | ||
var defaultRowHeight = this.grid.properties.defaultRowHeight; | ||
behavior.subgrids.forEach(function(dataModel) { | ||
@@ -244,6 +251,19 @@ var key = dataModel.name || dataModel.type; | ||
if (rowProps) { | ||
var subgrid = subgrids[key] = subgrids[key] || {}; | ||
subgrid[rowIndex] = rowProps; | ||
// create height mixin by invoking `height` getter | ||
var height = { height: rowProps.height }; | ||
if (height.height === defaultRowHeight) { | ||
height = undefined; | ||
} | ||
// clone it and mix in height | ||
rowProps = Object.assign({}, rowProps, height); | ||
// only include if at least one defined prop | ||
if (Object.getOwnPropertyNames(rowProps).find(definedProp)) { | ||
var subgrid = subgrids[key] || (subgrids[key] = {}); | ||
subgrid[rowIndex] = rowProps; | ||
} | ||
} | ||
} | ||
function definedProp(key) { return rowProps[key] !== undefined; } | ||
}); | ||
@@ -254,31 +274,18 @@ return subgrids; | ||
function setRowPropertiesBySubgridAndRowIndex(rowsHash) { // to be called with grid.properties as context | ||
var behavior = this.grid.behavior; | ||
for (var subgridName in rowsHash) { | ||
if (rowsHash.hasOwnProperty(subgridName)) { | ||
var subgrid = behavior.subgrids.lookup[subgridName]; | ||
if (subgrid) { | ||
var subgridHash = rowsHash[subgridName]; | ||
for (var rowIndex in subgridHash) { | ||
if (subgridHash.hasOwnProperty(rowIndex)) { | ||
var properties = subgridHash[rowIndex]; | ||
for (var propName in properties) { | ||
if (properties.hasOwnProperty(propName)) { | ||
var propValue = properties[propName]; | ||
switch (propName) { | ||
case 'height': | ||
behavior.setRowHeight(rowIndex, Number(propValue), subgrid); | ||
break; | ||
default: | ||
console.warn('Unexpected row property "' + propName + '" ignored. (The only row property currently implemented is "height").'); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
var behavior = this.grid.behavior, | ||
methodName = this.settingState ? 'setRowProperties' : 'addRowProperties'; | ||
Object.keys(rowsHash).forEach(function(subgridName) { | ||
var subgrid = behavior.subgrids.lookup[subgridName]; | ||
if (subgrid) { | ||
var subgridHash = rowsHash[subgridName]; | ||
Object.keys(subgridHash).forEach(function(rowIndex) { | ||
var properties = subgridHash[rowIndex]; | ||
behavior[methodName](rowIndex, properties, subgrid); | ||
}); | ||
} | ||
} | ||
}); | ||
} | ||
function getColumnPropertiesByColumnName() { // to be called with grid.properties as context | ||
function getColumnPropertiesByColumnIndexOrName() { // to be called with grid.properties as context | ||
var columns = this.grid.behavior.getColumns(), | ||
@@ -297,6 +304,3 @@ headerify = this.grid.headerify; | ||
default: | ||
var value = column.properties[key]; | ||
if (value !== undefined) { | ||
properties[key] = value; | ||
} | ||
properties[key] = column.properties[key]; | ||
} | ||
@@ -312,17 +316,4 @@ return properties; | ||
function setColumnPropertiesByColumnName(columnsHash) { // to be called with grid.properties as context | ||
var columns = this.grid.behavior.getColumns(); | ||
for (var columnName in columnsHash) { | ||
if (columnsHash.hasOwnProperty(columnName)) { | ||
var column = columns.find(nameMatches); | ||
if (column) { | ||
column.properties = columnsHash[columnName]; | ||
} | ||
} | ||
} | ||
function nameMatches(column) { | ||
return column.name === columnName; | ||
} | ||
function setColumnPropertiesByColumnIndexOrName(columnsHash) { // to be called with grid.properties as context | ||
this.grid.behavior.addAllColumnProperties(columnsHash, this.settingState); | ||
} | ||
@@ -357,30 +348,25 @@ | ||
var subgrids = this.grid.behavior.subgrids, | ||
columns = this.grid.behavior.getColumns(); | ||
columns = this.grid.behavior.getColumns(), | ||
methodName = this.settingState ? 'setCellProperties' : 'addCellProperties'; | ||
for (var subgridName in cellsHash) { | ||
if (cellsHash.hasOwnProperty(subgridName)) { | ||
var subgrid = subgrids.lookup[subgridName]; | ||
if (subgrid) { | ||
var subgridHash = cellsHash[subgridName]; | ||
for (var rowIndex in subgridHash) { | ||
if (subgridHash.hasOwnProperty(rowIndex)) { | ||
var columnProps = subgridHash[rowIndex]; | ||
for (var columnName in columnProps) { | ||
if (columnProps.hasOwnProperty(columnName)) { | ||
var column = columns.find(nameMatches); | ||
if (column) { | ||
var properties = columnProps[columnName]; | ||
column.addCellProperties(rowIndex, properties, subgrid); | ||
} | ||
} | ||
Object.keys(cellsHash).forEach(function(subgridName) { | ||
var subgrid = subgrids.lookup[subgridName]; | ||
if (subgrid) { | ||
var subgridHash = cellsHash[subgridName]; | ||
Object.keys(subgridHash).forEach(function(rowIndex) { | ||
var columnProps = subgridHash[rowIndex]; | ||
Object.keys(columnProps).forEach(function(columnName) { | ||
var properties = columnProps[columnName]; | ||
if (properties) { | ||
var column = columns.find(function(column) { | ||
return column.name === columnName; | ||
}); | ||
if (column) { | ||
column[methodName](rowIndex, properties, subgrid); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
function nameMatches(column) { | ||
return column.name === columnName; | ||
} | ||
}); | ||
} | ||
@@ -387,0 +373,0 @@ |
@@ -8,6 +8,3 @@ 'use strict'; | ||
var REGEXP_META_PREFIX = /^__/, // starts with double underscore | ||
REGEXP_WORD_SEPARATORS = /[\s\-_]*([^\s\-_])([^\s\-_]+)/g, | ||
REGEXP_CAPITAL_LETTERS = /[A-Z]/g, | ||
REGEXP_LOWER_CASE_LETTER = /[a-z]/; | ||
var REGEXP_META_PREFIX = /^__/; // starts with double underscore | ||
@@ -19,35 +16,14 @@ /** | ||
*/ | ||
function getFieldNames(hash) { | ||
exports.getFieldNames = function(hash) { | ||
return Object.keys(hash || []).filter(function(fieldName) { | ||
return !REGEXP_META_PREFIX.test(fieldName); | ||
}); | ||
} | ||
}; | ||
function capitalize(a, b, c) { | ||
return b.toUpperCase() + c; | ||
} | ||
exports.titleize = require('synonomous').prototype.toTitle; | ||
/** | ||
* Separates camel case or white-space-, hypen-, or underscore-separated-words into truly separate words and capitalizing the first letter of each. | ||
* @param string | ||
* @returns {string} | ||
* @memberOf module:fields | ||
*/ | ||
function titleize(string) { | ||
return (REGEXP_LOWER_CASE_LETTER.test(string) ? string : string.toLowerCase()) | ||
.replace(REGEXP_WORD_SEPARATORS, capitalize) | ||
.replace(REGEXP_CAPITAL_LETTERS, ' $&') | ||
.trim(); | ||
} | ||
function getSchema(data){ | ||
return getFieldNames(data && data[0] || {}).map(function(name) { | ||
return { name: name, header: titleize(name) }; | ||
exports.getSchema = function(data){ | ||
return exports.getFieldNames(data && data[0] || {}).map(function(name) { | ||
return { name: name, header: exports.titleize(name) }; | ||
}); | ||
} | ||
module.exports = { | ||
getFieldNames: getFieldNames, | ||
titleize: titleize, | ||
getSchema: getSchema | ||
}; |
@@ -7,47 +7,37 @@ 'use strict'; | ||
* @class | ||
* @param {object} [options] - The following options can alternatively be set in the prototype of an extending class. | ||
* @param {boolean} [options.singletons=false] - The registry will consist of singletons which will be instantiated as they are added. | ||
* (Otherwise the registry consists of constructors which are instantiated later on as needed.) | ||
* @param {boolean} [options.private=false] - This instance will use a private registry. | ||
*/ | ||
var Registry = Base.extend('Registry', { | ||
initialize: function(options) { | ||
this.options = options; | ||
if (this.option('private')) { | ||
this.items = Object.create(this.items); | ||
} | ||
initialize: function() { | ||
this.items = Object.create(null); | ||
}, | ||
option: function(key) { | ||
return this.options && key in this.options ? this.options[key] : this[key]; | ||
}, | ||
/** | ||
* @summary Register and instantiate a singleton. | ||
* @summary Register an item and return it. | ||
* @desc Adds an item to the registry using the provided name (or the class name), converted to all lower case. | ||
* @param {string} [name] - Case-insensitive item key. If not given, `Constructor.prototype.$$CLASS_NAME` is used. | ||
* @param {function} Constructor | ||
* @param {string} [name] - Case-insensitive item key. If not given, fallsback to `item.prototype.$$CLASS_NAME` or `item.prototype.name` or `item.name`. | ||
* @param [item] - If unregistered or omitted, nothing is added and method returns `undefined`. | ||
* | ||
* > Note: `$$CLASS_NAME` is normally set by providing a string as the (optional) first parameter (`alias`) in your {@link https://www.npmjs.com/package/extend-me|extend} call. | ||
* | ||
* @returns {function|Constructor} A newly registered item, either `Constructor` or singleton created by `new Constructor`. | ||
* @returns Newly registered item or `undefined` if unregistered. | ||
* | ||
* @memberOf Registry# | ||
*/ | ||
add: function(name, Constructor) { | ||
if (typeof name === 'function') { | ||
Constructor = name; | ||
add: function(name, item) { | ||
if (arguments.length === 1) { | ||
item = name; | ||
name = undefined; | ||
} | ||
name = name || Constructor.prototype.$$CLASS_NAME || Constructor.name; // try Funciton.prototype.name as last resort | ||
if (!item) { | ||
return; | ||
} | ||
name = name || item.getClassName && item.getClassName(); | ||
if (!name) { | ||
throw new this.HypergridError('Expected a registration name.'); | ||
throw new this.HypergridError('Cannot register ' + this.friendlyName() + ' without a name.'); | ||
} | ||
name = name.toLowerCase(); | ||
return (this.items[name] = this.option('singletons') ? this.construct(Constructor) : Constructor); | ||
return (this.items[name] = item); | ||
}, | ||
@@ -67,9 +57,8 @@ | ||
/** | ||
* Fetch a registered singleton. | ||
* Fetch a registered item. | ||
* @param {string} [name] | ||
* @param {boolean} [noThrow] - Avoid throwing error if no such item; just return `undefined`. | ||
* @returns {function|Constructor|undefined} A registered constructor item or `undefined` if none such. | ||
* @returns {*|undefined} A registered item or `undefined` if unregistered. | ||
* @memberOf Registry# | ||
*/ | ||
get: function(name, noThrow) { | ||
get: function(name) { | ||
if (!name) { | ||
@@ -82,44 +71,51 @@ return; | ||
if (!result) { | ||
var lowerName = name.toLowerCase(); | ||
result = this.items[lowerName]; // name may differ in case only | ||
var lowerName = name.toLowerCase(); // name may differ in case only | ||
var foundName = Object.keys(this.items).find(function(key) { return lowerName === key.toLowerCase(); }); | ||
result = this.items[foundName]; | ||
if (result) { | ||
this.addSynonym(name, lowerName); // register found name as a synonym for faster access next time around to avoid converting to lower case again | ||
// Register name as a synonym for the found name for faster access next | ||
// time without having to convert to lower case on every get. | ||
this.addSynonym(name, foundName); | ||
} else { | ||
throw new this.HypergridError('Expected "' + name + '" to be a case-insensitive match for a registered ' + this.friendlyName() + '.'); | ||
} | ||
} | ||
if (!noThrow && !result) { | ||
var classDesc = this.BaseClass.$$CLASS_NAME.replace(/([A-Z])/g, ' $1').trim().toLowerCase(); | ||
throw new this.HypergridError('Expected "' + name + '" to be a registered ' + classDesc + '.'); | ||
} | ||
return result; | ||
}, | ||
/** | ||
* @summary Lookup registered item and return a new instance thereof. | ||
* @returns New instance of the named constructor or `undefined` if none such. | ||
* @param {string} name - Name of a registered item. | ||
* @param {string} [options] - Properties to add to the instantiated item primarily for `mustache` use. | ||
* @memberOf Registry# | ||
*/ | ||
create: function(name, options) { | ||
var Constructor = this.get(name); | ||
if (typeof Constructor !== 'function') { | ||
return; | ||
friendlyName: function() { | ||
if (this.BaseClass) { | ||
var name = this.BaseClass.getClassName(); | ||
name = name && name.replace(/([A-Z])/g, ' $1').trim().toLowerCase(); | ||
} else { | ||
name = singularOf(this.getClassName()).toLowerCase(); | ||
} | ||
name = name || 'item'; | ||
return indefArtOf(name) + ' ' + name; | ||
} | ||
}); | ||
if (Constructor.abstract) { | ||
throw new this.HypergridError('Attempt to instantiate the abstract "' + name + '" class.'); | ||
var endings = [ | ||
{ plural: /ies$/, singular: 'y' }, | ||
{ plural: /s$/, singular: '' } | ||
]; | ||
function singularOf(name) { | ||
endings.find(function(ending) { | ||
if (ending.plural.test(name)) { | ||
name = name.replace(ending.plural, ending.singular); | ||
return true; | ||
} | ||
}); | ||
return name; | ||
} | ||
return this.construct(Constructor, options); | ||
}, | ||
function indefArtOf(name) { | ||
return /^[aeiou]/.test(name) ? 'an' : 'a'; | ||
} | ||
construct: function(Constructor, options) { | ||
return new Constructor(Object.assign({}, this.options, options)); | ||
} | ||
}); | ||
module.exports = Registry; |
@@ -1245,2 +1245,3 @@ /* eslint-env browser */ | ||
gap = false; | ||
if (x) { | ||
@@ -1260,2 +1261,3 @@ if ((gap = hasFixedColumnGap && c === fixedColumnCount)) { | ||
} | ||
this.visibleColumns[c] = this.visibleColumnsByIndex[vx] = vc = { | ||
@@ -1303,2 +1305,3 @@ index: c, | ||
vy = r; | ||
gap = false; | ||
if (scrollableSubgrid) { | ||
@@ -1305,0 +1308,0 @@ if ((gap = hasFixedRowGap && r === fixedRowCount)) { |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
712491
18154
12
87
+ Addedsynonomous@^1.0.1
+ Addedsynonomous@1.0.2(transitive)
Updatedextend-me@^2.7.0