Skip to content

Instantly share code, notes, and snippets.

@julianrubisch
Created July 13, 2021 14:46
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save julianrubisch/6262811ced05d94b42cccd303647c242 to your computer and use it in GitHub Desktop.
Save julianrubisch/6262811ced05d94b42cccd303647c242 to your computer and use it in GitHub Desktop.
import { Controller } from "stimulus";
import { get } from "@rails/request.js";
import { PageSnapshot } from "@hotwired/turbo";
export default class extends Controller {
static values = { hoverTime: Number };
connect() {
this.element.addEventListener("mouseover", this.prefetch.bind(this));
this.element.addEventListener("touchstart", this.prefetch.bind(this));
}
async prefetch(e) {
if (this.prefetched) return;
const response = await get(this.url.toString());
if (response.ok) {
const html = await response.html;
const snapshot = snapshotFromHTML(html);
Turbo.navigator.view.snapshotCache.put(this.url, snapshot);
}
}
get prefetched() {
return (
location.href === this.url ||
Turbo.navigator.view.snapshotCache.has(this.url)
);
}
get url() {
this._url =
this._url || new URL(this.element.getAttribute("href"), document.baseURI);
return this._url;
}
get hoverTime() {
return this.hoverTimeValue || 300;
}
}
const snapshotFromHTML = (html) => PageSnapshot.fromHTMLString(html);
@adrienpoly
Copy link

maybe add a teardown function to remove the event listeners

  disconnect() {
    this.element.removeEventListener("mouseover", this.prefetch);
    this.element.removeEventListener("touchstart", this.prefetch);
  }

@KonnorRogers
Copy link

KonnorRogers commented Jul 25, 2021

As a fun exercise, I wanted to see what this would look like with mrujs new prefetch mechanism...

// app/javascript/packs/application.js
import mrujs from "mrujs"
import * as Turbo from "@hotwired/turbo"

mrujs.start()

// prefetch_controller.js
import { Controller } from "stimulus";

export default class extends Controller {
  static values = { hoverTime: Number };
  initialize() {
    this.boundPrefetch = this.prefetch.bind(this);    
  }

  connect() {
    this.element.addEventListener("mouseover", this.boundPrefetch);
    this.element.addEventListener("touchstart", this.boundPrefetch);
  }

  disconnect() {
     this.element.removeEventListener("mouseover", this.boundPrefetch);
     this.element.removeEventListener("touchstart", this.boundPrefetch);
  }

  prefetch(e) {
    if (this.prefetched) return;
    
    window.mrujs.fetch(this.url, { method: "get" })
      .then((response) => response.text())
      .then((html) => window.mrujs.navigationAdapter.prefetch({ url: this.url, html }))
      .catch((err) => console.error(err))
  }

  get prefetched() {
    return (
      location.href === this.url ||
      window.mrujs.navigationAdapter.cacheContains(this.url)
    );
  }

  get url() {
    this._url =
      this._url || new URL(this.element.getAttribute("href"), document.baseURI);

    return this._url;
  }

  get hoverTime() {
    return this.hoverTimeValue || 300;
  }
}

this solution will also work for Turbolinks as well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment