lightweight-router 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/router.min.js +1 -1
- package/package.json +1 -1
- package/src/router.js +39 -26
package/dist/router.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{let
|
|
1
|
+
(()=>{let l={},n=async()=>{document.body.classList.add("loading");var e=globalThis.location.pathname,t=document.querySelector("router");let o=t.querySelector(`route[path="${e}"]`);if(o||((o=document.createElement("route")).setAttribute("path",e),t.appendChild(o)),!o.innerHTML){let e=l[globalThis.location.href];e||(e=await d(globalThis.location.href),l[globalThis.location.href]=e);var n,r=(new DOMParser).parseFromString(e,"text/html"),a=r.querySelector("title"),a=(a&&(document.title=a.textContent),o.innerHTML=r.body.innerHTML,Array.from(o.querySelectorAll("script")));for(n of a){var i=document.createElement("script");n.src?i.src=n.src:i.textContent=n.textContent,n.parentNode.replaceChild(i,n)}}t.querySelectorAll("route").forEach(e=>e.style.display="none"),o.style.display="contents",document.body.classList.remove("loading"),window.scrollTo(0,0),s&&s(e)},r=async e=>{l[e.href]||(l[e.href]=await d(e.href))},a=(e,t)=>{e.forEach(e=>{e.isIntersecting&&(e=e.target,l[e.href]||(r(e),t.unobserve(e)))})},i=e=>{var t=e.target.closest("A");t&&t.href&&c(t.href)&&t.origin===location.origin&&(e.preventDefault(),globalThis.history.pushState(null,null,t.href),globalThis.dispatchEvent(new Event("popstate")))};function c(e){if(e&&!e.startsWith("#")&&!e.startsWith("javascript:")){if(e.startsWith("/"))return 1;try{var t=new URL(e,window.location.origin),o=new URL(window.location.href);return o.hostname.replace(/^www\./,"")===t.hostname.replace(/^www\./,"")?o.pathname!==t.pathname||!t.hash:void 0}catch{}}}let s,d=async e=>{e=await t(e);return e.ok?e.text():"Couldn't fetch the route - HTTP error! status: "+e.status},t=async e=>{if(!h){var t=await fetch(e,{method:"POST",body:"onlyRoute"});if(t.ok)return t}return fetch(e)},h=!1,e=(e={})=>{var t,e=e.onRouteChange,e=(e&&(e=e,s=e),document.createElement("style")),e=(e.textContent=".loading{animation:pulse 1s infinite alternate}@keyframes pulse{from{opacity:.6}to{opacity:.1}}route{content-visibility:auto}",document.head.appendChild(e),document.querySelector("router")),o=globalThis.location.pathname,o=(e||(e=document.createElement("router"),(t=document.createElement("route")).setAttribute("path",o),t.innerHTML=document.body.innerHTML,e.appendChild(t),document.body.innerHTML="",document.body.appendChild(e),h=!0),globalThis.addEventListener("popstate",n),document.addEventListener("click",i),document.body.addEventListener("mouseover",e=>{"A"===e.target.tagName&&"onHover"===e.target.getAttribute("prefetch")&&(async e=>{e=e.target;!l[e.href]&&c(e.href)&&await r(e)})(e)}),new IntersectionObserver(a,{root:null,threshold:.5}));(t=>{let o=navigator.connection&&navigator.connection.saveData;document.querySelectorAll("a").forEach(e=>{"onHover"===e.getAttribute("prefetch")||o||c(e.href)||t.observe(e)})})(o)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>e()):e()})();
|
package/package.json
CHANGED
package/src/router.js
CHANGED
|
@@ -1,50 +1,55 @@
|
|
|
1
1
|
let linkData = {};
|
|
2
2
|
const handlePopState = async () => {
|
|
3
|
-
|
|
3
|
+
document.body.classList.add("loading");
|
|
4
4
|
const currentPath = globalThis.location.pathname;
|
|
5
|
+
const router = document.querySelector("router");
|
|
5
6
|
|
|
6
7
|
let currentRoute = router.querySelector(`route[path="${currentPath}"]`);
|
|
7
8
|
|
|
9
|
+
// If the route doesn't exist in DOM, create and append it
|
|
8
10
|
if (!currentRoute) {
|
|
9
11
|
currentRoute = document.createElement("route");
|
|
10
|
-
currentRoute.setAttribute("path",
|
|
12
|
+
currentRoute.setAttribute("path", currentPath);
|
|
11
13
|
router.appendChild(currentRoute);
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
// Only fetch and render content if the route is empty
|
|
17
|
+
if (!currentRoute.innerHTML) {
|
|
18
|
+
let content = linkData[globalThis.location.href];
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
// Fetch content if it's not already cached
|
|
21
|
+
if (!content) {
|
|
22
|
+
content = await fetchContent(globalThis.location.href);
|
|
23
|
+
linkData[globalThis.location.href] = content;
|
|
24
|
+
}
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
const parser = new DOMParser();
|
|
27
|
+
const doc = parser.parseFromString(content, "text/html");
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
// Update the page title with the new content's title
|
|
30
|
+
const newTitle = doc.querySelector("title");
|
|
31
|
+
if (newTitle) document.title = newTitle.textContent;
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
currentRoute.innerHTML = doc.body.innerHTML;
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
// Execute scripts from the fetched content
|
|
36
|
+
const scripts = Array.from(currentRoute.querySelectorAll("script"));
|
|
37
|
+
for (const oldScript of scripts) {
|
|
38
|
+
const newScript = document.createElement("script");
|
|
39
|
+
if (oldScript.src) {
|
|
40
|
+
newScript.src = oldScript.src;
|
|
41
|
+
} else {
|
|
42
|
+
newScript.textContent = oldScript.textContent;
|
|
43
|
+
}
|
|
44
|
+
oldScript.parentNode.replaceChild(newScript, oldScript);
|
|
39
45
|
}
|
|
40
|
-
oldScript.parentNode.replaceChild(newScript, oldScript);
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
// Display only the current route
|
|
43
49
|
router.querySelectorAll("route").forEach(route => (route.style.display = "none"));
|
|
44
50
|
currentRoute.style.display = "contents";
|
|
45
51
|
|
|
46
52
|
document.body.classList.remove("loading");
|
|
47
|
-
// Reset scroll position to the top
|
|
48
53
|
window.scrollTo(0, 0);
|
|
49
54
|
|
|
50
55
|
// Call the route change handler if it's set
|
|
@@ -152,8 +157,8 @@ const startRouter = (options = {}) => {
|
|
|
152
157
|
animation: pulse 1s infinite alternate;
|
|
153
158
|
}
|
|
154
159
|
@keyframes pulse {
|
|
155
|
-
from { opacity: 0.
|
|
156
|
-
to { opacity: 0.
|
|
160
|
+
from { opacity: 0.6; }
|
|
161
|
+
to { opacity: 0.1; }
|
|
157
162
|
}
|
|
158
163
|
route {
|
|
159
164
|
content-visibility: auto;
|
|
@@ -189,3 +194,11 @@ const startRouter = (options = {}) => {
|
|
|
189
194
|
};
|
|
190
195
|
|
|
191
196
|
export { startRouter };
|
|
197
|
+
|
|
198
|
+
// TODO: create ultra minified version or deploy
|
|
199
|
+
// TODO: write proper automated tests
|
|
200
|
+
// - add support for prefetching on hover
|
|
201
|
+
// - add support for prefetching on click
|
|
202
|
+
// - add support for prefetching on scroll
|
|
203
|
+
// - add support for prefetching on focus
|
|
204
|
+
// - add support for prefetching on touch
|