@stimulus-library/controllers
Version:
A library of useful controllers for Stimulus
69 lines (68 loc) • 2.37 kB
JavaScript
import { BaseController, warn } from "@stimulus-library/utilities";
import { useEventListener } from "@stimulus-library/mixins";
export class PrefetchController extends BaseController {
get _mode() {
return this.hasModeValue ? this.modeValue : "mouseover";
}
get _supportsPrefetch() {
var _a, _b;
const link = document.createElement("link");
return ((_a = link.relList) === null || _a === void 0 ? void 0 : _a.supports) && ((_b = link.relList) === null || _b === void 0 ? void 0 : _b.supports("prefetch"));
}
get _href() {
return this.el.href;
}
get _existingPrefetch() {
return (document.head.querySelectorAll(`link[rel="prefetch"][href="${this._href}"]`) || []).length > 0;
}
get _connectionSuitable() {
const connection = navigator.connection;
if (!connection) {
return true;
}
if (connection) {
if (connection.saveData) {
warn(this, "Data Saving is enabled");
return false;
}
if (/2g/.test(connection.effectiveType)) {
warn(this, "Network is too slow");
return false;
}
}
return true;
}
connect() {
if (!this._supportsPrefetch) {
return;
}
switch (this._mode) {
case "intersect":
this._setupObserver();
break;
case "mouseover":
useEventListener(this, this.el, "mouseover", this.prefetch, { once: true });
break;
default:
throw new Error(`'${this._mode}' is not a supported prefetch mode`);
}
}
_setupObserver() {
const observer = new IntersectionObserver(([entry], observer) => {
if (entry.isIntersecting) {
this.prefetch();
observer.unobserve(entry.target);
}
});
observer.observe(this.element);
}
prefetch() {
if (this._existingPrefetch || !this._connectionSuitable) {
return;
}
const link = document.createElement("link");
Object.assign(link, { rel: "prefetch", href: this._href, as: "document" });
document.head.appendChild(link);
}
}
PrefetchController.values = { mode: String };