diff --git a/src/observers/link_prefetch_observer.js b/src/observers/link_prefetch_observer.js index 165569dbd..99231e677 100644 --- a/src/observers/link_prefetch_observer.js +++ b/src/observers/link_prefetch_observer.js @@ -9,10 +9,14 @@ import { StreamMessage } from "../core/streams/stream_message" import { FetchMethod, FetchRequest } from "../http/fetch_request" import { prefetchCache, cacheTtl } from "../core/drive/prefetch_cache" +const observedEvents = { + "mouseenter": "mouseleave", + "touchstart": "touchcancel" +} + export class LinkPrefetchObserver { started = false - hoverTriggerEvent = "mouseenter" - touchTriggerEvent = "touchstart" + #linkToPrefetch = null constructor(delegate, eventTarget) { this.delegate = delegate @@ -32,26 +36,30 @@ export class LinkPrefetchObserver { stop() { if (!this.started) return - this.eventTarget.removeEventListener(this.hoverTriggerEvent, this.#tryToPrefetchRequest, { - capture: true, - passive: true - }) - this.eventTarget.removeEventListener(this.touchTriggerEvent, this.#tryToPrefetchRequest, { - capture: true, - passive: true + Object.entries(observedEvents).forEach(([startEventName, stopEventName]) => { + this.eventTarget.removeEventListener(startEventName, this.#tryToPrefetchRequest, { + capture: true, + passive: true + }) + this.eventTarget.removeEventListener(stopEventName, this.#tryToCancelPrefetchRequest, { + capture: true, + passive: true + }) }) this.eventTarget.removeEventListener("turbo:before-fetch-request", this.#tryToUsePrefetchedRequest, true) this.started = false } #enable = () => { - this.eventTarget.addEventListener(this.hoverTriggerEvent, this.#tryToPrefetchRequest, { - capture: true, - passive: true - }) - this.eventTarget.addEventListener(this.touchTriggerEvent, this.#tryToPrefetchRequest, { - capture: true, - passive: true + Object.entries(observedEvents).forEach(([startEventName, stopEventName]) => { + this.eventTarget.addEventListener(startEventName, this.#tryToPrefetchRequest, { + capture: true, + passive: true + }) + this.eventTarget.addEventListener(stopEventName, this.#tryToCancelPrefetchRequest, { + capture: true, + passive: true + }) }) this.eventTarget.addEventListener("turbo:before-fetch-request", this.#tryToUsePrefetchedRequest, true) this.started = true @@ -68,6 +76,7 @@ export class LinkPrefetchObserver { const location = getLocationForLink(link) if (this.delegate.canPrefetchRequestToLocation(link, location)) { + this.#linkToPrefetch = link const fetchRequest = new FetchRequest( this, FetchMethod.get, @@ -77,12 +86,18 @@ export class LinkPrefetchObserver { ) prefetchCache.setLater(location.toString(), fetchRequest, this.#cacheTtl) - - link.addEventListener("mouseleave", () => prefetchCache.clear(), { once: true }) } } } + #tryToCancelPrefetchRequest = (event) => { + if (event.target === this.#linkToPrefetch) { + prefetchCache.clear() + } + + this.#linkToPrefetch = null + } + #tryToUsePrefetchedRequest = (event) => { if (event.target.tagName !== "FORM" && event.detail.fetchOptions.method === "get") { const cached = prefetchCache.get(event.detail.url.toString())