Skip to content

Commit 944d259

Browse files
committed
fix(sideMenu): fix stopping content scrolling
When a list was within a side menu it could scroll up and down, but if the user happened to drag a little bit on the X axis, then it would try to open the side menu and the Y scroll of the content stopped. Closes #1541
1 parent e5b5906 commit 944d259

File tree

4 files changed

+101
-66
lines changed

4 files changed

+101
-66
lines changed

Diff for: js/angular/directive/sideMenuContent.js

+72-37
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ function($timeout, $ionicGesture) {
3939
compile: function(element, attr) {
4040
return { pre: prelink };
4141
function prelink($scope, $element, $attr, sideMenuCtrl) {
42+
var startCoord = null;
43+
var primaryScrollAxis = null;
4244

4345
$element.addClass('menu-content pane');
4446

@@ -54,48 +56,75 @@ function($timeout, $ionicGesture) {
5456
$scope.$watch(attr.edgeDragThreshold, function(value) {
5557
sideMenuCtrl.edgeDragThreshold(value);
5658
});
57-
}
58-
59-
var defaultPrevented = false;
60-
var isDragging = false;
59+
}
6160

6261
// Listen for taps on the content to close the menu
63-
function contentTap(e) {
62+
function onContentTap(e) {
6463
if(sideMenuCtrl.getOpenAmount() !== 0) {
6564
sideMenuCtrl.close();
6665
e.gesture.srcEvent.preventDefault();
66+
startCoord = null;
67+
primaryScrollAxis = null;
6768
}
6869
}
69-
ionic.on('tap', contentTap, $element[0]);
7070

71-
var dragFn = function(e) {
72-
if(defaultPrevented || !sideMenuCtrl.isDraggableTarget(e)) return;
73-
isDragging = true;
74-
sideMenuCtrl._handleDrag(e);
75-
e.gesture.srcEvent.preventDefault();
76-
};
71+
function onDragX(e) {
72+
if(!sideMenuCtrl.isDraggableTarget(e)) return;
73+
74+
if( getPrimaryScrollAxis(e) == 'x') {
75+
sideMenuCtrl._handleDrag(e);
76+
e.gesture.srcEvent.preventDefault();
77+
}
78+
}
7779

78-
var dragVertFn = function(e) {
79-
if(isDragging) {
80+
function onDragY(e) {
81+
if( getPrimaryScrollAxis(e) == 'x' ) {
8082
e.gesture.srcEvent.preventDefault();
8183
}
82-
};
83-
84-
//var dragGesture = Gesture.on('drag', dragFn, $element);
85-
var dragRightGesture = $ionicGesture.on('dragright', dragFn, $element);
86-
var dragLeftGesture = $ionicGesture.on('dragleft', dragFn, $element);
87-
var dragUpGesture = $ionicGesture.on('dragup', dragVertFn, $element);
88-
var dragDownGesture = $ionicGesture.on('dragdown', dragVertFn, $element);
89-
90-
var dragReleaseFn = function(e) {
91-
isDragging = false;
92-
if(!defaultPrevented) {
93-
sideMenuCtrl._endDrag(e);
84+
}
85+
86+
function onDragRelease(e) {
87+
sideMenuCtrl._endDrag(e);
88+
startCoord = null;
89+
primaryScrollAxis = null;
90+
}
91+
92+
function getPrimaryScrollAxis(gestureEvt) {
93+
// gets whether the user is primarily scrolling on the X or Y
94+
// If a majority of the drag has been on the Y since the start of
95+
// the drag, but the X has moved a little bit, it's still a Y drag
96+
97+
if(primaryScrollAxis) {
98+
// we already figured out which way they're scrolling
99+
return primaryScrollAxis
94100
}
95-
defaultPrevented = false;
96-
};
97101

98-
var releaseGesture = $ionicGesture.on('release', dragReleaseFn, $element);
102+
if(gestureEvt && gestureEvt.gesture) {
103+
104+
if(!startCoord) {
105+
// get the starting point
106+
startCoord = ionic.tap.pointerCoord(gestureEvt.gesture.srcEvent);
107+
108+
} else {
109+
// we already have a starting point, figure out which direction they're going
110+
var endCoord = ionic.tap.pointerCoord(gestureEvt.gesture.srcEvent);
111+
112+
var xDistance = Math.abs(endCoord.x - startCoord.x);
113+
var yDistance = Math.abs(endCoord.y - startCoord.y);
114+
115+
var scrollAxis = ( xDistance > yDistance ? 'x' : 'y' );
116+
117+
if( Math.max(xDistance, yDistance) > 30 ) {
118+
// ok, we pretty much know which way they're going
119+
// let's lock it in
120+
primaryScrollAxis = scrollAxis;
121+
}
122+
123+
return scrollAxis;
124+
}
125+
126+
}
127+
}
99128

100129
sideMenuCtrl.setContent({
101130
element: element[0],
@@ -111,25 +140,31 @@ function($timeout, $ionicGesture) {
111140
});
112141
}),
113142
enableAnimation: function() {
114-
//this.el.classList.add(this.animateClass);
115143
$scope.animationEnabled = true;
116144
$element[0].classList.add('menu-animated');
117145
},
118146
disableAnimation: function() {
119-
//this.el.classList.remove(this.animateClass);
120147
$scope.animationEnabled = false;
121148
$element[0].classList.remove('menu-animated');
122149
}
123150
});
124151

152+
// add gesture handlers
153+
var dragRightGesture = $ionicGesture.on('dragright', onDragX, $element);
154+
var dragLeftGesture = $ionicGesture.on('dragleft', onDragX, $element);
155+
var dragUpGesture = $ionicGesture.on('dragup', onDragY, $element);
156+
var dragDownGesture = $ionicGesture.on('dragdown', onDragY, $element);
157+
var releaseGesture = $ionicGesture.on('release', onDragRelease, $element);
158+
var contentTapGesture = $ionicGesture.on('tap', onContentTap, $element);
159+
125160
// Cleanup
126161
$scope.$on('$destroy', function() {
127-
$ionicGesture.off(dragLeftGesture, 'dragleft', dragFn);
128-
$ionicGesture.off(dragRightGesture, 'dragright', dragFn);
129-
$ionicGesture.off(dragUpGesture, 'dragup', dragFn);
130-
$ionicGesture.off(dragDownGesture, 'dragdown', dragFn);
131-
$ionicGesture.off(releaseGesture, 'release', dragReleaseFn);
132-
ionic.off('tap', contentTap, $element[0]);
162+
$ionicGesture.off(dragLeftGesture, 'dragleft', onDragX);
163+
$ionicGesture.off(dragRightGesture, 'dragright', onDragX);
164+
$ionicGesture.off(dragUpGesture, 'dragup', onDragY);
165+
$ionicGesture.off(dragDownGesture, 'dragdown', onDragY);
166+
$ionicGesture.off(releaseGesture, 'release', onDragRelease);
167+
$ionicGesture.off(contentTapGesture, 'tap', onContentTap);
133168
});
134169
}
135170
}

Diff for: js/utils/tap.js

+19-19
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,21 @@ ionic.tap = {
266266
// used to cancel any simulated clicks which may happen on a touchend/mouseup
267267
// gestures uses this method within its tap and hold events
268268
tapPointerMoved = true;
269+
},
270+
271+
pointerCoord: function(event) {
272+
// This method can get coordinates for both a mouse click
273+
// or a touch depending on the given event
274+
var c = { x:0, y:0 };
275+
if(event) {
276+
var touches = event.touches && event.touches.length ? event.touches : [event];
277+
var e = (event.changedTouches && event.changedTouches[0]) || touches[0];
278+
if(e) {
279+
c.x = e.clientX || e.pageX || 0;
280+
c.y = e.clientY || e.pageY || 0;
281+
}
282+
}
283+
return c;
269284
}
270285

271286
};
@@ -285,7 +300,7 @@ function tapClick(e) {
285300

286301
if( ionic.tap.requiresNativeClick(ele) || tapPointerMoved ) return false;
287302

288-
var c = getPointerCoordinates(e);
303+
var c = ionic.tap.pointerCoord(e);
289304

290305
console.log('tapClick', e.type, ele.tagName, '('+c.x+','+c.y+')');
291306
triggerMouseEvent('click', ele, c.x, c.y);
@@ -342,7 +357,7 @@ function tapMouseDown(e) {
342357
}
343358

344359
tapPointerMoved = false;
345-
tapPointerStart = getPointerCoordinates(e);
360+
tapPointerStart = ionic.tap.pointerCoord(e);
346361

347362
tapEventListener('mousemove');
348363
ionic.activator.start(e);
@@ -382,7 +397,7 @@ function tapTouchStart(e) {
382397
tapPointerMoved = false;
383398

384399
tapEnableTouchEvents();
385-
tapPointerStart = getPointerCoordinates(e);
400+
tapPointerStart = ionic.tap.pointerCoord(e);
386401

387402
tapEventListener(tapTouchMoveListener);
388403
ionic.activator.start(e);
@@ -530,7 +545,7 @@ function tapHasPointerMoved(endEvent) {
530545
if(!endEvent || endEvent.target.nodeType !== 1 || !tapPointerStart || ( tapPointerStart.x === 0 && tapPointerStart.y === 0 )) {
531546
return false;
532547
}
533-
var endCoordinates = getPointerCoordinates(endEvent);
548+
var endCoordinates = ionic.tap.pointerCoord(endEvent);
534549

535550
var hasClassList = !!(endEvent.target.classList && endEvent.target.classList.contains);
536551
var releaseTolerance = hasClassList & endEvent.target.classList.contains('button') ?
@@ -541,21 +556,6 @@ function tapHasPointerMoved(endEvent) {
541556
Math.abs(tapPointerStart.y - endCoordinates.y) > releaseTolerance;
542557
}
543558

544-
function getPointerCoordinates(event) {
545-
// This method can get coordinates for both a mouse click
546-
// or a touch depending on the given event
547-
var c = { x:0, y:0 };
548-
if(event) {
549-
var touches = event.touches && event.touches.length ? event.touches : [event];
550-
var e = (event.changedTouches && event.changedTouches[0]) || touches[0];
551-
if(e) {
552-
c.x = e.clientX || e.pageX || 0;
553-
c.y = e.clientY || e.pageY || 0;
554-
}
555-
}
556-
return c;
557-
}
558-
559559
function tapContainingElement(ele, allowSelf) {
560560
var climbEle = ele;
561561
for(var x=0; x<6; x++) {

Diff for: js/views/scrollView.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ ionic.views.Scroll = ionic.views.View.inherit({
704704
}
705705

706706
self.touchStart = function(e) {
707-
self.startCoordinates = getPointerCoordinates(e);
707+
self.startCoordinates = ionic.tap.pointerCoord(e);
708708

709709
if ( ionic.tap.ignoreScrollStart(e) ) {
710710
return;
@@ -744,7 +744,7 @@ ionic.views.Scroll = ionic.views.View.inherit({
744744

745745
if(self.startCoordinates) {
746746
// we have start coordinates, so get this touch move's current coordinates
747-
var currentCoordinates = getPointerCoordinates(e);
747+
var currentCoordinates = ionic.tap.pointerCoord(e);
748748

749749
if( self.__isSelectable &&
750750
ionic.tap.isTextInput(e.target) &&

Diff for: test/unit/utils/tap.unit.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -619,13 +619,13 @@ describe('Ionic Tap', function() {
619619

620620
it('Should get coordinates from page mouse event', function() {
621621
var e = { pageX: 77, pageY: 77 };
622-
var c = getPointerCoordinates(e);
622+
var c = ionic.tap.pointerCoord(e);
623623
expect(c).toEqual({x:77, y: 77});
624624
});
625625

626626
it('Should get coordinates from client mouse event', function() {
627627
var e = { clientX: 77, clientY: 77 };
628-
var c = getPointerCoordinates(e);
628+
var c = ionic.tap.pointerCoord(e);
629629
expect(c).toEqual({x:77, y: 77});
630630
});
631631

@@ -634,29 +634,29 @@ describe('Ionic Tap', function() {
634634
touches: [{ clientX: 99, clientY: 99 }],
635635
changedTouches: [{ clientX: 88, clientY: 88 }]
636636
};
637-
var c = getPointerCoordinates(e);
637+
var c = ionic.tap.pointerCoord(e);
638638
expect(c).toEqual({x:88, y: 88});
639639
});
640640

641641
it('Should get coordinates from page touches', function() {
642642
var e = {
643643
touches: [{ pageX: 99, pageY: 99 }]
644644
};
645-
var c = getPointerCoordinates(e);
645+
var c = ionic.tap.pointerCoord(e);
646646
expect(c).toEqual({x:99, y: 99});
647647
});
648648

649649
it('Should get coordinates from client touches', function() {
650650
var e = {
651651
touches: [{ clientX: 99, clientY: 99 }]
652652
};
653-
var c = getPointerCoordinates(e);
653+
var c = ionic.tap.pointerCoord(e);
654654
expect(c).toEqual({x:99, y: 99});
655655
});
656656

657657
it('Should get 0 coordinates', function() {
658658
var e = {};
659-
var c = getPointerCoordinates(e);
659+
var c = ionic.tap.pointerCoord(e);
660660
expect(c).toEqual({x:0, y: 0});
661661
});
662662

@@ -1232,8 +1232,8 @@ describe('Ionic Tap', function() {
12321232

12331233
ele.type = 'text';
12341234
expect( ionic.tap.isDateInput(ele) ).toEqual(false);
1235-
1236-
1235+
1236+
12371237
});
12381238

12391239
it('Should isLabelWithTextInput', function() {

0 commit comments

Comments
 (0)