178 lines
4.6 KiB
JavaScript
178 lines
4.6 KiB
JavaScript
|
|
/**
|
||
|
|
* @fileoverview URL Router Service for Rantii
|
||
|
|
* @author retoor <retoor@molodetz.nl>
|
||
|
|
* @description Handles URL routing and navigation state management
|
||
|
|
* @keywords router, navigation, url, history, routing
|
||
|
|
*/
|
||
|
|
|
||
|
|
class Router {
|
||
|
|
constructor() {
|
||
|
|
this.routes = new Map();
|
||
|
|
this.currentRoute = null;
|
||
|
|
this.currentParams = {};
|
||
|
|
this.onRouteChange = null;
|
||
|
|
this.basePath = this.detectBasePath();
|
||
|
|
}
|
||
|
|
|
||
|
|
detectBasePath() {
|
||
|
|
const path = window.location.pathname;
|
||
|
|
const htmlIndex = path.lastIndexOf('.html');
|
||
|
|
if (htmlIndex !== -1) {
|
||
|
|
return path.substring(0, path.lastIndexOf('/') + 1);
|
||
|
|
}
|
||
|
|
return path.endsWith('/') ? path : path + '/';
|
||
|
|
}
|
||
|
|
|
||
|
|
init() {
|
||
|
|
window.addEventListener('popstate', () => this.handleRoute());
|
||
|
|
this.handleRoute();
|
||
|
|
}
|
||
|
|
|
||
|
|
register(name, handler) {
|
||
|
|
this.routes.set(name, handler);
|
||
|
|
}
|
||
|
|
|
||
|
|
getParams() {
|
||
|
|
const params = new URLSearchParams(window.location.search);
|
||
|
|
const result = {};
|
||
|
|
for (const [key, value] of params) {
|
||
|
|
result[key] = value;
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
handleRoute() {
|
||
|
|
const params = this.getParams();
|
||
|
|
this.currentParams = params;
|
||
|
|
|
||
|
|
let routeName = 'home';
|
||
|
|
if (params.rant) {
|
||
|
|
routeName = 'rant';
|
||
|
|
} else if (params.user) {
|
||
|
|
routeName = 'user';
|
||
|
|
} else if (params.search !== undefined) {
|
||
|
|
routeName = 'search';
|
||
|
|
} else if (params.notifications !== undefined) {
|
||
|
|
routeName = 'notifications';
|
||
|
|
} else if (params.settings !== undefined) {
|
||
|
|
routeName = 'settings';
|
||
|
|
} else if (params.login !== undefined) {
|
||
|
|
routeName = 'login';
|
||
|
|
} else if (params.weekly !== undefined) {
|
||
|
|
routeName = 'weekly';
|
||
|
|
} else if (params.collabs !== undefined) {
|
||
|
|
routeName = 'collabs';
|
||
|
|
} else if (params.stories !== undefined) {
|
||
|
|
routeName = 'stories';
|
||
|
|
}
|
||
|
|
|
||
|
|
this.currentRoute = routeName;
|
||
|
|
const handler = this.routes.get(routeName);
|
||
|
|
if (handler) {
|
||
|
|
handler(params);
|
||
|
|
}
|
||
|
|
if (this.onRouteChange) {
|
||
|
|
this.onRouteChange(routeName, params);
|
||
|
|
}
|
||
|
|
window.dispatchEvent(new CustomEvent('rantii:route-change', {
|
||
|
|
detail: { route: routeName, params }
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
|
||
|
|
navigate(routeName, params = {}) {
|
||
|
|
const url = this.buildUrl(params);
|
||
|
|
window.history.pushState({ route: routeName, params }, '', url);
|
||
|
|
this.handleRoute();
|
||
|
|
}
|
||
|
|
|
||
|
|
replace(routeName, params = {}) {
|
||
|
|
const url = this.buildUrl(params);
|
||
|
|
window.history.replaceState({ route: routeName, params }, '', url);
|
||
|
|
this.handleRoute();
|
||
|
|
}
|
||
|
|
|
||
|
|
buildUrl(params = {}) {
|
||
|
|
const searchParams = new URLSearchParams();
|
||
|
|
Object.entries(params).forEach(([key, value]) => {
|
||
|
|
if (value !== undefined && value !== null && value !== '') {
|
||
|
|
searchParams.set(key, value);
|
||
|
|
} else if (value === '') {
|
||
|
|
searchParams.set(key, '');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
const queryString = searchParams.toString();
|
||
|
|
const currentPath = window.location.pathname;
|
||
|
|
return queryString ? `${currentPath}?${queryString}` : currentPath;
|
||
|
|
}
|
||
|
|
|
||
|
|
goHome() {
|
||
|
|
this.navigate('home', {});
|
||
|
|
}
|
||
|
|
|
||
|
|
goToRant(rantId, commentId = null) {
|
||
|
|
const params = { rant: rantId };
|
||
|
|
if (commentId) {
|
||
|
|
params.comment = commentId;
|
||
|
|
}
|
||
|
|
this.navigate('rant', params);
|
||
|
|
}
|
||
|
|
|
||
|
|
goToUser(username) {
|
||
|
|
this.navigate('user', { user: username });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToSearch(term = '') {
|
||
|
|
this.navigate('search', { search: term });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToNotifications() {
|
||
|
|
this.navigate('notifications', { notifications: '' });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToSettings() {
|
||
|
|
this.navigate('settings', { settings: '' });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToLogin() {
|
||
|
|
this.navigate('login', { login: '' });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToWeekly() {
|
||
|
|
this.navigate('weekly', { weekly: '' });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToCollabs() {
|
||
|
|
this.navigate('collabs', { collabs: '' });
|
||
|
|
}
|
||
|
|
|
||
|
|
goToStories() {
|
||
|
|
this.navigate('stories', { stories: '' });
|
||
|
|
}
|
||
|
|
|
||
|
|
back() {
|
||
|
|
window.history.back();
|
||
|
|
}
|
||
|
|
|
||
|
|
forward() {
|
||
|
|
window.history.forward();
|
||
|
|
}
|
||
|
|
|
||
|
|
getCurrentRoute() {
|
||
|
|
return this.currentRoute;
|
||
|
|
}
|
||
|
|
|
||
|
|
getCurrentParams() {
|
||
|
|
return this.currentParams;
|
||
|
|
}
|
||
|
|
|
||
|
|
setRouteChangeCallback(callback) {
|
||
|
|
this.onRouteChange = callback;
|
||
|
|
}
|
||
|
|
|
||
|
|
isCurrentRoute(routeName) {
|
||
|
|
return this.currentRoute === routeName;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export { Router };
|