How do I convert an absolute url to a relative url?
Converting relative to absolute is trival
const rel = "../images/doggy.jpg"
const base = "https://example.com/pages/page.html?foo=bar#baz";
function relToAbs(baseHref, relHref) {
const url = new URL(rel, base);
return `${url.origin}${url.pathname}`;
}
console.log(base, rel);
Going the opposite direction seems to require a bunch of code.
Here's what I tried.
const pageURL1 = 'https://example.com/bar/baz.html?bla=blap#hash';
const pageURL2 = 'https://example.com/bar/?bla=blap#hash';
const absURL1 = 'https://example.com/bar/image/doggy.jpg';
const absURL2 = 'https://example.com/image/kitty.jpg';
const absURL3 = 'https://example.com/bar/birdy.jpg';
const tests = [
{ pageHref: pageURL1, absHref: absURL1, expected: 'image/doggy.jpg', },
{ pageHref: pageURL1, absHref: absURL2, expected: '../image/kitty.jpg', },
{ pageHref: pageURL1, absHref: absURL3, expected: 'birdy.jpg', },
{ pageHref: pageURL2, absHref: absURL1, expected: 'image/doggy.jpg', },
{ pageHref: pageURL2, absHref: absURL2, expected: '../image/kitty.jpg', },
{ pageHref: pageURL2, absHref: absURL3, expected: 'birdy.jpg', },
];
for (const {pageHref, absHref, expected} of tests) {
const actual = absToRel(pageHref, absHref);
console.log(absHref, actual, actual === expected ? 'pass' : 'FAIL');
}
function absToRel(pageHref, absHref) {
const pagePaths = dirPaths(pageHref).slice(0, -1);
const absPaths = dirPaths(absHref);
if (pagePaths[0] !== absPaths[0]) {
return absHref; // not same domain
}
// remove same paths
const firstDiffNdx = firstNonMatchingNdx(pagePaths, absPaths);
pagePaths.splice(0, firstDiffNdx);
absPaths.splice(0, firstDiffNdx);
// for each path still on page add a ..
return [
...(new Array(pagePaths.length).fill('..')),
...absPaths,
].join('/');
}
function firstNonMatchingNdx(a, b) {
let ndx = 0;
while (ndx < a.length && a[ndx] === b[ndx]) {
++ndx;
}
return ndx;
}
function dirPaths(href) {
const url = new URL(href);
return [url.origin, ...url.pathname.split('/')];
}