1+ /*!
2+ * @license
3+ * Copyright Google LLC All Rights Reserved.
4+ *
5+ * Use of this source code is governed by an MIT-style license that can be
6+ * found in the LICENSE file at https://angular.dev/license
7+ */
18
29/** Configuration object used to register passive and capturing events. */
310const eventListenerOptions : AddEventListenerOptions = {
@@ -12,7 +19,7 @@ const hoverTriggers = new WeakMap<Element, DeferEventEntry>();
1219const interactionTriggers = new WeakMap < Element , DeferEventEntry > ( ) ;
1320
1421/** Currently-registered `viewport` triggers. */
15- const viewportTriggers = new WeakMap < Element , DeferEventEntry > ( ) ;
22+ export const viewportTriggers = new WeakMap < Element , DeferEventEntry > ( ) ;
1623
1724/** Names of the events considered as interaction events. */
1825export const interactionEventNames = [ 'click' , 'keydown' ] as const ;
@@ -37,14 +44,12 @@ class DeferEventEntry {
3744 } ;
3845}
3946
40- export function getViewportTriggers ( ) {
41- return viewportTriggers ;
42- }
43-
4447/**
4548 * Registers an interaction trigger.
4649 * @param trigger Element that is the trigger.
4750 * @param callback Callback to be invoked when the trigger is interacted with.
51+ * @return cleanup function which removes trigger Element from interactionTriggers map
52+ * and interaction event listeners from the trigger Element
4853 */
4954export function onInteraction ( trigger : Element , callback : VoidFunction ) : VoidFunction {
5055 let entry = interactionTriggers . get ( trigger ) ;
@@ -86,11 +91,12 @@ export function onInteraction(trigger: Element, callback: VoidFunction): VoidFun
8691 } ;
8792}
8893
89-
9094/**
9195 * Registers a hover trigger.
9296 * @param trigger Element that is the trigger.
9397 * @param callback Callback to be invoked when the trigger is hovered over.
98+ * @return cleanup function which removes trigger element from hoverTriggers map
99+ * and removes hover interaction event listeners from the trigger element
94100 */
95101export function onHover ( trigger : Element , callback : VoidFunction ) : VoidFunction {
96102 let entry = hoverTriggers . get ( trigger ) ;
@@ -120,125 +126,63 @@ export function onHover(trigger: Element, callback: VoidFunction): VoidFunction
120126 } ;
121127}
122128
123- export interface Observer {
124- observe : ( target : Element ) => void ,
125- unobserve : ( target : Element ) => void ,
126- disconnect : ( ) => void ;
129+ /**
130+ * Used to create an IntersectionObserver instance.
131+ * @return IntersectionObserver that is used by onViewport
132+ */
133+ export function createIntersectionObserver ( ) {
134+ return new IntersectionObserver ( ( entries ) => {
135+ for ( const current of entries ) {
136+ if ( current . isIntersecting && viewportTriggers . has ( current . target ) ) {
137+ viewportTriggers . get ( current . target ) ! . listener ( ) ;
138+ }
139+ }
140+ } ) ;
127141}
128142
129143/**
130144 * Registers a viewport trigger.
131145 * @param trigger Element that is the trigger.
132146 * @param callback Callback to be invoked when the trigger comes into the viewport.
133- * @param observer Observer interface which provides a way to observe changes to target element
147+ * @param observerFactoryFn Factory function which returns an IntersectionObserver
148+ * @return cleanup function which removes trigger Element from viewportTriggers map
149+ * and tells the intersection observer to stop observing trigger Element and set
150+ * intersectionObserver to null if there are no more Elements to observe
134151 */
135152export function onViewport (
136153 trigger : Element ,
137154 callback : VoidFunction ,
138- observer : Observer ,
155+ observerFactoryFn : ( ) => IntersectionObserver ,
139156) : VoidFunction {
140157 let entry = viewportTriggers . get ( trigger ) ;
141158
159+ intersectionObserver = intersectionObserver || observerFactoryFn ( ) ;
160+
142161 if ( ! entry ) {
143162 entry = new DeferEventEntry ( ) ;
144- observer . observe ( trigger ) ;
163+ intersectionObserver ! . observe ( trigger ) ;
145164 viewportTriggers . set ( trigger , entry ) ;
146165 observedViewportElements ++ ;
147166 }
148167
149168 entry . callbacks . add ( callback ) ;
150169
151170 return ( ) => {
152- // It's possible that a different cleanup callback fully removed this element already.
153171 if ( ! viewportTriggers . has ( trigger ) ) {
154172 return ;
155173 }
156174
157175 entry ! . callbacks . delete ( callback ) ;
158176
159177 if ( entry ! . callbacks . size === 0 ) {
160- observer . unobserve ( trigger ) ;
178+ intersectionObserver ? .unobserve ( trigger ) ;
161179 viewportTriggers . delete ( trigger ) ;
162180 observedViewportElements -- ;
163181 }
164182
165183 if ( observedViewportElements === 0 ) {
166- observer . disconnect ( ) ;
184+ intersectionObserver ?. disconnect ( ) ;
185+ intersectionObserver = null ;
167186 }
168187 } ;
169188}
170-
171-
172- // function createIntersectionObserver(ngZone: NgZone | undefined): IntersectionObserver {
173- // return new IntersectionObserver((entries) => {
174- // for (const current of entries) {
175- // // Only invoke the callbacks if the specific element is intersecting.
176- // if (current.isIntersecting && viewportTriggers.has(current.target)) {
177- // if (ngZone) {
178- // ngZone!.run(viewportTriggers.get(current.target)!.listener);
179- // } else {
180- // viewportTriggers.get(current.target)!.listener();
181- // }
182- // }
183- // }
184- // })
185- // }
186-
187- // /**
188- // * Registers a viewport trigger.
189- // * @param trigger Element that is the trigger.
190- // * @param callback Callback to be invoked when the trigger comes into the viewport.
191- // * @param injector Injector that can be used by the trigger to resolve DI tokens.
192- // */
193- // export function onViewport(
194- // trigger: Element,
195- // callback: VoidFunction,
196- // injector?: Injector,
197- // ): VoidFunction {
198- // const ngZone = injector?.get(NgZone);
199- // let entry = viewportTriggers.get(trigger);
200-
201- // if (!intersectionObserver) {
202- // if (injector) {
203- // intersectionObserver = ngZone!.runOutsideAngular(() => {
204- // return createIntersectionObserver(ngZone);
205- // });
206- // } else {
207- // intersectionObserver = createIntersectionObserver(ngZone);
208- // }
209- // }
210-
211- // if (!entry) {
212- // entry = new DeferEventEntry();
213- // if (ngZone) {
214- // ngZone.runOutsideAngular(() => intersectionObserver!.observe(trigger));
215- // } else {
216- // intersectionObserver!.observe(trigger);
217- // }
218- // viewportTriggers.set(trigger, entry);
219- // observedViewportElements++;
220- // }
221-
222- // entry.callbacks.add(callback);
223-
224- // return () => {
225- // // It's possible that a different cleanup callback fully removed this element already.
226- // if (!viewportTriggers.has(trigger)) {
227- // return;
228- // }
229-
230- // entry!.callbacks.delete(callback);
231-
232- // if (entry!.callbacks.size === 0) {
233- // intersectionObserver?.unobserve(trigger);
234- // viewportTriggers.delete(trigger);
235- // observedViewportElements--;
236- // }
237-
238- // if (observedViewportElements === 0) {
239- // intersectionObserver?.disconnect();
240- // intersectionObserver = null;
241- // }
242- // };
243- // }
244-
0 commit comments