From b74f5d20d3d27e5be6b97dafe0740e33b62bd4ce Mon Sep 17 00:00:00 2001 From: yousuf64 Date: Mon, 2 Sep 2024 09:04:29 +0530 Subject: [PATCH] added route listener --- packages/@productled/core/src/Productled.ts | 11 +++-- .../@productled/core/src/RouteListener.ts | 47 +++++++++++++++++++ .../react-sample/src/ProductledInit.tsx | 10 +--- 3 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 packages/@productled/core/src/RouteListener.ts diff --git a/packages/@productled/core/src/Productled.ts b/packages/@productled/core/src/Productled.ts index e770a3c..29a4adb 100644 --- a/packages/@productled/core/src/Productled.ts +++ b/packages/@productled/core/src/Productled.ts @@ -4,6 +4,7 @@ import Plugin from './Plugin'; import ConfigStore from './ConfigStore'; import PluginStore from './PluginStore'; import DocumentService from './DocumentService'; +import { RouteListener } from "./RouteListener"; type pluginName = string; @@ -18,6 +19,7 @@ class Productled { protected configStore: ConfigStore; protected pluginStore: PluginStore; protected documentService: DocumentService; + protected routeListener: RouteListener; /** * The constructor is private to ensure that the class is a singleton. @@ -28,6 +30,7 @@ class Productled { this.pluginStore = new PluginStore(); this.documentService = new DocumentService(); this.configStore = new ConfigStore(); + this.routeListener = new RouteListener(); } /** @@ -52,12 +55,11 @@ class Productled { /** * This method is called when the route changes. * It retrieves the hooks for the current route and executes them. + * @param {string} url - The URL of the new route * @returns {Promise} */ - public routeChanged() { - - const currentRoute = window.location.pathname; - const hooks = this.hookStore.getHooks(currentRoute); + public routeChanged(url: string) { + const hooks = this.hookStore.getHooks(url); const hookExecuter = new HookExecuter(this.pluginStore, this.documentService); hookExecuter.executeHooks(hooks); @@ -76,6 +78,7 @@ class Productled { // Get the hooks for the plugin and add them to the hook store const hooks = this.configStore.getHooks(pluginName); this.hookStore.addHooks(hooks, pluginName); + this.routeListener.addListener(this.routeChanged.bind(this)); } } diff --git a/packages/@productled/core/src/RouteListener.ts b/packages/@productled/core/src/RouteListener.ts new file mode 100644 index 0000000..3e5e41e --- /dev/null +++ b/packages/@productled/core/src/RouteListener.ts @@ -0,0 +1,47 @@ +type RouteListenerFunc = (url: string) => void; + +class RouteListener { + private listening: boolean = false; + private listeners: Array = []; + + addListener(listener: RouteListenerFunc): void { + this.listeners.push(listener); + + if (!this.listening) { + this.listening = true; + this.startListen(); + + setTimeout(() => this.notifyListeners(window.location.pathname)) // Initial notification + } + } + + private startListen() { + // Overriding the pushState method to notify listeners + const pushState = window.history.pushState; + window.history.pushState = (...args): void => { + pushState.apply(window.history, args); + + const url = args[2]; + if (!url) { + return; + } else if (url instanceof URL) { + this.notifyListeners(url.toString()); + } else { + this.notifyListeners(url); + } + }; + } + + private notifyListeners(url: string): void { + for (const listener of this.listeners) { + // Scheduled for the next event loop + setTimeout(() => listener(url)); + } + } + + removeListener(listener: Function): void { + this.listeners = this.listeners.filter(l => l !== listener); + } +} + +export { RouteListener, RouteListenerFunc }; \ No newline at end of file diff --git a/packages/samples/react-sample/src/ProductledInit.tsx b/packages/samples/react-sample/src/ProductledInit.tsx index ac149a0..0ae2f7e 100644 --- a/packages/samples/react-sample/src/ProductledInit.tsx +++ b/packages/samples/react-sample/src/ProductledInit.tsx @@ -1,14 +1,6 @@ -import React, { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; -import { Productled } from '@productled/core'; +import React from 'react'; const ProductledInit: React.FC = () => { - const location = useLocation(); - - useEffect(() => { - Productled.getInstance().routeChanged(); - }, [location.pathname]); - return null; }