From 54f7a0e9ebde14996e58cc2e8fbc36238a469055 Mon Sep 17 00:00:00 2001 From: Jonathan Richard Henry Evans Date: Tue, 24 Feb 2015 14:05:49 +0000 Subject: [PATCH 1/5] fixes findRow --- addon/components/ember-table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/components/ember-table.js b/addon/components/ember-table.js index e55ab72..893db3d 100644 --- a/addon/components/ember-table.js +++ b/addon/components/ember-table.js @@ -622,8 +622,8 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, ResizeHandlerMi findRow: function(content) { var row, _i, _len, _ref; _ref = this.get('bodyContent'); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - row = _ref[_i]; + for (_i = 0, _len = _ref.get('length'); _i < _len; _i++) { + row = _ref.objectAt(_i); if (row.get('content') === content) { return row; } From e6b4afde577c95b34ffc34225a27752dd37efa48 Mon Sep 17 00:00:00 2001 From: Jonathan Evans Date: Sat, 17 Jan 2015 20:36:30 +0000 Subject: [PATCH 2/5] Replace the resize-handler mixin with the backalleycoder method http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ --- addon/components/ember-table.js | 19 +++------ addon/mixins/resize-handler-mixin.js | 51 ---------------------- addon/resize-detection.js | 64 ++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 65 deletions(-) delete mode 100644 addon/mixins/resize-handler-mixin.js create mode 100644 addon/resize-detection.js diff --git a/addon/components/ember-table.js b/addon/components/ember-table.js index 893db3d..be6c2d3 100644 --- a/addon/components/ember-table.js +++ b/addon/components/ember-table.js @@ -1,14 +1,14 @@ import Ember from 'ember'; import StyleBindingsMixin from '../mixins/style-bindings-mixin'; -import ResizeHandlerMixin from '../mixins/resize-handler-mixin'; import RowArrayController from '../controllers/row'; import RowDefinition from '../row-definition'; +import { addResizeListener } from '../resize-detection'; /* global $ */ var EmberTableComponent; -EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, ResizeHandlerMixin, { +EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { classNames: ['ember-table-tables-container'], classNameBindings: ['enableContentSelection:ember-table-content-selectable'], @@ -251,17 +251,9 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, ResizeHandlerMi return this.elementSizeDidChange(); }, - onResizeEnd: function() { - - /* - we need to put this on the run loop, because resize event came from - window. Otherwise, we get this warning when used in tests. You have - turned on testing mode, which disabled the run-loop's autorun. You - will need to wrap any code with asynchronous side-effects in an - Ember.run - */ - return Ember.run(this, this.elementSizeDidChange); - }, + addResizeListener: function() { + addResizeListener(this.get('element'), Ember.run.bind(this, this.elementSizeDidChange)); + }.on("didInsertElement"), elementSizeDidChange: function() { if ((this.get('_state') || this.get('state')) !== 'inDOM') { @@ -582,7 +574,6 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, ResizeHandlerMi rowIndex = this.rowIndex(this.get('persistedSelection.lastObject')); } else { rowIndex = this.rowIndex(this.get('lastSelected')); - console.log(rowIndex); } // Calculate new index, defaulting to current index for edge values diff --git a/addon/mixins/resize-handler-mixin.js b/addon/mixins/resize-handler-mixin.js deleted file mode 100644 index f89a034..0000000 --- a/addon/mixins/resize-handler-mixin.js +++ /dev/null @@ -1,51 +0,0 @@ -import Ember from 'ember'; - -/* global jQuery */ - -export default Ember.Mixin.create({ - resizeEndDelay: 200, - resizing: false, - onResizeStart: Ember.K, - onResizeEnd: Ember.K, - onResize: Ember.K, - endResize: Ember.computed(function() { - return function(event) { - if (this.isDestroyed) { - return; - } - this.set('resizing', false); - return typeof this.onResizeEnd === "function" ? this.onResizeEnd(event) : void 0; - }; - }), - handleWindowResize: function(event) { - if (!this.get('resizing')) { - this.set('resizing', true); - if (typeof this.onResizeStart === "function") { - this.onResizeStart(event); - } - } - if (typeof this.onResize === "function") { - this.onResize(event); - } - return Ember.run.debounce(this, this.get('endResize'), event, this.get('resizeEndDelay')); - }, - didInsertElement: function() { - this._super(); - return this._setupDocumentHandlers(); - }, - willDestroyElement: function() { - this._removeDocumentHandlers(); - return this._super(); - }, - _setupDocumentHandlers: function() { - if (this._resizeHandler) { - return; - } - this._resizeHandler = jQuery.proxy(this.get('handleWindowResize'), this); - return jQuery(window).on("resize." + this.elementId, this._resizeHandler); - }, - _removeDocumentHandlers: function() { - jQuery(window).off("resize." + this.elementId, this._resizeHandler); - return this._resizeHandler = null; - } -}); diff --git a/addon/resize-detection.js b/addon/resize-detection.js new file mode 100644 index 0000000..682e650 --- /dev/null +++ b/addon/resize-detection.js @@ -0,0 +1,64 @@ +var attachEvent = document.attachEvent; +var isIE = navigator.userAgent.match(/Trident/); +var requestFrame = (function(){ + var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || + function(fn){ return window.setTimeout(fn, 20); }; + return function(fn){ return raf(fn); }; +})(); + +var cancelFrame = (function(){ + var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || + window.clearTimeout; + return function(id){ return cancel(id); }; +})(); + +function resizeListener(e){ + var win = e.target || e.srcElement; + if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__); + win.__resizeRAF__ = requestFrame(function(){ + var trigger = win.__resizeTrigger__; + trigger.__resizeListeners__.forEach(function(fn){ + fn.call(trigger, e); + }); + }); +} + +function objectLoad(e){ + this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; + this.contentDocument.defaultView.addEventListener('resize', resizeListener); +} + +var addResizeListener = function(element, fn){ + if (!element.__resizeListeners__) { + element.__resizeListeners__ = []; + if (attachEvent) { + element.__resizeTrigger__ = element; + element.attachEvent('onresize', resizeListener); + } + else { + if (getComputedStyle(element).position == 'static') element.style.position = 'relative'; + var obj = element.__resizeTrigger__ = document.createElement('object'); + obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); + obj.__resizeElement__ = element; + obj.onload = objectLoad; + obj.type = 'text/html'; + if (isIE) element.appendChild(obj); + obj.data = 'about:blank'; + if (!isIE) element.appendChild(obj); + } + } + element.__resizeListeners__.push(fn); +}; + +var removeResizeListener = function(element, fn){ + element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); + if (!element.__resizeListeners__.length) { + if (attachEvent) element.detachEvent('onresize', resizeListener); + else { + element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener); + element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__); + } + } +} + +export { addResizeListener, removeResizeListener }; From e8b59de78d9e3009228a4fe9ca095736b40646cf Mon Sep 17 00:00:00 2001 From: Jonathan Evans Date: Sat, 17 Jan 2015 20:44:02 +0000 Subject: [PATCH 3/5] Lint resize-detection code --- addon/resize-detection.js | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/addon/resize-detection.js b/addon/resize-detection.js index 682e650..44b8425 100644 --- a/addon/resize-detection.js +++ b/addon/resize-detection.js @@ -1,3 +1,4 @@ +// Private / Helper Methods var attachEvent = document.attachEvent; var isIE = navigator.userAgent.match(/Trident/); var requestFrame = (function(){ @@ -6,15 +7,17 @@ var requestFrame = (function(){ return function(fn){ return raf(fn); }; })(); -var cancelFrame = (function(){ +var cancelFrame = (function() { var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.clearTimeout; return function(id){ return cancel(id); }; })(); -function resizeListener(e){ +function resizeListener(e) { var win = e.target || e.srcElement; - if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__); + if (win.__resizeRAF__) { + cancelFrame(win.__resizeRAF__); + } win.__resizeRAF__ = requestFrame(function(){ var trigger = win.__resizeTrigger__; trigger.__resizeListeners__.forEach(function(fn){ @@ -23,12 +26,14 @@ function resizeListener(e){ }); } -function objectLoad(e){ +function objectLoad() { this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; this.contentDocument.defaultView.addEventListener('resize', resizeListener); } -var addResizeListener = function(element, fn){ +// Public methods + +var addResizeListener = function(element, fn) { if (!element.__resizeListeners__) { element.__resizeListeners__ = []; if (attachEvent) { @@ -36,29 +41,36 @@ var addResizeListener = function(element, fn){ element.attachEvent('onresize', resizeListener); } else { - if (getComputedStyle(element).position == 'static') element.style.position = 'relative'; - var obj = element.__resizeTrigger__ = document.createElement('object'); + if (getComputedStyle(element).position === 'static') { + element.style.position = 'relative'; + } + var obj = element.__resizeTrigger__ = document.createElement('object'); obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); obj.__resizeElement__ = element; obj.onload = objectLoad; obj.type = 'text/html'; - if (isIE) element.appendChild(obj); + if (isIE) { + element.appendChild(obj); + } obj.data = 'about:blank'; - if (!isIE) element.appendChild(obj); + if (!isIE) { + element.appendChild(obj); + } } } element.__resizeListeners__.push(fn); }; -var removeResizeListener = function(element, fn){ +var removeResizeListener = function(element, fn) { element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); if (!element.__resizeListeners__.length) { - if (attachEvent) element.detachEvent('onresize', resizeListener); - else { + if (attachEvent) { + element.detachEvent('onresize', resizeListener); + } else { element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener); element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__); } } -} +}; export { addResizeListener, removeResizeListener }; From 8accae6496f6127cf84277129f7f886cd9e705eb Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 24 Feb 2015 15:43:05 +0100 Subject: [PATCH 4/5] Move table scroll if navigating with arrow keys --- addon/components/ember-table.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/addon/components/ember-table.js b/addon/components/ember-table.js index be6c2d3..181968f 100644 --- a/addon/components/ember-table.js +++ b/addon/components/ember-table.js @@ -438,6 +438,10 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { return Math.floor(this.get('_bodyHeight') / this.get('rowHeight')); }).property('_bodyHeight', 'rowHeight'), + _endIndex: Ember.computed(function() { + return this.get('_startIndex') + this.get('_numItemsShowing'); + }).property('_startIndex', '_numItemsShowing'), + _startIndex: Ember.computed(function() { var index, numContent, numViews, rowHeight, scrollTop; numContent = this.get('bodyContent.length'); @@ -544,6 +548,10 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { } }, + //Super hacky, refactor + _scrollToVertical: function(y) { + this.$('.ember-table-body-container .antiscroll-inner').scrollTop(y); + }, keyDown: function (e) { if (e.keyCode === 38) { @@ -582,9 +590,18 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { } else if (direction === 'down' && rowIndex !== this.get('bodyContent.length') - 1) { futureRowIndex = rowIndex + 1; } else { - futureRowIndex = rowIndex; + //We are at the end or the start so don't want to do anything + return; + } + if (direction === 'down' && futureRowIndex + 1 > this.get('_endIndex')) { + this._scrollToVertical(this.get('_tableScrollTop') + this.get('rowHeight') * 4); } + if (direction === 'up' && futureRowIndex - 1 < this.get('_startIndex')) { + this._scrollToVertical(this.get('_tableScrollTop') - this.get('rowHeight') * 4); + } + + // Clear current selection this.get('persistedSelection').clear(); this.get('rangeSelection').clear(); From ef4bea6709a582a7b241eba1cb7850b81defadf7 Mon Sep 17 00:00:00 2001 From: Jonathan Evans Date: Tue, 17 Mar 2015 17:41:05 -0400 Subject: [PATCH 5/5] Change to using ember-resize-mixin --- addon/components/ember-table.js | 17 +++----- addon/resize-detection.js | 76 --------------------------------- 2 files changed, 6 insertions(+), 87 deletions(-) delete mode 100644 addon/resize-detection.js diff --git a/addon/components/ember-table.js b/addon/components/ember-table.js index 181968f..ebdbdb7 100644 --- a/addon/components/ember-table.js +++ b/addon/components/ember-table.js @@ -2,13 +2,11 @@ import Ember from 'ember'; import StyleBindingsMixin from '../mixins/style-bindings-mixin'; import RowArrayController from '../controllers/row'; import RowDefinition from '../row-definition'; -import { addResizeListener } from '../resize-detection'; +import ResizeMixin from 'ember-resize-mixin/main'; /* global $ */ -var EmberTableComponent; - -EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { +var EmberTableComponent = Ember.Component.extend(ResizeMixin, StyleBindingsMixin, { classNames: ['ember-table-tables-container'], classNameBindings: ['enableContentSelection:ember-table-content-selectable'], @@ -248,17 +246,14 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { didInsertElement: function() { this._super(); this.set('_tableScrollTop', 0); - return this.elementSizeDidChange(); + Ember.run.next(this, this.elementSizeDidChange); }, - addResizeListener: function() { - addResizeListener(this.get('element'), Ember.run.bind(this, this.elementSizeDidChange)); - }.on("didInsertElement"), - elementSizeDidChange: function() { if ((this.get('_state') || this.get('state')) !== 'inDOM') { return; } + this.set('_width', this.$().parent().outerWidth()); this.set('_height', this.$().parent().outerHeight()); @@ -266,8 +261,8 @@ EmberTableComponent = Ember.Component.extend(StyleBindingsMixin, { we need to wait for the table to be fully rendered before antiscroll can be used */ - return Ember.run.next(this, this.updateLayout); - }, + Ember.run.next(this, this.updateLayout); + }.on('resize'), updateLayout: function() { diff --git a/addon/resize-detection.js b/addon/resize-detection.js deleted file mode 100644 index 44b8425..0000000 --- a/addon/resize-detection.js +++ /dev/null @@ -1,76 +0,0 @@ -// Private / Helper Methods -var attachEvent = document.attachEvent; -var isIE = navigator.userAgent.match(/Trident/); -var requestFrame = (function(){ - var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || - function(fn){ return window.setTimeout(fn, 20); }; - return function(fn){ return raf(fn); }; -})(); - -var cancelFrame = (function() { - var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || - window.clearTimeout; - return function(id){ return cancel(id); }; -})(); - -function resizeListener(e) { - var win = e.target || e.srcElement; - if (win.__resizeRAF__) { - cancelFrame(win.__resizeRAF__); - } - win.__resizeRAF__ = requestFrame(function(){ - var trigger = win.__resizeTrigger__; - trigger.__resizeListeners__.forEach(function(fn){ - fn.call(trigger, e); - }); - }); -} - -function objectLoad() { - this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; - this.contentDocument.defaultView.addEventListener('resize', resizeListener); -} - -// Public methods - -var addResizeListener = function(element, fn) { - if (!element.__resizeListeners__) { - element.__resizeListeners__ = []; - if (attachEvent) { - element.__resizeTrigger__ = element; - element.attachEvent('onresize', resizeListener); - } - else { - if (getComputedStyle(element).position === 'static') { - element.style.position = 'relative'; - } - var obj = element.__resizeTrigger__ = document.createElement('object'); - obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); - obj.__resizeElement__ = element; - obj.onload = objectLoad; - obj.type = 'text/html'; - if (isIE) { - element.appendChild(obj); - } - obj.data = 'about:blank'; - if (!isIE) { - element.appendChild(obj); - } - } - } - element.__resizeListeners__.push(fn); -}; - -var removeResizeListener = function(element, fn) { - element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); - if (!element.__resizeListeners__.length) { - if (attachEvent) { - element.detachEvent('onresize', resizeListener); - } else { - element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener); - element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__); - } - } -}; - -export { addResizeListener, removeResizeListener };