@@ -61,14 +61,20 @@ const ignoreMouseEventsTimeout = 800;
6161/** Options that apply to all the event listeners that are bound by the ripple renderer. */
6262const passiveEventOptions = normalizePassiveListenerOptions ( { passive : true } ) ;
6363
64+ /** Events that signal that the pointer is down. */
65+ const pointerDownEvents = [ 'mousedown' , 'touchstart' ] ;
66+
67+ /** Events that signal that the pointer is up. */
68+ const pointerUpEvents = [ 'mouseup' , 'mouseleave' , 'touchend' , 'touchcancel' ] ;
69+
6470/**
6571 * Helper service that performs DOM manipulations. Not intended to be used outside this module.
6672 * The constructor takes a reference to the ripple directive's host element and a map of DOM
6773 * event handlers to be installed on the element that triggers ripple animations.
6874 * This will eventually become a custom renderer once Angular support exists.
6975 * @docs -private
7076 */
71- export class RippleRenderer {
77+ export class RippleRenderer implements EventListenerObject {
7278 /** Element where the ripples are being added to. */
7379 private _containerElement : HTMLElement ;
7480
@@ -78,9 +84,6 @@ export class RippleRenderer {
7884 /** Whether the pointer is currently down or not. */
7985 private _isPointerDown = false ;
8086
81- /** Events to be registered on the trigger element. */
82- private _triggerEvents = new Map < string , any > ( ) ;
83-
8487 /** Set of currently active ripple references. */
8588 private _activeRipples = new Set < RippleRef > ( ) ;
8689
@@ -90,6 +93,9 @@ export class RippleRenderer {
9093 /** Time in milliseconds when the last touchstart event happened. */
9194 private _lastTouchStartEvent : number ;
9295
96+ /** Whether pointer-up event listeners have been registered. */
97+ private _pointerUpEventsRegistered = false ;
98+
9399 /**
94100 * Cached dimensions of the ripple container. Set when the first
95101 * ripple is shown and cleared once no more ripples are visible.
@@ -104,16 +110,6 @@ export class RippleRenderer {
104110 // Only do anything if we're on the browser.
105111 if ( platform . isBrowser ) {
106112 this . _containerElement = coerceElement ( elementOrElementRef ) ;
107-
108- // Specify events which need to be registered on the trigger.
109- this . _triggerEvents
110- . set ( 'mousedown' , this . _onMousedown )
111- . set ( 'mouseup' , this . _onPointerUp )
112- . set ( 'mouseleave' , this . _onPointerUp )
113-
114- . set ( 'touchstart' , this . _onTouchStart )
115- . set ( 'touchend' , this . _onPointerUp )
116- . set ( 'touchcancel' , this . _onPointerUp ) ;
117113 }
118114 }
119115
@@ -241,17 +237,34 @@ export class RippleRenderer {
241237 // Remove all previously registered event listeners from the trigger element.
242238 this . _removeTriggerEvents ( ) ;
243239
244- this . _ngZone . runOutsideAngular ( ( ) => {
245- this . _triggerEvents . forEach ( ( fn , type ) => {
246- element . addEventListener ( type , fn , passiveEventOptions ) ;
247- } ) ;
248- } ) ;
249-
250240 this . _triggerElement = element ;
241+ this . _registerEvents ( pointerDownEvents ) ;
242+ }
243+
244+ /**
245+ * Handles all registered events.
246+ * @docs -private
247+ */
248+ handleEvent ( event : Event ) {
249+ if ( event . type === 'mousedown' ) {
250+ this . _onMousedown ( event as MouseEvent ) ;
251+ } else if ( event . type === 'touchstart' ) {
252+ this . _onTouchStart ( event as TouchEvent ) ;
253+ } else {
254+ this . _onPointerUp ( ) ;
255+ }
256+
257+ // If pointer-up events haven't been registered yet, do so now.
258+ // We do this on-demand in order to reduce the total number of event listeners
259+ // registered by the ripples, which speeds up the rendering time for large UIs.
260+ if ( ! this . _pointerUpEventsRegistered ) {
261+ this . _registerEvents ( pointerUpEvents ) ;
262+ this . _pointerUpEventsRegistered = true ;
263+ }
251264 }
252265
253266 /** Function being called whenever the trigger is being pressed using mouse. */
254- private _onMousedown = ( event : MouseEvent ) => {
267+ private _onMousedown ( event : MouseEvent ) {
255268 // Screen readers will fire fake mouse events for space/enter. Skip launching a
256269 // ripple in this case for consistency with the non-screen-reader experience.
257270 const isFakeMousedown = isFakeMousedownFromScreenReader ( event ) ;
@@ -265,7 +278,7 @@ export class RippleRenderer {
265278 }
266279
267280 /** Function being called whenever the trigger is being pressed using touch. */
268- private _onTouchStart = ( event : TouchEvent ) => {
281+ private _onTouchStart ( event : TouchEvent ) {
269282 if ( ! this . _target . rippleDisabled ) {
270283 // Some browsers fire mouse events after a `touchstart` event. Those synthetic mouse
271284 // events will launch a second ripple if we don't ignore mouse events for a specific
@@ -284,7 +297,7 @@ export class RippleRenderer {
284297 }
285298
286299 /** Function being called whenever the trigger is being released. */
287- private _onPointerUp = ( ) => {
300+ private _onPointerUp ( ) {
288301 if ( ! this . _isPointerDown ) {
289302 return ;
290303 }
@@ -309,12 +322,27 @@ export class RippleRenderer {
309322 this . _ngZone . runOutsideAngular ( ( ) => setTimeout ( fn , delay ) ) ;
310323 }
311324
325+ /** Registers event listeners for a given list of events. */
326+ private _registerEvents ( eventTypes : string [ ] ) {
327+ this . _ngZone . runOutsideAngular ( ( ) => {
328+ eventTypes . forEach ( ( type ) => {
329+ this . _triggerElement ! . addEventListener ( type , this , passiveEventOptions ) ;
330+ } ) ;
331+ } ) ;
332+ }
333+
312334 /** Removes previously registered event listeners from the trigger element. */
313335 _removeTriggerEvents ( ) {
314336 if ( this . _triggerElement ) {
315- this . _triggerEvents . forEach ( ( fn , type ) => {
316- this . _triggerElement ! . removeEventListener ( type , fn , passiveEventOptions ) ;
337+ pointerDownEvents . forEach ( ( type ) => {
338+ this . _triggerElement ! . removeEventListener ( type , this , passiveEventOptions ) ;
317339 } ) ;
340+
341+ if ( this . _pointerUpEventsRegistered ) {
342+ pointerUpEvents . forEach ( ( type ) => {
343+ this . _triggerElement ! . removeEventListener ( type , this , passiveEventOptions ) ;
344+ } ) ;
345+ }
318346 }
319347 }
320348}
0 commit comments