Skip to content

Commit 4a21013

Browse files
committed
fix(scrollView): stop memory-leak when destroying scrollView
Fixes #1096
1 parent 6b402c3 commit 4a21013

File tree

3 files changed

+61
-23
lines changed

3 files changed

+61
-23
lines changed

js/angular/controller/scrollController.js

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
5151

5252
$scope.$on('$destroy', function() {
5353
deregisterInstance();
54+
scrollView.__removeEventHandlers();
5455
ionic.off('resize', resize, $window);
5556
$window.removeEventListener('resize', resize);
5657
backListenDone();

js/utils/dom.js

+11
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,17 @@
250250
return null;
251251
},
252252

253+
elementHasParent: function(element, parent) {
254+
var current = element;
255+
while (current) {
256+
if (current.parentNode === parent) {
257+
return true;
258+
}
259+
current = current.parentNode;
260+
}
261+
return false;
262+
},
263+
253264
/**
254265
* @ngdoc method
255266
* @name ionic.DomUtil#rectContains

js/views/scrollView.js

+49-23
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ ionic.views.Scroll = ionic.views.View.inherit({
668668

669669
scrollBottomOffsetToTop = container.getBoundingClientRect().bottom;
670670
//distance from top of focused element to the bottom of the scroll view
671-
var elementTopOffsetToScrollBottom = e.detail.elementTop - scrollBottomOffsetToTop;
671+
var elementTopOffsetToScrollBottom = e.detail.elementTop - scrollBottomOffsetToTop;
672672

673673
var scrollTop = elementTopOffsetToScrollBottom + scrollMidpointOffset;
674674
ionic.tap.cloneFocusedInput(container, self);
@@ -807,55 +807,82 @@ ionic.views.Scroll = ionic.views.View.inherit({
807807
// Mouse Events
808808
var mousedown = false;
809809

810-
container.addEventListener("mousedown", function(e) {
810+
self.mouseDown = function(e) {
811811
if ( ionic.tap.ignoreScrollStart(e) || e.target.tagName === 'SELECT' ) {
812812
return;
813813
}
814814
self.doTouchStart(getEventTouches(e), e.timeStamp);
815815

816816
e.preventDefault();
817817
mousedown = true;
818-
}, false);
818+
};
819819

820-
document.addEventListener("mousemove", function(e) {
820+
self.mouseMove = function(e) {
821821
if (!mousedown || e.defaultPrevented) {
822822
return;
823823
}
824824

825825
self.doTouchMove(getEventTouches(e), e.timeStamp);
826826

827827
mousedown = true;
828-
}, false);
828+
};
829829

830-
document.addEventListener("mouseup", function(e) {
830+
self.mouseUp = function(e) {
831831
if (!mousedown) {
832832
return;
833833
}
834834

835835
self.doTouchEnd(e.timeStamp);
836836

837837
mousedown = false;
838-
}, false);
839-
840-
var wheelShowBarFn = ionic.debounce(function() {
841-
self.__fadeScrollbars('in');
842-
}, 500, true);
838+
};
843839

844-
var wheelHideBarFn = ionic.debounce(function() {
845-
self.__fadeScrollbars('out');
846-
}, 100, false);
840+
self.mouseWheel = ionic.animationFrameThrottle(function(e) {
841+
if (ionic.DomUtil.elementHasParent(e.target, self.__container)) {
842+
self.hintResize();
843+
self.scrollBy(
844+
e.wheelDeltaX/self.options.wheelDampen,
845+
-e.wheelDeltaY/self.options.wheelDampen
846+
);
847+
self.__fadeScrollbars('in');
848+
clearTimeout(self.__wheelHideBarTimeout);
849+
self.__wheelHideBarTimeout = setTimeout(function() {
850+
self.__fadeScrollbars('out');
851+
}, 100);
852+
}
853+
});
847854

848-
//For Firefox
849-
document.addEventListener('mousewheel', onMouseWheel);
850-
}
851-
function onMouseWheel(e) {
852-
self.hintResize();
853-
wheelShowBarFn();
854-
self.scrollBy(e.wheelDeltaX/self.options.wheelDampen, -e.wheelDeltaY/self.options.wheelDampen);
855-
wheelHideBarFn();
855+
container.addEventListener("mousedown", self.mouseDown, false);
856+
document.addEventListener("mousemove", self.mouseMove, false);
857+
document.addEventListener("mouseup", self.mouseUp, false);
858+
document.addEventListener('mousewheel', self.mouseWheel, false);
856859
}
857860
},
858861

862+
__removeEventHandlers: function() {
863+
var container = this.__container;
864+
865+
container.removeEventListener('touchstart', self.touchStart);
866+
document.removeEventListener('touchmove', self.touchMove);
867+
document.removeEventListener('touchend', self.touchEnd);
868+
document.removeEventListener('touchcancel', self.touchCancel);
869+
870+
container.removeEventListener("pointerdown", self.touchStart);
871+
document.removeEventListener("pointermove", self.touchMove);
872+
document.removeEventListener("pointerup", self.touchEnd);
873+
document.removeEventListener("pointercancel", self.touchEnd);
874+
875+
container.removeEventListener("MSPointerDown", self.touchStart);
876+
document.removeEventListener("MSPointerMove", self.touchMove);
877+
document.removeEventListener("MSPointerUp", self.touchEnd);
878+
document.removeEventListener("MSPointerCancel", self.touchEnd);
879+
880+
container.removeEventListener("mousedown", self.mouseDown);
881+
document.removeEventListener("mousemove", self.mouseMove);
882+
document.removeEventListener("mouseup", self.mouseUp);
883+
document.removeEventListener('mousewheel', self.mouseWheel);
884+
},
885+
859886
/** Create a scroll bar div with the given direction **/
860887
__createScrollbar: function(direction) {
861888
var bar = document.createElement('div'),
@@ -1503,7 +1530,6 @@ ionic.views.Scroll = ionic.views.View.inherit({
15031530

15041531
},
15051532

1506-
15071533
/**
15081534
* Touch start handler for scrolling support
15091535
*/

0 commit comments

Comments
 (0)