gijo-varghese / flying-pages

Load inner pages instantly, intelligently
ISC License
211 stars 21 forks source link

a.target.closest #18

Open harryfear opened 2 weeks ago

harryfear commented 2 weeks ago

Getting error a.target.closest is not a function on some Chrome contexts:—

  // Add URL to queue on mouse hover, after timeout
  const mouseOverListener = (event) => {
    const elm = event.target.closest("a");
    if (elm && elm.href && !alreadyPrefetched.has(elm.href)) {
      hoverTimer = setTimeout(() => {
        addUrlToQueue(elm.href, true);
      }, window.FPConfig.hoverDelay);
    }
  };

  // Prefetch on touchstart on mobile
  const touchStartListener = (event) => {
    const elm = event.target.closest("a");
    if (elm && elm.href && !alreadyPrefetched.has(elm.href))
      addUrlToQueue(elm.href, true);
  };

  // Clear timeout on mouse out if not already prefetched
  const mouseOutListener = (event) => {
    const elm = event.target.closest("a");
    if (elm && elm.href && !alreadyPrefetched.has(elm.href)) {
      clearTimeout(hoverTimer);
    }
  };

Claude says: "This can happen if the event target is a text node or a non-element node."

Element.closest() method is supported in Chrome 75 but I'm seeing the error in Chrome 75-128.

gijo-varghese commented 2 weeks ago

@harryfear please share the steps to reproduce

harryfear commented 2 weeks ago

One possible fix could be:

const target = event.target.nodeType === Node.ELEMENT_NODE ? event.target : event.target.parentElement;

In Chrome 75-128 and Firefox 105:

<div id="container">
  <a href="https://example.com">
    Click <span>here</span>
  </a>
</div>

If the element is removed during another operation, it will fail:

    <div id="container">
        <a href="https://example.com" id="testLink">Click me to simulate error</a>
    </div>

    <script>
        function setupDemo() {
            const container = document.getElementById('container');

            container.addEventListener('click', (event) => {
                event.preventDefault();
                console.log("Click event triggered");

                // Store the original target
                const originalTarget = event.target;

                // Remove the element from the DOM
                const link = document.getElementById('testLink');
                if (link) {
                    console.log("Removing link element");
                    link.remove();
                }

                // Nullify the element's properties to simulate complete removal
                Object.setPrototypeOf(originalTarget, null);

                // Now try to use closest() on the nullified target
                try {
                    console.log("Attempting to call closest()");
                    const elm = originalTarget.closest("a");
                    if (elm && elm.href) {
                        console.log("Clicked link:", elm.href);
                    }
                } catch (error) {
                    console.error("Error:", error.message);
                }
            });
        }

        document.addEventListener('DOMContentLoaded', setupDemo);
    </script>