Skip to content

Instantly share code, notes, and snippets.

@wisniewski94
Created April 29, 2021 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wisniewski94/979de42508a2eb1c712925d0bfbd9176 to your computer and use it in GitHub Desktop.
Save wisniewski94/979de42508a2eb1c712925d0bfbd9176 to your computer and use it in GitHub Desktop.
class Router {
constructor() {
this.#init();
}
#paths = {};
#redirect(url) {
if (url === '/404') {
window.history.replaceState(null, null, url);
} else {
window.history.pushState(null, null, url)
};
this.#checkPatterns(url);
}
#handleError() {
console.error('Page not found');
this.#redirect('/404');
}
#transformRegexOutput(input) {
try {
return Object
.keys(input)
.filter(key => Number(key))
.reduce((obj, key) => ({ ...obj, [key]: input[key] }), {});
} catch (error) {
this.#handleError();
return {};
}
}
#mergeObjects(obj1, obj2) {
let iterator = -1;
return Object
.entries(obj1)
.reduce((obj, key, index) => {
if (obj1[index + 1] == '*') iterator += 1;
return ({ ...obj, [obj1[index + 1] == '*' ? iterator : obj1[index + 1].substring(1)]: obj2[index + 1] })
}, {})
}
#parsePattern(pattern) {
return '^' + pattern
.replace(/\\/g, '\\/')
.replace(/(\*|:\w*)/gm, '(:?[A-z0-9|*]*)') + '(?:\\/?)$';
}
get(pattern, callback) {
const paths = this.#paths;
if (!paths[pattern]) {
paths[pattern] = {};
paths[pattern].callbacks = [];
}
paths[pattern].reg = this.#parsePattern(pattern);
paths[pattern].callbacks.push(callback);
return true;
}
#checkIfAnyPatternIsMatching(url) {
return (element, index, array) => {
const pattern = this.#paths[element].reg;
const newRegex = new RegExp(pattern, 'i').exec(url);
if (!newRegex) { return false };
return true;
}
}
#getParams(pattern, url) {
const parsedPattern = this.#paths[pattern].reg;
const regex = new RegExp(parsedPattern, 'i');
const tokens = this.#transformRegexOutput(regex.exec(pattern));
const params = this.#transformRegexOutput(regex.exec(url));
return this.#mergeObjects(tokens, params);
}
#processURL(pattern, url) {
const result = this.#getParams(pattern, url);
return this.#paths[pattern].callbacks.forEach(callback => callback(result));
}
#checkPatterns(url) {
const result = Object.keys(this.#paths).find(this.#checkIfAnyPatternIsMatching(url));
if (!result) {
this.#handleError();
return false;
}
this.#processURL(result, url);
return true;
}
#init() {
this.get('/', data => {
// console.log('/')
});
this.get('/404', data => {
// console.log('/404')
});
document.addEventListener('click', event => {
const target = event.target.closest('a');
if (!target) {
return;
}
if (target.hostname === location.hostname) {
event.preventDefault();
this.#redirect(target.getAttribute("href"));
}
}, false);
window.addEventListener('DOMContentLoaded', event => {
event.preventDefault();
this.#checkPatterns(location.pathname);
});
window.addEventListener('popstate', event => {
//event.preventDefault();
this.#checkPatterns(location.pathname);
});
}
}
export default Router;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment