| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | 
							- /*
 
-  * Copyright 2020 Google LLC
 
-  *
 
-  * Licensed under the Apache License, Version 2.0 (the "License");
 
-  * you may not use this file except in compliance with the License.
 
-  * You may obtain a copy of the License at
 
-  *
 
-  *     https://www.apache.org/licenses/LICENSE-2.0
 
-  *
 
-  * Unless required by applicable law or agreed to in writing, software
 
-  * distributed under the License is distributed on an "AS IS" BASIS,
 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-  * See the License for the specific language governing permissions and
 
-  * limitations under the License.
 
-  */
 
- let firstInputEvent;
 
- let firstInputDelay;
 
- let firstInputTimeStamp;
 
- let callbacks;
 
- const listenerOpts = { passive: true, capture: true };
 
- const startTimeStamp = new Date();
 
- /**
 
-  * Accepts a callback to be invoked once the first input delay and event
 
-  * are known.
 
-  */
 
- export const firstInputPolyfill = (onFirstInput) => {
 
-     callbacks.push(onFirstInput);
 
-     reportFirstInputDelayIfRecordedAndValid();
 
- };
 
- export const resetFirstInputPolyfill = () => {
 
-     callbacks = [];
 
-     firstInputDelay = -1;
 
-     firstInputEvent = null;
 
-     eachEventType(addEventListener);
 
- };
 
- /**
 
-  * Records the first input delay and event, so subsequent events can be
 
-  * ignored. All added event listeners are then removed.
 
-  */
 
- const recordFirstInputDelay = (delay, event) => {
 
-     if (!firstInputEvent) {
 
-         firstInputEvent = event;
 
-         firstInputDelay = delay;
 
-         firstInputTimeStamp = new Date;
 
-         eachEventType(removeEventListener);
 
-         reportFirstInputDelayIfRecordedAndValid();
 
-     }
 
- };
 
- /**
 
-  * Reports the first input delay and event (if they're recorded and valid)
 
-  * by running the array of callback functions.
 
-  */
 
- const reportFirstInputDelayIfRecordedAndValid = () => {
 
-     // In some cases the recorded delay is clearly wrong, e.g. it's negative
 
-     // or it's larger than the delta between now and initialization.
 
-     // - https://github.com/GoogleChromeLabs/first-input-delay/issues/4
 
-     // - https://github.com/GoogleChromeLabs/first-input-delay/issues/6
 
-     // - https://github.com/GoogleChromeLabs/first-input-delay/issues/7
 
-     if (firstInputDelay >= 0 &&
 
-         // @ts-ignore (subtracting two dates always returns a number)
 
-         firstInputDelay < firstInputTimeStamp - startTimeStamp) {
 
-         const entry = {
 
-             entryType: 'first-input',
 
-             name: firstInputEvent.type,
 
-             target: firstInputEvent.target,
 
-             cancelable: firstInputEvent.cancelable,
 
-             startTime: firstInputEvent.timeStamp,
 
-             processingStart: firstInputEvent.timeStamp + firstInputDelay,
 
-         };
 
-         callbacks.forEach(function (callback) {
 
-             callback(entry);
 
-         });
 
-         callbacks = [];
 
-     }
 
- };
 
- /**
 
-  * Handles pointer down events, which are a special case.
 
-  * Pointer events can trigger main or compositor thread behavior.
 
-  * We differentiate these cases based on whether or not we see a
 
-  * 'pointercancel' event, which are fired when we scroll. If we're scrolling
 
-  * we don't need to report input delay since FID excludes scrolling and
 
-  * pinch/zooming.
 
-  */
 
- const onPointerDown = (delay, event) => {
 
-     /**
 
-      * Responds to 'pointerup' events and records a delay. If a pointer up event
 
-      * is the next event after a pointerdown event, then it's not a scroll or
 
-      * a pinch/zoom.
 
-      */
 
-     const onPointerUp = () => {
 
-         recordFirstInputDelay(delay, event);
 
-         removePointerEventListeners();
 
-     };
 
-     /**
 
-      * Responds to 'pointercancel' events and removes pointer listeners.
 
-      * If a 'pointercancel' is the next event to fire after a pointerdown event,
 
-      * it means this is a scroll or pinch/zoom interaction.
 
-      */
 
-     const onPointerCancel = () => {
 
-         removePointerEventListeners();
 
-     };
 
-     /**
 
-      * Removes added pointer event listeners.
 
-      */
 
-     const removePointerEventListeners = () => {
 
-         removeEventListener('pointerup', onPointerUp, listenerOpts);
 
-         removeEventListener('pointercancel', onPointerCancel, listenerOpts);
 
-     };
 
-     addEventListener('pointerup', onPointerUp, listenerOpts);
 
-     addEventListener('pointercancel', onPointerCancel, listenerOpts);
 
- };
 
- /**
 
-  * Handles all input events and records the time between when the event
 
-  * was received by the operating system and when it's JavaScript listeners
 
-  * were able to run.
 
-  */
 
- const onInput = (event) => {
 
-     // Only count cancelable events, which should trigger behavior
 
-     // important to the user.
 
-     if (event.cancelable) {
 
-         // In some browsers `event.timeStamp` returns a `DOMTimeStamp` value
 
-         // (epoch time) instead of the newer `DOMHighResTimeStamp`
 
-         // (document-origin time). To check for that we assume any timestamp
 
-         // greater than 1 trillion is a `DOMTimeStamp`, and compare it using
 
-         // the `Date` object rather than `performance.now()`.
 
-         // - https://github.com/GoogleChromeLabs/first-input-delay/issues/4
 
-         const isEpochTime = event.timeStamp > 1e12;
 
-         const now = isEpochTime ? new Date : performance.now();
 
-         // Input delay is the delta between when the system received the event
 
-         // (e.g. event.timeStamp) and when it could run the callback (e.g. `now`).
 
-         const delay = now - event.timeStamp;
 
-         if (event.type == 'pointerdown') {
 
-             onPointerDown(delay, event);
 
-         }
 
-         else {
 
-             recordFirstInputDelay(delay, event);
 
-         }
 
-     }
 
- };
 
- /**
 
-  * Invokes the passed callback const for =  each event type with t =>he
 
-  * `onInput` const and =  `listenerOpts =>`.
 
-  */
 
- const eachEventType = (callback) => {
 
-     const eventTypes = [
 
-         'mousedown',
 
-         'keydown',
 
-         'touchstart',
 
-         'pointerdown',
 
-     ];
 
-     eventTypes.forEach((type) => callback(type, onInput, listenerOpts));
 
- };
 
 
  |