...
 
Commits (10)
...@@ -6,6 +6,15 @@ ...@@ -6,6 +6,15 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>SIB test: sib-router</title> <title>SIB test: sib-router</title>
<script type="module" src="../src/index.js"></script> <script type="module" src="../src/index.js"></script>
<a href="." id="reload">reload</a>
<script>
reload.href = location.pathname;
window.addEventListener('keydown', ev => {
if(!ev.ctrlKey || ev.key !== 'r') return;
ev.preventDefault();
reload.click();
});
</script>
<style> <style>
sib-router { sib-router {
display: block; display: block;
...@@ -26,46 +35,67 @@ ...@@ -26,46 +35,67 @@
</head> </head>
<body> <body>
<h1>Musical Instruments</h1> <details>
<sib-router default-route="keyboard"> <summary>use-hash</summary>
<sib-route name="keyboard">Keyboard</sib-route> <h1>Musical Instruments</h1>
<sib-route name="string">String</sib-route> <sib-link next="ukulele">→ Go to ukulele</sib-link>
<sib-route name="brass">Brass</sib-route> <sib-link next="brass" data-src="myID">→ Go to brass</sib-link>
</sib-router> <hr>
<sib-router default-route="keyboard" route-prefix="examples/sub-menu.html" use-hash>
<div id="keyboard" hidden> <sib-route name="keyboard">Keyboard</sib-route>
<sib-router default-route="piano"> <sib-route name="string">String</sib-route>
<sib-route name="piano">Piano</sib-route> <sib-route name="brass">Brass</sib-route>
<sib-route name="harpsichord">Harpsichord</sib-route>
<sib-route name="organ">Organ</sib-route>
</sib-router> </sib-router>
<div hidden id="piano"><h2>Piano</h2></div>
<div hidden id="harpsichord"><h2>Harpsichord</h2></div>
<div hidden id="organ"><h2>Organ</h2></div>
</div>
<div id="string" hidden> <div id="keyboard" hidden>
<sib-router default-route="violin"> <sib-router default-route="piano" route-prefix="titi" use-hash>
<sib-route name="violin">Violin</sib-route> <sib-route name="piano">Piano</sib-route>
<sib-route name="contrabass">Contrabass</sib-route> <sib-route name="harpsichord">Harpsichord</sib-route>
<sib-route name="guitar">Guitar</sib-route> <sib-route name="organ">Organ</sib-route>
<sib-route name="ukulele">Ukulele</sib-route> </sib-router>
</sib-router> <div hidden id="piano"><h2>Piano</h2></div>
<div hidden id="violin"><h2>Violin</h2></div> <div hidden id="harpsichord"><h2>Harpsichord</h2></div>
<div hidden id="contrabass"><h2>Contrabass</h2></div> <div hidden id="organ"><h2>Organ</h2></div>
<div hidden id="guitar"><h2>Guitar</h2></div> </div>
<div hidden id="ukulele"><h2>Ukulele</h2></div>
</div>
<div id="brass" hidden> <div id="string" hidden>
<sib-router default-route="trumpet"> <sib-router default-route="violin" use-hash>
<sib-route name="trumpet">Trumpet</sib-route> <sib-route name="violin">Violin</sib-route>
<sib-route name="trombone">Trombone</sib-route> <sib-route name="contrabass">Contrabass</sib-route>
<sib-route name="tuba">Tuba</sib-route> <sib-route name="guitar">Guitar</sib-route>
</sib-router> <sib-route name="ukulele">Ukulele</sib-route>
<div hidden id="trumpet"><h2>Trumpet</h2></div> </sib-router>
<div hidden id="trombone"><h2>Trombone</h2></div> <div hidden id="violin"><h2>Violin</h2></div>
<div hidden id="tuba"><h2>Tuba</h2></div> <div hidden id="contrabass"><h2>Contrabass</h2></div>
</div> <div hidden id="guitar"><h2>Guitar</h2></div>
<div hidden id="ukulele"><h2>Ukulele</h2></div>
</div>
<div id="brass" hidden>
<sib-router default-route="trumpet" use-hash>
<sib-route name="trumpet">Trumpet</sib-route>
<sib-route name="trombone">Trombone</sib-route>
<sib-route name="tuba">Tuba</sib-route>
</sib-router>
<div hidden id="trumpet"><h2>Trumpet</h2></div>
<div hidden id="trombone"><h2>Trombone</h2></div>
<div hidden id="tuba"><h2>Tuba</h2></div>
</div>
</details>
<script>
const details0 = document.querySelector('details');
const details = details0.cloneNode(true);
details.querySelector('summary').textContent = 'no use-hash';
Array.from(details.querySelectorAll('[use-hash]')).forEach(elm =>
elm.removeAttribute('use-hash'),
);
['default-route', 'name', 'id', 'next'].forEach(attr => {
Array.from(details.querySelectorAll(`[${attr}]`)).forEach(elm => {
elm.setAttribute(attr, '_' + elm.getAttribute(attr));
});
});
details0.parentElement.insertBefore(details, details0.nextSibling);
</script>
</body> </body>
</html> </html>
...@@ -27,30 +27,24 @@ export default class SIBRoute extends HTMLElement { ...@@ -27,30 +27,24 @@ export default class SIBRoute extends HTMLElement {
return this.closest('sib-router'); return this.closest('sib-router');
} }
get resourceId() { get resourceId() {
if(this.router.currentURL.split('/')[1]) { const id = this.router.currentURL.split('/')[1];
return this.decodeId(this.router.currentURL.split('/')[1]); if(!id || !id.startsWith('@')) return '';
} return this.decodeId(id);
return '';
} }
encodeId(id) { encodeId(id) {
if (id) { if (!id) return '';
return encodeURIComponent(id); return '@' + encodeURIComponent(id);
}
return;
} }
decodeId(id) { decodeId(id) {
if(id) { if(!id) return '';
return decodeURIComponent(id); return decodeURIComponent(id.replace(/^@/, ''));
}
return;
} }
getPath(prefix, name, id = '') { getPath(prefix, name, id = '') {
const encodedId = this.encodeId(id); const encodedId = this.encodeId(id);
return [prefix, name, encodedId].filter(s=>s).join('/'); return [prefix, name, encodedId].filter(s => s).join('/');
} }
updateResource() { updateResource() {
if(this.resourceId) { if(this.resourceId) {
...@@ -62,9 +56,12 @@ export default class SIBRoute extends HTMLElement { ...@@ -62,9 +56,12 @@ export default class SIBRoute extends HTMLElement {
} }
} }
} }
updateSubrouter(router) { updateSubRouters() {
router.setAttribute('route-prefix', this.getPath(this.router.prefix, this.name, this.resourceId)); for(let router of this.view.querySelectorAll('sib-router')){
router.display(); const routePrefix = this.getPath(this.router.prefix, this.name, this.resourceId);
router.setAttribute('route-prefix', routePrefix);
router.display();
}
} }
activate() { activate() {
if ('HTMLDialogElement' in window && this.view instanceof window.HTMLDialogElement){ if ('HTMLDialogElement' in window && this.view instanceof window.HTMLDialogElement){
...@@ -76,10 +73,7 @@ export default class SIBRoute extends HTMLElement { ...@@ -76,10 +73,7 @@ export default class SIBRoute extends HTMLElement {
} }
this.setAttribute('active', ''); this.setAttribute('active', '');
this.updateResource(); this.updateResource();
this.updateSubRouters();
// Reseting all routers within the selected view
for(let router of this.view.querySelectorAll('sib-router'))
this.updateSubrouter(router);
} }
hide() { hide() {
if ('HTMLDialogElement' in window && this.view instanceof window.HTMLDialogElement){ if ('HTMLDialogElement' in window && this.view instanceof window.HTMLDialogElement){
......
export default class SIBRouter extends HTMLElement { export default class SIBRouter extends HTMLElement {
constructor() { constructor() {
super(); super();
window.addEventListener('popstate', event => this.display()); window.addEventListener('popstate', () => this.display());
window.addEventListener('requestNavigation', event => { window.addEventListener('requestNavigation', ({detail}) =>
this.navigate(event.detail.route, event.detail.resource); this.navigate(detail.route, detail.resource, detail.keepURL)
}) );
window.addEventListener('DOMContentLoaded', event => this.display()); window.addEventListener('DOMContentLoaded', () => {
for (const route of this.routes) {
route.updateSubRouters();
}
this.display();
});
} }
get useHash() { get useHash() {
return this.hasAttribute('use-hash'); return this.hasAttribute('use-hash');
...@@ -20,12 +25,12 @@ export default class SIBRouter extends HTMLElement { ...@@ -20,12 +25,12 @@ export default class SIBRouter extends HTMLElement {
return this.getAttribute('default-route') || ''; return this.getAttribute('default-route') || '';
} }
get currentURL() { get currentURL() {
let url = (this.useHash ? location.hash : location.pathname).slice(1); let url = this.useHash ? location.hash : location.pathname;
if(url.startsWith(this.prefix)) url = url.slice(1);
url = url.slice(this.prefix.length); if(url.startsWith(this.prefix)) {
if(url.startsWith('/')) url = url.slice(this.prefix.length);
url = url.slice(1); }
return url; return stripSlashes(url);
} }
get currentRouteName() { get currentRouteName() {
return this.currentURL.split('/')[0] || this.defaultRoute; return this.currentURL.split('/')[0] || this.defaultRoute;
...@@ -36,14 +41,16 @@ export default class SIBRouter extends HTMLElement { ...@@ -36,14 +41,16 @@ export default class SIBRouter extends HTMLElement {
display(routeName = this.currentRouteName, resource) { display(routeName = this.currentRouteName, resource) {
this.dispatchEvent(new CustomEvent('navigate', {detail: {route: routeName, resource}})); for(let route of this.routes) {
for(let route of this.routes) if(routeName === route.name) {
if(routeName == route.name) this.dispatchEvent(new CustomEvent('navigate', {detail: {route: routeName, resource}}));
route.activate(); route.activate();
else } else {
route.hide(); route.hide();
}
}
} }
navigate(routeName = '', resource) { navigate(routeName = '', resource, keepURL) {
let route let route
if(routeName) { if(routeName) {
route = this.querySelector('sib-route[name="'+routeName+'"]'); route = this.querySelector('sib-route[name="'+routeName+'"]');
...@@ -53,19 +60,27 @@ export default class SIBRouter extends HTMLElement { ...@@ -53,19 +60,27 @@ export default class SIBRouter extends HTMLElement {
} }
if(!route) return; //this route is not for me! if(!route) return; //this route is not for me!
if(this.prefix) {
const route = this.prefix.split('/').pop();
setTimeout(() => {
this.dispatchEvent(new CustomEvent('requestNavigation', {
detail: {route: route, keepURL: true},
bubbles: true,
}))
});
}
const id = resource ? resource['@id'] : null; const id = resource ? resource['@id'] : null;
const path = route.getPath(this.prefix, routeName, id) const path = route.getPath(this.prefix, routeName, id);
if(!keepURL && !this.hasAttribute('keep-url')) {
//update current URL //update current URL
const prefix = this.useHash ? '#' : '/';
history.pushState({}, routeName, prefix + path);
}
this.display(routeName, resource); this.display(routeName, resource);
if(this.hasAttribute('keep-url')) return;
if(this.useHash)
window.location.hash = path;
else
history.pushState({}, routeName, '/' + path);
} }
} }
customElements.define('sib-router', SIBRouter); customElements.define('sib-router', SIBRouter);
function stripSlashes(str) {
return str.replace(/^\/+|\/+$/g, '');
}