Skip to content

Commit 83e3243

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

File tree

4 files changed

+184
-30
lines changed

4 files changed

+184
-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(getPointerEventNames(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

+38-30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,40 @@
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+
/**
21+
*
22+
* @param {string} eventType The event type
23+
* @param {Array} [pointerTypes] The pointer type restrictions. By default mouse and touch pointers.
24+
* @returns {string} The event names
25+
*/
26+
function getPointerEventNames(eventType, pointerTypes) {
27+
pointerTypes = pointerTypes || Object.keys(POINTER_EVENTS);
28+
var res = [];
29+
angular.forEach(pointerTypes, function (pointerType) {
30+
var eventName = POINTER_EVENTS[pointerType][eventType];
31+
if (eventName) {
32+
res.push(eventName);
33+
}
34+
});
35+
return res.join(' ');
36+
}
37+
38+
539
/**
640
* @ngdoc service
741
* @name $swipe
@@ -25,20 +59,6 @@ ngTouch.factory('$swipe', [function() {
2559
// The total distance in any direction before we make the call on swipe vs. scroll.
2660
var MOVE_BUFFER_RADIUS = 10;
2761

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-
4262
function getCoordinates(event) {
4363
var touches = event.touches && event.touches.length ? event.touches : [event];
4464
var e = (event.changedTouches && event.changedTouches[0]) ||
@@ -52,17 +72,6 @@ ngTouch.factory('$swipe', [function() {
5272
};
5373
}
5474

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-
6675
return {
6776
/**
6877
* @ngdoc method
@@ -106,24 +115,23 @@ ngTouch.factory('$swipe', [function() {
106115
// Whether a swipe is active.
107116
var active = false;
108117

109-
pointerTypes = pointerTypes || ['mouse', 'touch'];
110-
element.on(getEvents(pointerTypes, 'start'), function(event) {
118+
element.on(getPointerEventNames('start', pointerTypes), function(event) {
111119
startCoords = getCoordinates(event);
112120
active = true;
113121
totalX = 0;
114122
totalY = 0;
115123
lastPos = startCoords;
116124
eventHandlers['start'] && eventHandlers['start'](startCoords, event);
117125
});
118-
var events = getEvents(pointerTypes, 'cancel');
126+
var events = getPointerEventNames('cancel', pointerTypes);
119127
if (events) {
120128
element.on(events, function(event) {
121129
active = false;
122130
eventHandlers['cancel'] && eventHandlers['cancel'](event);
123131
});
124132
}
125133

126-
element.on(getEvents(pointerTypes, 'move'), function(event) {
134+
element.on(getPointerEventNames('move', pointerTypes), function(event) {
127135
if (!active) return;
128136

129137
// Android will send a touchcancel if it thinks we're starting to scroll.
@@ -157,7 +165,7 @@ ngTouch.factory('$swipe', [function() {
157165
}
158166
});
159167

160-
element.on(getEvents(pointerTypes, 'end'), function(event) {
168+
element.on(getPointerEventNames('end', pointerTypes), function(event) {
161169
if (!active) return;
162170
active = false;
163171
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)