diff --git a/.jsdoc.conf.json b/.jsdoc.conf.json
index 90a02900e..33cf0bd24 100644
--- a/.jsdoc.conf.json
+++ b/.jsdoc.conf.json
@@ -4,8 +4,7 @@
"dictionaries": ["jsdoc","closure"]
},
"source": {
- "include": ["src", "add-ons"],
- "exclude": ["src/behaviors/old"]
+ "include": ["src", "add-ons"]
},
"plugins": ["plugins/markdown"],
"markdown": {
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..980bbcb2a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+- '6'
+
+before_script:
+ - npm install -g gulp
+script: gulp build
\ No newline at end of file
diff --git a/README.md b/README.md
index 1a321cc7c..7e9647534 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
+[](https://travis-ci.org/openfin/fin-hypergrid)
+
**fin-hypergrid** is an ultra-fast HTML5 grid presentation layer, achieving its speed by rendering (in a canvas tag) only the currently visible portion of your (virtual) grid, thus avoiding the latency and life-cycle issues of building, walking, and maintaining a complex DOM structure.
-### Current Release (1.0.8 - 8 August 2016)
+### Current Release (1.0.9 - 29 August 2016)
-The current version replaces last year's [prototype version](https://github.com/openfin/fin-hypergrid/tree/polymer-prototype), which was built around Polymer. It is now completely "de-polymerized" and is being made available as:
+The current version 1.0 replaces last year's [prototype version](https://github.com/openfin/fin-hypergrid/tree/polymer-prototype), which was built around Polymer. It is now completely "de-polymerized" and is being made available as:
* An [npm module](https://www.npmjs.com/package/fin-hypergrid) for use with browserify.
* A single JavaScript file [fin-hypergrid.js](https://openfin.github.io/fin-hypergrid/build/fin-hypergrid.js) you can reference in a `
+ *
+ * ```
+ * ```javascript
+ * var groupedHeader = fin.hypergrid.groupedHeader;
+ * ```
+ *
+ * ### Usage
+ *
+ * This example specifies that the two named columns are under a group labeled "Name":
+ * ```javascript
+ * var grid = new fin.Hypergrid(...);
+ * groupedHeader.mixInTo(grid, options);
+ * grid.behavior.setHeaders({
+ * firstName: 'Name|First',
+ * lastName: 'Name|Last'
+ * });
+ * ```
+ *
+ * You can nest headers to any level. The example above is only one level deep. The live {@link http://openfin.github.io/fin-hypergrid/grouped-header.html|demo} demonstrates a nested header (one additional level).
+ *
+ * This API uses its own extension of the {@link SimpleCell} cell renderer which does the stretched partial cell renders explained above. It also calls a background paint function to fill the area behind the group labels. This API comes with two such background paint functions, described below. These are both exposed so you can specify one over the other. You can also specify a reference to a custom function.
+ *
+ * ### Background paint functions
+ *
+ * #### {@link groupedHeader.drawProportionalBottomBorder|drawProportionalBottomBorder}
+ * This is the default background paint function. It paints a bottom border under the group header whose thickness is in proportion to the order (level) of the group:
+ *
+ * 
+ *
+ * The lowest-order group has a 1-pixel thick border; borders grow progressively thicker with each superior group; the highest-order group has the thickest border.
+ *
+ * #### {@link groupedHeader.drawLinearGradient|drawLinearGradient}
+ * This paints a background that transitions color from top to bottom:
+ *
+ * 
+ *
+ * ### Options
+ *
+ * Options are supplied to the {@link groupedHeader.mixInTo|mixInTo} call and apply to the entire grid so that all column groups in a grid share the same appearance. Most options (with the exception of `delimiter`) are for the use of the {@link groupedHeader.mixInTo~GroupedHeader|GroupedHeader} cell renderer.
+ *
+ * #### `paintBackground` option
+ *
+ * To override the default background paint function, pass a reference in the `backgroundPaint` option:
+ * ```javascript
+ * fin.Hypergrid.groupedHeader.mixInTo(grid, {
+ * paintBackground: groupedHeader.drawLinearGradient
+ * });
+ * ```
+ *
+ * #### `gradientStops` option
+ *
+ * Gradients blend between a series of colors filling the area behind the group label from top to bottom. Each color may include an opacity level.
+ *
+ * The gradient illustrated above is the default. It uses the default header label color to fill the background, transitioning from top alpha=0% to bottom alpha=35%.
+ *
+ * You can however specify your own {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient/addColorStop|gradient stops}:
+ *
+ * ```javascript
+ * fin.Hypergrid.groupedHeader.mixInTo(grid, {
+ * paintBackground: fin.Hypergrid.groupedHeader.drawLinearGradient,
+ * gradientStops: [
+ * [0, 'rgba(255, 255, 0, 0)'],
+ * [1, 'rgba(255, 255, 0, .5)']
+ * ],
+ * groupColor: 'red'
+ *});
+ * ```
+ *
+ * The gradient shown above fills the background, transitioning from top (0) in yellow (`255, 255, 0`) with alpha=0% (`0`) to bottom (`1`) with alpha=50% (`.5`):
+ *
+ * 
+ *
+ * #### `groupColor` option
+ *
+ * The example above also illustrates setting the `groupColor` option which specifies the font color for the group labels, in this case red (yuck! but it's just an example).
+ *
+ * #### `delimiter` option
+ *
+ * Allows you to change the delimiter in the header strings from the default vertical bar character (`'|'`) to something else.
+ *
+ * @mixin
+ */
+var groupedHeader = {
+ mixInTo: mixInTo,
+ setHeaders: setHeaders,
+ drawProportionalBottomBorder: drawProportionalBottomBorder,
+ drawLinearGradient: drawLinearGradient
};
module.exports = groupedHeader;
diff --git a/add-ons/row-by-id.js b/add-ons/row-by-id.js
new file mode 100644
index 000000000..3d6a514c6
--- /dev/null
+++ b/add-ons/row-by-id.js
@@ -0,0 +1,346 @@
+'use strict';
+
+/**
+ * Mix into your data model for get/modify/delete access to rows by single- or multi-column ID.
+ *
+ * These functions are all basically wrappers for the heavily overloaded {@link http://openfin.github.io/hyper-analytics/DataSource.html#findRow|DataSource.prototype.findRow} method.
+ *
+ * ### Usage
+ *
+ * ##### Client-side install with `
+ *
+ * ```
+ * 2. In a `` element:
+ * ```javascript
+ * rowById.mixInTo(MyDataModel.prototype);
+ * ```
+ *
+ * ##### Browserify integration with `require()`
+ * ```javascript
+ * var rowById = require('./add-ons/rowById');
+ * ...
+ * robById.mixInTo(myGrid.behavior.dataModel);
+ * ```
+ *
+ * ##### Note
+ *
+ * The above code access methodologies reference two different files:
+ * * The built version comes from ./build/add-ons and the API is assigned to `window.fin.Hypergrid.rowById`
+ * * The repo version comes from ./add-ons and the API is assigned to `module.exports`
+ *
+ * ### Examples
+ *
+ * _Instructions:_ You can try the examples below by going to [rowById.html](http://openfin.github.io/fin-hypergrid/rowById.html). This page is identical to [rowById.html](http://openfin.github.io/fin-hypergrid/example.html) _except_ with the addition of the above client-side install and mix-in lines. Then copy & paste each of the following code blocks into Chrome's developer console and hit the return key, observing the changes to the grid as you do so.
+ *
+ * 1. Set up some variables:
+ * ```javascript
+ * var behavior = grid.behavior;
+ * var dataModel = behavior.dataModel;
+ * var findKey = "symbol";
+ * var findVal = 'FB';
+ * ```
+ * 2. Add a new row:
+ * ```javascript
+ * var newDataRow = {};
+ * newDataRow[findKey] = findVal;
+ * newDataRow.name = 'Facebook';
+ * newDataRow.prevclose = 125.08;
+ * dataModel.addRow(newDataRow);
+ * // To see the new row you must (eventually) call:
+ * behavior.applyAnalytics();
+ * grid.behaviorChanged();
+ * ```
+ * 3. Modify an existing row:
+ * ```javascript
+ * var modKey = 'name';
+ * var modVal = 'Facebook, Inc.';
+ * var dataRow = dataModel.modifyRowById(findKey, findVal, modKey, modVal);
+ * // To see the modified cells you must (eventually) call:
+ * behavior.applyAnalytics();
+ * grid.repaint();
+ * ```
+ * 4. Delete (remove) a row:
+ * ```javascript
+ * var oldRow = dataModel.deleteRowById(findKey, findVal);
+ * // To see the row disappear you must (eventually) call:
+ * behavior.applyAnalytics();
+ * grid.behaviorChanged();
+ * ```
+ * 5. Replace an existing row:
+ * ```javascript
+ * findVal = 'MSFT';
+ * var newRow = {symbol: "ABC", name: "Google", prevclose: 666};
+ * var oldRow = dataModel.replaceRowById(findKey, findVal, newRow);
+ * // To see the row change you must (eventually) call:
+ * behavior.applyAnalytics();
+ * grid.repaint();
+ * ```
+ * This replaces the row with the new row object, returning but otherwise discarding the old row object. That is, the new row object takes on the ordinal of the old row object. By contrast, modifyDataRow keeps the existing row object, updating it in place.
+ *
+ * 6. Fetch a row (find the row and return the row object):
+ * ```javascript
+ * findVal = 'ABC';
+ * var dataRow = dataModel.getRowById(findKey, findVal);
+ * ```
+ * 7. Get a row's index (find the row and return its ordinal) (for use with Hypergrid's various grid coordinate methods):
+ * ```javascript
+ * var rowIndex = dataModel.getRowIndexById(findKey, findVal);
+ * ```
+ * 8. Erase (blank) a row:
+ * ```javascript
+ * var oldRow = dataModel.eraseRowById(findKey, findVal);
+ * // To see the row blank you must (eventually) call:
+ * grid.behavior.applyAnalytics();
+ * grid.repaint();
+ * ```
+ *
+ * ### Notes
+ *
+ * ##### Updating the rendered grid
+ *
+ * The following calls should be made sparingly as they can be expensive. The good news is that they only need to be called at the very end of a batch grid data changes.
+ * 1. Call `grid.behavior.applyAnalytics()`. This call does nothing when the data source pipeline is empty. Otherwise, applies each data source transformations (filter, sort) in the pipeline. Needed when adding, deleting, or modifying rows.
+ * 2. Call `grid.behaviorChanged()` when the number of rows (or columns) changes as a result of the data alteration.
+ * 3. Call `grid.repaint()` when cells are updated in place. Note that `behaviorChanged` calls `repaint` for you so you only need to call one or the other.
+ *
+ * ##### Search key hash option
+ *
+ * Search key(s) may be provided in a single hash parameter instead of in two distinct parameters (_à la_ underscore.js)
+ *
+ * For any of the methods above that take a search key, the first two arguments (`findkey` and `findVal`) may be replaced with a single argument `findHash`, a hash of key:value pairs, optionally followed by a 2nd argument `findList`, a _whitelist_ (an array) of which keys in `findHash` to use. These overloads allow for searching based on multiple columns:
+ *
+ * ###### Example 1
+ * Single-column primary key:
+ * ```javascript
+ * behavior.getRow({ symbol: 'FB' });
+ * ```
+ * ###### Example 2
+ * Multi-column primary key (target row must match all keys):
+ * ```javascript
+ * behavior.getRow({ symbol: 'FB', name: 'Facebook' });
+ * ```
+ * ###### Example 3
+ * Limit the column(s) that comprise the primary key with `findList`, an array of allowable search keys:
+ * ```javascript
+ * var findWhiteList = ['symbol'];
+ * behavior.getRow({ symbol: 'FB', name: 'the facebook' }, findKeyList);
+ * ```
+ * In the above example, name is ignored because it is absent from the key list. This example is therefore functionally equivalent to example 2.a.
+ *
+ * ##### Modifications hash option
+ *
+ * Field(s) to modify may be provided in a hash instead (_à la_ jQuery.js)
+ *
+ * This overload allows for updating multiple columns of a row with a single method call:
+ * ```javascript
+ * var modHash = { name: 'Facebook, Inc.', prevclose: 125};
+ * dataModel.modifyRowById('symbol', 'FB', modHash);
+ * ```
+ * The above is equivalent to the following separate calls which each update a specific field in the same row:
+ * ```javascript
+ * dataModel.modifyRowById('symbol', 'FB', 'name', 'Facebook, Inc.');
+ * dataModel.modifyRowById('symbol', 'FB', 'prevclose', 125);
+ * ```
+ * Normally all included fields will be modified. As in `findList` (described above), you can limit which fields to actually modify by providing an additional parameter `modList`, an array of fields to modify. The following example modifies the "prevClose" field but not the "name" field:
+ * ```javascript
+ * var modWhiteList = ['prevclose'];
+ * dataModel.modifyRowById('symbol', 'FB', modHash, modWhiteList);
+ * ```
+ *
+ * ##### Summary
+ *
+ * The overloads discussed above in _Search key hash option_ and _Modifier hash option_ may be combined. For example, the full list of overloads for {@link rowById.modifyRowById} is:
+ *
+ * ```javascript
+ * behavior.modifyRowById(findKey, findVal, modKey, modVal);
+ * behavior.modifyRowById(findKey, findVal, modHash);
+ * behavior.modifyRowById(findKey, findVal, modHash, modWhiteList);
+ * behavior.modifyRowById(findHash, modKey, modVal);
+ * behavior.modifyRowById(findHash, modHash);
+ * behavior.modifyRowById(findHash, modHash, modWhiteList);
+ * behavior.modifyRowById(findHash, findWhiteList, modKey, modVal);
+ * behavior.modifyRowById(findHash, findWhiteList, modHash);
+ * behavior.modifyRowById(findHash, findWhiteList, modHash, modWhiteList);
+ * ```
+ *
+ * @mixin
+ */
+var rowById = {
+ /**
+ * @summary Remove the ID'd data row object from the data store.
+ * @desc If data source pipeline in use, to see the deletion in the grid, you must eventually call:
+ * ```javascript
+ * this.grid.behavior.applyAnalytics();
+ * this.grid.behaviorChanged();
+ * ```
+ * Caveat: The row indexes of all rows following the deleted row will now be one less than they were!
+ * @param {object|string} keyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of 0 or more key-value pairs to search for.
+ * @param {*|string[]} [valOrList] - One of:
+ * _omitted_ - When `keyOrHash` is a hash and you want to search all its keys.
+ * _string[]_ - When `keyOrHash` is a hash but you only want to search certain keys.
+ * _otherwise_ - When `keyOrHash` is a string. Value to search for.
+ * @returns {object} The deleted row object.
+ */
+ deleteRowById: function(keyOrHash, valOrList) {
+ return this.source.findRow.apply(this.source, getByIdArgs(keyOrHash, valOrList).concat([null]));
+ },
+
+ /**
+ * @summary Undefine the ID'd row object in place.
+ * @desc Similar to {@link rowById.deleteRowById|deleteRowById} except leave an `undefined` in place of data row object. This renders as a blank row in the grid.
+ *
+ * If data source pipeline in use, to see the deletion in the grid, you must eventually call:
+ * ```javascript
+ * this.grid.behavior.applyAnalytics();
+ * this.grid.behaviorChanged();
+ * ```
+ * @param {object|string} keyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of 0 or more key-value pairs to search for.
+ * @param {*|string[]} [valOrList] - One of:
+ * _omitted_ - When `keyOrHash` is a hash and you want to search all its keys.
+ * _string[]_ - When `keyOrHash` is a hash but you only want to search certain keys.
+ * _otherwise_ - When `keyOrHash` is a string. Value to search for.
+ * @returns {object} The deleted row object.
+ */
+ eraseRowById: function(keyOrHash, valOrList) {
+ return this.source.findRow.apply(this.source, getByIdArgs(keyOrHash, valOrList).concat([undefined]));
+ },
+
+ /**
+ * @param {object|string} keyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of 0 or more key-value pairs to search for.
+ * @param {*|string[]} [valOrList] - One of:
+ * _omitted_ - When `keyOrHash` is a hash and you want to search all its keys.
+ * _string[]_ - When `keyOrHash` is a hash but you only want to search certain keys.
+ * _otherwise_ - When `keyOrHash` is a string. Value to search for.
+ * @returns {number}
+ */
+ getRowIndexById: function(keyOrHash, valOrList) {
+ this.source.findRow.apply(this.source, arguments);
+ return this.source.getProperty('foundRowIndex');
+ },
+
+ /**
+ * @param {object|string} keyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of 0 or more key-value pairs to search for.
+ * @param {*|string[]} [valOrList] - One of:
+ * _omitted_ - When `keyOrHash` is a hash and you want to search all its keys.
+ * _string[]_ - When `keyOrHash` is a hash but you only want to search certain keys.
+ * _otherwise_ - When `keyOrHash` is a string. Value to search for.
+ * @returns {object}
+ */
+ getRowById: function(keyOrHash, valOrList) {
+ return this.source.findRow.apply(this.source, arguments);
+ },
+
+ /**
+ * @summary Update selected columns in existing data row.
+ * @desc If data source pipeline in use, to see the deletion in the grid, you must eventually call:
+ * ```javascript
+ * this.grid.behavior.applyAnalytics();
+ * this.grid.repaint();
+ * ```
+ * @param {object|string} findKeyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of zero or more key-value pairs to search for.
+ * @param {*|string[]} [findValOrList] - One of:
+ * _omitted_ - When `findKeyOrHash` is a hash and you want to search all its keys.
+ * _string[]_ - When `findKeyOrHash` is a hash but you only want to search certain keys.
+ * _otherwise_ - When `findKeyOrHash` is a string. Value to search for.
+ * @param {object|string} modKeyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of zero or more key-value pairs to modify.
+ * @param {*|string[]} [modValOrList] - One of:
+ * _omitted_ - When `modKeyOrHash` is a hash and you want to modify all its keys.
+ * _string[]_ - When `modKeyOrHash` is a hash but you only want to modify certain keys.
+ * _otherwise_ - When `modKeyOrHash` is a string. The modified value.
+ * @returns {object} The modified row object.
+ */
+ modifyRowById: function(findKeyOrHash, findValOrList, modKeyOrHash, modValOrList) {
+ var dataRow, keys, columnName;
+
+ if (typeof findKeyOrHash !== 'object' || findValOrList instanceof Array) {
+ dataRow = this.source.findRow(findKeyOrHash, findValOrList);
+ } else {
+ dataRow = this.source.findRow(findKeyOrHash);
+ modValOrList = modKeyOrHash; // promote
+ modKeyOrHash = findValOrList; // promote
+ }
+
+ if (dataRow) {
+ if (typeof modKeyOrHash !== 'object') {
+ dataRow[modKeyOrHash] = modValOrList;
+ } else {
+ keys = modValOrList instanceof Array ? modValOrList : Object.keys(modKeyOrHash);
+ for (var key in keys) {
+ columnName = keys[key];
+ dataRow[columnName] = modKeyOrHash[columnName];
+ }
+ }
+ }
+
+ return dataRow;
+ },
+
+ /**
+ * @summary Replace entire ID'd row object with another.
+ * @desc The replacement may have (but does not have to have) the same ID as the row object being replaced.
+ *
+ * If data source pipeline in use, to see the replaced row in the grid, you must eventually call:
+ * ```javascript
+ * this.grid.behavior.applyAnalytics();
+ * this.grid.behaviorChanged();
+ * ```
+ * @param {object|string} keyOrHash - One of:
+ * * _string_ - Column name.
+ * * _object_ - Hash of zero or more key-value pairs to search for.
+ * @param {*|string[]} [valOrList] - One of:
+ * _omitted_ - When `keyOrHash` is a hash and you want to search all its keys.
+ * _string[]_ - When `keyOrHash` is a hash but you only want to search certain keys.
+ * _otherwise_ - When `keyOrHash` is a string. Value to search for.
+ * @param {object} replacement
+ * @returns {object} The replaced row object.
+ */
+ replaceRowById: function(keyOrHash, valOrList, replacement) {
+ if (typeof keyOrHash === 'object' && !(valOrList instanceof Array)) {
+ replacement = valOrList; // promote
+ }
+ if (typeof replacement !== 'object') {
+ throw 'Expected an object for replacement but found ' + typeof replacement + '.';
+ }
+ return this.source.findRow.apply(this.source, arguments);
+ }
+};
+
+function getByIdArgs(keyOrHash, valOrList) {
+ var length = typeof keyOrHash !== 'object' || valOrList instanceof Array ? 2 : 1;
+ return Array.prototype.slice.call(arguments, 0, length);
+}
+
+/**
+ * @name mixInTo
+ * @summary Mix all the other members into the given target object.
+ * @desc The target object is intended to be Hypergrid's in-memory data model object ({@link dataModels.JSON}).
+ *
+ * **NOTE:** This `mixInTo` method is defined here rather than above just so that it will be non-enumerable and therefore not itself mixed into the `target` object.
+ * @function
+ * @param {object} target - Your data model instance or its prototype.
+ * @memberOf rowById
+ */
+Object.defineProperty(rowById, 'mixInTo', { // defined here just to make it non-enumerable
+ value: function(target) {
+ Object.keys(this).forEach(function(key) {
+ target[key] = this[key];
+ }.bind(this));
+ }
+});
+
+module.exports = rowById;
diff --git a/add-ons/tree-view.js b/add-ons/tree-view.js
index 42f8a620a..5c54f52c9 100644
--- a/add-ons/tree-view.js
+++ b/add-ons/tree-view.js
@@ -1,39 +1,74 @@
'use strict';
+// NOTE: gulpfile.js's 'add-ons' task makes a copy of this file, altering the final line. The copy is placed in demo/build/add-ons/ along with a minified version. Both files are eventually deployed to http://openfin.github.io/fin-hypergrid/add-ons/. Neither file is saved to the repo.
+
/**
* @classdesc This is a simple helper class to set up the tree-view data source in the context of a hypergrid.
*
* It includes methods to:
- * * Insert `DataSourceTreeview` into the data model's pipeline (`addPipe`, `addPipeTo`).
- * * Perform the self-join and rebuild the index to turn the tree-view on or off, optionally hiding the ID columns (`setRelation`).
+ * * Insert the tree-view data source (`DataSourceTreeview`) into the data model's pipeline (see {#@link TreeView#setPipeline|setPipeline} method) along with the optional filter and sort data sources.
+ * * Perform the self-join and rebuild the index to turn the tree-view on or off, optionally hiding the ID columns ({#@link TreeView#setRelation|setRelation} method).
*
- * @param {object} [options]
- * @param {boolean} [options.shared=false]
+ * @param {object} options - Passed to data source's {@link DataSourceTreeView#setRelation|setRelation} method ({@link http://openfin.github.io/hyper-analytics/DataSourceTreeview.html#setRelation|see}) when called here by local API's {@link TreeView#setRelation|this.setRelation} method.
* @constructor
*/
function TreeView(grid, options) {
this.grid = grid;
- this.options = options;
+ this.options = options || {};
}
TreeView.prototype = {
+
constructor: TreeView.prototype.constructor,
/**
- * @summary Reconfigure the dataModel's pipeline for tree view.
- * @desc The pipeline is reset starting with either the given `options.dataSource` _or_ the existing pipeline's first data source.
+ * @summary Reconfigure the data model's data pipeline for tree view.
+ * @desc The _data transformation pipeline_ is an ordered list of data transformations, always beginning with an actual data source. Each _transformation_ in the pipeline operates on the data source immediately ahead of it. While transformations are free to completely rewrite the data in any way they want, most transformations merely apply an index to the data.
+ *
+ * The _shared pipeline_ is defined on the data model's prototype and is used for all grid instances (using the same data model). A grid can however define a _local pipeline_ on the data model's instance.
+ *
+ * In any case, the actual data pipeline is (re)constructed from a _pipeline configuration_ each time data is set on the grid via {@link dataModel/JSON#setData|setData}.
+ *
+ * This method reconfigures the data pipeline suitable for tree view. It is designed to operate on either of:
+ * * the "shared" pipeline configuration (on the grid's data model's prototype)
+ * * the grid's "local" pipeline configuration (on the grid's data model's instance)
*
- * Then the tree view filter and sorter data sources are added as requested.
+ * This method operates as follows:
+ * 1. Reset the pipeline:
+ * * In the case of the shared pipeline, the array is truncated in place.
+ * * In the case of an instance pipeline, a new array is created.
+ * 2. Add the first data source:
+ * * The data source provided in `options.firstPipe` is used if given; otherwise...
+ * * The existing pipeline configuration's first data source will be reused. (First time in, this will always come from the prototype's version.)
+ * 3. Add the filter data source (if requested).
+ * 4. Add the tree sorter data source (if requested).
+ * 5. Finally, add the tree view data source.
*
- * Finally the tree view data source is added.
+ * Step 1 above operates on the shared pipeline when you supply the data model's prototype in `options.dataModelPrototype` (see below). In this case, you have the option of calling this method _before_ instantiating your grid(s):
*
- * This method can operate on either:
- * * A data model prototype, which will affect all data models subsequently created therefrom. The prototype must be given in `options.dataModelPrototype`.
- * * The current data model instance. In this case, the instance is given its own new pipeline.
+ * ```javascript
+ * var JSON = Hypergrid.dataModels.JSON.prototype;
+ * var pipelineOptions = { dataModelPrototype: JSON.prototype }
+ * TreeView.prototype.setPipeline(pipelineOptions);
+ * ```
+ *
+ * This approach avoids the need to reset the data after reconfiguring the pipeline (in which case, do _not_ call this method again after instantiation).
*
* @param {object} [options]
- * @param {object} [options.dataModelPrototype] - Adds the pipes to the given object. If omitted, this must be an instance; adds the pipes to a new "own" pipeline created from the first data source of the instance's old pipeline.
- * @param {dataSourcePipelineObject} [options.firstPipe] - Use as first data source in the new pipeline. If omitted, re-uses the existing pipeline's first data source.
+ *
+ * @param {boolean} [options.includeFilter=false] - Enables filtering. Includes the filter data source. The filter row is hidden if falsy.
+ *
+ * @param {boolean} [options.includeSorter=false] - Enables sorting. Includes the specialized tree sorter data source.
+ *
+ * @param {object} [options.dataModelPrototype] - Adds requested pipes to the "shared" pipeline array object instead of to a new custom (instance) pipeline array object.
+ *
+ * Supply this option when you want to set up the "shared" pipeline on the data model prototype, which would then be available to all grid instances subsequently created thereafter. In this case, you can call this method before or after grid instantiation. To call it before, call it directly on `TreeView.prototype`; to call it after, call it normally (on the `TreeView` instance).
+ *
+ * If omitted, a new "own" (instance) pipeline is created, overriding the prototype's (shared) pipeline. (In this case this method must be called normally, on the `Treeview` instance.)
+ *
+ * In either case, if called "normally" (on the instance), the data is reset via `setData`. (If called on the prototype it is not reset here. Currently the `Hypergrid` constructor calls it.)
+ *
+ * @param {dataSourcePipelineObject} [options.firstPipe] - Use as first data source in the new pipeline. If undefined, the existing pipeline's first data source will be reused.
*/
setPipeline: function(options) {
options = options || {};
@@ -78,7 +113,7 @@ TreeView.prototype = {
/**
* @summary Build/unbuild the tree view.
- * @param {boolean} join - Turn tree-view **ON**. If falsy (or omitted), turn it **OFF**.
+ * @param {boolean} join - If truthy, turn tree-view **ON**. If falsy (or omitted), turn it **OFF**.
* @param {boolean} [hideIdColumns=false] - Once hidden, cannot be unhidden from here.
* @returns {boolean} Joined state.
*/
@@ -92,11 +127,11 @@ TreeView.prototype = {
columnProps = behavior.getColumn(dataSource.treeColumn.index).getProperties();
if (joined) {
- // save the current value of column's editable property and set it to false
+ // Make the tree column uneditable: Save the current value of the tree column's editable property and set it to false.
this.editableWas = !!columnProps.editable;
columnProps.editable = false;
- // save value of grid's checkboxOnlyRowSelections property and set it to true so drill-down clicks don't select the row they are in
+ // Save value of grid's checkboxOnlyRowSelections property and set it to true so drill-down clicks don't select the row they are in
this.checkboxOnlyRowSelectionsWas = state.checkboxOnlyRowSelections;
state.checkboxOnlyRowSelections = true;
@@ -110,16 +145,7 @@ TreeView.prototype = {
}
});
}
-
- dataSource.defaultSortColumn = dataSource.getColumnInfo(options.defaultSortColumn, dataSource.treeColumn.name);
-
- // If unsorted, sort by tree column
- if (behavior.getSortedColumnIndexes().length === 0) {
- var gridIndex = behavior.getActiveColumnIndex(dataSource.defaultSortColumn.index);
- this.grid.toggleSort(gridIndex, []);
- }
} else {
- dataSource.defaultSortColumn = undefined;
columnProps.editable = this.editableWas;
state.checkboxOnlyRowSelections = this.checkboxOnlyRowSelectionsWas;
}
@@ -132,12 +158,14 @@ TreeView.prototype = {
return joined;
}
+
};
/**
* This is the required test function called by the data model's `isDrilldown` method in context. _Do not call directly._
* @param {number} [event.dataCell.x] If available, also checks that the column clicked is the tree column.
* @returns {boolean} If the data source is a tree view.
+ * @private
*/
function isTreeview(event) {
var treeview = this.sources.treeview,
diff --git a/demo/data/tree-data.js b/demo/data/tree-data.js
index 086227584..cb1d6bc05 100644
--- a/demo/data/tree-data.js
+++ b/demo/data/tree-data.js
@@ -2,18 +2,18 @@
(function() {
var data = [
- { ID: 0, parentID: null, State: 'USA', Latitude: 36.2161472, Longitude: -113.6866279 },
- { ID: 10, parentID: null, State: 'France', Latitude: 46.1274793, Longitude: -2.288454 },
- { ID: 1, parentID: 0, State: 'New York', Latitude: 40.7055651, Longitude: -74.118086 },
- { ID: 2, parentID: 1, State: 'Albany', Latitude: 42.6681345, Longitude: -73.846419 },
- { ID: 3, parentID: 1, State: 'Syracuse', Latitude: 43.0352286, Longitude: -76.1742994 },
- { ID: 4, parentID: 0, State: 'California', Latitude: 37.1870791, Longitude: -123.762638 },
- { ID: 5, parentID: 4, State: 'Monterey', Latitude: 36.5943628, Longitude: -121.9025183 },
- { ID: 6, parentID: 4, State: 'Berkeley', Latitude: 37.8759458, Longitude: -122.2981316 },
- { ID: 7, parentID: 4, State: 'Laguna', Latitude: 33.5482634, Longitude: -117.8447927 },
- { ID: 8, parentID: 0, State: 'Massachusetts', Latitude: 42.6369691, Longitude: -71.3618803 },
- { ID: 9, parentID: 8, State: 'Lowell', Latitude: 42.6369691, Longitude: -71.3618803 },
- { ID: 11, parentID: 10, State: 'Paris', Latitude: 48.8588376, Longitude: 2.2773459 },
+ { ID: 1, parentID: 20, State: 'New York', Latitude: 40.7055651, Longitude: -74.118086 },
+ { ID: 5, parentID: 4, State: 'Monterey', Latitude: 36.5943628, Longitude: -121.9025183 },
+ { ID: 2, parentID: 1, State: 'Albany', Latitude: 42.6681345, Longitude: -73.846419 },
+ { ID: 20, parentID: null, State: 'USA', Latitude: 36.2161472, Longitude: -113.6866279 },
+ { ID: 6, parentID: 4, State: 'Berkeley', Latitude: 37.8759458, Longitude: -122.2981316 },
+ { ID: 3, parentID: 1, State: 'Syracuse', Latitude: 43.0352286, Longitude: -76.1742994 },
+ { ID: 4, parentID: 20, State: 'California', Latitude: 37.1870791, Longitude: -123.762638 },
+ { ID: 10, parentID: null, State: 'France', Latitude: 46.1274793, Longitude: -2.288454 },
+ { ID: 7, parentID: 4, State: 'Laguna', Latitude: 33.5482634, Longitude: -117.8447927 },
+ { ID: 8, parentID: 20, State: 'Massachusetts', Latitude: 42.6369691, Longitude: -71.3618803 },
+ { ID: 9, parentID: 8, State: 'Lowell', Latitude: 42.6369691, Longitude: -71.3618803 },
+ { ID: 11, parentID: 10, State: 'Paris', Latitude: 48.8588376, Longitude: 2.2773459 },
];
window.treeData = data;
})();
diff --git a/demo/example.html b/demo/example.html
index 90f952e5a..c0739f193 100644
--- a/demo/example.html
+++ b/demo/example.html
@@ -7,7 +7,7 @@