Some checks failed
Deploy Application / deploy (push) Has been cancelled
151 lines
3.9 KiB
JavaScript
151 lines
3.9 KiB
JavaScript
/**
|
|
* URL Manager for LiveComponents
|
|
*
|
|
* Handles URL updates without page reload:
|
|
* - data-lc-push-url: Push URL to browser history
|
|
* - data-lc-replace-url: Replace URL without history entry
|
|
* - Browser Back/Forward support
|
|
* - SPA Router coordination
|
|
*/
|
|
|
|
export class UrlManager {
|
|
constructor() {
|
|
this.initialized = false;
|
|
this.popStateHandler = null;
|
|
}
|
|
|
|
/**
|
|
* Initialize URL manager
|
|
*/
|
|
init() {
|
|
if (this.initialized) {
|
|
console.warn('[UrlManager] Already initialized');
|
|
return;
|
|
}
|
|
|
|
// Setup popstate handler for browser back/forward
|
|
this.popStateHandler = (event) => {
|
|
this.handlePopState(event);
|
|
};
|
|
window.addEventListener('popstate', this.popStateHandler);
|
|
|
|
this.initialized = true;
|
|
console.log('[UrlManager] Initialized');
|
|
}
|
|
|
|
/**
|
|
* Push URL to browser history
|
|
*
|
|
* @param {string} url - URL to push
|
|
* @param {string} title - Optional page title
|
|
*/
|
|
pushUrl(url, title = '') {
|
|
try {
|
|
window.history.pushState({ url, title }, title || document.title, url);
|
|
|
|
// Update document title if provided
|
|
if (title) {
|
|
document.title = title;
|
|
}
|
|
|
|
// Dispatch custom event
|
|
window.dispatchEvent(new CustomEvent('lc:url:pushed', {
|
|
detail: { url, title }
|
|
}));
|
|
|
|
console.log(`[UrlManager] Pushed URL: ${url}`);
|
|
} catch (error) {
|
|
console.error('[UrlManager] Failed to push URL:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replace URL without history entry
|
|
*
|
|
* @param {string} url - URL to replace
|
|
* @param {string} title - Optional page title
|
|
*/
|
|
replaceUrl(url, title = '') {
|
|
try {
|
|
window.history.replaceState({ url, title }, title || document.title, url);
|
|
|
|
// Update document title if provided
|
|
if (title) {
|
|
document.title = title;
|
|
}
|
|
|
|
// Dispatch custom event
|
|
window.dispatchEvent(new CustomEvent('lc:url:replaced', {
|
|
detail: { url, title }
|
|
}));
|
|
|
|
console.log(`[UrlManager] Replaced URL: ${url}`);
|
|
} catch (error) {
|
|
console.error('[UrlManager] Failed to replace URL:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle browser back/forward navigation
|
|
*
|
|
* @param {PopStateEvent} event - PopState event
|
|
*/
|
|
handlePopState(event) {
|
|
const state = event.state;
|
|
|
|
if (state && state.url) {
|
|
// Dispatch custom event for popstate
|
|
window.dispatchEvent(new CustomEvent('lc:url:popstate', {
|
|
detail: { url: state.url, state }
|
|
}));
|
|
|
|
// If SPA Router is available, let it handle navigation
|
|
if (window.SPARouter && typeof window.SPARouter.navigate === 'function') {
|
|
window.SPARouter.navigate(state.url);
|
|
return;
|
|
}
|
|
|
|
// Otherwise, trigger a page reload or custom handling
|
|
// This is a fallback - in most cases, SPA Router should handle it
|
|
console.log('[UrlManager] PopState detected, URL:', state.url);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get current URL
|
|
*
|
|
* @returns {string} - Current URL
|
|
*/
|
|
getCurrentUrl() {
|
|
return window.location.href;
|
|
}
|
|
|
|
/**
|
|
* Get current path
|
|
*
|
|
* @returns {string} - Current path
|
|
*/
|
|
getCurrentPath() {
|
|
return window.location.pathname;
|
|
}
|
|
|
|
/**
|
|
* Cleanup URL manager
|
|
*/
|
|
cleanup() {
|
|
if (this.popStateHandler) {
|
|
window.removeEventListener('popstate', this.popStateHandler);
|
|
this.popStateHandler = null;
|
|
}
|
|
this.initialized = false;
|
|
}
|
|
}
|
|
|
|
// Create singleton instance
|
|
export const urlManager = new UrlManager();
|
|
export default urlManager;
|
|
|
|
|
|
|
|
|