From 9c9f2726dcde0256e836ab4a84be115cb426401b Mon Sep 17 00:00:00 2001 From: Marais Rossouw Date: Fri, 5 Jan 2018 20:30:06 +1000 Subject: [PATCH] fix: silently ignore a verticle animation when no item (#3757) If when the verticleAnimationFrame callback fires, and the item no longer exists, (it has no parent), then we need to silently ignore that frame --- lib/timeline/Core.js | 2 +- lib/timeline/Timeline.js | 9 ++++++++ test/Timeline.test.js | 44 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 test/Timeline.test.js diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js index 719c77cf..597fb753 100644 --- a/lib/timeline/Core.js +++ b/lib/timeline/Core.js @@ -137,7 +137,7 @@ Core.prototype._create = function (container) { // emitted via emitter this.hammer = new Hammer(this.dom.root); var pinchRecognizer = this.hammer.get('pinch').set({enable: true}); - hammerUtil.disablePreventDefaultVertically(pinchRecognizer); + pinchRecognizer && hammerUtil.disablePreventDefaultVertically(pinchRecognizer); this.hammer.get('pan').set({threshold:5, direction: Hammer.DIRECTION_HORIZONTAL}); this.listeners = {}; diff --git a/lib/timeline/Timeline.js b/lib/timeline/Timeline.js index 7310e623..84b35c91 100644 --- a/lib/timeline/Timeline.js +++ b/lib/timeline/Timeline.js @@ -448,6 +448,10 @@ Timeline.prototype.focus = function(id, options) { var verticalAnimationFrame = function(ease, willDraw, done) { var verticalScroll = getItemVerticalScroll(me, item); + if (verticalScroll === false) { + return; // We don't need to scroll, so do nothing + } + if(!initialVerticalScroll) { initialVerticalScroll = verticalScroll; } @@ -560,6 +564,11 @@ function getEnd(item) { * @return {{shouldScroll: bool, scrollOffset: number, itemTop: number}} */ function getItemVerticalScroll(timeline, item) { + if (!item.parent) { + // The item no longer exists, so ignore this focus. + return false; + } + var leftHeight = timeline.props.leftContainer.height; var contentHeight = timeline.props.left.height; diff --git a/test/Timeline.test.js b/test/Timeline.test.js new file mode 100644 index 00000000..355e3ffb --- /dev/null +++ b/test/Timeline.test.js @@ -0,0 +1,44 @@ +var DataSet = require('../lib/DataSet'); +var Timeline = require('../lib/timeline/Timeline'); + +describe('Timeline', function () { + before(function () { + this.jsdom = require('jsdom-global')({ + pretendToBeVisual: true + }); + global['Element'] = window.Element; + global['requestAnimationFrame'] = function(cb) { + cb(); + }; + }); + + after(function () { + this.jsdom(); + }); + + it('should not throw when updating data in close succession', function (done) { + var timeline = new Timeline(document.createElement('div'), []); + + var events = [ + {start: new Date(), id: 1}, + {start: new Date(), id: 2} + ]; + + timeline + .setItems(new DataSet(events)); + + setTimeout(function() { + timeline + .setItems(new DataSet([ + {start: new Date(), id: 3}, + {start: new Date(), id: 4}, + {start: new Date(), id: 5} + ])); + + done(); + }, 5); + + timeline + .setSelection([events[0].id], {animation: false}); + }); +});