diff --git a/src/index.js b/src/index.js index e0313e6a..db57414c 100644 --- a/src/index.js +++ b/src/index.js @@ -23,21 +23,37 @@ function setUrl(url, type='push') { } +function getCurrentLocation() { + return (customHistory && customHistory.location) || + (customHistory && customHistory.getCurrentLocation && customHistory.getCurrentLocation()) || + (typeof location!=='undefined' ? location : EMPTY); +} + + function getCurrentUrl() { - let url; - if (customHistory && customHistory.location) { - url = customHistory.location; - } - else if (customHistory && customHistory.getCurrentLocation) { - url = customHistory.getCurrentLocation(); - } - else { - url = typeof location!=='undefined' ? location : EMPTY; - } + let url = getCurrentLocation(); return `${url.pathname || ''}${url.search || ''}`; } +const a = typeof document!=='undefined' && document.createElement('a'); + +/* Resolve URL relative to current location */ +function resolve(url) { + let current = getCurrentLocation(); + if (a) { + a.setAttribute('href', url); + if ( + (current.protocol && a.protocol !== current.protocol) || + (current.host && a.host !== current.host) + ) { + return; + } + return a.pathname + a.search + a.hash; + } + return url; +} + function route(url, replace=false) { if (typeof url!=='string' && url.url) { @@ -45,6 +61,9 @@ function route(url, replace=false) { url = url.url; } + url = resolve(url); + if (!url) return; + // only push URL into history if we can handle it if (canRoute(url)) { setUrl(url, replace ? 'replace' : 'push'); @@ -79,17 +98,11 @@ function routeTo(url) { function routeFromLink(node) { - // only valid elements - if (!node || !node.getAttribute) return; - - let href = node.getAttribute('href'), - target = node.getAttribute('target'); - - // ignore links with targets and non-path URLs - if (!href || !href.match(/^\//g) || (target && !target.match(/^_?self$/i))) return; + // ignore invalid & external links: + if (!node || (node.target && !node.target.match(/^_?self$/i))) return; // attempt to route, if no match simply cede control to browser - return route(href); + return route(node.pathname + node.search + node.hash); } @@ -117,12 +130,9 @@ function delegateLinkHandler(e) { let t = e.target; do { - if (String(t.nodeName).toUpperCase()==='A' && t.getAttribute('href') && isPreactElement(t)) { - if (t.hasAttribute('native')) return; + if (String(t.nodeName).toUpperCase()==='A' && t.pathname && isPreactElement(t) && !t.hasAttribute('native') && routeFromLink(t)) { // if link is handled by the router, prevent browser defaults - if (routeFromLink(t)) { - return prevent(e); - } + return prevent(e); } } while ((t=t.parentNode)); } diff --git a/test/dom.js b/test/dom.js index 5687a832..758479b7 100644 --- a/test/dom.js +++ b/test/dom.js @@ -170,6 +170,22 @@ describe('dom', () => { route('/foo'); expect(routerRef.base.outerHTML).to.eql('
bar is
'); }); + + it('should support relative links', () => { + class A { + render() { + return go; + } + } + history.replaceState(null, null, '/foo/one'); + mount( +