diff --git a/examples/bclys/fin-hypergrid.dev.html b/examples/bclys/fin-hypergrid.dev.html deleted file mode 100644 index 8eab4605b..000000000 --- a/examples/bclys/fin-hypergrid.dev.html +++ /dev/null @@ -1,37964 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/bclys/fin-hypergrid.min.html b/examples/bclys/fin-hypergrid.min.html deleted file mode 100644 index a513aa7bf..000000000 --- a/examples/bclys/fin-hypergrid.min.html +++ /dev/null @@ -1,32 +0,0 @@ - \ No newline at end of file diff --git a/examples/bclys/index.html b/examples/bclys/index.html index 7184f34de..f94a64c56 100644 --- a/examples/bclys/index.html +++ b/examples/bclys/index.html @@ -7,7 +7,7 @@ - + @@ -89,11 +89,10 @@ var div = document.querySelector('div#json-example'), bodyStyle = window.getComputedStyle(document.body); - var getContainer = function(grid) { + jsonGrid = new fin.Hypergrid(div, function(grid) { return new fin.Hypergrid.behaviors.JSON(grid, window.people1); - }; + }); - jsonGrid = new fin.Hypergrid(div, getContainer); var jsonModel = jsonGrid.getBehavior(); //functions for showing the grouping/rollup capbilities @@ -541,7 +540,7 @@ var state = { columnIndexes: [ fieldsMap.last_name, - fieldsMap.pets, + fieldsMap.total_number_of_pets_owned, fieldsMap.birthDate, fieldsMap.birthState, // fieldsMap.residenceState, diff --git a/examples/bclys/index.js b/examples/bclys/index.js index fa9edcbd8..16f9403c0 100644 --- a/examples/bclys/index.js +++ b/examples/bclys/index.js @@ -1,5 +1,5 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o CAUTION: Mutates `this` array! - * @param {Array} appendix - * @returns {Array} Reference to `this` (for convenience) - */ -function append(appendix) { - this.splice.bind(this, this.length, 0).apply(this, appendix); - return this; -} - -module.exports = DataNodeGroup; -},{"./DataNodeBase":5,"./util/Mappy":17}],7:[function(require,module,exports){ -'use strict'; - -var DataNodeBase = require('./DataNodeBase'); - -var DataNodeLeaf = DataNodeBase.extend('DataNodeLeaf', { - - prune: function(depth) { - this.depth = depth; - this.data[0] = this.computeDepthString(); + var elapsed = now - this.lastRepaintTime; + if (elapsed > interval && this.dirty) { + this.lastRepaintTime = now - (elapsed % interval); + this.paintNow(); + } }, - getIndex: function() { - return this.index; + beginPainting: function() { + var self = this; + this.dirty = true; + this.tickPainter = function(now) { + self.tickPaint(now); + }; + paintables.push(this); }, - buildView: function(aggregator) { - aggregator.addView(this); + stopPainting: function() { + paintables.splice(paintables.indexOf(this), 1); }, - computeHeight: function() { - return 1; - } - -}); - -module.exports = DataNodeLeaf; -},{"./DataNodeBase":5}],8:[function(require,module,exports){ -'use strict'; - -var DataNodeGroup = require('./DataNodeGroup'); - -var DataNodeTree = DataNodeGroup.extend('DataNodeTree', { - - initialize: function(key) { - this.height = 0; - this.expanded = true; + beginResizing: function() { + var self = this; + this.tickResizer = function() { + self.checksize(); + }; + resizables.push(this); }, - prune: function() { - this.children = this.children.values; - this.children.forEach(function(child) { - child.prune(0); - }); + stopResizing: function() { + resizables.splice(resizables.indexOf(this), 1); }, - buildView: function(aggregator) { - this.children.forEach(function(child) { - child.buildView(aggregator); - }); + start: function() { + this.beginPainting(); + this.beginResizing(); }, - computeHeight: function() { - var height = 1; - - this.children.forEach(function(child) { - height = height + child.computeHeight(); - }); - - return (this.height = height); - } + stop: function() { + this.stopPainting(); + this.stopResizing(); + }, -}); + checksize: function() { + //this is expensive lets do it at some modulo + var sizeNow = this.div.getBoundingClientRect(); + if (sizeNow.width !== this.size.width || sizeNow.height !== this.size.height) { + this.sizeChangedNotification(); + } + }, -module.exports = DataNodeTree; -},{"./DataNodeGroup":6}],9:[function(require,module,exports){ -'use strict'; + sizeChangedNotification: function() { + this.resize(); + }, -var headerify = require('./util/headerify'); + resize: function() { + var box = this.size = this.div.getBoundingClientRect(); -function DataSource(data, fields) { - this.fields = fields || computeFieldNames(data[0]); - this.data = data; -} + this.canvas.width = this.buffer.width = box.width; + this.canvas.height = this.buffer.height = box.height; -DataSource.prototype = { - constructor: DataSource.prototype.constructor, // preserve constructor + //fix ala sir spinka, see + //http://www.html5rocks.com/en/tutorials/canvas/hidpi/ + //just add 'hdpi' as an attribute to the fin-canvas tag + var ratio = 1; + var useBitBlit = this.useBitBlit(); + var isHIDPI = window.devicePixelRatio && this.useHiDPI(); + if (isHIDPI) { + var devicePixelRatio = window.devicePixelRatio || 1; + var backingStoreRatio = this.canvasCTX.webkitBackingStorePixelRatio || + this.canvasCTX.mozBackingStorePixelRatio || + this.canvasCTX.msBackingStorePixelRatio || + this.canvasCTX.oBackingStorePixelRatio || + this.canvasCTX.backingStorePixelRatio || 1; - isNullObject: false, + ratio = devicePixelRatio / backingStoreRatio; + //this.canvasCTX.scale(ratio, ratio); + } + var width = this.canvas.getAttribute('width'); + var height = this.canvas.getAttribute('height'); + this.canvas.width = width * ratio; + this.canvas.height = height * ratio; + this.buffer.width = width * ratio; + this.buffer.height = height * ratio; - getRow: function(y) { - return this.data[y]; - }, + this.canvas.style.width = width + 'px'; + this.canvas.style.height = height + 'px'; + this.buffer.style.width = width + 'px'; + this.buffer.style.height = height + 'px'; - getValue: function(x, y) { - var row = this.getRow(y); - if (!row) { - return null; + this.bufferCTX.scale(ratio, ratio); + if (isHIDPI && !useBitBlit) { + this.canvasCTX.scale(ratio, ratio); } - return row[this.fields[x]]; - }, - setValue: function(x, y, value) { - this.getRow(y)[this.fields[x]] = value; + //this.origin = new rectangular.Point(Math.round(this.size.left), Math.round(this.size.top)); + this.bounds = new rectangular.Rectangle(0, 0, box.width, box.height); + //setTimeout(function() { + var comp = this._component; + if (comp) { + comp.setBounds(this.bounds); + } + this.resizeNotification(); + this.paintNow(); + //}); }, - getRowCount: function() { - return this.data.length; + resizeNotification: function() { + //to be overridden }, - getColumnCount: function() { - return this.getFields().length; + getBounds: function() { + return this.bounds; }, - getFields: function() { - return this.fields; - }, + paintNow: function() { + var self = this; + this.safePaintImmediately(function(gc) { + gc.clearRect(0, 0, self.canvas.width, self.canvas.height); - getHeaders: function() { - return ( - this.headers = this.headers || - this.getDefaultHeaders().map(function(each) { - return headerify(each); - }) - ); - }, + var comp = self._component; + if (comp) { + comp._paint(gc); + } - getDefaultHeaders: function() { - return this.getFields(); + self.dirty = false; + }); }, - setFields: function(fields) { - this.fields = fields; + safePaintImmediately: function(paintFunction) { + var useBitBlit = this.useBitBlit(), + gc = useBitBlit ? this.bufferGC : this.gc; + try { + gc.save(); + paintFunction(gc); + } catch (e) { + console.error(e); + } finally { + gc.restore(); + } + if (useBitBlit) { + this.flushBuffer(); + } }, - setHeaders: function(headers) { - if (!(headers instanceof Array)) { - error('setHeaders', 'param #1 `headers` not array'); + flushBuffer: function() { + if (this.buffer.width > 0 && this.buffer.height > 0) { + this.canvasCTX.drawImage(this.buffer, 0, 0); } - this.headers = headers; }, - getGrandTotals: function() { - //nothing here - return; + dispatchNewEvent: function(event, name, detail) { + detail = { + detail: detail || {} + }; + detail.detail.primitiveEvent = event; + return this.canvas.dispatchEvent(new CustomEvent(name, detail)); }, - setData: function(arrayOfUniformObjects) { - this.data = arrayOfUniformObjects; - } -}; - -function error(methodName, message) { - throw new Error('DataSource.' + methodName + ': ' + message); -} - -function computeFieldNames(object) { - if (!object) { - return []; - } - var fields = [].concat(Object.getOwnPropertyNames(object).filter(function(e) { - return e.substr(0, 2) !== '__'; - })); - return fields; -} - -module.exports = DataSource; -},{"./util/headerify":19}],10:[function(require,module,exports){ -'use strict'; - -var _ = require('object-iterators'); - -var DataSourceSorter = require('./DataSourceSorter'); -var DataNodeTree = require('./DataNodeTree'); -var DataNodeGroup = require('./DataNodeGroup'); -var DataNodeLeaf = require('./DataNodeLeaf'); -var headerify = require('./util/headerify'); - -//?[t,c,b,a] -// t is a dataSource, -// a is a dictionary of aggregates, columnName:function -// b is a dictionary of groupbys, columnName:sourceColumnName -// c is a list of constraints, - -function DataSourceAggregator(dataSource) { - this.dataSource = dataSource; - this.tree = new DataNodeTree('Totals'); - this.index = []; - this.aggregates = []; - this.headers = []; - this.groupBys = []; - this.view = []; - this.sorterInstance = {}; - this.presortGroups = true; - this.lastAggregate = {}; - this.setAggregates({}); -} - -DataSourceAggregator.prototype = { - constructor: DataSourceAggregator.prototype.constructor, // preserve constructor - - isNullObject: false, - - setAggregates: function(aggregations) { - this.lastAggregate = aggregations; - this.clearAggregations(); - this.headers.length = 0; + dispatchNewMouseKeysEvent: function(event, name, detail) { + detail = detail || {}; + detail.mouse = this.mouseLocation; + detail.keys = this.currentKeys; + return this.dispatchNewEvent(event, name, detail); + }, - if (this.hasGroups()) { - this.headers.push('Tree'); + finmousemove: function(e) { + if (!this.isDragging() && this.mousedown) { + this.beDragging(); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-dragstart', { + isRightClick: this.isRightClick(e) + }); + this.dragstart = new rectangular.Point(this.mouseLocation.x, this.mouseLocation.y); + } + this.mouseLocation = this.getLocal(e); + //console.log(this.mouseLocation); + if (this.isDragging()) { + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-drag', { + dragstart: this.dragstart, + isRightClick: this.isRightClick(e) + }); + } + if (this.bounds.contains(this.mouseLocation)) { + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-mousemove'); } - - var self = this; - _(aggregations).each(function(aggregation, key) { - self.addAggregate(key, aggregation); - }); }, - addAggregate: function(label, func) { - this.headers.push(headerify(label)); - this.aggregates.push(func); - }, + finmousedown: function(e) { + this.mouseLocation = this.getLocal(e); + this.mousedown = true; - setGroupBys: function(columnIndexArray) { - var groupBys = this.groupBys; - groupBys.length = 0; - columnIndexArray.forEach(function(columnIndex) { - groupBys.push(columnIndex); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-mousedown', { + isRightClick: this.isRightClick(e) }); - this.setAggregates(this.lastAggregate); + this.takeFocus(); }, - addGroupBy: function(index) { - this.groupBys.push(index); + finmouseup: function(e) { + if (this.isDragging()) { + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-dragend', { + dragstart: this.dragstart, + isRightClick: this.isRightClick(e) + }); + this.beNotDragging(); + this.dragEndtime = Date.now(); + } + this.mousedown = false; + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-mouseup', { + isRightClick: this.isRightClick(e) + }); + //this.mouseLocation = new rectangular.Point(-1, -1); }, - hasGroups: function() { - return !!this.groupBys.length; + finmouseout: function(e) { + if (!this.mousedown) { + this.mouseLocation = new rectangular.Point(-1, -1); + } + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-mouseout'); }, - hasAggregates: function() { - return !!this.aggregates.length; + finwheelmoved: function(e) { + if (this.isDragging() || !this.hasFocus()) { + return; + } + e.preventDefault(); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-wheelmoved', { + isRightClick: this.isRightClick(e) + }); }, - apply: function() { - this.buildGroupTree(); + finclick: function(e) { + if (Date.now() - this.lastClickTime < 250) { + //this is a double click... + this.findblclick(e); + return; + } + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-click', { + isRightClick: this.isRightClick(e) + }); + this.lastClickTime = Date.now(); }, - clearGroups: function() { - this.groupBys.length = 0; + finrelease: function(e) { + this.holdPulseCount = 0; + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-release'); }, - clearAggregations: function() { - this.aggregates.length = 0; - this.headers.length = 0; + finflick: function(e) { + if (!this.hasFocus()) { + return; + } + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-flick', { + isRightClick: this.isRightClick(e) + }); }, - buildGroupTree: function() { - var groupBys = this.groupBys, - leafDepth = groupBys.length - 1, - source = this.dataSource, - rowCount = source.getRowCount(), - tree = this.tree = new DataNodeTree('Totals'); - - // first sort data - if (this.presortGroups) { - groupBys.reverse().forEach(function(groupBy) { - source = new DataSourceSorter(source); - source.sortOn(groupBy); - }); + fintrackstart: function(e) { + if (!this.hasFocus()) { + return; } + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-trackstart'); + }, - for (var r = 0; r < rowCount; r++) { - var path = tree; - - groupBys.forEach(function(g, c) { // eslint-disable-line no-loop-func - var key = source.getValue(g, r), - terminalNode = (c === leafDepth), - Constructor = terminalNode ? DataNodeLeaf : DataNodeGroup, - ifAbsentFunc = createNode.bind(this, Constructor); - path = path.children.getIfAbsent(key, ifAbsentFunc); - }); - - path.index.push(r); + fintrack: function(e) { + if (!this.hasFocus()) { + return; } - - this.sorterInstance = new DataSourceSorter(source); - tree.prune(); - tree.computeAggregates(this); - this.buildView(); + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-track'); }, - addView: function(dataNode) { - this.view.push(dataNode); + fintrackend: function(e) { + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-trackend'); }, - buildView: function() { - this.view.length = 0; - this.tree.computeHeight(); - this.tree.buildView(this); + finhold: function(e) { + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-hold', { + isRightClick: this.isRightClick(e) + }); }, - viewMakesSense: function() { - return this.hasAggregates(); + finholdpulse: function(e) { + this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-holdpulse', { + count: this.holdPulseCount++ + }); }, - getValue: function(x, y) { - if (!this.viewMakesSense()) { - return this.dataSource.getValue(x, y); - } - var row = this.view[y]; - if (!row) { - return null; + fintap: function(e) { + //this nonsense is to hold a tap if it's really a double click + var self = this; + var now = Date.now(); + var dif = now - this.lastDoubleClickTime; + if (dif < 300) { + return; } - return row.getValue(x); // TODO: what kind of object is row... ? should it be unfiltred? - }, - - setValue: function(x, y, value) { - if (!this.viewMakesSense()) { - return this.dataSource.setValue(x, y, value); + //dragend is also causing a tap + //lets fix this here + if (now - this.dragEndtime < 100) { + return; } + setTimeout(function() { + self._fintap(e); + }, 180); }, - getColumnCount: function() { - if (!this.viewMakesSense()) { - return this.dataSource.getColumnCount(); + _fintap: function(e) { + //this nonsense is to hold a tap if it's really a double click + var now = Date.now(); + var dif = now - this.lastDoubleClickTime; + if (dif < 300) { + return; } - return this.getHeaders().length; + //this.mouseLocation = this.getLocal(e); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-tap', { + isRightClick: this.isRightClick(e) + }); }, - getRowCount: function() { - if (!this.viewMakesSense()) { - return this.dataSource.getRowCount(); - } - return this.view.length; //header column + findblclick: function(e) { + this.mouseLocation = this.getLocal(e); + this.lastDoubleClickTime = Date.now(); + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-dblclick', { + isRightClick: this.isRightClick(e) + }); + //console.log('dblclick', this.currentKeys); }, - click: function(y) { - var group = this.view[y]; - group.toggleExpansionState(this); - this.buildView(); + getCharMap: function() { //TODO: This is static. Make it a property of the constructor. + return charMap; }, - getHeaders: function() { - if (!this.viewMakesSense()) { - return this.dataSource.getHeaders(); + finkeydown: function(e) { + if (!this.hasFocus()) { + return; } - return this.headers; // TODO: Views override dataSource headers with their own headers? + + //e.preventDefault(); + var keyChar = e.shiftKey ? charMap[e.keyCode][1] : charMap[e.keyCode][0]; + if (e.repeat) { + if (this.repeatKey === keyChar) { + this.repeatKeyCount++; + } else { + this.repeatKey = keyChar; + this.repeatKeyStartTime = Date.now(); + } + } else { + this.repeatKey = null; + this.repeatKeyCount = 0; + this.repeatKeyStartTime = 0; + } + if (this.currentKeys.indexOf(keyChar) === -1) { + this.currentKeys.push(keyChar); + } + //console.log(keyChar, e.keyCode); + this.dispatchNewEvent(e, 'fin-canvas-keydown', { + alt: e.altKey, + ctrl: e.ctrlKey, + char: keyChar, + code: e.charCode, + key: e.keyCode, + meta: e.metaKey, + repeatCount: this.repeatKeyCount, + repeatStartTime: this.repeatKeyStartTime, + shift: e.shiftKey, + identifier: e.keyIdentifier, + currentKeys: this.currentKeys.slice(0) + }); }, - setHeaders: function(headers) { - this.dataSource.setHeaders(headers); + finkeyup: function(e) { + var keyChar = e.shiftKey ? charMap[e.keyCode][1] : charMap[e.keyCode][0]; + this.currentKeys.splice(this.currentKeys.indexOf(keyChar), 1); + if (!this.hasFocus()) { + return; + } + this.repeatKeyCount = 0; + this.repeatKey = null; + this.repeatKeyStartTime = 0; + this.dispatchNewEvent(e, 'fin-canvas-keyup', { + alt: e.altKey, + ctrl: e.ctrlKey, + char: keyChar, + code: e.charCode, + key: e.keyCode, + meta: e.metaKey, + repeat: e.repeat, + shift: e.shiftKey, + identifier: e.keyIdentifier, + currentKeys: this.currentKeys.slice(0) + }); }, - getFields: function() { - return this.dataSource.getFields(); + finfocusgained: function(e) { + this.dispatchNewEvent(e, 'fin-canvas-focus-gained'); }, - setFields: function(fields) { - return this.dataSource.setFields(fields); + finfocuslost: function(e) { + this.dispatchNewEvent(e, 'fin-canvas-focus-lost'); }, - getGrandTotals: function() { - var view = this.tree; - return [view.data]; + fincontextmenu: function(e) { + if (e.ctrlKey && this.currentKeys.indexOf('CTRL') === -1) { + this.currentKeys.push('CTRL'); + } + if (Date.now() - this.lastClickTime < 250) { + //this is a double click... + this.findblclick(e); + return; + } + this.dispatchNewMouseKeysEvent(e, 'fin-canvas-context-menu', { + isRightClick: this.isRightClick(e) + }); + this.lastClickTime = Date.now(); }, - getRow: function(y) { - if (!this.viewMakesSense()) { - return this.dataSource.getRow(y); + repaint: function() { + var fps = this.getFPS(); + this.dirty = true; + if (!paintLoopRunning || fps === 0) { + this.paintNow(); } + }, - var rollups = this.view[y]; + getMouseLocation: function() { + return this.mouseLocation; + }, - return rollups ? rollups : this.tree; + getOrigin: function() { + var rect = this.canvas.getBoundingClientRect(); + var p = new rectangular.Point(rect.left, rect.top); + return p; }, - setData: function(arrayOfUniformObjects) { - this.dataSource.setData(arrayOfUniformObjects); - this.apply(); - } -}; + getLocal: function(e) { + var rect = this.canvas.getBoundingClientRect(); + var p = new rectangular.Point(e.clientX - rect.left, e.clientY - rect.top); + return p; + }, -function createNode(DataNodeConstructor, key, map) { - var value = new DataNodeConstructor(key); - map.set(key, value); - return value; -} + hasFocus: function() { + return document.activeElement === this.canvas; + }, -module.exports = DataSourceAggregator; -},{"./DataNodeGroup":6,"./DataNodeLeaf":7,"./DataNodeTree":8,"./DataSourceSorter":14,"./util/headerify":19,"object-iterators":24}],11:[function(require,module,exports){ -'use strict'; + takeFocus: function() { + var self = this; + if (!this.hasFocus()) { + setTimeout(function() { + self.canvas.focus(); + }, 10); + } + }, -var DataSourceIndexed = require('./DataSourceIndexed'); + beDragging: function() { + this.dragging = true; + this.disableDocumentElementSelection(); + }, -var DataSourceFilter = DataSourceIndexed.extend('DataSourceFilter', { + beNotDragging: function() { + this.dragging = false; + this.enableDocumentElementSelection(); + }, - initialize: function() { - this.filters = []; + isDragging: function() { + return this.dragging; }, - add: function(columnIndex, filter) { - filter.columnIndex = columnIndex; - this.filters.push(filter); + disableDocumentElementSelection: function() { + var style = document.body.style; + style.cssText = style.cssText + '-webkit-user-select: none'; }, - clearAll: function() { - this.filters.length = 0; - this.clearIndex(); + enableDocumentElementSelection: function() { + var style = document.body.style; + style.cssText = style.cssText.replace('-webkit-user-select: none', ''); }, - applyAll: function() { - if (!this.filters.length) { - this.clearIndex(); - } else { - this.buildIndex(applyFilters); - } + setFocusable: function(truthy) { + this.focuser.style.display = truthy ? '' : 'none'; }, - getRowCount: function() { - return this.filters.length ? this.index.length : this.dataSource.getRowCount(); + isRightClick: function(e) { + var isRightMB; + e = e || window.event; + + if ('which' in e) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera + isRightMB = e.which === 3; + } else if ('button' in e) { // IE, Opera + isRightMB = e.button === 2; + } + return isRightMB; }, - aliases: { - set: 'add' + dispatchEvent: function(e) { + return this.canvas.dispatchEvent(e); } -}); +}; -function applyFilters(r, rowObject) { // called in context from .buildIndex() - var self = this; +function paintLoopFunction(now) { + if (!paintLoopRunning) { + return; + } + for (var i = 0; i < paintables.length; i++) { + try { + paintables[i].tickPainter(now); + } catch (e) { + console.error(e); + } + } + requestAnimationFrame(paintLoopFunction); +} +requestAnimationFrame(paintLoopFunction); - if (Array.prototype.find) { - // double negative here means "no filter fails" (i.e., row passes all filters) - return !this.filters.find(function(filter) { - return !filter(self.dataSource.getValue(filter.columnIndex, r), rowObject, r); - }); - } else { - return this.filters.reduce(function(isFiltered, filter) { - return isFiltered && filter(self.dataSource.getValue(filter.columnIndex, r), rowObject, r); - }, true); +function resizablesLoopFunction(now) { + if (!resizeLoopRunning) { + return; + } + for (var i = 0; i < resizables.length; i++) { + try { + resizables[i].tickResizer(now); + } catch (e) { + console.error(e); + } } } +setInterval(resizablesLoopFunction, RESIZE_POLLING_INTERVAL); -module.exports = DataSourceFilter; +function makeCharMap() { + var map = []; -},{"./DataSourceIndexed":13}],12:[function(require,module,exports){ -'use strict'; + var empty = ['', '']; -var DataSourceIndexed = require('./DataSourceIndexed'); - -var DataSourceGlobalFilter = DataSourceIndexed.extend('DataSourceGlobalFilter', { - - set: function(filter) { - this.filter = filter; - }, - - clear: function() { - delete this.filter; - this.clearIndex(); - }, + for (var i = 0; i < 256; i++) { + map[i] = empty; + } - apply: function() { - if (!this.filter) { - this.clearIndex(); - } else { - this.buildIndex(applyFilter); - } - }, + map[27] = ['ESC', 'ESCSHIFT']; + map[192] = ['`', '~']; + map[49] = ['1', '!']; + map[50] = ['2', '@']; + map[51] = ['3', '#']; + map[52] = ['4', '$']; + map[53] = ['5', '%']; + map[54] = ['6', '^']; + map[55] = ['7', '&']; + map[56] = ['8', '*']; + map[57] = ['9', '(']; + map[48] = ['0', ')']; + map[189] = ['-', '_']; + map[187] = ['=', '+']; + map[8] = ['DELETE', 'DELETESHIFT']; + map[9] = ['TAB', 'TABSHIFT']; + map[81] = ['q', 'Q']; + map[87] = ['w', 'W']; + map[69] = ['e', 'E']; + map[82] = ['r', 'R']; + map[84] = ['t', 'T']; + map[89] = ['y', 'Y']; + map[85] = ['u', 'U']; + map[73] = ['i', 'I']; + map[79] = ['o', 'O']; + map[80] = ['p', 'P']; + map[219] = ['[', '{']; + map[221] = [']', '}']; + map[220] = ['\\', '|']; + map[220] = ['CAPSLOCK', 'CAPSLOCKSHIFT']; + map[65] = ['a', 'A']; + map[83] = ['s', 'S']; + map[68] = ['d', 'D']; + map[70] = ['f', 'F']; + map[71] = ['g', 'G']; + map[72] = ['h', 'H']; + map[74] = ['j', 'J']; + map[75] = ['k', 'K']; + map[76] = ['l', 'L']; + map[186] = [';', ':']; + map[222] = ['\'', '|']; + map[13] = ['RETURN', 'RETURNSHIFT']; + map[16] = ['SHIFT', 'SHIFT']; + map[90] = ['z', 'Z']; + map[88] = ['x', 'X']; + map[67] = ['c', 'C']; + map[86] = ['v', 'V']; + map[66] = ['b', 'B']; + map[78] = ['n', 'N']; + map[77] = ['m', 'M']; + map[188] = [',', '<']; + map[190] = ['.', '>']; + map[191] = ['/', '?']; + map[16] = ['SHIFT', 'SHIFT']; + map[17] = ['CTRL', 'CTRLSHIFT']; + map[18] = ['ALT', 'ALTSHIFT']; + map[91] = ['COMMANDLEFT', 'COMMANDLEFTSHIFT']; + map[32] = ['SPACE', 'SPACESHIFT']; + map[93] = ['COMMANDRIGHT', 'COMMANDRIGHTSHIFT']; + map[18] = ['ALT', 'ALTSHIFT']; + map[38] = ['UP', 'UPSHIFT']; + map[37] = ['LEFT', 'LEFTSHIFT']; + map[40] = ['DOWN', 'DOWNSHIFT']; + map[39] = ['RIGHT', 'RIGHTSHIFT']; - getRowCount: function() { - return this.filter ? this.index.length : this.dataSource.getRowCount(); - } -}); + map[33] = ['PAGEUP', 'PAGEUPSHIFT']; + map[34] = ['PAGEDOWN', 'PAGEDOWNSHIFT']; + map[35] = ['PAGERIGHT', 'PAGERIGHTSHIFT']; + map[36] = ['PAGELEFT', 'PAGELEFTSHIFT']; -function applyFilter(r, rowObject) { // called in context from .buildIndex() - var self = this; - return this.getFields().find(function(columnIndex) { - var cellValue = self.dataSource.getValue(columnIndex, r); - return self.filter(cellValue, rowObject, r); - }); + return map; } -module.exports = DataSourceGlobalFilter; -},{"./DataSourceIndexed":13}],13:[function(require,module,exports){ -'use strict'; +module.exports = Canvas; -var Base = require('extend-me').Base; +},{"./js/GraphicsContext.js":6,"./js/polymergestures.dev.js":8,"rectangular":29}],6:[function(require,module,exports){ +'use strict'; -var DataSourceIndexed = Base.extend('DataSourceIndexed', { +var consoleLogger = require('./gc-console-logger'); - isNullObject: false, +/** + * @constructor + * @param gc - The 2-D graphics context from your canvas + * @param {boolean|apiLogger} [logger=true] + * * `true` uses `gc-console-logger` function bound to 'gc.' as prefix + * * string uses `gc-console-logger` function bound to string + * * function used as is + */ +function GraphicsContext(gc, logger) { + this.gc = gc; - initialize: function(dataSource) { - this.dataSource = dataSource; - this.index = []; - }, + var self = this; + var reWEBKIT = /^webkit/; - transposeY: function(y) { - return this.index.length ? this.index[y] : y; - }, + switch (typeof logger) { - getRow: function(y) { - return this.dataSource.getRow(this.transposeY(y)); - }, + case 'string': + logger = consoleLogger.bind(undefined, logger + '.'); + break; - getValue: function(x, y) { - return this.dataSource.getValue(x, this.transposeY(y)); - }, + case 'boolean': + if (logger === true) { + logger = consoleLogger.bind(undefined, 'gc.'); + } + break; - setValue: function(x, y, value) { - this.dataSource.setValue(x, this.transposeY(y), value); - }, + case 'function': + if (logger.length !== 3) { + throw 'GraphicsContext: User-supplied API logger function does not accept three parameters.'; + } + break; - getRowCount: function() { - return this.index.length || this.dataSource.getRowCount(); - }, + default: + logger = false; + } - getColumnCount: function() { - return this.dataSource.getColumnCount(); - }, + // Stub out all the prototype members of the canvas 2D graphics context: + Object.keys(Object.getPrototypeOf(gc)).forEach(MakeStub); - getFields: function() { - return this.dataSource.getFields(); - }, + // Some older browsers (e.g., Chrome 40) did not have all members of canvas + // 2D graphics context in the prototype so we make this additional call: + Object.keys(gc).forEach(MakeStub); - setFields: function(fields) { - return this.dataSource.setFields(fields); - }, + function MakeStub(key) { + if (key in GraphicsContext.prototype || reWEBKIT.test(key)) { + return; + } + if (typeof gc[key] === 'function') { + self[key] = !logger ? gc[key].bind(gc) : function() { + return logger(key, arguments, gc[key].apply(gc, arguments)); + }; + } else { + Object.defineProperty(self, key, { + get: function() { + var result = gc[key]; + return logger ? logger(key, 'getter', result) : result; + }, + set: function(value) { + gc[key] = logger ? logger(key, 'setter', value) : value; + } + }); + } + } +} - getDefaultHeaders: function() { - return this.dataSource.getFields(); - }, +module.exports = GraphicsContext; - setHeaders: function(headers) { - return this.dataSource.setHeaders(headers); - }, +},{"./gc-console-logger":7}],7:[function(require,module,exports){ +'use strict'; - getHeaders: function() { - return this.dataSource.getHeaders(); - }, +var YIELDS = '\u27F9'; // LONG RIGHTWARDS DOUBLE ARROW - getGrandTotals: function() { - return this.dataSource.getGrandTotals(); - }, +function consoleLogger(prefix, name, args, value) { + var result = value; - setData: function(arrayOfUniformObjects) { - return this.dataSource.setData(arrayOfUniformObjects); - }, + if (typeof value === 'string') { + result = '"' + result + '"'; + } - clearIndex: function() { - this.index.length = 0; - }, + name = prefix + name; - buildIndex: function(predicate) { - var rowCount = this.dataSource.getRowCount(), - index = this.index; + switch (args) { + case 'getter': + console.log(name, '=', result); + break; - index.length = 0; + case 'setter': + console.log(name, YIELDS, result); + break; - for (var r = 0; r < rowCount; r++) { - if (!predicate || predicate.call(this, r, this.dataSource.getRow(r))) { - index.push(r); + default: // method call + name += '(' + Array.prototype.slice.call(args).join(', ') + ')'; + if (result === undefined) { + console.log(name); + } else { + console.log(name, YIELDS, result); } - } - - return index; } -}); - -module.exports = DataSourceIndexed; + return value; +} -},{"extend-me":3}],14:[function(require,module,exports){ -'use strict'; +module.exports = consoleLogger; -var DataSourceIndexed = require('./DataSourceIndexed'); -var stableSort = require('./util/stableSort'); +},{}],8:[function(require,module,exports){ +/* eslint-disable */ -var DataSourceSorter = DataSourceIndexed.extend('DataSourceSorter', { - initialize: function() { - this.descendingSort = false; // TODO: this does not seem to be in use - }, +/** + * @license + * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. + * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt + * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt + * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt + * Code distributed by Google as part of the polymer project is also + * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt + */ +//module.exports = {}; - sortOn: function(colIdx, direction) { - switch (direction) { - case 0: - this.clearIndex(); - break; +(function(scope) { + var hasFullPath = false; - case undefined: - case 1: - case -1: - var self = this; // for use in getValue - stableSort.sort(this.buildIndex(), getValue, direction); - break; - } + // test for full event path support + var pathTest = document.createElement('meta'); + if (pathTest.createShadowRoot) { + var sr = pathTest.createShadowRoot(); + var s = document.createElement('span'); + sr.appendChild(s); + pathTest.addEventListener('testpath', function(ev) { + if (ev.path) { + // if the span is in the event path, then path[0] is the real source for all events + hasFullPath = ev.path[0] === s; + } + ev.stopPropagation(); + }); + var ev = new CustomEvent('testpath', { + bubbles: true + }); + // must add node to DOM to trigger event listener + document.head.appendChild(pathTest); + s.dispatchEvent(ev); + pathTest.parentNode.removeChild(pathTest); + sr = s = null; + } + pathTest = null; - function getValue(rowIdx) { - return valOrFuncCall(self.dataSource.getValue(colIdx, rowIdx)); + var target = { + shadow: function(inEl) { + if (inEl) { + return inEl.shadowRoot || inEl.webkitShadowRoot; + } + }, + canTarget: function(shadow) { + return shadow && Boolean(shadow.elementFromPoint); + }, + targetingShadow: function(inEl) { + var s = this.shadow(inEl); + if (this.canTarget(s)) { + return s; + } + }, + olderShadow: function(shadow) { + var os = shadow.olderShadowRoot; + if (!os) { + var se = shadow.querySelector('shadow'); + if (se) { + os = se.olderShadowRoot; + } + } + return os; + }, + allShadows: function(element) { + var shadows = [], + s = this.shadow(element); + while (s) { + shadows.push(s); + s = this.olderShadow(s); + } + return shadows; + }, + searchRoot: function(inRoot, x, y) { + var t, st, sr, os; + if (inRoot) { + t = inRoot.elementFromPoint(x, y); + if (t) { + // found element, check if it has a ShadowRoot + sr = this.targetingShadow(t); + } else if (inRoot !== document) { + // check for sibling roots + sr = this.olderShadow(inRoot); + } + // search other roots, fall back to light dom element + return this.searchRoot(sr, x, y) || t; + } + }, + owner: function(element) { + if (!element) { + return document; + } + var s = element; + // walk up until you hit the shadow root or document + while (s.parentNode) { + s = s.parentNode; + } + // the owner element is expected to be a Document or ShadowRoot + if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGMENT_NODE) { + s = document; + } + return s; + }, + findTarget: function(inEvent) { + if (hasFullPath && inEvent.path && inEvent.path.length) { + return inEvent.path[0]; + } + var x = inEvent.clientX, + y = inEvent.clientY; + // if the listener is in the shadow root, it is much faster to start there + var s = this.owner(inEvent.target); + // if x, y is not in this root, fall back to document search + if (!s.elementFromPoint(x, y)) { + s = document; + } + return this.searchRoot(s, x, y); + }, + findTouchAction: function(inEvent) { + var n; + if (hasFullPath && inEvent.path && inEvent.path.length) { + var path = inEvent.path; + for (var i = 0; i < path.length; i++) { + n = path[i]; + if (n.nodeType === Node.ELEMENT_NODE && n.hasAttribute('touch-action')) { + return n.getAttribute('touch-action'); + } + } + } else { + n = inEvent.target; + while (n) { + if (n.nodeType === Node.ELEMENT_NODE && n.hasAttribute('touch-action')) { + return n.getAttribute('touch-action'); + } + n = n.parentNode || n.host; + } + } + // auto is default + return "auto"; + }, + LCA: function(a, b) { + if (a === b) { + return a; + } + if (a && !b) { + return a; + } + if (b && !a) { + return b; + } + if (!b && !a) { + return document; + } + // fast case, a is a direct descendant of b or vice versa + if (a.contains && a.contains(b)) { + return a; + } + if (b.contains && b.contains(a)) { + return b; + } + var adepth = this.depth(a); + var bdepth = this.depth(b); + var d = adepth - bdepth; + if (d >= 0) { + a = this.walk(a, d); + } else { + b = this.walk(b, -d); + } + while (a && b && a !== b) { + a = a.parentNode || a.host; + b = b.parentNode || b.host; + } + return a; + }, + walk: function(n, u) { + for (var i = 0; n && (i < u); i++) { + n = n.parentNode || n.host; + } + return n; + }, + depth: function(n) { + var d = 0; + while (n) { + d++; + n = n.parentNode || n.host; + } + return d; + }, + deepContains: function(a, b) { + var common = this.LCA(a, b); + // if a is the common ancestor, it must "deeply" contain b + return common === a; + }, + insideNode: function(node, x, y) { + var rect = node.getBoundingClientRect(); + return (rect.left <= x) && (x <= rect.right) && (rect.top <= y) && (y <= rect.bottom); + }, + path: function(event) { + var p; + if (hasFullPath && event.path && event.path.length) { + p = event.path; + } else { + p = []; + var n = this.findTarget(event); + while (n) { + p.push(n); + n = n.parentNode || n.host; + } + } + return p; } - } -}); - -function valOrFuncCall(valOrFunc) { - return typeof valOrFunc === 'function' ? valOrFunc() : valOrFunc; -} - -module.exports = DataSourceSorter; -},{"./DataSourceIndexed":13,"./util/stableSort":20}],15:[function(require,module,exports){ -'use strict'; - -var DataSourceIndexed = require('./DataSourceIndexed'); -var DataSourceSorter = require('./DataSourceSorter'); - -var DataSourceSorterComposite = DataSourceIndexed.extend('DataSourceSorterComposite', { - initialize: function() { - this.sorts = []; - this.last = this.dataSource; - }, - - // Caveats regarding this.sorts: - // 1. Columns should be uniquely represented (i.e., no repeats with same columnIndex) - // 2. Columns should be added low- to high-order (i.e., most grouped columns come last) - sortOn: function(columnIndex, direction) { - this.sorts.push([columnIndex, direction]); - }, + }; + scope.targetFinding = target; + /** + * Given an event, finds the "deepest" node that could have been the original target before ShadowDOM retargetting + * + * @param {Event} Event An event object with clientX and clientY properties + * @return {Element} The probable event origninator + */ + scope.findTarget = target.findTarget.bind(target); + /** + * Determines if the "container" node deeply contains the "containee" node, including situations where the "containee" is contained by one or more ShadowDOM + * roots. + * + * @param {Node} container + * @param {Node} containee + * @return {Boolean} + */ + scope.deepContains = target.deepContains.bind(target); - applySorts: function() { - var each = this.dataSource; + /** + * Determines if the x/y position is inside the given node. + * + * Example: + * + * function upHandler(event) { + * var innode = PolymerGestures.insideNode(event.target, event.clientX, event.clientY); + * if (innode) { + * // wait for tap? + * } else { + * // tap will never happen + * } + * } + * + * @param {Node} node + * @param {Number} x Screen X position + * @param {Number} y screen Y position + * @return {Boolean} + */ + scope.insideNode = target.insideNode; - this.sorts.forEach(function(sort) { - each = new DataSourceSorter(each); - each.sortOn.apply(each, sort); - }); +})(exports); - this.last = each; - }, +(function() { + function shadowSelector(v) { + return 'html /deep/ ' + selector(v); + } - clearSorts: function() { - this.sorts.length = 0; - this.last = this.dataSource; - }, + function selector(v) { + return '[touch-action="' + v + '"]'; + } - getValue: function(x, y) { - return this.last.getValue(x, y); - }, - - setValue: function(x, y, value) { - this.last.setValue(x, y, value); + function rule(v) { + return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + ';}'; } -}); + var attrib2css = [ + 'none', + 'auto', + 'pan-x', + 'pan-y', { + rule: 'pan-x pan-y', + selectors: [ + 'pan-x pan-y', + 'pan-y pan-x' + ] + }, + 'manipulation' + ]; + var styles = ''; + // only install stylesheet if the browser has touch action support + var hasTouchAction = typeof document.head.style.touchAction === 'string'; + // only add shadow selectors if shadowdom is supported + var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoot; -module.exports = DataSourceSorterComposite; -},{"./DataSourceIndexed":13,"./DataSourceSorter":14}],16:[function(require,module,exports){ -'use strict'; + if (hasTouchAction) { + attrib2css.forEach(function(r) { + if (String(r) === r) { + styles += selector(r) + rule(r) + '\n'; + if (hasShadowRoot) { + styles += shadowSelector(r) + rule(r) + '\n'; + } + } else { + styles += r.selectors.map(selector) + rule(r.rule) + '\n'; + if (hasShadowRoot) { + styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n'; + } + } + }); -module.exports = { - JSDataSource: require('./DataSource'), - DataSourceSorter: require('./DataSourceSorter'), - DataSourceSorterComposite: require('./DataSourceSorterComposite'), - DataSourceFilter: require('./DataSourceFilter'), - DataSourceGlobalFilter: require('./DataSourceGlobalFilter'), - DataSourceAggregator: require('./DataSourceAggregator'), - util: { - aggregations: require('./util/aggregations') + var el = document.createElement('style'); + el.textContent = styles; + document.head.appendChild(el); } -}; -},{"./DataSource":9,"./DataSourceAggregator":10,"./DataSourceFilter":11,"./DataSourceGlobalFilter":12,"./DataSourceSorter":14,"./DataSourceSorterComposite":15,"./util/aggregations":18}],17:[function(require,module,exports){ -'use strict'; +})(); -function Mappy() { - this.keys = []; - this.data = {}; - this.values = []; -} +/** + * This is the constructor for new PointerEvents. + * + * New Pointer Events must be given a type, and an optional dictionary of + * initialization properties. + * + * Due to certain platform requirements, events returned from the constructor + * identify as MouseEvents. + * + * @constructor + * @param {String} inType The type of the event to create. + * @param {Object} [inDict] An optional dictionary of initial event properties. + * @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`. + */ +(function(scope) { -Mappy.prototype = { + var MOUSE_PROPS = [ + 'bubbles', + 'cancelable', + 'view', + 'detail', + 'screenX', + 'screenY', + 'clientX', + 'clientY', + 'ctrlKey', + 'altKey', + 'shiftKey', + 'metaKey', + 'button', + 'relatedTarget', + 'pageX', + 'pageY' + ]; - constructor: Mappy.prototype.constructor, // preserve constructor + var MOUSE_DEFAULTS = [ + false, + false, + null, + null, + 0, + 0, + 0, + 0, + false, + false, + false, + false, + 0, + null, + 0, + 0 + ]; - set: function(key, value) { - var hashCode = hash(key); - if (!(hashCode in this.data)) { - this.keys.push(key); - this.values.push(value); - } - this.data[hashCode] = value; - }, + var NOP_FACTORY = function() { + return function() {}; + }; - get: function(key) { - var hashCode = hash(key); - return this.data[hashCode]; - }, + var eventFactory = { + // TODO(dfreedm): this is overridden by tap recognizer, needs review + preventTap: NOP_FACTORY, + makeBaseEvent: function(inType, inDict) { + var e = document.createEvent('Event'); + e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false); + e.preventTap = eventFactory.preventTap(e); + return e; + }, + makeGestureEvent: function(inType, inDict) { + inDict = inDict || Object.create(null); - getIfAbsent: function(key, ifAbsentFunc) { - var value = this.get(key); - if (value === undefined) { - value = ifAbsentFunc(key, this); - } - return value; - }, + var e = this.makeBaseEvent(inType, inDict); + for (var i = 0, keys = Object.keys(inDict), k; i < keys.length; i++) { + k = keys[i]; + if (k !== 'bubbles' && k !== 'cancelable') { + e[k] = inDict[k]; + } + } + return e; + }, + makePointerEvent: function(inType, inDict) { + inDict = inDict || Object.create(null); - size: function() { - return this.keys.length; - }, + var e = this.makeBaseEvent(inType, inDict); + // define inherited MouseEvent properties + for (var i = 2, p; i < MOUSE_PROPS.length; i++) { + p = MOUSE_PROPS[i]; + e[p] = inDict[p] || MOUSE_DEFAULTS[i]; + } + e.buttons = inDict.buttons || 0; - clear: function() { - this.keys.length = 0; - // TODO: Is there a reason why this.values is not being truncated here as well? - this.data = {}; - }, + // Spec requires that pointers without pressure specified use 0.5 for down + // state and 0 for up state. + var pressure = 0; + if (inDict.pressure) { + pressure = inDict.pressure; + } else { + pressure = e.buttons ? 0.5 : 0; + } - delete: function(key) { - var hashCode = hash(key); - if (this.data[hashCode] !== undefined) { - var index = betterIndexOf(this.keys, key); - this.keys.splice(index, 1); - this.values.splice(index, 1); - delete this.data[hashCode]; + // add x/y properties aliased to clientX/Y + e.x = e.clientX; + e.y = e.clientY; + + // define the properties of the PointerEvent interface + e.pointerId = inDict.pointerId || 0; + e.width = inDict.width || 0; + e.height = inDict.height || 0; + e.pressure = pressure; + e.tiltX = inDict.tiltX || 0; + e.tiltY = inDict.tiltY || 0; + e.pointerType = inDict.pointerType || ''; + e.hwTimestamp = inDict.hwTimestamp || 0; + e.isPrimary = inDict.isPrimary || false; + e._source = inDict._source || ''; + return e; } - }, + }; - forEach: function(func) { - var keys = this.keys, - self = this; - keys.forEach(function(key) { - var value = self.get(key); - func(value, key, self); - }); - }, + scope.eventFactory = eventFactory; +})(exports); - map: function(func) { - var keys = this.keys, - newMap = new Mappy(), - self = this; - keys.forEach(function(key) { - var value = self.get(key), - transformed = func(value, key, self); - newMap.set(key, transformed); - }); - return newMap; - }, +/** + * This module implements an map of pointer states + */ +(function(scope) { + var USE_MAP = window.Map && window.Map.prototype.forEach; + var POINTERS_FN = function() { + return this.size; + }; - copy: function() { - var keys = this.keys, - newMap = new Mappy(), - self = this; - keys.forEach(function(key) { - var value = self.get(key); - newMap.set(key, value); - }); - return newMap; + function PointerMap() { + if (USE_MAP) { + var m = new Map(); + m.pointers = POINTERS_FN; + return m; + } else { + this.keys = []; + this.values = []; + } } -}; - -var OID_PREFIX = '.~.#%_'; //this should be something we never will see at the beginning of a string -var counter = 0; - -function hash(key) { - var typeOf = typeof key; - - switch (typeOf) { - case 'number': - case 'string': - case 'boolean': - case 'symbol': - return OID_PREFIX + typeOf + '_' + key; - - case 'undefined': - return OID_PREFIX + 'undefined'; - - case 'object': - // TODO: what about handling null (special case of object)? - case 'function': - return (key.___finhash = key.___finhash || OID_PREFIX + counter++); // eslint-disable-line - } -} - -// Object.is polyfill, courtesy of @WebReflection -var is = Object.is || function(a, b) { - return a === b ? a !== 0 || 1 / a == 1 / b : a != a && b != b; // eslint-disable-line -}; - -// More reliable indexOf, courtesy of @WebReflection -function betterIndexOf(arr, value) { - if (value != value || value === 0) { // eslint-disable-line - for (var i = arr.length; i-- && !is(arr[i], value);) { // eslint-disable-line + PointerMap.prototype = { + set: function(inId, inEvent) { + var i = this.keys.indexOf(inId); + if (i > -1) { + this.values[i] = inEvent; + } else { + this.keys.push(inId); + this.values.push(inEvent); + } + }, + has: function(inId) { + return this.keys.indexOf(inId) > -1; + }, + 'delete': function(inId) { + var i = this.keys.indexOf(inId); + if (i > -1) { + this.keys.splice(i, 1); + this.values.splice(i, 1); + } + }, + get: function(inId) { + var i = this.keys.indexOf(inId); + return this.values[i]; + }, + clear: function() { + this.keys.length = 0; + this.values.length = 0; + }, + // return value, key, map + forEach: function(callback, thisArg) { + this.values.forEach(function(v, i) { + callback.call(thisArg, v, this.keys[i], this); + }, this); + }, + pointers: function() { + return this.keys.length; } - } else { - i = [].indexOf.call(arr, value); - } - return i; -} - -module.exports = Mappy; -},{}],18:[function(require,module,exports){ -'use strict'; - -function count(group) { - return group.getRowCount(); -} - -function sum(columnIndex, group) { - var r = group.getRowCount(), - n = 0; - - while (r--) { - n += group.getValue(columnIndex, r); - } - - return n; -} - -function minmax(columnIndex, method, n, group) { - var r = group.getRowCount(); - - while (r--) { - n = method(n, group.getValue(columnIndex, r)); - } - - return n; -} - -function avg(columnIndex, group) { - return sum(columnIndex, group) / group.getRowCount(); -} - -function first(columnIndex, group) { - return group.getValue(columnIndex, 0); -} - -function last(columnIndex, group) { - return group.getValue(columnIndex, group.getRowCount() - 1); -} - -function stddev(columnIndex, group) { - var rows = group.getRowCount(), - mean = avg(columnIndex, group); - - for (var dev, r = rows, variance = 0; r--; variance += dev * dev) { - dev = group.getValue(columnIndex, r) - mean; - } + }; - return Math.sqrt(variance / rows); -} + scope.PointerMap = PointerMap; +})(exports); -module.exports = { - count: function(columnIndex) { - return count; - }, - sum: function(columnIndex) { - return sum.bind(this, columnIndex); - }, - min: function(columnIndex) { - return minmax.bind(this, columnIndex, Math.min, Infinity); - }, - max: function(columnIndex) { - return minmax.bind(this, columnIndex, Math.max, -Infinity); - }, - avg: function(columnIndex) { - return avg.bind(this, columnIndex); - }, - first: function(columnIndex) { - return first.bind(this, columnIndex); - }, - last: function(columnIndex) { - return last.bind(this, columnIndex); - }, - stddev: function(columnIndex) { - return stddev.bind(this, columnIndex); - } -}; -},{}],19:[function(require,module,exports){ -'use strict'; +(function(scope) { + var CLONE_PROPS = [ + // MouseEvent + 'bubbles', + 'cancelable', + 'view', + 'detail', + 'screenX', + 'screenY', + 'clientX', + 'clientY', + 'ctrlKey', + 'altKey', + 'shiftKey', + 'metaKey', + 'button', + 'relatedTarget', + // DOM Level 3 + 'buttons', + // PointerEvent + 'pointerId', + 'width', + 'height', + 'pressure', + 'tiltX', + 'tiltY', + 'pointerType', + 'hwTimestamp', + 'isPrimary', + // event instance + 'type', + 'target', + 'currentTarget', + 'which', + 'pageX', + 'pageY', + 'timeStamp', + // gesture addons + 'preventTap', + 'tapPrevented', + '_source' + ]; -function headerify(string) { - return (/[a-z]/.test(string) ? string : string.toLowerCase()) - .replace(/[\s\-_]*([^\s\-_])([^\s\-_]+)/g, replacer) - .replace(/[A-Z]/g, ' $&') - .trim(); -} + var CLONE_DEFAULTS = [ + // MouseEvent + false, + false, + null, + null, + 0, + 0, + 0, + 0, + false, + false, + false, + false, + 0, + null, + // DOM Level 3 + 0, + // PointerEvent + 0, + 0, + 0, + 0, + 0, + 0, + '', + 0, + false, + // event instance + '', + null, + null, + 0, + 0, + 0, + 0, + function() {}, + false + ]; -function replacer(a, b, c) { - return b.toUpperCase() + c; -} + var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined'); -module.exports = headerify; -},{}],20:[function(require,module,exports){ -'use strict'; + var eventFactory = scope.eventFactory; -function stabilize(comparator, descending, arr1, arr2) { // eslint-disable-line no-shadow - var x = arr1[0]; - var y = arr2[0]; - - if (x === y) { - x = descending ? arr2[1] : arr1[1]; - y = descending ? arr1[1] : arr2[1]; - } else { - if (y === null) { - return -1; - } - if (x === null) { - return 1; - } - } - - return comparator(x, y); -} - -function ascendingNumbers(x, y) { - return x - y; -} - -function descendingNumbers(x, y) { - return y - x; -} - -function ascendingAllOthers(x, y) { - return x < y ? -1 : 1; -} - -function descendingAllOthers(x, y) { - return y < x ? -1 : 1; -} - -function ascending(typeOfData) { - return stabilize.bind(this, typeOfData === 'number' ? ascendingNumbers : ascendingAllOthers, false); -} - -function descending(typeOfData) { - return stabilize.bind(this, typeOfData === 'number' ? descendingNumbers : descendingAllOthers, true); -} - -function sort(index, getValue, direction) { - - var compare, i; - - // apply defaults - if (direction === undefined) { - direction = 1; - } - - if (index.length) { // something to do - switch (direction) { - case 0: - return; // bail: nothing to sort - - case undefined: // eslint-disable-line no-fallthrough - direction = 1; - case 1: - compare = ascending(typeof getValue(0)); - break; - - case -1: - compare = descending(typeof getValue(0)); - break; - } - - // set up the sort..... - var tmp = new Array(index.length); - - // add the index for "stability" - for (i = 0; i < index.length; i++) { - tmp[i] = [getValue(i), i]; - } - - // do the actual sort - tmp.sort(compare); - - // copy the sorted values into our index vector - for (i = 0; i < index.length; i++) { - index[i] = tmp[i][1]; - } - } - -} - -exports.sort = sort; -},{}],21:[function(require,module,exports){ -// list-dragon node module -// https://github.com/openfin/list-dragon - -'use strict'; - -/* eslint-env node, browser */ - -(function (module) { // eslint-disable-line no-unused-expressions - - // This closure supports NodeJS-less client side includes with `. - * For custom namespace, such as `window.namespace.rectangular`: - * ```html - * - * - * - * ``` - * 2. File was reorganized to use prototypal inheritance so: - * a. Change `finrectangle.point.create(...)` to `new rectangular.Point(...)` - * b. Change `finrectangle.rectangle.create(...)` to `new rectangular.Rectangle(...)` - * 3. Change all invocations of `Rectangle.top`, `.left`, `.bottom`, `.right`, `.width`, - * `.height`, and `.area` to getter references by removing the invocation operator - * (i.e., the parentheses). - * 4. Change all invocations of `.isContainedWithinRectangle()` to `.within()`. - * 5. Change all invocations of `.equal()` to `.equals()`. - * 6. Change all invocations of `.lessThanEqualTo()` to `.lessThanOrEqualTo()`. - * 7. Change all invocations of `.greaterThanEqualTo()` to `.greaterThanOrEqualTo()`. - */ + //var behavior = grid.getBehavior(); + var y = gridCell.y; + // var previousDragExtent = grid.getDragExtent(); + var mouseDown = grid.getMouseDown(); -(function(module, exports) { // eslint-disable-line no-unused-expressions + var newY = y - mouseDown.y; + //var newY = y - mouseDown.y; - // This closure supports NodeJS-less client side includes with