Skip to content

Commit e5dc96d

Browse files
committed
A working relative links implementation (with test) that only accounts for links in a document (not route('./foo')). See #138.
1 parent 315be7c commit e5dc96d

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed

src/index.js

+9-18
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,11 @@ function routeTo(url) {
7979

8080

8181
function routeFromLink(node) {
82-
// only valid elements
83-
if (!node || !node.getAttribute) return;
84-
85-
let href = node.getAttribute('href'),
86-
target = node.getAttribute('target');
87-
88-
// ignore links with targets and non-path URLs
89-
if (!href || !href.match(/^\//g) || (target && !target.match(/^_?self$/i))) return;
82+
// ignore invalid & external links:
83+
if (!node || node.protocol!==location.protocol || node.host!==location.host || (node.target && !node.target.match(/^_?self$/i))) return;
9084

9185
// attempt to route, if no match simply cede control to browser
92-
return route(href);
86+
return route(node.pathname + node.search + node.hash);
9387
}
9488

9589

@@ -117,12 +111,9 @@ function delegateLinkHandler(e) {
117111

118112
let t = e.target;
119113
do {
120-
if (String(t.nodeName).toUpperCase()==='A' && t.getAttribute('href') && isPreactElement(t)) {
121-
if (t.hasAttribute('native')) return;
114+
if (String(t.nodeName).toUpperCase()==='A' && t.pathname && isPreactElement(t) && !t.hasAttribute('native') && routeFromLink(t)) {
122115
// if link is handled by the router, prevent browser defaults
123-
if (routeFromLink(t)) {
124-
return prevent(e);
125-
}
116+
return prevent(e);
126117
}
127118
} while ((t=t.parentNode));
128119
}
@@ -131,13 +122,13 @@ function delegateLinkHandler(e) {
131122
let eventListenersInitialized = false;
132123

133124
function initEventListeners() {
134-
if (eventListenersInitialized){
135-
return;
136-
}
125+
if (eventListenersInitialized) return;
137126

138127
if (typeof addEventListener==='function') {
139128
if (!customHistory) {
140-
addEventListener('popstate', () => routeTo(getCurrentUrl()));
129+
addEventListener('popstate', () => {
130+
routeTo(getCurrentUrl());
131+
});
141132
}
142133
addEventListener('click', delegateLinkHandler);
143134
}

test/dom.js

+16
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ describe('dom', () => {
170170
route('/foo');
171171
expect(routerRef.base.outerHTML).to.eql('<p>bar is </p>');
172172
});
173+
174+
it('should support relative links', () => {
175+
class A {
176+
render() {
177+
return <a href="two">go</a>;
178+
}
179+
}
180+
history.replaceState(null, null, '/foo/one');
181+
mount(
182+
<Router>
183+
<A default />
184+
</Router>
185+
);
186+
scratch.querySelector('a').click();
187+
expect(location.pathname).to.equal('/foo/two');
188+
});
173189
});
174190

175191
describe('preact-router/match', () => {

0 commit comments

Comments
 (0)