2021-04-09 22:00:24 +03:00
|
|
|
import userInit from "/index.js";
|
|
|
|
|
|
|
|
let prefetchedPages;
|
|
|
|
let initialLocationHash;
|
|
|
|
|
|
|
|
function pagesInit(
|
|
|
|
/** @type { mainElmModule: { init: any } } */ { mainElmModule }
|
|
|
|
) {
|
|
|
|
prefetchedPages = [window.location.pathname];
|
|
|
|
initialLocationHash = document.location.hash.replace(/^#/, "");
|
|
|
|
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
document.addEventListener("DOMContentLoaded", (_) => {
|
|
|
|
loadContentAndInitializeApp(mainElmModule).then(resolve, reject);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getContentJsonPromise(path) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
if (window.__elmPagesContentJson__) {
|
|
|
|
console.log("GOT content.json from window");
|
|
|
|
resolve(window.__elmPagesContentJson__);
|
|
|
|
} else {
|
|
|
|
return httpGet(`${window.location.origin}${path}content.json`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadContentAndInitializeApp(
|
|
|
|
/** @type { init: any } */ mainElmModule
|
|
|
|
) {
|
|
|
|
let path = window.location.pathname.replace(/(\w)$/, "$1/");
|
|
|
|
if (!path.endsWith("/")) {
|
|
|
|
path = path + "/";
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.all([getContentJsonPromise(path)]).then(function (
|
|
|
|
/** @type {[JSON]} */ [contentJson]
|
|
|
|
) {
|
|
|
|
const app = mainElmModule.init({
|
|
|
|
flags: {
|
|
|
|
secrets: null,
|
|
|
|
baseUrl: document.baseURI,
|
|
|
|
isPrerendering: false,
|
|
|
|
isDevServer: false,
|
|
|
|
isElmDebugMode: false,
|
|
|
|
contentJson,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2021-05-15 05:33:52 +03:00
|
|
|
app.ports.toJsPort.subscribe((fromElm) => {
|
|
|
|
loadNamedAnchor();
|
2021-04-09 22:00:24 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
return app;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadNamedAnchor() {
|
|
|
|
if (initialLocationHash !== "") {
|
|
|
|
const namedAnchor = document.querySelector(`[name=${initialLocationHash}]`);
|
|
|
|
namedAnchor && namedAnchor.scrollIntoView();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function prefetchIfNeeded(/** @type {HTMLAnchorElement} */ target) {
|
|
|
|
if (target.host === window.location.host) {
|
|
|
|
if (prefetchedPages.includes(target.pathname)) {
|
|
|
|
// console.log("Already preloaded", target.href);
|
|
|
|
// console.log("Not a known route, skipping preload", target.pathname);
|
|
|
|
} else if (
|
2021-05-15 05:33:52 +03:00
|
|
|
// !allRoutes.includes(new URL(target.pathname, document.baseURI).href)
|
|
|
|
false
|
2021-04-09 22:00:24 +03:00
|
|
|
) {
|
|
|
|
} else {
|
|
|
|
prefetchedPages.push(target.pathname);
|
|
|
|
// console.log("Preloading...", target.pathname);
|
|
|
|
const link = document.createElement("link");
|
|
|
|
link.setAttribute("as", "fetch");
|
|
|
|
|
|
|
|
link.setAttribute("rel", "prefetch");
|
|
|
|
link.setAttribute("href", origin + target.pathname + "/content.json");
|
|
|
|
document.head.appendChild(link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function httpGet(/** @type string */ theUrl) {
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
const xmlHttp = new XMLHttpRequest();
|
|
|
|
xmlHttp.onreadystatechange = function () {
|
|
|
|
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
|
|
|
|
resolve(JSON.parse(xmlHttp.responseText));
|
|
|
|
};
|
|
|
|
xmlHttp.onerror = reject;
|
|
|
|
xmlHttp.open("GET", theUrl, true); // true for asynchronous
|
|
|
|
xmlHttp.send(null);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const appPromise = pagesInit({
|
|
|
|
mainElmModule: Elm.TemplateModulesBeta,
|
|
|
|
});
|
|
|
|
userInit(appPromise);
|
|
|
|
|
2021-04-18 07:21:17 +03:00
|
|
|
if (typeof connect === "function") {
|
|
|
|
connect(function (newContentJson) {
|
|
|
|
appPromise.then((app) => {
|
|
|
|
app.ports.fromJsPort.send({ contentJson: newContentJson });
|
|
|
|
});
|
2021-04-09 22:00:24 +03:00
|
|
|
});
|
2021-04-18 07:21:17 +03:00
|
|
|
}
|
2021-05-15 05:33:52 +03:00
|
|
|
|
|
|
|
/** @param {MouseEvent} event */
|
|
|
|
const trigger_prefetch = (event) => {
|
|
|
|
const a = find_anchor(/** @type {Node} */ (event.target));
|
|
|
|
if (a && a.href && a.hasAttribute("elm-pages:prefetch")) {
|
|
|
|
console.log("PREFETCH", a.href);
|
|
|
|
prefetchIfNeeded(a);
|
|
|
|
// this.prefetch(new URL(/** @type {string} */ (a.href)));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** @type {NodeJS.Timeout} */
|
|
|
|
let mousemove_timeout;
|
|
|
|
|
|
|
|
/** @param {MouseEvent} event */
|
|
|
|
const handle_mousemove = (event) => {
|
|
|
|
clearTimeout(mousemove_timeout);
|
|
|
|
mousemove_timeout = setTimeout(() => {
|
|
|
|
trigger_prefetch(event);
|
|
|
|
}, 20);
|
|
|
|
};
|
|
|
|
|
|
|
|
addEventListener("touchstart", trigger_prefetch);
|
|
|
|
addEventListener("mousemove", handle_mousemove);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {Node} node
|
|
|
|
// * @rturns {HTMLAnchorElement | SVGAElement}
|
|
|
|
* @returns {HTMLAnchorElement}
|
|
|
|
*/
|
|
|
|
function find_anchor(node) {
|
|
|
|
while (node && node.nodeName.toUpperCase() !== "A") node = node.parentNode; // SVG <a> elements have a lowercase name
|
|
|
|
// return /** @type {HTMLAnchorElement | SVGAElement} */ (node);
|
|
|
|
return /** @type {HTMLAnchorElement} */ (node);
|
|
|
|
}
|