@@ -5,156 +5,89 @@ import { App } from '../app/app';
5
5
import { Config } from '../../config/config' ;
6
6
import { hasPointerMoved , pointerCoord } from '../../util/dom' ;
7
7
import { RippleActivator } from './ripple' ;
8
-
8
+ import { UIEventManager , PointerEvents , PointerEventType } from '../../util/ui-event-manager' ;
9
9
10
10
/**
11
11
* @private
12
12
*/
13
13
@Injectable ( )
14
14
export class TapClick {
15
- private lastTouch : number = 0 ;
16
15
private disableClick : number = 0 ;
17
- private lastActivated : number = 0 ;
18
16
private usePolyfill : boolean ;
19
17
private activator : Activator ;
20
18
private startCoord : any ;
21
- private pointerMove : any ;
19
+ private events : UIEventManager = new UIEventManager ( false ) ;
20
+ private pointerEvents : PointerEvents ;
22
21
23
22
constructor (
24
23
config : Config ,
25
24
private app : App ,
26
25
zone : NgZone
27
26
) {
28
- if ( config . get ( 'activator' ) === 'ripple' ) {
27
+ let activator = config . get ( 'activator' ) ;
28
+ if ( activator === 'ripple' ) {
29
29
this . activator = new RippleActivator ( app , config ) ;
30
30
31
- } else if ( config . get ( ' activator' ) === 'highlight' ) {
31
+ } else if ( activator === 'highlight' ) {
32
32
this . activator = new Activator ( app , config ) ;
33
33
}
34
34
35
35
this . usePolyfill = ( config . get ( 'tapPolyfill' ) === true ) ;
36
36
37
- zone . runOutsideAngular ( ( ) => {
38
- addListener ( 'click' , this . click . bind ( this ) , true ) ;
39
-
40
- addListener ( 'touchstart' , this . touchStart . bind ( this ) ) ;
41
- addListener ( 'touchend' , this . touchEnd . bind ( this ) ) ;
42
- addListener ( 'touchcancel' , this . pointerCancel . bind ( this ) ) ;
43
-
44
- addListener ( 'mousedown' , this . mouseDown . bind ( this ) , true ) ;
45
- addListener ( 'mouseup' , this . mouseUp . bind ( this ) , true ) ;
37
+ this . events . listen ( document , 'click' , this . click . bind ( this ) , true ) ;
38
+ this . pointerEvents = this . events . pointerEvents ( {
39
+ element : < any > document ,
40
+ pointerDown : this . pointerStart . bind ( this ) ,
41
+ pointerMove : this . pointerMove . bind ( this ) ,
42
+ pointerUp : this . pointerEnd . bind ( this ) ,
43
+ passive : true
46
44
} ) ;
47
-
48
- this . pointerMove = ( ev : UIEvent ) => {
49
- if ( ! this . startCoord || hasPointerMoved ( POINTER_MOVE_UNTIL_CANCEL , this . startCoord , pointerCoord ( ev ) ) ) {
50
- this . pointerCancel ( ev ) ;
51
- }
52
- } ;
53
- }
54
-
55
- touchStart ( ev : UIEvent ) {
56
- this . lastTouch = Date . now ( ) ;
57
- this . pointerStart ( ev ) ;
45
+ this . pointerEvents . mouseWait = DISABLE_NATIVE_CLICK_AMOUNT ;
58
46
}
59
47
60
- touchEnd ( ev : UIEvent ) {
61
- this . lastTouch = Date . now ( ) ;
62
-
63
- if ( this . usePolyfill && this . startCoord && this . app . isEnabled ( ) ) {
64
- // only dispatch mouse click events from a touchend event
65
- // when tapPolyfill config is true, and the startCoordand endCoord
66
- // are not too far off from each other
67
- let endCoord = pointerCoord ( ev ) ;
68
-
69
- if ( ! hasPointerMoved ( POINTER_TOLERANCE , this . startCoord , endCoord ) ) {
70
- // prevent native mouse click events for XX amount of time
71
- this . disableClick = this . lastTouch + DISABLE_NATIVE_CLICK_AMOUNT ;
72
-
73
- if ( this . app . isScrolling ( ) ) {
74
- // do not fire off a click event while the app was scrolling
75
- console . debug ( 'click from touch prevented by scrolling ' + Date . now ( ) ) ;
76
-
77
- } else {
78
- // dispatch a mouse click event
79
- console . debug ( 'create click from touch ' + Date . now ( ) ) ;
80
-
81
- let clickEvent : any = document . createEvent ( 'MouseEvents' ) ;
82
- clickEvent . initMouseEvent ( 'click' , true , true , window , 1 , 0 , 0 , endCoord . x , endCoord . y , false , false , false , false , 0 , null ) ;
83
- clickEvent . isIonicTap = true ;
84
- ev . target . dispatchEvent ( clickEvent ) ;
85
- }
86
- }
48
+ pointerStart ( ev : any ) : boolean {
49
+ if ( this . startCoord ) {
50
+ return false ;
87
51
}
88
-
89
- this . pointerEnd ( ev ) ;
90
- }
91
-
92
- mouseDown ( ev : any ) {
93
- if ( this . isDisabledNativeClick ( ) ) {
94
- console . debug ( 'mouseDown prevent ' + ev . target . tagName + ' ' + Date . now ( ) ) ;
95
- // does not prevent default on purpose
96
- // so native blur events from inputs can happen
97
- ev . stopPropagation ( ) ;
98
-
99
- } else if ( this . lastTouch + DISABLE_NATIVE_CLICK_AMOUNT < Date . now ( ) ) {
100
- this . pointerStart ( ev ) ;
52
+ let activatableEle = getActivatableTarget ( ev . target ) ;
53
+ if ( ! activatableEle ) {
54
+ this . startCoord = null ;
55
+ return false ;
101
56
}
57
+ this . startCoord = pointerCoord ( ev ) ;
58
+ this . activator && this . activator . downAction ( ev , activatableEle , this . startCoord ) ;
59
+ return true ;
102
60
}
103
61
104
- mouseUp ( ev : any ) {
105
- if ( this . isDisabledNativeClick ( ) ) {
106
- console . debug ( 'mouseUp prevent ' + ev . target . tagName + ' ' + Date . now ( ) ) ;
107
- ev . preventDefault ( ) ;
108
- ev . stopPropagation ( ) ;
109
- }
110
-
111
- if ( this . lastTouch + DISABLE_NATIVE_CLICK_AMOUNT < Date . now ( ) ) {
112
- this . pointerEnd ( ev ) ;
62
+ pointerMove ( ev : UIEvent ) {
63
+ if ( ! this . startCoord ||
64
+ hasPointerMoved ( POINTER_TOLERANCE , this . startCoord , pointerCoord ( ev ) ) ||
65
+ this . app . isScrolling ( ) ) {
66
+ this . pointerCancel ( ev ) ;
113
67
}
114
68
}
115
69
116
- pointerStart ( ev : any ) {
117
- let activatableEle = getActivatableTarget ( ev . target ) ;
118
-
119
- if ( activatableEle ) {
120
- this . startCoord = pointerCoord ( ev ) ;
121
-
122
- let now = Date . now ( ) ;
123
- if ( this . lastActivated + 150 < now && ! this . app . isScrolling ( ) ) {
124
- this . activator && this . activator . downAction ( ev , activatableEle , this . startCoord ) ;
125
- this . lastActivated = now ;
126
- }
127
-
128
- this . moveListeners ( true ) ;
129
-
130
- } else {
131
- this . startCoord = null ;
70
+ pointerEnd ( ev : any , type : PointerEventType ) {
71
+ if ( ! this . startCoord ) {
72
+ return ;
132
73
}
133
- }
134
-
135
- pointerEnd ( ev : any ) {
136
- if ( this . startCoord && this . activator ) {
74
+ if ( type === PointerEventType . TOUCH && this . usePolyfill && this . app . isEnabled ( ) ) {
75
+ this . handleTapPolyfill ( ev ) ;
76
+ }
77
+ if ( this . activator ) {
137
78
let activatableEle = getActivatableTarget ( ev . target ) ;
138
79
if ( activatableEle ) {
139
80
this . activator . upAction ( ev , activatableEle , this . startCoord ) ;
140
81
}
141
82
}
142
-
143
- this . moveListeners ( false ) ;
83
+ this . startCoord = null ;
144
84
}
145
85
146
86
pointerCancel ( ev : UIEvent ) {
147
87
console . debug ( 'pointerCancel from ' + ev . type + ' ' + Date . now ( ) ) ;
88
+ this . startCoord = null ;
148
89
this . activator && this . activator . clearState ( ) ;
149
- this . moveListeners ( false ) ;
150
- }
151
-
152
- moveListeners ( shouldAdd : boolean ) {
153
- removeListener ( this . usePolyfill ? 'touchmove' : 'mousemove' , this . pointerMove ) ;
154
-
155
- if ( shouldAdd ) {
156
- addListener ( this . usePolyfill ? 'touchmove' : 'mousemove' , this . pointerMove ) ;
157
- }
90
+ this . pointerEvents . stop ( ) ;
158
91
}
159
92
160
93
click ( ev : any ) {
@@ -174,6 +107,34 @@ export class TapClick {
174
107
}
175
108
}
176
109
110
+ handleTapPolyfill ( ev : any ) {
111
+ // only dispatch mouse click events from a touchend event
112
+ // when tapPolyfill config is true, and the startCoordand endCoord
113
+ // are not too far off from each other
114
+ let endCoord = pointerCoord ( ev ) ;
115
+
116
+ if ( hasPointerMoved ( POINTER_TOLERANCE , this . startCoord , endCoord ) ) {
117
+ console . debug ( 'click from touch prevented by pointer moved' ) ;
118
+ return ;
119
+ }
120
+ // prevent native mouse click events for XX amount of time
121
+ this . disableClick = Date . now ( ) + DISABLE_NATIVE_CLICK_AMOUNT ;
122
+
123
+ if ( this . app . isScrolling ( ) ) {
124
+ // do not fire off a click event while the app was scrolling
125
+ console . debug ( 'click from touch prevented by scrolling ' + Date . now ( ) ) ;
126
+
127
+ } else {
128
+ // dispatch a mouse click event
129
+ console . debug ( 'create click from touch ' + Date . now ( ) ) ;
130
+
131
+ let clickEvent : any = document . createEvent ( 'MouseEvents' ) ;
132
+ clickEvent . initMouseEvent ( 'click' , true , true , window , 1 , 0 , 0 , endCoord . x , endCoord . y , false , false , false , false , 0 , null ) ;
133
+ clickEvent . isIonicTap = true ;
134
+ ev . target . dispatchEvent ( clickEvent ) ;
135
+ }
136
+ }
137
+
177
138
isDisabledNativeClick ( ) {
178
139
return this . disableClick > Date . now ( ) ;
179
140
}
@@ -194,33 +155,23 @@ function getActivatableTarget(ele: HTMLElement) {
194
155
/**
195
156
* @private
196
157
*/
197
- export const isActivatable = function ( ele : HTMLElement ) {
198
- if ( ACTIVATABLE_ELEMENTS . test ( ele . tagName ) ) {
158
+ export const isActivatable = function ( ele : HTMLElement ) {
159
+ if ( ACTIVATABLE_ELEMENTS . indexOf ( ele . tagName ) > - 1 ) {
199
160
return true ;
200
161
}
201
162
202
163
let attributes = ele . attributes ;
203
164
for ( let i = 0 , l = attributes . length ; i < l ; i ++ ) {
204
- if ( ACTIVATABLE_ATTRIBUTES . test ( attributes [ i ] . name ) ) {
165
+ if ( ACTIVATABLE_ATTRIBUTES . indexOf ( attributes [ i ] . name ) > - 1 ) {
205
166
return true ;
206
167
}
207
168
}
208
-
209
169
return false ;
210
170
} ;
211
171
212
- function addListener ( type : string , listener : any , useCapture ?: boolean ) {
213
- document . addEventListener ( type , listener , useCapture ) ;
214
- }
215
-
216
- function removeListener ( type : string , listener : any ) {
217
- document . removeEventListener ( type , listener ) ;
218
- }
219
-
220
- const ACTIVATABLE_ELEMENTS = / ^ ( A | B U T T O N ) $ / ;
221
- const ACTIVATABLE_ATTRIBUTES = / t a p p a b l e | b u t t o n / i;
222
- const POINTER_TOLERANCE = 4 ;
223
- const POINTER_MOVE_UNTIL_CANCEL = 10 ;
172
+ const ACTIVATABLE_ELEMENTS = [ 'A' , 'BUTTON' ] ;
173
+ const ACTIVATABLE_ATTRIBUTES = [ 'tappable' , 'button' ] ;
174
+ const POINTER_TOLERANCE = 60 ;
224
175
const DISABLE_NATIVE_CLICK_AMOUNT = 2500 ;
225
176
226
177
export function setupTapClick ( config : Config , app : App , zone : NgZone ) {
0 commit comments