Skip to content
58 changes: 46 additions & 12 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,61 @@ function setUrl(url, type='push') {
}


function getCurrentLocation() {
return (customHistory && customHistory.location) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation is good, but if it's only ever called from getCurrentUrl(), let's just inline it there.

Copy link
Contributor Author

@ashsearle ashsearle Feb 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also called from the new resolve method used by route.

I was wondering whether to tweak resolve to take a base parameter as well, then move it to util.js and add test-cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends - there was talk about moving customHistory to be a property of Router instances so that they had proper instance separation instead of the singleton stuff. Might be better to go that route rather than making it more singelton-ey? Different PR I guess though.

(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 || ''}`;
}


// Lifted from https://tools.ietf.org/html/rfc3986#appendix-B
const uriRegex = new RegExp('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?');

/* Resolve URL relative to current location */
function resolve(url) {
let current = getCurrentLocation();
let [,
protocol,,
,hostname,
pathname,
search,,
// hash,,
] = uriRegex.exec(url);
if (
(protocol && protocol !== current.protocol) ||
(hostname && hostname !== current.hostname)
) {
return;
}
if (pathname.charAt(0) !== '/') {
let stack = (current.pathname||'/').split("/"),
segments = pathname.split("/");
stack.pop();
for (let i=0; i<segments.length; i++) {
if (segments[i] === "..")
stack.pop();
else if (segments[i] !== ".")
stack.push(segments[i]);
}
pathname = stack.join("/");
}
return `${pathname}${search || ''}`;
}

function route(url, replace=false) {
if (typeof url!=='string' && url.url) {
replace = url.replace;
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');
Expand Down Expand Up @@ -83,8 +117,8 @@ function routeFromLink(node) {
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 links with targets
if (!href || (target && !target.match(/^_?self$/i))) return;

// attempt to route, if no match simply cede control to browser
return route(href);
Expand Down