Socket
Socket
Sign inDemoInstall

fin-hypergrid

Package Overview
Dependencies
Maintainers
2
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fin-hypergrid - npm Package Compare versions

Comparing version 1.0.4 to 1.0.6

src/cellRenderers/Button.js

258

html/index.js
'use strict';
exports.CQL = [
'<label title="${1}">',
' <a type="button" class="filter-copy"></a>',
' <div class="filter-tree-remove-button" title="delete conditional"></div>',
' <strong>%{0}:</strong>',
' <input name="${1}" class="filter-text-box ${3}" value="%{2}">',
'</label>',
'<div class="filter-tree-warn"></div>'
'<li>',
' <label title="${1}">',
' <a type="button" class="filter-copy"></a>',
' <div class="filter-tree-remove-button" title="delete conditional"></div>',
' <strong>%{0}:</strong>',
' <input name="${1}" class="filter-text-box ${3}" value="%{2}">',
' </label>',
' <div class="filter-tree-warn"></div>',
'</li>'
].join('\n');
exports.SQL = [
'<label title="${1}">',
' <a type="button" class="filter-copy"></a>',
' <div class="filter-tree-remove-button" title="delete conditional"></div>',
' <strong>%{0}:</strong>',
' <textarea name="${1}" rows="1" class="filter-text-box ${3}">%{2}</textarea>',
'</label>',
'<div class="filter-tree-warn"></div>'
'<li>',
' <label title="${1}">',
' <a type="button" class="filter-copy"></a>',
' <div class="filter-tree-remove-button" title="delete conditional"></div>',
' <strong>%{0}:</strong>',
' <textarea name="${1}" rows="1" class="filter-text-box ${3}">%{2}</textarea>',
' </label>',
' <div class="filter-tree-warn"></div>',
'</li>'
].join('\n');

@@ -28,44 +32,44 @@

' #hypergrid-dialog {',
' position: absolute;',
' top: 0;',
' left: 0;',
' bottom: 0;',
' right: 0;',
' background-color: white;',
' font: 10pt sans-serif;',
' opacity: 0;',
' transition: opacity 1s;',
' box-shadow: rgba(0, 0, 0, 0.298039) 0px 19px 38px, rgba(0, 0, 0, 0.219608) 0px 15px 12px;',
' position: absolute;',
' top: 0;',
' left: 0;',
' bottom: 0;',
' right: 0;',
' background-color: white;',
' font: 10pt sans-serif;',
' opacity: 0;',
' transition: opacity 1s;',
' box-shadow: rgba(0, 0, 0, 0.298039) 0px 19px 38px, rgba(0, 0, 0, 0.219608) 0px 15px 12px;',
' }',
' #hypergrid-dialog.hypergrid-dialog-visible {',
' opacity: 1;',
' transition: opacity 1s;',
' opacity: 1;',
' transition: opacity 1s;',
' }',
'',
' #hypergrid-dialog .hypergrid-dialog-control-panel {',
' position: absolute;',
' top: 0px;',
' right: 12px;',
' position: absolute;',
' top: 0px;',
' right: 12px;',
' }',
' #hypergrid-dialog .hypergrid-dialog-control-panel a {',
' color: #999;',
' font-size: 33px;',
' transition: text-shadow .35s, color .35s;',
' text-decoration: none;',
' color: #999;',
' font-size: 33px;',
' transition: text-shadow .35s, color .35s;',
' text-decoration: none;',
' }',
' #hypergrid-dialog .hypergrid-dialog-close:after {',
' content: \'\\D7\';',
' content: \'\\D7\';',
' }',
' #hypergrid-dialog .hypergrid-dialog-settings:after {',
' font-family: Apple Symbols;',
' content: \'\\2699\';',
' font-family: Apple Symbols;',
' content: \'\\2699\';',
' }',
' #hypergrid-dialog .hypergrid-dialog-control-panel a:hover {',
' color: black;',
' text-shadow: 0 0 6px #337ab7;',
' transition: text-shadow .35s, color .35s;',
' color: black;',
' text-shadow: 0 0 6px #337ab7;',
' transition: text-shadow .35s, color .35s;',
' }',
' #hypergrid-dialog .hypergrid-dialog-control-panel a:active {',
' color: #d00;',
' transition: color 0s;',
' color: #d00;',
' transition: color 0s;',
' }',

@@ -215,3 +219,3 @@ ' </style>',

' <header id="columnsQB" class="default-tab">',
' Query Builder',
' Query Builder',
' </header>',

@@ -223,68 +227,68 @@ '',

' <header id="columnsSQL" class="tabz-bg2">',
' SQL',
' SQL',
' </header>',
'',
' <section class="filter-expression-syntax tabz-bg2">',
' <div>',
' <p>',
' <span></span>',
' <a type="button" class="filter-copy" title="The state of the column filters subtree expressed in SQL syntax (all the column filter subexpressions shown below AND&rsquo;d together).">',
' all</a>',
' </p>',
' <ol></ol>',
' </div>',
' <div>',
' <p>',
' <span></span>',
' <a type="button" class="filter-copy" title="The state of the column filters subtree expressed in SQL syntax (all the column filter subexpressions shown below AND&rsquo;d together).">',
' all</a>',
' </p>',
' <ol></ol>',
' </div>',
' </section>',
'',
' <header id="columnsCQL" class="tabz-bg1">',
' CQL',
' CQL',
' </header>',
'',
' <section class="filter-expression-syntax tabz-bg1">',
' <p>',
' <em>',
' <small>Column filter cells accept a simplified, compact, and intuitive syntax, which is however not as flexible or concise as SQL syntax or using the Query Builder.</small>',
' <a class="more-info"></a>',
' </em>',
' </p>',
' <div class="more-info">',
' <ul>',
' <li>',
' Simple expressions',
' <ul>',
' <li>All simple expressions take the form <i>operator literal</i> or <i>operator identifier</i>. The (left side) column is always implied and is the same for all simple expressions in a compound expression. This is because column filters are always tied to a known column.</li>',
' <p>',
' <em>',
' <small>Column filter cells accept a simplified, compact, and intuitive syntax, which is however not as flexible or concise as SQL syntax or using the Query Builder.</small>',
' <a class="more-info"></a>',
' </em>',
' </p>',
' <div class="more-info">',
' <ul>',
' <li>',
' Simple expressions',
' <ul>',
' <li>All simple expressions take the form <i>operator literal</i> or <i>operator identifier</i>. The (left side) column is always implied and is the same for all simple expressions in a compound expression. This is because column filters are always tied to a known column.</li>',
'',
' <li>If the operator is an equals sign (=), it may be omitted.</li>',
' <li>If the operator is an equals sign (=), it may be omitted.</li>',
'',
' <li>Besides operators, no other punctuation is permitted, meaning that no quotation marks and no parentheses.</li>',
' <li>Besides operators, no other punctuation is permitted, meaning that no quotation marks and no parentheses.</li>',
'',
' <li>If a literal exactly matches a column name or alias, the operand is not taken literally and instead refers to the value in that column. (There are properties to control what constitutes such a match: Column name, alias, or either; and the case-sensitivity of the match.)</li>',
' <li>If a literal exactly matches a column name or alias, the operand is not taken literally and instead refers to the value in that column. (There are properties to control what constitutes such a match: Column name, alias, or either; and the case-sensitivity of the match.)</li>',
'',
' <li>As literals are unquoted, any operator symbol or operator word (including logical operators for compound expressions) terminates a literal.</li>',
' <li>As literals are unquoted, any operator symbol or operator word (including logical operators for compound expressions) terminates a literal.</li>',
'',
' <li>An important corollary to the above features is that operators may not appear in literals.</li>',
' </ul>',
' </li>',
' <li>An important corollary to the above features is that operators may not appear in literals.</li>',
' </ul>',
' </li>',
'',
' <li>',
' Compound expressions',
' <ul>',
' <li>Compound expressions are formed by connecting simple expressions with the logical operators <code>AND</code>, <code>OR</code>, <code>NOR</code>, or <code>NAND</code> ("not and").</li>',
' <li>',
' Compound expressions',
' <ul>',
' <li>Compound expressions are formed by connecting simple expressions with the logical operators <code>AND</code>, <code>OR</code>, <code>NOR</code>, or <code>NAND</code> ("not and").</li>',
'',
' <li>However, all logical operators used in a compound column filter expression must be homogeneous. You may not mix the above logical operators in a single column. (If you need to do this, create a table filter expression instead.)</li>',
' </ul>',
' </li>',
' <li>However, all logical operators used in a compound column filter expression must be homogeneous. You may not mix the above logical operators in a single column. (If you need to do this, create a table filter expression instead.)</li>',
' </ul>',
' </li>',
'',
' <li>',
' Hidden logic',
' <ul>',
' <li>If the column is also referenced in a table filter expression (on the left side of a simple expression), the column filter is flagged in its grid cell with a special star character. This is just a flag; it is not part of the syntax. <span style="color:red; font-style:italic">Not yet implemented.</span></li>',
' </ul>',
' </li>',
' </ul>',
' </div>',
' <li>',
' Hidden logic',
' <ul>',
' <li>If the column is also referenced in a table filter expression (on the left side of a simple expression), the column filter is flagged in its grid cell with a special star character. This is just a flag; it is not part of the syntax. <span style="color:red; font-style:italic">Not yet implemented.</span></li>',
' </ul>',
' </li>',
' </ul>',
' </div>',
'',
' <div>',
' <p><span></span></p>',
' <ol></ol>',
' </div>',
' <div>',
' <p><span></span></p>',
' <ol></ol>',
' </div>',
' </section>',

@@ -302,7 +306,7 @@ ' </div>',

' <p>',
' These filter subexpressions are both required (<code>AND</code>&rsquo;d together), resulting in a subset of <em>qualified rows</em> which have passed through both filters.',
' It\'s called a <dfn>tree</dfn> because it contains both <dfn>branches</dfn> and <dfn>leaves</dfn>.',
' The leaves represent <dfn>conditional expressions</dfn> (or simply <dfn>conditionals</dfn>).',
' The branches, also known as <dfn>subtrees</dfn>, contain leaves and/or other branches and represent subexpressions that group conditionals together.',
' Grouped conditionals are evaluated together, before conditionals outside the group.',
' These filter subexpressions are both required (<code>AND</code>&rsquo;d together), resulting in a subset of <em>qualified rows</em> which have passed through both filters.',
' It\'s called a <dfn>tree</dfn> because it contains both <dfn>branches</dfn> and <dfn>leaves</dfn>.',
' The leaves represent <dfn>conditional expressions</dfn> (or simply <dfn>conditionals</dfn>).',
' The branches, also known as <dfn>subtrees</dfn>, contain leaves and/or other branches and represent subexpressions that group conditionals together.',
' Grouped conditionals are evaluated together, before conditionals outside the group.',
' </p>',

@@ -313,3 +317,3 @@ ' </div>',

' <header id="tableQB">',
' Query Builder',
' Query Builder',
' </header>',

@@ -321,43 +325,43 @@ '',

' <header id="tableSQL" class="tabz-bg2">',
' SQL',
' SQL',
' </header>',
'',
' <section class="filter-expression-syntax tabz-bg2">',
' <div>',
' <p>',
' SQL WHERE clause syntax with certain restrictions.',
' <a class="more-info"></a>',
' </p>',
' <div class="more-info">',
' <ul>',
' <li>',
' Simple expressions',
' <ul>',
' <li>All simple expressions must be of the form <i>column operator literal</i> or <i>column operator identifier</i>. That is, the left side must refer to a column (may not be a literal); whereas the right side may be either.</li>',
' <div>',
' <p>',
' SQL WHERE clause syntax with certain restrictions.',
' <a class="more-info"></a>',
' </p>',
' <div class="more-info">',
' <ul>',
' <li>',
' Simple expressions',
' <ul>',
' <li>All simple expressions must be of the form <i>column operator literal</i> or <i>column operator identifier</i>. That is, the left side must refer to a column (may not be a literal); whereas the right side may be either.</li>',
'',
' <li>Column names may be quoted with the currently set quote characters (typically double-quotes). If unquoted, they must consist of classic identifier syntax (alphanumerics and underscore, but not beginning with a numeral).</li>',
' <li>Column names may be quoted with the currently set quote characters (typically double-quotes). If unquoted, they must consist of classic identifier syntax (alphanumerics and underscore, but not beginning with a numeral).</li>',
'',
' <li>All literals must be quoted strings (using single quotes). (In a future release we expect to support unquoted numeric syntax for columns explicitly typed as numeric.)</li>',
' </ul>',
' </li>',
' <li>All literals must be quoted strings (using single quotes). (In a future release we expect to support unquoted numeric syntax for columns explicitly typed as numeric.)</li>',
' </ul>',
' </li>',
'',
' <li>',
' Compound expressions',
' <ul>',
' <li>Compound expressions are formed by connecting simple expressions with the logical operators <code>AND</code> or <code>OR</code>.</li>',
' <li>',
' Compound expressions',
' <ul>',
' <li>Compound expressions are formed by connecting simple expressions with the logical operators <code>AND</code> or <code>OR</code>.</li>',
'',
' <li>However, all logical operators at each level in a complex expression (each parenthesized subexpression) must be homogeneous, <i>i.e.,</i> either <code>AND</code> or <code>OR</code> but not a mixture of the two. In other words, there is no implicit operator precedence; grouping of expressions must always be explicitly stated with parentheses.</li>',
' <li>However, all logical operators at each level in a complex expression (each parenthesized subexpression) must be homogeneous, <i>i.e.,</i> either <code>AND</code> or <code>OR</code> but not a mixture of the two. In other words, there is no implicit operator precedence; grouping of expressions must always be explicitly stated with parentheses.</li>',
'',
' <li>The unary logical operator <code>NOT</code> is supoorted before parentheses only. While the Query Builder and the Column Filter allow they syntax <code>&hellip; NOT <i>operator</i> &hellip;</code> (where <code><i>operator</i></code> is <code>IN</code>, <code>LIKE</code>, <i>etc.</i>), these must be expressed here with parenthethes: <code>NOT (&hellip; <i>operator</i> &hellip;)</code>.</li>',
' <li>The unary logical operator <code>NOT</code> is supoorted before parentheses only. While the Query Builder and the Column Filter allow they syntax <code>&hellip; NOT <i>operator</i> &hellip;</code> (where <code><i>operator</i></code> is <code>IN</code>, <code>LIKE</code>, <i>etc.</i>), these must be expressed here with parenthethes: <code>NOT (&hellip; <i>operator</i> &hellip;)</code>.</li>',
'',
' <li>While the Query Builder and Column Filter syntax support the pseudo-operators <code>NOR</code> and <code>NAND</code>, in SQL these must be expressed as <code>NOT (&hellip; OR &hellip;)</code> and <code>NOT (&hellip; AND &hellip;)</code>, respectively.</li>',
' <li>While the Query Builder and Column Filter syntax support the pseudo-operators <code>NOR</code> and <code>NAND</code>, in SQL these must be expressed as <code>NOT (&hellip; OR &hellip;)</code> and <code>NOT (&hellip; AND &hellip;)</code>, respectively.</li>',
'',
' <li>The Query Builder and Column Filter syntax also support the pseudo-operators <code>BEGINS abc</code>, <code>ENDS xyz</code>, and <code>CONTAINS def</code>. These are expressed in SQL by <code>LIKE \'abc%\'</code>, <code>LIKE \'%xyz\'</code>, and <code>LIKE \'%def%\'</code>, respectively.</li>',
' </ul>',
' </li>',
' </ul>',
' </div>',
' </div>',
' <div class="filter-tree-warn"></div>',
' <textarea></textarea>',
' <li>The Query Builder and Column Filter syntax also support the pseudo-operators <code>BEGINS abc</code>, <code>ENDS xyz</code>, and <code>CONTAINS def</code>. These are expressed in SQL by <code>LIKE \'abc%\'</code>, <code>LIKE \'%xyz\'</code>, and <code>LIKE \'%def%\'</code>, respectively.</li>',
' </ul>',
' </li>',
' </ul>',
' </div>',
' </div>',
' <div class="filter-tree-warn"></div>',
' <textarea></textarea>',
' </section>',

@@ -364,0 +368,0 @@ '',

{
"name": "fin-hypergrid",
"version": "1.0.4",
"version": "1.0.6",
"description": "Canvas-based high-performance spreadsheet",

@@ -19,8 +19,8 @@ "repository": {

"dependencies": {
"automat": "1.1.1",
"automat": "1.2.0",
"extend-me": "2.2.2",
"filter-tree": "0.3.26",
"filter-tree": "0.3.32",
"finbars": "1.5.1",
"fincanvas": "1.2.1",
"hyper-analytics": "0.10.4",
"hyper-analytics": "0.11.0",
"list-dragon": "1.3.3",

@@ -42,6 +42,7 @@ "lru-cache": "2.7.0",

"gulp-concat": "^2.6.0",
"gulp-each": "^0.1.1",
"gulp-eslint": "^1.1.0",
"gulp-exclude-gitignore": "^1.0.0",
"gulp-footer": "^1.0.5",
"gulp-header": "^1.7.1",
"gulp-header": "^1.8.2",
"gulp-imagine-64": "^1.0.1",

@@ -55,2 +56,3 @@ "gulp-load-plugins": "^1.1.0",

"gutil": "^1.6.4",
"header": "^0.1.1",
"multipipe": "^0.2.1",

@@ -57,0 +59,0 @@ "multiple": "^0.2.1",

**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.
### Release 1.0
<img src="images/README/gridshot04.gif">
### Release 1.0.6 (23 June 2016)
This 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:

@@ -9,8 +11,18 @@ * An [npm module](https://www.npmjs.com/package/fin-hypergrid) for use with browserify.

_For a list of changes since the previous version, 1.0.3 (27 May 2016), click [here](version-history.md)._
### Demos
See the version 1.0 [demo](https://openfin.github.io/fin-hypergrid).
##### Developer Tutorial
The prototype version's [demos](http://openfin.github.io/fin-hypergrid-polymer-demo/components/fin-hypergrid/demo.html) had some nice applications you may wish to look at for inspiration of what you can do with hypergrid and to give you some idea of the speed and responsiveness of the engine.
This [tutorial](https://openfin.github.io/fin-hypergrid) is a tool that shows developers how to use Hypergrid and implement its features.
##### Hyperblotter
Hyperblotter is a demo app that shows the capabilities of both OpenFin and Hypergrid.
Check out the Table view on Hyperblotter on a Windows machine via [this installer](https://dl.openfin.co/services/download?fileName=Hyperblotter&config=http://cdn.openfin.co/demos/hyperblotter/app.json).
![](https://github.com/openfin/fin-hypergrid/blob/master/images/Hyperblotter%20Tabled%20Reduced%20Rows.png)
### Features

@@ -24,14 +36,17 @@

* Supports local (client-side) as well as remote (server-side) data hosting
* Comes with default "analytics" modules (sorting, filtering, aggregation)
* Events for all UI manipulations including mouse, keyboard, and programmatic UI changes
* Tree-view (drill-downs) support for aggregated local data
* Tree-view (drill-downs) presentation for pre-aggregated local data
##### Future development
* The analytics modules will be plug-in-replaceable in a future release (at which point the default modules will be broken out into separate npm modules/JavaScript files)
* Tree-view support for remotely aggregated data
* Tree-view presentation for remotely aggregated data
###### The Filtering & Analytics (sorting & aggregation) modules provided will be broken out of Hypergrid
* We are currently working on expanding the API to enable application developers to easily provide their own functionality
* Hypergrid will have no opinion on how the underlying data should be pivoted, but will remain capable of presenting pivoted data
* The current filtering and analytics modules will become separate npm modules/JavaScript files that can be forked and further developed
### Documentation
Essential documenation and examples will be added to this page in the near future.
Essential documentation and examples will be added to this page in the near future.

@@ -41,1 +56,6 @@ We are also maintaining [online API documentation](http://openfin.github.io/fin-hypergrid/doc/Hypergrid.html) for all public objects and modules. This documentation is necessarily a on-going work-in-progress.

(Cell editor information can be found [here](http://openfin.github.io/fin-hypergrid/doc/tutorial-cell-editors.html).)
(Cell Rendering information can be found [here](http://openfin.github.io/fin-hypergrid/doc/tutorial-cell-renderer.html).)
Hypergrid global configurations can be found [here](http://openfin.github.io/fin-hypergrid/doc/module-defaults.html)
Use it for modifying various hypergrid features and property defaults

@@ -9,10 +9,4 @@ /* eslint-env browser */

var dialogs = require('../dialogs');
var CellProvider = require('../lib/CellProvider');
var ColumnSchemaFactory = require('../filter/ColumnSchemaFactory');
var DefaultFilter = require('../filter/DefaultFilter');
function deriveSchema() {
return new ColumnSchemaFactory(this.columns).schema;
}
var noExportProperties = [

@@ -50,4 +44,3 @@ 'columnHeader',

*/
initialize: function(grid, schema) {
initialize: function(grid, schema, dataRows) {
/**

@@ -59,4 +52,2 @@ * @type {Hypergrid}

this.schema = schema || deriveSchema;
/**

@@ -114,3 +105,2 @@ * @type {DataModel}

reset: function() {
this.cellProvider = this.createCellProvider();
this.renderedColumnCount = 30;

@@ -141,7 +131,21 @@ this.renderedRowCount = 60;

this.allColumns[-2] = this.columns[-2] = this.newColumn(-2);
this.columnEnum = {};
},
getVisibleColumn: function(x) {
getActiveColumn: function(x) {
return this.columns[x];
},
getVisibleColumn: function() {
this.deprecated('getVisibleColumn(x)', 'getActiveColumn(x)', '1.0.6', arguments);
},
getVisibleColumnName: function() {
this.deprecated('getVisibleColumnName(x)', 'getActiveColumn(x).name', '1.0.6', arguments);
},
getColumnId: function() {
this.deprecated('getColumnId(x)', 'getActiveColumn(x).header', '1.0.6', arguments);
},
getHeader: function() {
this.deprecated('getHeader(x)', 'getActiveColumn(x).header', '1.0.6', arguments);
},

@@ -152,6 +156,2 @@ getColumn: function(x) {

getColumnId: function(x) {
return this.getVisibleColumn(x).getHeader();
},
newColumn: function(options) {

@@ -494,3 +494,3 @@ var column = new Column(this, options);

getColumnWidth: function(x) {
var column = this.getVisibleColumn(x);
var column = this.getActiveColumn(x);
if (!column) {

@@ -504,17 +504,15 @@ return this.resolveProperty('defaultColumnWidth');

setColumnWidth: function(x, width) {
this.getVisibleColumn(x).setWidth(width);
this.getActiveColumn(x).setWidth(width);
this.stateChanged();
},
/** @deprecated Use `.dataModel` property instead.
* @memberOf Behavior.prototype
* @returns {Hypergrid} The hypergrid to which this behavior is attached.
*/
getDataModel: function() {
return this.deprecated('dataModel', { since: '0.2.1' });
},
getCellRenderer: function(config, x, y) {
return this.getVisibleColumn(x).getCellRenderer(config, y);
return this.getActiveColumn(x).getCellRenderer(config, y);
},
getCellProvider: function(name) {
this.deprecated('getCellProvider()', 'grid.cellRenderers', '1.0.6', arguments);
},
createCellProvider: function(name) {
console.error('getCellProvider() is deprecated as of v1.0.6. No replacement; do not call. Previously called by `Behavior` constructor; `new CellRenderers()` is now called by `Hypergrid` constructor instead.', arguments);
},

@@ -685,11 +683,2 @@ applyAnalytics: function() {

* @memberOf Behavior.prototype
* @desc getter for the cell provider
* @return {CellProvider}
*/
getCellProvider: function() {
return this.cellProvider;
},
/**
* @memberOf Behavior.prototype
* @desc setter for the hypergrid

@@ -701,22 +690,4 @@ * @param {Hypergrid} grid

/** @deprecated Use `.grid` property instead.
* @memberOf Behavior.prototype
* @returns {Hypergrid} The hypergrid to which this behavior is attached.
* @param {type} varname - descripton
*/
getGrid: function() {
return this.deprecated('grid', { since: '0.2' });
},
/**
* @memberOf Behavior.prototype
* @desc You can override this function and substitute your own cell provider.
* @return {CellProvider}
*/
createCellProvider: function() {
return new CellProvider();
},
/**
* @memberOf Behavior.prototype
* @desc First check to see if something was overridden.

@@ -728,3 +699,3 @@ * @return {*} The value at `x,y` for the top left section of the hypergrid.

getValue: function(x, y) {
var column = this.getVisibleColumn(x);
var column = this.getActiveColumn(x);
return column && column.getValue(y);

@@ -734,3 +705,3 @@ },

getUnfilteredValue: function(x, y) {
var column = this.getVisibleColumn(x);
var column = this.getActiveColumn(x);
return column && column.getUnfilteredValue(y);

@@ -748,3 +719,3 @@ },

setValue: function(x, y, value) {
var column = this.getVisibleColumn(x);
var column = this.getActiveColumn(x);
return column && column.setValue(y, value);

@@ -979,5 +950,5 @@ },

*/
onTap: function(grid, event) {
onClick: function(grid, event) {
if (this.featureChain) {
this.featureChain.handleTap(grid, event);
this.featureChain.handleClick(grid, event);
this.setCursor(grid);

@@ -1081,15 +1052,2 @@ }

* @memberOf Behavior.prototype
* @desc delegate handling hold pulse to the feature chain of responsibility
* @param {Hypergrid} grid
* @param {Object} event - the event details
*/
onHoldPulse: function(grid, event) {
if (this.featureChain) {
this.featureChain.handleHoldPulse(grid, event);
this.setCursor(grid);
}
},
/**
* @memberOf Behavior.prototype
* @desc delegate handling double click to the feature chain of responsibility

@@ -1192,20 +1150,2 @@ * @param {Hypergrid} grid

* @memberOf Behavior.prototype
* @return {string} The field at `visibleColumnIndex`.
* @param {number} visibleColumnIndex - the column index of interest
*/
getVisibleColumnName: function(visibleColumnIndex) {
return this.getVisibleColumn(visibleColumnIndex).name;
},
/**
* @memberOf Behavior.prototype
* @return {string} The column heading at `visibleColumnIndex'.
* @param {number} visibleColumnIndex - the column index of interest
*/
getHeader: function(visibleColumnIndex) {
return this.getVisibleColumn(visibleColumnIndex).header;
},
/**
* @memberOf Behavior.prototype
* @desc Rebuild the column order indexes

@@ -1233,9 +1173,10 @@ * @param {Array} columnIndexes - list of column indexes

var labels = [];
var columnCount = this.getColumnCount();
var columnCount = this.getActiveColumnCount();
for (var i = 0; i < columnCount; i++) {
if (indexes.indexOf(i) === -1) {
var column = this.getActiveColumn(i);
labels.push({
id: i,
header: this.getHeader(i),
field: this.getVisibleColumnName(i)
header: column.header,
field: column.name
});

@@ -1381,5 +1322,8 @@ }

*/
getColumnCount: function() {
getActiveColumnCount: function() {
return this.columns.length;
},
getColumnCount: function() {
this.deprecated('getColumnCount()', 'getActiveColumnCount()', '1.0.6', arguments);
},

@@ -1431,11 +1375,21 @@ /**

* @memberOf Behavior.prototype
* @return {cellEditor} The cell editor for the cell at cell coordinates `x,y`
* @param {number} x - The horizontal cell coordinate.
* @param {number} y - The vertical cell coordinate.
* @param {boolean} isDblClick - When called from `onEditorActivate`, indicates if event was a double-click. This allows different editors for single- vs. double-click
* @return {cellEditor} The cell editor for the cell at the given coordinates.
* @param {Point} editPoint - The grid cell coordinates.
*/
getCellEditorAt: function(x, y) {
return this.grid.isFilterRow(y)
? this.grid.createCellEditor('filterbox')
: this.getVisibleColumn(x).getCellEditorAt(y);
getCellEditorAt: function(editPoint) {
var cellEditor, options,
column = this.getActiveColumn(editPoint.x);
if (column) {
options = {
column: column,
editPoint: editPoint
};
cellEditor = this.grid.isFilterRow(editPoint.y)
? this.grid.cellEditors.create('filterbox', options)
: column.getCellEditorAt(editPoint.y, options);
}
return cellEditor;
},

@@ -1449,3 +1403,3 @@

toggleSort: function(x, keys) {
this.getVisibleColumn(x).toggleSort(keys);
this.getActiveColumn(x).toggleSort(keys);
},

@@ -1545,3 +1499,3 @@

convertViewPointToDataPoint: function(viewPoint) {
var newX = this.getVisibleColumn(viewPoint.x).index;
var newX = this.getActiveColumn(viewPoint.x).index;
var newPoint = this.grid.newPoint(newX, viewPoint.y);

@@ -1570,2 +1524,7 @@ return newPoint;

setRelation: function(options) {
this.dataModel.setRelation(options);
this.shapeChanged();
},
getRowContextFunction: function(selectedRows) {

@@ -1608,13 +1567,9 @@ return function() {

getNewFilter: function() {
var newFilter;
if (this.columns.length) {
var options = {
schema: typeof this.schema === 'function' ? this.schema(this.columns) : this.schema,
caseSensitiveColumnNames: this.grid.resolveProperty('filterCaseSensitiveColumnNames'),
resolveAliases: this.grid.resolveProperty('filterResolveAliases'),
defaultColumnFilterOperator: this.grid.resolveProperty('filterDefaultColumnFilterOperator')
};
newFilter = new DefaultFilter(options);
newFilter.loadColumnPropertiesFromSchema(this.columns);
}
var newFilter = new DefaultFilter({
schema: typeof this.schema === 'function' ? this.schema(this.columns) : this.schema,
caseSensitiveColumnNames: this.grid.resolveProperty('filterCaseSensitiveColumnNames'),
resolveAliases: this.grid.resolveProperty('filterResolveAliases'),
defaultColumnFilterOperator: this.grid.resolveProperty('filterDefaultColumnFilterOperator')
});
newFilter.loadColumnPropertiesFromSchema(this.columns);
return newFilter;

@@ -1621,0 +1576,0 @@ },

@@ -6,4 +6,2 @@ /* eslint-env browser */

var _ = require('object-iterators');
var localization = require('../lib/localization');
var deprecated = require('../lib/deprecated');

@@ -77,2 +75,3 @@ var propertyNames = [

set: function(options) {
var fields = this.dataModel.getFields();
var column = this;

@@ -83,18 +82,26 @@ propertyNames.forEach(function(option) {

}
if (option === 'name') {
if (column.name === undefined) {
column.name = fields[column.index];
} else if (column.index === undefined) {
column.index = fields.indexOf(column.name);
}
if (column.index === undefined || column.name === undefined) {
throw 'Expected column name or index.';
} else if (fields[column.index] !== column.name) {
throw 'Expected to find `column.name` in position `column.index` in data model\'s fields list.';
}
}
});
},
var fields = this.dataModel.getFields();
if (column.name === undefined) {
column.name = fields[column.index];
} else if (column.index === undefined) {
column.index = fields.indexOf(column.name);
}
set header(value) {
this._header = value;
this.dataModel.getHeaders()[this.index] = value;
},
if (column.index === undefined) {
throw 'column.index not defined';
} else if (column.name === undefined) {
throw 'column.name not defined';
} else if (fields[column.index] !== column.name) {
throw 'Expected to find `column.name` in position `column.index` in data model\'s fields list.';
}
get header() {
return this._header;
},

@@ -124,7 +131,17 @@

getCellRenderer: function(config, y) {
return this.dataModel.getCellRenderer(config, this.index, y);
config.x = this.index;
config.y = y;
var declaredRendererName =
this.getCellProperties(y).renderer ||
this.getProperties().renderer;
var renderer = this.dataModel.getCell(config, declaredRendererName);
renderer.config = config;
return renderer;
},
getCellProperties: function(y) {
return this.cellProperties[y];
y = this.dataModel.getDataIndex(y);
return this.cellProperties[y] || {};
},

@@ -197,3 +214,3 @@

typeOf: function(something) {
if (something === null || something === undefined) {
if (something == null) {
return null;

@@ -230,20 +247,36 @@ }

getCellEditorAt: function(y) {
return this.dataModel.getCellEditorAt(this.index, y);
},
/** @deprecated Use `.header` property instead.
/**
* This method determines the proposed cell editor name from the render properties. The algorithm is:
* 1. `editor` render property (cell editor name)
* 2. `format` render property (localizer name)
* 3. `type` column property (type name)
*
* Note that "render property" means in each case the first defined property found on the cell, column, or grid.
*
* @param {number} y - The original untranslated row index.
* @param {object} options - Will be decorated with `format` and `column`.
* @param {Point} options.editPoint
* @returns {undefined|CellEditor} Falsy value means either no declared cell editor _or_ instantiation aborted by falsy return return from fireRequestCellEdit.
*/
getHeader: function() {
return deprecated.call(this, 'header', { since: '1.0' });
},
getCellEditorAt: function(y, options) {
var cellEditor,
cellProps = this.getCellProperties(y),
columnProps = this.getProperties(),
editorName = cellProps.editor || columnProps.editor;
/** @deprecated Use `.name` property instead.
*/
getField: function() {
return deprecated.call(this, 'name', { since: '1.0', getterName: 'getField' });
options.format = cellProps.format || columnProps.format;
cellEditor = this.dataModel.getCellEditorAt(this.index, y, editorName, options);
if (cellEditor && !cellEditor.grid) {
// cell editor returned but not fully instantiated (aborted by falsy return from fireRequestCellEdit)
cellEditor = undefined;
}
return cellEditor;
},
getFormatter: function() {
return localization.get(this.getProperties().format).localize;
var localizerName = this.getProperties().format;
return this.behavior.grid.localization.get(localizerName).format;
}

@@ -250,0 +283,0 @@ };

@@ -5,2 +5,3 @@ 'use strict';

var DataModelJSON = require('../dataModels/JSON');
var ColumnSchemaFactory = require('../filter/ColumnSchemaFactory');
var features = require('../features');

@@ -29,3 +30,3 @@ var aggregations = require('../Shared.js').analytics.util.aggregations;

initialize: function(grid, schema, dataRows) {
this.setData(dataRows);
this.setData(dataRows, schema);
},

@@ -56,2 +57,3 @@

var fields = dataModel.getFields();
var REGEX_CAMEL_CASE = /([^_A-Z])([A-Z]+)/g;
this.clearColumns();

@@ -61,2 +63,3 @@ for (var index = 0; index < columnCount; index++) {

var column = this.addColumn({ index: index, header: header });
this.columnEnum[column.name.replace(REGEX_CAMEL_CASE, '$1_$2').toUpperCase()] = index;
var properties = column.getProperties();

@@ -103,18 +106,25 @@ properties.field = fields[index];

*/
setData: function(dataRows) {
this.dataModel.setData(dataRows);
setData: function(dataRows, options) {
var self = this,
grid = this.grid;
this.dataModel.setData(dataRows, options);
this.createColumns();
this.schema = options && options.schema || deriveSchema;
this.setGlobalFilter(this.getNewFilter());
var self = this;
if (this.grid.isColumnAutosizing()) {
if (grid.cellEditor) {
grid.cellEditor.cancelEditing();
}
if (grid.isColumnAutosizing()) {
setTimeout(function() {
self.autosizeAllColumns();
}, 100);
self.changed();
grid.allowEvents(dataRows.length);
} else {
setTimeout(function() {
self.getColumn(-1).checkColumnAutosizing(true);
self.changed();
grid.allowEvents(dataRows.length);
});

@@ -126,3 +136,3 @@ }

* @summary Set the top totals.
* @memberOf behaviors.JSON.prototype
* @memberOf behaviors.JSON.p rototype
* @param {Array<Array>} totalRows - array of rows (arrays) of totals

@@ -239,4 +249,8 @@ */

},
getActiveColumns: function() {
return this.dataModel.getActiveColumns();
},
getVisibleColumns: function() {
return this.dataModel.getVisibleColumns();
this.deprecated('getVisibleColumns()', 'getActiveColumns()', '1.0.6', arguments);
},

@@ -277,2 +291,8 @@

function deriveSchema() {
return new ColumnSchemaFactory(this.columns).schema;
}
//Logic to moved to adapter layer outside of Hypergrid Core

@@ -279,0 +299,0 @@ function removeHiddenColumns(oldSorted, hiddenColumns){

@@ -17,3 +17,3 @@ 'use strict';

setScrollPositionX: noop,
getColumnCount: n00p,
getActiveColumnCount: n00p,
getFixedColumnCount: n00p,

@@ -20,0 +20,0 @@ getFixedColumnsWidth: n00p,

@@ -6,8 +6,8 @@ /* eslint-env browser */

var mustache = require('mustache');
var _ = require('object-iterators');
var Base = require('../lib/Base');
var localization = require('../lib/localization');
var effects = require('../lib/effects');
var Localization = require('../lib/Localization');
var extract = /\/\*\s*([^]+?)\s+\*\//; // finds the string inside the /* ... */; the (group) excludes the whitespace
/**

@@ -18,4 +18,22 @@ * @constructor

initialize: function(grid, localizer) {
/**
* @param grid
* @param {string} options - Properties listed below + arbitrary mustache "variables" for merging into template.
* @param {Point} options.editPoint
* @param {string} [options.format] - Name of a localizer with which to override prototype's `localizer` property.
*/
initialize: function(grid, options) {
// Establish `this.editPoint` and possibly `this.format`; plus other arbitrary properties for mustache use.
for (var key in options) {
if (options.hasOwnProperty(key) && this[key] !== null) {
this[key] = options[key];
}
}
var value = grid.behavior.getValue(this.editPoint.x, this.editPoint.y);
if (value instanceof Array) {
value = value[1]; //it's a nested object
}
/**

@@ -28,23 +46,15 @@ * my instance of hypergrid

if (localizer) {
this.localizer = localizer;
}
this.grid.cellEditor = this;
this.editorPoint = {
x: 0,
y: 0
};
this.locale = grid.localization.locale; // for template's `lang` attribute
this.reset();
// override native localizer with localizer named in format if defined (from instantiation options)
if (this.format) {
this.localizer = this.grid.localization.get(this.format);
}
var self = this;
this.el.addEventListener('keyup', this.keyup.bind(this));
this.el.addEventListener('keydown', function(e) { grid.fireSyntheticEditorKeyDownEvent(self, e); });
this.el.addEventListener('keypress', function(e) { grid.fireSyntheticEditorKeyPressEvent(self, e); });
this.el.onblur = function(e) { self.cancelEditing(); };
},
this.initialValue = value;
reset: function() {
var container = document.createElement('DIV');
container.innerHTML = this.getHTML();
container.innerHTML = mustache.render(this.template, this);

@@ -65,4 +75,20 @@ /**

this.input = this.el;
this.errors = 0;
var self = this;
this.el.addEventListener('keyup', this.keyup.bind(this));
this.el.addEventListener('keydown', function(e) {
grid.fireSyntheticEditorKeyDownEvent(self, e);
});
this.el.addEventListener('keypress', function(e) {
grid.fireSyntheticEditorKeyPressEvent(self, e);
});
this.el.onblur = function(e) {
self.cancelEditing();
};
},
localizer: Localization.prototype.null,
specialKeyups: {

@@ -81,5 +107,6 @@ //0x08: 'clearStopEditing', // backspace

e.preventDefault();
this[specialKeyup]();
this.grid.repaint();
this.grid.takeFocus();
if (this[specialKeyup](3)) {
this.grid.repaint();
this.grid.takeFocus();
}
}

@@ -91,16 +118,3 @@

localizer: localization.get(null),
/**
* the point that I am editing at right now
* @type {Point}
* @default null
* @memberOf CellEditor.prototype
*/
editorPoint: {
x: -1,
y: -1
},
/**
* if true, check that the editor is in the right location

@@ -113,10 +127,2 @@ * @type {boolean}

/** @deprecated Use `.grid.behavior` property instead.
* @memberOf CellEditor.prototype
* @returns {Behavior} The behavior (model).
*/
getBehavior: function() {
return this.deprecated('grid.behavior', { since: '0.2' });
},
/**

@@ -135,10 +141,2 @@ * @memberOf CellEditor.prototype

scrollValueChangedNotification: function() {
this.setCheckEditorPositionFlag();
},
/**
* @desc turn on checkEditorPositionFlag boolean field
* @memberOf CellEditor.prototype
*/
setCheckEditorPositionFlag: function() {
this.checkEditorPositionFlag = true;

@@ -152,4 +150,3 @@ },

moveEditor: function() {
var editorPoint = this.getEditorPoint();
var cellBounds = this.grid._getBoundsOfCell(editorPoint.x, editorPoint.y);
var cellBounds = this.grid._getBoundsOfCell(this.editPoint.x, this.editPoint.y);

@@ -166,34 +163,24 @@ //hack to accommodate bootstrap margin issues...

/**
* @desc begin editing at location point
* @param {Point} point - the location to start editing at
* @memberOf CellEditor.prototype
*/
beginEditAt: function(point) {
if (!this.isAdded) {
this.isAdded = true;
this.attachEditor();
}
this.setEditorPoint(point);
var value = this.grid.behavior.getValue(point.x, point.y);
if (value instanceof Array) {
value = value[1]; //it's a nested object
}
if (this.grid.fireRequestCellEdit(point, value)) {
this.initialValue = value;
this.setCheckEditorPositionFlag();
beginEditing: function() {
if (this.grid.fireRequestCellEdit(this.editPoint, this.initialValue)) {
this.checkEditorPositionFlag = true;
this.checkEditor();
}
},
beginEditAt: function(Constructor, name) {
this.deprecated('beginEditAt(point)', 'beginEditing()', '1.0.6');
},
/**
* @desc put value into our editor
* @param {object} value - whatever value we want to edit
* @summary Put the value into our editor.
* @desc Formats the value and displays it.
* The localizer's {@link localizerInterface#format|format} method will be called.
*
* Override this method if your editor has additional or alternative GUI elements.
*
* @param {object} value - The raw unformatted value from the data source that we want to edit.
* @memberOf CellEditor.prototype
*/
setEditorValue: function(value) {
this.input.value = this.localizer.localize(value);
this.input.value = this.localizer.format(value);
},

@@ -203,21 +190,2 @@

* @memberOf CellEditor.prototype
* @desc returns the point at which we are currently editing
* @returns {Point}
*/
getEditorPoint: function() {
return this.editorPoint;
},
/**
* @memberOf CellEditor.prototype
* @desc set the current editor location
* @param {Point} point - the data location of the current editor
*/
setEditorPoint: function(point) {
this.editorPoint = point;
this.modelPoint = this.grid.convertViewPointToDataPoint(point);
},
/**
* @memberOf CellEditor.prototype
* @desc display the editor

@@ -237,16 +205,61 @@ */

/**
/** @summary Stops editing.
* @desc Before saving, validates the edited value in two phases as follows:
* 1. Call `validateEditorValue`. (Calls the localizer's `invalid()` function, if available.)
* 2. Catch any errors thrown by the {@link CellEditor#getEditorValue|getEditorValue} method.
*
* **If the edited value passes both phases of the validation:**
* Saves the edited value by calling the {@link CellEditor#saveEditorValue|saveEditorValue} method.
*
* **On validation failure:**
* 1. If `feedback` was omitted, cancels editing, discarding the edited value.
* 2. If `feedback` was provided, gives the user some feedback (see `feedback`, below).
*
* @param {number} [feedback] What to do on validation failure:
* * If omitted, simply cancels editing without saving edited value.
* * If 0, shows the error feedback effect (see the {@link CellEditor#errorEffect|errorEffect} property).
* * If > 0, shows the error feedback effect _and_ calls the {@link CellEditor#errorEffectEnd|errorEffectEnd} method) every `feedback` call(s) to `stopEditing`.
* @returns {boolean} Truthy means successful stop. Falsy means syntax error prevented stop. Note that editing is canceled when no feedback requested and successful stop includes (successful) cancel.
* @memberOf CellEditor.prototype
* @desc stop editing
*/
stopEditing: function() {
var value = this.getEditorValue();
if (this.grid.fireSyntheticEditorDataChangeEvent(this, this.initialValue, value)) {
this.saveEditorValue(value);
stopEditing: function(feedback) {
/**
* @type {boolean|string|Error}
*/
var error = this.validateEditorValue();
if (!error) {
try {
var value = this.getEditorValue();
} catch (err) {
error = err;
}
}
if (!error && this.grid.fireSyntheticEditorDataChangeEvent(this, this.initialValue, value)) {
try {
this.saveEditorValue(value);
} catch (err) {
error = err;
}
}
if (!error) {
this.hideEditor();
this.grid.cellEditor = null;
this.el.remove();
} else if (feedback >= 0) { // never true when `feedback` undefined
var point = this.editPoint;
this.grid.selectViewportCell(point.x, point.y - this.grid.getHeaderRowCount());
this.errorEffectBegin(++this.errors % feedback === 0 && error);
} else { // invalid but no feedback
return this.cancelEditing();
}
return !error;
},
/** @summary Cancels editing.
* @returns {boolean} Successful. (Cancel is always successful.)
*/
cancelEditing: function() {

@@ -259,5 +272,87 @@ if (this.grid.cellEditor) { // because stopEditing's .remove triggers blur which comes here

}
return true;
},
/**
* Calls the effect function indicated in the {@link CellEditor#errorEffect|errorEffect} property which triggers a series of CSS transitions.
* @param {boolean|string|Error} [error] - If defined, call the {@link CellEditor#errorEffectEnd|errorEffectEnd} method at the end of the last effect transition with this error.
* @memberOf CellEditor.prototype
*/
errorEffectBegin: function(error) {
var options = { callback: error && this.errorEffectEnd.bind(this, error) },
effect = this.errorEffect;
if (typeof effect === 'string') {
effect = this.errorEffects[effect];
}
if (typeof effect === 'object') {
_(options).extendOwn(effect.options);
effect = effect.effector;
}
if (typeof effect === 'function') {
effect.call(this, options);
} else {
throw 'Expected `this.errorEffect` to resolve to an error effect function.';
}
},
/**
* This function expects to be passed an error. There is no point in calling this function if there is no error. Nevertheless, if called with a falsy `error`, returns without doing anything.
* @this {CellEditor}
* @param {boolean|string|Error} [error]
*/
errorEffectEnd: function(error) {
if (error) {
var msg =
'Invalid value. To resolve, do one of the following:\n\n' +
' * Correct the error and try again.\n' +
' - or -\n' +
' * Cancel editing by pressing the "esc" (escape) key.';
error = error.message || error;
if (typeof error !== 'string') {
error = '';
}
if (this.localizer.expectation) {
error = error ? error + '\n' + this.localizer.expectation : this.localizer.expectation;
}
if (error) {
error = '\n' + error;
error = error.replace(/[\n\r]+/g, '\n\n * ');
msg += '\n\nAdditional information about this error:' + error;
}
alert(msg); // eslint-disable-line no-alert
}
},
/** @typedef effectObject
* @property {effectFunction} effector
* @property {object} [options] - An options object with which to call the function.
*/
/**
* May be one of:
* * **string** - Name of registered error effect.
* * **effectFunction** - Reference to an effect function.
* * **effectObject** - Reference to an effectObject containing an {@link effectFunction} and an `options` object with which to call the function.
* @type {string|effectFunction|effectObject}
* @memberOf CellEditor.prototype
*/
errorEffect: 'shaker',
/**
* Hash of registered {@link effectFunction}s or {@link effectObject}s.
* @memberOf CellEditor.prototype
*/
errorEffects: {
shaker: effects.shaker,
glower: effects.glower
},
/**
* @desc save the new value into the behavior (model)

@@ -267,3 +362,3 @@ * @memberOf CellEditor.prototype

saveEditorValue: function(value) {
var point = this.getEditorPoint();
var point = this.editPoint;

@@ -280,3 +375,8 @@ if (

/**
* @desc return the current editor's value
* @summary Extract the edited value from the editor.
* @desc De-format the edited string back into a primitive value.
*
* The localizer's {@link localizerInterface#parse|parse} method will be called on the text box contents.
*
* Override this method if your editor has additional or alternative GUI elements. The GUI elements will influence the primitive value, either by altering the edited string before it is parsed, or by transforming the parsed value before returning it.
* @returns {object} the current editor's value

@@ -286,6 +386,14 @@ * @memberOf CellEditor.prototype

getEditorValue: function() {
return this.localizer.standardize(this.input.value);
return this.localizer.parse(this.input.value);
},
/**
* If there is no validator on the localizer, returns falsy (not invalid; possibly valid).
* @returns {boolean|string} Truthy value means invalid. If a string, this will be an error message. If not a string, it merely indicates a generic invalid result.
*/
validateEditorValue: function() {
return this.localizer.invalid && this.localizer.invalid(this.input.value);
},
/**
* @summary Request focus for my input control.

@@ -296,14 +404,13 @@ * @desc See GRID-95 "Scrollbar moves inward" for issue and work-around explanation.

takeFocus: function() {
var self = this;
setTimeout(function() {
var input = self.el,
transformWas = input.style.transform;
var el = this.el,
leftWas = el.style.left,
topWas = el.style.top;
input.style.transform = 'translate(0,0)'; // work-around: move to upper left
el.style.left = el.style.top = 0; // work-around: move to upper left
self.input.focus();
self.selectAll();
this.input.focus();
this.selectAll();
input.style.transform = transformWas;
});
el.style.left = leftWas;
el.style.top = topWas;
},

@@ -325,7 +432,5 @@

input.style.transform = translate(
cellBounds.x - 1,
cellBounds.y - 1
);
input.style.position = 'absolute';
input.style.left = px(cellBounds.x - 1);
input.style.top = px(cellBounds.y - 1);
input.style.width = px(cellBounds.width + 2);

@@ -342,9 +447,8 @@ input.style.height = px(cellBounds.height + 2);

this.checkEditorPositionFlag = false;
var editorPoint = this.getEditorPoint();
if (this.grid.isDataVisible(editorPoint.x, editorPoint.y)) {
if (this.grid.isDataVisible(this.editPoint.x, this.editPoint.y)) {
this.setEditorValue(this.initialValue);
this.attachEditor();
this.moveEditor();
this.showEditor();
this.takeFocus();
this.showEditor();
} else {

@@ -364,14 +468,4 @@ this.hideEditor();

/** @deprecated Use `.grid` property instead. */
getGrid: function() {
return this.deprecated('grid', { since: '0.2' });
},
template: ''
template: function() {/**/},
getHTML: function() {
var template = this.template.toString().match(extract)[1];
return mustache.render(template, this);
},
});

@@ -381,3 +475,2 @@

function px(n) { return n + 'px'; }
function translate(x, y) { return 'translate(' + px(x) + ',' + px(y) + ')'; }

@@ -384,0 +477,0 @@

@@ -6,2 +6,4 @@ 'use strict';

/**
* As of spring 2016:
* Functions well in Chrome and Firefox; unimplemented in Safari.
* @constructor

@@ -11,7 +13,3 @@ */

template: function() {
/*
<input type="color">
*/
}
template: '<input type="color" lang="{{locale}}" style="{{style}}">'

@@ -18,0 +16,0 @@ });

@@ -27,2 +27,4 @@ // ComboBox.js - A combo-box is a combination of a text-box and a drop-down.

* A combo box is a text box that also has a drop-down containing options. The drop-down consists of an actual drop-down list (a `<select>` list) plus a _control area_ above it containing toggles. The toggles control the visibility of the various "mode lists."
*
* Functions well in Chrome, Safari, Firefox, and Internet Explorer.
* @constructor

@@ -46,2 +48,4 @@ */

this.menuModesSource = this.column.menuModes || { distinctValues: true };
// wire-ups

@@ -54,21 +58,13 @@ this.dropper.addEventListener('mousedown', this.toggleDropDown.bind(this));

template: function() {
/*
<div class="hypergrid-input" title="">
<input>
<span title="Click for options"></span>
<div>
<div></div>
<select size="12"></select>
</div>
</div>
*/
},
template: [
'<div class="hypergrid-input" title="">',
' <input type="text" lang="{{locale}}" style="{{style}}">',
' <span title="Click for options"></span>',
' <div>',
' <div></div>',
' <select size="12" lang="{{locale}}"></select>',
' </div>',
'</div>'
].join('\n'),
beginEditAt: function(point) {
this.column = this.grid.behavior.columns[point.x];
this.menuModesSource = this.column.menuModes || { distinctValues: true };
prototype.beginEditAt.call(this, point);
},
modes: [

@@ -75,0 +71,0 @@ {

@@ -6,3 +6,2 @@ /* eslint-env browser */

var CellEditor = require('./CellEditor');
var localization = require('../lib/localization');

@@ -21,3 +20,9 @@ var isChromium = window.chrome,

/**
/**
* As of spring 2016:
* Functions well in Chrome except no localization (day, month names; date format).
* Unimplemented in Safari, Firefox, Internet Explorer.
* This is a "snmart" control. It detects Chrome:
* * If Chrome, uses chromeDate overrides format to that required by the value attribute, yyyy-mm-dd. (Note that this is not the format displayed in the control, which is always mm/dd/yyyy.)
* * Otherwise uses localized date format _but_ falls back to a regular text box.
* @constructor

@@ -27,12 +32,13 @@ */

initialize: function(grid, localizer) {
initialize: function(grid) {
var usesDateInputControl = isChrome;
var localizerName,
usesDateInputControl = isChrome;
if (!usesDateInputControl) {
this.template = {
/*
<input type="text">
*/
};
if (usesDateInputControl) {
localizerName = 'chromeDate';
this.template = '<input type="date">';
} else {
localizerName = 'date';
this.template = '<input type="text">';

@@ -43,14 +49,6 @@ this.selectAll = function() {

};
this.localizer = localization.get('date');
}
},
template: function() {
/*
<input id="editor" type="date">
*/
},
localizer: localization.get('chromeDate')
this.localizer = grid.localization.get(localizerName);
}
});

@@ -57,0 +55,0 @@

@@ -6,3 +6,3 @@ /* eslint-env browser */

var popMenu = require('pop-menu');
var Conditionals = require('filter-tree').Conditionals;
var Conditionals = require('../Shared').FilterTree.Conditionals;

@@ -29,39 +29,42 @@ var ComboBox = require('./ComboBox');

beginEditAt: function(point) {
initialize: function() {
// look in the filter, under column filters, for a column filter for this column
var filter = this.grid.getGlobalFilter(),
column = this.column = this.grid.behavior.columns[point.x],
columnName = column.name,
var root = this.grid.getGlobalFilter(),
columnName = this.column.name,
columnFilters = this.grid.getGlobalFilter().columnFilters,
columnFilterSubtree = filter.getColumnFilter(columnName),
columnSchema = filter.schema.lookup(columnName);
columnFilterSubtree = root.getColumnFilter(columnName) || {},
columnSchema = root.schema.lookup(columnName) || {};
this.opMenu = // get the operator list from the node, schema, typeOpMap, or root:
// get the operator list from the node, schema, typeOpMap, or root:
// (This mimics the code in FilterLeaf.js's `getOpMenu` function becauase the node may not exist yet.)
this.opMenu =
columnFilterSubtree && columnFilterSubtree.opMenu || // first try column filter node's `operator` list, if any
// pull operator list from column schema if available
columnSchema.opMenu ||
columnSchema && ( // ELSE as column filter may not yet exist, try it's schema for `opMenu` or `type`
columnSchema.opMenu || // pull operator list from column schema if it has one; IF it doesn't...
columnSchema.type && // BUT it has a type...
filter.typeOpMap && // AND the filter has a defined type-operator map...
filter.typeOpMap[columnSchema.type] // THEN use the operator list for the column's type if there is one
) ||
// operator list for the column's type if available
root.typeOpMap && root.typeOpMap[columnSchema.type || columnFilterSubtree.type] ||
filter.opMenu; // ELSE try the default operator list (which itself defaults to `Conditionals.defaultOpMenu`)
// default operator list (which itself defaults to `Conditionals.defaultOpMenu`)
root.opMenu;
this.menuModesSource = // get the column filter's `menuModes` object -- contains the states of the drop-down option icons:
// get the column filter's `menuModes` object -- contains the states of the drop-down option icons:
this.menuModesSource =
column.menuModes || // first try proxy from last time (because editing may have ended without a column filter to put in the filter tree)
// first try proxy from last time (because editing may have ended without a column filter to put in the filter tree)
this.column.menuModes ||
columnFilterSubtree && columnFilterSubtree.menuModes || // ELSE try column filter's `menuModes` WHEN available
// ELSE try column filter's `menuModes` WHEN available
columnFilterSubtree.menuModes ||
columnFilterSubtree.menuModes ||
columnSchema && columnSchema.menuModes || // try use column schema's `menuModes` when defined
// try use column schema's `menuModes` when defined
columnSchema.menuModes ||
columnFilters.menuModes; // ELSE try the filter default (which itself defaults to operators ON, others OFF; see definition at top of DefaultFilter.js)
// ELSE try the filter default (which itself defaults to operators ON, others OFF; see definition at top of DefaultFilter.js)
columnFilters.menuModes;
prototype.beginEditAt.call(this, point);
},

@@ -102,3 +105,3 @@

var columns = this.grid.behavior.columns,
x = this.editorPoint.x;
x = this.editPoint.x;

@@ -113,3 +116,3 @@ while (optgroup.firstElementChild) {

option = new Option(name);
option.title = '[' + name + ']\r"' + column.getHeader() + '"';
option.title = '[' + name + ']\r"' + column.header + '"';
optgroup.appendChild(option);

@@ -116,0 +119,0 @@ }

@@ -7,115 +7,111 @@ /**

var localization = require('../lib/localization');
/**
* @summary Hash of cell editor object constructors.
* @desc This hash's only purpose is to support the convenience methods defined herein: {@link cellEditors.extend|extend}, {@link cellEditors.register|register}, and {@link cellEditors.instantiate|instantiate}. If you do not need these methods' functionality, you do not need to register your cell editors.
* @type {object}
*/
var constructors = {};
/**
* @summary Register a cell editor (class) or a synonym of an already-registered cell editor.
* @desc Adds a custom cell editor to the `constructors` hash using the provided name (or the class name), converted to all lower case.
*
* To register a syonym for an already-registered cell editor, use the following construct:
* ```
* var cellEditors = require('./cellEditors');
* cellEditors.register(cellEditors.get('spinner'), 'elevator');
* ```
* This makes a synonym "elevator" for the "spinner" cell editor.
*
* > All native cell editors are "preregistered" in cellEditors/index.js.
*
* @param {YourCellEditor.prototype.constructor} Constructor - A constructor, typically extended from `CellEditor` (or a descendant therefrom).
*
* @param {string} [editorName] - Case-insensitive editor key. If not given, `YourCellEditor.prototype.$$CLASS_NAME` is used.
*
* > Note: `$$CLASS_NAME` can be easily set up by providing a string as the (optional) first parameter in your {@link https://www.npmjs.com/package/extend-me|CellEditor.extend} call. (Formal parameter name: `alias`.)
*
* @memberOf module:cellEditors
* @param {Hypergrid} grid
* @param {boolean} [privateRegistry=false] - This instance will use a private registry.
* @constructor
*/
function register(Constructor, editorName) {
editorName = editorName || Constructor.prototype.$$CLASS_NAME;
editorName = editorName && editorName.toLowerCase();
constructors[editorName] = Constructor;
return Constructor;
}
function CellEditors(grid, privateRegistry) {
this.grid = grid;
if (privateRegistry) {
this.editors = {};
}
/**
* @param {string} editorName
* @returns {*}
*/
function get(editorName) {
return constructors[editorName && editorName.toLowerCase()];
// preregister the standard cell editors
if (privateRegistry || !this.get('celleditor')) {
this.add(require('./CellEditor'));
this.add(require('./ComboBox'));
this.add(require('./Color'));
this.add(require('./Date'));
this.add(require('./FilterBox'));
this.add(require('./Number'));
this.add(require('./Slider'));
this.add(require('./Spinner'));
this.add(require('./Textfield'));
}
}
CellEditors.prototype = {
constructor: CellEditors.prototype.constructor, // preserve constructor
/**
* Must be called with YOUR Hypergrid object as context!
* @returns {CellEditor} New instance of the named cell editor.
* @param {string} editorName
* @this {Hypergrid}
* @memberOf module:cellEditors
*/
function instantiate(editorName) {
var CellEditorConstructor = get(editorName);
return CellEditorConstructor && new CellEditorConstructor(this);
}
/**
* @summary Register a cell editor constructor.
* @desc Adds a custom cell editor constructor to the `editors` hash using the provided name (or the class name), converted to all lower case.
*
* > All native cell editors are "preregistered" in `editors`..
*
* @param {string} [name] - Case-insensitive editor key. If not given, `YourCellEditor.prototype.$$CLASS_NAME` is used.
*
* @param {YourCellEditor.prototype.constructor} Constructor - A constructor, typically extended from `CellEditor` (or a descendant therefrom).
*
* > Note: `$$CLASS_NAME` can be easily set up by providing a string as the (optional) first parameter (`alias`) in your {@link https://www.npmjs.com/package/extend-me|CellEditor.extend} call.
*
* @returns {CellEditor} A newly registered constructor extended from {@link CellEditor}.
*
* @memberOf module:cellEditors
*/
add: function(name, Constructor) {
if (typeof name === 'function') {
Constructor = name;
name = undefined;
}
name = name || Constructor.prototype.$$CLASS_NAME;
name = name && name.toLowerCase();
this.editors[name] = Constructor;
return Constructor;
},
/**
* @summary Create a new localized cell editor class.
*
* @desc Extend the provided cell editor ('baseClassName') using the named localizer (`localizerName`), naming it after the localizer unless otherwise specified (in `newClassName`)
*
* @param {string} localizerName
*
* @param {string} [baseClassName='textfield'] - The base class must have been previously registered.
*
* @param {string} [newClassName=localizerName] - Provide a value here to name the cell editor differently from its localizer.
*
* @returns {function} The new cell editor constructor.
*
* @memberOf module:cellEditors
*/
function extend(localizerName, baseClassName, newClassName) {
baseClassName = baseClassName || 'textfield';
newClassName = newClassName || localizerName;
/**
* @summary Register a synonym for an existing cell editor constructor.
* @param {string} synonymName
* @param {string} existingName
* @returns {CellEditor} The previously registered constructor this new synonym points to.
* @memberOf CellEditors.prototype
*/
addSynonym: function(synonymName, existingName) {
var cellEditor = this.get(existingName);
return (this.editors[synonymName] = cellEditor);
},
return constructors[baseClassName].extend(newClassName, {
localizer: localization.get(localizerName)
});
}
/**
* @param {string} name - Name of a registered editor.
* @returns {CellEditor} A registered constructor extended from {@link CellEditor}.
* @memberOf CellEditors.prototype
*/
get: function(name) {
return this.editors[name && name.toLowerCase()];
},
/**
* @summary Lookup registered cell editor and return a new instance thereof.
* @desc Note: Must be called with the Hypergrid object as context!
* @returns {CellEditor} New instance of the named cell editor.
* @param {string} name - Name of a registered editor.
* @param {string} [options] - Properties to add to the instantiated editor primarily for mustache's use.
* @memberOf CellEditors.prototype
*/
create: function(name, options) {
var cellEditor,
Constructor = this.get(name);
// register standard cell editors
register(require('./CellEditor'));
register(require('./ComboBox'));
//register(require('./Combo'));
register(require('./Color'));
register(require('./Date'));
register(require('./FilterBox'));
register(require('./Number'));
register(require('./Slider'));
register(require('./Spinner'));
register(require('./Textfield'));
if (Constructor) {
if (Constructor.abstract) {
throw 'Attempt to instantiate an "abstract" cell editor class.';
}
cellEditor = new Constructor(this.grid, options);
}
return cellEditor;
},
// Register synonyms for standard type names.
// It is unnecessary to set up synonyms for 'date' and 'number' because there are already suitable cell editor resitrations matching those names.
register(constructors.number, 'int');
register(constructors.number, 'float');
register(constructors.textfield, 'string');
/**
* The cell editor registry containing all the "preregistered" cell editor constructors.
* @private
* @memberOf CellEditors.prototype
*/
editors: {}
};
module.exports = {
constructors: constructors,
register: register,
get: get,
instantiate: instantiate,
extend: extend
};
module.exports = CellEditors;
'use strict';
var Textfield = require('./Textfield');
var localization = require('../lib/localization');
/**
* Functions well in Chrome, Safari, Firefox, and Internet Explorer.
* @constructor

@@ -11,12 +11,8 @@ */

template: function() {
/*
<input type="text">
*/
},
initialize: function(grid) {
this.localizer = grid.localization.get('number');
}
localizer: localization.get('number')
});
module.exports = Number;

@@ -10,7 +10,3 @@ 'use strict';

template: function() {
/*
<input type="range">
*/
}
template: '<input type="range" lang="{{locale}}" style="{{style}}">'

@@ -17,0 +13,0 @@ });

@@ -10,7 +10,3 @@ 'use strict';

template: function() {
/*
<input type="number">
*/
}
template: '<input type="number" lang="{{locale}}" style="{{style}}">'

@@ -17,0 +13,0 @@ });

'use strict';
var CellEditor = require('./CellEditor.js');
var Localization = require('../lib/Localization');
/**
* As of spring 2016:
* Functions well in Chrome, Safari, Firefox, and Internet Explorer.
* @constructor

@@ -10,8 +14,6 @@ */

template: function() {
/*
<input type="text">
*/
},
template: '<input type="text" lang="{{locale}}" style="{{style}}">',
localizer: Localization.prototype.string,
selectAll: function() {

@@ -18,0 +20,0 @@ var lastCharPlusOne = this.getEditorValue().length;

@@ -20,12 +20,2 @@ 'use strict';

/** @deprecated Use `.grid` property instead. */
getGrid: function() {
return this.deprecated('grid', { since: '0.2' });
},
/** @deprecated Use `.grid.behavior` property instead. */
getBehavior: function() {
return this.deprecated('grid.behavior', { since: '0.2' });
},
changed: function() {

@@ -62,30 +52,37 @@ this.grid.behavior.changed();

/**
* This method as written returns the `cellEditor` property (containing the cell editor class name) from the cell properties hash or, failing that, the column properties hash. The name is then used to instantiate a cell editor of that name found in the list of registered cel editors. If neither hash has such a property, or if no such editor is registered, returns `undefined` &mdash; which has the effect of making the cell editor non-editable.
* @param {object} config
* @param {string} declaredRendererName - The proposed cell renderer name (form the render properties).
* @returns {CellRenderer}
* @memberOf DataModel.prototype
*/
getCell: function(config, declaredRendererName) {
return this.grid.cellRenderers.get(declaredRendererName);
},
/**
* @summary Instantiate a new cell editor.
* @desc The application developer may override this method to:
* * Instantiate and return an arbitrary cell editor. The generic implementation here simply returns the declared cell editor. This is `undefined` when there was no such declaration, or if the named cell editor was not registered.
* * Return `undefined` for no cell editor at all. The cell will not be editable.
* * Set properties on the instance by passing them in the `options` object. These are applied to the new cell editor object after instantiation but before rendering.
* * Manipulate the cell editor object (including its DOM elements) after rendering but before DOM insertion.
*
* An easy way of making all cell editors non-editable regardless of the property settings (either temporarily or permanently) is to override this method with a null method (that returns `undefined`).
* Overriding this method with a null function (that always returns `undefined`) will have the effect of making all cells uneditable.
*
* The application developer may also wish to override this method to instantiate and return a `CellEditor` to be determined more precisely at run-time. This selection is usually based on column (`x`) but may in fact vary by row as well. Besides putting off the decision of which cell editor to use, this approach also has the advantage of being able to set attributes on the cell editor after instantiation but before it is rendered.
* @param {number} columnIndex - Absolute column index. I.e., the position of the column in the data source's original `fields` array, as echoed in `behavior.allColumns[]`.
* @param {number} rowIndex - Row index of the data row in the currently filtered and sorted list of rows, regardless of vertical scroll position, offset by the number of header rows (all the rows above the first data row including the filter row). I.e., after subtracting out the number of header rows, this is the position of the data row in the `index` array of the data source (i.e., the last data source pipeline).
* @param {string} declaredEditorName - The proposed cell editor name (from the render properties).
* @param {object} options - Properties to copy to the new cell editor primarily for mustache's use. Additionally, always includes the following:
* @param {string} options.format - The value of the `format` render prop. May be `undefined`.
* @param {object} options.column - For convenience, the column object in `behavior.allColumns[]` to which `columnIndex` refers.
* @param {Point} options.editPoint - The grid coordinates of the cell to edit.
* @param {number} options.editPoint.x - The horizontal model coordinate of the cell to edit. This is the grid coordinate regardless of horizontal scroll position. I.e., the position of the column in the ordered list of selected columns (`behavior.columns[]`). (This is the coordinate required by {@link Hypergrid#editAt|editAt}.)
* @param {number} options.editPoint.y - Same as `rowIndex`.
*
* @param {number} x - Absolute column index.
* @param {number} y - Row index in `dataRows` (raw `dataSource.data`) array.
* @returns {undefined|CellEditor} An object instantiated from the registered cell editor constructor named in `declaredEditorName`. A falsy return means the cell is not editable because the `declaredEditorName` was not registered.
*
* @returns {undefined|CellEditor} An object instantiated from a constructor extended from CellEditor. If return value is `undefined` (or otherwise falsy), the cell will not be editable.
* @memberOf DataModel.prototype
*/
getCellEditorAt: function(x, y) {
var cellProperties,
columnProperties,
column = this.grid.behavior.getColumn(x);
var editorName = (cellProperties = column.getCellProperties(y) || {}).editor ||
(columnProperties = column.getProperties()).editor;
if (!editorName && editorName !== null) { // null means don't fallback to format
editorName = cellProperties.format || columnProperties.format;
}
if (!editorName && editorName !== null) { // null means don't fallback to type
editorName = column.getType();
}
return this.grid.createCellEditor(editorName);
getCellEditorAt: function(columnIndex, rowIndex, declaredEditorName, options) {
return this.grid.cellEditors.create(declaredEditorName, options);
}

@@ -92,0 +89,0 @@

@@ -37,3 +37,11 @@ 'use strict';

return null;
}
},
viewMakesSense: function() {
return false;
},
setAggregates: function() {},
setGroupBys: function() {},
groupBys: [],
};

@@ -48,11 +56,12 @@

//null object pattern for the source object
source: nullDataSource,
resetSources: function() {
this.sources = {
source: nullDataSource,
aggregator: nullDataSource,
globalfilter: nullDataSource,
sortercomposite: nullDataSource
};
this.dataSource = undefined;
},
preglobalfilter: nullDataSource,
presorter: nullDataSource,
analytics: nullDataSource,
postglobalfilter: nullDataSource,
postsorter: nullDataSource,
topTotals: [],

@@ -62,2 +71,3 @@ bottomTotals: [],

initialize: function() {
this.resetSources();
this.selectedData = [];

@@ -75,3 +85,3 @@ },

hasAggregates: function() {
return this.analytics.hasAggregates();
return this.sources.aggregator.hasAggregates();
},

@@ -84,23 +94,15 @@

hasGroups: function() {
return this.analytics.hasGroups();
return this.sources.aggregator.hasGroups();
},
viewMakesSense: function() {
return this.analytics.viewMakesSense();
},
getDataSource: function() {
return this.postsorter; //this.hasAggregates() ? this.analytics : this.presorter;
return this.dataSource;
},
getGlobalFilterDataSource: function() {
return this.postglobalfilter; //this.hasAggregates() ? this.postfilter : this.prefilter;
return this.sources.globalfilter;
},
getSortDataSource: function() {
return this.viewMakesSense() ? this.groupsorter : this.postsorter;
},
getData: function() {
return this.source.data;
return this.sources.source.data;
},

@@ -128,2 +130,3 @@

var value;
if (hasHierarchyColumn) {

@@ -138,11 +141,15 @@ if (x === -2) {

value = this.getHeaderRowValue(x, y);
return value;
} else {
// if (hasHierarchyColumn) {
// y += 1;
// }
value = this.getDataSource().getValue(x, y - headerRowCount);
}
// if (hasHierarchyColumn) {
// y += 1;
// }
value = this.getDataSource().getValue(x, y - headerRowCount);
return value;
},
getDataIndex: function(y) {
return this.getDataSource().getDataIndex(y - this.grid.getHeaderRowCount());
},
/**

@@ -255,3 +262,3 @@ * @memberOf dataModels.JSON.prototype

var offset = (hasAggregates && !showTree) ? -1 : 0;
return this.analytics.getColumnCount() + offset;
return this.sources.aggregator.getColumnCount() + offset;
},

@@ -274,3 +281,3 @@

getHeaders: function() {
return this.analytics.getHeaders();
return this.sources.aggregator.getHeaders();
},

@@ -302,20 +309,81 @@

/** @typedef {object} dataSourcePipelineObject
* @property {function} DataSource - A `hyper-analytics`-style "data source" constructor.
* @property {*} [options] - When defined, passed as 2nd argument to constructor.
* @property {string} [parent] - Defines a branch off the main sequence.
*/
/**
* @type {dataSourcePipelineObject[]}
* @memberOf dataModels.JSON.prototype
* @param {object[]} dataRows
*/
setData: function(dataRows) {
this.source = new analytics.JSDataSource(dataRows);
//this.preglobalfilter = new analytics.DataSourceGlobalFilter(this.source);
//this.presorter = new analytics.DataSourceSorterComposite(this.prefilter);
pipeline: [
{ type: 'JSDataSource' },
{ type: 'DataSourceAggregator' },
{ type: 'DataSourceGlobalFilter' },
{ type: 'DataSourceSorterComposite' },
{ type: 'DataNodeGroupSorter', parent: 'DataSourceAggregator' }
],
this.analytics = new analytics.DataSourceAggregator(this.source);
/**
* @summary Instantiates the data source pipeline.
* @desc Each new layer is created using the supplied constructor and a reference to the previous data source in the pipeline. A reference to each new layer is added to `this` dataModel as a property using the layer's `name`.
*
* The first layer must have a `@@CLASS_NAME` of `'DataSource'`. Hence, the start of the pipeline is `this.source`. The last layer is assigned the synonym `this.dataSource`.
*
* Branches are created when a layer specifies a name in `parent`.
* @param {object[]} dataSource - Array of uniform objects containing the grid data.
* @memberOf dataModels.JSON.prototype
*/
setData: function(dataSource) {
this.resetSources();
this.postglobalfilter = new analytics.DataSourceGlobalFilter(this.analytics);
this.postsorter = new analytics.DataSourceSorterComposite(this.postglobalfilter);
this.pipeline.forEach(function(sources, layer, index) {
var DataSource = analytics[layer.type];
this.groupsorter = new analytics.DataNodeGroupSorter(this.analytics);
layer.name = layer.name || getDataSourceName(layer.type);
if (index === 0 && layer.name !== 'source') {
throw 'Expected pipeline to begin with source.';
}
if (layer.parent) {
this.dataSource = this.dataSource || dataSource; // tip of main trunk on first diversion
dataSource = sources[getDataSourceName(layer.parent)];
if (!dataSource) {
throw 'Parent data source not in pipeline.';
}
}
dataSource = layer.options === undefined
? new DataSource(dataSource)
: new DataSource(dataSource, layer.options);
sources[layer.name] = dataSource;
}.bind(this, this.sources));
this.dataSource = this.dataSource || dataSource; // tip of main trunk if never branched
this.applyAnalytics();
},
/**
* Add a layer to the data source pipeline.
* @param {dataSourcePipelineObject} newLayer - The new pipeline layer.
* @param {string} [referenceLayer] - Name of an existing pipeline layer after which the new layer will be added. If not found (such as `null`), inserts at beginning. If `undefined` or omitted, adds to end.
* @memberOf dataModels.JSON.prototype
*/
addPipe: function(newLayer, referenceLayer) {
var layerIndex;
if (referenceLayer !== undefined) {
referenceLayer = this.pipeline.find(function(layer, index) {
var found = layer.type === referenceLayer;
layerIndex = index;
return found;
});
}
if (referenceLayer === undefined) {
layerIndex = this.pipeline.length;
}
this.pipeline.splice(layerIndex + 1, 0, newLayer);
},

@@ -360,3 +428,3 @@

setGroups: function(groups) {
this.analytics.setGroupBys(groups);
this.sources.aggregator.setGroupBys(groups);
this.applyAnalytics();

@@ -373,3 +441,3 @@ this.grid.fireSyntheticGroupsChangedEvent(this.getGroups());

var fields = this.getFields().slice(0);
var groupBys = this.analytics.groupBys;
var groupBys = this.sources.aggregator.groupBys;
var groups = [];

@@ -392,4 +460,4 @@ for (var i = 0; i < groupBys.length; i++) {

getAvailableGroups: function() {
var headers = this.source.getHeaders().slice(0);
var groupBys = this.analytics.groupBys;
var headers = this.sources.source.getHeaders().slice(0);
var groupBys = this.sources.aggregator.groupBys;
var groups = [];

@@ -413,3 +481,3 @@ for (var i = 0; i < headers.length; i++) {

*/
getVisibleColumns: function() {
getActiveColumns: function() {
return this.grid.behavior.columns.filter(function(column) {

@@ -419,2 +487,5 @@ return column.name !== 'tree';

},
getVisibleColumns: function() {
this.deprecated('getVisibleColumns()', 'getActiveColumns()', '1.0.6', arguments);
},

@@ -445,3 +516,3 @@ /**

setAggregates: function(aggregations) {
this.quietlySetAggregates(aggregations);
this.sources.aggregator.setAggregates(aggregations);
this.applyAnalytics();

@@ -452,10 +523,2 @@ },

* @memberOf dataModels.JSON.prototype
* @param aggregations
*/
quietlySetAggregates: function(aggregations) {
this.analytics.setAggregates(aggregations);
},
/**
* @memberOf dataModels.JSON.prototype
* @returns {boolean}

@@ -468,16 +531,39 @@ */

setRelation: function(options) {
this.sources.treeview.setRelation(options);
this.applyAnalytics();
},
/**
* @memberOf dataModels.JSON.prototype
*/
applyAnalytics: function(dontApplyGroupBysAndAggregations) {
applyAnalytics: function(dontApplyAggregator) {
selectedDataRowsBackingSelectedGridRows.call(this);
if (!dontApplyGroupBysAndAggregations) {
applyGroupBysAndAggregations.call(this);
}
this.pipeline.forEach(function(sources, layer) {
var dataSource = sources[layer.name];
applyFilters.call(this);
switch (layer.type) {
case 'DataSourceAggregator':
if (dontApplyAggregator) {
dataSource = undefined;
}
break;
applySorts.call(this);
case 'DataSourceSorterComposite':
if (sources.aggregator && sources.aggregator.viewMakesSense()) {
dataSource = sources.groupsorter;
}
dataSource.clearSorts();
(this.getPrivateState().sorts || []).forEach(function(sort) {
dataSource.sortOn(Math.abs(sort) - 1, Math.sign(sort));
});
break;
}
if (dataSource && dataSource.apply) {
dataSource.apply();
}
}.bind(this, this.sources));
reselectGridRowsBackedBySelectedDataRows.call(this);

@@ -610,3 +696,3 @@ },

/**
* @memberOf dataModels.JSON.prototype
* @memberOf dataModels.JSON.prototypedrilldown
* @param cell

@@ -616,13 +702,12 @@ * @param event

cellClicked: function(cell, event) {
if (!this.hasAggregates()) {
return;
if (
this.sources.treeview && event.dataCell.x === this.sources.treeview.treeColumnIndex ||
this.hasAggregates() && event.gridCell.x === 0
) {
var expandable = this.getDataSource().click(event.gridCell.y - this.grid.getHeaderRowCount());
if (expandable) {
this.applyAnalytics(true);
this.changed();
}
}
if (event.gridCell.x !== 0) {
return; // this wasn't a click on the hierarchy column
}
var headerRowCount = this.grid.getHeaderRowCount();
var y = event.gridCell.y - headerRowCount;
this.getDataSource().click(y);
this.applyAnalytics(true);
this.changed();
},

@@ -757,2 +842,3 @@

this.getGlobalFilter().setColumnFilterState(columnName, state, options);
this.grid.fireSyntheticFilterAppliedEvent();
this.applyAnalytics();

@@ -778,2 +864,3 @@ },

this.getGlobalFilter().setColumnFiltersState(state, options);
this.grid.fireSyntheticFilterAppliedEvent();
this.applyAnalytics();

@@ -800,2 +887,3 @@ },

this.getGlobalFilter().setTableFilterState(state, options);
this.grid.fireSyntheticFilterAppliedEvent();
this.applyAnalytics();

@@ -806,27 +894,3 @@ },

* @memberOf dataModels.JSON.prototype
* @param {object} config
* @param {number} x
* @param {number} y
* @param {number} untranslatedX
* @param {number} untranslatedY
* @returns {object}
*/
getCellRenderer: function(config, x, y, untranslatedX, untranslatedY) {
var renderer;
var provider = this.grid.getCellProvider();
config.x = x;
config.y = y;
config.untranslatedX = untranslatedX;
config.untranslatedY = untranslatedY;
renderer = provider.getCell(config);
renderer.config = config;
return renderer;
},
/**
* @memberOf dataModels.JSON.prototype
*/
applyState: function() {

@@ -844,7 +908,7 @@ this.applyAnalytics();

getUnfilteredValue: function(x, y) {
return this.source.getValue(x, y);
return this.sources.source.getValue(x, y);
},
getUnfilteredRowCount: function() {
return this.source.getRowCount();
return this.sources.source.getRowCount();
}

@@ -910,50 +974,8 @@ });

/**
* @private
* @memberOf dataModels.JSON.prototype
*/
function applyGroupBysAndAggregations() {
if (this.analytics.aggregates.length === 0) {
this.quietlySetAggregates({});
}
this.analytics.apply();
function getDataSourceName(name) {
name = analytics[name].prototype.$$CLASS_NAME || name;
return name.replace(/^Data(Source|Node)/, '').toLowerCase() || 'source';
}
/**
* @private
* @memberOf dataModels.JSON.prototype
*/
function applyFilters() {
this.getGlobalFilterDataSource().apply();
var details = [];
// TODO: return something useful...
// was previously returning, for each column in this.getVisibleColumns():
// [ { column: column.header, format: 'complex' or column.getProperties().format }, ... ]
this.grid.fireSyntheticFilterAppliedEvent({
details: details
});
}
/**
* @private
* @memberOf dataModels.JSON.prototype
*/
function applySorts() {
var sortingSource = this.getSortDataSource();
var sorts = this.getPrivateState().sorts;
sortingSource.clearSorts();
if (sorts && sorts.length !== 0) {
for (var i = 0; i < sorts.length; i++) {
var colIndex = Math.abs(sorts[i]) - 1;
var type = sorts[i] < 0 ? -1 : 1;
sortingSource.sortOn(colIndex, type);
}
}
sortingSource.applySorts();
}
module.exports = JSON;

@@ -7,3 +7,2 @@ /* eslint-env browser */

var renderCellError = require('./lib/renderCellError');

@@ -20,3 +19,3 @@ /**

* The font for data cells.
* @default '13px Tahoma, Geneva, sans-serif'
* @default
* @type {cssFont}

@@ -30,3 +29,3 @@ * @instance

* The font for data cells.
* @default '13px Tahoma, Geneva, sans-serif'
* @default
* @type {cssFont}

@@ -39,3 +38,3 @@ * @instance

* Font color for data cells.
* @default 'rgb(25, 25, 25)'
* @default
* @type {string}

@@ -48,3 +47,3 @@ * @instance

* Background color for data cells.
* @default 'rgb(241, 241, 241)'
* @default
* @type {string}

@@ -57,3 +56,3 @@ * @instance

* Font style for selected cell(s).
* @default 'bold'
* @default
* @type {string}

@@ -66,3 +65,3 @@ * @instance

* Font color for selected cell(s).
* @default 'rgb(0, 0, 128)'
* @default
* @type {string}

@@ -73,3 +72,3 @@ * @instance

/**
* @default true
* @default
* @type {boolean}

@@ -81,3 +80,3 @@ * @instance

* Background color for selected cell(s).
* @default 'rgba(147, 185, 255, 0.45)'
* @default
* @type {string}

@@ -94,3 +93,3 @@ * @instance

/**
* @default '12px Tahoma, Geneva, sans-serif'
* @default
* @type {cssFont}

@@ -102,3 +101,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -111,3 +110,3 @@ * @instance

* Font style for selected columns' headers.
* @default 'bold'
* @default
* @type {string}

@@ -119,3 +118,3 @@ * @instance

/**
* @default 'rgb(223, 227, 232)'
* @default
* @type {cssColor}

@@ -127,3 +126,3 @@ * @instance

/**
* @default 'rgb(80, 80, 80)'
* @default
* @type {cssColor}

@@ -135,3 +134,3 @@ * @instance

/**
* @default 'rgba(255, 220, 97, 0.45)'
* @default
* @type {cssColor}

@@ -143,3 +142,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -151,3 +150,3 @@ * @instance

/**
* @default 'rgb(255, 180, 0)'
* @default
* @type {cssColor}

@@ -162,3 +161,3 @@ * @instance

/**
* @default '12px Tahoma, Geneva, sans-serif'
* @default
* @type {cssFont}

@@ -170,3 +169,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -178,3 +177,3 @@ * @instance

/**
* @default 'rgb(223, 227, 232)'
* @default
* @type {cssColor}

@@ -186,3 +185,3 @@ * @instance

/**
* @default 'rgb(80, 80, 80)'
* @default
* @type {cssColor}

@@ -195,3 +194,3 @@ * @instance

* Font style for selected rows' headers.
* @default 'bold'
* @default
* @type {string}

@@ -203,3 +202,3 @@ * @instance

/**
* @default 'rgba(255, 220, 97, 0.45)'
* @default
* @type {cssColor}

@@ -211,3 +210,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -219,3 +218,3 @@ * @instance

/**
* @default 'rgb(255, 180, 0)'
* @default
* @type {cssColor}

@@ -230,3 +229,3 @@ * @instance

/**
* @default '12px Tahoma, Geneva, sans-serif'
* @default
* @type {cssFont}

@@ -238,3 +237,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -246,3 +245,3 @@ * @instance

/**
* @default 'white'
* @default
* @type {cssColor}

@@ -254,3 +253,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -262,3 +261,3 @@ * @instance

/**
* @default 'rgb(255, 220, 97)'
* @default
* @type {cssColor}

@@ -270,3 +269,3 @@ * @instance

/**
* @default 'rgba(0,0,0,0.8)'
* @default
* @type {cssColor}

@@ -278,3 +277,3 @@ * @instance

/**
* @default 0.4
* @default
* @type {number}

@@ -288,3 +287,3 @@ * @instance

/**
* @default '12px Tahoma, Geneva, sans-serif'
* @default
* @type {cssFont}

@@ -296,3 +295,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -304,3 +303,3 @@ * @instance

/**
* @default 'rgb(223, 227, 232)'
* @default
* @type {cssColor}

@@ -312,3 +311,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -320,3 +319,3 @@ * @instance

/**
* @default 'rgba(255, 220, 97, 0.45)'
* @default
* @type {cssColor}

@@ -328,3 +327,3 @@ * @instance

/**
* @default 'rgb(25, 25, 25)'
* @default
* @type {cssColor}

@@ -336,3 +335,3 @@ * @instance

/**
* @default 'rgb(255, 180, 0)'
* @default
* @type {cssColor}

@@ -344,3 +343,3 @@ * @instance

/**
* @default 'rgb(201, 201, 201)'
* @default
* @type {cssColor}

@@ -352,3 +351,3 @@ * @instance

/**
* @default 0
* @default
* @type {number}

@@ -360,3 +359,3 @@ * @instance

/**
* @default 'visible'
* @default
* @type {string}

@@ -368,3 +367,3 @@ * @instance

/**
* @default 'hidden'
* @default
* @type {string}

@@ -376,3 +375,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -384,3 +383,3 @@ * @instance

/**
* @default ''
* @default
* @type {string}

@@ -392,3 +391,3 @@ * @instance

/**
* @default ''
* @default
* @type {string}

@@ -402,3 +401,3 @@ * @instance

/**
* @default 'center'
* @default
* @type {string}

@@ -410,3 +409,3 @@ * @instance

/**
* @default 'center'
* @default
* @type {string}

@@ -418,3 +417,3 @@ * @instance

/**
* @default 5
* @default
* @type {number}

@@ -426,3 +425,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -434,3 +433,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -441,3 +440,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -449,3 +448,3 @@ * @instance

/**
* @default 'rgb(199, 199 199)'
* @default
* @type {cssColor}

@@ -457,3 +456,3 @@ * @instance

/**
* @default 0.4
* @default
* @type {number}

@@ -466,3 +465,3 @@ * @instance

/**
* @default 15
* @default
* @type {number}

@@ -474,3 +473,3 @@ * @instance

/**
* @default 100
* @default
* @type {number}

@@ -484,3 +483,3 @@ * @instance

/**
* @default 60
* @default
* @type {number}

@@ -492,3 +491,3 @@ * @instance

/**
* @default `false`
* @default
* @type {boolean}

@@ -502,3 +501,3 @@ * @instance

/**
* @default `false`
* @default
* @type {boolean}

@@ -511,3 +510,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -526,3 +525,3 @@ * @instance

/**
* @default `false`
* @default
* @type {boolean}

@@ -536,3 +535,3 @@ * @instance

/**
* @default getTextWidth
* @default `getTextWidth`
* @type {function}

@@ -544,3 +543,3 @@ * @instance

/**
* @default getTextHeight
* @default `getTextHeight`
* @type {function}

@@ -553,3 +552,3 @@ * @instance

/**
* @default 0
* @default
* @type {number}

@@ -561,3 +560,3 @@ * @instance

/**
* @default 0
* @default
* @type {number}

@@ -569,3 +568,3 @@ * @instance

/**
* @default 0
* @default
* @type {number}

@@ -578,3 +577,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -586,3 +585,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -594,3 +593,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -602,3 +601,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -611,3 +610,3 @@ * @instance

/** Clicking in a cell "selects" it; it is added to the select region and repainted with "cell selection" colors.
* @default `true`
* @default
* @type {boolean}

@@ -619,3 +618,3 @@ * @instance

/** Clicking in a row header (leftmost column) "selects" the row; the entire row is added to the select region and repainted with "row selection" colors.
* @default `true`
* @default
* @type {boolean}

@@ -627,3 +626,3 @@ * @instance

/** Clicking in a column header (top row) "selects" the column; the entire column is added to the select region and repainted with "column selection" colors.
* @default `true`
* @default
* @type {boolean}

@@ -635,3 +634,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -643,3 +642,3 @@ * @instance

/**
* @default 'rgba(0, 0, 48, 0.2)'
* @default
* @type {cssColor}

@@ -651,3 +650,3 @@ * @instance

/**
* @default 'black'
* @default
* @type {string}

@@ -659,3 +658,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -667,3 +666,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -675,3 +674,3 @@ * @instance

/**
* @default `false`
* @default
* @type {boolean}

@@ -683,3 +682,3 @@ * @instance

/**
* @default `false`
* @default
* @type {boolean}

@@ -691,3 +690,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -699,3 +698,3 @@ * @instance

/**
* @default `true`
* @default
* @type {boolean}

@@ -707,3 +706,3 @@ * @instance

/**
* @default 325
* @default
* @type {number}

@@ -724,3 +723,3 @@ * @instance

*
* @default `true`
* @default
* @type {boolean}

@@ -732,9 +731,3 @@ * @instance

/**
* @default renderCellError
* @type {function}
*/
renderCellError: renderCellError,
/**
* @default `false`
* @default
* @type {boolean}

@@ -744,3 +737,3 @@ */

/** Name of a formatter for cell text.
/** @summary Name of a formatter for cell text.
* The default (`undefined`) falls back to `column.type`.

@@ -750,15 +743,21 @@ * The value `null` does no formatting.

* @type {undefined|null|string}
* @see /lib/localizers.js
* @tutorial localization
*/
format: undefined,
/** Name of a cell formatter for cell text.
* The default (`undefined`) falls back to `format`.
* The value `null` does no formatting.
/** @summary Name of a cell editor from the {@link module:cellEditors|cellEditors API}..
* @desc Not editable if named editor is does not exist.
* @default undefined
* @type {undefined|null|string}
* @see /lib/localizers.js
* @tutorial cell-editors
*/
editor: undefined,
/**
* Name of cell renderer from the {@link module:cellRenderers|cellRenderers API}.
* @default
* @type {string}
*/
renderer: 'SimpleCell',
/********** HOVER COLORS **********/

@@ -768,3 +767,3 @@

* @property {boolean} [enable=false] - `false` means not hilite on hover
* @property {cssColor} backgroundColor - cell, row, or colummn background color. Alpha channel will be respected and if given will be painted over the cells predetermined color.
* @property {cssColor} backgroundColor - cell, row, or column background color. Alpha channel will be respected and if given will be painted over the cells predetermined color.
* @property {cssColor} [header.backgroundColor=backgroundColor] - for columns and rows, this is the background color of the column or row "handle" (header rows or columns, respectively). (Not used for cells.)

@@ -805,3 +804,3 @@ */

* @type {boolean}
* @default `false`
* @default
*/

@@ -812,3 +811,3 @@ link: false,

* @type {boolean}
* @default `false`
* @default
*/

@@ -815,0 +814,0 @@ strikeThrough: false,

@@ -8,3 +8,3 @@ /* eslint-env browser */

var Dialog = require('./Dialog');
var css = require('../css');
var stylesheet = require('../lib/stylesheet');

@@ -36,10 +36,10 @@ /**

this.hiddenColumns = {
title: 'Hidden Columns',
models: behavior.getHiddenColumns()
this.inactiveColumns = {
title: 'Inactive Columns',
models: behavior.getHiddenColumns().sort(compareByName)
};
this.visibleColumns = {
title: 'Visible Columns',
models: behavior.getVisibleColumns()
this.activeColumns = {
title: 'Active Columns',
models: behavior.getActiveColumns()
};

@@ -50,19 +50,21 @@

// parse & add the drag-and-drop stylesheet addendum
var stylesheetAddendum = css.inject('list-dragon-addendum');
var stylesheetAddendum = stylesheet.inject('list-dragon-addendum');
// create drag-and-drop sets from the lists
var listOptions = {
// add the list-dragon-base stylesheet right before the addendum
cssStylesheetReferenceElement: stylesheetAddendum
},
listSets = [
new ListDragon([
this.selectedGroups,
this.availableGroups
], listOptions),
new ListDragon([
this.hiddenColumns,
this.visibleColumns
], listOptions)
];
var listSets = [
new ListDragon([
this.selectedGroups,
this.availableGroups
], {
// add the list-dragon-base stylesheet right before the addendum
cssStylesheetReferenceElement: stylesheetAddendum
}),
new ListDragon([
this.inactiveColumns,
this.activeColumns
], {
// these models have a header property as their labels
label: '{header}'
})
];

@@ -111,3 +113,3 @@ // add the drag-and-drop sets to the dialog

onClosed: function() {
if (this.visibleColumns) {
if (this.activeColumns) {
var behavior = this.grid.behavior,

@@ -122,3 +124,3 @@ columns = behavior.columns,

}
this.visibleColumns.models.forEach(function(column) {
this.activeColumns.models.forEach(function(column) {
columns.push(column);

@@ -133,3 +135,3 @@ });

this.grid.addProperties({ sortOnHiddenColumns: this.sortOnHiddenColumns });
behavior.sortChanged(this.hiddenColumns.models);
behavior.sortChanged(this.inactiveColumns.models);
}

@@ -142,3 +144,9 @@

function compareByName(a, b) {
a = a.header.toString().toUpperCase();
b = b.header.toString().toUpperCase();
return a < b ? -1 : a > b ? +1 : 0;
}
module.exports = ColumnPicker;

@@ -8,3 +8,3 @@ /* eslint-env browser */

var Base = require('../lib/Base');
var markup = require('../html/markup.html');
var markup = require('../../html');
var images = require('../../images');

@@ -14,3 +14,3 @@ var elfor = require('../lib/elfor');

/**
* Creates and services a DOM element used as a cntainer for a dialog. The standard `markup.diaglog` is simply a div with a _control panel_ containing a close box and a settings gear icon.
* Creates and services a DOM element used as a cntainer for a dialog. The standard `markup.dialog` is simply a div with a _control panel_ containing a close box and a settings gear icon.
*

@@ -175,20 +175,24 @@ * You can supply an alternative dialog template. The interface is:

function removeDialog(evt) {
if (this.el.parentElement.tagName !== 'BODY') {
this.el.parentElement.style.visibility = 'hidden';
if (evt.target === this.el && evt.propertyName === 'opacity') {
if (this.el.parentElement.tagName !== 'BODY') {
this.el.parentElement.style.visibility = 'hidden';
}
this.el.remove();
delete this.el;
this.onClosed();
this.terminate();
this.closing = false;
this.closed = true;
}
this.el.remove();
delete this.el;
this.onClosed();
this.terminate();
this.closing = false;
this.closed = true;
}
function hideApp(evt) {
this.appVisible('hidden');
this.el.removeEventListener('transitionend', this.hideAppBound);
this.onOpened();
this.opening = false;
this.opened = true;
if (evt.target === this.el && evt.propertyName === 'opacity') {
this.appVisible('hidden');
this.el.removeEventListener('transitionend', this.hideAppBound);
this.onOpened();
this.opening = false;
this.opened = true;
}
}

@@ -206,3 +210,3 @@

} else if (!this.onClick.call(this, evt) && evt.target.tagName === 'A') {
} else if (this.onClick && !this.onClick.call(this, evt) && evt.target.tagName === 'A') {
evt.preventDefault(); // ignore href of handled event

@@ -209,0 +213,0 @@ }

@@ -10,3 +10,3 @@ /* eslint-env browser */

var Dialog = require('./Dialog');
var markup = require('../html/markup.html');
var markup = require('../../html');
var copyInput = require('../lib/copy-input');

@@ -198,3 +198,3 @@

// show or hide the error
warningEl.innerHTML = error || '';
warningEl.innerHTML = error.message || error || '';
}

@@ -316,4 +316,11 @@

// default:
var options = { syntax: queryLanguage, alert: true };
var error = this.filter.setColumnFilterState(ctrl.name, ctrl.value, options);
var error,
options = { syntax: queryLanguage, alert: true };
try {
error = this.filter.setColumnFilterState(ctrl.name, ctrl.value, options);
} catch (err) {
error = err;
}
decorateFilterInput(ctrl, error);

@@ -320,0 +327,0 @@ //}

@@ -16,3 +16,3 @@ 'use strict';

*/
handleTap: function(grid, event) {
handleClick: function(grid, event) {
if (

@@ -24,3 +24,3 @@ event.gridCell.y >= grid.behavior.getHeaderRowCount() &&

} else if (this.next) {
this.next.handleTap(grid, event);
this.next.handleClick(grid, event);
}

@@ -27,0 +27,0 @@ }

@@ -26,3 +26,3 @@ 'use strict';

handleTap: function(grid, event) {
handleClick: function(grid, event) {
var isDoubleClickEditorActivation = grid.resolveProperty('editOnDoubleClick');

@@ -32,21 +32,6 @@ if (this.checkActivateEditor(grid, event, !isDoubleClickEditorActivation)) {

} else if (this.next) {
this.next.handleTap(grid, event);
this.next.handleClick(grid, event);
}
},
/**
* @memberOf CellEditing.prototype
* @desc handle this event down the feature chain of responsibility
* @param {Hypergrid} grid
* @param {Object} event - the event details
*/
handleHoldPulse: function(grid, event) {
var isDoubleClickEditorActivation = grid.resolveProperty('editOnDoubleClick');
if (this.checkActivateEditor(grid, event, !isDoubleClickEditorActivation)) {
grid.onEditorActivate(event);
} else if (this.next) {
this.next.handleHoldPulse(grid, event);
}
},
checkActivateEditor: function(grid, event, isDoubleClickEditorActivation) {

@@ -53,0 +38,0 @@ var headerRowCount = grid.behavior.getHeaderRowCount();

@@ -69,3 +69,3 @@ 'use strict';

var headerColumnCount = grid.behavior.getHeaderColumnCount();
var columnCount = grid.behavior.getColumnCount();
var columnCount = grid.getColumnCount();
var isOutside = viewCell.x >= columnCount;

@@ -72,0 +72,0 @@

@@ -131,3 +131,3 @@ /* eslint-env browser */

if (distance < 10) {
if (distance < 10 || this.isFixedColumn(grid, event)) {
if (this.next) {

@@ -165,3 +165,3 @@ this.next.handleMouseDrag(grid, event);

handleMouseDown: function(grid, event) {
if (grid.behavior.isColumnReorderable()) {
if (grid.behavior.isColumnReorderable() && !this.isFixedColumn(grid, event)) {
if (this.isHeaderRow(grid, event) && event.gridCell.x !== -1) {

@@ -215,3 +215,3 @@ this.dragArmed = true;

if (!this.dragging && event.mousePoint.y < 5 && event.viewPoint.y === 0) {
if (!this.dragging && event.mousePoint.y < 5 && event.viewPoint.y === 0 && !this.isFixedColumn(grid, event)) {
this.cursor = this.getCanDragCursorName();

@@ -508,6 +508,5 @@ } else {

var dragColumnIndex = grid.renderOverridesCache.dragger.columnIndex;
var columnWidth = grid.renderOverridesCache.dragger.width;
var minX = 0; //grid.getFixedColumnsWidth();
var maxX = grid.renderer.getFinalVisableColumnBoundary() - columnWidth;
var minX = 0;
var maxX = grid.renderer.getFinalVisableColumnBoundary();
x = Math.min(x, maxX + 15);

@@ -514,0 +513,0 @@ x = Math.max(minX - 15, x);

@@ -187,5 +187,5 @@ 'use strict';

*/
handleHoldPulse: function(grid, event) {
handleClick: function(grid, event) {
if (this.next) {
this.next.handleHoldPulse(grid, event);
this.next.handleClick(grid, event);
}

@@ -200,14 +200,2 @@ },

*/
handleTap: function(grid, event) {
if (this.next) {
this.next.handleTap(grid, event);
}
},
/**
* @memberOf Feature.prototype
* @desc handle this event down the feature chain of responsibility
* @param {Hypergrid} grid
* @param {Object} event - the event details
*/
handleMouseDrag: function(grid, event) {

@@ -214,0 +202,0 @@ if (this.next) {

@@ -18,23 +18,8 @@ 'use strict';

handleTap: function(grid, event) {
handleClick: function(grid, event) {
if (grid.isFilterRow(event.gridCell.y)) {
grid.onEditorActivate(event);
} else if (this.next) {
this.next.handleTap(grid, event);
this.next.handleClick(grid, event);
}
},
/**
* @memberOf CellEditing.prototype
* @desc handle this event down the feature chain of responsibility
* @param {Hypergrid} grid
* @param {Object} event - the event details
*/
handleHoldPulse: function(grid, event) {
var isDoubleClickEditorActivation = grid.resolveProperty('editOnDoubleClick');
if (this.checkActivateEditor(grid, event, !isDoubleClickEditorActivation)) {
grid.onEditorActivate(event);
} else if (this.next) {
this.next.handleHoldPulse(grid, event);
}
}

@@ -41,0 +26,0 @@

@@ -15,26 +15,7 @@ 'use strict';

/** @typedef {function} fieldsProviderFunc
* @returns {menuOption[]} see jsdoc typedef in pop-menu.js
*/
function quote(text) {
var qt = ParserCQL.qt;
return qt + text.replace(new RegExp(qt, 'g'), qt + qt) + qt;
}
/**
* @constructor
* @extends Operators
*/
var ConditionalsCql = FilterTree.Conditionals.extend({
makeLIKE: function(beg, end, op, c, originalOp) {
op = originalOp.toLowerCase();
return op + ' ' + c.operand;
},
makeIN: function(op, c) {
return op.toLowerCase() + ' ' + c.operand.replace(/\s*,\s*/g, ',');
},
make: function(op, c) {
op = op.toLowerCase();
if (/\w/.test(op)) { op += ' '; }
op += c.operand;
return op;
}
});
var likeDresses = [

@@ -72,4 +53,21 @@ { regex: /^(NOT )?LIKE %(.+)%$/i, operator: 'contains' },

}
var conditionals = new ConditionalsCql();
var conditionalsCQL = new FilterTree.Conditionals();
conditionalsCQL.makeLIKE = function(beg, end, op, originalOp, c) {
op = originalOp.toLowerCase();
return op + ' ' + quote(c.operand);
};
conditionalsCQL.makeIN = function(op, c) {
return op.toLowerCase() + ' (' + c.operand.replace(/\s*,\s*/g, ', ') + ')';
};
conditionalsCQL.make = function(op, c) {
var numericOperand;
op = op.toLowerCase();
if (/\w/.test(op)) { op += ' '; }
op += c.getType() === 'number' && !isNaN(numericOperand = Number(c.operand))
? numericOperand
: quote(c.operand);
return op;
};
// replace the default filter tree terminal node constructor with an extension of same

@@ -82,3 +80,3 @@ var CustomFilterLeaf = FilterTree.prototype.addEditor({

if (syntax === 'CQL') {
result = this.getSyntax(conditionals);
result = this.getSyntax(conditionalsCQL);
result = convertLikeToPseudoOp(result);

@@ -101,26 +99,25 @@ var defaultOp = this.schema.lookup(this.column).defaultOp || this.root.parserCQL.defaultOp; // mimics logic in parser-CQL.js, line 110

_(FilterTree.Node.prototype.templates).extendOwn({
columnFilter: function() {
/*
<span class="filter-tree">
<strong><span>{2} </span></strong><br>
Match
<label><input type="radio" class="filter-tree-op-choice" name="treeOp{1}" value="op-or">any</label>
<label><input type="radio" class="filter-tree-op-choice" name="treeOp{1}" value="op-and">all</label>
<label><input type="radio" class="filter-tree-op-choice" name="treeOp{1}" value="op-nor">none</label>
of the following:
<select>
<option value="">New expression&hellip;</option>
</select>
<ol></ol>
</span>
*/
},
columnFilters: function() {
/*
<span class="filter-tree filter-tree-type-column-filters">
Match <strong>all</strong> of the following column filter subexpressions:
<ol></ol>
</span>
*/
}
columnFilter: [
'<span class="filter-tree">',
' <strong><span>{2} </span></strong><br>',
' Match',
' <label><input type="radio" class="filter-tree-op-choice" name="treeOp{1}" value="op-or">any</label>',
' <label><input type="radio" class="filter-tree-op-choice" name="treeOp{1}" value="op-and">all</label>',
' <label><input type="radio" class="filter-tree-op-choice" name="treeOp{1}" value="op-nor">none</label>',
' of the following:',
' <select>',
' <option value="">New expression&hellip;</option>',
' </select>',
' <ol></ol>',
'</span>'
]
.join('\n'),
columnFilters: [
'<span class="filter-tree filter-tree-type-column-filters">',
' Match <strong>all</strong> of the following column filter subexpressions:',
' <ol></ol>',
'</span>'
]
.join('\n')
});

@@ -135,3 +132,3 @@

*
* @param {FilterTreeOptionsObject} options - You hsould provide a column schema. The easiest approach is to provide a schema for the entire filter tree through `options.schema`.
* @param {FilterTreeOptionsObject} options - You should provide a column schema. The easiest approach is to provide a schema for the entire filter tree through `options.schema`.
*

@@ -170,3 +167,3 @@ * Although not recommended, the column schema can also be embedded in the state object, either at the root, `options.state.schema`, or for any descendant node. For example, a separate schema could be provided for each expression or subexpression that need to render column list drop-downs.

if (this === this.root && !this.parserCQL) {
this.parserCQL = new ParserCQL({
this.parserCQL = new ParserCQL(this.conditionals.ops, {
schema: this.schema,

@@ -291,3 +288,3 @@ defaultOp: options.defaultColumnFilterOperator

* @summary Set a particular column filter's state.
* @desc Adds CQL support to this.getState().
* @desc Adds CQL support to this.getState(). This function throws parser errors.
*

@@ -306,4 +303,2 @@ * @param {string} columnName

*
* @returns {undefined|Error|string} `undefined` indicates success.
* @memberOf DefaultFilter.prototype

@@ -327,3 +322,2 @@ */

// on first use, set up a new CQL instance for this column filter's subtree bound to column properties
if (options.syntax === 'CQL') {

@@ -333,3 +327,3 @@ // Convert some CQL state syntax into a filter tree state object.

try {
state = this.root.parserCQL.parse(state, { columnName: columnName });
state = this.root.parserCQL.parse(state, columnName);
if (state) {

@@ -341,4 +335,3 @@ options.syntax = 'object';

} catch (e) {
error = e.message || e;
console.warn(error);
error = e;
}

@@ -366,3 +359,5 @@ }

return error;
if (error) {
throw error;
}
},

@@ -477,4 +472,6 @@

});
column.type = columnSchema.type || column.type;
column.header = columnSchema.alias || column.header;
if (column) {
column.type = columnSchema.type || column.type;
column.header = columnSchema.alias || column.header;
}
});

@@ -484,2 +481,3 @@ }

module.exports = DefaultFilter;
'use strict';
var _ = require('object-iterators');
var REGEXP_BOOLS = /\b(AND|OR|NOR)\b/gi,
REGEXP_CELL_FILTER = /^\s*(<=|>=|<>|[<≤≠≥>=]|(NOT )?(IN|CONTAINS|BEGINS|ENDS|LIKE) )?(.*?)\s*$/i,
EXP = '(.*?)', BR = '\\b',
PREFIX = '^' + EXP + BR,
INFIX = BR + EXP + BR,
POSTFIX = BR + EXP + '$',
opMap = {
'>=': '≥',
'<=': '≤',
'<>': '≠'
};
POSTFIX = BR + EXP + '$';

@@ -26,14 +22,69 @@ function ParserCqlError(message) {

*
* @author Jonathan Eiten <jonathan@openfin.com>
* @author Jonathan Eiten jonathan@openfin.com
*
* @desc See {@tutorial CQL} for the grammar.
*
* @param {object} operatorsHash - Hash of valid operators. Each is an object, the only property of interest being `complex` which if truthy means operand may be a list of multiple operands.
* @param {object} [options]
* @param {menuItem[]} [options.schema] - Column schema for column name/alias validation. Throws an error if name fails validation (but see `resolveAliases`). Omit to skip column name validation.
* @param {boolean} [options.defaultOp='='] - Default operator for column when not defined in column schema.
*/
function ParserCQL(options) {
function ParserCQL(operatorsHash, options) {
var operators = [];
this.schema = options && options.schema;
this.defaultOp = options && options.defaultOp || '=';
this.defaultOp = (options && options.defaultOp || '=').toUpperCase();
_(operatorsHash).each(function(props, op) {
if (op !== 'undefined') {
operators.push(op);
}
});
// Put larger ones first so that in case a smaller one is a substring of a larger one (such as '<' is to '<='), larger one will be matched first.
operators = operators.sort(descendingByLength);
// Escape all symbolic (non alpha) operators.
operators = operators.map(function(op) { return /[^\w]/.test(op) ? '\\' + op.split('').join('\\') : op; });
var symbolicOperators = operators.filter(function(op) { return op[0] === '\\'; }),
alphaOperators = operators.filter(function(op) { return op[0] !== '\\'; }).join('|');
if (alphaOperators) {
alphaOperators = '\\b(' + alphaOperators + ')\\b';
}
/** @summary Regex to match any operator.
* @desc Matches symbolic operators (made up of non-alpha characters) or identifier operators (word-boundary-isolated runs of alphanumeric characters).
* @type {RegExp}
*/
this.REGEX_OPERATOR = new RegExp(symbolicOperators.concat(alphaOperators).join('|'), 'ig');
operators = operators.join('|') // pipe them
.replace(/\s+/g, '\\s+'); // arbitrary string of whitespace chars -> whitespace regex matcher
/** @summary Regex to match an operator + optional operator
* @desc THe operator is optional. The operand may (or may not) be enclosed in parentheses.
* @desc Match list:
* 0. _input string_
* 1. operator
* 2. outer operand (may include parentheses)
* 3. inner operand without parentheses (when an operand was given with parentheses)
* 4. inner operand (when an operand was given without parentheses)
* @type {RegExp}
* @private
* @memberOf ParserCQL.prototype
*/
this.REGEX_EXPRESSION = new RegExp('^\\s*(' + operators + ')?\\s*(\\(\\s*(.+?)\\s*\\)|(.+?))\\s*$', 'i');
this.REGEX_LITERAL_TOKENS = new RegExp('\\' + ParserCQL.qt + '(\\d+)' + '\\' + ParserCQL.qt, 'g');
}
/** @summary Operand quotation mark character.
* @desc Should be a single character (length === 1).
* @default '"'
* @type {string}
*/
ParserCQL.qt = '"';
ParserCQL.prototype = {

@@ -69,4 +120,5 @@

/**
* Break an expression chain into a list of expressions.
* @summary Break an expression chain into a list of expressions.
* @param {string} cql
* @param {string[]} booleans
* @returns {string[]}

@@ -96,2 +148,3 @@ */

* @param {string[]} expressions
* @param {string[]} literals - list of literals indexed by token
*

@@ -102,19 +155,39 @@ * @returns {expressionState[]} where `expressionState` is one of:

*/
makeChildren: function(columnName, expressions) {
var children = [],
self = this;
makeChildren: function(columnName, expressions, literals) {
var self = this;
return expressions.reduce(function(children, exp) {
if (exp) {
var parts = exp.match(self.REGEX_EXPRESSION);
if (parts) {
var op = parts[1],
outerLiteral = parts[2],
innerLiteral = parts.slice(3).find(function(part) {
return part !== undefined;
});
expressions.forEach(function(expression) {
if (expression) {
var parts = expression.match(REGEXP_CELL_FILTER),
literal = parts[parts.length - 1];
op = (op || '').replace(/\s+/g, ' ').trim().toUpperCase();
if (literal) {
var op = parts[1] && parts[1] || // as specified by user
var parenthesized = /^\(.*\)$/.test(outerLiteral),
innerOperators = innerLiteral.match(self.REGEX_OPERATOR);
if (!parenthesized && innerOperators) {
if (op === '' && outerLiteral === innerOperators[0]) {
throw new ParserCqlError('Expected an operand.');
}
throw new ParserCqlError(
'Expected operand but found additional operator(s): ' +
innerOperators
.toString() // convert to comma-separated list
.toUpperCase()
.replace(/,/g, ', ') // add spaces after the commas
.replace(/^([^,]+), ([^,]+)$/, '$1 and $2') // replace only comma with "and"
.replace(/(.+,.+), ([^,]+)$/, '$1, and $2') // add "and" after last of several commas
);
}
op = op ||
self.schema && self.schema.lookup(columnName).defaultOp || // column's default operator from schema
self.defaultOp; // grid's default operator
op = opMap[op] || op; // accommodate alternate spellings of operators
op = op.trim().toUpperCase(); // clean up & normalize
var child = {

@@ -125,3 +198,3 @@ column: columnName,

var fieldName = self.schema && self.schema.lookup(literal);
var fieldName = self.schema && self.schema.lookup(innerLiteral);
if (fieldName) {

@@ -131,3 +204,6 @@ child.operand = fieldName.name || fieldName;

} else {
child.operand = literal;
// Find and expand all collapsed literals.
child.operand = innerLiteral.replace(self.REGEX_LITERAL_TOKENS, function(match, index) {
return literals[index];
});
}

@@ -137,6 +213,6 @@

}
return children;
}
});
return children;
}, []);
},

@@ -152,3 +228,3 @@

*
* @param {string} options.columnName - (Required.)
* @param {string} columnName

@@ -160,11 +236,12 @@ * @returns {undefined|{operator: string, children: string[], schema: string[]}}

*/
parse: function(cql, options) {
var columnName = options.columnName;
parse: function(cql, columnName) {
// reduce all runs of white space to a single space; then trim
cql = cql.replace(/\s\s+/g, ' ').trim();
var literals = [];
cql = tokenizeLiterals(cql, ParserCQL.qt, literals);
var booleans = this.captureBooleans(cql),
expressions = this.captureExpressions(cql, booleans),
children = this.makeChildren(columnName, expressions),
children = this.makeChildren(columnName, expressions, literals),
operator = booleans && booleans[0],

@@ -188,2 +265,43 @@ state;

function descendingByLength(a, b) {
return b.length - a.length;
}
/**
* @summary Collapse literals.
* @desc Allows reserved words to exist inside a quoted string.
* Literals are collapsed to a quoted numerical index into the `literals` array.
* @param {string} text
* @param {string} qt
* @param {string[]} literals - Empty array in which to return extracted literals.
* @returns {string}
*/
function tokenizeLiterals(text, qt, literals) {
literals.length = 0;
for (
var i = 0, j = 0, k, innerLiteral;
(j = text.indexOf(qt, j)) >= 0;
j = j + 1 + (i + '').length + 1, i++
) {
k = j;
do {
k = text.indexOf(qt, k + 1);
if (k < 0) {
throw new ParserCqlError('Quotation marks must be paired; nested quotation marks must be doubled.');
}
} while (text[++k] === qt);
innerLiteral = text
.slice(++j, --k) // extract
.replace(new RegExp(qt + qt, 'g'), qt); // unescape escaped quotation marks
literals.push(innerLiteral);
text = text.substr(0, j) + i + text.substr(k); // collapse
}
return text;
}
module.exports = ParserCQL;

@@ -9,5 +9,15 @@

/**
* Transform a primitive value into a human-friendly string representation.
* @name localizerInterface#name
* @summary Name to use for registering the localizer.
* @desc Implementation of this property is optional.
* If undefined, a name will need to be supplied at registration time.
* @type {string}
*/
/**
* @name localizerInterface#format
* @summary Transform a primitive value into a human-friendly string representation.
* @desc Implementation of this method is required.
* @method
* @name localizerInterface#localize
* @param {*} value
* @returns {string}

@@ -17,21 +27,41 @@ */

/**
* Transform a formatted string representation back into a primitive typed value.
* @summary Transform a formatted string representation back into a primitive typed value.
* @desc Implementation of this method is required.
* @method
* @name localizerInterface#standardize
* @returns {string} Primitive typed value.
* @name localizerInterface#parse
* @param {string} editedValue
* @returns {null|*} Primitive typed value.
* @throws {boolean|string|Error} Parser error.
*/
/**
* Tests string representation for all valid characters.
* (Implementation optional.)
* @name localizerInterface#invalid
* @summary Tests string representation for invalidity.
* @desc Implementation of this method is optional.
*
* The method may be strict or loose but caller has no way of knowing and must assume loose. Loose means it may return a false negative. This means that while a truthy return means invalid, falsy merely means "not invalid." In other words, you cannot assume that a falsy value means valid. The parser is the final arbiter and should be designed to throw an error on parser jam. For example, a number parser should not simply return NaN but should throw an error.
*
* Overridden by `options.invalid` passed to constructor.
* @method
* @name localizerInterface#isValid
* @returns {boolean} `true` means valid; `false` means invalid character found.
* @returns {boolean|string} Truthy value means invalid. If a string, this will be an error message. If not a string, it merely indicates a generic invalid result.
*/
/**
* Locale passed to constructor.
* (Implementation optional.)
* @name localizerInterface#expectation
* @summary A string to use when no validation error message is available.
* @desc Implementation of this property is optional.
*
* This string should describe the syntax and semantics of the expected value. Typically it begins with "Expected ..."
*
* If undefined and in the absence of an error message, the user will know only that the value is invalid but nothing else.
*
* Overridden by `options.expectation` passed to constructor.
*
* @type {string}
*/
/**
* @name localizerInterface#locale
* @summary Locale provided to constructor. Required.
* @type {string}
*/

@@ -11,38 +11,69 @@ 'use strict';

var warned = {};
var regexIsMethod = /\)$/;
/**
*
* @param dotProps
* @param {object} [options]
* @param {object} [options.asOfVersion]
* @param {object} [options.getterName] - If omitted, final name in dotProps will be used prefixed with 'get'.
* @returns {deprecated}
* User is warned and new property is returned or new method is called and the result is returned.
* @param {string} methodName - Deprecated method name with parentheses (required) containing argument list (optional).
* @param {string} dotProps - Dot-separated new property name to invoke or method name to call. Method names are indicated by including parentheses with optional argument list. The arguments in each list are drawn from the arguments presented in the `methodName` parameter.
* @param {string} since - Version in which the name was deprecated.
* @param {Arguments|Array} [args] - Actual arguments. Only needed when arguments are listed in `methodName`. The order of the arguments must match.
* @param {string} [notes] - Notes to add to message.
* @returns {*} Return value of new property or method call.
*/
var deprecated = function(dotProps, options) {
var chain = dotProps.split('.'),
method = chain[chain.length - 1],
asOfVersion = options && options.asOfVersion,
result = this,
warning;
var deprecated = function(methodName, dotProps, since, args, notes) {
if (!regexIsMethod.test(methodName)) {
throw 'Expected method name to have parentheses.';
}
method = options && options.getterName || 'get' + method[0].toUpperCase() + method.substr(1);
if (typeof args === 'string') {
// `args` omitted
notes = args;
args = undefined;
}
warning = '.' + method + '() method is deprecated';
var chain = dotProps.split('.'),
formalArgList = argList(methodName),
result = this;
if (asOfVersion) {
warning += ' as of v' + options.asOfVersion;
if (!(methodName in warned)) {
warned[methodName] = deprecated.warnings;
}
if (warned[methodName]) {
var memberType = regexIsMethod.test(dotProps) ? 'method' : 'property';
var warning = 'The .' + methodName + '() method is deprecated as of v' + since +
' in favor of the .' + chain.join('.') + ' ' + memberType + '.' +
' (Will be removed in a future release.)';
warning += '. Use .' + dotProps;
if (notes) {
warning += ' ' + notes;
}
if (dotProps[dotProps.length - 1] !== ')') {
warning += ' property';
console.warn(warning);
--warned[methodName];
}
warning += ' instead. (Will be removed in a future release.)';
function mapToFormalArg(argName) {
var index = formalArgList.indexOf(argName);
if (index === -1) {
throw 'Actual arg "' + argName + '" not found in formal arg list ' + formalArgList;
}
return args[index];
}
console.warn(warning);
for (var i = 0, last = chain.length - 1; i <= last; ++i) {
var link = chain[i],
actualArgList = regexIsMethod.test(link) ? argList(link) : undefined,
actualArgs = [];
chain.forEach(function(link) {
result = result[link];
});
if (actualArgList) {
actualArgs = actualArgList.map(mapToFormalArg);
link = link.match(/(\w+)/)[1];
result = result[link].apply(result, actualArgs);
} else {
result = result[link];
}
}

@@ -52,2 +83,8 @@ return result;

deprecated.warnings = 5; // just enough to be annoying
function argList(s) {
return s.match(/^\w+\((.*)\)$/)[1].match(/(\w+)/g);
}
module.exports = deprecated;

@@ -7,4 +7,4 @@ /* eslint-env browser */

var _ = require('object-iterators');
var Base = require('./Base');
var images = require('../../images');

@@ -183,10 +183,2 @@

/** @deprecated Use `.grid` property instead.
* @memberOf Renderer.prototype
* @returns {Hypergrid} grid
*/
getGrid: function() {
return this.deprecated('grid', { since: '0.2' });
},
/**

@@ -441,3 +433,3 @@ * @memberOf Renderer.prototype

var column = behavior.getVisibleColumn(c);
var column = behavior.getActiveColumn(c);
if (column) {

@@ -511,27 +503,20 @@ translatedIndex = column.index;

this.renderOverrides(gc);
this.renderFocusCell(gc);
this.renderLastSelection(gc);
gc.closePath();
},
focusLineStep: [
[5, 5],
[0, 1, 5, 4],
[0, 2, 5, 3],
[0, 3, 5, 2],
[0, 4, 5, 1],
[0, 5, 5, 0],
[1, 5, 4, 0],
[2, 5, 3, 0],
[3, 5, 2, 0],
[4, 5, 1, 0]
],
renderFocusCell: function(gc) {
renderLastSelection: function(gc) {
gc.beginPath();
this._renderFocusCell(gc);
this._renderLastSelection(gc);
gc.closePath();
},
_renderFocusCell: function(gc) {
_renderLastSelection: function(gc) {
/*
Compute the Bounds of the Last Selection that is visible
*/
var selections = this.grid.selectionModel.getSelections();

@@ -541,3 +526,3 @@ if (!selections || selections.length === 0) {

}
var selection = selections[selections.length - 1];
var selection = this.grid.selectionModel.getLastSelection();
var mouseDown = selection.origin;

@@ -598,20 +583,19 @@ if (mouseDown.x === -1) {

gc.rect(x, y, width, height);
gc.fillStyle = this.resolveProperty('selectionRegionOverlayColor');
gc.fill();
gc.lineWidth = 1;
gc.strokeStyle = this.resolveProperty('selectionRegionOutlineColor');
/*
// animate the dashed line a bit here for fun
Render the selection model around the bounds
gc.stroke();
*/
//gc.rect(x, y, width, height);
//gc.strokeStyle = 'white';
// animate the dashed line a bit here for fun
//gc.setLineDash(this.focusLineStep[Math.floor(10 * (Date.now() / 300 % 1)) % this.focusLineStep.length]);
//gc.stroke();
var config = {
bounds: {
x: x,
y: y,
width: width,
height: height
},
selectionRegionOverlayColor: this.grid.resolveProperty('selectionRegionOverlayColor'),
selectionRegionOutlineColor: this.grid.resolveProperty('selectionRegionOutlineColor')
};
this.grid.cellRenderers.get('lastselection').paint(gc, config);
},

@@ -672,10 +656,2 @@

/** @deprecated Use `.grid.behavior` property instead.
* @memberOf Renderer.prototype
* @returns {Behavior} The behavior (model).
*/
getBehavior: function() {
return this.deprecated('grid.behavior', { since: '0.2' });
},
getColumnEdges: function() {

@@ -814,4 +790,4 @@ return this.columnEdges;

paintCells: function(gc) {
var renderCellError,
message,
var message,
config = {},
x, y,

@@ -845,3 +821,2 @@ c, r,

this.renderedColumnMinWidths[c] = 0;
renderCellError = behavior.getColumnProperties(c).renderCellError;

@@ -874,16 +849,22 @@ gc.save();

if (renderCellError) {
var rawGc = gc.gc || gc, // Don't log these canvas calls
errY = rowEdges[y],
errHeight = rowEdges[y + 1] - errY;
var rawGc = gc.gc || gc, // Don't log these canvas calls
errY = rowEdges[y],
errHeight = rowEdges[y + 1] - errY;
rawGc.save(); // define clipping region
rawGc.beginPath();
rawGc.rect(clipX, errY, clipWidth, errHeight);
rawGc.clip();
rawGc.save(); // define clipping region
rawGc.beginPath();
rawGc.rect(clipX, errY, clipWidth, errHeight);
rawGc.clip();
config = {
bounds: {
y: errY,
x: clipX,
height: errHeight,
width: clipWidth
}
};
renderCellError(rawGc, message, clipX, errY, clipWidth, errHeight);
this.grid.cellRenderers.get('errorcell').paint(rawGc, config, message);
rawGc.restore(); // discard clipping region
}
rawGc.restore(); // discard clipping region

@@ -1079,17 +1060,14 @@ }

var cell = behavior.getCellRenderer(cellProperties, c, r);
var column = behavior.getVisibleColumn(c);
var overrides = behavior.getCellProperties(column.index, r);
var column = behavior.getActiveColumn(c);
//declarative cell properties
_(cellProperties).extendOwn(overrides);
if (isGridRow) {
var overrides = behavior.getCellProperties(column.index, r);
_(cellProperties).extendOwn(overrides);
}
//allow the renderer to identify itself if it's a button
cellProperties.buttonCells = this.buttonCells;
if (cellProperties.isUserDataArea) {
var formatName = cellProperties.format;
if (!formatName && formatName !== null) { // null means don't fallback to type
formatName = column.getType();
}
}
cellProperties.formatValue = grid.getFormatter(formatName);
cellProperties.formatValue = grid.getFormatter(cellProperties.isUserDataArea && cellProperties.format);
cell.paint(gc, cellProperties);

@@ -1126,3 +1104,3 @@

ctx.save();
this.renderFocusCell(ctx);
this.renderLastSelection(ctx);
ctx.restore();

@@ -1129,0 +1107,0 @@ ctx.closePath();

@@ -107,5 +107,14 @@ 'use strict';

* @param {number} ey - extent y coordinate
* @param {boolean} silent - whether to fire selection changed event
*/
select: function(ox, oy, ex, ey) {
select: function(ox, oy, ex, ey, silent) {
var newSelection = this.grid.newRectangle(ox, oy, ex, ey);
newSelection.firstSelectedCell = this.grid.newPoint(ox, oy); //Cache the first selected cell before it gets normalized to top-left origin
newSelection.lastSelectedCell = (
(newSelection.firstSelectedCell.x === newSelection.origin.x && newSelection.firstSelectedCell.y === newSelection.origin.y)
?
newSelection.corner
:
newSelection.origin
);
this.selections.push(newSelection);

@@ -115,3 +124,3 @@ this.flattenedX.push(newSelection.flattenXAt(0));

this.setLastSelectionType('cell');
this.grid.selectionChanged();
if (!silent) {this.grid.selectionChanged();}
},

@@ -118,0 +127,0 @@

@@ -10,8 +10,7 @@ /* eslint-env browser */

analytics: require('hyper-analytics'), // npm
//analytics: require('../../hyper-analytics/src'), // steve & DJ
//analytics: require('../../../hyper-analytics/src'), // jonathan
//analytics: require('../../hyper-analytics/src'), // developers
FilterTree: require('filter-tree'), // npm
//FilterTree: require('../../../filter-tree/src'), // jonathan
//FilterTree: require('../../filter-tree'), // developers
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc