Skip to content

Commit 4ef1500

Browse files
committed
feat(ngTouch): override mouse event directives
The mouse directives handle the touch events too. Closes angular#5334
1 parent 89c57a8 commit 4ef1500

File tree

4 files changed

+178
-30
lines changed

4 files changed

+178
-30
lines changed

angularFiles.js

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ var angularFiles = {
106106
'src/ngTouch/touch.js',
107107
'src/ngTouch/swipe.js',
108108
'src/ngTouch/directive/ngClick.js',
109+
'src/ngTouch/directive/ngEventDirs.js',
109110
'src/ngTouch/directive/ngSwipe.js'
110111
],
111112
'ngAria': [

src/ngTouch/directive/ngEventDirs.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
/* global ngTouch: false, POINTER_EVENTS: false */
4+
5+
/*
6+
* A collection of directives that allows creation of custom event handlers that are defined as
7+
* angular expressions and are compiled and executed within the current scope.
8+
*/
9+
var ngTouchEventDirectives = {};
10+
11+
12+
// Duplicate from the ng module...
13+
var forceAsyncEvents = {
14+
'blur': true,
15+
'focus': true
16+
};
17+
18+
forEach(Object.keys(POINTER_EVENTS.mouse),
19+
function (eventType) {
20+
21+
var eventName = POINTER_EVENTS.mouse[eventType];
22+
var directiveName = directiveNormalize('ng-' + eventName);
23+
24+
ngTouch.config(['$provide', function ($provide) {
25+
$provide.decorator(directiveName + 'Directive', ['$delegate', function ($delegate) {
26+
// drop the default mouse directives
27+
$delegate.shift();
28+
return $delegate;
29+
}]);
30+
}]);
31+
32+
ngTouchEventDirectives[directiveName] = ['$parse', '$rootScope', function ($parse, $rootScope) {
33+
return {
34+
restrict: 'A',
35+
compile: function ($element, attr) {
36+
var fn = $parse(attr[directiveName]);
37+
return function ngEventHandler(scope, element) {
38+
//
39+
element.on(getEvents(eventType), function (event) {
40+
var callback = function () {
41+
fn(scope, {$event: event});
42+
};
43+
if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
44+
scope.$evalAsync(callback);
45+
} else {
46+
scope.$apply(callback);
47+
}
48+
});
49+
50+
};
51+
}
52+
};
53+
}];
54+
}
55+
);
56+
57+
ngTouch.directive(ngTouchEventDirectives);
58+
59+

src/ngTouch/swipe.js

+32-30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22

33
/* global ngTouch: false */
44

5+
// The pointer event matching map
6+
var POINTER_EVENTS = {
7+
'mouse': {
8+
start: 'mousedown',
9+
move: 'mousemove',
10+
end: 'mouseup'
11+
},
12+
'touch': {
13+
start: 'touchstart',
14+
move: 'touchmove',
15+
end: 'touchend',
16+
cancel: 'touchcancel'
17+
}
18+
};
19+
20+
function getEvents(eventType, pointerTypes) {
21+
pointerTypes = pointerTypes || Object.keys(POINTER_EVENTS);
22+
var res = [];
23+
angular.forEach(pointerTypes, function (pointerType) {
24+
var eventName = POINTER_EVENTS[pointerType][eventType];
25+
if (eventName) {
26+
res.push(eventName);
27+
}
28+
});
29+
return res.join(' ');
30+
}
31+
32+
533
/**
634
* @ngdoc service
735
* @name $swipe
@@ -25,20 +53,6 @@ ngTouch.factory('$swipe', [function() {
2553
// The total distance in any direction before we make the call on swipe vs. scroll.
2654
var MOVE_BUFFER_RADIUS = 10;
2755

28-
var POINTER_EVENTS = {
29-
'mouse': {
30-
start: 'mousedown',
31-
move: 'mousemove',
32-
end: 'mouseup'
33-
},
34-
'touch': {
35-
start: 'touchstart',
36-
move: 'touchmove',
37-
end: 'touchend',
38-
cancel: 'touchcancel'
39-
}
40-
};
41-
4256
function getCoordinates(event) {
4357
var touches = event.touches && event.touches.length ? event.touches : [event];
4458
var e = (event.changedTouches && event.changedTouches[0]) ||
@@ -52,17 +66,6 @@ ngTouch.factory('$swipe', [function() {
5266
};
5367
}
5468

55-
function getEvents(pointerTypes, eventType) {
56-
var res = [];
57-
angular.forEach(pointerTypes, function(pointerType) {
58-
var eventName = POINTER_EVENTS[pointerType][eventType];
59-
if (eventName) {
60-
res.push(eventName);
61-
}
62-
});
63-
return res.join(' ');
64-
}
65-
6669
return {
6770
/**
6871
* @ngdoc method
@@ -106,24 +109,23 @@ ngTouch.factory('$swipe', [function() {
106109
// Whether a swipe is active.
107110
var active = false;
108111

109-
pointerTypes = pointerTypes || ['mouse', 'touch'];
110-
element.on(getEvents(pointerTypes, 'start'), function(event) {
112+
element.on(getEvents('start', pointerTypes), function(event) {
111113
startCoords = getCoordinates(event);
112114
active = true;
113115
totalX = 0;
114116
totalY = 0;
115117
lastPos = startCoords;
116118
eventHandlers['start'] && eventHandlers['start'](startCoords, event);
117119
});
118-
var events = getEvents(pointerTypes, 'cancel');
120+
var events = getEvents( 'cancel', pointerTypes);
119121
if (events) {
120122
element.on(events, function(event) {
121123
active = false;
122124
eventHandlers['cancel'] && eventHandlers['cancel'](event);
123125
});
124126
}
125127

126-
element.on(getEvents(pointerTypes, 'move'), function(event) {
128+
element.on(getEvents('move', pointerTypes), function(event) {
127129
if (!active) return;
128130

129131
// Android will send a touchcancel if it thinks we're starting to scroll.
@@ -157,7 +159,7 @@ ngTouch.factory('$swipe', [function() {
157159
}
158160
});
159161

160-
element.on(getEvents(pointerTypes, 'end'), function(event) {
162+
element.on(getEvents('end', pointerTypes), function(event) {
161163
if (!active) return;
162164
active = false;
163165
eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event);
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'use strict';
2+
3+
describe('ngMousedown (touch)', function() {
4+
var element;
5+
6+
beforeEach(function() {
7+
module('ngTouch');
8+
});
9+
10+
afterEach(function() {
11+
dealoc(element);
12+
});
13+
14+
it('should pass event object on mousedown', inject(function($rootScope, $compile) {
15+
element = $compile('<div ng-mousedown="event = $event"></div>')($rootScope);
16+
$rootScope.$digest();
17+
18+
browserTrigger(element, 'mousedown');
19+
expect($rootScope.event).toBeDefined();
20+
}));
21+
22+
it('should pass event object on touchstart too', inject(function($rootScope, $compile) {
23+
element = $compile('<div ng-mousedown="event = $event"></div>')($rootScope);
24+
$rootScope.$digest();
25+
26+
browserTrigger(element, 'touchstart');
27+
expect($rootScope.event).toBeDefined();
28+
}));
29+
});
30+
31+
32+
describe('ngMousemove (touch)', function() {
33+
var element;
34+
35+
beforeEach(function() {
36+
module('ngTouch');
37+
});
38+
39+
afterEach(function() {
40+
dealoc(element);
41+
});
42+
43+
it('should pass event object on mousemove', inject(function($rootScope, $compile) {
44+
element = $compile('<div ng-mousemove="event = $event"></div>')($rootScope);
45+
$rootScope.$digest();
46+
47+
browserTrigger(element, 'mousemove');
48+
expect($rootScope.event).toBeDefined();
49+
}));
50+
51+
it('should pass event object on touchstart too', inject(function($rootScope, $compile) {
52+
element = $compile('<div ng-mousemove="event = $event"></div>')($rootScope);
53+
$rootScope.$digest();
54+
55+
browserTrigger(element, 'mousemove');
56+
expect($rootScope.event).toBeDefined();
57+
}));
58+
});
59+
60+
describe('ngMouseup (touch)', function() {
61+
var element;
62+
63+
beforeEach(function() {
64+
module('ngTouch');
65+
});
66+
67+
afterEach(function() {
68+
dealoc(element);
69+
});
70+
71+
it('should pass event object on mouseup', inject(function($rootScope, $compile) {
72+
element = $compile('<div ng-mouseup="event = $event"></div>')($rootScope);
73+
$rootScope.$digest();
74+
75+
browserTrigger(element, 'mouseup');
76+
expect($rootScope.event).toBeDefined();
77+
}));
78+
79+
it('should pass event object on touchstart too', inject(function($rootScope, $compile) {
80+
element = $compile('<div ng-mouseup="event = $event"></div>')($rootScope);
81+
$rootScope.$digest();
82+
83+
browserTrigger(element, 'mouseup');
84+
expect($rootScope.event).toBeDefined();
85+
}));
86+
});

0 commit comments

Comments
 (0)