Skip to content

Commit

Permalink
Merge pull request #10 from Netcentric/router
Browse files Browse the repository at this point in the history
Initial Router version
  • Loading branch information
nc-andreashaller authored Mar 1, 2024
2 parents 74f16c4 + 901640f commit e57afa5
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 0 deletions.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions packages/scripts/router/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# eddys-router
SPA Style router with soft naviagtion betweeen pages

## Description
This is a simple router that uses the `fetch` API to load content from the server and update just the `<main>` tag.
It also uses the `history` API to update the URL and listen for changes to the URL.

Excluded paths can be configured in the router.js file to prevent the router from loading content for certain paths. This is useful for paths that should be loaded in the traditional way, (for example, a page that contains a react app using react-router)

If other components need to be updated when the URL changes (for example the navigation), they can listen for the `router:navgate` event on the `window` object. (see `listenToNavigationeEvents()` in `header.js` for an example)

## How to use
1. Install the router.js to your repository

```bash
npm i @netcentric/eddys-router
```

2. Load the router script in your head.html file

```html
<script src="/libs/eddys-router/router.js" type="module"></script>
```

3. Configure the excluded paths

```javascript
window.router = {
excludedPaths: [
'/content/excluded-path',
'/content/excluded-path-2'
];
};
```

4. If needed listen for the `router:navgate` event in other components

```javascript
window.addEventListener('router:navgate', (event) => {
// do something with the event
});
```

## Demo Links

- Preview: https://main--eddys-router--nfarmache-nc.hlx.page/
- Live: https://main--eddys-router--nfarmache-nc.hlx.live/
117 changes: 117 additions & 0 deletions packages/scripts/router/libs/eddys-router/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { decorateMain } from '../scripts/scripts.js';
import { loadBlocks, decorateTemplateAndTheme } from '../scripts/aem.js';



function isPathExcluded(path) {
return ((window.router || {}).excludedPaths || []).some((excludedPath) => (
path === excludedPath
|| path.startsWith(`${excludedPath}/`)
));
}

function emitNavigateEvent() {
window.dispatchEvent(
new CustomEvent('router:navgate', {
bubbles: true,
}),
);
}

async function render(html) {
const main = document.querySelector('body>main');
const head = document.querySelector('html>head');
const newDocument = new DOMParser().parseFromString(html, 'text/html');
const newHead = newDocument.querySelector('html>head');

// replace meta tags
[...head.querySelectorAll('meta')].forEach((tag) => tag.remove());
const metaHtml = [...newHead.querySelectorAll('meta')].map((meta) => (meta).outerHTML).join('\n');
head.querySelector('title').insertAdjacentHTML('afterend', metaHtml);

// replace title
document.title = newDocument.title;

// replace main
main.innerHTML = newDocument.querySelector('body>main').innerHTML;
main.classList.add('hidden');
document.body.className = 'appear';
decorateTemplateAndTheme();
decorateMain(main);
await loadBlocks(main);
main.classList.remove('hidden');
emitNavigateEvent();
}

async function navigate(path, shouldPushState = true) {
fetch(path)
.then((response) => {
const contentType = response.headers.get('content-type');
if (!response.ok || !contentType || !contentType.includes('text/html')) {
window.location.href = path;
}

return response.text();
})
.then(async (html) => {
if (shouldPushState) {
window.history.pushState({}, '', path);
}

await render(html);
});
}

function checkUrl(href, force = false) {
const url = new URL(href, document.location.href);
const path = `${url.pathname}${url.search}${url.hash}`;
const simplePath = url.pathname;

if (force) {
return { path, shouldFetchPage: true };
}

// check origin
if (url.origin !== document.location.origin) {
return { shouldFetchPage: false };
}

// check if it's the same page
if (simplePath === document.location.pathname) {
return { shouldFetchPage: false };
}

// check excluded paths
if (isPathExcluded(simplePath)) {
return { shouldFetchPage: false };
}

// ok
return { path, shouldFetchPage: true };
}

const clickHandler = (event) => {
const { target } = event;
if (target.tagName !== 'A' || typeof target.href === 'undefined') return;
const { shouldFetchPage, path } = checkUrl(target.href);
if (!shouldFetchPage) return;

event.preventDefault();
navigate(path);
};

const popstateHandler = () => {
const { path } = checkUrl(document.location.href, true);
navigate(path, false);
};

function router() {
if (isPathExcluded(document.location.pathname)) {
return;
}

document.addEventListener('click', clickHandler);
window.addEventListener('popstate', popstateHandler);
}

router();
35 changes: 35 additions & 0 deletions packages/scripts/router/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@netcentric/eddys-router",
"version": "1.0.0",
"description": "Plugin to add SPA style routing to AEM EdgeDelivery sites.",
"license": "Apache-2.0",
"private": false,
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/netcentric/eddys-collection.git"
},
"main": "router.js",
"author": "Cognizant Netcentric (https://www.netcentric.biz)",
"scripts": {
"postinstall": "node install.js",
"release": "semantic-release",
"test": "echo \"eddys-router\""
},
"browserslist": [
"last 2 versions",
"not ie > 0",
"not ie_mob > 0",
"not dead",
"not OperaMini all"
],
"engines": {
"node": ">=18.0.0"
},
"files": [
"./libs",
"install.js"
]
}

0 comments on commit e57afa5

Please sign in to comment.