135 lines
4.6 KiB
JavaScript
135 lines
4.6 KiB
JavaScript
// deeplinks.js - Deep Link Manager for Game Timer
|
|
|
|
// Available actions
|
|
const VALID_ACTIONS = ['start', 'pause', 'toggle', 'nextplayer', 'reset'];
|
|
|
|
// Class to manage all deep link functionality
|
|
class DeepLinkManager {
|
|
constructor() {
|
|
this.actionHandlers = {};
|
|
|
|
// Initialize listeners
|
|
this.initServiceWorkerListener();
|
|
this.initHashChangeListener();
|
|
this.initPopStateListener();
|
|
}
|
|
|
|
// Register action handlers
|
|
registerHandler(action, handlerFn) {
|
|
if (VALID_ACTIONS.includes(action)) {
|
|
this.actionHandlers[action] = handlerFn;
|
|
console.log(`Registered handler for action: ${action}`);
|
|
} else {
|
|
console.warn(`Attempted to register handler for invalid action: ${action}`);
|
|
}
|
|
}
|
|
|
|
// Extract action from URL parameters (search or hash)
|
|
getActionFromUrl() {
|
|
// Check for action in both search params and hash
|
|
const searchParams = new URLSearchParams(window.location.search);
|
|
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
|
|
|
// First check search params (for direct curl or navigation)
|
|
const searchAction = searchParams.get('action');
|
|
if (searchAction && VALID_ACTIONS.includes(searchAction)) {
|
|
console.log('Found action in search params:', searchAction);
|
|
return searchAction;
|
|
}
|
|
|
|
// Then check hash params (existing deep link mechanism)
|
|
const hashAction = hashParams.get('action');
|
|
if (hashAction && VALID_ACTIONS.includes(hashAction)) {
|
|
console.log('Found action in hash params:', hashAction);
|
|
return hashAction;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// Process an action
|
|
handleAction(action) {
|
|
if (!action) return;
|
|
|
|
console.log('Processing action:', action);
|
|
|
|
if (this.actionHandlers[action]) {
|
|
this.actionHandlers[action]();
|
|
} else {
|
|
console.log('No handler registered for action:', action);
|
|
}
|
|
}
|
|
|
|
// Handle deep links from URL
|
|
processDeepLink() {
|
|
// Get action from URL parameters
|
|
const action = this.getActionFromUrl();
|
|
|
|
// Process the action if found
|
|
if (action) {
|
|
this.handleAction(action);
|
|
|
|
// Clear the parameters to prevent duplicate actions if page is refreshed
|
|
if (window.history && window.history.replaceState) {
|
|
// Create new URL without the action parameter
|
|
const newUrl = window.location.pathname;
|
|
window.history.replaceState({}, document.title, newUrl);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize service worker message listener
|
|
initServiceWorkerListener() {
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.addEventListener('message', (event) => {
|
|
if (event.data && event.data.type === 'ACTION') {
|
|
console.log('Received action from service worker:', event.data.action);
|
|
this.handleAction(event.data.action);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Initialize hash change listener
|
|
initHashChangeListener() {
|
|
window.addEventListener('hashchange', () => {
|
|
console.log('Hash changed, checking for actions');
|
|
this.processDeepLink();
|
|
});
|
|
}
|
|
|
|
// Initialize popstate listener for navigation events
|
|
initPopStateListener() {
|
|
window.addEventListener('popstate', () => {
|
|
console.log('Navigation occurred, checking for actions');
|
|
this.processDeepLink();
|
|
});
|
|
}
|
|
|
|
// Send an action to the service worker
|
|
sendActionToServiceWorker(action) {
|
|
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
|
navigator.serviceWorker.controller.postMessage({
|
|
type: 'PROCESS_ACTION',
|
|
action: action
|
|
});
|
|
}
|
|
}
|
|
|
|
// Generate a deep link URL for a specific action
|
|
generateDeepLink(action, useHash = false) {
|
|
if (!VALID_ACTIONS.includes(action)) {
|
|
console.warn(`Cannot generate deep link for invalid action: ${action}`);
|
|
return null;
|
|
}
|
|
|
|
const baseUrl = window.location.origin + window.location.pathname;
|
|
return useHash ?
|
|
`${baseUrl}#action=${action}` :
|
|
`${baseUrl}?action=${action}`;
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
const deepLinkManager = new DeepLinkManager();
|
|
export default deepLinkManager; |