diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..21bd9af --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,62 @@ +on: + push: + branches: + - main + + pull_request: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: package.json + cache: npm + + # Working around https://github.com/npm/cli/issues/4828 + # - run: npm ci + - run: npm install --no-package-lock + + - name: Check formatting + run: npm run format:check + + - name: Check syntax + run: npm run lint + + - name: Run tests + run: npm test + + - run: npm run build + + publish: + runs-on: ubuntu-latest + if: github.event_name == 'release' + needs: build + + permissions: + contents: read + id-token: write + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: package.json + cache: npm + registry-url: "https://registry.npmjs.org" + + # Working around https://github.com/npm/cli/issues/4828 + # - run: npm ci + - run: npm install --no-package-lock + + - run: npm run build + + - run: npm run npm:publish:dry-run + + - run: npm run npm:publish diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml deleted file mode 100644 index 9515ed5..0000000 --- a/.github/workflows/node.js.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Node.js CI - -on: - push: - branches: [ "master", "develop" ] - pull_request: - branches: [ "master" ] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [20.x, 21.x, 22.x] - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - - run: npm install - - run: npm run build - - run: npm test - - run: sudo apt-get install xvfb - - run: xvfb-run --auto-servernum npm run test:chrome - - run: xvfb-run --auto-servernum npm run test:firefox - - # Separate job for publishing to npm - publish: - runs-on: ubuntu-latest - needs: build # Wait for build to complete - if: github.ref == 'refs/heads/master' && github.event_name == 'push' - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js 20.x - uses: actions/setup-node@v3 - with: - node-version: "20.x" - cache: "npm" - - run: npm install - - run: npm run build - - - name: Authenticate with npm - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc - - - name: Run npm publish dry run - run: npm run npm:publish:dry-run - - - name: Publish to npm - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: npm run npm:publish diff --git a/.gitignore b/.gitignore index 33c98dd..8a133c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store .idea +bin node_modules -build/nightwatch \ No newline at end of file +build/nightwatch diff --git a/README.md b/README.md index 8881a20..f2cac1c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ npm i @puremvc/puremvc-js-multicore-framework * [React Native](https://en.wikipedia.org/wiki/React_Native) ## Status -Production - [Version 2.0.9](https://github.com/PureMVC/puremvc-js-multicore-framework/blob/master/VERSION) +Production - [Version 2.0.9](https://github.com/PureMVC/puremvc-js-multicore-framework/blob/main/VERSION) #### Documentation - https://jsdoc.app/about-commandline.html diff --git a/VERSION b/VERSION index 5aae294..d0c35e6 100644 --- a/VERSION +++ b/VERSION @@ -1,10 +1,10 @@ PureMVC MultiCore Framework for JavaScript -------------------------------------------------------------------------- -Release Date: 9/4/24 +Release Date: 11/25/25 Platform: JavaScript Version: 2 Revision: 0 - Minor: 9 + Minor: 10 Authors: Saad Shams : David Foley : Cliff Hall @@ -19,3 +19,4 @@ Release Date: 9/4/24 2.0.7 - Finally? NPM bundling 2.0.8 - CI/CD Pipeline 2.0.9 - CI/CD Integrating Automated Tokens +2.0.10 - diff --git a/bin/cjs/index.cjs b/bin/cjs/index.cjs deleted file mode 100644 index f5dc90a..0000000 --- a/bin/cjs/index.cjs +++ /dev/null @@ -1,1636 +0,0 @@ -'use strict'; - -/* - * Observer.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - -/** - * A base `Observer` implementation. - * - *

An `Observer` is an object that encapsulates information - * about an interested object with a method that should - * be called when a particular `Notification` is broadcast.

- * - *

In PureMVC, the `Observer` class assumes these responsibilities:

- * - *
    - *
  • Encapsulate the notification (callback) method of the interested object.
  • - *
  • Encapsulate the notification context (this) of the interested object.
  • - *
  • Provide methods for setting the notification method and context.
  • - *
  • Provide a method for notifying the interested object.
  • - *
- * - * @class Observer - */ -class Observer { - - /** - * Constructor. - * - *

The notification method on the interested object should take - * one parameter of type `Notification`

- * - * @param {function(Notification):void | null} [notify = null] - * @param {Object | null} [context = null] - */ - constructor(notify = null, context = null) { - this._notifyMethod = notify; - this._notifyContext = context; - } - - /** - * Notify the interested object. - * - * @param {Notification} notification - */ - notifyObserver(notification) { - this._notifyMethod.call(this._notifyContext, notification); - } - - /** - * Compare an object to the notification context. - * - * @param {Object} notifyContext - * @returns {boolean} - */ - compareNotifyContext(notifyContext) { - return this._notifyContext === notifyContext; - } - - /** - * Get the notification method. - * - * @returns {function(Notification):void} - */ - get notifyMethod() { - return this._notifyMethod - } - - /** - * Set the notification method. - * - *

The notification method should take one parameter of type `Notification`.

- * - * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received. - */ - set notifyMethod(notifyMethod) { - this._notifyMethod = notifyMethod; - } - - /** - * Get the notifyContext - * - * @returns {Object} - */ - get notifyContext() { - return this._notifyContext; - } - - /** - * Set the notification context. - * - * @param {Object} notifyContext - */ - set notifyContext(notifyContext) { - this._notifyContext = notifyContext; - } - -} - -/* - * View.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A Multiton `View` implementation. - * - *

In PureMVC, the `View` class assumes these responsibilities:

- * - *
    - *
  • Maintain a cache of `Mediator` instances.
  • - *
  • Provide methods for registering, retrieving, and removing `Mediators`.
  • - *
  • Notifying `Mediators` when they are registered or removed.
  • - *
  • Managing the observer lists for each `Notification` in the application.
  • - *
  • Providing a method for attaching `Observers` to a `Notification`'s observer list.
  • - *
  • Providing a method for broadcasting a `Notification`.
  • - *
  • Notifying the `Observers` of a given `Notification` when it broadcast.
  • - *
- * - * @see Mediator Mediator - * @see Observer Observer - * @see Notification Notification - * - * @class View - */ -class View { - - /** - * Constructor. - * - *

This `View` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `View.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - View.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.mediatorMap = new Map(); - /** @protected - * @type {Map.>} */ - this.observerMap = new Map(); - this.initializeView(); - } - - /** - *

Initialize the Multiton View instance.

- * - *

Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.

- */ - initializeView() { - - } - - /** - * View Multiton factory method. - * - * @static - * @param {string} key - * @param {function(string):View} factory - * @returns {View} the Multiton instance of `View` - */ - static getInstance(key, factory) { - if (View.instanceMap == null) - /** @static - * @type {Map} */ - View.instanceMap = new Map(); - if (View.instanceMap.get(key) == null) View.instanceMap.set(key, factory(key)); - return View.instanceMap.get(key); - } - - /** - *

Register an `Observer` to be notified - * of `Notifications` with a given name.

- * - * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of - * @param {Observer} observer the `Observer` to register - */ - registerObserver(notificationName, observer) { - if (this.observerMap.get(notificationName) != null) { - let observers = this.observerMap.get(notificationName); - observers.push(observer); - } else { - this.observerMap.set(notificationName, new Array(observer)); - } - } - - /** - *

Notify the `Observers` for a particular `Notification`.

- * - *

All previously attached `Observers` for this `Notification`'s - * list are notified and are passed a reference to the `Notification` in - * the order in which they were registered.

- * - * @param {Notification} notification the `Notification` to notify `Observers` of. - */ - notifyObservers(notification) { - if (this.observerMap.has(notification.name)) { - // Copy observers from reference array to working array, - // since the reference array may change during the notification loop - let observers = this.observerMap.get(notification.name).slice(); - - // Notify Observers from the working array - for(let i = 0; i < observers.length; i++) { - observers[i].notifyObserver(notification); - } - } - } - - /** - *

Remove the observer for a given notifyContext from an observer list for a given Notification name.

- * - * @param {string} notificationName which observer list to remove from - * @param {Object} notifyContext remove the observer with this object as its notifyContext - */ - removeObserver(notificationName, notifyContext) { - // the observer list for the notification under inspection - let observers = this.observerMap.get(notificationName); - - // find the observer for the notifyContext - for (let i = 0; i < observers.length; i++) { - if (observers[i].compareNotifyContext(notifyContext) === true) { - // there can only be one Observer for a given notifyContext - // in any given Observer list, so remove it and break - observers.splice(i, 1); - break; - } - } - - // Also, when a Notification's Observer list length falls to - // zero, delete the notification key from the observer map - if (observers.length === 0) { - this.observerMap.delete(notificationName); - } - } - - /** - * Register a `Mediator` instance with the `View`. - * - *

Registers the `Mediator` so that it can be retrieved by name, - * and further interrogates the `Mediator` for its - * `Notification` interests.

- * - *

If the `Mediator` returns any `Notification` - * names to be notified about, an `Observer` is created encapsulating - * the `Mediator` instance's `handleNotification` method - * and registering it as an `Observer` for all `Notifications` the - * `Mediator` is interested in.

- * - * @param {Mediator} mediator a reference to the `Mediator` instance - */ - registerMediator(mediator) { - // do not allow re-registration (you must to removeMediator fist) - if (this.mediatorMap.has(mediator.mediatorName) !== false) return; - - mediator.initializeNotifier(this.multitonKey); - - // Register the Mediator for retrieval by name - this.mediatorMap.set(mediator.mediatorName, mediator); - - // Get Notification interests, if any. - let interests = mediator.listNotificationInterests(); - - // Register Mediator as an observer for each notification of interests - if (interests.length > 0) { - // Create Observer referencing this mediator's handleNotification method - let observer = new Observer(mediator.handleNotification.bind(mediator), mediator); // check bind - - // Register Mediator as Observer for its list of Notification interests - for (let i = 0; i < interests.length; i++) { - this.registerObserver(interests[i], observer); - } - } - - // alert the mediator that it has been registered - mediator.onRegister(); - } - - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName the name of the `Mediator` instance to retrieve. - * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.mediatorMap.get(mediatorName) || null; - } - - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` instance to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - // Retrieve the named mediator - let mediator = this.mediatorMap.get(mediatorName); - - if (mediator) { - // for every notification this mediator is interested in... - let interests = mediator.listNotificationInterests(); - for (let i = 0; i < interests.length; i++) { - // remove the observer linking the mediator - // to the notification interest - this.removeObserver(interests[i], mediator); - } - - // remove the mediator from the map - this.mediatorMap.delete(mediatorName); - - // alert the mediator that it has been removed - mediator.onRemove(); - } - - return mediator; - } - - /** - * Check if a Mediator is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.mediatorMap.has(mediatorName); - } - - /** - * Remove a View instance - * - * @static - * @param key multitonKey of View instance to remove - */ - static removeView(key) { - this.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "View instance for this Multiton key already constructed!" }; - -} - -/* - * Controller.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A Multiton `Controller` implementation. - * - *

In PureMVC, the `Controller` class follows the - * 'Command and Controller' strategy, and assumes these - * responsibilities:

- * - *
    - *
  • Remembering which `Command`s - * are intended to handle which `Notifications`.
  • - *
  • Registering itself as an `Observer` with - * the `View` for each `Notification` - * that it has a `Command` mapping for.
  • - *
  • Creating a new instance of the proper `Command` - * to handle a given `Notification` when notified by the `View`.
  • - *
  • Calling the `Command`'s `execute` - * method, passing in the `Notification`.
  • - *
- * - *

Your application must register `Commands` with the - * Controller.

- * - *

The simplest way is to subclass `Facade`, - * and use its `initializeController` method to add your - * registrations.

- * - * @see View View - * @see Observer Observer - * @see Notification Notification - * @see SimpleCommand SimpleCommand - * @see MacroCommand MacroCommand - * - * @class Controller - */ -class Controller { - - /** - * Constructor. - * - *

This `Controller` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Controller.getInstance( multitonKey )`

- * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Controller.instanceMap[key] != null) throw new Error(Controller.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Controller.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.commandMap = new Map(); - this.initializeController(); - } - - /** - * Initialize the Multiton `Controller` instance. - * - *

Called automatically by the constructor.

- * - *

Note that if you are using a subclass of `View` - * in your application, you should also subclass `Controller` - * and override the `initializeController` method in the - * following way:

- * - *
`
-     *		// ensure that the Controller is talking to my View implementation
-     *		initializeController( )
-     *		{
-     *			this.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key));
-     *		}
-     * `
- * - */ - initializeController() { - /** @protected - * @type {View} **/ - this.view = View.getInstance(this.multitonKey, (key) => new View(key)); - } - - /** - * `Controller` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Controller} factory - * @returns {Controller} the Multiton instance of `Controller` - */ - static getInstance(key, factory) { - if (Controller.instanceMap == null) - /** @static - @type {Map} */ - Controller.instanceMap = new Map(); - if (Controller.instanceMap.get(key) == null) Controller.instanceMap.set(key, factory(key)); - return Controller.instanceMap.get(key); - } - - /** - *

If a `Command` has previously been registered - * to handle the given `Notification`, then it is executed.

- * - * @param {Notification} notification a `Notification` - */ - executeCommand(notification) { - let factory = this.commandMap.get(notification.name); - if (factory == null) return; - - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } - - /** - *

Register a particular `Command` class as the handler - * for a particular `Notification`.

- * - *

If an `Command` has already been registered to - * handle `Notification`s with this name, it is no longer - * used, the new `Command` is used instead.

- * - *

The Observer for the new Command is only created if this the - * first time a Command has been registered for this Notification name.

- * - * @param notificationName the name of the `Notification` - * @param {function():SimpleCommand} factory - */ - registerCommand(notificationName, factory) { - if (this.commandMap.get(notificationName) == null) { - this.view.registerObserver(notificationName, new Observer(this.executeCommand, this)); - } - this.commandMap.set(notificationName, factory); - } - - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @return {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.commandMap.has(notificationName); - } - - /** - * Remove a previously registered `Command` to `Notification` mapping. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - // if the Command is registered... - if(this.hasCommand(notificationName)) { - // remove the observer - this.view.removeObserver(notificationName, this); - - // remove the command - this.commandMap.delete(notificationName); - } - } - - /** - * Remove a Controller instance - * - * @static - * @param {string} key of Controller instance to remove - */ - static removeController(key) { - Controller.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Controller instance for this Multiton key already constructed!" }; -} - -/* - * Model.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - -/** - * A Multiton `Model` implementation. - * - *

In PureMVC, the `Model` class provides - * access to model objects (Proxies) by named lookup. - * - *

The `Model` assumes these responsibilities:

- * - *
    - *
  • Maintain a cache of `Proxy` instances.
  • - *
  • Provide methods for registering, retrieving, and removing - * `Proxy` instances.
  • - *
- * - *

Your application must register `Proxy` instances - * with the `Model`. Typically, you use an - * `Command` to create and register `Proxy` - * instances once the `Facade` has initialized the Core - * actors.

- * - * @see Proxy Proxy - * - * @class Model - */ -class Model { - - /** - * Constructor. - * - *

This `Model` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `Model.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key instance has already been constructed - */ - constructor(key) { - if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Model.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.proxyMap = new Map(); - this.initializeModel(); - } - - /** - * Initialize the `Model` instance. - * - *

Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.

- * - */ - initializeModel() { - - } - - /** - * `Model` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Model} factory - * @returns {Model} the instance for this Multiton key - */ - static getInstance(key, factory) { - if (Model.instanceMap == null) - /** @static - @type {Map} */ - Model.instanceMap = new Map(); - if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key)); - return Model.instanceMap.get(key); - } - - /** - * Register a `Proxy` with the `Model`. - * - * @param {Proxy} proxy a `Proxy` to be held by the `Model`. - */ - registerProxy(proxy) { - proxy.initializeNotifier(this.multitonKey); - this.proxyMap.set(proxy.proxyName, proxy); - proxy.onRegister(); - } - - /** - * Retrieve a `Proxy` from the `Model`. - * - * @param {string} proxyName - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.proxyMap.get(proxyName) || null; - } - - /** - * Check if a Proxy is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.proxyMap.has(proxyName); - } - - /** - * Remove a `Proxy` from the `Model`. - * - * @param {string} proxyName name of the `Proxy` instance to be removed. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - let proxy = this.proxyMap.get(proxyName); - if (proxy != null) { - this.proxyMap.delete(proxyName); - proxy.onRemove(); - } - return proxy; - } - - /** - * Remove a Model instance - * - * @static - * @param key - */ - static removeModel(key) { - Model.instanceMap.delete(key); - } - - /** - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Model instance for this Multiton key already constructed!" }; -} - -/* - * Notification.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - -/** - * A base `Notification` implementation. - * - *

PureMVC does not rely upon underlying event models such - * as the one provided with Flash, and ActionScript 3 does - * not have an inherent event model.

- * - *

The Observer Pattern as implemented within PureMVC exists - * to support event-driven communication between the - * application and the actors of the MVC triad.

- * - *

Notifications are not meant to be a replacement for Events - * in Flex/Flash/Apollo. Generally, `Mediator` implementors - * place event listeners on their view components, which they - * then handle in the usual way. This may lead to the broadcast of `Notification`s to - * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command` - * instances communicate with each other and `Mediator`s - * by broadcasting `Notification`s.

- * - *

A key difference between Flash `Event`s and PureMVC - * `Notification`s is that `Event`s follow the - * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy - * until some parent component handles the `Event`, while - * PureMVC `Notification`s follow a 'Publish/Subscribe' - * pattern. PureMVC classes need not be related to each other in a - * parent/child relationship in order to communicate with one another - * using `Notification`s.

- * - * @class Notification - */ -class Notification { - - /** - * Constructor. - * - * @constructor - * @param {string} name - The name of the notification. - * @param {Object|null} [body=null] - The body of the notification, defaults to `null`. - * @param {string} [type=""] - The type of the notification, defaults to an empty string. - */ - constructor(name, body = null, type = "") { - this._name = name; - this._body = body; - this._type = type; - } - - /** - * Get the name of the `Notification` instance. - * - * @returns {string} - */ - get name() { - return this._name; - } - - /** - * Get the body of the `Notification` instance. - * - * @returns {Object | null} - */ - get body() { - return this._body; - } - - /** - * Set the body of the `Notification` instance. - * - * @param {Object|null} body - */ - set body(body) { - this._body = body; - } - - /** - * Get the type of the `Notification` instance. - * - * @returns {string} - */ - get type() { - return this._type; - } - - /** - * Set the type of the `Notification` instance. - * - * @param {string} type - */ - set type(type) { - this._type = type; - } - - /** - * Get the string representation of the `Notification` instance. - * - * @returns {string} - */ - toString() { - let str= "Notification Name: " + this.name; - str+= "\nBody:" + ((this.body == null ) ? "null" : this.body.toString()); - str+= "\nType:" + ((this.type == null ) ? "null" : this.type); - return str; - } - -} - -/* - * Facade.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base Multiton `Facade` implementation. - * - * @see Model Model - * @see View View - * @see Controller Controller - * - * @class Facade - */ -class Facade { - - /** - * Constructor. - * - *

This `Facade` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Facade.getInstance( multitonKey )`

- * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG); - this.initializeNotifier(key); - Facade.instanceMap.set(this.multitonKey, this); - this.initializeFacade(); - } - - /** - * Initialize the Multiton `Facade` instance. - * - *

Called automatically by the constructor. Override in your - * subclass to do any subclass specific initializations. Be - * sure to call `super.initializeFacade()`, though.

- */ - initializeFacade() { - this.initializeModel(); - this.initializeController(); - this.initializeView(); - } - - /** - * Facade Multiton Factory method - * - * @static - * @param {string} key - * @param {function(string):Facade} factory - * @returns {Facade} the Multiton instance of the Facade - */ - static getInstance(key, factory) { - if (Facade.instanceMap == null) - /** @static - * @type {Map} */ - Facade.instanceMap = new Map(); - if (Facade.instanceMap.get(key) == null) Facade.instanceMap.set(key, factory(key)); - return Facade.instanceMap.get(key); - } - - /** - * Initialize the `Model`. - * - *

Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

- * - *
    - *
  • You wish to initialize a different `Model`.
  • - *
  • You have `Proxy`s to register with the Model that do not - * retrieve a reference to the Facade at construction time.`
  • - *
- * - * If you don't want to initialize a different `Model`, - * call `super.initializeModel()` at the beginning of your - * method, then register `Proxy`s. - * - *

Note: This method is rarely overridden; in practice you are more - * likely to use a `Command` to create and register `Proxy`s - * with the `Model`, since `Proxy`s with mutable data will likely - * need to send `Notification`s and thus will likely want to fetch a reference to - * the `Facade` during their construction.

- */ - initializeModel() { - if (this.model != null) return; - this.model = Model.getInstance(this.multitonKey, key => new Model(key)); - } - - /** - * Initialize the `Controller`. - * - *

Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

- * - *
    - *
  • You wish to initialize a different `Controller`.
  • - *
  • You have `Commands` to register with the `Controller` at startup.`.
  • - *
- * - *

If you don't want to initialize a different `Controller`, - * call `super.initializeController()` at the beginning of your - * method, then register `Command`s.

- */ - initializeController() { - if (this.controller != null) return; - this.controller = Controller.getInstance(this.multitonKey, key => new Controller(key)); - } - - /** - * Initialize the `View`. - * - *

Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

- * - *
    - *
  • You wish to initialize a different `View`.
  • - *
  • You have `Observers` to register with the `View`
  • - *
- * - *

If you don't want to initialize a different `View`, - * call `super.initializeView()` at the beginning of your - * method, then register `Mediator` instances.

- * - *

Note: This method is rarely overridden; in practice you are more - * likely to use a `Command` to create and register `Mediator`s - * with the `View`, since `Mediator` instances will need to send - * `Notification`s and thus will likely want to fetch a reference - * to the `Facade` during their construction.

- */ - initializeView() { - if (this.view != null) return; - this.view = View.getInstance(this.multitonKey, key => new View(key)); - } - - /** - * Register a `Command` with the `Controller` by Notification name. - * - * @param {string} notificationName the name of the `Notification` to associate the `Command` with - * @param {function():SimpleCommand} factory a reference to the factory of the `Command` - */ - registerCommand(notificationName, factory) { - this.controller.registerCommand(notificationName, factory); - } - - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @returns {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.controller.hasCommand(notificationName); - } - - /** - * Remove a previously registered `Command` to `Notification` mapping from the Controller. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - this.controller.removeCommand(notificationName); - } - - /** - * Register a `Proxy` with the `Model` by name. - * - * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`. - */ - registerProxy(proxy) { - this.model.registerProxy(proxy); - } - - /** - * Remove a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the `Proxy` to remove from the `Model`. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - return this.model.removeProxy(proxyName); - } - - /** - * Check if a `Proxy` is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.model.hasProxy(proxyName); - } - - /** - * Retrieve a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the name of the proxy to be retrieved. - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.model.retrieveProxy(proxyName); - } - - /** - * Register a `Mediator` with the `View`. - * - * @param {Mediator} mediator a reference to the `Mediator` - */ - registerMediator(mediator) { - this.view.registerMediator(mediator); - } - - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - return this.view.removeMediator(mediatorName); - } - - /** - * Check if a `Mediator` is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.view.hasMediator(mediatorName); - } - - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName - * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.view.retrieveMediator(mediatorName); - } - - /** - * Create and send an `Notification`. - * - *

Keeps us from having to construct new notification - * instances in our implementation code.

- * - * @param {string} notificationName the name of the notification to send - * @param {Object} [body] body the body of the notification (optional) - * @param {string} [type] type the type of the notification (optional) - */ - sendNotification(notificationName, body = null, type = "") { - this.notifyObservers(new Notification(notificationName, body, type)); - } - - /** - * Notify `Observer`s. - * - *

This method is left public mostly for backward - * compatibility, and to allow you to send custom - * notification classes using the facade.

- * - *

Usually you should just call `sendNotification` - * and pass the parameters, never having to - * construct the notification yourself.

- * - * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of. - */ - notifyObservers(notification) { - this.view.notifyObservers(notification); - } - - /** - * Set the Multiton key for this facade instance. - * - *

Not called directly, but instead from the - * constructor when getInstance is invoked. - * It is necessary to be public in order to - * implement Notifier.

- */ - initializeNotifier(key) { - this.multitonKey = key; - } - - /** - * Check if a Core is registered or not - * - * @static - * @param {string} key the multiton key for the Core in question - * @returns {boolean} whether a Core is registered with the given `key`. - */ - static hasCore(key) { - return this.instanceMap.has(key); - } - - /** - * Remove a Core. - * - *

Remove the Model, View, Controller and Facade - * instances for the given key.

- * - * @static - * @param {string} key multitonKey of the Core to remove - */ - static removeCore(key) { - if (Facade.instanceMap.get(key) == null) return; - Model.removeModel(key); - View.removeView(key); - Controller.removeController(key); - this.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() {return "Facade instance for this Multiton key already constructed!"}; -} - -/* - * Notifier.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A Base `Notifier` implementation. - * - *

`MacroCommand, Command, Mediator` and `Proxy` - * all have a need to send `Notifications`.

- * - *

The `Notifier` interface provides a common method called - * `sendNotification` that relieves implementation code of - * the necessity to actually construct `Notifications`.

- * - *

The `Notifier` class, which all the above-mentioned classes - * extend, provides an initialized reference to the `Facade` - * Multiton, which is required for the convenience method - * for sending `Notifications`, but also eases implementation as these - * classes have frequent `Facade` interactions and usually require - * access to the facade anyway.

- * - *

NOTE: In the MultiCore version of the framework, there is one caveat to - * notifiers, they cannot send notifications or reach the facade until they - * have a valid multitonKey.

- * - * The multitonKey is set: - * * on a Command when it is executed by the Controller - * * on a Mediator is registered with the View - * * on a Proxy is registered with the Model. - * - * @see Proxy Proxy - * @see Facade Facade - * @see Mediator Mediator - * @see MacroCommand MacroCommand - * @see SimpleCommand SimpleCommand - * - * @class Notifier - */ -class Notifier { - - constructor() {} - - /** - * Create and send an `Notification`. - * - *

Keeps us from having to construct new Notification - * instances in our implementation code.

- * - * @param {string} notificationName - * @param {Object} [body] body - * @param {string} [type] type - */ - sendNotification (notificationName, body = null, type = "") { - if (this.facade != null) { - this.facade.sendNotification(notificationName, body, type); - } - } - - /** - * Initialize this Notifier instance. - * - *

This is how a Notifier gets its multitonKey. - * Calls to sendNotification or to access the - * facade will fail until after this method - * has been called.

- * - *

Mediators, Commands or Proxies may override - * this method in order to send notifications - * or access the Multiton Facade instance as - * soon as possible. They CANNOT access the facade - * in their constructors, since this method will not - * yet have been called.

- * - * @param {string} key the multitonKey for this Notifier to use - */ - initializeNotifier(key) { - this.multitonKey = key; - } - - /** - * Return the Multiton Facade instance - * - * @typedef {Facade} Facade - * - * @throws {Error} - */ - get facade() { - if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG); - return Facade.getInstance(this.multitonKey, key => new Facade(key)); - } - - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() { return "multitonKey for this Notifier not yet initialized!" } -} - -/* - * SimpleCommand.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Command` implementation. - * - *

Your subclass should override the `execute` - * method where your business logic will handle the `Notification`.

- * - * @see Controller Controller - * @see Notification Notification - * @see MacroCommand MacroCommand - * - * @class SimpleCommand - */ -class SimpleCommand extends Notifier { - - constructor() { - super(); - } - - /** - * Fulfill the use-case initiated by the given `Notification`. - * - *

In the Command Pattern, an application use-case typically - * begins with some user action, which results in a `Notification` being broadcast, which - * is handled by business logic in the `execute` method of an - * `Command`.

- * - * @param {Notification} notification - */ - execute(notification) { - - } - -} - -/* - * MacroCommand.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Command` implementation that executes other `Command`s. - * - *

A `MacroCommand` maintains a list of - * `Command` Class references called SubCommands.

- * - *

When `execute` is called, the `MacroCommand` - * instantiates and calls `execute` on each of its SubCommands turn. - * Each SubCommand will be passed a reference to the original - * `Notification` that was passed to the `MacroCommand`'s - * `execute` method.

- * - *

Unlike `SimpleCommand`, your subclass - * should not override `execute`, but instead, should - * override the `initializeMacroCommand` method, - * calling `addSubCommand` once for each SubCommand - * to be executed.

- * - * @see Controller Controller - * @see Notification Notification - * @see SimpleCommand SimpleCommand - * - * @class MacroCommand - */ -class MacroCommand extends SimpleCommand { - - /** - * Constructor. - * - *

You should not need to define a constructor, - * instead, override the `initializeMacroCommand` - * method.

- * - *

If your subclass does define a constructor, be - * sure to call `super()`.

- * - * @constructor - */ - constructor() { - super(); - /** @protected - * @type {Array.} */ - this.subCommands = []; - this.initializeMacroCommand(); - } - - /** - * Initialize the `MacroCommand`. - * - *

In your subclass, override this method to - * initialize the `MacroCommand`'s SubCommand - * list with `Command` class references like - * this:

- * - *
`
-     *		// Initialize MyMacroCommand
-     *		initializeMacroCommand() {
-     *			this.addSubCommand(() => new app.FirstCommand());
-     *			this.addSubCommand(() => new app.SecondCommand());
-     *			this.addSubCommand(() => new app.ThirdCommand());
-     *		}
-     * `
- * - *

Note that SubCommands may be any `Command` implementor, - * `MacroCommand`s or `SimpleCommands` are both acceptable. - */ - initializeMacroCommand() { - - } - - /** - * Add a SubCommand. - * - *

The SubCommands will be called in First In/First Out (FIFO) - * order.

- * - * @param {function():SimpleCommand} factory - */ - addSubCommand(factory) { - this.subCommands.push(factory); - } - - /** - * Execute this `MacroCommand`'s SubCommands. - * - *

The SubCommands will be called in First In/First Out (FIFO) - * order.

- * - * @param {Notification} notification - */ - execute(notification) { - while(this.subCommands.length > 0) { - let factory = this.subCommands.shift(); - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } - } - -} - -/* - * Mediator.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Mediator` implementation. - * - * @see View View - * - * @class Mediator - */ -class Mediator extends Notifier { - - /** - * Constructor. - * - * @constructor - * @param {string | null} [mediatorName=null] - * @param {Object | null} [viewComponent=null] - */ - constructor(mediatorName = null, viewComponent = null) { - super(); - this._mediatorName = mediatorName || Mediator.NAME; - this._viewComponent = viewComponent; - } - - /** - * Called by the View when the Mediator is registered - */ - onRegister() { - - } - - /** - * Called by the View when the Mediator is removed - */ - onRemove() { - - } - - /** - * List the `Notification` names this - * `Mediator` is interested in being notified of. - * - * @returns {string[]} - */ - listNotificationInterests() { - return []; - } - - /** - * Handle `Notification`s. - * - *

- * Typically this will be handled in a switch statement, - * with one 'case' entry per `Notification` - * the `Mediator` is interested in. - * - * @param {Notification} notification - */ - handleNotification(notification) { - - } - - /** - * the mediator name - * - * @returns {string} - */ - get mediatorName() { - return this._mediatorName; - } - - /** - * Get the `Mediator`'s view component. - * - *

- * Additionally, an implicit getter will usually - * be defined in the subclass that casts the view - * object to a type, like this:

- * - * @returns {Object | null} - */ - get viewComponent() { - return this._viewComponent; - } - - /** - * Set the `Mediator`'s view component. - * - * @param {Object} viewComponent - */ - set viewComponent(viewComponent) { - this._viewComponent = viewComponent; - } - - /** - * The name of the `Mediator`. - * - *

Typically, a `Mediator` will be written to serve - * one specific control or group controls and so, - * will not have a need to be dynamically named.

- * - * @static - * @returns {string} - */ - static get NAME() { return "Mediator" } -} - -/* - * Proxy.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Proxy` implementation. - * - *

In PureMVC, `Proxy` classes are used to manage parts of the - * application's data model.

- * - *

A `Proxy` might simply manage a reference to a local data object, - * in which case interacting with it might involve setting and - * getting of its data in synchronous fashion.

- * - *

`Proxy` classes are also used to encapsulate the application's - * interaction with remote services to save or retrieve data, in which case, - * we adopt an asynchronous idiom; setting data (or calling a method) on the - * `Proxy` and listening for a `Notification` to be sent - * when the `Proxy` has retrieved the data from the service.

- * - * @see Model Model - * - * @class Proxy - */ -class Proxy extends Notifier { - /** - * Constructor - * - * @constructor - * @param {string | null} [proxyName=null] - * @param {Object | null} [data=null] - */ - constructor(proxyName = null, data = null) { - super(); - /** @protected - * @type {string} */ - this._proxyName = proxyName || Proxy.NAME; - /** @protected - * @type {Object | null} */ - this._data = data; - } - - /** - * Called by the Model when the Proxy is registered - */ - onRegister() {} - - /** - * Called by the Model when the Proxy is removed - */ - onRemove() {} - - /** - * Get the proxy name - * - * @returns {string} - */ - get proxyName() { - return this._proxyName; - } - - /** - * Get the data object - * - * @returns {Object | null} - */ - get data () { - return this._data; - } - - /** - * Set the data object - * - * @param {Object} data - */ - set data(data) { - this._data = data; - } - - /** - * - * @static - * @returns {string} - */ - static get NAME() { return "Proxy" } -} - -exports.Controller = Controller; -exports.Facade = Facade; -exports.MacroCommand = MacroCommand; -exports.Mediator = Mediator; -exports.Model = Model; -exports.Notification = Notification; -exports.Notifier = Notifier; -exports.Observer = Observer; -exports.Proxy = Proxy; -exports.SimpleCommand = SimpleCommand; -exports.View = View; diff --git a/bin/cjs/index.min.cjs b/bin/cjs/index.min.cjs deleted file mode 100644 index e3b9eab..0000000 --- a/bin/cjs/index.min.cjs +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";class t{constructor(t=null,e=null){this._notifyMethod=t,this._notifyContext=e}notifyObserver(t){this._notifyMethod.call(this._notifyContext,t)}compareNotifyContext(t){return this._notifyContext===t}get notifyMethod(){return this._notifyMethod}set notifyMethod(t){this._notifyMethod=t}get notifyContext(){return this._notifyContext}set notifyContext(t){this._notifyContext=t}}class e{constructor(t){if(null!=e.instanceMap.get(t))throw new Error(e.MULTITON_MSG);this.multitonKey=t,e.instanceMap.set(this.multitonKey,this),this.mediatorMap=new Map,this.observerMap=new Map,this.initializeView()}initializeView(){}static getInstance(t,i){return null==e.instanceMap&&(e.instanceMap=new Map),null==e.instanceMap.get(t)&&e.instanceMap.set(t,i(t)),e.instanceMap.get(t)}registerObserver(t,e){if(null!=this.observerMap.get(t)){this.observerMap.get(t).push(e)}else this.observerMap.set(t,new Array(e))}notifyObservers(t){if(this.observerMap.has(t.name)){let e=this.observerMap.get(t.name).slice();for(let i=0;i0){let n=new t(e.handleNotification.bind(e),e);for(let t=0;tnew e(t)))}static getInstance(t,e){return null==i.instanceMap&&(i.instanceMap=new Map),null==i.instanceMap.get(t)&&i.instanceMap.set(t,e(t)),i.instanceMap.get(t)}executeCommand(t){let e=this.commandMap.get(t.name);if(null==e)return;let i=e();i.initializeNotifier(this.multitonKey),i.execute(t)}registerCommand(e,i){null==this.commandMap.get(e)&&this.view.registerObserver(e,new t(this.executeCommand,this)),this.commandMap.set(e,i)}hasCommand(t){return this.commandMap.has(t)}removeCommand(t){this.hasCommand(t)&&(this.view.removeObserver(t,this),this.commandMap.delete(t))}static removeController(t){i.instanceMap.delete(t)}static get MULTITON_MSG(){return"Controller instance for this Multiton key already constructed!"}}class n{constructor(t){if(null!=n.instanceMap.get(t))throw new Error(n.MULTITON_MSG);this.multitonKey=t,n.instanceMap.set(this.multitonKey,this),this.proxyMap=new Map,this.initializeModel()}initializeModel(){}static getInstance(t,e){return null==n.instanceMap&&(n.instanceMap=new Map),null==n.instanceMap.get(t)&&n.instanceMap.set(t,e(t)),n.instanceMap.get(t)}registerProxy(t){t.initializeNotifier(this.multitonKey),this.proxyMap.set(t.proxyName,t),t.onRegister()}retrieveProxy(t){return this.proxyMap.get(t)||null}hasProxy(t){return this.proxyMap.has(t)}removeProxy(t){let e=this.proxyMap.get(t);return null!=e&&(this.proxyMap.delete(t),e.onRemove()),e}static removeModel(t){n.instanceMap.delete(t)}static get MULTITON_MSG(){return"Model instance for this Multiton key already constructed!"}}class r{constructor(t,e=null,i=""){this._name=t,this._body=e,this._type=i}get name(){return this._name}get body(){return this._body}set body(t){this._body=t}get type(){return this._type}set type(t){this._type=t}toString(){let t="Notification Name: "+this.name;return t+="\nBody:"+(null==this.body?"null":this.body.toString()),t+="\nType:"+(null==this.type?"null":this.type),t}}class s{constructor(t){if(null!=s.instanceMap[t])throw new Error(s.MULTITON_MSG);this.initializeNotifier(t),s.instanceMap.set(this.multitonKey,this),this.initializeFacade()}initializeFacade(){this.initializeModel(),this.initializeController(),this.initializeView()}static getInstance(t,e){return null==s.instanceMap&&(s.instanceMap=new Map),null==s.instanceMap.get(t)&&s.instanceMap.set(t,e(t)),s.instanceMap.get(t)}initializeModel(){null==this.model&&(this.model=n.getInstance(this.multitonKey,(t=>new n(t))))}initializeController(){null==this.controller&&(this.controller=i.getInstance(this.multitonKey,(t=>new i(t))))}initializeView(){null==this.view&&(this.view=e.getInstance(this.multitonKey,(t=>new e(t))))}registerCommand(t,e){this.controller.registerCommand(t,e)}hasCommand(t){return this.controller.hasCommand(t)}removeCommand(t){this.controller.removeCommand(t)}registerProxy(t){this.model.registerProxy(t)}removeProxy(t){return this.model.removeProxy(t)}hasProxy(t){return this.model.hasProxy(t)}retrieveProxy(t){return this.model.retrieveProxy(t)}registerMediator(t){this.view.registerMediator(t)}removeMediator(t){return this.view.removeMediator(t)}hasMediator(t){return this.view.hasMediator(t)}retrieveMediator(t){return this.view.retrieveMediator(t)}sendNotification(t,e=null,i=""){this.notifyObservers(new r(t,e,i))}notifyObservers(t){this.view.notifyObservers(t)}initializeNotifier(t){this.multitonKey=t}static hasCore(t){return this.instanceMap.has(t)}static removeCore(t){null!=s.instanceMap.get(t)&&(n.removeModel(t),e.removeView(t),i.removeController(t),this.instanceMap.delete(t))}static get MULTITON_MSG(){return"Facade instance for this Multiton key already constructed!"}}class o{constructor(){}sendNotification(t,e=null,i=""){null!=this.facade&&this.facade.sendNotification(t,e,i)}initializeNotifier(t){this.multitonKey=t}get facade(){if(null==this.multitonKey)throw new Error(o.MULTITON_MSG);return s.getInstance(this.multitonKey,(t=>new s(t)))}static get MULTITON_MSG(){return"multitonKey for this Notifier not yet initialized!"}}class a extends o{constructor(){super()}execute(t){}}class l extends o{constructor(t=null,e=null){super(),this._mediatorName=t||l.NAME,this._viewComponent=e}onRegister(){}onRemove(){}listNotificationInterests(){return[]}handleNotification(t){}get mediatorName(){return this._mediatorName}get viewComponent(){return this._viewComponent}set viewComponent(t){this._viewComponent=t}static get NAME(){return"Mediator"}}class h extends o{constructor(t=null,e=null){super(),this._proxyName=t||h.NAME,this._data=e}onRegister(){}onRemove(){}get proxyName(){return this._proxyName}get data(){return this._data}set data(t){this._data=t}static get NAME(){return"Proxy"}}exports.Controller=i,exports.Facade=s,exports.MacroCommand=class extends a{constructor(){super(),this.subCommands=[],this.initializeMacroCommand()}initializeMacroCommand(){}addSubCommand(t){this.subCommands.push(t)}execute(t){for(;this.subCommands.length>0;){let e=this.subCommands.shift()();e.initializeNotifier(this.multitonKey),e.execute(t)}}},exports.Mediator=l,exports.Model=n,exports.Notification=r,exports.Notifier=o,exports.Observer=t,exports.Proxy=h,exports.SimpleCommand=a,exports.View=e; -//# sourceMappingURL=index.min.cjs.map diff --git a/bin/cjs/index.min.cjs.map b/bin/cjs/index.min.cjs.map deleted file mode 100644 index c915234..0000000 --- a/bin/cjs/index.min.cjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.min.cjs","sources":["../../src/patterns/observer/Observer.js","../../src/core/View.js","../../src/core/Controller.js","../../src/core/Model.js","../../src/patterns/observer/Notification.js","../../src/patterns/facade/Facade.js","../../src/patterns/observer/Notifier.js","../../src/patterns/command/SimpleCommand.js","../../src/patterns/mediator/Mediator.js","../../src/patterns/proxy/Proxy.js","../../src/patterns/command/MacroCommand.js"],"sourcesContent":["/*\n * Observer.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\n/**\n * A base `Observer` implementation.\n *\n *

An `Observer` is an object that encapsulates information\n * about an interested object with a method that should\n * be called when a particular `Notification` is broadcast.

\n *\n *

In PureMVC, the `Observer` class assumes these responsibilities:

\n *\n *
    \n *
  • Encapsulate the notification (callback) method of the interested object.
  • \n *
  • Encapsulate the notification context (this) of the interested object.
  • \n *
  • Provide methods for setting the notification method and context.
  • \n *
  • Provide a method for notifying the interested object.
  • \n *
\n *\n * @class Observer\n */\nclass Observer {\n\n /**\n * Constructor.\n *\n *

The notification method on the interested object should take\n * one parameter of type `Notification`

\n *\n * @param {function(Notification):void | null} [notify = null]\n * @param {Object | null} [context = null]\n */\n constructor(notify = null, context = null) {\n this._notifyMethod = notify;\n this._notifyContext = context;\n }\n\n /**\n * Notify the interested object.\n *\n * @param {Notification} notification\n */\n notifyObserver(notification) {\n this._notifyMethod.call(this._notifyContext, notification);\n }\n\n /**\n * Compare an object to the notification context.\n *\n * @param {Object} notifyContext\n * @returns {boolean}\n */\n compareNotifyContext(notifyContext) {\n return this._notifyContext === notifyContext;\n }\n\n /**\n * Get the notification method.\n *\n * @returns {function(Notification):void}\n */\n get notifyMethod() {\n return this._notifyMethod\n }\n\n /**\n * Set the notification method.\n *\n *

The notification method should take one parameter of type `Notification`.

\n *\n * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received.\n */\n set notifyMethod(notifyMethod) {\n this._notifyMethod = notifyMethod;\n }\n\n /**\n * Get the notifyContext\n *\n * @returns {Object}\n */\n get notifyContext() {\n return this._notifyContext;\n }\n\n /**\n * Set the notification context.\n *\n * @param {Object} notifyContext\n */\n set notifyContext(notifyContext) {\n this._notifyContext = notifyContext;\n }\n\n}\nexport { Observer }\n","/*\n * View.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Observer} from \"../patterns/observer/Observer.js\";\n\n/**\n * A Multiton `View` implementation.\n *\n *

In PureMVC, the `View` class assumes these responsibilities:

\n *\n *
    \n *
  • Maintain a cache of `Mediator` instances.
  • \n *
  • Provide methods for registering, retrieving, and removing `Mediators`.
  • \n *
  • Notifying `Mediators` when they are registered or removed.
  • \n *
  • Managing the observer lists for each `Notification` in the application.
  • \n *
  • Providing a method for attaching `Observers` to a `Notification`'s observer list.
  • \n *
  • Providing a method for broadcasting a `Notification`.
  • \n *
  • Notifying the `Observers` of a given `Notification` when it broadcast.
  • \n *
\n *\n * @see Mediator Mediator\n * @see Observer Observer\n * @see Notification Notification\n *\n * @class View\n */\nclass View {\n\n /**\n * Constructor.\n *\n *

This `View` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Multiton\n * Factory method `View.getInstance( multitonKey )`\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key has already been constructed\n */\n constructor(key) {\n if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG);\n /** @protected\n * @type {string} */\n this.multitonKey = key;\n View.instanceMap.set(this.multitonKey, this);\n /** @protected\n * @type {Map} */\n this.mediatorMap = new Map();\n /** @protected\n * @type {Map.>} */\n this.observerMap = new Map();\n this.initializeView();\n }\n\n /**\n *

Initialize the Multiton View instance.

\n *\n *

Called automatically by the constructor, this\n * is your opportunity to initialize the Multiton\n * instance in your subclass without overriding the\n * constructor.

\n */\n initializeView() {\n\n }\n\n /**\n * View Multiton factory method.\n *\n * @static\n * @param {string} key\n * @param {function(string):View} factory\n * @returns {View} the Multiton instance of `View`\n */\n static getInstance(key, factory) {\n if (View.instanceMap == null)\n /** @static\n * @type {Map} */\n View.instanceMap = new Map();\n if (View.instanceMap.get(key) == null) View.instanceMap.set(key, factory(key));\n return View.instanceMap.get(key);\n }\n\n /**\n *

Register an `Observer` to be notified\n * of `Notifications` with a given name.

\n *\n * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of\n * @param {Observer} observer the `Observer` to register\n */\n registerObserver(notificationName, observer) {\n if (this.observerMap.get(notificationName) != null) {\n let observers = this.observerMap.get(notificationName);\n observers.push(observer);\n } else {\n this.observerMap.set(notificationName, new Array(observer));\n }\n }\n\n /**\n *

Notify the `Observers` for a particular `Notification`.

\n *\n *

All previously attached `Observers` for this `Notification`'s\n * list are notified and are passed a reference to the `Notification` in\n * the order in which they were registered.

\n *\n * @param {Notification} notification the `Notification` to notify `Observers` of.\n */\n notifyObservers(notification) {\n if (this.observerMap.has(notification.name)) {\n // Copy observers from reference array to working array,\n // since the reference array may change during the notification loop\n let observers = this.observerMap.get(notification.name).slice();\n\n // Notify Observers from the working array\n for(let i = 0; i < observers.length; i++) {\n observers[i].notifyObserver(notification);\n }\n }\n }\n\n /**\n *

Remove the observer for a given notifyContext from an observer list for a given Notification name.

\n *\n * @param {string} notificationName which observer list to remove from\n * @param {Object} notifyContext remove the observer with this object as its notifyContext\n */\n removeObserver(notificationName, notifyContext) {\n // the observer list for the notification under inspection\n let observers = this.observerMap.get(notificationName);\n\n // find the observer for the notifyContext\n for (let i = 0; i < observers.length; i++) {\n if (observers[i].compareNotifyContext(notifyContext) === true) {\n // there can only be one Observer for a given notifyContext\n // in any given Observer list, so remove it and break\n observers.splice(i, 1);\n break;\n }\n }\n\n // Also, when a Notification's Observer list length falls to\n // zero, delete the notification key from the observer map\n if (observers.length === 0) {\n this.observerMap.delete(notificationName);\n }\n }\n\n /**\n * Register a `Mediator` instance with the `View`.\n *\n *

Registers the `Mediator` so that it can be retrieved by name,\n * and further interrogates the `Mediator` for its\n * `Notification` interests.

\n *\n *

If the `Mediator` returns any `Notification`\n * names to be notified about, an `Observer` is created encapsulating\n * the `Mediator` instance's `handleNotification` method\n * and registering it as an `Observer` for all `Notifications` the\n * `Mediator` is interested in.

\n *\n * @param {Mediator} mediator a reference to the `Mediator` instance\n */\n registerMediator(mediator) {\n // do not allow re-registration (you must to removeMediator fist)\n if (this.mediatorMap.has(mediator.mediatorName) !== false) return;\n\n mediator.initializeNotifier(this.multitonKey);\n\n // Register the Mediator for retrieval by name\n this.mediatorMap.set(mediator.mediatorName, mediator);\n\n // Get Notification interests, if any.\n let interests = mediator.listNotificationInterests();\n\n // Register Mediator as an observer for each notification of interests\n if (interests.length > 0) {\n // Create Observer referencing this mediator's handleNotification method\n let observer = new Observer(mediator.handleNotification.bind(mediator), mediator); // check bind\n\n // Register Mediator as Observer for its list of Notification interests\n for (let i = 0; i < interests.length; i++) {\n this.registerObserver(interests[i], observer);\n }\n }\n\n // alert the mediator that it has been registered\n mediator.onRegister();\n }\n\n /**\n * Retrieve a `Mediator` from the `View`.\n *\n * @param {string} mediatorName the name of the `Mediator` instance to retrieve.\n * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`.\n */\n retrieveMediator(mediatorName) {\n return this.mediatorMap.get(mediatorName) || null;\n }\n\n /**\n * Remove a `Mediator` from the `View`.\n *\n * @param {string} mediatorName name of the `Mediator` instance to be removed.\n * @returns {Mediator} the `Mediator` that was removed from the `View`\n */\n removeMediator(mediatorName) {\n // Retrieve the named mediator\n let mediator = this.mediatorMap.get(mediatorName);\n\n if (mediator) {\n // for every notification this mediator is interested in...\n let interests = mediator.listNotificationInterests();\n for (let i = 0; i < interests.length; i++) {\n // remove the observer linking the mediator\n // to the notification interest\n this.removeObserver(interests[i], mediator);\n }\n\n // remove the mediator from the map\n this.mediatorMap.delete(mediatorName);\n\n // alert the mediator that it has been removed\n mediator.onRemove();\n }\n\n return mediator;\n }\n\n /**\n * Check if a Mediator is registered or not\n *\n * @param {string} mediatorName\n * @returns {boolean} whether a Mediator is registered with the given `mediatorName`.\n */\n hasMediator(mediatorName) {\n return this.mediatorMap.has(mediatorName);\n }\n\n /**\n * Remove a View instance\n *\n * @static\n * @param key multitonKey of View instance to remove\n */\n static removeView(key) {\n this.instanceMap.delete(key);\n }\n\n /**\n * Message Constants\n *\n * @static\n * @type {string}\n */\n static get MULTITON_MSG() { return \"View instance for this Multiton key already constructed!\" };\n\n}\nexport { View }\n","/*\n * Controller.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {View} from \"./View.js\"\nimport {Observer} from \"../patterns/observer/Observer.js\";\n\n/**\n * A Multiton `Controller` implementation.\n *\n *

In PureMVC, the `Controller` class follows the\n * 'Command and Controller' strategy, and assumes these\n * responsibilities:

\n *\n *
    \n *
  • Remembering which `Command`s\n * are intended to handle which `Notifications`.
  • \n *
  • Registering itself as an `Observer` with\n * the `View` for each `Notification`\n * that it has a `Command` mapping for.
  • \n *
  • Creating a new instance of the proper `Command`\n * to handle a given `Notification` when notified by the `View`.
  • \n *
  • Calling the `Command`'s `execute`\n * method, passing in the `Notification`.
  • \n *
\n *\n *

Your application must register `Commands` with the\n * Controller.

\n *\n *

The simplest way is to subclass `Facade`,\n * and use its `initializeController` method to add your\n * registrations.

\n *\n * @see View View\n * @see Observer Observer\n * @see Notification Notification\n * @see SimpleCommand SimpleCommand\n * @see MacroCommand MacroCommand\n *\n * @class Controller\n */\nclass Controller {\n\n /**\n * Constructor.\n *\n *

This `Controller` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Factory method,\n * passing the unique key for this instance\n * `Controller.getInstance( multitonKey )`

\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key has already been constructed\n */\n constructor(key) {\n if (Controller.instanceMap[key] != null) throw new Error(Controller.MULTITON_MSG);\n /** @protected\n * @type {string} */\n this.multitonKey = key;\n Controller.instanceMap.set(this.multitonKey, this);\n /** @protected\n * @type {Map} */\n this.commandMap = new Map();\n this.initializeController();\n }\n\n /**\n * Initialize the Multiton `Controller` instance.\n *\n *

Called automatically by the constructor.

\n *\n *

Note that if you are using a subclass of `View`\n * in your application, you should also subclass `Controller`\n * and override the `initializeController` method in the\n * following way:

\n *\n *
`\n     *\t\t// ensure that the Controller is talking to my View implementation\n     *\t\tinitializeController( )\n     *\t\t{\n     *\t\t\tthis.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key));\n     *\t\t}\n     * `
\n *\n */\n initializeController() {\n /** @protected\n * @type {View} **/\n this.view = View.getInstance(this.multitonKey, (key) => new View(key));\n }\n\n /**\n * `Controller` Multiton Factory method.\n *\n * @static\n * @param {string} key\n * @param {function(string):Controller} factory\n * @returns {Controller} the Multiton instance of `Controller`\n */\n static getInstance(key, factory) {\n if (Controller.instanceMap == null)\n /** @static\n @type {Map} */\n Controller.instanceMap = new Map();\n if (Controller.instanceMap.get(key) == null) Controller.instanceMap.set(key, factory(key));\n return Controller.instanceMap.get(key);\n }\n\n /**\n *

If a `Command` has previously been registered\n * to handle the given `Notification`, then it is executed.

\n *\n * @param {Notification} notification a `Notification`\n */\n executeCommand(notification) {\n let factory = this.commandMap.get(notification.name);\n if (factory == null) return;\n\n let commandInstance = factory();\n commandInstance.initializeNotifier(this.multitonKey);\n commandInstance.execute(notification);\n }\n\n /**\n *

Register a particular `Command` class as the handler\n * for a particular `Notification`.

\n *\n *

If an `Command` has already been registered to\n * handle `Notification`s with this name, it is no longer\n * used, the new `Command` is used instead.

\n *\n *

The Observer for the new Command is only created if this the\n * first time a Command has been registered for this Notification name.

\n *\n * @param notificationName the name of the `Notification`\n * @param {function():SimpleCommand} factory\n */\n registerCommand(notificationName, factory) {\n if (this.commandMap.get(notificationName) == null) {\n this.view.registerObserver(notificationName, new Observer(this.executeCommand, this));\n }\n this.commandMap.set(notificationName, factory);\n }\n\n /**\n * Check if a Command is registered for a given Notification\n *\n * @param {string} notificationName\n * @return {boolean} whether a Command is currently registered for the given `notificationName`.\n */\n hasCommand(notificationName) {\n return this.commandMap.has(notificationName);\n }\n\n /**\n * Remove a previously registered `Command` to `Notification` mapping.\n *\n * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for\n */\n removeCommand(notificationName) {\n // if the Command is registered...\n if(this.hasCommand(notificationName)) {\n // remove the observer\n this.view.removeObserver(notificationName, this);\n\n // remove the command\n this.commandMap.delete(notificationName)\n }\n }\n\n /**\n * Remove a Controller instance\n *\n * @static\n * @param {string} key of Controller instance to remove\n */\n static removeController(key) {\n Controller.instanceMap.delete(key);\n }\n\n /**\n * Message Constants\n *\n * @static\n * @type {string}\n */\n static get MULTITON_MSG() { return \"Controller instance for this Multiton key already constructed!\" };\n}\nexport { Controller }\n","/*\n * Model.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\n/**\n * A Multiton `Model` implementation.\n *\n *

In PureMVC, the `Model` class provides\n * access to model objects (Proxies) by named lookup.\n *\n *

The `Model` assumes these responsibilities:

\n *\n *
    \n *
  • Maintain a cache of `Proxy` instances.
  • \n *
  • Provide methods for registering, retrieving, and removing\n * `Proxy` instances.
  • \n *
\n *\n *

Your application must register `Proxy` instances\n * with the `Model`. Typically, you use an\n * `Command` to create and register `Proxy`\n * instances once the `Facade` has initialized the Core\n * actors.

\n *\n * @see Proxy Proxy\n *\n * @class Model\n */\nclass Model {\n\n /**\n * Constructor.\n *\n *

This `Model` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Multiton\n * Factory method `Model.getInstance( multitonKey )`\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key instance has already been constructed\n */\n constructor(key) {\n if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG);\n /** @protected\n * @type {string} */\n this.multitonKey = key;\n Model.instanceMap.set(this.multitonKey, this);\n /** @protected\n * @type {Map} */\n this.proxyMap = new Map();\n this.initializeModel();\n }\n\n /**\n * Initialize the `Model` instance.\n *\n *

Called automatically by the constructor, this\n * is your opportunity to initialize the Multiton\n * instance in your subclass without overriding the\n * constructor.

\n *\n */\n initializeModel() {\n\n }\n\n /**\n * `Model` Multiton Factory method.\n *\n * @static\n * @param {string} key\n * @param {function(string):Model} factory\n * @returns {Model} the instance for this Multiton key\n */\n static getInstance(key, factory) {\n if (Model.instanceMap == null)\n /** @static\n @type {Map} */\n Model.instanceMap = new Map();\n if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key));\n return Model.instanceMap.get(key);\n }\n\n /**\n * Register a `Proxy` with the `Model`.\n *\n * @param {Proxy} proxy a `Proxy` to be held by the `Model`.\n */\n registerProxy(proxy) {\n proxy.initializeNotifier(this.multitonKey);\n this.proxyMap.set(proxy.proxyName, proxy);\n proxy.onRegister();\n }\n\n /**\n * Retrieve a `Proxy` from the `Model`.\n *\n * @param {string} proxyName\n * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`.\n */\n retrieveProxy(proxyName) {\n return this.proxyMap.get(proxyName) || null;\n }\n\n /**\n * Check if a Proxy is registered\n *\n * @param {string} proxyName\n * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`.\n */\n hasProxy(proxyName) {\n return this.proxyMap.has(proxyName);\n }\n\n /**\n * Remove a `Proxy` from the `Model`.\n *\n * @param {string} proxyName name of the `Proxy` instance to be removed.\n * @returns {Proxy} the `Proxy` that was removed from the `Model`\n */\n removeProxy(proxyName) {\n let proxy = this.proxyMap.get(proxyName);\n if (proxy != null) {\n this.proxyMap.delete(proxyName);\n proxy.onRemove();\n }\n return proxy;\n }\n\n /**\n * Remove a Model instance\n *\n * @static\n * @param key\n */\n static removeModel(key) {\n Model.instanceMap.delete(key);\n }\n\n /**\n * @static\n * @type {string}\n */\n static get MULTITON_MSG() { return \"Model instance for this Multiton key already constructed!\" };\n}\nexport { Model }\n","/*\n * Notification.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\n/**\n * A base `Notification` implementation.\n *\n *

PureMVC does not rely upon underlying event models such\n * as the one provided with Flash, and ActionScript 3 does\n * not have an inherent event model.

\n *\n *

The Observer Pattern as implemented within PureMVC exists\n * to support event-driven communication between the\n * application and the actors of the MVC triad.

\n *\n *

Notifications are not meant to be a replacement for Events\n * in Flex/Flash/Apollo. Generally, `Mediator` implementors\n * place event listeners on their view components, which they\n * then handle in the usual way. This may lead to the broadcast of `Notification`s to\n * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command`\n * instances communicate with each other and `Mediator`s\n * by broadcasting `Notification`s.

\n *\n *

A key difference between Flash `Event`s and PureMVC\n * `Notification`s is that `Event`s follow the\n * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy\n * until some parent component handles the `Event`, while\n * PureMVC `Notification`s follow a 'Publish/Subscribe'\n * pattern. PureMVC classes need not be related to each other in a\n * parent/child relationship in order to communicate with one another\n * using `Notification`s.

\n *\n * @class Notification\n */\nclass Notification {\n\n /**\n * Constructor.\n *\n * @constructor\n * @param {string} name - The name of the notification.\n * @param {Object|null} [body=null] - The body of the notification, defaults to `null`.\n * @param {string} [type=\"\"] - The type of the notification, defaults to an empty string.\n */\n constructor(name, body = null, type = \"\") {\n this._name = name;\n this._body = body;\n this._type = type;\n }\n\n /**\n * Get the name of the `Notification` instance.\n *\n * @returns {string}\n */\n get name() {\n return this._name;\n }\n\n /**\n * Get the body of the `Notification` instance.\n *\n * @returns {Object | null}\n */\n get body() {\n return this._body;\n }\n\n /**\n * Set the body of the `Notification` instance.\n *\n * @param {Object|null} body\n */\n set body(body) {\n this._body = body;\n }\n\n /**\n * Get the type of the `Notification` instance.\n *\n * @returns {string}\n */\n get type() {\n return this._type;\n }\n\n /**\n * Set the type of the `Notification` instance.\n *\n * @param {string} type\n */\n set type(type) {\n this._type = type;\n }\n\n /**\n * Get the string representation of the `Notification` instance.\n *\n * @returns {string}\n */\n toString() {\n let str= \"Notification Name: \" + this.name;\n str+= \"\\nBody:\" + ((this.body == null ) ? \"null\" : this.body.toString());\n str+= \"\\nType:\" + ((this.type == null ) ? \"null\" : this.type);\n return str;\n }\n\n}\nexport { Notification }\n","/*\n * Facade.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Controller} from \"../../core/Controller.js\";\nimport {Model} from \"../../core/Model.js\";\nimport {View} from \"../../core/View.js\";\nimport {Notification} from \"../observer/Notification.js\";\n\n/**\n * A base Multiton `Facade` implementation.\n *\n * @see Model Model\n * @see View View\n * @see Controller Controller\n *\n * @class Facade\n */\nclass Facade {\n\n /**\n * Constructor.\n *\n *

This `Facade` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Factory method,\n * passing the unique key for this instance\n * `Facade.getInstance( multitonKey )`

\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key has already been constructed\n */\n constructor(key) {\n if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG);\n this.initializeNotifier(key);\n Facade.instanceMap.set(this.multitonKey, this);\n this.initializeFacade();\n }\n\n /**\n * Initialize the Multiton `Facade` instance.\n *\n *

Called automatically by the constructor. Override in your\n * subclass to do any subclass specific initializations. Be\n * sure to call `super.initializeFacade()`, though.

\n */\n initializeFacade() {\n this.initializeModel();\n this.initializeController();\n this.initializeView();\n }\n\n /**\n * Facade Multiton Factory method\n *\n * @static\n * @param {string} key\n * @param {function(string):Facade} factory\n * @returns {Facade} the Multiton instance of the Facade\n */\n static getInstance(key, factory) {\n if (Facade.instanceMap == null)\n /** @static\n * @type {Map} */\n Facade.instanceMap = new Map();\n if (Facade.instanceMap.get(key) == null) Facade.instanceMap.set(key, factory(key));\n return Facade.instanceMap.get(key);\n }\n\n /**\n * Initialize the `Model`.\n *\n *

Called by the `initializeFacade` method.\n * Override this method in your subclass of `Facade`\n * if one or both of the following are true:

\n *\n *
    \n *
  • You wish to initialize a different `Model`.
  • \n *
  • You have `Proxy`s to register with the Model that do not\n * retrieve a reference to the Facade at construction time.`
  • \n *
\n *\n * If you don't want to initialize a different `Model`,\n * call `super.initializeModel()` at the beginning of your\n * method, then register `Proxy`s.\n *\n *

Note: This method is rarely overridden; in practice you are more\n * likely to use a `Command` to create and register `Proxy`s\n * with the `Model`, since `Proxy`s with mutable data will likely\n * need to send `Notification`s and thus will likely want to fetch a reference to\n * the `Facade` during their construction.

\n */\n initializeModel() {\n if (this.model != null) return;\n this.model = Model.getInstance(this.multitonKey, key => new Model(key));\n }\n\n /**\n * Initialize the `Controller`.\n *\n *

Called by the `initializeFacade` method.\n * Override this method in your subclass of `Facade`\n * if one or both of the following are true:

\n *\n *
    \n *
  • You wish to initialize a different `Controller`.
  • \n *
  • You have `Commands` to register with the `Controller` at startup.`.
  • \n *
\n *\n *

If you don't want to initialize a different `Controller`,\n * call `super.initializeController()` at the beginning of your\n * method, then register `Command`s.

\n */\n initializeController() {\n if (this.controller != null) return;\n this.controller = Controller.getInstance(this.multitonKey, key => new Controller(key));\n }\n\n /**\n * Initialize the `View`.\n *\n *

Called by the `initializeFacade` method.\n * Override this method in your subclass of `Facade`\n * if one or both of the following are true:

\n *\n *
    \n *
  • You wish to initialize a different `View`.
  • \n *
  • You have `Observers` to register with the `View`
  • \n *
\n *\n *

If you don't want to initialize a different `View`,\n * call `super.initializeView()` at the beginning of your\n * method, then register `Mediator` instances.

\n *\n *

Note: This method is rarely overridden; in practice you are more\n * likely to use a `Command` to create and register `Mediator`s\n * with the `View`, since `Mediator` instances will need to send\n * `Notification`s and thus will likely want to fetch a reference\n * to the `Facade` during their construction.

\n */\n initializeView() {\n if (this.view != null) return;\n this.view = View.getInstance(this.multitonKey, key => new View(key));\n }\n\n /**\n * Register a `Command` with the `Controller` by Notification name.\n *\n * @param {string} notificationName the name of the `Notification` to associate the `Command` with\n * @param {function():SimpleCommand} factory a reference to the factory of the `Command`\n */\n registerCommand(notificationName, factory) {\n this.controller.registerCommand(notificationName, factory);\n }\n\n /**\n * Check if a Command is registered for a given Notification\n *\n * @param {string} notificationName\n * @returns {boolean} whether a Command is currently registered for the given `notificationName`.\n */\n hasCommand(notificationName) {\n return this.controller.hasCommand(notificationName);\n }\n\n /**\n * Remove a previously registered `Command` to `Notification` mapping from the Controller.\n *\n * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for\n */\n removeCommand(notificationName) {\n this.controller.removeCommand(notificationName);\n }\n\n /**\n * Register a `Proxy` with the `Model` by name.\n *\n * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`.\n */\n registerProxy(proxy) {\n this.model.registerProxy(proxy);\n }\n\n /**\n * Remove a `Proxy` from the `Model` by name.\n *\n * @param {string} proxyName the `Proxy` to remove from the `Model`.\n * @returns {Proxy} the `Proxy` that was removed from the `Model`\n */\n removeProxy(proxyName) {\n return this.model.removeProxy(proxyName);\n }\n\n /**\n * Check if a `Proxy` is registered\n *\n * @param {string} proxyName\n * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`.\n */\n hasProxy(proxyName) {\n return this.model.hasProxy(proxyName);\n }\n\n /**\n * Retrieve a `Proxy` from the `Model` by name.\n *\n * @param {string} proxyName the name of the proxy to be retrieved.\n * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`.\n */\n retrieveProxy(proxyName) {\n return this.model.retrieveProxy(proxyName);\n }\n\n /**\n * Register a `Mediator` with the `View`.\n *\n * @param {Mediator} mediator a reference to the `Mediator`\n */\n registerMediator(mediator) {\n this.view.registerMediator(mediator);\n }\n\n /**\n * Remove a `Mediator` from the `View`.\n *\n * @param {string} mediatorName name of the `Mediator` to be removed.\n * @returns {Mediator} the `Mediator` that was removed from the `View`\n */\n removeMediator(mediatorName) {\n return this.view.removeMediator(mediatorName);\n }\n\n /**\n * Check if a `Mediator` is registered or not\n *\n * @param {string} mediatorName\n * @returns {boolean} whether a Mediator is registered with the given `mediatorName`.\n */\n hasMediator(mediatorName) {\n return this.view.hasMediator(mediatorName);\n }\n\n /**\n * Retrieve a `Mediator` from the `View`.\n *\n * @param {string} mediatorName\n * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`.\n */\n retrieveMediator(mediatorName) {\n return this.view.retrieveMediator(mediatorName);\n }\n\n /**\n * Create and send an `Notification`.\n *\n *

Keeps us from having to construct new notification\n * instances in our implementation code.

\n *\n * @param {string} notificationName the name of the notification to send\n * @param {Object} [body] body the body of the notification (optional)\n * @param {string} [type] type the type of the notification (optional)\n */\n sendNotification(notificationName, body = null, type = \"\") {\n this.notifyObservers(new Notification(notificationName, body, type));\n }\n\n /**\n * Notify `Observer`s.\n *\n *

This method is left public mostly for backward\n * compatibility, and to allow you to send custom\n * notification classes using the facade.

\n *\n *

Usually you should just call `sendNotification`\n * and pass the parameters, never having to\n * construct the notification yourself.

\n *\n * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of.\n */\n notifyObservers(notification) {\n this.view.notifyObservers(notification);\n }\n\n /**\n * Set the Multiton key for this facade instance.\n *\n *

Not called directly, but instead from the\n * constructor when getInstance is invoked.\n * It is necessary to be public in order to\n * implement Notifier.

\n */\n initializeNotifier(key) {\n this.multitonKey = key;\n }\n\n /**\n * Check if a Core is registered or not\n *\n * @static\n * @param {string} key the multiton key for the Core in question\n * @returns {boolean} whether a Core is registered with the given `key`.\n */\n static hasCore(key) {\n return this.instanceMap.has(key);\n }\n\n /**\n * Remove a Core.\n *\n *

Remove the Model, View, Controller and Facade\n * instances for the given key.

\n *\n * @static\n * @param {string} key multitonKey of the Core to remove\n */\n static removeCore(key) {\n if (Facade.instanceMap.get(key) == null) return;\n Model.removeModel(key);\n View.removeView(key);\n Controller.removeController(key);\n this.instanceMap.delete(key);\n }\n\n /**\n * Message Constants\n *\n * @static\n * @returns {string}\n */\n static get MULTITON_MSG() {return \"Facade instance for this Multiton key already constructed!\"};\n}\nexport { Facade }\n","/*\n * Notifier.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Facade} from \"../facade/Facade.js\";\n\n/**\n * A Base `Notifier` implementation.\n *\n *

`MacroCommand, Command, Mediator` and `Proxy`\n * all have a need to send `Notifications`.

\n *\n *

The `Notifier` interface provides a common method called\n * `sendNotification` that relieves implementation code of\n * the necessity to actually construct `Notifications`.

\n *\n *

The `Notifier` class, which all the above-mentioned classes\n * extend, provides an initialized reference to the `Facade`\n * Multiton, which is required for the convenience method\n * for sending `Notifications`, but also eases implementation as these\n * classes have frequent `Facade` interactions and usually require\n * access to the facade anyway.

\n *\n *

NOTE: In the MultiCore version of the framework, there is one caveat to\n * notifiers, they cannot send notifications or reach the facade until they\n * have a valid multitonKey.

\n *\n * The multitonKey is set:\n * * on a Command when it is executed by the Controller\n * * on a Mediator is registered with the View\n * * on a Proxy is registered with the Model.\n *\n * @see Proxy Proxy\n * @see Facade Facade\n * @see Mediator Mediator\n * @see MacroCommand MacroCommand\n * @see SimpleCommand SimpleCommand\n *\n * @class Notifier\n */\nclass Notifier {\n\n constructor() {}\n\n /**\n * Create and send an `Notification`.\n *\n *

Keeps us from having to construct new Notification\n * instances in our implementation code.

\n *\n * @param {string} notificationName\n * @param {Object} [body] body\n * @param {string} [type] type\n */\n sendNotification (notificationName, body = null, type = \"\") {\n if (this.facade != null) {\n this.facade.sendNotification(notificationName, body, type);\n }\n }\n\n /**\n * Initialize this Notifier instance.\n *\n *

This is how a Notifier gets its multitonKey.\n * Calls to sendNotification or to access the\n * facade will fail until after this method\n * has been called.

\n *\n *

Mediators, Commands or Proxies may override\n * this method in order to send notifications\n * or access the Multiton Facade instance as\n * soon as possible. They CANNOT access the facade\n * in their constructors, since this method will not\n * yet have been called.

\n *\n * @param {string} key the multitonKey for this Notifier to use\n */\n initializeNotifier(key) {\n this.multitonKey = key;\n }\n\n /**\n * Return the Multiton Facade instance\n *\n * @typedef {Facade} Facade\n *\n * @throws {Error}\n */\n get facade() {\n if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG);\n return Facade.getInstance(this.multitonKey, key => new Facade(key));\n }\n\n /**\n * Message Constants\n *\n * @static\n * @returns {string}\n */\n static get MULTITON_MSG() { return \"multitonKey for this Notifier not yet initialized!\" }\n}\nexport { Notifier }\n","/*\n * SimpleCommand.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Notifier} from \"../observer/Notifier.js\";\n\n/**\n * A base `Command` implementation.\n *\n *

Your subclass should override the `execute`\n * method where your business logic will handle the `Notification`.

\n *\n * @see Controller Controller\n * @see Notification Notification\n * @see MacroCommand MacroCommand\n *\n * @class SimpleCommand\n */\nclass SimpleCommand extends Notifier {\n\n constructor() {\n super();\n }\n\n /**\n * Fulfill the use-case initiated by the given `Notification`.\n *\n *

In the Command Pattern, an application use-case typically\n * begins with some user action, which results in a `Notification` being broadcast, which\n * is handled by business logic in the `execute` method of an\n * `Command`.

\n *\n * @param {Notification} notification\n */\n execute(notification) {\n\n }\n\n}\nexport { SimpleCommand }\n","/*\n * Mediator.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Notifier} from \"../observer/Notifier.js\";\n\n/**\n * A base `Mediator` implementation.\n *\n * @see View View\n *\n * @class Mediator\n */\nclass Mediator extends Notifier {\n\n /**\n * Constructor.\n *\n * @constructor\n * @param {string | null} [mediatorName=null]\n * @param {Object | null} [viewComponent=null]\n */\n constructor(mediatorName = null, viewComponent = null) {\n super();\n this._mediatorName = mediatorName || Mediator.NAME;\n this._viewComponent = viewComponent;\n }\n\n /**\n * Called by the View when the Mediator is registered\n */\n onRegister() {\n\n }\n\n /**\n * Called by the View when the Mediator is removed\n */\n onRemove() {\n\n }\n\n /**\n * List the `Notification` names this\n * `Mediator` is interested in being notified of.\n *\n * @returns {string[]}\n */\n listNotificationInterests() {\n return [];\n }\n\n /**\n * Handle `Notification`s.\n *\n *

\n * Typically this will be handled in a switch statement,\n * with one 'case' entry per `Notification`\n * the `Mediator` is interested in.\n *\n * @param {Notification} notification\n */\n handleNotification(notification) {\n\n }\n\n /**\n * the mediator name\n *\n * @returns {string}\n */\n get mediatorName() {\n return this._mediatorName;\n }\n\n /**\n * Get the `Mediator`'s view component.\n *\n *

\n * Additionally, an implicit getter will usually\n * be defined in the subclass that casts the view\n * object to a type, like this:

\n *\n * @returns {Object | null}\n */\n get viewComponent() {\n return this._viewComponent;\n }\n\n /**\n * Set the `Mediator`'s view component.\n *\n * @param {Object} viewComponent\n */\n set viewComponent(viewComponent) {\n this._viewComponent = viewComponent;\n }\n\n /**\n * The name of the `Mediator`.\n *\n *

Typically, a `Mediator` will be written to serve\n * one specific control or group controls and so,\n * will not have a need to be dynamically named.

\n *\n * @static\n * @returns {string}\n */\n static get NAME() { return \"Mediator\" }\n}\nexport { Mediator }\n","/*\n * Proxy.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Notifier} from \"../observer/Notifier.js\";\n\n/**\n * A base `Proxy` implementation.\n *\n *

In PureMVC, `Proxy` classes are used to manage parts of the\n * application's data model.

\n *\n *

A `Proxy` might simply manage a reference to a local data object,\n * in which case interacting with it might involve setting and\n * getting of its data in synchronous fashion.

\n *\n *

`Proxy` classes are also used to encapsulate the application's\n * interaction with remote services to save or retrieve data, in which case,\n * we adopt an asynchronous idiom; setting data (or calling a method) on the\n * `Proxy` and listening for a `Notification` to be sent\n * when the `Proxy` has retrieved the data from the service.

\n *\n * @see Model Model\n *\n * @class Proxy\n */\nclass Proxy extends Notifier {\n /**\n * Constructor\n *\n * @constructor\n * @param {string | null} [proxyName=null]\n * @param {Object | null} [data=null]\n */\n constructor(proxyName = null, data = null) {\n super();\n /** @protected\n * @type {string} */\n this._proxyName = proxyName || Proxy.NAME;\n /** @protected\n * @type {Object | null} */\n this._data = data;\n }\n\n /**\n * Called by the Model when the Proxy is registered\n */\n onRegister() {}\n\n /**\n * Called by the Model when the Proxy is removed\n */\n onRemove() {}\n\n /**\n * Get the proxy name\n *\n * @returns {string}\n */\n get proxyName() {\n return this._proxyName;\n }\n\n /**\n * Get the data object\n *\n * @returns {Object | null}\n */\n get data () {\n return this._data;\n }\n\n /**\n * Set the data object\n *\n * @param {Object} data\n */\n set data(data) {\n this._data = data;\n }\n\n /**\n *\n * @static\n * @returns {string}\n */\n static get NAME() { return \"Proxy\" }\n}\nexport { Proxy }\n","/*\n * MacroCommand.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {SimpleCommand} from \"./SimpleCommand.js\";\n\n/**\n * A base `Command` implementation that executes other `Command`s.\n *\n *

A `MacroCommand` maintains a list of\n * `Command` Class references called SubCommands.

\n *\n *

When `execute` is called, the `MacroCommand`\n * instantiates and calls `execute` on each of its SubCommands turn.\n * Each SubCommand will be passed a reference to the original\n * `Notification` that was passed to the `MacroCommand`'s\n * `execute` method.

\n *\n *

Unlike `SimpleCommand`, your subclass\n * should not override `execute`, but instead, should\n * override the `initializeMacroCommand` method,\n * calling `addSubCommand` once for each SubCommand\n * to be executed.

\n *\n * @see Controller Controller\n * @see Notification Notification\n * @see SimpleCommand SimpleCommand\n *\n * @class MacroCommand\n */\nclass MacroCommand extends SimpleCommand {\n\n /**\n * Constructor.\n *\n *

You should not need to define a constructor,\n * instead, override the `initializeMacroCommand`\n * method.

\n *\n *

If your subclass does define a constructor, be\n * sure to call `super()`.

\n *\n * @constructor\n */\n constructor() {\n super();\n /** @protected\n * @type {Array.} */\n this.subCommands = [];\n this.initializeMacroCommand();\n }\n\n /**\n * Initialize the `MacroCommand`.\n *\n *

In your subclass, override this method to\n * initialize the `MacroCommand`'s SubCommand\n * list with `Command` class references like\n * this:

\n *\n *
`\n     *\t\t// Initialize MyMacroCommand\n     *\t\tinitializeMacroCommand() {\n     *\t\t\tthis.addSubCommand(() => new app.FirstCommand());\n     *\t\t\tthis.addSubCommand(() => new app.SecondCommand());\n     *\t\t\tthis.addSubCommand(() => new app.ThirdCommand());\n     *\t\t}\n     * `
\n *\n *

Note that SubCommands may be any `Command` implementor,\n * `MacroCommand`s or `SimpleCommands` are both acceptable.\n */\n initializeMacroCommand() {\n\n }\n\n /**\n * Add a SubCommand.\n *\n *

The SubCommands will be called in First In/First Out (FIFO)\n * order.

\n *\n * @param {function():SimpleCommand} factory\n */\n addSubCommand(factory) {\n this.subCommands.push(factory);\n }\n\n /**\n * Execute this `MacroCommand`'s SubCommands.\n *\n *

The SubCommands will be called in First In/First Out (FIFO)\n * order.

\n *\n * @param {Notification} notification\n */\n execute(notification) {\n while(this.subCommands.length > 0) {\n let factory = this.subCommands.shift();\n let commandInstance = factory();\n commandInstance.initializeNotifier(this.multitonKey);\n commandInstance.execute(notification);\n }\n }\n\n}\nexport { MacroCommand }\n"],"names":["Observer","constructor","notify","context","this","_notifyMethod","_notifyContext","notifyObserver","notification","call","compareNotifyContext","notifyContext","notifyMethod","View","key","instanceMap","get","Error","MULTITON_MSG","multitonKey","set","mediatorMap","Map","observerMap","initializeView","getInstance","factory","registerObserver","notificationName","observer","push","Array","notifyObservers","has","name","observers","slice","i","length","removeObserver","splice","delete","registerMediator","mediator","mediatorName","initializeNotifier","interests","listNotificationInterests","handleNotification","bind","onRegister","retrieveMediator","removeMediator","onRemove","hasMediator","removeView","Controller","commandMap","initializeController","view","executeCommand","commandInstance","execute","registerCommand","hasCommand","removeCommand","removeController","Model","proxyMap","initializeModel","registerProxy","proxy","proxyName","retrieveProxy","hasProxy","removeProxy","removeModel","Notification","body","type","_name","_body","_type","toString","str","Facade","initializeFacade","model","controller","sendNotification","hasCore","removeCore","Notifier","facade","SimpleCommand","super","Mediator","viewComponent","_mediatorName","NAME","_viewComponent","Proxy","data","_proxyName","_data","subCommands","initializeMacroCommand","addSubCommand","shift"],"mappings":"aA0BA,MAAMA,EAWF,WAAAC,CAAYC,EAAS,KAAMC,EAAU,MACjCC,KAAKC,cAAgBH,EACrBE,KAAKE,eAAiBH,CACzB,CAOD,cAAAI,CAAeC,GACXJ,KAAKC,cAAcI,KAAKL,KAAKE,eAAgBE,EAChD,CAQD,oBAAAE,CAAqBC,GACjB,OAAOP,KAAKE,iBAAmBK,CAClC,CAOD,gBAAIC,GACA,OAAOR,KAAKC,aACf,CASD,gBAAIO,CAAaA,GACbR,KAAKC,cAAgBO,CACxB,CAOD,iBAAID,GACA,OAAOP,KAAKE,cACf,CAOD,iBAAIK,CAAcA,GACdP,KAAKE,eAAiBK,CACzB,EClEL,MAAME,EAeF,WAAAZ,CAAYa,GACR,GAAiC,MAA7BD,EAAKE,YAAYC,IAAIF,GAAc,MAAM,IAAIG,MAAMJ,EAAKK,cAG5Dd,KAAKe,YAAcL,EACnBD,EAAKE,YAAYK,IAAIhB,KAAKe,YAAaf,MAGvCA,KAAKiB,YAAc,IAAIC,IAGvBlB,KAAKmB,YAAc,IAAID,IACvBlB,KAAKoB,gBACR,CAUD,cAAAA,GAEC,CAUD,kBAAOC,CAAYX,EAAKY,GAMpB,OALwB,MAApBb,EAAKE,cAGLF,EAAKE,YAAc,IAAIO,KACM,MAA7BT,EAAKE,YAAYC,IAAIF,IAAcD,EAAKE,YAAYK,IAAIN,EAAKY,EAAQZ,IAClED,EAAKE,YAAYC,IAAIF,EAC/B,CASD,gBAAAa,CAAiBC,EAAkBC,GAC/B,GAA8C,MAA1CzB,KAAKmB,YAAYP,IAAIY,GAA2B,CAChCxB,KAAKmB,YAAYP,IAAIY,GAC3BE,KAAKD,EAC3B,MACYzB,KAAKmB,YAAYH,IAAIQ,EAAkB,IAAIG,MAAMF,GAExD,CAWD,eAAAG,CAAgBxB,GACZ,GAAIJ,KAAKmB,YAAYU,IAAIzB,EAAa0B,MAAO,CAGzC,IAAIC,EAAY/B,KAAKmB,YAAYP,IAAIR,EAAa0B,MAAME,QAGxD,IAAI,IAAIC,EAAI,EAAGA,EAAIF,EAAUG,OAAQD,IACjCF,EAAUE,GAAG9B,eAAeC,EAEnC,CACJ,CAQD,cAAA+B,CAAeX,EAAkBjB,GAE7B,IAAIwB,EAAY/B,KAAKmB,YAAYP,IAAIY,GAGrC,IAAK,IAAIS,EAAI,EAAGA,EAAIF,EAAUG,OAAQD,IAClC,IAAyD,IAArDF,EAAUE,GAAG3B,qBAAqBC,GAAyB,CAG3DwB,EAAUK,OAAOH,EAAG,GACpB,KACH,CAKoB,IAArBF,EAAUG,QACVlC,KAAKmB,YAAYkB,OAAOb,EAE/B,CAiBD,gBAAAc,CAAiBC,GAEb,IAAoD,IAAhDvC,KAAKiB,YAAYY,IAAIU,EAASC,cAAyB,OAE3DD,EAASE,mBAAmBzC,KAAKe,aAGjCf,KAAKiB,YAAYD,IAAIuB,EAASC,aAAcD,GAG5C,IAAIG,EAAYH,EAASI,4BAGzB,GAAID,EAAUR,OAAS,EAAG,CAEtB,IAAIT,EAAW,IAAI7B,EAAS2C,EAASK,mBAAmBC,KAAKN,GAAWA,GAGxE,IAAK,IAAIN,EAAI,EAAGA,EAAIS,EAAUR,OAAQD,IAClCjC,KAAKuB,iBAAiBmB,EAAUT,GAAIR,EAE3C,CAGDc,EAASO,YACZ,CAQD,gBAAAC,CAAiBP,GACb,OAAOxC,KAAKiB,YAAYL,IAAI4B,IAAiB,IAChD,CAQD,cAAAQ,CAAeR,GAEX,IAAID,EAAWvC,KAAKiB,YAAYL,IAAI4B,GAEpC,GAAID,EAAU,CAEV,IAAIG,EAAYH,EAASI,4BACzB,IAAK,IAAIV,EAAI,EAAGA,EAAIS,EAAUR,OAAQD,IAGlCjC,KAAKmC,eAAeO,EAAUT,GAAIM,GAItCvC,KAAKiB,YAAYoB,OAAOG,GAGxBD,EAASU,UACZ,CAED,OAAOV,CACV,CAQD,WAAAW,CAAYV,GACR,OAAOxC,KAAKiB,YAAYY,IAAIW,EAC/B,CAQD,iBAAOW,CAAWzC,GACdV,KAAKW,YAAY0B,OAAO3B,EAC3B,CAQD,uBAAWI,GAAiB,MAAO,0DAA4D,ECzNnG,MAAMsC,EAgBF,WAAAvD,CAAYa,GACR,GAAmC,MAA/B0C,EAAWzC,YAAYD,GAAc,MAAM,IAAIG,MAAMuC,EAAWtC,cAGpEd,KAAKe,YAAcL,EACnB0C,EAAWzC,YAAYK,IAAIhB,KAAKe,YAAaf,MAG7CA,KAAKqD,WAAa,IAAInC,IACtBlB,KAAKsD,sBACR,CAqBD,oBAAAA,GAGItD,KAAKuD,KAAO9C,EAAKY,YAAYrB,KAAKe,aAAcL,GAAQ,IAAID,EAAKC,IACpE,CAUD,kBAAOW,CAAYX,EAAKY,GAMpB,OAL8B,MAA1B8B,EAAWzC,cAGXyC,EAAWzC,YAAc,IAAIO,KACM,MAAnCkC,EAAWzC,YAAYC,IAAIF,IAAc0C,EAAWzC,YAAYK,IAAIN,EAAKY,EAAQZ,IAC9E0C,EAAWzC,YAAYC,IAAIF,EACrC,CAQD,cAAA8C,CAAepD,GACX,IAAIkB,EAAUtB,KAAKqD,WAAWzC,IAAIR,EAAa0B,MAC/C,GAAe,MAAXR,EAAiB,OAErB,IAAImC,EAAkBnC,IACtBmC,EAAgBhB,mBAAmBzC,KAAKe,aACxC0C,EAAgBC,QAAQtD,EAC3B,CAgBD,eAAAuD,CAAgBnC,EAAkBF,GACe,MAAzCtB,KAAKqD,WAAWzC,IAAIY,IACpBxB,KAAKuD,KAAKhC,iBAAiBC,EAAkB,IAAI5B,EAASI,KAAKwD,eAAgBxD,OAEnFA,KAAKqD,WAAWrC,IAAIQ,EAAkBF,EACzC,CAQD,UAAAsC,CAAWpC,GACP,OAAOxB,KAAKqD,WAAWxB,IAAIL,EAC9B,CAOD,aAAAqC,CAAcrC,GAEPxB,KAAK4D,WAAWpC,KAEfxB,KAAKuD,KAAKpB,eAAeX,EAAkBxB,MAG3CA,KAAKqD,WAAWhB,OAAOb,GAE9B,CAQD,uBAAOsC,CAAiBpD,GACpB0C,EAAWzC,YAAY0B,OAAO3B,EACjC,CAQD,uBAAWI,GAAiB,MAAO,gEAAkE,ECjKzG,MAAMiD,EAeF,WAAAlE,CAAYa,GACR,GAAkC,MAA9BqD,EAAMpD,YAAYC,IAAIF,GAAc,MAAM,IAAIG,MAAMkD,EAAMjD,cAG9Dd,KAAKe,YAAcL,EACnBqD,EAAMpD,YAAYK,IAAIhB,KAAKe,YAAaf,MAGxCA,KAAKgE,SAAW,IAAI9C,IACpBlB,KAAKiE,iBACR,CAWD,eAAAA,GAEC,CAUD,kBAAO5C,CAAYX,EAAKY,GAMpB,OALyB,MAArByC,EAAMpD,cAGNoD,EAAMpD,YAAc,IAAIO,KACM,MAA9B6C,EAAMpD,YAAYC,IAAIF,IAAcqD,EAAMpD,YAAYK,IAAIN,EAAKY,EAAQZ,IACpEqD,EAAMpD,YAAYC,IAAIF,EAChC,CAOD,aAAAwD,CAAcC,GACVA,EAAM1B,mBAAmBzC,KAAKe,aAC9Bf,KAAKgE,SAAShD,IAAImD,EAAMC,UAAWD,GACnCA,EAAMrB,YACT,CAQD,aAAAuB,CAAcD,GACV,OAAOpE,KAAKgE,SAASpD,IAAIwD,IAAc,IAC1C,CAQD,QAAAE,CAASF,GACL,OAAOpE,KAAKgE,SAASnC,IAAIuC,EAC5B,CAQD,WAAAG,CAAYH,GACR,IAAID,EAAQnE,KAAKgE,SAASpD,IAAIwD,GAK9B,OAJa,MAATD,IACAnE,KAAKgE,SAAS3B,OAAO+B,GACrBD,EAAMlB,YAEHkB,CACV,CAQD,kBAAOK,CAAY9D,GACfqD,EAAMpD,YAAY0B,OAAO3B,EAC5B,CAMD,uBAAWI,GAAiB,MAAO,2DAA6D,EC/GpG,MAAM2D,EAUF,WAAA5E,CAAYiC,EAAM4C,EAAO,KAAMC,EAAO,IAClC3E,KAAK4E,MAAQ9C,EACb9B,KAAK6E,MAAQH,EACb1E,KAAK8E,MAAQH,CAChB,CAOD,QAAI7C,GACA,OAAO9B,KAAK4E,KACf,CAOD,QAAIF,GACA,OAAO1E,KAAK6E,KACf,CAOD,QAAIH,CAAKA,GACL1E,KAAK6E,MAAQH,CAChB,CAOD,QAAIC,GACA,OAAO3E,KAAK8E,KACf,CAOD,QAAIH,CAAKA,GACL3E,KAAK8E,MAAQH,CAChB,CAOD,QAAAI,GACI,IAAIC,EAAK,sBAAwBhF,KAAK8B,KAGtC,OAFAkD,GAAM,WAA2B,MAAbhF,KAAK0E,KAAiB,OAAS1E,KAAK0E,KAAKK,YAC7DC,GAAM,WAA2B,MAAbhF,KAAK2E,KAAiB,OAAS3E,KAAK2E,MACjDK,CACV,ECvFL,MAAMC,EAgBF,WAAApF,CAAYa,GACR,GAA+B,MAA3BuE,EAAOtE,YAAYD,GAAc,MAAM,IAAIG,MAAMoE,EAAOnE,cAC5Dd,KAAKyC,mBAAmB/B,GACxBuE,EAAOtE,YAAYK,IAAIhB,KAAKe,YAAaf,MACzCA,KAAKkF,kBACR,CASD,gBAAAA,GACIlF,KAAKiE,kBACLjE,KAAKsD,uBACLtD,KAAKoB,gBACR,CAUD,kBAAOC,CAAYX,EAAKY,GAMpB,OAL0B,MAAtB2D,EAAOtE,cAGPsE,EAAOtE,YAAc,IAAIO,KACM,MAA/B+D,EAAOtE,YAAYC,IAAIF,IAAcuE,EAAOtE,YAAYK,IAAIN,EAAKY,EAAQZ,IACtEuE,EAAOtE,YAAYC,IAAIF,EACjC,CAyBD,eAAAuD,GACsB,MAAdjE,KAAKmF,QACTnF,KAAKmF,MAAQpB,EAAM1C,YAAYrB,KAAKe,aAAaL,GAAO,IAAIqD,EAAMrD,KACrE,CAkBD,oBAAA4C,GAC2B,MAAnBtD,KAAKoF,aACTpF,KAAKoF,WAAahC,EAAW/B,YAAYrB,KAAKe,aAAaL,GAAO,IAAI0C,EAAW1C,KACpF,CAwBD,cAAAU,GACqB,MAAbpB,KAAKuD,OACTvD,KAAKuD,KAAO9C,EAAKY,YAAYrB,KAAKe,aAAaL,GAAO,IAAID,EAAKC,KAClE,CAQD,eAAAiD,CAAgBnC,EAAkBF,GAC9BtB,KAAKoF,WAAWzB,gBAAgBnC,EAAkBF,EACrD,CAQD,UAAAsC,CAAWpC,GACP,OAAOxB,KAAKoF,WAAWxB,WAAWpC,EACrC,CAOD,aAAAqC,CAAcrC,GACVxB,KAAKoF,WAAWvB,cAAcrC,EACjC,CAOD,aAAA0C,CAAcC,GACVnE,KAAKmF,MAAMjB,cAAcC,EAC5B,CAQD,WAAAI,CAAYH,GACR,OAAOpE,KAAKmF,MAAMZ,YAAYH,EACjC,CAQD,QAAAE,CAASF,GACL,OAAOpE,KAAKmF,MAAMb,SAASF,EAC9B,CAQD,aAAAC,CAAcD,GACV,OAAOpE,KAAKmF,MAAMd,cAAcD,EACnC,CAOD,gBAAA9B,CAAiBC,GACbvC,KAAKuD,KAAKjB,iBAAiBC,EAC9B,CAQD,cAAAS,CAAeR,GACX,OAAOxC,KAAKuD,KAAKP,eAAeR,EACnC,CAQD,WAAAU,CAAYV,GACR,OAAOxC,KAAKuD,KAAKL,YAAYV,EAChC,CAQD,gBAAAO,CAAiBP,GACb,OAAOxC,KAAKuD,KAAKR,iBAAiBP,EACrC,CAYD,gBAAA6C,CAAiB7D,EAAkBkD,EAAO,KAAMC,EAAO,IACnD3E,KAAK4B,gBAAgB,IAAI6C,EAAajD,EAAkBkD,EAAMC,GACjE,CAeD,eAAA/C,CAAgBxB,GACZJ,KAAKuD,KAAK3B,gBAAgBxB,EAC7B,CAUD,kBAAAqC,CAAmB/B,GACfV,KAAKe,YAAcL,CACtB,CASD,cAAO4E,CAAQ5E,GACX,OAAOV,KAAKW,YAAYkB,IAAInB,EAC/B,CAWD,iBAAO6E,CAAW7E,GACqB,MAA/BuE,EAAOtE,YAAYC,IAAIF,KAC3BqD,EAAMS,YAAY9D,GAClBD,EAAK0C,WAAWzC,GAChB0C,EAAWU,iBAAiBpD,GAC5BV,KAAKW,YAAY0B,OAAO3B,GAC3B,CAQD,uBAAWI,GAAgB,MAAO,4DAA4D,ECnSlG,MAAM0E,EAEF,WAAA3F,GAAgB,CAYhB,gBAAAwF,CAAkB7D,EAAkBkD,EAAO,KAAMC,EAAO,IACjC,MAAf3E,KAAKyF,QACLzF,KAAKyF,OAAOJ,iBAAiB7D,EAAkBkD,EAAMC,EAE5D,CAmBD,kBAAAlC,CAAmB/B,GACfV,KAAKe,YAAcL,CACtB,CASD,UAAI+E,GACA,GAAwB,MAApBzF,KAAKe,YAAqB,MAAM,IAAIF,MAAM2E,EAAS1E,cACvD,OAAOmE,EAAO5D,YAAYrB,KAAKe,aAAaL,GAAO,IAAIuE,EAAOvE,IACjE,CAQD,uBAAWI,GAAiB,MAAO,oDAAsD,ECjF7F,MAAM4E,UAAsBF,EAExB,WAAA3F,GACI8F,OACH,CAYD,OAAAjC,CAAQtD,GAEP,ECvBL,MAAMwF,UAAiBJ,EASnB,WAAA3F,CAAY2C,EAAe,KAAMqD,EAAgB,MAC7CF,QACA3F,KAAK8F,cAAgBtD,GAAgBoD,EAASG,KAC9C/F,KAAKgG,eAAiBH,CACzB,CAKD,UAAA/C,GAEC,CAKD,QAAAG,GAEC,CAQD,yBAAAN,GACI,MAAO,EACV,CAYD,kBAAAC,CAAmBxC,GAElB,CAOD,gBAAIoC,GACA,OAAOxC,KAAK8F,aACf,CAYD,iBAAID,GACA,OAAO7F,KAAKgG,cACf,CAOD,iBAAIH,CAAcA,GACd7F,KAAKgG,eAAiBH,CACzB,CAYD,eAAWE,GAAS,MAAO,UAAY,EClF3C,MAAME,UAAcT,EAQhB,WAAA3F,CAAYuE,EAAY,KAAM8B,EAAO,MACjCP,QAGA3F,KAAKmG,WAAa/B,GAAa6B,EAAMF,KAGrC/F,KAAKoG,MAAQF,CAChB,CAKD,UAAApD,GAAe,CAKf,QAAAG,GAAa,CAOb,aAAImB,GACA,OAAOpE,KAAKmG,UACf,CAOD,QAAID,GACA,OAAOlG,KAAKoG,KACf,CAOD,QAAIF,CAAKA,GACLlG,KAAKoG,MAAQF,CAChB,CAOD,eAAWH,GAAS,MAAO,OAAS,6DCxDxC,cAA2BL,EAcvB,WAAA7F,GACI8F,QAGA3F,KAAKqG,YAAc,GACnBrG,KAAKsG,wBACR,CAsBD,sBAAAA,GAEC,CAUD,aAAAC,CAAcjF,GACVtB,KAAKqG,YAAY3E,KAAKJ,EACzB,CAUD,OAAAoC,CAAQtD,GACJ,KAAMJ,KAAKqG,YAAYnE,OAAS,GAAG,CAC/B,IACIuB,EADUzD,KAAKqG,YAAYG,OACTlF,GACtBmC,EAAgBhB,mBAAmBzC,KAAKe,aACxC0C,EAAgBC,QAAQtD,EAC3B,CACJ"} \ No newline at end of file diff --git a/bin/esm/index.js b/bin/esm/index.js deleted file mode 100644 index 6e1013c..0000000 --- a/bin/esm/index.js +++ /dev/null @@ -1,1624 +0,0 @@ -/* - * Observer.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - -/** - * A base `Observer` implementation. - * - *

An `Observer` is an object that encapsulates information - * about an interested object with a method that should - * be called when a particular `Notification` is broadcast.

- * - *

In PureMVC, the `Observer` class assumes these responsibilities:

- * - *
    - *
  • Encapsulate the notification (callback) method of the interested object.
  • - *
  • Encapsulate the notification context (this) of the interested object.
  • - *
  • Provide methods for setting the notification method and context.
  • - *
  • Provide a method for notifying the interested object.
  • - *
- * - * @class Observer - */ -class Observer { - - /** - * Constructor. - * - *

The notification method on the interested object should take - * one parameter of type `Notification`

- * - * @param {function(Notification):void | null} [notify = null] - * @param {Object | null} [context = null] - */ - constructor(notify = null, context = null) { - this._notifyMethod = notify; - this._notifyContext = context; - } - - /** - * Notify the interested object. - * - * @param {Notification} notification - */ - notifyObserver(notification) { - this._notifyMethod.call(this._notifyContext, notification); - } - - /** - * Compare an object to the notification context. - * - * @param {Object} notifyContext - * @returns {boolean} - */ - compareNotifyContext(notifyContext) { - return this._notifyContext === notifyContext; - } - - /** - * Get the notification method. - * - * @returns {function(Notification):void} - */ - get notifyMethod() { - return this._notifyMethod - } - - /** - * Set the notification method. - * - *

The notification method should take one parameter of type `Notification`.

- * - * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received. - */ - set notifyMethod(notifyMethod) { - this._notifyMethod = notifyMethod; - } - - /** - * Get the notifyContext - * - * @returns {Object} - */ - get notifyContext() { - return this._notifyContext; - } - - /** - * Set the notification context. - * - * @param {Object} notifyContext - */ - set notifyContext(notifyContext) { - this._notifyContext = notifyContext; - } - -} - -/* - * View.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A Multiton `View` implementation. - * - *

In PureMVC, the `View` class assumes these responsibilities:

- * - *
    - *
  • Maintain a cache of `Mediator` instances.
  • - *
  • Provide methods for registering, retrieving, and removing `Mediators`.
  • - *
  • Notifying `Mediators` when they are registered or removed.
  • - *
  • Managing the observer lists for each `Notification` in the application.
  • - *
  • Providing a method for attaching `Observers` to a `Notification`'s observer list.
  • - *
  • Providing a method for broadcasting a `Notification`.
  • - *
  • Notifying the `Observers` of a given `Notification` when it broadcast.
  • - *
- * - * @see Mediator Mediator - * @see Observer Observer - * @see Notification Notification - * - * @class View - */ -class View { - - /** - * Constructor. - * - *

This `View` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `View.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - View.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.mediatorMap = new Map(); - /** @protected - * @type {Map.>} */ - this.observerMap = new Map(); - this.initializeView(); - } - - /** - *

Initialize the Multiton View instance.

- * - *

Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.

- */ - initializeView() { - - } - - /** - * View Multiton factory method. - * - * @static - * @param {string} key - * @param {function(string):View} factory - * @returns {View} the Multiton instance of `View` - */ - static getInstance(key, factory) { - if (View.instanceMap == null) - /** @static - * @type {Map} */ - View.instanceMap = new Map(); - if (View.instanceMap.get(key) == null) View.instanceMap.set(key, factory(key)); - return View.instanceMap.get(key); - } - - /** - *

Register an `Observer` to be notified - * of `Notifications` with a given name.

- * - * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of - * @param {Observer} observer the `Observer` to register - */ - registerObserver(notificationName, observer) { - if (this.observerMap.get(notificationName) != null) { - let observers = this.observerMap.get(notificationName); - observers.push(observer); - } else { - this.observerMap.set(notificationName, new Array(observer)); - } - } - - /** - *

Notify the `Observers` for a particular `Notification`.

- * - *

All previously attached `Observers` for this `Notification`'s - * list are notified and are passed a reference to the `Notification` in - * the order in which they were registered.

- * - * @param {Notification} notification the `Notification` to notify `Observers` of. - */ - notifyObservers(notification) { - if (this.observerMap.has(notification.name)) { - // Copy observers from reference array to working array, - // since the reference array may change during the notification loop - let observers = this.observerMap.get(notification.name).slice(); - - // Notify Observers from the working array - for(let i = 0; i < observers.length; i++) { - observers[i].notifyObserver(notification); - } - } - } - - /** - *

Remove the observer for a given notifyContext from an observer list for a given Notification name.

- * - * @param {string} notificationName which observer list to remove from - * @param {Object} notifyContext remove the observer with this object as its notifyContext - */ - removeObserver(notificationName, notifyContext) { - // the observer list for the notification under inspection - let observers = this.observerMap.get(notificationName); - - // find the observer for the notifyContext - for (let i = 0; i < observers.length; i++) { - if (observers[i].compareNotifyContext(notifyContext) === true) { - // there can only be one Observer for a given notifyContext - // in any given Observer list, so remove it and break - observers.splice(i, 1); - break; - } - } - - // Also, when a Notification's Observer list length falls to - // zero, delete the notification key from the observer map - if (observers.length === 0) { - this.observerMap.delete(notificationName); - } - } - - /** - * Register a `Mediator` instance with the `View`. - * - *

Registers the `Mediator` so that it can be retrieved by name, - * and further interrogates the `Mediator` for its - * `Notification` interests.

- * - *

If the `Mediator` returns any `Notification` - * names to be notified about, an `Observer` is created encapsulating - * the `Mediator` instance's `handleNotification` method - * and registering it as an `Observer` for all `Notifications` the - * `Mediator` is interested in.

- * - * @param {Mediator} mediator a reference to the `Mediator` instance - */ - registerMediator(mediator) { - // do not allow re-registration (you must to removeMediator fist) - if (this.mediatorMap.has(mediator.mediatorName) !== false) return; - - mediator.initializeNotifier(this.multitonKey); - - // Register the Mediator for retrieval by name - this.mediatorMap.set(mediator.mediatorName, mediator); - - // Get Notification interests, if any. - let interests = mediator.listNotificationInterests(); - - // Register Mediator as an observer for each notification of interests - if (interests.length > 0) { - // Create Observer referencing this mediator's handleNotification method - let observer = new Observer(mediator.handleNotification.bind(mediator), mediator); // check bind - - // Register Mediator as Observer for its list of Notification interests - for (let i = 0; i < interests.length; i++) { - this.registerObserver(interests[i], observer); - } - } - - // alert the mediator that it has been registered - mediator.onRegister(); - } - - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName the name of the `Mediator` instance to retrieve. - * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.mediatorMap.get(mediatorName) || null; - } - - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` instance to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - // Retrieve the named mediator - let mediator = this.mediatorMap.get(mediatorName); - - if (mediator) { - // for every notification this mediator is interested in... - let interests = mediator.listNotificationInterests(); - for (let i = 0; i < interests.length; i++) { - // remove the observer linking the mediator - // to the notification interest - this.removeObserver(interests[i], mediator); - } - - // remove the mediator from the map - this.mediatorMap.delete(mediatorName); - - // alert the mediator that it has been removed - mediator.onRemove(); - } - - return mediator; - } - - /** - * Check if a Mediator is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.mediatorMap.has(mediatorName); - } - - /** - * Remove a View instance - * - * @static - * @param key multitonKey of View instance to remove - */ - static removeView(key) { - this.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "View instance for this Multiton key already constructed!" }; - -} - -/* - * Controller.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A Multiton `Controller` implementation. - * - *

In PureMVC, the `Controller` class follows the - * 'Command and Controller' strategy, and assumes these - * responsibilities:

- * - *
    - *
  • Remembering which `Command`s - * are intended to handle which `Notifications`.
  • - *
  • Registering itself as an `Observer` with - * the `View` for each `Notification` - * that it has a `Command` mapping for.
  • - *
  • Creating a new instance of the proper `Command` - * to handle a given `Notification` when notified by the `View`.
  • - *
  • Calling the `Command`'s `execute` - * method, passing in the `Notification`.
  • - *
- * - *

Your application must register `Commands` with the - * Controller.

- * - *

The simplest way is to subclass `Facade`, - * and use its `initializeController` method to add your - * registrations.

- * - * @see View View - * @see Observer Observer - * @see Notification Notification - * @see SimpleCommand SimpleCommand - * @see MacroCommand MacroCommand - * - * @class Controller - */ -class Controller { - - /** - * Constructor. - * - *

This `Controller` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Controller.getInstance( multitonKey )`

- * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Controller.instanceMap[key] != null) throw new Error(Controller.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Controller.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.commandMap = new Map(); - this.initializeController(); - } - - /** - * Initialize the Multiton `Controller` instance. - * - *

Called automatically by the constructor.

- * - *

Note that if you are using a subclass of `View` - * in your application, you should also subclass `Controller` - * and override the `initializeController` method in the - * following way:

- * - *
`
-     *		// ensure that the Controller is talking to my View implementation
-     *		initializeController( )
-     *		{
-     *			this.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key));
-     *		}
-     * `
- * - */ - initializeController() { - /** @protected - * @type {View} **/ - this.view = View.getInstance(this.multitonKey, (key) => new View(key)); - } - - /** - * `Controller` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Controller} factory - * @returns {Controller} the Multiton instance of `Controller` - */ - static getInstance(key, factory) { - if (Controller.instanceMap == null) - /** @static - @type {Map} */ - Controller.instanceMap = new Map(); - if (Controller.instanceMap.get(key) == null) Controller.instanceMap.set(key, factory(key)); - return Controller.instanceMap.get(key); - } - - /** - *

If a `Command` has previously been registered - * to handle the given `Notification`, then it is executed.

- * - * @param {Notification} notification a `Notification` - */ - executeCommand(notification) { - let factory = this.commandMap.get(notification.name); - if (factory == null) return; - - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } - - /** - *

Register a particular `Command` class as the handler - * for a particular `Notification`.

- * - *

If an `Command` has already been registered to - * handle `Notification`s with this name, it is no longer - * used, the new `Command` is used instead.

- * - *

The Observer for the new Command is only created if this the - * first time a Command has been registered for this Notification name.

- * - * @param notificationName the name of the `Notification` - * @param {function():SimpleCommand} factory - */ - registerCommand(notificationName, factory) { - if (this.commandMap.get(notificationName) == null) { - this.view.registerObserver(notificationName, new Observer(this.executeCommand, this)); - } - this.commandMap.set(notificationName, factory); - } - - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @return {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.commandMap.has(notificationName); - } - - /** - * Remove a previously registered `Command` to `Notification` mapping. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - // if the Command is registered... - if(this.hasCommand(notificationName)) { - // remove the observer - this.view.removeObserver(notificationName, this); - - // remove the command - this.commandMap.delete(notificationName); - } - } - - /** - * Remove a Controller instance - * - * @static - * @param {string} key of Controller instance to remove - */ - static removeController(key) { - Controller.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Controller instance for this Multiton key already constructed!" }; -} - -/* - * Model.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - -/** - * A Multiton `Model` implementation. - * - *

In PureMVC, the `Model` class provides - * access to model objects (Proxies) by named lookup. - * - *

The `Model` assumes these responsibilities:

- * - *
    - *
  • Maintain a cache of `Proxy` instances.
  • - *
  • Provide methods for registering, retrieving, and removing - * `Proxy` instances.
  • - *
- * - *

Your application must register `Proxy` instances - * with the `Model`. Typically, you use an - * `Command` to create and register `Proxy` - * instances once the `Facade` has initialized the Core - * actors.

- * - * @see Proxy Proxy - * - * @class Model - */ -class Model { - - /** - * Constructor. - * - *

This `Model` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `Model.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key instance has already been constructed - */ - constructor(key) { - if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Model.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.proxyMap = new Map(); - this.initializeModel(); - } - - /** - * Initialize the `Model` instance. - * - *

Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.

- * - */ - initializeModel() { - - } - - /** - * `Model` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Model} factory - * @returns {Model} the instance for this Multiton key - */ - static getInstance(key, factory) { - if (Model.instanceMap == null) - /** @static - @type {Map} */ - Model.instanceMap = new Map(); - if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key)); - return Model.instanceMap.get(key); - } - - /** - * Register a `Proxy` with the `Model`. - * - * @param {Proxy} proxy a `Proxy` to be held by the `Model`. - */ - registerProxy(proxy) { - proxy.initializeNotifier(this.multitonKey); - this.proxyMap.set(proxy.proxyName, proxy); - proxy.onRegister(); - } - - /** - * Retrieve a `Proxy` from the `Model`. - * - * @param {string} proxyName - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.proxyMap.get(proxyName) || null; - } - - /** - * Check if a Proxy is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.proxyMap.has(proxyName); - } - - /** - * Remove a `Proxy` from the `Model`. - * - * @param {string} proxyName name of the `Proxy` instance to be removed. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - let proxy = this.proxyMap.get(proxyName); - if (proxy != null) { - this.proxyMap.delete(proxyName); - proxy.onRemove(); - } - return proxy; - } - - /** - * Remove a Model instance - * - * @static - * @param key - */ - static removeModel(key) { - Model.instanceMap.delete(key); - } - - /** - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Model instance for this Multiton key already constructed!" }; -} - -/* - * Notification.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - -/** - * A base `Notification` implementation. - * - *

PureMVC does not rely upon underlying event models such - * as the one provided with Flash, and ActionScript 3 does - * not have an inherent event model.

- * - *

The Observer Pattern as implemented within PureMVC exists - * to support event-driven communication between the - * application and the actors of the MVC triad.

- * - *

Notifications are not meant to be a replacement for Events - * in Flex/Flash/Apollo. Generally, `Mediator` implementors - * place event listeners on their view components, which they - * then handle in the usual way. This may lead to the broadcast of `Notification`s to - * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command` - * instances communicate with each other and `Mediator`s - * by broadcasting `Notification`s.

- * - *

A key difference between Flash `Event`s and PureMVC - * `Notification`s is that `Event`s follow the - * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy - * until some parent component handles the `Event`, while - * PureMVC `Notification`s follow a 'Publish/Subscribe' - * pattern. PureMVC classes need not be related to each other in a - * parent/child relationship in order to communicate with one another - * using `Notification`s.

- * - * @class Notification - */ -class Notification { - - /** - * Constructor. - * - * @constructor - * @param {string} name - The name of the notification. - * @param {Object|null} [body=null] - The body of the notification, defaults to `null`. - * @param {string} [type=""] - The type of the notification, defaults to an empty string. - */ - constructor(name, body = null, type = "") { - this._name = name; - this._body = body; - this._type = type; - } - - /** - * Get the name of the `Notification` instance. - * - * @returns {string} - */ - get name() { - return this._name; - } - - /** - * Get the body of the `Notification` instance. - * - * @returns {Object | null} - */ - get body() { - return this._body; - } - - /** - * Set the body of the `Notification` instance. - * - * @param {Object|null} body - */ - set body(body) { - this._body = body; - } - - /** - * Get the type of the `Notification` instance. - * - * @returns {string} - */ - get type() { - return this._type; - } - - /** - * Set the type of the `Notification` instance. - * - * @param {string} type - */ - set type(type) { - this._type = type; - } - - /** - * Get the string representation of the `Notification` instance. - * - * @returns {string} - */ - toString() { - let str= "Notification Name: " + this.name; - str+= "\nBody:" + ((this.body == null ) ? "null" : this.body.toString()); - str+= "\nType:" + ((this.type == null ) ? "null" : this.type); - return str; - } - -} - -/* - * Facade.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base Multiton `Facade` implementation. - * - * @see Model Model - * @see View View - * @see Controller Controller - * - * @class Facade - */ -class Facade { - - /** - * Constructor. - * - *

This `Facade` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Facade.getInstance( multitonKey )`

- * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG); - this.initializeNotifier(key); - Facade.instanceMap.set(this.multitonKey, this); - this.initializeFacade(); - } - - /** - * Initialize the Multiton `Facade` instance. - * - *

Called automatically by the constructor. Override in your - * subclass to do any subclass specific initializations. Be - * sure to call `super.initializeFacade()`, though.

- */ - initializeFacade() { - this.initializeModel(); - this.initializeController(); - this.initializeView(); - } - - /** - * Facade Multiton Factory method - * - * @static - * @param {string} key - * @param {function(string):Facade} factory - * @returns {Facade} the Multiton instance of the Facade - */ - static getInstance(key, factory) { - if (Facade.instanceMap == null) - /** @static - * @type {Map} */ - Facade.instanceMap = new Map(); - if (Facade.instanceMap.get(key) == null) Facade.instanceMap.set(key, factory(key)); - return Facade.instanceMap.get(key); - } - - /** - * Initialize the `Model`. - * - *

Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

- * - *
    - *
  • You wish to initialize a different `Model`.
  • - *
  • You have `Proxy`s to register with the Model that do not - * retrieve a reference to the Facade at construction time.`
  • - *
- * - * If you don't want to initialize a different `Model`, - * call `super.initializeModel()` at the beginning of your - * method, then register `Proxy`s. - * - *

Note: This method is rarely overridden; in practice you are more - * likely to use a `Command` to create and register `Proxy`s - * with the `Model`, since `Proxy`s with mutable data will likely - * need to send `Notification`s and thus will likely want to fetch a reference to - * the `Facade` during their construction.

- */ - initializeModel() { - if (this.model != null) return; - this.model = Model.getInstance(this.multitonKey, key => new Model(key)); - } - - /** - * Initialize the `Controller`. - * - *

Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

- * - *
    - *
  • You wish to initialize a different `Controller`.
  • - *
  • You have `Commands` to register with the `Controller` at startup.`.
  • - *
- * - *

If you don't want to initialize a different `Controller`, - * call `super.initializeController()` at the beginning of your - * method, then register `Command`s.

- */ - initializeController() { - if (this.controller != null) return; - this.controller = Controller.getInstance(this.multitonKey, key => new Controller(key)); - } - - /** - * Initialize the `View`. - * - *

Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

- * - *
    - *
  • You wish to initialize a different `View`.
  • - *
  • You have `Observers` to register with the `View`
  • - *
- * - *

If you don't want to initialize a different `View`, - * call `super.initializeView()` at the beginning of your - * method, then register `Mediator` instances.

- * - *

Note: This method is rarely overridden; in practice you are more - * likely to use a `Command` to create and register `Mediator`s - * with the `View`, since `Mediator` instances will need to send - * `Notification`s and thus will likely want to fetch a reference - * to the `Facade` during their construction.

- */ - initializeView() { - if (this.view != null) return; - this.view = View.getInstance(this.multitonKey, key => new View(key)); - } - - /** - * Register a `Command` with the `Controller` by Notification name. - * - * @param {string} notificationName the name of the `Notification` to associate the `Command` with - * @param {function():SimpleCommand} factory a reference to the factory of the `Command` - */ - registerCommand(notificationName, factory) { - this.controller.registerCommand(notificationName, factory); - } - - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @returns {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.controller.hasCommand(notificationName); - } - - /** - * Remove a previously registered `Command` to `Notification` mapping from the Controller. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - this.controller.removeCommand(notificationName); - } - - /** - * Register a `Proxy` with the `Model` by name. - * - * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`. - */ - registerProxy(proxy) { - this.model.registerProxy(proxy); - } - - /** - * Remove a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the `Proxy` to remove from the `Model`. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - return this.model.removeProxy(proxyName); - } - - /** - * Check if a `Proxy` is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.model.hasProxy(proxyName); - } - - /** - * Retrieve a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the name of the proxy to be retrieved. - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.model.retrieveProxy(proxyName); - } - - /** - * Register a `Mediator` with the `View`. - * - * @param {Mediator} mediator a reference to the `Mediator` - */ - registerMediator(mediator) { - this.view.registerMediator(mediator); - } - - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - return this.view.removeMediator(mediatorName); - } - - /** - * Check if a `Mediator` is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.view.hasMediator(mediatorName); - } - - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName - * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.view.retrieveMediator(mediatorName); - } - - /** - * Create and send an `Notification`. - * - *

Keeps us from having to construct new notification - * instances in our implementation code.

- * - * @param {string} notificationName the name of the notification to send - * @param {Object} [body] body the body of the notification (optional) - * @param {string} [type] type the type of the notification (optional) - */ - sendNotification(notificationName, body = null, type = "") { - this.notifyObservers(new Notification(notificationName, body, type)); - } - - /** - * Notify `Observer`s. - * - *

This method is left public mostly for backward - * compatibility, and to allow you to send custom - * notification classes using the facade.

- * - *

Usually you should just call `sendNotification` - * and pass the parameters, never having to - * construct the notification yourself.

- * - * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of. - */ - notifyObservers(notification) { - this.view.notifyObservers(notification); - } - - /** - * Set the Multiton key for this facade instance. - * - *

Not called directly, but instead from the - * constructor when getInstance is invoked. - * It is necessary to be public in order to - * implement Notifier.

- */ - initializeNotifier(key) { - this.multitonKey = key; - } - - /** - * Check if a Core is registered or not - * - * @static - * @param {string} key the multiton key for the Core in question - * @returns {boolean} whether a Core is registered with the given `key`. - */ - static hasCore(key) { - return this.instanceMap.has(key); - } - - /** - * Remove a Core. - * - *

Remove the Model, View, Controller and Facade - * instances for the given key.

- * - * @static - * @param {string} key multitonKey of the Core to remove - */ - static removeCore(key) { - if (Facade.instanceMap.get(key) == null) return; - Model.removeModel(key); - View.removeView(key); - Controller.removeController(key); - this.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() {return "Facade instance for this Multiton key already constructed!"}; -} - -/* - * Notifier.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A Base `Notifier` implementation. - * - *

`MacroCommand, Command, Mediator` and `Proxy` - * all have a need to send `Notifications`.

- * - *

The `Notifier` interface provides a common method called - * `sendNotification` that relieves implementation code of - * the necessity to actually construct `Notifications`.

- * - *

The `Notifier` class, which all the above-mentioned classes - * extend, provides an initialized reference to the `Facade` - * Multiton, which is required for the convenience method - * for sending `Notifications`, but also eases implementation as these - * classes have frequent `Facade` interactions and usually require - * access to the facade anyway.

- * - *

NOTE: In the MultiCore version of the framework, there is one caveat to - * notifiers, they cannot send notifications or reach the facade until they - * have a valid multitonKey.

- * - * The multitonKey is set: - * * on a Command when it is executed by the Controller - * * on a Mediator is registered with the View - * * on a Proxy is registered with the Model. - * - * @see Proxy Proxy - * @see Facade Facade - * @see Mediator Mediator - * @see MacroCommand MacroCommand - * @see SimpleCommand SimpleCommand - * - * @class Notifier - */ -class Notifier { - - constructor() {} - - /** - * Create and send an `Notification`. - * - *

Keeps us from having to construct new Notification - * instances in our implementation code.

- * - * @param {string} notificationName - * @param {Object} [body] body - * @param {string} [type] type - */ - sendNotification (notificationName, body = null, type = "") { - if (this.facade != null) { - this.facade.sendNotification(notificationName, body, type); - } - } - - /** - * Initialize this Notifier instance. - * - *

This is how a Notifier gets its multitonKey. - * Calls to sendNotification or to access the - * facade will fail until after this method - * has been called.

- * - *

Mediators, Commands or Proxies may override - * this method in order to send notifications - * or access the Multiton Facade instance as - * soon as possible. They CANNOT access the facade - * in their constructors, since this method will not - * yet have been called.

- * - * @param {string} key the multitonKey for this Notifier to use - */ - initializeNotifier(key) { - this.multitonKey = key; - } - - /** - * Return the Multiton Facade instance - * - * @typedef {Facade} Facade - * - * @throws {Error} - */ - get facade() { - if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG); - return Facade.getInstance(this.multitonKey, key => new Facade(key)); - } - - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() { return "multitonKey for this Notifier not yet initialized!" } -} - -/* - * SimpleCommand.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Command` implementation. - * - *

Your subclass should override the `execute` - * method where your business logic will handle the `Notification`.

- * - * @see Controller Controller - * @see Notification Notification - * @see MacroCommand MacroCommand - * - * @class SimpleCommand - */ -class SimpleCommand extends Notifier { - - constructor() { - super(); - } - - /** - * Fulfill the use-case initiated by the given `Notification`. - * - *

In the Command Pattern, an application use-case typically - * begins with some user action, which results in a `Notification` being broadcast, which - * is handled by business logic in the `execute` method of an - * `Command`.

- * - * @param {Notification} notification - */ - execute(notification) { - - } - -} - -/* - * MacroCommand.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Command` implementation that executes other `Command`s. - * - *

A `MacroCommand` maintains a list of - * `Command` Class references called SubCommands.

- * - *

When `execute` is called, the `MacroCommand` - * instantiates and calls `execute` on each of its SubCommands turn. - * Each SubCommand will be passed a reference to the original - * `Notification` that was passed to the `MacroCommand`'s - * `execute` method.

- * - *

Unlike `SimpleCommand`, your subclass - * should not override `execute`, but instead, should - * override the `initializeMacroCommand` method, - * calling `addSubCommand` once for each SubCommand - * to be executed.

- * - * @see Controller Controller - * @see Notification Notification - * @see SimpleCommand SimpleCommand - * - * @class MacroCommand - */ -class MacroCommand extends SimpleCommand { - - /** - * Constructor. - * - *

You should not need to define a constructor, - * instead, override the `initializeMacroCommand` - * method.

- * - *

If your subclass does define a constructor, be - * sure to call `super()`.

- * - * @constructor - */ - constructor() { - super(); - /** @protected - * @type {Array.} */ - this.subCommands = []; - this.initializeMacroCommand(); - } - - /** - * Initialize the `MacroCommand`. - * - *

In your subclass, override this method to - * initialize the `MacroCommand`'s SubCommand - * list with `Command` class references like - * this:

- * - *
`
-     *		// Initialize MyMacroCommand
-     *		initializeMacroCommand() {
-     *			this.addSubCommand(() => new app.FirstCommand());
-     *			this.addSubCommand(() => new app.SecondCommand());
-     *			this.addSubCommand(() => new app.ThirdCommand());
-     *		}
-     * `
- * - *

Note that SubCommands may be any `Command` implementor, - * `MacroCommand`s or `SimpleCommands` are both acceptable. - */ - initializeMacroCommand() { - - } - - /** - * Add a SubCommand. - * - *

The SubCommands will be called in First In/First Out (FIFO) - * order.

- * - * @param {function():SimpleCommand} factory - */ - addSubCommand(factory) { - this.subCommands.push(factory); - } - - /** - * Execute this `MacroCommand`'s SubCommands. - * - *

The SubCommands will be called in First In/First Out (FIFO) - * order.

- * - * @param {Notification} notification - */ - execute(notification) { - while(this.subCommands.length > 0) { - let factory = this.subCommands.shift(); - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } - } - -} - -/* - * Mediator.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Mediator` implementation. - * - * @see View View - * - * @class Mediator - */ -class Mediator extends Notifier { - - /** - * Constructor. - * - * @constructor - * @param {string | null} [mediatorName=null] - * @param {Object | null} [viewComponent=null] - */ - constructor(mediatorName = null, viewComponent = null) { - super(); - this._mediatorName = mediatorName || Mediator.NAME; - this._viewComponent = viewComponent; - } - - /** - * Called by the View when the Mediator is registered - */ - onRegister() { - - } - - /** - * Called by the View when the Mediator is removed - */ - onRemove() { - - } - - /** - * List the `Notification` names this - * `Mediator` is interested in being notified of. - * - * @returns {string[]} - */ - listNotificationInterests() { - return []; - } - - /** - * Handle `Notification`s. - * - *

- * Typically this will be handled in a switch statement, - * with one 'case' entry per `Notification` - * the `Mediator` is interested in. - * - * @param {Notification} notification - */ - handleNotification(notification) { - - } - - /** - * the mediator name - * - * @returns {string} - */ - get mediatorName() { - return this._mediatorName; - } - - /** - * Get the `Mediator`'s view component. - * - *

- * Additionally, an implicit getter will usually - * be defined in the subclass that casts the view - * object to a type, like this:

- * - * @returns {Object | null} - */ - get viewComponent() { - return this._viewComponent; - } - - /** - * Set the `Mediator`'s view component. - * - * @param {Object} viewComponent - */ - set viewComponent(viewComponent) { - this._viewComponent = viewComponent; - } - - /** - * The name of the `Mediator`. - * - *

Typically, a `Mediator` will be written to serve - * one specific control or group controls and so, - * will not have a need to be dynamically named.

- * - * @static - * @returns {string} - */ - static get NAME() { return "Mediator" } -} - -/* - * Proxy.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -/** - * A base `Proxy` implementation. - * - *

In PureMVC, `Proxy` classes are used to manage parts of the - * application's data model.

- * - *

A `Proxy` might simply manage a reference to a local data object, - * in which case interacting with it might involve setting and - * getting of its data in synchronous fashion.

- * - *

`Proxy` classes are also used to encapsulate the application's - * interaction with remote services to save or retrieve data, in which case, - * we adopt an asynchronous idiom; setting data (or calling a method) on the - * `Proxy` and listening for a `Notification` to be sent - * when the `Proxy` has retrieved the data from the service.

- * - * @see Model Model - * - * @class Proxy - */ -class Proxy extends Notifier { - /** - * Constructor - * - * @constructor - * @param {string | null} [proxyName=null] - * @param {Object | null} [data=null] - */ - constructor(proxyName = null, data = null) { - super(); - /** @protected - * @type {string} */ - this._proxyName = proxyName || Proxy.NAME; - /** @protected - * @type {Object | null} */ - this._data = data; - } - - /** - * Called by the Model when the Proxy is registered - */ - onRegister() {} - - /** - * Called by the Model when the Proxy is removed - */ - onRemove() {} - - /** - * Get the proxy name - * - * @returns {string} - */ - get proxyName() { - return this._proxyName; - } - - /** - * Get the data object - * - * @returns {Object | null} - */ - get data () { - return this._data; - } - - /** - * Set the data object - * - * @param {Object} data - */ - set data(data) { - this._data = data; - } - - /** - * - * @static - * @returns {string} - */ - static get NAME() { return "Proxy" } -} - -export { Controller, Facade, MacroCommand, Mediator, Model, Notification, Notifier, Observer, Proxy, SimpleCommand, View }; diff --git a/bin/esm/index.min.js b/bin/esm/index.min.js deleted file mode 100644 index 02b3b0d..0000000 --- a/bin/esm/index.min.js +++ /dev/null @@ -1,2 +0,0 @@ -class t{constructor(t=null,e=null){this._notifyMethod=t,this._notifyContext=e}notifyObserver(t){this._notifyMethod.call(this._notifyContext,t)}compareNotifyContext(t){return this._notifyContext===t}get notifyMethod(){return this._notifyMethod}set notifyMethod(t){this._notifyMethod=t}get notifyContext(){return this._notifyContext}set notifyContext(t){this._notifyContext=t}}class e{constructor(t){if(null!=e.instanceMap.get(t))throw new Error(e.MULTITON_MSG);this.multitonKey=t,e.instanceMap.set(this.multitonKey,this),this.mediatorMap=new Map,this.observerMap=new Map,this.initializeView()}initializeView(){}static getInstance(t,i){return null==e.instanceMap&&(e.instanceMap=new Map),null==e.instanceMap.get(t)&&e.instanceMap.set(t,i(t)),e.instanceMap.get(t)}registerObserver(t,e){if(null!=this.observerMap.get(t)){this.observerMap.get(t).push(e)}else this.observerMap.set(t,new Array(e))}notifyObservers(t){if(this.observerMap.has(t.name)){let e=this.observerMap.get(t.name).slice();for(let i=0;i0){let n=new t(e.handleNotification.bind(e),e);for(let t=0;tnew e(t)))}static getInstance(t,e){return null==i.instanceMap&&(i.instanceMap=new Map),null==i.instanceMap.get(t)&&i.instanceMap.set(t,e(t)),i.instanceMap.get(t)}executeCommand(t){let e=this.commandMap.get(t.name);if(null==e)return;let i=e();i.initializeNotifier(this.multitonKey),i.execute(t)}registerCommand(e,i){null==this.commandMap.get(e)&&this.view.registerObserver(e,new t(this.executeCommand,this)),this.commandMap.set(e,i)}hasCommand(t){return this.commandMap.has(t)}removeCommand(t){this.hasCommand(t)&&(this.view.removeObserver(t,this),this.commandMap.delete(t))}static removeController(t){i.instanceMap.delete(t)}static get MULTITON_MSG(){return"Controller instance for this Multiton key already constructed!"}}class n{constructor(t){if(null!=n.instanceMap.get(t))throw new Error(n.MULTITON_MSG);this.multitonKey=t,n.instanceMap.set(this.multitonKey,this),this.proxyMap=new Map,this.initializeModel()}initializeModel(){}static getInstance(t,e){return null==n.instanceMap&&(n.instanceMap=new Map),null==n.instanceMap.get(t)&&n.instanceMap.set(t,e(t)),n.instanceMap.get(t)}registerProxy(t){t.initializeNotifier(this.multitonKey),this.proxyMap.set(t.proxyName,t),t.onRegister()}retrieveProxy(t){return this.proxyMap.get(t)||null}hasProxy(t){return this.proxyMap.has(t)}removeProxy(t){let e=this.proxyMap.get(t);return null!=e&&(this.proxyMap.delete(t),e.onRemove()),e}static removeModel(t){n.instanceMap.delete(t)}static get MULTITON_MSG(){return"Model instance for this Multiton key already constructed!"}}class s{constructor(t,e=null,i=""){this._name=t,this._body=e,this._type=i}get name(){return this._name}get body(){return this._body}set body(t){this._body=t}get type(){return this._type}set type(t){this._type=t}toString(){let t="Notification Name: "+this.name;return t+="\nBody:"+(null==this.body?"null":this.body.toString()),t+="\nType:"+(null==this.type?"null":this.type),t}}class r{constructor(t){if(null!=r.instanceMap[t])throw new Error(r.MULTITON_MSG);this.initializeNotifier(t),r.instanceMap.set(this.multitonKey,this),this.initializeFacade()}initializeFacade(){this.initializeModel(),this.initializeController(),this.initializeView()}static getInstance(t,e){return null==r.instanceMap&&(r.instanceMap=new Map),null==r.instanceMap.get(t)&&r.instanceMap.set(t,e(t)),r.instanceMap.get(t)}initializeModel(){null==this.model&&(this.model=n.getInstance(this.multitonKey,(t=>new n(t))))}initializeController(){null==this.controller&&(this.controller=i.getInstance(this.multitonKey,(t=>new i(t))))}initializeView(){null==this.view&&(this.view=e.getInstance(this.multitonKey,(t=>new e(t))))}registerCommand(t,e){this.controller.registerCommand(t,e)}hasCommand(t){return this.controller.hasCommand(t)}removeCommand(t){this.controller.removeCommand(t)}registerProxy(t){this.model.registerProxy(t)}removeProxy(t){return this.model.removeProxy(t)}hasProxy(t){return this.model.hasProxy(t)}retrieveProxy(t){return this.model.retrieveProxy(t)}registerMediator(t){this.view.registerMediator(t)}removeMediator(t){return this.view.removeMediator(t)}hasMediator(t){return this.view.hasMediator(t)}retrieveMediator(t){return this.view.retrieveMediator(t)}sendNotification(t,e=null,i=""){this.notifyObservers(new s(t,e,i))}notifyObservers(t){this.view.notifyObservers(t)}initializeNotifier(t){this.multitonKey=t}static hasCore(t){return this.instanceMap.has(t)}static removeCore(t){null!=r.instanceMap.get(t)&&(n.removeModel(t),e.removeView(t),i.removeController(t),this.instanceMap.delete(t))}static get MULTITON_MSG(){return"Facade instance for this Multiton key already constructed!"}}class o{constructor(){}sendNotification(t,e=null,i=""){null!=this.facade&&this.facade.sendNotification(t,e,i)}initializeNotifier(t){this.multitonKey=t}get facade(){if(null==this.multitonKey)throw new Error(o.MULTITON_MSG);return r.getInstance(this.multitonKey,(t=>new r(t)))}static get MULTITON_MSG(){return"multitonKey for this Notifier not yet initialized!"}}class a extends o{constructor(){super()}execute(t){}}class l extends a{constructor(){super(),this.subCommands=[],this.initializeMacroCommand()}initializeMacroCommand(){}addSubCommand(t){this.subCommands.push(t)}execute(t){for(;this.subCommands.length>0;){let e=this.subCommands.shift()();e.initializeNotifier(this.multitonKey),e.execute(t)}}}class h extends o{constructor(t=null,e=null){super(),this._mediatorName=t||h.NAME,this._viewComponent=e}onRegister(){}onRemove(){}listNotificationInterests(){return[]}handleNotification(t){}get mediatorName(){return this._mediatorName}get viewComponent(){return this._viewComponent}set viewComponent(t){this._viewComponent=t}static get NAME(){return"Mediator"}}class c extends o{constructor(t=null,e=null){super(),this._proxyName=t||c.NAME,this._data=e}onRegister(){}onRemove(){}get proxyName(){return this._proxyName}get data(){return this._data}set data(t){this._data=t}static get NAME(){return"Proxy"}}export{i as Controller,r as Facade,l as MacroCommand,h as Mediator,n as Model,s as Notification,o as Notifier,t as Observer,c as Proxy,a as SimpleCommand,e as View}; -//# sourceMappingURL=index.min.js.map diff --git a/bin/esm/index.min.js.map b/bin/esm/index.min.js.map deleted file mode 100644 index cf6946e..0000000 --- a/bin/esm/index.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.min.js","sources":["../../src/patterns/observer/Observer.js","../../src/core/View.js","../../src/core/Controller.js","../../src/core/Model.js","../../src/patterns/observer/Notification.js","../../src/patterns/facade/Facade.js","../../src/patterns/observer/Notifier.js","../../src/patterns/command/SimpleCommand.js","../../src/patterns/command/MacroCommand.js","../../src/patterns/mediator/Mediator.js","../../src/patterns/proxy/Proxy.js"],"sourcesContent":["/*\n * Observer.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\n/**\n * A base `Observer` implementation.\n *\n *

An `Observer` is an object that encapsulates information\n * about an interested object with a method that should\n * be called when a particular `Notification` is broadcast.

\n *\n *

In PureMVC, the `Observer` class assumes these responsibilities:

\n *\n *
    \n *
  • Encapsulate the notification (callback) method of the interested object.
  • \n *
  • Encapsulate the notification context (this) of the interested object.
  • \n *
  • Provide methods for setting the notification method and context.
  • \n *
  • Provide a method for notifying the interested object.
  • \n *
\n *\n * @class Observer\n */\nclass Observer {\n\n /**\n * Constructor.\n *\n *

The notification method on the interested object should take\n * one parameter of type `Notification`

\n *\n * @param {function(Notification):void | null} [notify = null]\n * @param {Object | null} [context = null]\n */\n constructor(notify = null, context = null) {\n this._notifyMethod = notify;\n this._notifyContext = context;\n }\n\n /**\n * Notify the interested object.\n *\n * @param {Notification} notification\n */\n notifyObserver(notification) {\n this._notifyMethod.call(this._notifyContext, notification);\n }\n\n /**\n * Compare an object to the notification context.\n *\n * @param {Object} notifyContext\n * @returns {boolean}\n */\n compareNotifyContext(notifyContext) {\n return this._notifyContext === notifyContext;\n }\n\n /**\n * Get the notification method.\n *\n * @returns {function(Notification):void}\n */\n get notifyMethod() {\n return this._notifyMethod\n }\n\n /**\n * Set the notification method.\n *\n *

The notification method should take one parameter of type `Notification`.

\n *\n * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received.\n */\n set notifyMethod(notifyMethod) {\n this._notifyMethod = notifyMethod;\n }\n\n /**\n * Get the notifyContext\n *\n * @returns {Object}\n */\n get notifyContext() {\n return this._notifyContext;\n }\n\n /**\n * Set the notification context.\n *\n * @param {Object} notifyContext\n */\n set notifyContext(notifyContext) {\n this._notifyContext = notifyContext;\n }\n\n}\nexport { Observer }\n","/*\n * View.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Observer} from \"../patterns/observer/Observer.js\";\n\n/**\n * A Multiton `View` implementation.\n *\n *

In PureMVC, the `View` class assumes these responsibilities:

\n *\n *
    \n *
  • Maintain a cache of `Mediator` instances.
  • \n *
  • Provide methods for registering, retrieving, and removing `Mediators`.
  • \n *
  • Notifying `Mediators` when they are registered or removed.
  • \n *
  • Managing the observer lists for each `Notification` in the application.
  • \n *
  • Providing a method for attaching `Observers` to a `Notification`'s observer list.
  • \n *
  • Providing a method for broadcasting a `Notification`.
  • \n *
  • Notifying the `Observers` of a given `Notification` when it broadcast.
  • \n *
\n *\n * @see Mediator Mediator\n * @see Observer Observer\n * @see Notification Notification\n *\n * @class View\n */\nclass View {\n\n /**\n * Constructor.\n *\n *

This `View` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Multiton\n * Factory method `View.getInstance( multitonKey )`\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key has already been constructed\n */\n constructor(key) {\n if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG);\n /** @protected\n * @type {string} */\n this.multitonKey = key;\n View.instanceMap.set(this.multitonKey, this);\n /** @protected\n * @type {Map} */\n this.mediatorMap = new Map();\n /** @protected\n * @type {Map.>} */\n this.observerMap = new Map();\n this.initializeView();\n }\n\n /**\n *

Initialize the Multiton View instance.

\n *\n *

Called automatically by the constructor, this\n * is your opportunity to initialize the Multiton\n * instance in your subclass without overriding the\n * constructor.

\n */\n initializeView() {\n\n }\n\n /**\n * View Multiton factory method.\n *\n * @static\n * @param {string} key\n * @param {function(string):View} factory\n * @returns {View} the Multiton instance of `View`\n */\n static getInstance(key, factory) {\n if (View.instanceMap == null)\n /** @static\n * @type {Map} */\n View.instanceMap = new Map();\n if (View.instanceMap.get(key) == null) View.instanceMap.set(key, factory(key));\n return View.instanceMap.get(key);\n }\n\n /**\n *

Register an `Observer` to be notified\n * of `Notifications` with a given name.

\n *\n * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of\n * @param {Observer} observer the `Observer` to register\n */\n registerObserver(notificationName, observer) {\n if (this.observerMap.get(notificationName) != null) {\n let observers = this.observerMap.get(notificationName);\n observers.push(observer);\n } else {\n this.observerMap.set(notificationName, new Array(observer));\n }\n }\n\n /**\n *

Notify the `Observers` for a particular `Notification`.

\n *\n *

All previously attached `Observers` for this `Notification`'s\n * list are notified and are passed a reference to the `Notification` in\n * the order in which they were registered.

\n *\n * @param {Notification} notification the `Notification` to notify `Observers` of.\n */\n notifyObservers(notification) {\n if (this.observerMap.has(notification.name)) {\n // Copy observers from reference array to working array,\n // since the reference array may change during the notification loop\n let observers = this.observerMap.get(notification.name).slice();\n\n // Notify Observers from the working array\n for(let i = 0; i < observers.length; i++) {\n observers[i].notifyObserver(notification);\n }\n }\n }\n\n /**\n *

Remove the observer for a given notifyContext from an observer list for a given Notification name.

\n *\n * @param {string} notificationName which observer list to remove from\n * @param {Object} notifyContext remove the observer with this object as its notifyContext\n */\n removeObserver(notificationName, notifyContext) {\n // the observer list for the notification under inspection\n let observers = this.observerMap.get(notificationName);\n\n // find the observer for the notifyContext\n for (let i = 0; i < observers.length; i++) {\n if (observers[i].compareNotifyContext(notifyContext) === true) {\n // there can only be one Observer for a given notifyContext\n // in any given Observer list, so remove it and break\n observers.splice(i, 1);\n break;\n }\n }\n\n // Also, when a Notification's Observer list length falls to\n // zero, delete the notification key from the observer map\n if (observers.length === 0) {\n this.observerMap.delete(notificationName);\n }\n }\n\n /**\n * Register a `Mediator` instance with the `View`.\n *\n *

Registers the `Mediator` so that it can be retrieved by name,\n * and further interrogates the `Mediator` for its\n * `Notification` interests.

\n *\n *

If the `Mediator` returns any `Notification`\n * names to be notified about, an `Observer` is created encapsulating\n * the `Mediator` instance's `handleNotification` method\n * and registering it as an `Observer` for all `Notifications` the\n * `Mediator` is interested in.

\n *\n * @param {Mediator} mediator a reference to the `Mediator` instance\n */\n registerMediator(mediator) {\n // do not allow re-registration (you must to removeMediator fist)\n if (this.mediatorMap.has(mediator.mediatorName) !== false) return;\n\n mediator.initializeNotifier(this.multitonKey);\n\n // Register the Mediator for retrieval by name\n this.mediatorMap.set(mediator.mediatorName, mediator);\n\n // Get Notification interests, if any.\n let interests = mediator.listNotificationInterests();\n\n // Register Mediator as an observer for each notification of interests\n if (interests.length > 0) {\n // Create Observer referencing this mediator's handleNotification method\n let observer = new Observer(mediator.handleNotification.bind(mediator), mediator); // check bind\n\n // Register Mediator as Observer for its list of Notification interests\n for (let i = 0; i < interests.length; i++) {\n this.registerObserver(interests[i], observer);\n }\n }\n\n // alert the mediator that it has been registered\n mediator.onRegister();\n }\n\n /**\n * Retrieve a `Mediator` from the `View`.\n *\n * @param {string} mediatorName the name of the `Mediator` instance to retrieve.\n * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`.\n */\n retrieveMediator(mediatorName) {\n return this.mediatorMap.get(mediatorName) || null;\n }\n\n /**\n * Remove a `Mediator` from the `View`.\n *\n * @param {string} mediatorName name of the `Mediator` instance to be removed.\n * @returns {Mediator} the `Mediator` that was removed from the `View`\n */\n removeMediator(mediatorName) {\n // Retrieve the named mediator\n let mediator = this.mediatorMap.get(mediatorName);\n\n if (mediator) {\n // for every notification this mediator is interested in...\n let interests = mediator.listNotificationInterests();\n for (let i = 0; i < interests.length; i++) {\n // remove the observer linking the mediator\n // to the notification interest\n this.removeObserver(interests[i], mediator);\n }\n\n // remove the mediator from the map\n this.mediatorMap.delete(mediatorName);\n\n // alert the mediator that it has been removed\n mediator.onRemove();\n }\n\n return mediator;\n }\n\n /**\n * Check if a Mediator is registered or not\n *\n * @param {string} mediatorName\n * @returns {boolean} whether a Mediator is registered with the given `mediatorName`.\n */\n hasMediator(mediatorName) {\n return this.mediatorMap.has(mediatorName);\n }\n\n /**\n * Remove a View instance\n *\n * @static\n * @param key multitonKey of View instance to remove\n */\n static removeView(key) {\n this.instanceMap.delete(key);\n }\n\n /**\n * Message Constants\n *\n * @static\n * @type {string}\n */\n static get MULTITON_MSG() { return \"View instance for this Multiton key already constructed!\" };\n\n}\nexport { View }\n","/*\n * Controller.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {View} from \"./View.js\"\nimport {Observer} from \"../patterns/observer/Observer.js\";\n\n/**\n * A Multiton `Controller` implementation.\n *\n *

In PureMVC, the `Controller` class follows the\n * 'Command and Controller' strategy, and assumes these\n * responsibilities:

\n *\n *
    \n *
  • Remembering which `Command`s\n * are intended to handle which `Notifications`.
  • \n *
  • Registering itself as an `Observer` with\n * the `View` for each `Notification`\n * that it has a `Command` mapping for.
  • \n *
  • Creating a new instance of the proper `Command`\n * to handle a given `Notification` when notified by the `View`.
  • \n *
  • Calling the `Command`'s `execute`\n * method, passing in the `Notification`.
  • \n *
\n *\n *

Your application must register `Commands` with the\n * Controller.

\n *\n *

The simplest way is to subclass `Facade`,\n * and use its `initializeController` method to add your\n * registrations.

\n *\n * @see View View\n * @see Observer Observer\n * @see Notification Notification\n * @see SimpleCommand SimpleCommand\n * @see MacroCommand MacroCommand\n *\n * @class Controller\n */\nclass Controller {\n\n /**\n * Constructor.\n *\n *

This `Controller` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Factory method,\n * passing the unique key for this instance\n * `Controller.getInstance( multitonKey )`

\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key has already been constructed\n */\n constructor(key) {\n if (Controller.instanceMap[key] != null) throw new Error(Controller.MULTITON_MSG);\n /** @protected\n * @type {string} */\n this.multitonKey = key;\n Controller.instanceMap.set(this.multitonKey, this);\n /** @protected\n * @type {Map} */\n this.commandMap = new Map();\n this.initializeController();\n }\n\n /**\n * Initialize the Multiton `Controller` instance.\n *\n *

Called automatically by the constructor.

\n *\n *

Note that if you are using a subclass of `View`\n * in your application, you should also subclass `Controller`\n * and override the `initializeController` method in the\n * following way:

\n *\n *
`\n     *\t\t// ensure that the Controller is talking to my View implementation\n     *\t\tinitializeController( )\n     *\t\t{\n     *\t\t\tthis.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key));\n     *\t\t}\n     * `
\n *\n */\n initializeController() {\n /** @protected\n * @type {View} **/\n this.view = View.getInstance(this.multitonKey, (key) => new View(key));\n }\n\n /**\n * `Controller` Multiton Factory method.\n *\n * @static\n * @param {string} key\n * @param {function(string):Controller} factory\n * @returns {Controller} the Multiton instance of `Controller`\n */\n static getInstance(key, factory) {\n if (Controller.instanceMap == null)\n /** @static\n @type {Map} */\n Controller.instanceMap = new Map();\n if (Controller.instanceMap.get(key) == null) Controller.instanceMap.set(key, factory(key));\n return Controller.instanceMap.get(key);\n }\n\n /**\n *

If a `Command` has previously been registered\n * to handle the given `Notification`, then it is executed.

\n *\n * @param {Notification} notification a `Notification`\n */\n executeCommand(notification) {\n let factory = this.commandMap.get(notification.name);\n if (factory == null) return;\n\n let commandInstance = factory();\n commandInstance.initializeNotifier(this.multitonKey);\n commandInstance.execute(notification);\n }\n\n /**\n *

Register a particular `Command` class as the handler\n * for a particular `Notification`.

\n *\n *

If an `Command` has already been registered to\n * handle `Notification`s with this name, it is no longer\n * used, the new `Command` is used instead.

\n *\n *

The Observer for the new Command is only created if this the\n * first time a Command has been registered for this Notification name.

\n *\n * @param notificationName the name of the `Notification`\n * @param {function():SimpleCommand} factory\n */\n registerCommand(notificationName, factory) {\n if (this.commandMap.get(notificationName) == null) {\n this.view.registerObserver(notificationName, new Observer(this.executeCommand, this));\n }\n this.commandMap.set(notificationName, factory);\n }\n\n /**\n * Check if a Command is registered for a given Notification\n *\n * @param {string} notificationName\n * @return {boolean} whether a Command is currently registered for the given `notificationName`.\n */\n hasCommand(notificationName) {\n return this.commandMap.has(notificationName);\n }\n\n /**\n * Remove a previously registered `Command` to `Notification` mapping.\n *\n * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for\n */\n removeCommand(notificationName) {\n // if the Command is registered...\n if(this.hasCommand(notificationName)) {\n // remove the observer\n this.view.removeObserver(notificationName, this);\n\n // remove the command\n this.commandMap.delete(notificationName)\n }\n }\n\n /**\n * Remove a Controller instance\n *\n * @static\n * @param {string} key of Controller instance to remove\n */\n static removeController(key) {\n Controller.instanceMap.delete(key);\n }\n\n /**\n * Message Constants\n *\n * @static\n * @type {string}\n */\n static get MULTITON_MSG() { return \"Controller instance for this Multiton key already constructed!\" };\n}\nexport { Controller }\n","/*\n * Model.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\n/**\n * A Multiton `Model` implementation.\n *\n *

In PureMVC, the `Model` class provides\n * access to model objects (Proxies) by named lookup.\n *\n *

The `Model` assumes these responsibilities:

\n *\n *
    \n *
  • Maintain a cache of `Proxy` instances.
  • \n *
  • Provide methods for registering, retrieving, and removing\n * `Proxy` instances.
  • \n *
\n *\n *

Your application must register `Proxy` instances\n * with the `Model`. Typically, you use an\n * `Command` to create and register `Proxy`\n * instances once the `Facade` has initialized the Core\n * actors.

\n *\n * @see Proxy Proxy\n *\n * @class Model\n */\nclass Model {\n\n /**\n * Constructor.\n *\n *

This `Model` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Multiton\n * Factory method `Model.getInstance( multitonKey )`\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key instance has already been constructed\n */\n constructor(key) {\n if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG);\n /** @protected\n * @type {string} */\n this.multitonKey = key;\n Model.instanceMap.set(this.multitonKey, this);\n /** @protected\n * @type {Map} */\n this.proxyMap = new Map();\n this.initializeModel();\n }\n\n /**\n * Initialize the `Model` instance.\n *\n *

Called automatically by the constructor, this\n * is your opportunity to initialize the Multiton\n * instance in your subclass without overriding the\n * constructor.

\n *\n */\n initializeModel() {\n\n }\n\n /**\n * `Model` Multiton Factory method.\n *\n * @static\n * @param {string} key\n * @param {function(string):Model} factory\n * @returns {Model} the instance for this Multiton key\n */\n static getInstance(key, factory) {\n if (Model.instanceMap == null)\n /** @static\n @type {Map} */\n Model.instanceMap = new Map();\n if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key));\n return Model.instanceMap.get(key);\n }\n\n /**\n * Register a `Proxy` with the `Model`.\n *\n * @param {Proxy} proxy a `Proxy` to be held by the `Model`.\n */\n registerProxy(proxy) {\n proxy.initializeNotifier(this.multitonKey);\n this.proxyMap.set(proxy.proxyName, proxy);\n proxy.onRegister();\n }\n\n /**\n * Retrieve a `Proxy` from the `Model`.\n *\n * @param {string} proxyName\n * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`.\n */\n retrieveProxy(proxyName) {\n return this.proxyMap.get(proxyName) || null;\n }\n\n /**\n * Check if a Proxy is registered\n *\n * @param {string} proxyName\n * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`.\n */\n hasProxy(proxyName) {\n return this.proxyMap.has(proxyName);\n }\n\n /**\n * Remove a `Proxy` from the `Model`.\n *\n * @param {string} proxyName name of the `Proxy` instance to be removed.\n * @returns {Proxy} the `Proxy` that was removed from the `Model`\n */\n removeProxy(proxyName) {\n let proxy = this.proxyMap.get(proxyName);\n if (proxy != null) {\n this.proxyMap.delete(proxyName);\n proxy.onRemove();\n }\n return proxy;\n }\n\n /**\n * Remove a Model instance\n *\n * @static\n * @param key\n */\n static removeModel(key) {\n Model.instanceMap.delete(key);\n }\n\n /**\n * @static\n * @type {string}\n */\n static get MULTITON_MSG() { return \"Model instance for this Multiton key already constructed!\" };\n}\nexport { Model }\n","/*\n * Notification.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\n/**\n * A base `Notification` implementation.\n *\n *

PureMVC does not rely upon underlying event models such\n * as the one provided with Flash, and ActionScript 3 does\n * not have an inherent event model.

\n *\n *

The Observer Pattern as implemented within PureMVC exists\n * to support event-driven communication between the\n * application and the actors of the MVC triad.

\n *\n *

Notifications are not meant to be a replacement for Events\n * in Flex/Flash/Apollo. Generally, `Mediator` implementors\n * place event listeners on their view components, which they\n * then handle in the usual way. This may lead to the broadcast of `Notification`s to\n * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command`\n * instances communicate with each other and `Mediator`s\n * by broadcasting `Notification`s.

\n *\n *

A key difference between Flash `Event`s and PureMVC\n * `Notification`s is that `Event`s follow the\n * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy\n * until some parent component handles the `Event`, while\n * PureMVC `Notification`s follow a 'Publish/Subscribe'\n * pattern. PureMVC classes need not be related to each other in a\n * parent/child relationship in order to communicate with one another\n * using `Notification`s.

\n *\n * @class Notification\n */\nclass Notification {\n\n /**\n * Constructor.\n *\n * @constructor\n * @param {string} name - The name of the notification.\n * @param {Object|null} [body=null] - The body of the notification, defaults to `null`.\n * @param {string} [type=\"\"] - The type of the notification, defaults to an empty string.\n */\n constructor(name, body = null, type = \"\") {\n this._name = name;\n this._body = body;\n this._type = type;\n }\n\n /**\n * Get the name of the `Notification` instance.\n *\n * @returns {string}\n */\n get name() {\n return this._name;\n }\n\n /**\n * Get the body of the `Notification` instance.\n *\n * @returns {Object | null}\n */\n get body() {\n return this._body;\n }\n\n /**\n * Set the body of the `Notification` instance.\n *\n * @param {Object|null} body\n */\n set body(body) {\n this._body = body;\n }\n\n /**\n * Get the type of the `Notification` instance.\n *\n * @returns {string}\n */\n get type() {\n return this._type;\n }\n\n /**\n * Set the type of the `Notification` instance.\n *\n * @param {string} type\n */\n set type(type) {\n this._type = type;\n }\n\n /**\n * Get the string representation of the `Notification` instance.\n *\n * @returns {string}\n */\n toString() {\n let str= \"Notification Name: \" + this.name;\n str+= \"\\nBody:\" + ((this.body == null ) ? \"null\" : this.body.toString());\n str+= \"\\nType:\" + ((this.type == null ) ? \"null\" : this.type);\n return str;\n }\n\n}\nexport { Notification }\n","/*\n * Facade.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Controller} from \"../../core/Controller.js\";\nimport {Model} from \"../../core/Model.js\";\nimport {View} from \"../../core/View.js\";\nimport {Notification} from \"../observer/Notification.js\";\n\n/**\n * A base Multiton `Facade` implementation.\n *\n * @see Model Model\n * @see View View\n * @see Controller Controller\n *\n * @class Facade\n */\nclass Facade {\n\n /**\n * Constructor.\n *\n *

This `Facade` implementation is a Multiton,\n * so you should not call the constructor\n * directly, but instead call the static Factory method,\n * passing the unique key for this instance\n * `Facade.getInstance( multitonKey )`

\n *\n * @constructor\n * @param {string} key\n *\n * @throws {Error} Error if instance for this Multiton key has already been constructed\n */\n constructor(key) {\n if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG);\n this.initializeNotifier(key);\n Facade.instanceMap.set(this.multitonKey, this);\n this.initializeFacade();\n }\n\n /**\n * Initialize the Multiton `Facade` instance.\n *\n *

Called automatically by the constructor. Override in your\n * subclass to do any subclass specific initializations. Be\n * sure to call `super.initializeFacade()`, though.

\n */\n initializeFacade() {\n this.initializeModel();\n this.initializeController();\n this.initializeView();\n }\n\n /**\n * Facade Multiton Factory method\n *\n * @static\n * @param {string} key\n * @param {function(string):Facade} factory\n * @returns {Facade} the Multiton instance of the Facade\n */\n static getInstance(key, factory) {\n if (Facade.instanceMap == null)\n /** @static\n * @type {Map} */\n Facade.instanceMap = new Map();\n if (Facade.instanceMap.get(key) == null) Facade.instanceMap.set(key, factory(key));\n return Facade.instanceMap.get(key);\n }\n\n /**\n * Initialize the `Model`.\n *\n *

Called by the `initializeFacade` method.\n * Override this method in your subclass of `Facade`\n * if one or both of the following are true:

\n *\n *
    \n *
  • You wish to initialize a different `Model`.
  • \n *
  • You have `Proxy`s to register with the Model that do not\n * retrieve a reference to the Facade at construction time.`
  • \n *
\n *\n * If you don't want to initialize a different `Model`,\n * call `super.initializeModel()` at the beginning of your\n * method, then register `Proxy`s.\n *\n *

Note: This method is rarely overridden; in practice you are more\n * likely to use a `Command` to create and register `Proxy`s\n * with the `Model`, since `Proxy`s with mutable data will likely\n * need to send `Notification`s and thus will likely want to fetch a reference to\n * the `Facade` during their construction.

\n */\n initializeModel() {\n if (this.model != null) return;\n this.model = Model.getInstance(this.multitonKey, key => new Model(key));\n }\n\n /**\n * Initialize the `Controller`.\n *\n *

Called by the `initializeFacade` method.\n * Override this method in your subclass of `Facade`\n * if one or both of the following are true:

\n *\n *
    \n *
  • You wish to initialize a different `Controller`.
  • \n *
  • You have `Commands` to register with the `Controller` at startup.`.
  • \n *
\n *\n *

If you don't want to initialize a different `Controller`,\n * call `super.initializeController()` at the beginning of your\n * method, then register `Command`s.

\n */\n initializeController() {\n if (this.controller != null) return;\n this.controller = Controller.getInstance(this.multitonKey, key => new Controller(key));\n }\n\n /**\n * Initialize the `View`.\n *\n *

Called by the `initializeFacade` method.\n * Override this method in your subclass of `Facade`\n * if one or both of the following are true:

\n *\n *
    \n *
  • You wish to initialize a different `View`.
  • \n *
  • You have `Observers` to register with the `View`
  • \n *
\n *\n *

If you don't want to initialize a different `View`,\n * call `super.initializeView()` at the beginning of your\n * method, then register `Mediator` instances.

\n *\n *

Note: This method is rarely overridden; in practice you are more\n * likely to use a `Command` to create and register `Mediator`s\n * with the `View`, since `Mediator` instances will need to send\n * `Notification`s and thus will likely want to fetch a reference\n * to the `Facade` during their construction.

\n */\n initializeView() {\n if (this.view != null) return;\n this.view = View.getInstance(this.multitonKey, key => new View(key));\n }\n\n /**\n * Register a `Command` with the `Controller` by Notification name.\n *\n * @param {string} notificationName the name of the `Notification` to associate the `Command` with\n * @param {function():SimpleCommand} factory a reference to the factory of the `Command`\n */\n registerCommand(notificationName, factory) {\n this.controller.registerCommand(notificationName, factory);\n }\n\n /**\n * Check if a Command is registered for a given Notification\n *\n * @param {string} notificationName\n * @returns {boolean} whether a Command is currently registered for the given `notificationName`.\n */\n hasCommand(notificationName) {\n return this.controller.hasCommand(notificationName);\n }\n\n /**\n * Remove a previously registered `Command` to `Notification` mapping from the Controller.\n *\n * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for\n */\n removeCommand(notificationName) {\n this.controller.removeCommand(notificationName);\n }\n\n /**\n * Register a `Proxy` with the `Model` by name.\n *\n * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`.\n */\n registerProxy(proxy) {\n this.model.registerProxy(proxy);\n }\n\n /**\n * Remove a `Proxy` from the `Model` by name.\n *\n * @param {string} proxyName the `Proxy` to remove from the `Model`.\n * @returns {Proxy} the `Proxy` that was removed from the `Model`\n */\n removeProxy(proxyName) {\n return this.model.removeProxy(proxyName);\n }\n\n /**\n * Check if a `Proxy` is registered\n *\n * @param {string} proxyName\n * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`.\n */\n hasProxy(proxyName) {\n return this.model.hasProxy(proxyName);\n }\n\n /**\n * Retrieve a `Proxy` from the `Model` by name.\n *\n * @param {string} proxyName the name of the proxy to be retrieved.\n * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`.\n */\n retrieveProxy(proxyName) {\n return this.model.retrieveProxy(proxyName);\n }\n\n /**\n * Register a `Mediator` with the `View`.\n *\n * @param {Mediator} mediator a reference to the `Mediator`\n */\n registerMediator(mediator) {\n this.view.registerMediator(mediator);\n }\n\n /**\n * Remove a `Mediator` from the `View`.\n *\n * @param {string} mediatorName name of the `Mediator` to be removed.\n * @returns {Mediator} the `Mediator` that was removed from the `View`\n */\n removeMediator(mediatorName) {\n return this.view.removeMediator(mediatorName);\n }\n\n /**\n * Check if a `Mediator` is registered or not\n *\n * @param {string} mediatorName\n * @returns {boolean} whether a Mediator is registered with the given `mediatorName`.\n */\n hasMediator(mediatorName) {\n return this.view.hasMediator(mediatorName);\n }\n\n /**\n * Retrieve a `Mediator` from the `View`.\n *\n * @param {string} mediatorName\n * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`.\n */\n retrieveMediator(mediatorName) {\n return this.view.retrieveMediator(mediatorName);\n }\n\n /**\n * Create and send an `Notification`.\n *\n *

Keeps us from having to construct new notification\n * instances in our implementation code.

\n *\n * @param {string} notificationName the name of the notification to send\n * @param {Object} [body] body the body of the notification (optional)\n * @param {string} [type] type the type of the notification (optional)\n */\n sendNotification(notificationName, body = null, type = \"\") {\n this.notifyObservers(new Notification(notificationName, body, type));\n }\n\n /**\n * Notify `Observer`s.\n *\n *

This method is left public mostly for backward\n * compatibility, and to allow you to send custom\n * notification classes using the facade.

\n *\n *

Usually you should just call `sendNotification`\n * and pass the parameters, never having to\n * construct the notification yourself.

\n *\n * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of.\n */\n notifyObservers(notification) {\n this.view.notifyObservers(notification);\n }\n\n /**\n * Set the Multiton key for this facade instance.\n *\n *

Not called directly, but instead from the\n * constructor when getInstance is invoked.\n * It is necessary to be public in order to\n * implement Notifier.

\n */\n initializeNotifier(key) {\n this.multitonKey = key;\n }\n\n /**\n * Check if a Core is registered or not\n *\n * @static\n * @param {string} key the multiton key for the Core in question\n * @returns {boolean} whether a Core is registered with the given `key`.\n */\n static hasCore(key) {\n return this.instanceMap.has(key);\n }\n\n /**\n * Remove a Core.\n *\n *

Remove the Model, View, Controller and Facade\n * instances for the given key.

\n *\n * @static\n * @param {string} key multitonKey of the Core to remove\n */\n static removeCore(key) {\n if (Facade.instanceMap.get(key) == null) return;\n Model.removeModel(key);\n View.removeView(key);\n Controller.removeController(key);\n this.instanceMap.delete(key);\n }\n\n /**\n * Message Constants\n *\n * @static\n * @returns {string}\n */\n static get MULTITON_MSG() {return \"Facade instance for this Multiton key already constructed!\"};\n}\nexport { Facade }\n","/*\n * Notifier.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Facade} from \"../facade/Facade.js\";\n\n/**\n * A Base `Notifier` implementation.\n *\n *

`MacroCommand, Command, Mediator` and `Proxy`\n * all have a need to send `Notifications`.

\n *\n *

The `Notifier` interface provides a common method called\n * `sendNotification` that relieves implementation code of\n * the necessity to actually construct `Notifications`.

\n *\n *

The `Notifier` class, which all the above-mentioned classes\n * extend, provides an initialized reference to the `Facade`\n * Multiton, which is required for the convenience method\n * for sending `Notifications`, but also eases implementation as these\n * classes have frequent `Facade` interactions and usually require\n * access to the facade anyway.

\n *\n *

NOTE: In the MultiCore version of the framework, there is one caveat to\n * notifiers, they cannot send notifications or reach the facade until they\n * have a valid multitonKey.

\n *\n * The multitonKey is set:\n * * on a Command when it is executed by the Controller\n * * on a Mediator is registered with the View\n * * on a Proxy is registered with the Model.\n *\n * @see Proxy Proxy\n * @see Facade Facade\n * @see Mediator Mediator\n * @see MacroCommand MacroCommand\n * @see SimpleCommand SimpleCommand\n *\n * @class Notifier\n */\nclass Notifier {\n\n constructor() {}\n\n /**\n * Create and send an `Notification`.\n *\n *

Keeps us from having to construct new Notification\n * instances in our implementation code.

\n *\n * @param {string} notificationName\n * @param {Object} [body] body\n * @param {string} [type] type\n */\n sendNotification (notificationName, body = null, type = \"\") {\n if (this.facade != null) {\n this.facade.sendNotification(notificationName, body, type);\n }\n }\n\n /**\n * Initialize this Notifier instance.\n *\n *

This is how a Notifier gets its multitonKey.\n * Calls to sendNotification or to access the\n * facade will fail until after this method\n * has been called.

\n *\n *

Mediators, Commands or Proxies may override\n * this method in order to send notifications\n * or access the Multiton Facade instance as\n * soon as possible. They CANNOT access the facade\n * in their constructors, since this method will not\n * yet have been called.

\n *\n * @param {string} key the multitonKey for this Notifier to use\n */\n initializeNotifier(key) {\n this.multitonKey = key;\n }\n\n /**\n * Return the Multiton Facade instance\n *\n * @typedef {Facade} Facade\n *\n * @throws {Error}\n */\n get facade() {\n if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG);\n return Facade.getInstance(this.multitonKey, key => new Facade(key));\n }\n\n /**\n * Message Constants\n *\n * @static\n * @returns {string}\n */\n static get MULTITON_MSG() { return \"multitonKey for this Notifier not yet initialized!\" }\n}\nexport { Notifier }\n","/*\n * SimpleCommand.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Notifier} from \"../observer/Notifier.js\";\n\n/**\n * A base `Command` implementation.\n *\n *

Your subclass should override the `execute`\n * method where your business logic will handle the `Notification`.

\n *\n * @see Controller Controller\n * @see Notification Notification\n * @see MacroCommand MacroCommand\n *\n * @class SimpleCommand\n */\nclass SimpleCommand extends Notifier {\n\n constructor() {\n super();\n }\n\n /**\n * Fulfill the use-case initiated by the given `Notification`.\n *\n *

In the Command Pattern, an application use-case typically\n * begins with some user action, which results in a `Notification` being broadcast, which\n * is handled by business logic in the `execute` method of an\n * `Command`.

\n *\n * @param {Notification} notification\n */\n execute(notification) {\n\n }\n\n}\nexport { SimpleCommand }\n","/*\n * MacroCommand.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {SimpleCommand} from \"./SimpleCommand.js\";\n\n/**\n * A base `Command` implementation that executes other `Command`s.\n *\n *

A `MacroCommand` maintains a list of\n * `Command` Class references called SubCommands.

\n *\n *

When `execute` is called, the `MacroCommand`\n * instantiates and calls `execute` on each of its SubCommands turn.\n * Each SubCommand will be passed a reference to the original\n * `Notification` that was passed to the `MacroCommand`'s\n * `execute` method.

\n *\n *

Unlike `SimpleCommand`, your subclass\n * should not override `execute`, but instead, should\n * override the `initializeMacroCommand` method,\n * calling `addSubCommand` once for each SubCommand\n * to be executed.

\n *\n * @see Controller Controller\n * @see Notification Notification\n * @see SimpleCommand SimpleCommand\n *\n * @class MacroCommand\n */\nclass MacroCommand extends SimpleCommand {\n\n /**\n * Constructor.\n *\n *

You should not need to define a constructor,\n * instead, override the `initializeMacroCommand`\n * method.

\n *\n *

If your subclass does define a constructor, be\n * sure to call `super()`.

\n *\n * @constructor\n */\n constructor() {\n super();\n /** @protected\n * @type {Array.} */\n this.subCommands = [];\n this.initializeMacroCommand();\n }\n\n /**\n * Initialize the `MacroCommand`.\n *\n *

In your subclass, override this method to\n * initialize the `MacroCommand`'s SubCommand\n * list with `Command` class references like\n * this:

\n *\n *
`\n     *\t\t// Initialize MyMacroCommand\n     *\t\tinitializeMacroCommand() {\n     *\t\t\tthis.addSubCommand(() => new app.FirstCommand());\n     *\t\t\tthis.addSubCommand(() => new app.SecondCommand());\n     *\t\t\tthis.addSubCommand(() => new app.ThirdCommand());\n     *\t\t}\n     * `
\n *\n *

Note that SubCommands may be any `Command` implementor,\n * `MacroCommand`s or `SimpleCommands` are both acceptable.\n */\n initializeMacroCommand() {\n\n }\n\n /**\n * Add a SubCommand.\n *\n *

The SubCommands will be called in First In/First Out (FIFO)\n * order.

\n *\n * @param {function():SimpleCommand} factory\n */\n addSubCommand(factory) {\n this.subCommands.push(factory);\n }\n\n /**\n * Execute this `MacroCommand`'s SubCommands.\n *\n *

The SubCommands will be called in First In/First Out (FIFO)\n * order.

\n *\n * @param {Notification} notification\n */\n execute(notification) {\n while(this.subCommands.length > 0) {\n let factory = this.subCommands.shift();\n let commandInstance = factory();\n commandInstance.initializeNotifier(this.multitonKey);\n commandInstance.execute(notification);\n }\n }\n\n}\nexport { MacroCommand }\n","/*\n * Mediator.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Notifier} from \"../observer/Notifier.js\";\n\n/**\n * A base `Mediator` implementation.\n *\n * @see View View\n *\n * @class Mediator\n */\nclass Mediator extends Notifier {\n\n /**\n * Constructor.\n *\n * @constructor\n * @param {string | null} [mediatorName=null]\n * @param {Object | null} [viewComponent=null]\n */\n constructor(mediatorName = null, viewComponent = null) {\n super();\n this._mediatorName = mediatorName || Mediator.NAME;\n this._viewComponent = viewComponent;\n }\n\n /**\n * Called by the View when the Mediator is registered\n */\n onRegister() {\n\n }\n\n /**\n * Called by the View when the Mediator is removed\n */\n onRemove() {\n\n }\n\n /**\n * List the `Notification` names this\n * `Mediator` is interested in being notified of.\n *\n * @returns {string[]}\n */\n listNotificationInterests() {\n return [];\n }\n\n /**\n * Handle `Notification`s.\n *\n *

\n * Typically this will be handled in a switch statement,\n * with one 'case' entry per `Notification`\n * the `Mediator` is interested in.\n *\n * @param {Notification} notification\n */\n handleNotification(notification) {\n\n }\n\n /**\n * the mediator name\n *\n * @returns {string}\n */\n get mediatorName() {\n return this._mediatorName;\n }\n\n /**\n * Get the `Mediator`'s view component.\n *\n *

\n * Additionally, an implicit getter will usually\n * be defined in the subclass that casts the view\n * object to a type, like this:

\n *\n * @returns {Object | null}\n */\n get viewComponent() {\n return this._viewComponent;\n }\n\n /**\n * Set the `Mediator`'s view component.\n *\n * @param {Object} viewComponent\n */\n set viewComponent(viewComponent) {\n this._viewComponent = viewComponent;\n }\n\n /**\n * The name of the `Mediator`.\n *\n *

Typically, a `Mediator` will be written to serve\n * one specific control or group controls and so,\n * will not have a need to be dynamically named.

\n *\n * @static\n * @returns {string}\n */\n static get NAME() { return \"Mediator\" }\n}\nexport { Mediator }\n","/*\n * Proxy.js\n * PureMVC JavaScript Multicore\n *\n * Copyright(c) 2023 Saad Shams \n * Your reuse is governed by the BSD License\n*/\n\nimport {Notifier} from \"../observer/Notifier.js\";\n\n/**\n * A base `Proxy` implementation.\n *\n *

In PureMVC, `Proxy` classes are used to manage parts of the\n * application's data model.

\n *\n *

A `Proxy` might simply manage a reference to a local data object,\n * in which case interacting with it might involve setting and\n * getting of its data in synchronous fashion.

\n *\n *

`Proxy` classes are also used to encapsulate the application's\n * interaction with remote services to save or retrieve data, in which case,\n * we adopt an asynchronous idiom; setting data (or calling a method) on the\n * `Proxy` and listening for a `Notification` to be sent\n * when the `Proxy` has retrieved the data from the service.

\n *\n * @see Model Model\n *\n * @class Proxy\n */\nclass Proxy extends Notifier {\n /**\n * Constructor\n *\n * @constructor\n * @param {string | null} [proxyName=null]\n * @param {Object | null} [data=null]\n */\n constructor(proxyName = null, data = null) {\n super();\n /** @protected\n * @type {string} */\n this._proxyName = proxyName || Proxy.NAME;\n /** @protected\n * @type {Object | null} */\n this._data = data;\n }\n\n /**\n * Called by the Model when the Proxy is registered\n */\n onRegister() {}\n\n /**\n * Called by the Model when the Proxy is removed\n */\n onRemove() {}\n\n /**\n * Get the proxy name\n *\n * @returns {string}\n */\n get proxyName() {\n return this._proxyName;\n }\n\n /**\n * Get the data object\n *\n * @returns {Object | null}\n */\n get data () {\n return this._data;\n }\n\n /**\n * Set the data object\n *\n * @param {Object} data\n */\n set data(data) {\n this._data = data;\n }\n\n /**\n *\n * @static\n * @returns {string}\n */\n static get NAME() { return \"Proxy\" }\n}\nexport { Proxy }\n"],"names":["Observer","constructor","notify","context","this","_notifyMethod","_notifyContext","notifyObserver","notification","call","compareNotifyContext","notifyContext","notifyMethod","View","key","instanceMap","get","Error","MULTITON_MSG","multitonKey","set","mediatorMap","Map","observerMap","initializeView","getInstance","factory","registerObserver","notificationName","observer","push","Array","notifyObservers","has","name","observers","slice","i","length","removeObserver","splice","delete","registerMediator","mediator","mediatorName","initializeNotifier","interests","listNotificationInterests","handleNotification","bind","onRegister","retrieveMediator","removeMediator","onRemove","hasMediator","removeView","Controller","commandMap","initializeController","view","executeCommand","commandInstance","execute","registerCommand","hasCommand","removeCommand","removeController","Model","proxyMap","initializeModel","registerProxy","proxy","proxyName","retrieveProxy","hasProxy","removeProxy","removeModel","Notification","body","type","_name","_body","_type","toString","str","Facade","initializeFacade","model","controller","sendNotification","hasCore","removeCore","Notifier","facade","SimpleCommand","super","MacroCommand","subCommands","initializeMacroCommand","addSubCommand","shift","Mediator","viewComponent","_mediatorName","NAME","_viewComponent","Proxy","data","_proxyName","_data"],"mappings":"AA0BA,MAAMA,EAWF,WAAAC,CAAYC,EAAS,KAAMC,EAAU,MACjCC,KAAKC,cAAgBH,EACrBE,KAAKE,eAAiBH,CACzB,CAOD,cAAAI,CAAeC,GACXJ,KAAKC,cAAcI,KAAKL,KAAKE,eAAgBE,EAChD,CAQD,oBAAAE,CAAqBC,GACjB,OAAOP,KAAKE,iBAAmBK,CAClC,CAOD,gBAAIC,GACA,OAAOR,KAAKC,aACf,CASD,gBAAIO,CAAaA,GACbR,KAAKC,cAAgBO,CACxB,CAOD,iBAAID,GACA,OAAOP,KAAKE,cACf,CAOD,iBAAIK,CAAcA,GACdP,KAAKE,eAAiBK,CACzB,EClEL,MAAME,EAeF,WAAAZ,CAAYa,GACR,GAAiC,MAA7BD,EAAKE,YAAYC,IAAIF,GAAc,MAAM,IAAIG,MAAMJ,EAAKK,cAG5Dd,KAAKe,YAAcL,EACnBD,EAAKE,YAAYK,IAAIhB,KAAKe,YAAaf,MAGvCA,KAAKiB,YAAc,IAAIC,IAGvBlB,KAAKmB,YAAc,IAAID,IACvBlB,KAAKoB,gBACR,CAUD,cAAAA,GAEC,CAUD,kBAAOC,CAAYX,EAAKY,GAMpB,OALwB,MAApBb,EAAKE,cAGLF,EAAKE,YAAc,IAAIO,KACM,MAA7BT,EAAKE,YAAYC,IAAIF,IAAcD,EAAKE,YAAYK,IAAIN,EAAKY,EAAQZ,IAClED,EAAKE,YAAYC,IAAIF,EAC/B,CASD,gBAAAa,CAAiBC,EAAkBC,GAC/B,GAA8C,MAA1CzB,KAAKmB,YAAYP,IAAIY,GAA2B,CAChCxB,KAAKmB,YAAYP,IAAIY,GAC3BE,KAAKD,EAC3B,MACYzB,KAAKmB,YAAYH,IAAIQ,EAAkB,IAAIG,MAAMF,GAExD,CAWD,eAAAG,CAAgBxB,GACZ,GAAIJ,KAAKmB,YAAYU,IAAIzB,EAAa0B,MAAO,CAGzC,IAAIC,EAAY/B,KAAKmB,YAAYP,IAAIR,EAAa0B,MAAME,QAGxD,IAAI,IAAIC,EAAI,EAAGA,EAAIF,EAAUG,OAAQD,IACjCF,EAAUE,GAAG9B,eAAeC,EAEnC,CACJ,CAQD,cAAA+B,CAAeX,EAAkBjB,GAE7B,IAAIwB,EAAY/B,KAAKmB,YAAYP,IAAIY,GAGrC,IAAK,IAAIS,EAAI,EAAGA,EAAIF,EAAUG,OAAQD,IAClC,IAAyD,IAArDF,EAAUE,GAAG3B,qBAAqBC,GAAyB,CAG3DwB,EAAUK,OAAOH,EAAG,GACpB,KACH,CAKoB,IAArBF,EAAUG,QACVlC,KAAKmB,YAAYkB,OAAOb,EAE/B,CAiBD,gBAAAc,CAAiBC,GAEb,IAAoD,IAAhDvC,KAAKiB,YAAYY,IAAIU,EAASC,cAAyB,OAE3DD,EAASE,mBAAmBzC,KAAKe,aAGjCf,KAAKiB,YAAYD,IAAIuB,EAASC,aAAcD,GAG5C,IAAIG,EAAYH,EAASI,4BAGzB,GAAID,EAAUR,OAAS,EAAG,CAEtB,IAAIT,EAAW,IAAI7B,EAAS2C,EAASK,mBAAmBC,KAAKN,GAAWA,GAGxE,IAAK,IAAIN,EAAI,EAAGA,EAAIS,EAAUR,OAAQD,IAClCjC,KAAKuB,iBAAiBmB,EAAUT,GAAIR,EAE3C,CAGDc,EAASO,YACZ,CAQD,gBAAAC,CAAiBP,GACb,OAAOxC,KAAKiB,YAAYL,IAAI4B,IAAiB,IAChD,CAQD,cAAAQ,CAAeR,GAEX,IAAID,EAAWvC,KAAKiB,YAAYL,IAAI4B,GAEpC,GAAID,EAAU,CAEV,IAAIG,EAAYH,EAASI,4BACzB,IAAK,IAAIV,EAAI,EAAGA,EAAIS,EAAUR,OAAQD,IAGlCjC,KAAKmC,eAAeO,EAAUT,GAAIM,GAItCvC,KAAKiB,YAAYoB,OAAOG,GAGxBD,EAASU,UACZ,CAED,OAAOV,CACV,CAQD,WAAAW,CAAYV,GACR,OAAOxC,KAAKiB,YAAYY,IAAIW,EAC/B,CAQD,iBAAOW,CAAWzC,GACdV,KAAKW,YAAY0B,OAAO3B,EAC3B,CAQD,uBAAWI,GAAiB,MAAO,0DAA4D,ECzNnG,MAAMsC,EAgBF,WAAAvD,CAAYa,GACR,GAAmC,MAA/B0C,EAAWzC,YAAYD,GAAc,MAAM,IAAIG,MAAMuC,EAAWtC,cAGpEd,KAAKe,YAAcL,EACnB0C,EAAWzC,YAAYK,IAAIhB,KAAKe,YAAaf,MAG7CA,KAAKqD,WAAa,IAAInC,IACtBlB,KAAKsD,sBACR,CAqBD,oBAAAA,GAGItD,KAAKuD,KAAO9C,EAAKY,YAAYrB,KAAKe,aAAcL,GAAQ,IAAID,EAAKC,IACpE,CAUD,kBAAOW,CAAYX,EAAKY,GAMpB,OAL8B,MAA1B8B,EAAWzC,cAGXyC,EAAWzC,YAAc,IAAIO,KACM,MAAnCkC,EAAWzC,YAAYC,IAAIF,IAAc0C,EAAWzC,YAAYK,IAAIN,EAAKY,EAAQZ,IAC9E0C,EAAWzC,YAAYC,IAAIF,EACrC,CAQD,cAAA8C,CAAepD,GACX,IAAIkB,EAAUtB,KAAKqD,WAAWzC,IAAIR,EAAa0B,MAC/C,GAAe,MAAXR,EAAiB,OAErB,IAAImC,EAAkBnC,IACtBmC,EAAgBhB,mBAAmBzC,KAAKe,aACxC0C,EAAgBC,QAAQtD,EAC3B,CAgBD,eAAAuD,CAAgBnC,EAAkBF,GACe,MAAzCtB,KAAKqD,WAAWzC,IAAIY,IACpBxB,KAAKuD,KAAKhC,iBAAiBC,EAAkB,IAAI5B,EAASI,KAAKwD,eAAgBxD,OAEnFA,KAAKqD,WAAWrC,IAAIQ,EAAkBF,EACzC,CAQD,UAAAsC,CAAWpC,GACP,OAAOxB,KAAKqD,WAAWxB,IAAIL,EAC9B,CAOD,aAAAqC,CAAcrC,GAEPxB,KAAK4D,WAAWpC,KAEfxB,KAAKuD,KAAKpB,eAAeX,EAAkBxB,MAG3CA,KAAKqD,WAAWhB,OAAOb,GAE9B,CAQD,uBAAOsC,CAAiBpD,GACpB0C,EAAWzC,YAAY0B,OAAO3B,EACjC,CAQD,uBAAWI,GAAiB,MAAO,gEAAkE,ECjKzG,MAAMiD,EAeF,WAAAlE,CAAYa,GACR,GAAkC,MAA9BqD,EAAMpD,YAAYC,IAAIF,GAAc,MAAM,IAAIG,MAAMkD,EAAMjD,cAG9Dd,KAAKe,YAAcL,EACnBqD,EAAMpD,YAAYK,IAAIhB,KAAKe,YAAaf,MAGxCA,KAAKgE,SAAW,IAAI9C,IACpBlB,KAAKiE,iBACR,CAWD,eAAAA,GAEC,CAUD,kBAAO5C,CAAYX,EAAKY,GAMpB,OALyB,MAArByC,EAAMpD,cAGNoD,EAAMpD,YAAc,IAAIO,KACM,MAA9B6C,EAAMpD,YAAYC,IAAIF,IAAcqD,EAAMpD,YAAYK,IAAIN,EAAKY,EAAQZ,IACpEqD,EAAMpD,YAAYC,IAAIF,EAChC,CAOD,aAAAwD,CAAcC,GACVA,EAAM1B,mBAAmBzC,KAAKe,aAC9Bf,KAAKgE,SAAShD,IAAImD,EAAMC,UAAWD,GACnCA,EAAMrB,YACT,CAQD,aAAAuB,CAAcD,GACV,OAAOpE,KAAKgE,SAASpD,IAAIwD,IAAc,IAC1C,CAQD,QAAAE,CAASF,GACL,OAAOpE,KAAKgE,SAASnC,IAAIuC,EAC5B,CAQD,WAAAG,CAAYH,GACR,IAAID,EAAQnE,KAAKgE,SAASpD,IAAIwD,GAK9B,OAJa,MAATD,IACAnE,KAAKgE,SAAS3B,OAAO+B,GACrBD,EAAMlB,YAEHkB,CACV,CAQD,kBAAOK,CAAY9D,GACfqD,EAAMpD,YAAY0B,OAAO3B,EAC5B,CAMD,uBAAWI,GAAiB,MAAO,2DAA6D,EC/GpG,MAAM2D,EAUF,WAAA5E,CAAYiC,EAAM4C,EAAO,KAAMC,EAAO,IAClC3E,KAAK4E,MAAQ9C,EACb9B,KAAK6E,MAAQH,EACb1E,KAAK8E,MAAQH,CAChB,CAOD,QAAI7C,GACA,OAAO9B,KAAK4E,KACf,CAOD,QAAIF,GACA,OAAO1E,KAAK6E,KACf,CAOD,QAAIH,CAAKA,GACL1E,KAAK6E,MAAQH,CAChB,CAOD,QAAIC,GACA,OAAO3E,KAAK8E,KACf,CAOD,QAAIH,CAAKA,GACL3E,KAAK8E,MAAQH,CAChB,CAOD,QAAAI,GACI,IAAIC,EAAK,sBAAwBhF,KAAK8B,KAGtC,OAFAkD,GAAM,WAA2B,MAAbhF,KAAK0E,KAAiB,OAAS1E,KAAK0E,KAAKK,YAC7DC,GAAM,WAA2B,MAAbhF,KAAK2E,KAAiB,OAAS3E,KAAK2E,MACjDK,CACV,ECvFL,MAAMC,EAgBF,WAAApF,CAAYa,GACR,GAA+B,MAA3BuE,EAAOtE,YAAYD,GAAc,MAAM,IAAIG,MAAMoE,EAAOnE,cAC5Dd,KAAKyC,mBAAmB/B,GACxBuE,EAAOtE,YAAYK,IAAIhB,KAAKe,YAAaf,MACzCA,KAAKkF,kBACR,CASD,gBAAAA,GACIlF,KAAKiE,kBACLjE,KAAKsD,uBACLtD,KAAKoB,gBACR,CAUD,kBAAOC,CAAYX,EAAKY,GAMpB,OAL0B,MAAtB2D,EAAOtE,cAGPsE,EAAOtE,YAAc,IAAIO,KACM,MAA/B+D,EAAOtE,YAAYC,IAAIF,IAAcuE,EAAOtE,YAAYK,IAAIN,EAAKY,EAAQZ,IACtEuE,EAAOtE,YAAYC,IAAIF,EACjC,CAyBD,eAAAuD,GACsB,MAAdjE,KAAKmF,QACTnF,KAAKmF,MAAQpB,EAAM1C,YAAYrB,KAAKe,aAAaL,GAAO,IAAIqD,EAAMrD,KACrE,CAkBD,oBAAA4C,GAC2B,MAAnBtD,KAAKoF,aACTpF,KAAKoF,WAAahC,EAAW/B,YAAYrB,KAAKe,aAAaL,GAAO,IAAI0C,EAAW1C,KACpF,CAwBD,cAAAU,GACqB,MAAbpB,KAAKuD,OACTvD,KAAKuD,KAAO9C,EAAKY,YAAYrB,KAAKe,aAAaL,GAAO,IAAID,EAAKC,KAClE,CAQD,eAAAiD,CAAgBnC,EAAkBF,GAC9BtB,KAAKoF,WAAWzB,gBAAgBnC,EAAkBF,EACrD,CAQD,UAAAsC,CAAWpC,GACP,OAAOxB,KAAKoF,WAAWxB,WAAWpC,EACrC,CAOD,aAAAqC,CAAcrC,GACVxB,KAAKoF,WAAWvB,cAAcrC,EACjC,CAOD,aAAA0C,CAAcC,GACVnE,KAAKmF,MAAMjB,cAAcC,EAC5B,CAQD,WAAAI,CAAYH,GACR,OAAOpE,KAAKmF,MAAMZ,YAAYH,EACjC,CAQD,QAAAE,CAASF,GACL,OAAOpE,KAAKmF,MAAMb,SAASF,EAC9B,CAQD,aAAAC,CAAcD,GACV,OAAOpE,KAAKmF,MAAMd,cAAcD,EACnC,CAOD,gBAAA9B,CAAiBC,GACbvC,KAAKuD,KAAKjB,iBAAiBC,EAC9B,CAQD,cAAAS,CAAeR,GACX,OAAOxC,KAAKuD,KAAKP,eAAeR,EACnC,CAQD,WAAAU,CAAYV,GACR,OAAOxC,KAAKuD,KAAKL,YAAYV,EAChC,CAQD,gBAAAO,CAAiBP,GACb,OAAOxC,KAAKuD,KAAKR,iBAAiBP,EACrC,CAYD,gBAAA6C,CAAiB7D,EAAkBkD,EAAO,KAAMC,EAAO,IACnD3E,KAAK4B,gBAAgB,IAAI6C,EAAajD,EAAkBkD,EAAMC,GACjE,CAeD,eAAA/C,CAAgBxB,GACZJ,KAAKuD,KAAK3B,gBAAgBxB,EAC7B,CAUD,kBAAAqC,CAAmB/B,GACfV,KAAKe,YAAcL,CACtB,CASD,cAAO4E,CAAQ5E,GACX,OAAOV,KAAKW,YAAYkB,IAAInB,EAC/B,CAWD,iBAAO6E,CAAW7E,GACqB,MAA/BuE,EAAOtE,YAAYC,IAAIF,KAC3BqD,EAAMS,YAAY9D,GAClBD,EAAK0C,WAAWzC,GAChB0C,EAAWU,iBAAiBpD,GAC5BV,KAAKW,YAAY0B,OAAO3B,GAC3B,CAQD,uBAAWI,GAAgB,MAAO,4DAA4D,ECnSlG,MAAM0E,EAEF,WAAA3F,GAAgB,CAYhB,gBAAAwF,CAAkB7D,EAAkBkD,EAAO,KAAMC,EAAO,IACjC,MAAf3E,KAAKyF,QACLzF,KAAKyF,OAAOJ,iBAAiB7D,EAAkBkD,EAAMC,EAE5D,CAmBD,kBAAAlC,CAAmB/B,GACfV,KAAKe,YAAcL,CACtB,CASD,UAAI+E,GACA,GAAwB,MAApBzF,KAAKe,YAAqB,MAAM,IAAIF,MAAM2E,EAAS1E,cACvD,OAAOmE,EAAO5D,YAAYrB,KAAKe,aAAaL,GAAO,IAAIuE,EAAOvE,IACjE,CAQD,uBAAWI,GAAiB,MAAO,oDAAsD,ECjF7F,MAAM4E,UAAsBF,EAExB,WAAA3F,GACI8F,OACH,CAYD,OAAAjC,CAAQtD,GAEP,ECNL,MAAMwF,UAAqBF,EAcvB,WAAA7F,GACI8F,QAGA3F,KAAK6F,YAAc,GACnB7F,KAAK8F,wBACR,CAsBD,sBAAAA,GAEC,CAUD,aAAAC,CAAczE,GACVtB,KAAK6F,YAAYnE,KAAKJ,EACzB,CAUD,OAAAoC,CAAQtD,GACJ,KAAMJ,KAAK6F,YAAY3D,OAAS,GAAG,CAC/B,IACIuB,EADUzD,KAAK6F,YAAYG,OACT1E,GACtBmC,EAAgBhB,mBAAmBzC,KAAKe,aACxC0C,EAAgBC,QAAQtD,EAC3B,CACJ,EC1FL,MAAM6F,UAAiBT,EASnB,WAAA3F,CAAY2C,EAAe,KAAM0D,EAAgB,MAC7CP,QACA3F,KAAKmG,cAAgB3D,GAAgByD,EAASG,KAC9CpG,KAAKqG,eAAiBH,CACzB,CAKD,UAAApD,GAEC,CAKD,QAAAG,GAEC,CAQD,yBAAAN,GACI,MAAO,EACV,CAYD,kBAAAC,CAAmBxC,GAElB,CAOD,gBAAIoC,GACA,OAAOxC,KAAKmG,aACf,CAYD,iBAAID,GACA,OAAOlG,KAAKqG,cACf,CAOD,iBAAIH,CAAcA,GACdlG,KAAKqG,eAAiBH,CACzB,CAYD,eAAWE,GAAS,MAAO,UAAY,EClF3C,MAAME,UAAcd,EAQhB,WAAA3F,CAAYuE,EAAY,KAAMmC,EAAO,MACjCZ,QAGA3F,KAAKwG,WAAapC,GAAakC,EAAMF,KAGrCpG,KAAKyG,MAAQF,CAChB,CAKD,UAAAzD,GAAe,CAKf,QAAAG,GAAa,CAOb,aAAImB,GACA,OAAOpE,KAAKwG,UACf,CAOD,QAAID,GACA,OAAOvG,KAAKyG,KACf,CAOD,QAAIF,CAAKA,GACLvG,KAAKyG,MAAQF,CAChB,CAOD,eAAWH,GAAS,MAAO,OAAS"} \ No newline at end of file diff --git a/docs/Controller.html b/docs/Controller.html index 4bf4f3f..39d54c0 100644 --- a/docs/Controller.html +++ b/docs/Controller.html @@ -298,7 +298,7 @@

(static) Source:
@@ -778,7 +778,7 @@

(static) Source:
@@ -914,7 +914,7 @@

execute
Source:
@@ -1049,7 +1049,7 @@

hasCommand<
Source:
@@ -1310,7 +1310,7 @@

regist
Source:
@@ -1466,7 +1466,7 @@

removeCo
Source:
@@ -1635,7 +1635,7 @@

new Control
Source:
@@ -1884,7 +1884,7 @@

(static) Source:
@@ -2364,7 +2364,7 @@

(static) Source:
@@ -2500,7 +2500,7 @@

execute
Source:
@@ -2635,7 +2635,7 @@

hasCommand<
Source:
@@ -2896,7 +2896,7 @@

regist
Source:
@@ -3052,7 +3052,7 @@

removeCo
Source:
@@ -3156,7 +3156,7 @@

Parameters:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Facade.html b/docs/Facade.html index e3a3dee..d0ffef5 100644 --- a/docs/Facade.html +++ b/docs/Facade.html @@ -201,7 +201,7 @@

(static)
Source:
@@ -275,7 +275,7 @@

(static) Source:
@@ -349,7 +349,7 @@

(static)
Source:
@@ -535,7 +535,7 @@

(static) hasC
Source:
@@ -697,7 +697,7 @@

(static) r
Source:
@@ -832,7 +832,7 @@

hasCommand<
Source:
@@ -992,7 +992,7 @@

hasMediato
Source:
@@ -1152,7 +1152,7 @@

hasProxySource:
@@ -1408,7 +1408,7 @@

initi
Source:
@@ -1594,7 +1594,7 @@

ini
Source:
@@ -1692,7 +1692,7 @@

initial
Source:
@@ -1781,7 +1781,7 @@

notify
Source:
@@ -1916,7 +1916,7 @@

regist
Source:
@@ -2077,7 +2077,7 @@

regis
Source:
@@ -2212,7 +2212,7 @@

register
Source:
@@ -2347,7 +2347,7 @@

removeCo
Source:
@@ -2482,7 +2482,7 @@

removeM
Source:
@@ -2642,7 +2642,7 @@

removeProx
Source:
@@ -2802,7 +2802,7 @@

retri
Source:
@@ -2962,7 +2962,7 @@

retrieve
Source:
@@ -3124,7 +3124,7 @@

sendN
Source:
@@ -3391,7 +3391,7 @@

new FacadeSource:
@@ -3566,7 +3566,7 @@

(static)
Source:
@@ -3640,7 +3640,7 @@

(static) Source:
@@ -3714,7 +3714,7 @@

(static)
Source:
@@ -3900,7 +3900,7 @@

(static) hasC
Source:
@@ -4062,7 +4062,7 @@

(static) r
Source:
@@ -4197,7 +4197,7 @@

hasCommand<
Source:
@@ -4357,7 +4357,7 @@

hasMediato
Source:
@@ -4517,7 +4517,7 @@

hasProxySource:
@@ -4773,7 +4773,7 @@

initi
Source:
@@ -4959,7 +4959,7 @@

ini
Source:
@@ -5057,7 +5057,7 @@

initial
Source:
@@ -5146,7 +5146,7 @@

notify
Source:
@@ -5281,7 +5281,7 @@

regist
Source:
@@ -5442,7 +5442,7 @@

regis
Source:
@@ -5577,7 +5577,7 @@

register
Source:
@@ -5712,7 +5712,7 @@

removeCo
Source:
@@ -5847,7 +5847,7 @@

removeM
Source:
@@ -6007,7 +6007,7 @@

removeProx
Source:
@@ -6167,7 +6167,7 @@

retri
Source:
@@ -6327,7 +6327,7 @@

retrieve
Source:
@@ -6489,7 +6489,7 @@

sendN
Source:
@@ -6691,7 +6691,7 @@

Parameters:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/MacroCommand.html b/docs/MacroCommand.html index 45356b7..0ac0175 100644 --- a/docs/MacroCommand.html +++ b/docs/MacroCommand.html @@ -213,7 +213,7 @@

(protected) Source:
@@ -299,7 +299,7 @@

addSubCo
Source:
@@ -436,7 +436,7 @@

executeSource:
@@ -585,7 +585,7 @@

Source:
@@ -702,7 +702,7 @@

new Macro
Source:
@@ -793,7 +793,7 @@

(protected) Source:
@@ -879,7 +879,7 @@

addSubCo
Source:
@@ -1016,7 +1016,7 @@

executeSource:
@@ -1165,7 +1165,7 @@

Source:
@@ -1217,7 +1217,7 @@

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Mediator.html b/docs/Mediator.html index df89006..3a9f1c1 100644 --- a/docs/Mediator.html +++ b/docs/Mediator.html @@ -204,7 +204,7 @@

(static) NAMESource:
@@ -268,7 +268,7 @@

mediatorN
Source:
@@ -336,7 +336,7 @@

viewComp
Source:
@@ -400,7 +400,7 @@

viewComp
Source:
@@ -478,7 +478,7 @@

han
Source:
@@ -614,7 +614,7 @@

Source:
@@ -718,7 +718,7 @@

onRegister<
Source:
@@ -801,7 +801,7 @@

onRemoveSource:
@@ -913,7 +913,7 @@

new Mediator<
Source:
@@ -1131,7 +1131,7 @@

(static) NAMESource:
@@ -1195,7 +1195,7 @@

mediatorN
Source:
@@ -1263,7 +1263,7 @@

viewComp
Source:
@@ -1327,7 +1327,7 @@

viewComp
Source:
@@ -1405,7 +1405,7 @@

han
Source:
@@ -1541,7 +1541,7 @@

Source:
@@ -1645,7 +1645,7 @@

onRegister<
Source:
@@ -1728,7 +1728,7 @@

onRemoveSource:
@@ -1780,7 +1780,7 @@

onRemove
- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Model.html b/docs/Model.html index fa211f1..af61828 100644 --- a/docs/Model.html +++ b/docs/Model.html @@ -210,7 +210,7 @@

(static)
Source:
@@ -280,7 +280,7 @@

(static) Source:
@@ -350,7 +350,7 @@

(protected) Source:
@@ -420,7 +420,7 @@

(protected) p
Source:
@@ -504,7 +504,7 @@

(static)
Source:
@@ -690,7 +690,7 @@

(static)
Source:
@@ -820,7 +820,7 @@

hasProxySource:
@@ -984,7 +984,7 @@

initia
Source:
@@ -1067,7 +1067,7 @@

register
Source:
@@ -1202,7 +1202,7 @@

removeProx
Source:
@@ -1362,7 +1362,7 @@

retrieve
Source:
@@ -1555,7 +1555,7 @@

new ModelSource:
@@ -1730,7 +1730,7 @@

(static)
Source:
@@ -1800,7 +1800,7 @@

(static) Source:
@@ -1870,7 +1870,7 @@

(protected) Source:
@@ -1940,7 +1940,7 @@

(protected) p
Source:
@@ -2024,7 +2024,7 @@

(static)
Source:
@@ -2210,7 +2210,7 @@

(static)
Source:
@@ -2340,7 +2340,7 @@

hasProxySource:
@@ -2504,7 +2504,7 @@

initia
Source:
@@ -2587,7 +2587,7 @@

register
Source:
@@ -2722,7 +2722,7 @@

removeProx
Source:
@@ -2882,7 +2882,7 @@

retrieve
Source:
@@ -3011,7 +3011,7 @@

Returns:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Notification.html b/docs/Notification.html index 93d9e73..916f367 100644 --- a/docs/Notification.html +++ b/docs/Notification.html @@ -215,7 +215,7 @@

bodySource:
@@ -279,7 +279,7 @@

bodySource:
@@ -343,7 +343,7 @@

nameSource:
@@ -407,7 +407,7 @@

typeSource:
@@ -471,7 +471,7 @@

typeSource:
@@ -545,7 +545,7 @@

toStringSource:
@@ -678,7 +678,7 @@

new Notif
Source:
@@ -928,7 +928,7 @@

bodySource:
@@ -992,7 +992,7 @@

bodySource:
@@ -1056,7 +1056,7 @@

nameSource:
@@ -1120,7 +1120,7 @@

typeSource:
@@ -1184,7 +1184,7 @@

typeSource:
@@ -1258,7 +1258,7 @@

toStringSource:
@@ -1331,7 +1331,7 @@
Returns:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Notifier.html b/docs/Notifier.html index b713367..6d82404 100644 --- a/docs/Notifier.html +++ b/docs/Notifier.html @@ -229,7 +229,7 @@

(static) Source:
@@ -293,7 +293,7 @@

facadeSource:
@@ -377,7 +377,7 @@

ini
Source:
@@ -514,7 +514,7 @@

sendN
Source:
@@ -716,7 +716,7 @@

Parameters:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Observer.html b/docs/Observer.html index d7c706a..c239cf6 100644 --- a/docs/Observer.html +++ b/docs/Observer.html @@ -204,7 +204,7 @@

notifyCo
Source:
@@ -268,7 +268,7 @@

notifyCo
Source:
@@ -332,7 +332,7 @@

notifyMet
Source:
@@ -397,7 +397,7 @@

notifyMet
Source:
@@ -471,7 +471,7 @@

c
Source:
@@ -627,7 +627,7 @@

notifyO
Source:
@@ -793,7 +793,7 @@

new Observer<
Source:
@@ -1005,7 +1005,7 @@

notifyCo
Source:
@@ -1069,7 +1069,7 @@

notifyCo
Source:
@@ -1133,7 +1133,7 @@

notifyMet
Source:
@@ -1198,7 +1198,7 @@

notifyMet
Source:
@@ -1272,7 +1272,7 @@

c
Source:
@@ -1428,7 +1428,7 @@

notifyO
Source:
@@ -1532,7 +1532,7 @@

Parameters:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/Proxy.html b/docs/Proxy.html index 2b8a042..8559649 100644 --- a/docs/Proxy.html +++ b/docs/Proxy.html @@ -1566,7 +1566,7 @@

onRemove
- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/SimpleCommand.html b/docs/SimpleCommand.html index 72b785e..fb1a128 100644 --- a/docs/SimpleCommand.html +++ b/docs/SimpleCommand.html @@ -321,7 +321,7 @@
Parameters:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/View.html b/docs/View.html index bd54345..2b1ebd4 100644 --- a/docs/View.html +++ b/docs/View.html @@ -211,7 +211,7 @@

(static)
Source:
@@ -285,7 +285,7 @@

(static) Source:
@@ -355,7 +355,7 @@

(protected) Source:
@@ -425,7 +425,7 @@

(protected) Source:
@@ -495,7 +495,7 @@

(protected) Source:
@@ -579,7 +579,7 @@

(static)
Source:
@@ -765,7 +765,7 @@

(static) r
Source:
@@ -895,7 +895,7 @@

hasMediato
Source:
@@ -1059,7 +1059,7 @@

initial
Source:
@@ -1145,7 +1145,7 @@

notify
Source:
@@ -1288,7 +1288,7 @@

regis
Source:
@@ -1424,7 +1424,7 @@

regis
Source:
@@ -1585,7 +1585,7 @@

removeM
Source:
@@ -1745,7 +1745,7 @@

removeO
Source:
@@ -1906,7 +1906,7 @@

retri
Source:
@@ -2099,7 +2099,7 @@

new ViewSource:
@@ -2274,7 +2274,7 @@

(static)
Source:
@@ -2348,7 +2348,7 @@

(static) Source:
@@ -2418,7 +2418,7 @@

(protected) Source:
@@ -2488,7 +2488,7 @@

(protected) Source:
@@ -2558,7 +2558,7 @@

(protected) Source:
@@ -2642,7 +2642,7 @@

(static)
Source:
@@ -2828,7 +2828,7 @@

(static) r
Source:
@@ -2958,7 +2958,7 @@

hasMediato
Source:
@@ -3122,7 +3122,7 @@

initial
Source:
@@ -3208,7 +3208,7 @@

notify
Source:
@@ -3351,7 +3351,7 @@

regis
Source:
@@ -3487,7 +3487,7 @@

regis
Source:
@@ -3648,7 +3648,7 @@

removeM
Source:
@@ -3808,7 +3808,7 @@

removeO
Source:
@@ -3969,7 +3969,7 @@

retri
Source:
@@ -4098,7 +4098,7 @@

Returns:

- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/core_Controller.js.html b/docs/core_Controller.js.html index d6a384a..fad0dbe 100644 --- a/docs/core_Controller.js.html +++ b/docs/core_Controller.js.html @@ -45,10 +45,10 @@

core/Controller.js

* * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {View} from "./View.js" -import {Observer} from "../patterns/observer/Observer.js"; +import { View } from "./View.js"; +import { Observer } from "../patterns/observer/Observer.js"; /** * A Multiton `Controller` implementation. @@ -85,156 +85,162 @@

core/Controller.js

* @class Controller */ class Controller { + /** + * Constructor. + * + * <P>This `Controller` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Factory method, + * passing the unique key for this instance + * `Controller.getInstance( multitonKey )`</P> + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key has already been constructed + */ + constructor(key) { + if (Controller.instanceMap[key] != null) + throw new Error(Controller.MULTITON_MSG); + /** @protected + * @type {string} */ + this.multitonKey = key; + Controller.instanceMap.set(this.multitonKey, this); + /** @protected + * @type {Map<string, function():SimpleCommand>} */ + this.commandMap = new Map(); + this.initializeController(); + } - /** - * Constructor. - * - * <P>This `Controller` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Controller.getInstance( multitonKey )`</P> - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Controller.instanceMap[key] != null) throw new Error(Controller.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Controller.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map<string, function():SimpleCommand>} */ - this.commandMap = new Map(); - this.initializeController(); - } - - /** - * Initialize the Multiton `Controller` instance. - * - * <P>Called automatically by the constructor.</P> - * - * <P>Note that if you are using a subclass of `View` - * in your application, you should <i>also</i> subclass `Controller` - * and override the `initializeController` method in the - * following way:</P> - * - * <pre>` - * // ensure that the Controller is talking to my View implementation - * initializeController( ) - * { - * this.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key)); - * } - * `</pre> - * - */ - initializeController() { - /** @protected - * @type {View} **/ - this.view = View.getInstance(this.multitonKey, (key) => new View(key)); - } + /** + * Initialize the Multiton `Controller` instance. + * + * <P>Called automatically by the constructor.</P> + * + * <P>Note that if you are using a subclass of `View` + * in your application, you should <i>also</i> subclass `Controller` + * and override the `initializeController` method in the + * following way:</P> + * + * <pre>` + * // ensure that the Controller is talking to my View implementation + * initializeController( ) + * { + * this.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key)); + * } + * `</pre> + * + */ + initializeController() { + /** @protected + * @type {View} **/ + this.view = View.getInstance(this.multitonKey, (key) => new View(key)); + } - /** - * `Controller` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Controller} factory - * @returns {Controller} the Multiton instance of `Controller` - */ - static getInstance(key, factory) { - if (Controller.instanceMap == null) - /** @static + /** + * `Controller` Multiton Factory method. + * + * @static + * @param {string} key + * @param {function(string):Controller} factory + * @returns {Controller} the Multiton instance of `Controller` + */ + static getInstance(key, factory) { + if (Controller.instanceMap == null) + /** @static @type {Map<string, Controller>} */ - Controller.instanceMap = new Map(); - if (Controller.instanceMap.get(key) == null) Controller.instanceMap.set(key, factory(key)); - return Controller.instanceMap.get(key); - } + Controller.instanceMap = new Map(); + if (Controller.instanceMap.get(key) == null) + Controller.instanceMap.set(key, factory(key)); + return Controller.instanceMap.get(key); + } - /** - * <P>If a `Command` has previously been registered - * to handle the given `Notification`, then it is executed.</P> - * - * @param {Notification} notification a `Notification` - */ - executeCommand(notification) { - let factory = this.commandMap.get(notification.name); - if (factory == null) return; + /** + * <P>If a `Command` has previously been registered + * to handle the given `Notification`, then it is executed.</P> + * + * @param {Notification} notification a `Notification` + */ + executeCommand(notification) { + let factory = this.commandMap.get(notification.name); + if (factory == null) return; - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } + let commandInstance = factory(); + commandInstance.initializeNotifier(this.multitonKey); + commandInstance.execute(notification); + } - /** - * <P>Register a particular `Command` class as the handler - * for a particular `Notification`.</P> - * - * <P>If an `Command` has already been registered to - * handle `Notification`s with this name, it is no longer - * used, the new `Command` is used instead.</P> - * - * <P>The Observer for the new Command is only created if this the - * first time a Command has been registered for this Notification name.</P> - * - * @param notificationName the name of the `Notification` - * @param {function():SimpleCommand} factory - */ - registerCommand(notificationName, factory) { - if (this.commandMap.get(notificationName) == null) { - this.view.registerObserver(notificationName, new Observer(this.executeCommand, this)); - } - this.commandMap.set(notificationName, factory); + /** + * <P>Register a particular `Command` class as the handler + * for a particular `Notification`.</P> + * + * <P>If an `Command` has already been registered to + * handle `Notification`s with this name, it is no longer + * used, the new `Command` is used instead.</P> + * + * <P>The Observer for the new Command is only created if this the + * first time a Command has been registered for this Notification name.</P> + * + * @param notificationName the name of the `Notification` + * @param {function():SimpleCommand} factory + */ + registerCommand(notificationName, factory) { + if (this.commandMap.get(notificationName) == null) { + this.view.registerObserver( + notificationName, + new Observer(this.executeCommand, this), + ); } + this.commandMap.set(notificationName, factory); + } - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @return {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.commandMap.has(notificationName); - } + /** + * Check if a Command is registered for a given Notification + * + * @param {string} notificationName + * @return {boolean} whether a Command is currently registered for the given `notificationName`. + */ + hasCommand(notificationName) { + return this.commandMap.has(notificationName); + } - /** - * Remove a previously registered `Command` to `Notification` mapping. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - // if the Command is registered... - if(this.hasCommand(notificationName)) { - // remove the observer - this.view.removeObserver(notificationName, this); + /** + * Remove a previously registered `Command` to `Notification` mapping. + * + * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for + */ + removeCommand(notificationName) { + // if the Command is registered... + if (this.hasCommand(notificationName)) { + // remove the observer + this.view.removeObserver(notificationName, this); - // remove the command - this.commandMap.delete(notificationName) - } + // remove the command + this.commandMap.delete(notificationName); } + } - /** - * Remove a Controller instance - * - * @static - * @param {string} key of Controller instance to remove - */ - static removeController(key) { - Controller.instanceMap.delete(key); - } + /** + * Remove a Controller instance + * + * @static + * @param {string} key of Controller instance to remove + */ + static removeController(key) { + Controller.instanceMap.delete(key); + } - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Controller instance for this Multiton key already constructed!" }; + /** + * Message Constants + * + * @static + * @type {string} + */ + static get MULTITON_MSG() { + return "Controller instance for this Multiton key already constructed!"; + } } -export { Controller } +export { Controller }; @@ -247,7 +253,7 @@

core/Controller.js


- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/core_Model.js.html b/docs/core_Model.js.html index dfd3b16..33b94c3 100644 --- a/docs/core_Model.js.html +++ b/docs/core_Model.js.html @@ -45,7 +45,7 @@

core/Model.js

* * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ /** * A Multiton `Model` implementation. @@ -72,125 +72,125 @@

core/Model.js

* @class Model */ class Model { - - /** - * Constructor. - * - * <P>This `Model` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `Model.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key instance has already been constructed - */ - constructor(key) { - if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Model.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map<string, Proxy>} */ - this.proxyMap = new Map(); - this.initializeModel(); - } - - /** - * Initialize the `Model` instance. - * - * <P>Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.</P> - * - */ - initializeModel() { - - } - - /** - * `Model` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Model} factory - * @returns {Model} the instance for this Multiton key - */ - static getInstance(key, factory) { - if (Model.instanceMap == null) - /** @static + /** + * Constructor. + * + * <P>This `Model` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Multiton + * Factory method `Model.getInstance( multitonKey )` + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key instance has already been constructed + */ + constructor(key) { + if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG); + /** @protected + * @type {string} */ + this.multitonKey = key; + Model.instanceMap.set(this.multitonKey, this); + /** @protected + * @type {Map<string, Proxy>} */ + this.proxyMap = new Map(); + this.initializeModel(); + } + + /** + * Initialize the `Model` instance. + * + * <P>Called automatically by the constructor, this + * is your opportunity to initialize the Multiton + * instance in your subclass without overriding the + * constructor.</P> + * + */ + initializeModel() {} + + /** + * `Model` Multiton Factory method. + * + * @static + * @param {string} key + * @param {function(string):Model} factory + * @returns {Model} the instance for this Multiton key + */ + static getInstance(key, factory) { + if (Model.instanceMap == null) + /** @static @type {Map<string, Model>} */ - Model.instanceMap = new Map(); - if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key)); - return Model.instanceMap.get(key); - } - - /** - * Register a `Proxy` with the `Model`. - * - * @param {Proxy} proxy a `Proxy` to be held by the `Model`. - */ - registerProxy(proxy) { - proxy.initializeNotifier(this.multitonKey); - this.proxyMap.set(proxy.proxyName, proxy); - proxy.onRegister(); + Model.instanceMap = new Map(); + if (Model.instanceMap.get(key) == null) + Model.instanceMap.set(key, factory(key)); + return Model.instanceMap.get(key); + } + + /** + * Register a `Proxy` with the `Model`. + * + * @param {Proxy} proxy a `Proxy` to be held by the `Model`. + */ + registerProxy(proxy) { + proxy.initializeNotifier(this.multitonKey); + this.proxyMap.set(proxy.proxyName, proxy); + proxy.onRegister(); + } + + /** + * Retrieve a `Proxy` from the `Model`. + * + * @param {string} proxyName + * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. + */ + retrieveProxy(proxyName) { + return this.proxyMap.get(proxyName) || null; + } + + /** + * Check if a Proxy is registered + * + * @param {string} proxyName + * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. + */ + hasProxy(proxyName) { + return this.proxyMap.has(proxyName); + } + + /** + * Remove a `Proxy` from the `Model`. + * + * @param {string} proxyName name of the `Proxy` instance to be removed. + * @returns {Proxy} the `Proxy` that was removed from the `Model` + */ + removeProxy(proxyName) { + let proxy = this.proxyMap.get(proxyName); + if (proxy != null) { + this.proxyMap.delete(proxyName); + proxy.onRemove(); } - - /** - * Retrieve a `Proxy` from the `Model`. - * - * @param {string} proxyName - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.proxyMap.get(proxyName) || null; - } - - /** - * Check if a Proxy is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.proxyMap.has(proxyName); - } - - /** - * Remove a `Proxy` from the `Model`. - * - * @param {string} proxyName name of the `Proxy` instance to be removed. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - let proxy = this.proxyMap.get(proxyName); - if (proxy != null) { - this.proxyMap.delete(proxyName); - proxy.onRemove(); - } - return proxy; - } - - /** - * Remove a Model instance - * - * @static - * @param key - */ - static removeModel(key) { - Model.instanceMap.delete(key); - } - - /** - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Model instance for this Multiton key already constructed!" }; + return proxy; + } + + /** + * Remove a Model instance + * + * @static + * @param key + */ + static removeModel(key) { + Model.instanceMap.delete(key); + } + + /** + * @static + * @type {string} + */ + static get MULTITON_MSG() { + return "Model instance for this Multiton key already constructed!"; + } } -export { Model } +export { Model }; @@ -203,7 +203,7 @@

core/Model.js


- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/core_View.js.html b/docs/core_View.js.html index 9a91eba..e1356f4 100644 --- a/docs/core_View.js.html +++ b/docs/core_View.js.html @@ -45,9 +45,9 @@

core/View.js

* * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {Observer} from "../patterns/observer/Observer.js"; +import { Observer } from "../patterns/observer/Observer.js"; /** * A Multiton `View` implementation. @@ -71,240 +71,242 @@

core/View.js

* @class View */ class View { - - /** - * Constructor. - * - * <P>This `View` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `View.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - View.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map<string, Mediator>} */ - this.mediatorMap = new Map(); - /** @protected - * @type {Map.<string, Array.<Observer>>} */ - this.observerMap = new Map(); - this.initializeView(); + /** + * Constructor. + * + * <P>This `View` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Multiton + * Factory method `View.getInstance( multitonKey )` + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key has already been constructed + */ + constructor(key) { + if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG); + /** @protected + * @type {string} */ + this.multitonKey = key; + View.instanceMap.set(this.multitonKey, this); + /** @protected + * @type {Map<string, Mediator>} */ + this.mediatorMap = new Map(); + /** @protected + * @type {Map.<string, Array.<Observer>>} */ + this.observerMap = new Map(); + this.initializeView(); + } + + /** + * <P>Initialize the Multiton View instance.</P> + * + * <P>Called automatically by the constructor, this + * is your opportunity to initialize the Multiton + * instance in your subclass without overriding the + * constructor.</P> + */ + initializeView() {} + + /** + * View Multiton factory method. + * + * @static + * @param {string} key + * @param {function(string):View} factory + * @returns {View} the Multiton instance of `View` + */ + static getInstance(key, factory) { + if (View.instanceMap == null) + /** @static + * @type {Map<string, View>} */ + View.instanceMap = new Map(); + if (View.instanceMap.get(key) == null) + View.instanceMap.set(key, factory(key)); + return View.instanceMap.get(key); + } + + /** + * <P>Register an `Observer` to be notified + * of `Notifications` with a given name.</P> + * + * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of + * @param {Observer} observer the `Observer` to register + */ + registerObserver(notificationName, observer) { + if (this.observerMap.get(notificationName) != null) { + let observers = this.observerMap.get(notificationName); + observers.push(observer); + } else { + this.observerMap.set(notificationName, new Array(observer)); } - - /** - * <P>Initialize the Multiton View instance.</P> - * - * <P>Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.</P> - */ - initializeView() { - + } + + /** + * <P>Notify the `Observers` for a particular `Notification`.</P> + * + * <P>All previously attached `Observers` for this `Notification`'s + * list are notified and are passed a reference to the `Notification` in + * the order in which they were registered.</P> + * + * @param {Notification} notification the `Notification` to notify `Observers` of. + */ + notifyObservers(notification) { + if (this.observerMap.has(notification.name)) { + // Copy observers from reference array to working array, + // since the reference array may change during the notification loop + let observers = this.observerMap.get(notification.name).slice(); + + // Notify Observers from the working array + for (let i = 0; i < observers.length; i++) { + observers[i].notifyObserver(notification); + } } - - /** - * View Multiton factory method. - * - * @static - * @param {string} key - * @param {function(string):View} factory - * @returns {View} the Multiton instance of `View` - */ - static getInstance(key, factory) { - if (View.instanceMap == null) - /** @static - * @type {Map<string, View>} */ - View.instanceMap = new Map(); - if (View.instanceMap.get(key) == null) View.instanceMap.set(key, factory(key)); - return View.instanceMap.get(key); + } + + /** + * <P>Remove the observer for a given notifyContext from an observer list for a given Notification name.</P> + * + * @param {string} notificationName which observer list to remove from + * @param {Object} notifyContext remove the observer with this object as its notifyContext + */ + removeObserver(notificationName, notifyContext) { + // the observer list for the notification under inspection + let observers = this.observerMap.get(notificationName); + + // find the observer for the notifyContext + for (let i = 0; i < observers.length; i++) { + if (observers[i].compareNotifyContext(notifyContext) === true) { + // there can only be one Observer for a given notifyContext + // in any given Observer list, so remove it and break + observers.splice(i, 1); + break; + } } - /** - * <P>Register an `Observer` to be notified - * of `Notifications` with a given name.</P> - * - * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of - * @param {Observer} observer the `Observer` to register - */ - registerObserver(notificationName, observer) { - if (this.observerMap.get(notificationName) != null) { - let observers = this.observerMap.get(notificationName); - observers.push(observer); - } else { - this.observerMap.set(notificationName, new Array(observer)); - } + // Also, when a Notification's Observer list length falls to + // zero, delete the notification key from the observer map + if (observers.length === 0) { + this.observerMap.delete(notificationName); } - - /** - * <P>Notify the `Observers` for a particular `Notification`.</P> - * - * <P>All previously attached `Observers` for this `Notification`'s - * list are notified and are passed a reference to the `Notification` in - * the order in which they were registered.</P> - * - * @param {Notification} notification the `Notification` to notify `Observers` of. - */ - notifyObservers(notification) { - if (this.observerMap.has(notification.name)) { - // Copy observers from reference array to working array, - // since the reference array may change during the notification loop - let observers = this.observerMap.get(notification.name).slice(); - - // Notify Observers from the working array - for(let i = 0; i < observers.length; i++) { - observers[i].notifyObserver(notification); - } - } - } - - /** - * <P>Remove the observer for a given notifyContext from an observer list for a given Notification name.</P> - * - * @param {string} notificationName which observer list to remove from - * @param {Object} notifyContext remove the observer with this object as its notifyContext - */ - removeObserver(notificationName, notifyContext) { - // the observer list for the notification under inspection - let observers = this.observerMap.get(notificationName); - - // find the observer for the notifyContext - for (let i = 0; i < observers.length; i++) { - if (observers[i].compareNotifyContext(notifyContext) === true) { - // there can only be one Observer for a given notifyContext - // in any given Observer list, so remove it and break - observers.splice(i, 1); - break; - } - } - - // Also, when a Notification's Observer list length falls to - // zero, delete the notification key from the observer map - if (observers.length === 0) { - this.observerMap.delete(notificationName); - } + } + + /** + * Register a `Mediator` instance with the `View`. + * + * <P>Registers the `Mediator` so that it can be retrieved by name, + * and further interrogates the `Mediator` for its + * `Notification` interests.</P> + * + * <P>If the `Mediator` returns any `Notification` + * names to be notified about, an `Observer` is created encapsulating + * the `Mediator` instance's `handleNotification` method + * and registering it as an `Observer` for all `Notifications` the + * `Mediator` is interested in.</p> + * + * @param {Mediator} mediator a reference to the `Mediator` instance + */ + registerMediator(mediator) { + // do not allow re-registration (you must to removeMediator fist) + if (this.mediatorMap.has(mediator.mediatorName) !== false) return; + + mediator.initializeNotifier(this.multitonKey); + + // Register the Mediator for retrieval by name + this.mediatorMap.set(mediator.mediatorName, mediator); + + // Get Notification interests, if any. + let interests = mediator.listNotificationInterests(); + + // Register Mediator as an observer for each notification of interests + if (interests.length > 0) { + // Create Observer referencing this mediator's handleNotification method + let observer = new Observer( + mediator.handleNotification.bind(mediator), + mediator, + ); // check bind + + // Register Mediator as Observer for its list of Notification interests + for (let i = 0; i < interests.length; i++) { + this.registerObserver(interests[i], observer); + } } - /** - * Register a `Mediator` instance with the `View`. - * - * <P>Registers the `Mediator` so that it can be retrieved by name, - * and further interrogates the `Mediator` for its - * `Notification` interests.</P> - * - * <P>If the `Mediator` returns any `Notification` - * names to be notified about, an `Observer` is created encapsulating - * the `Mediator` instance's `handleNotification` method - * and registering it as an `Observer` for all `Notifications` the - * `Mediator` is interested in.</p> - * - * @param {Mediator} mediator a reference to the `Mediator` instance - */ - registerMediator(mediator) { - // do not allow re-registration (you must to removeMediator fist) - if (this.mediatorMap.has(mediator.mediatorName) !== false) return; - - mediator.initializeNotifier(this.multitonKey); - - // Register the Mediator for retrieval by name - this.mediatorMap.set(mediator.mediatorName, mediator); - - // Get Notification interests, if any. - let interests = mediator.listNotificationInterests(); - - // Register Mediator as an observer for each notification of interests - if (interests.length > 0) { - // Create Observer referencing this mediator's handleNotification method - let observer = new Observer(mediator.handleNotification.bind(mediator), mediator); // check bind - - // Register Mediator as Observer for its list of Notification interests - for (let i = 0; i < interests.length; i++) { - this.registerObserver(interests[i], observer); - } - } - - // alert the mediator that it has been registered - mediator.onRegister(); + // alert the mediator that it has been registered + mediator.onRegister(); + } + + /** + * Retrieve a `Mediator` from the `View`. + * + * @param {string} mediatorName the name of the `Mediator` instance to retrieve. + * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`. + */ + retrieveMediator(mediatorName) { + return this.mediatorMap.get(mediatorName) || null; + } + + /** + * Remove a `Mediator` from the `View`. + * + * @param {string} mediatorName name of the `Mediator` instance to be removed. + * @returns {Mediator} the `Mediator` that was removed from the `View` + */ + removeMediator(mediatorName) { + // Retrieve the named mediator + let mediator = this.mediatorMap.get(mediatorName); + + if (mediator) { + // for every notification this mediator is interested in... + let interests = mediator.listNotificationInterests(); + for (let i = 0; i < interests.length; i++) { + // remove the observer linking the mediator + // to the notification interest + this.removeObserver(interests[i], mediator); + } + + // remove the mediator from the map + this.mediatorMap.delete(mediatorName); + + // alert the mediator that it has been removed + mediator.onRemove(); } - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName the name of the `Mediator` instance to retrieve. - * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.mediatorMap.get(mediatorName) || null; - } - - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` instance to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - // Retrieve the named mediator - let mediator = this.mediatorMap.get(mediatorName); - - if (mediator) { - // for every notification this mediator is interested in... - let interests = mediator.listNotificationInterests(); - for (let i = 0; i < interests.length; i++) { - // remove the observer linking the mediator - // to the notification interest - this.removeObserver(interests[i], mediator); - } - - // remove the mediator from the map - this.mediatorMap.delete(mediatorName); - - // alert the mediator that it has been removed - mediator.onRemove(); - } - - return mediator; - } - - /** - * Check if a Mediator is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.mediatorMap.has(mediatorName); - } - - /** - * Remove a View instance - * - * @static - * @param key multitonKey of View instance to remove - */ - static removeView(key) { - this.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "View instance for this Multiton key already constructed!" }; - + return mediator; + } + + /** + * Check if a Mediator is registered or not + * + * @param {string} mediatorName + * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. + */ + hasMediator(mediatorName) { + return this.mediatorMap.has(mediatorName); + } + + /** + * Remove a View instance + * + * @static + * @param key multitonKey of View instance to remove + */ + static removeView(key) { + this.instanceMap.delete(key); + } + + /** + * Message Constants + * + * @static + * @type {string} + */ + static get MULTITON_MSG() { + return "View instance for this Multiton key already constructed!"; + } } -export { View } +export { View }; @@ -317,7 +319,7 @@

core/View.js


- Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
diff --git a/docs/index.html b/docs/index.html index 421f7c0..d4a7969 100644 --- a/docs/index.html +++ b/docs/index.html @@ -60,7 +60,8 @@

Installation

Demos

Platforms / Technologies

@@ -73,7 +74,7 @@

Platforms / Technologies

  • React Native
  • Status

    -

    Production - Version 2.0.9

    +

    Production - Version 2.0.9

    Documentation

    • https://jsdoc.app/about-commandline.html
    • @@ -129,7 +130,7 @@

      License


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_command_MacroCommand.js.html b/docs/patterns_command_MacroCommand.js.html index 197113f..bf0a819 100644 --- a/docs/patterns_command_MacroCommand.js.html +++ b/docs/patterns_command_MacroCommand.js.html @@ -45,9 +45,9 @@

      patterns/command/MacroCommand.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {SimpleCommand} from "./SimpleCommand.js"; +import { SimpleCommand } from "./SimpleCommand.js"; /** * A base `Command` implementation that executes other `Command`s. @@ -74,82 +74,78 @@

      patterns/command/MacroCommand.js

      * @class MacroCommand */ class MacroCommand extends SimpleCommand { - - /** - * Constructor. - * - * <P>You should not need to define a constructor, - * instead, override the `initializeMacroCommand` - * method.</P> - * - * <P>If your subclass does define a constructor, be - * sure to call `super()`.</P> - * - * @constructor - */ - constructor() { - super(); - /** @protected - * @type {Array.<function():SimpleCommand>} */ - this.subCommands = []; - this.initializeMacroCommand(); - } - - /** - * Initialize the `MacroCommand`. - * - * <P>In your subclass, override this method to - * initialize the `MacroCommand`'s <i>SubCommand</i> - * list with `Command` class references like - * this:</P> - * - * <pre>` - * // Initialize MyMacroCommand - * initializeMacroCommand() { - * this.addSubCommand(() => new app.FirstCommand()); - * this.addSubCommand(() => new app.SecondCommand()); - * this.addSubCommand(() => new app.ThirdCommand()); - * } - * `</pre> - * - * <P>Note that <i>SubCommand</i>s may be any `Command` implementor, - * `MacroCommand`s or `SimpleCommands` are both acceptable. - */ - initializeMacroCommand() { - + /** + * Constructor. + * + * <P>You should not need to define a constructor, + * instead, override the `initializeMacroCommand` + * method.</P> + * + * <P>If your subclass does define a constructor, be + * sure to call `super()`.</P> + * + * @constructor + */ + constructor() { + super(); + /** @protected + * @type {Array.<function():SimpleCommand>} */ + this.subCommands = []; + this.initializeMacroCommand(); + } + + /** + * Initialize the `MacroCommand`. + * + * <P>In your subclass, override this method to + * initialize the `MacroCommand`'s <i>SubCommand</i> + * list with `Command` class references like + * this:</P> + * + * <pre>` + * // Initialize MyMacroCommand + * initializeMacroCommand() { + * this.addSubCommand(() => new app.FirstCommand()); + * this.addSubCommand(() => new app.SecondCommand()); + * this.addSubCommand(() => new app.ThirdCommand()); + * } + * `</pre> + * + * <P>Note that <i>SubCommand</i>s may be any `Command` implementor, + * `MacroCommand`s or `SimpleCommands` are both acceptable. + */ + initializeMacroCommand() {} + + /** + * Add a <i>SubCommand</i>. + * + * <P>The <i>SubCommands</i> will be called in First In/First Out (FIFO) + * order.</P> + * + * @param {function():SimpleCommand} factory + */ + addSubCommand(factory) { + this.subCommands.push(factory); + } + + /** + * Execute this `MacroCommand`'s <i>SubCommands</i>. + * + * <P>The <i>SubCommands</i> will be called in First In/First Out (FIFO) + * order.</P> + * + * @param {Notification} notification + */ + execute(notification) { + while (this.subCommands.length > 0) { + let factory = this.subCommands.shift(); + let commandInstance = factory(); + commandInstance.initializeNotifier(this.multitonKey); + commandInstance.execute(notification); } - - /** - * Add a <i>SubCommand</i>. - * - * <P>The <i>SubCommands</i> will be called in First In/First Out (FIFO) - * order.</P> - * - * @param {function():SimpleCommand} factory - */ - addSubCommand(factory) { - this.subCommands.push(factory); - } - - /** - * Execute this `MacroCommand`'s <i>SubCommands</i>. - * - * <P>The <i>SubCommands</i> will be called in First In/First Out (FIFO) - * order.</P> - * - * @param {Notification} notification - */ - execute(notification) { - while(this.subCommands.length > 0) { - let factory = this.subCommands.shift(); - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } - } - + } } -export { MacroCommand } +export { MacroCommand }; @@ -162,7 +158,7 @@

      patterns/command/MacroCommand.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_command_SimpleCommand.js.html b/docs/patterns_command_SimpleCommand.js.html index 1c150ab..c3fe502 100644 --- a/docs/patterns_command_SimpleCommand.js.html +++ b/docs/patterns_command_SimpleCommand.js.html @@ -45,9 +45,9 @@

      patterns/command/SimpleCommand.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {Notifier} from "../observer/Notifier.js"; +import { Notifier } from "../observer/Notifier.js"; /** * A base `Command` implementation. @@ -62,27 +62,24 @@

      patterns/command/SimpleCommand.js

      * @class SimpleCommand */ class SimpleCommand extends Notifier { - - constructor() { - super(); - } - - /** - * Fulfill the use-case initiated by the given `Notification`. - * - * <P>In the Command Pattern, an application use-case typically - * begins with some user action, which results in a `Notification` being broadcast, which - * is handled by business logic in the `execute` method of an - * `Command`.</P> - * - * @param {Notification} notification - */ - execute(notification) { - - } - + constructor() { + super(); + } + + /** + * Fulfill the use-case initiated by the given `Notification`. + * + * <P>In the Command Pattern, an application use-case typically + * begins with some user action, which results in a `Notification` being broadcast, which + * is handled by business logic in the `execute` method of an + * `Command`.</P> + * + * @param {Notification} notification + */ + // eslint-disable-next-line no-unused-vars + execute(notification) {} } -export { SimpleCommand } +export { SimpleCommand }; @@ -95,7 +92,7 @@

      patterns/command/SimpleCommand.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_facade_Facade.js.html b/docs/patterns_facade_Facade.js.html index 4a08b23..8b1955c 100644 --- a/docs/patterns_facade_Facade.js.html +++ b/docs/patterns_facade_Facade.js.html @@ -45,12 +45,12 @@

      patterns/facade/Facade.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {Controller} from "../../core/Controller.js"; -import {Model} from "../../core/Model.js"; -import {View} from "../../core/View.js"; -import {Notification} from "../observer/Notification.js"; +import { Controller } from "../../core/Controller.js"; +import { Model } from "../../core/Model.js"; +import { View } from "../../core/View.js"; +import { Notification } from "../observer/Notification.js"; /** * A base Multiton `Facade` implementation. @@ -62,321 +62,326 @@

      patterns/facade/Facade.js

      * @class Facade */ class Facade { - - /** - * Constructor. - * - * <P>This `Facade` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Facade.getInstance( multitonKey )`</P> - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG); - this.initializeNotifier(key); - Facade.instanceMap.set(this.multitonKey, this); - this.initializeFacade(); - } - - /** - * Initialize the Multiton `Facade` instance. - * - * <P>Called automatically by the constructor. Override in your - * subclass to do any subclass specific initializations. Be - * sure to call `super.initializeFacade()`, though.</P> - */ - initializeFacade() { - this.initializeModel(); - this.initializeController(); - this.initializeView(); - } - - /** - * Facade Multiton Factory method - * - * @static - * @param {string} key - * @param {function(string):Facade} factory - * @returns {Facade} the Multiton instance of the Facade - */ - static getInstance(key, factory) { - if (Facade.instanceMap == null) - /** @static - * @type {Map<string, Facade>} */ - Facade.instanceMap = new Map(); - if (Facade.instanceMap.get(key) == null) Facade.instanceMap.set(key, factory(key)); - return Facade.instanceMap.get(key); - } - - /** - * Initialize the `Model`. - * - * <P>Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:</P> - * - * <UL> - * <LI> You wish to initialize a different `Model`.</LI> - * <LI> You have `Proxy`s to register with the Model that do not - * retrieve a reference to the Facade at construction time.`</LI> - * </UL> - * - * If you don't want to initialize a different `Model`, - * call `super.initializeModel()` at the beginning of your - * method, then register `Proxy`s. - * - * <P>Note: This method is <i>rarely</i> overridden; in practice you are more - * likely to use a `Command` to create and register `Proxy`s - * with the `Model`, since `Proxy`s with mutable data will likely - * need to send `Notification`s and thus will likely want to fetch a reference to - * the `Facade` during their construction.</P> - */ - initializeModel() { - if (this.model != null) return; - this.model = Model.getInstance(this.multitonKey, key => new Model(key)); - } - - /** - * Initialize the `Controller`. - * - * <P>Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:</P> - * - * <UL> - * <LI> You wish to initialize a different `Controller`.</LI> - * <LI> You have `Commands` to register with the `Controller` at startup.`. </LI> - * </UL> - * - * <P>If you don't want to initialize a different `Controller`, - * call `super.initializeController()` at the beginning of your - * method, then register `Command`s.</P> - */ - initializeController() { - if (this.controller != null) return; - this.controller = Controller.getInstance(this.multitonKey, key => new Controller(key)); - } - - /** - * Initialize the `View`. - * - * <P>Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:</P> - * - * <UL> - * <LI> You wish to initialize a different `View`.</LI> - * <LI> You have `Observers` to register with the `View`</LI> - * </UL> - * - * <P>If you don't want to initialize a different `View`, - * call `super.initializeView()` at the beginning of your - * method, then register `Mediator` instances.</P> - * - * <P>Note: This method is <i>rarely</i> overridden; in practice you are more - * likely to use a `Command` to create and register `Mediator`s - * with the `View`, since `Mediator` instances will need to send - * `Notification`s and thus will likely want to fetch a reference - * to the `Facade` during their construction.</P> - */ - initializeView() { - if (this.view != null) return; - this.view = View.getInstance(this.multitonKey, key => new View(key)); - } - - /** - * Register a `Command` with the `Controller` by Notification name. - * - * @param {string} notificationName the name of the `Notification` to associate the `Command` with - * @param {function():SimpleCommand} factory a reference to the factory of the `Command` - */ - registerCommand(notificationName, factory) { - this.controller.registerCommand(notificationName, factory); - } - - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @returns {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.controller.hasCommand(notificationName); - } - - /** - * Remove a previously registered `Command` to `Notification` mapping from the Controller. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - this.controller.removeCommand(notificationName); - } - - /** - * Register a `Proxy` with the `Model` by name. - * - * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`. - */ - registerProxy(proxy) { - this.model.registerProxy(proxy); - } - - /** - * Remove a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the `Proxy` to remove from the `Model`. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - return this.model.removeProxy(proxyName); - } - - /** - * Check if a `Proxy` is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.model.hasProxy(proxyName); - } - - /** - * Retrieve a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the name of the proxy to be retrieved. - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.model.retrieveProxy(proxyName); - } - - /** - * Register a `Mediator` with the `View`. - * - * @param {Mediator} mediator a reference to the `Mediator` - */ - registerMediator(mediator) { - this.view.registerMediator(mediator); - } - - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - return this.view.removeMediator(mediatorName); - } - - /** - * Check if a `Mediator` is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.view.hasMediator(mediatorName); - } - - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName - * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.view.retrieveMediator(mediatorName); - } - - /** - * Create and send an `Notification`. - * - * <P>Keeps us from having to construct new notification - * instances in our implementation code.</P> - * - * @param {string} notificationName the name of the notification to send - * @param {Object} [body] body the body of the notification (optional) - * @param {string} [type] type the type of the notification (optional) - */ - sendNotification(notificationName, body = null, type = "") { - this.notifyObservers(new Notification(notificationName, body, type)); - } - - /** - * Notify `Observer`s. - * - * <P>This method is left public mostly for backward - * compatibility, and to allow you to send custom - * notification classes using the facade.</P> - * - * <P>Usually you should just call `sendNotification` - * and pass the parameters, never having to - * construct the notification yourself.</P> - * - * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of. - */ - notifyObservers(notification) { - this.view.notifyObservers(notification); - } - - /** - * Set the Multiton key for this facade instance. - * - * <P>Not called directly, but instead from the - * constructor when getInstance is invoked. - * It is necessary to be public in order to - * implement Notifier.</P> - */ - initializeNotifier(key) { - this.multitonKey = key; - } - - /** - * Check if a Core is registered or not - * - * @static - * @param {string} key the multiton key for the Core in question - * @returns {boolean} whether a Core is registered with the given `key`. - */ - static hasCore(key) { - return this.instanceMap.has(key); - } - - /** - * Remove a Core. - * - * <P>Remove the Model, View, Controller and Facade - * instances for the given key.</P> - * - * @static - * @param {string} key multitonKey of the Core to remove - */ - static removeCore(key) { - if (Facade.instanceMap.get(key) == null) return; - Model.removeModel(key); - View.removeView(key); - Controller.removeController(key); - this.instanceMap.delete(key); - } - - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() {return "Facade instance for this Multiton key already constructed!"}; + /** + * Constructor. + * + * <P>This `Facade` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Factory method, + * passing the unique key for this instance + * `Facade.getInstance( multitonKey )`</P> + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key has already been constructed + */ + constructor(key) { + if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG); + this.initializeNotifier(key); + Facade.instanceMap.set(this.multitonKey, this); + this.initializeFacade(); + } + + /** + * Initialize the Multiton `Facade` instance. + * + * <P>Called automatically by the constructor. Override in your + * subclass to do any subclass specific initializations. Be + * sure to call `super.initializeFacade()`, though.</P> + */ + initializeFacade() { + this.initializeModel(); + this.initializeController(); + this.initializeView(); + } + + /** + * Facade Multiton Factory method + * + * @static + * @param {string} key + * @param {function(string):Facade} factory + * @returns {Facade} the Multiton instance of the Facade + */ + static getInstance(key, factory) { + if (Facade.instanceMap == null) + /** @static + * @type {Map<string, Facade>} */ + Facade.instanceMap = new Map(); + if (Facade.instanceMap.get(key) == null) + Facade.instanceMap.set(key, factory(key)); + return Facade.instanceMap.get(key); + } + + /** + * Initialize the `Model`. + * + * <P>Called by the `initializeFacade` method. + * Override this method in your subclass of `Facade` + * if one or both of the following are true:</P> + * + * <UL> + * <LI> You wish to initialize a different `Model`.</LI> + * <LI> You have `Proxy`s to register with the Model that do not + * retrieve a reference to the Facade at construction time.`</LI> + * </UL> + * + * If you don't want to initialize a different `Model`, + * call `super.initializeModel()` at the beginning of your + * method, then register `Proxy`s. + * + * <P>Note: This method is <i>rarely</i> overridden; in practice you are more + * likely to use a `Command` to create and register `Proxy`s + * with the `Model`, since `Proxy`s with mutable data will likely + * need to send `Notification`s and thus will likely want to fetch a reference to + * the `Facade` during their construction.</P> + */ + initializeModel() { + if (this.model != null) return; + this.model = Model.getInstance(this.multitonKey, (key) => new Model(key)); + } + + /** + * Initialize the `Controller`. + * + * <P>Called by the `initializeFacade` method. + * Override this method in your subclass of `Facade` + * if one or both of the following are true:</P> + * + * <UL> + * <LI> You wish to initialize a different `Controller`.</LI> + * <LI> You have `Commands` to register with the `Controller` at startup.`. </LI> + * </UL> + * + * <P>If you don't want to initialize a different `Controller`, + * call `super.initializeController()` at the beginning of your + * method, then register `Command`s.</P> + */ + initializeController() { + if (this.controller != null) return; + this.controller = Controller.getInstance( + this.multitonKey, + (key) => new Controller(key), + ); + } + + /** + * Initialize the `View`. + * + * <P>Called by the `initializeFacade` method. + * Override this method in your subclass of `Facade` + * if one or both of the following are true:</P> + * + * <UL> + * <LI> You wish to initialize a different `View`.</LI> + * <LI> You have `Observers` to register with the `View`</LI> + * </UL> + * + * <P>If you don't want to initialize a different `View`, + * call `super.initializeView()` at the beginning of your + * method, then register `Mediator` instances.</P> + * + * <P>Note: This method is <i>rarely</i> overridden; in practice you are more + * likely to use a `Command` to create and register `Mediator`s + * with the `View`, since `Mediator` instances will need to send + * `Notification`s and thus will likely want to fetch a reference + * to the `Facade` during their construction.</P> + */ + initializeView() { + if (this.view != null) return; + this.view = View.getInstance(this.multitonKey, (key) => new View(key)); + } + + /** + * Register a `Command` with the `Controller` by Notification name. + * + * @param {string} notificationName the name of the `Notification` to associate the `Command` with + * @param {function():SimpleCommand} factory a reference to the factory of the `Command` + */ + registerCommand(notificationName, factory) { + this.controller.registerCommand(notificationName, factory); + } + + /** + * Check if a Command is registered for a given Notification + * + * @param {string} notificationName + * @returns {boolean} whether a Command is currently registered for the given `notificationName`. + */ + hasCommand(notificationName) { + return this.controller.hasCommand(notificationName); + } + + /** + * Remove a previously registered `Command` to `Notification` mapping from the Controller. + * + * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for + */ + removeCommand(notificationName) { + this.controller.removeCommand(notificationName); + } + + /** + * Register a `Proxy` with the `Model` by name. + * + * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`. + */ + registerProxy(proxy) { + this.model.registerProxy(proxy); + } + + /** + * Remove a `Proxy` from the `Model` by name. + * + * @param {string} proxyName the `Proxy` to remove from the `Model`. + * @returns {Proxy} the `Proxy` that was removed from the `Model` + */ + removeProxy(proxyName) { + return this.model.removeProxy(proxyName); + } + + /** + * Check if a `Proxy` is registered + * + * @param {string} proxyName + * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. + */ + hasProxy(proxyName) { + return this.model.hasProxy(proxyName); + } + + /** + * Retrieve a `Proxy` from the `Model` by name. + * + * @param {string} proxyName the name of the proxy to be retrieved. + * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. + */ + retrieveProxy(proxyName) { + return this.model.retrieveProxy(proxyName); + } + + /** + * Register a `Mediator` with the `View`. + * + * @param {Mediator} mediator a reference to the `Mediator` + */ + registerMediator(mediator) { + this.view.registerMediator(mediator); + } + + /** + * Remove a `Mediator` from the `View`. + * + * @param {string} mediatorName name of the `Mediator` to be removed. + * @returns {Mediator} the `Mediator` that was removed from the `View` + */ + removeMediator(mediatorName) { + return this.view.removeMediator(mediatorName); + } + + /** + * Check if a `Mediator` is registered or not + * + * @param {string} mediatorName + * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. + */ + hasMediator(mediatorName) { + return this.view.hasMediator(mediatorName); + } + + /** + * Retrieve a `Mediator` from the `View`. + * + * @param {string} mediatorName + * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`. + */ + retrieveMediator(mediatorName) { + return this.view.retrieveMediator(mediatorName); + } + + /** + * Create and send an `Notification`. + * + * <P>Keeps us from having to construct new notification + * instances in our implementation code.</P> + * + * @param {string} notificationName the name of the notification to send + * @param {Object} [body] body the body of the notification (optional) + * @param {string} [type] type the type of the notification (optional) + */ + sendNotification(notificationName, body = null, type = "") { + this.notifyObservers(new Notification(notificationName, body, type)); + } + + /** + * Notify `Observer`s. + * + * <P>This method is left public mostly for backward + * compatibility, and to allow you to send custom + * notification classes using the facade.</P> + * + * <P>Usually you should just call `sendNotification` + * and pass the parameters, never having to + * construct the notification yourself.</P> + * + * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of. + */ + notifyObservers(notification) { + this.view.notifyObservers(notification); + } + + /** + * Set the Multiton key for this facade instance. + * + * <P>Not called directly, but instead from the + * constructor when getInstance is invoked. + * It is necessary to be public in order to + * implement Notifier.</P> + */ + initializeNotifier(key) { + this.multitonKey = key; + } + + /** + * Check if a Core is registered or not + * + * @static + * @param {string} key the multiton key for the Core in question + * @returns {boolean} whether a Core is registered with the given `key`. + */ + static hasCore(key) { + return this.instanceMap.has(key); + } + + /** + * Remove a Core. + * + * <P>Remove the Model, View, Controller and Facade + * instances for the given key.</P> + * + * @static + * @param {string} key multitonKey of the Core to remove + */ + static removeCore(key) { + if (Facade.instanceMap.get(key) == null) return; + Model.removeModel(key); + View.removeView(key); + Controller.removeController(key); + this.instanceMap.delete(key); + } + + /** + * Message Constants + * + * @static + * @returns {string} + */ + static get MULTITON_MSG() { + return "Facade instance for this Multiton key already constructed!"; + } } -export { Facade } +export { Facade }; @@ -389,7 +394,7 @@

      patterns/facade/Facade.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_mediator_Mediator.js.html b/docs/patterns_mediator_Mediator.js.html index b55bfb2..31e202e 100644 --- a/docs/patterns_mediator_Mediator.js.html +++ b/docs/patterns_mediator_Mediator.js.html @@ -45,9 +45,9 @@

      patterns/mediator/Mediator.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {Notifier} from "../observer/Notifier.js"; +import { Notifier } from "../observer/Notifier.js"; /** * A base `Mediator` implementation. @@ -57,103 +57,99 @@

      patterns/mediator/Mediator.js

      * @class Mediator */ class Mediator extends Notifier { - - /** - * Constructor. - * - * @constructor - * @param {string | null} [mediatorName=null] - * @param {Object | null} [viewComponent=null] - */ - constructor(mediatorName = null, viewComponent = null) { - super(); - this._mediatorName = mediatorName || Mediator.NAME; - this._viewComponent = viewComponent; - } - - /** - * Called by the View when the Mediator is registered - */ - onRegister() { - - } - - /** - * Called by the View when the Mediator is removed - */ - onRemove() { - - } - - /** - * List the `Notification` names this - * `Mediator` is interested in being notified of. - * - * @returns {string[]} - */ - listNotificationInterests() { - return []; - } - - /** - * Handle `Notification`s. - * - * <P> - * Typically this will be handled in a switch statement, - * with one 'case' entry per `Notification` - * the `Mediator` is interested in. - * - * @param {Notification} notification - */ - handleNotification(notification) { - - } - - /** - * the mediator name - * - * @returns {string} - */ - get mediatorName() { - return this._mediatorName; - } - - /** - * Get the `Mediator`'s view component. - * - * <P> - * Additionally, an implicit getter will usually - * be defined in the subclass that casts the view - * object to a type, like this:</P> - * - * @returns {Object | null} - */ - get viewComponent() { - return this._viewComponent; - } - - /** - * Set the `Mediator`'s view component. - * - * @param {Object} viewComponent - */ - set viewComponent(viewComponent) { - this._viewComponent = viewComponent; - } - - /** - * The name of the `Mediator`. - * - * <P>Typically, a `Mediator` will be written to serve - * one specific control or group controls and so, - * will not have a need to be dynamically named.</P> - * - * @static - * @returns {string} - */ - static get NAME() { return "Mediator" } + /** + * Constructor. + * + * @constructor + * @param {string | null} [mediatorName=null] + * @param {Object | null} [viewComponent=null] + */ + constructor(mediatorName = null, viewComponent = null) { + super(); + this._mediatorName = mediatorName || Mediator.NAME; + this._viewComponent = viewComponent; + } + + /** + * Called by the View when the Mediator is registered + */ + onRegister() {} + + /** + * Called by the View when the Mediator is removed + */ + onRemove() {} + + /** + * List the `Notification` names this + * `Mediator` is interested in being notified of. + * + * @returns {string[]} + */ + listNotificationInterests() { + return []; + } + + /** + * Handle `Notification`s. + * + * <P> + * Typically this will be handled in a switch statement, + * with one 'case' entry per `Notification` + * the `Mediator` is interested in. + * + * @param {Notification} notification + */ + // eslint-disable-next-line no-unused-vars + handleNotification(notification) {} + + /** + * the mediator name + * + * @returns {string} + */ + get mediatorName() { + return this._mediatorName; + } + + /** + * Get the `Mediator`'s view component. + * + * <P> + * Additionally, an implicit getter will usually + * be defined in the subclass that casts the view + * object to a type, like this:</P> + * + * @returns {Object | null} + */ + get viewComponent() { + return this._viewComponent; + } + + /** + * Set the `Mediator`'s view component. + * + * @param {Object} viewComponent + */ + set viewComponent(viewComponent) { + this._viewComponent = viewComponent; + } + + /** + * The name of the `Mediator`. + * + * <P>Typically, a `Mediator` will be written to serve + * one specific control or group controls and so, + * will not have a need to be dynamically named.</P> + * + * @static + * @returns {string} + */ + static get NAME() { + return "Mediator"; + } } -export { Mediator } +export { Mediator }; @@ -166,7 +162,7 @@

      patterns/mediator/Mediator.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_observer_Notification.js.html b/docs/patterns_observer_Notification.js.html index af88962..7f00794 100644 --- a/docs/patterns_observer_Notification.js.html +++ b/docs/patterns_observer_Notification.js.html @@ -45,7 +45,7 @@

      patterns/observer/Notification.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ /** * A base `Notification` implementation. @@ -78,80 +78,78 @@

      patterns/observer/Notification.js

      * @class Notification */ class Notification { - - /** - * Constructor. - * - * @constructor - * @param {string} name - The name of the notification. - * @param {Object|null} [body=null] - The body of the notification, defaults to `null`. - * @param {string} [type=""] - The type of the notification, defaults to an empty string. - */ - constructor(name, body = null, type = "") { - this._name = name; - this._body = body; - this._type = type; - } - - /** - * Get the name of the `Notification` instance. - * - * @returns {string} - */ - get name() { - return this._name; - } - - /** - * Get the body of the `Notification` instance. - * - * @returns {Object | null} - */ - get body() { - return this._body; - } - - /** - * Set the body of the `Notification` instance. - * - * @param {Object|null} body - */ - set body(body) { - this._body = body; - } - - /** - * Get the type of the `Notification` instance. - * - * @returns {string} - */ - get type() { - return this._type; - } - - /** - * Set the type of the `Notification` instance. - * - * @param {string} type - */ - set type(type) { - this._type = type; - } - - /** - * Get the string representation of the `Notification` instance. - * - * @returns {string} - */ - toString() { - let str= "Notification Name: " + this.name; - str+= "\nBody:" + ((this.body == null ) ? "null" : this.body.toString()); - str+= "\nType:" + ((this.type == null ) ? "null" : this.type); - return str; - } - + /** + * Constructor. + * + * @constructor + * @param {string} name - The name of the notification. + * @param {Object|null} [body=null] - The body of the notification, defaults to `null`. + * @param {string} [type=""] - The type of the notification, defaults to an empty string. + */ + constructor(name, body = null, type = "") { + this._name = name; + this._body = body; + this._type = type; + } + + /** + * Get the name of the `Notification` instance. + * + * @returns {string} + */ + get name() { + return this._name; + } + + /** + * Get the body of the `Notification` instance. + * + * @returns {Object | null} + */ + get body() { + return this._body; + } + + /** + * Set the body of the `Notification` instance. + * + * @param {Object|null} body + */ + set body(body) { + this._body = body; + } + + /** + * Get the type of the `Notification` instance. + * + * @returns {string} + */ + get type() { + return this._type; + } + + /** + * Set the type of the `Notification` instance. + * + * @param {string} type + */ + set type(type) { + this._type = type; + } + + /** + * Get the string representation of the `Notification` instance. + * + * @returns {string} + */ + toString() { + let str = "Notification Name: " + this.name; + str += "\nBody:" + (this.body == null ? "null" : this.body.toString()); + str += "\nType:" + (this.type == null ? "null" : this.type); + return str; + } } -export { Notification } +export { Notification }; @@ -164,7 +162,7 @@

      patterns/observer/Notification.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_observer_Notifier.js.html b/docs/patterns_observer_Notifier.js.html index 1135c5b..19695c2 100644 --- a/docs/patterns_observer_Notifier.js.html +++ b/docs/patterns_observer_Notifier.js.html @@ -45,9 +45,9 @@

      patterns/observer/Notifier.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {Facade} from "../facade/Facade.js"; +import { Facade } from "../facade/Facade.js"; /** * A Base `Notifier` implementation. @@ -84,67 +84,68 @@

      patterns/observer/Notifier.js

      * @class Notifier */ class Notifier { - - constructor() {} - - /** - * Create and send a `Notification`. - * - * <P>Keeps us from having to construct new Notification - * instances in our implementation code.</P> - * - * @param {string} notificationName - * @param {Object} [body] body - * @param {string} [type] type - */ - sendNotification (notificationName, body = null, type = "") { - if (this.facade != null) { - this.facade.sendNotification(notificationName, body, type); - } - } - - /** - * Initialize this Notifier instance. - * - * <P>This is how a Notifier gets its multitonKey. - * Calls to sendNotification or to access the - * facade will fail until after this method - * has been called.</P> - * - * <P>Mediators, Commands or Proxies may override - * this method in order to send notifications - * or access the Multiton Facade instance as - * soon as possible. They CANNOT access the facade - * in their constructors, since this method will not - * yet have been called.</P> - * - * @param {string} key the multitonKey for this Notifier to use - */ - initializeNotifier(key) { - this.multitonKey = key; + constructor() {} + + /** + * Create and send a `Notification`. + * + * <P>Keeps us from having to construct new Notification + * instances in our implementation code.</P> + * + * @param {string} notificationName + * @param {Object} [body] body + * @param {string} [type] type + */ + sendNotification(notificationName, body = null, type = "") { + if (this.facade != null) { + this.facade.sendNotification(notificationName, body, type); } - - /** - * Return the Multiton Facade instance - * - * @returns {Facade} - * - * @throws {Error} - */ - get facade() { - if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG); - return Facade.getInstance(this.multitonKey, key => new Facade(key)); - } - - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() { return "multitonKey for this Notifier not yet initialized!" } + } + + /** + * Initialize this Notifier instance. + * + * <P>This is how a Notifier gets its multitonKey. + * Calls to sendNotification or to access the + * facade will fail until after this method + * has been called.</P> + * + * <P>Mediators, Commands or Proxies may override + * this method in order to send notifications + * or access the Multiton Facade instance as + * soon as possible. They CANNOT access the facade + * in their constructors, since this method will not + * yet have been called.</P> + * + * @param {string} key the multitonKey for this Notifier to use + */ + initializeNotifier(key) { + this.multitonKey = key; + } + + /** + * Return the Multiton Facade instance + * + * @returns {Facade} + * + * @throws {Error} + */ + get facade() { + if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG); + return Facade.getInstance(this.multitonKey, (key) => new Facade(key)); + } + + /** + * Message Constants + * + * @static + * @returns {string} + */ + static get MULTITON_MSG() { + return "multitonKey for this Notifier not yet initialized!"; + } } -export { Notifier } +export { Notifier }; @@ -157,7 +158,7 @@

      patterns/observer/Notifier.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_observer_Observer.js.html b/docs/patterns_observer_Observer.js.html index 0e9e096..ac3298b 100644 --- a/docs/patterns_observer_Observer.js.html +++ b/docs/patterns_observer_Observer.js.html @@ -45,7 +45,7 @@

      patterns/observer/Observer.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ /** * A base `Observer` implementation. @@ -66,80 +66,78 @@

      patterns/observer/Observer.js

      * @class Observer */ class Observer { - - /** - * Constructor. - * - * <P>The notification method on the interested object should take - * one parameter of type `Notification`</P> - * - * @param {function(Notification):void | null} [notify = null] - * @param {Object | null} [context = null] - */ - constructor(notify = null, context = null) { - this._notifyMethod = notify; - this._notifyContext = context; - } - - /** - * Notify the interested object. - * - * @param {Notification} notification - */ - notifyObserver(notification) { - this._notifyMethod.call(this._notifyContext, notification); - } - - /** - * Compare an object to the notification context. - * - * @param {Object} notifyContext - * @returns {boolean} - */ - compareNotifyContext(notifyContext) { - return this._notifyContext === notifyContext; - } - - /** - * Get the notification method. - * - * @returns {function(Notification):void} - */ - get notifyMethod() { - return this._notifyMethod - } - - /** - * Set the notification method. - * - * <P>The notification method should take one parameter of type `Notification`.</P> - * - * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received. - */ - set notifyMethod(notifyMethod) { - this._notifyMethod = notifyMethod; - } - - /** - * Get the notifyContext - * - * @returns {Object} - */ - get notifyContext() { - return this._notifyContext; - } - - /** - * Set the notification context. - * - * @param {Object} notifyContext - */ - set notifyContext(notifyContext) { - this._notifyContext = notifyContext; - } - + /** + * Constructor. + * + * <P>The notification method on the interested object should take + * one parameter of type `Notification`</P> + * + * @param {function(Notification):void | null} [notify = null] + * @param {Object | null} [context = null] + */ + constructor(notify = null, context = null) { + this._notifyMethod = notify; + this._notifyContext = context; + } + + /** + * Notify the interested object. + * + * @param {Notification} notification + */ + notifyObserver(notification) { + this._notifyMethod.call(this._notifyContext, notification); + } + + /** + * Compare an object to the notification context. + * + * @param {Object} notifyContext + * @returns {boolean} + */ + compareNotifyContext(notifyContext) { + return this._notifyContext === notifyContext; + } + + /** + * Get the notification method. + * + * @returns {function(Notification):void} + */ + get notifyMethod() { + return this._notifyMethod; + } + + /** + * Set the notification method. + * + * <P>The notification method should take one parameter of type `Notification`.</P> + * + * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received. + */ + set notifyMethod(notifyMethod) { + this._notifyMethod = notifyMethod; + } + + /** + * Get the notifyContext + * + * @returns {Object} + */ + get notifyContext() { + return this._notifyContext; + } + + /** + * Set the notification context. + * + * @param {Object} notifyContext + */ + set notifyContext(notifyContext) { + this._notifyContext = notifyContext; + } } -export { Observer } +export { Observer }; @@ -152,7 +150,7 @@

      patterns/observer/Observer.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/docs/patterns_proxy_Proxy.js.html b/docs/patterns_proxy_Proxy.js.html index f97c53c..5e9126d 100644 --- a/docs/patterns_proxy_Proxy.js.html +++ b/docs/patterns_proxy_Proxy.js.html @@ -45,9 +45,9 @@

      patterns/proxy/Proxy.js

      * * Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org> * Your reuse is governed by the BSD License -*/ + */ -import {Notifier} from "../observer/Notifier.js"; +import { Notifier } from "../observer/Notifier.js"; /** * A base `Proxy` implementation. @@ -70,68 +70,70 @@

      patterns/proxy/Proxy.js

      * @class Proxy */ class Proxy extends Notifier { - /** - * Constructor - * - * @constructor - * @param {string | null} [proxyName=null] - * @param {Object | null} [data=null] - */ - constructor(proxyName = null, data = null) { - super(); - /** @protected - * @type {string} */ - this._proxyName = proxyName || Proxy.NAME; - /** @protected - * @type {Object | null} */ - this._data = data; - } - - /** - * Called by the Model when the Proxy is registered - */ - onRegister() {} - - /** - * Called by the Model when the Proxy is removed - */ - onRemove() {} - - /** - * Get the proxy name - * - * @returns {string} - */ - get proxyName() { - return this._proxyName; - } - - /** - * Get the data object - * - * @returns {Object | null} - */ - get data () { - return this._data; - } - - /** - * Set the data object - * - * @param {Object} data - */ - set data(data) { - this._data = data; - } - - /** - * - * @static - * @returns {string} - */ - static get NAME() { return "Proxy" } + /** + * Constructor + * + * @constructor + * @param {string | null} [proxyName=null] + * @param {Object | null} [data=null] + */ + constructor(proxyName = null, data = null) { + super(); + /** @protected + * @type {string} */ + this._proxyName = proxyName || Proxy.NAME; + /** @protected + * @type {Object | null} */ + this._data = data; + } + + /** + * Called by the Model when the Proxy is registered + */ + onRegister() {} + + /** + * Called by the Model when the Proxy is removed + */ + onRemove() {} + + /** + * Get the proxy name + * + * @returns {string} + */ + get proxyName() { + return this._proxyName; + } + + /** + * Get the data object + * + * @returns {Object | null} + */ + get data() { + return this._data; + } + + /** + * Set the data object + * + * @param {Object} data + */ + set data(data) { + this._data = data; + } + + /** + * + * @static + * @returns {string} + */ + static get NAME() { + return "Proxy"; + } } -export { Proxy } +export { Proxy }; @@ -144,7 +146,7 @@

      patterns/proxy/Proxy.js


      - Generated by JSDoc 3.6.11 on Tue Oct 29 2024 20:35:08 GMT-0400 (Eastern Daylight Time) using the Minami theme. + Generated by JSDoc 3.6.11 on Tue Nov 25 2025 17:18:49 GMT-0500 (Eastern Standard Time) using the Minami theme.
      diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..736e304 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,7 @@ +import js from "@eslint/js"; +import globals from "globals"; +import { defineConfig } from "eslint/config"; + +export default defineConfig([ + { files: ["**/*.{js,mjs,cjs}"], plugins: { js }, extends: ["js/recommended"], languageOptions: { globals: {...globals.browser, ...globals.node} } }, +]); diff --git a/package-lock.json b/package-lock.json index c2dd7ed..d75e446 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@puremvc/puremvc-js-multicore-framework", - "version": "2.0.9", + "version": "2.0.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@puremvc/puremvc-js-multicore-framework", - "version": "2.0.9", + "version": "2.0.10", "license": "BSD-3-Clause", "bin": { "index.cjs": "bin/cjs/index.cjs", @@ -25,12 +25,14 @@ "chromedriver": "^130.0.2", "dotenv": "^16.0.3", "edgedriver": "^5.3.8", + "eslint": "^9.39.1", "geckodriver": "^4.2.1", "jsdoc": "^3.6.11", "minami": "^1.2.3", "mocha": "10.1.0", "nightwatch": "^3.3.2", - "rollup": "^4.6.1" + "prettier": "^3.5.1", + "rollup": "4.22.4" } }, "../src": { @@ -58,6 +60,313 @@ "node": ">=0.1.90" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -197,169 +506,224 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.0.tgz", - "integrity": "sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.0.tgz", - "integrity": "sha512-im6hUEyQ7ZfoZdNvtwgEJvBWZYauC9KVKq1w58LG2Zfz6zMd8gRrbN+xCVoqA2hv/v6fm9lp5LFGJ3za8EQH3A==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", + "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.0.tgz", - "integrity": "sha512-u7aTMskN6Dmg1lCT0QJ+tINRt+ntUrvVkhbPfFz4bCwRZvjItx2nJtwJnJRlKMMaQCHRjrNqHRDYvE4mBm3DlQ==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", + "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.0.tgz", - "integrity": "sha512-8FvEl3w2ExmpcOmX5RJD0yqXcVSOqAJJUJ29Lca29Ik+3zPS1yFimr2fr5JSZ4Z5gt8/d7WqycpgkX9nocijSw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", + "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.0.tgz", - "integrity": "sha512-lHoKYaRwd4gge+IpqJHCY+8Vc3hhdJfU6ukFnnrJasEBUvVlydP8PuwndbWfGkdgSvZhHfSEw6urrlBj0TSSfg==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", + "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", + "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.0.tgz", - "integrity": "sha512-JbEPfhndYeWHfOSeh4DOFvNXrj7ls9S/2omijVsao+LBPTPayT1uKcK3dHW3MwDJ7KO11t9m2cVTqXnTKpeaiw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", + "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.0.tgz", - "integrity": "sha512-ahqcSXLlcV2XUBM3/f/C6cRoh7NxYA/W7Yzuv4bDU1YscTFw7ay4LmD7l6OS8EMhTNvcrWGkEettL1Bhjf+B+w==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", + "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", + "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.0.tgz", - "integrity": "sha512-uwvOYNtLw8gVtrExKhdFsYHA/kotURUmZYlinH2VcQxNCQJeJXnkmWgw2hI9Xgzhgu7J9QvWiq9TtTVwWMDa+w==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", + "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", + "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.0.tgz", - "integrity": "sha512-m6pkSwcZZD2LCFHZX/zW2aLIISyzWLU3hrLLzQKMI12+OLEzgruTovAxY5sCZJkipklaZqPy/2bEEBNjp+Y7xg==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", + "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.0.tgz", - "integrity": "sha512-VFAC1RDRSbU3iOF98X42KaVicAfKf0m0OvIu8dbnqhTe26Kh6Ym9JrDulz7Hbk7/9zGc41JkV02g+p3BivOdAg==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", + "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.0.tgz", - "integrity": "sha512-9jPgMvTKXARz4inw6jezMLA2ihDBvgIU9Ml01hjdVpOcMKyxFBJrn83KVQINnbeqDv0+HdO1c09hgZ8N0s820Q==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", + "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.0.tgz", - "integrity": "sha512-WE4pT2kTXQN2bAv40Uog0AsV7/s9nT9HBWXAou8+++MBCnY51QS02KYtm6dQxxosKi1VIz/wZIrTQO5UP2EW+Q==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", + "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.0.tgz", - "integrity": "sha512-aPP5Q5AqNGuT0tnuEkK/g4mnt3ZhheiXrDIiSVIHN9mcN21OyXDVbEMqmXPE7e2OplNLDkcvV+ZoGJa2ZImFgw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", + "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -383,6 +747,20 @@ "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", "dev": true }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", @@ -517,10 +895,11 @@ } }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -535,6 +914,16 @@ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -570,6 +959,23 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -1139,6 +1545,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -1558,6 +1974,44 @@ "node": ">= 10" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/cssstyle": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", @@ -2010,36 +2464,285 @@ "engines": { "node": ">=6.0" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=4.0" + "node": "*" } }, - "node_modules/escodegen/node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "optional": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -2068,6 +2771,52 @@ "node": ">=0.4.0" } }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", @@ -2129,12 +2878,33 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "dev": true }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-xml-parser": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", @@ -2189,6 +2959,19 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -2237,6 +3020,27 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -2800,6 +3604,16 @@ } ] }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -2807,6 +3621,33 @@ "dev": true, "license": "MIT" }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3464,6 +4305,27 @@ "jsesc": "bin/jsesc" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -3538,6 +4400,16 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -3616,6 +4488,20 @@ "node": ">=0.10.0" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -3693,6 +4579,13 @@ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -4040,6 +4933,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -4593,6 +5493,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -4797,6 +5715,19 @@ "dev": true, "license": "(MIT AND Zlib)" }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse5": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", @@ -4841,6 +5772,16 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -4878,6 +5819,32 @@ "nice-napi": "^1.0.2" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -5280,6 +6247,16 @@ "lodash": "^4.17.21" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -5294,10 +6271,14 @@ } }, "node_modules/rollup": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.0.tgz", - "integrity": "sha512-bUHW/9N21z64gw8s6tP4c88P382Bq/L5uZDowHlHx6s/QWpjJXivIAbEw6LZthgSvlEizZBfLC4OAvWe7aoF7A==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", + "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -5306,22 +6287,32 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.0", - "@rollup/rollup-android-arm64": "4.9.0", - "@rollup/rollup-darwin-arm64": "4.9.0", - "@rollup/rollup-darwin-x64": "4.9.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.0", - "@rollup/rollup-linux-arm64-gnu": "4.9.0", - "@rollup/rollup-linux-arm64-musl": "4.9.0", - "@rollup/rollup-linux-riscv64-gnu": "4.9.0", - "@rollup/rollup-linux-x64-gnu": "4.9.0", - "@rollup/rollup-linux-x64-musl": "4.9.0", - "@rollup/rollup-win32-arm64-msvc": "4.9.0", - "@rollup/rollup-win32-ia32-msvc": "4.9.0", - "@rollup/rollup-win32-x64-msvc": "4.9.0", + "@rollup/rollup-android-arm-eabi": "4.22.4", + "@rollup/rollup-android-arm64": "4.22.4", + "@rollup/rollup-darwin-arm64": "4.22.4", + "@rollup/rollup-darwin-x64": "4.22.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", + "@rollup/rollup-linux-arm-musleabihf": "4.22.4", + "@rollup/rollup-linux-arm64-gnu": "4.22.4", + "@rollup/rollup-linux-arm64-musl": "4.22.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", + "@rollup/rollup-linux-riscv64-gnu": "4.22.4", + "@rollup/rollup-linux-s390x-gnu": "4.22.4", + "@rollup/rollup-linux-x64-gnu": "4.22.4", + "@rollup/rollup-linux-x64-musl": "4.22.4", + "@rollup/rollup-win32-arm64-msvc": "4.22.4", + "@rollup/rollup-win32-ia32-msvc": "4.22.4", + "@rollup/rollup-win32-x64-msvc": "4.22.4", "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, "node_modules/rrweb-cssom": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", @@ -5428,6 +6419,29 @@ "dev": true, "license": "MIT" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", @@ -5918,6 +6932,19 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -5978,6 +7005,16 @@ "node": ">=8" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -6172,6 +7209,16 @@ "node": ">=8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", diff --git a/package.json b/package.json index d0c4178..47ad716 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@puremvc/puremvc-js-multicore-framework", - "version": "2.0.9", + "version": "2.0.10", "description": "PureMVC MultiCore Framework for JavaScript", "type": "module", "main": "bin/cjs/index.cjs", @@ -12,19 +12,23 @@ } }, "scripts": { - "build": "npm run clean && npm run build:lib", - "build:lib": "rollup -c build/rollup.conf.mjs", - "build:doc": "jsdoc -c build/jsdoc.json", - "clean": "rm -rf bin", - "npm:publish:dry-run": "npm publish --dry-run", - "npm:publish": "npm publish --access public", - "test": "npm run test:bdd", - "test:bdd": "mocha \"test/**/*.js\"", - "test:e2e": "npm run test:safari && npm run test:chrome && npm run test:firefox && npm run test:edge", - "test:safari": "nightwatch -c build/nightwatch.conf.cjs --env default", - "test:chrome": "nightwatch -c build/nightwatch.conf.cjs --env chrome", - "test:firefox": "nightwatch -c build/nightwatch.conf.cjs --env firefox", - "test:edge": "nightwatch -c build/nightwatch.conf.cjs --env edge" + "build": "npm run clean && npm run build:lib && npm run build:doc", + "test": "npm run test:bdd", + "lint": "eslint ./src", + "lint:fix": "eslint ./src --fix", + "format:check": "prettier --check ./src", + "format:fix": "prettier --write ./src", + "npm:publish:dry-run": "npm publish --dry-run", + "npm:publish": "npm publish --access public", + "test:bdd": "mocha \"test/**/*.js\"", + "test:e2e": "npm run test:safari && npm run test:chrome && npm run test:firefox && npm run test:edge", + "test:safari": "nightwatch -c build/nightwatch.conf.cjs --env default", + "test:chrome": "nightwatch -c build/nightwatch.conf.cjs --env chrome", + "test:firefox": "nightwatch -c build/nightwatch.conf.cjs --env firefox", + "test:edge": "nightwatch -c build/nightwatch.conf.cjs --env edge", + "build:lib": "rollup -c build/rollup.conf.mjs", + "build:doc": "jsdoc -c build/jsdoc.json", + "clean": "rm -rf bin" }, "repository": { "type": "git", @@ -72,12 +76,14 @@ "chai": "^4.2.0", "chromedriver": "^130.0.2", "dotenv": "^16.0.3", - "edgedriver": "^5.3.8", + "eslint": "^9.39.1", + "edgedriver": "^5.3.8", "geckodriver": "^4.2.1", "jsdoc": "^3.6.11", "minami": "^1.2.3", "mocha": "10.1.0", "nightwatch": "^3.3.2", - "rollup": "^4.6.1" + "prettier": "^3.5.1", + "rollup": "4.22.4" } } diff --git a/src/core/Controller.js b/src/core/Controller.js index 42b945f..2aa325a 100644 --- a/src/core/Controller.js +++ b/src/core/Controller.js @@ -4,10 +4,10 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {View} from "./View.js" -import {Observer} from "../patterns/observer/Observer.js"; +import { View } from "./View.js"; +import { Observer } from "../patterns/observer/Observer.js"; /** * A Multiton `Controller` implementation. @@ -44,153 +44,159 @@ import {Observer} from "../patterns/observer/Observer.js"; * @class Controller */ class Controller { + /** + * Constructor. + * + *

      This `Controller` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Factory method, + * passing the unique key for this instance + * `Controller.getInstance( multitonKey )`

      + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key has already been constructed + */ + constructor(key) { + if (Controller.instanceMap[key] != null) + throw new Error(Controller.MULTITON_MSG); + /** @protected + * @type {string} */ + this.multitonKey = key; + Controller.instanceMap.set(this.multitonKey, this); + /** @protected + * @type {Map} */ + this.commandMap = new Map(); + this.initializeController(); + } - /** - * Constructor. - * - *

      This `Controller` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Controller.getInstance( multitonKey )`

      - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Controller.instanceMap[key] != null) throw new Error(Controller.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Controller.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.commandMap = new Map(); - this.initializeController(); - } - - /** - * Initialize the Multiton `Controller` instance. - * - *

      Called automatically by the constructor.

      - * - *

      Note that if you are using a subclass of `View` - * in your application, you should also subclass `Controller` - * and override the `initializeController` method in the - * following way:

      - * - *
      `
      -     *		// ensure that the Controller is talking to my View implementation
      -     *		initializeController( )
      -     *		{
      -     *			this.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key));
      -     *		}
      -     * `
      - * - */ - initializeController() { - /** @protected - * @type {View} **/ - this.view = View.getInstance(this.multitonKey, (key) => new View(key)); - } + /** + * Initialize the Multiton `Controller` instance. + * + *

      Called automatically by the constructor.

      + * + *

      Note that if you are using a subclass of `View` + * in your application, you should also subclass `Controller` + * and override the `initializeController` method in the + * following way:

      + * + *
      `
      +   *		// ensure that the Controller is talking to my View implementation
      +   *		initializeController( )
      +   *		{
      +   *			this.view = MyView.getInstance(this.multitonKey, (key) => new MyView(key));
      +   *		}
      +   * `
      + * + */ + initializeController() { + /** @protected + * @type {View} **/ + this.view = View.getInstance(this.multitonKey, (key) => new View(key)); + } - /** - * `Controller` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Controller} factory - * @returns {Controller} the Multiton instance of `Controller` - */ - static getInstance(key, factory) { - if (Controller.instanceMap == null) - /** @static + /** + * `Controller` Multiton Factory method. + * + * @static + * @param {string} key + * @param {function(string):Controller} factory + * @returns {Controller} the Multiton instance of `Controller` + */ + static getInstance(key, factory) { + if (Controller.instanceMap == null) + /** @static @type {Map} */ - Controller.instanceMap = new Map(); - if (Controller.instanceMap.get(key) == null) Controller.instanceMap.set(key, factory(key)); - return Controller.instanceMap.get(key); - } + Controller.instanceMap = new Map(); + if (Controller.instanceMap.get(key) == null) + Controller.instanceMap.set(key, factory(key)); + return Controller.instanceMap.get(key); + } - /** - *

      If a `Command` has previously been registered - * to handle the given `Notification`, then it is executed.

      - * - * @param {Notification} notification a `Notification` - */ - executeCommand(notification) { - let factory = this.commandMap.get(notification.name); - if (factory == null) return; + /** + *

      If a `Command` has previously been registered + * to handle the given `Notification`, then it is executed.

      + * + * @param {Notification} notification a `Notification` + */ + executeCommand(notification) { + let factory = this.commandMap.get(notification.name); + if (factory == null) return; - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } + let commandInstance = factory(); + commandInstance.initializeNotifier(this.multitonKey); + commandInstance.execute(notification); + } - /** - *

      Register a particular `Command` class as the handler - * for a particular `Notification`.

      - * - *

      If an `Command` has already been registered to - * handle `Notification`s with this name, it is no longer - * used, the new `Command` is used instead.

      - * - *

      The Observer for the new Command is only created if this the - * first time a Command has been registered for this Notification name.

      - * - * @param notificationName the name of the `Notification` - * @param {function():SimpleCommand} factory - */ - registerCommand(notificationName, factory) { - if (this.commandMap.get(notificationName) == null) { - this.view.registerObserver(notificationName, new Observer(this.executeCommand, this)); - } - this.commandMap.set(notificationName, factory); + /** + *

      Register a particular `Command` class as the handler + * for a particular `Notification`.

      + * + *

      If an `Command` has already been registered to + * handle `Notification`s with this name, it is no longer + * used, the new `Command` is used instead.

      + * + *

      The Observer for the new Command is only created if this the + * first time a Command has been registered for this Notification name.

      + * + * @param notificationName the name of the `Notification` + * @param {function():SimpleCommand} factory + */ + registerCommand(notificationName, factory) { + if (this.commandMap.get(notificationName) == null) { + this.view.registerObserver( + notificationName, + new Observer(this.executeCommand, this), + ); } + this.commandMap.set(notificationName, factory); + } - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @return {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.commandMap.has(notificationName); - } + /** + * Check if a Command is registered for a given Notification + * + * @param {string} notificationName + * @return {boolean} whether a Command is currently registered for the given `notificationName`. + */ + hasCommand(notificationName) { + return this.commandMap.has(notificationName); + } - /** - * Remove a previously registered `Command` to `Notification` mapping. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - // if the Command is registered... - if(this.hasCommand(notificationName)) { - // remove the observer - this.view.removeObserver(notificationName, this); + /** + * Remove a previously registered `Command` to `Notification` mapping. + * + * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for + */ + removeCommand(notificationName) { + // if the Command is registered... + if (this.hasCommand(notificationName)) { + // remove the observer + this.view.removeObserver(notificationName, this); - // remove the command - this.commandMap.delete(notificationName) - } + // remove the command + this.commandMap.delete(notificationName); } + } - /** - * Remove a Controller instance - * - * @static - * @param {string} key of Controller instance to remove - */ - static removeController(key) { - Controller.instanceMap.delete(key); - } + /** + * Remove a Controller instance + * + * @static + * @param {string} key of Controller instance to remove + */ + static removeController(key) { + Controller.instanceMap.delete(key); + } - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Controller instance for this Multiton key already constructed!" }; + /** + * Message Constants + * + * @static + * @type {string} + */ + static get MULTITON_MSG() { + return "Controller instance for this Multiton key already constructed!"; + } } -export { Controller } +export { Controller }; diff --git a/src/core/Model.js b/src/core/Model.js index 5436d6c..ff55f03 100644 --- a/src/core/Model.js +++ b/src/core/Model.js @@ -4,7 +4,7 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ /** * A Multiton `Model` implementation. @@ -31,122 +31,122 @@ * @class Model */ class Model { + /** + * Constructor. + * + *

      This `Model` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Multiton + * Factory method `Model.getInstance( multitonKey )` + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key instance has already been constructed + */ + constructor(key) { + if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG); + /** @protected + * @type {string} */ + this.multitonKey = key; + Model.instanceMap.set(this.multitonKey, this); + /** @protected + * @type {Map} */ + this.proxyMap = new Map(); + this.initializeModel(); + } - /** - * Constructor. - * - *

      This `Model` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `Model.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key instance has already been constructed - */ - constructor(key) { - if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - Model.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.proxyMap = new Map(); - this.initializeModel(); - } - - /** - * Initialize the `Model` instance. - * - *

      Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.

      - * - */ - initializeModel() { - - } + /** + * Initialize the `Model` instance. + * + *

      Called automatically by the constructor, this + * is your opportunity to initialize the Multiton + * instance in your subclass without overriding the + * constructor.

      + * + */ + initializeModel() {} - /** - * `Model` Multiton Factory method. - * - * @static - * @param {string} key - * @param {function(string):Model} factory - * @returns {Model} the instance for this Multiton key - */ - static getInstance(key, factory) { - if (Model.instanceMap == null) - /** @static + /** + * `Model` Multiton Factory method. + * + * @static + * @param {string} key + * @param {function(string):Model} factory + * @returns {Model} the instance for this Multiton key + */ + static getInstance(key, factory) { + if (Model.instanceMap == null) + /** @static @type {Map} */ - Model.instanceMap = new Map(); - if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key)); - return Model.instanceMap.get(key); - } + Model.instanceMap = new Map(); + if (Model.instanceMap.get(key) == null) + Model.instanceMap.set(key, factory(key)); + return Model.instanceMap.get(key); + } - /** - * Register a `Proxy` with the `Model`. - * - * @param {Proxy} proxy a `Proxy` to be held by the `Model`. - */ - registerProxy(proxy) { - proxy.initializeNotifier(this.multitonKey); - this.proxyMap.set(proxy.proxyName, proxy); - proxy.onRegister(); - } + /** + * Register a `Proxy` with the `Model`. + * + * @param {Proxy} proxy a `Proxy` to be held by the `Model`. + */ + registerProxy(proxy) { + proxy.initializeNotifier(this.multitonKey); + this.proxyMap.set(proxy.proxyName, proxy); + proxy.onRegister(); + } - /** - * Retrieve a `Proxy` from the `Model`. - * - * @param {string} proxyName - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.proxyMap.get(proxyName) || null; - } + /** + * Retrieve a `Proxy` from the `Model`. + * + * @param {string} proxyName + * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. + */ + retrieveProxy(proxyName) { + return this.proxyMap.get(proxyName) || null; + } - /** - * Check if a Proxy is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.proxyMap.has(proxyName); - } + /** + * Check if a Proxy is registered + * + * @param {string} proxyName + * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. + */ + hasProxy(proxyName) { + return this.proxyMap.has(proxyName); + } - /** - * Remove a `Proxy` from the `Model`. - * - * @param {string} proxyName name of the `Proxy` instance to be removed. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - let proxy = this.proxyMap.get(proxyName); - if (proxy != null) { - this.proxyMap.delete(proxyName); - proxy.onRemove(); - } - return proxy; + /** + * Remove a `Proxy` from the `Model`. + * + * @param {string} proxyName name of the `Proxy` instance to be removed. + * @returns {Proxy} the `Proxy` that was removed from the `Model` + */ + removeProxy(proxyName) { + let proxy = this.proxyMap.get(proxyName); + if (proxy != null) { + this.proxyMap.delete(proxyName); + proxy.onRemove(); } + return proxy; + } - /** - * Remove a Model instance - * - * @static - * @param key - */ - static removeModel(key) { - Model.instanceMap.delete(key); - } + /** + * Remove a Model instance + * + * @static + * @param key + */ + static removeModel(key) { + Model.instanceMap.delete(key); + } - /** - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "Model instance for this Multiton key already constructed!" }; + /** + * @static + * @type {string} + */ + static get MULTITON_MSG() { + return "Model instance for this Multiton key already constructed!"; + } } -export { Model } +export { Model }; diff --git a/src/core/View.js b/src/core/View.js index 9af6ea5..e0ed962 100644 --- a/src/core/View.js +++ b/src/core/View.js @@ -4,9 +4,9 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {Observer} from "../patterns/observer/Observer.js"; +import { Observer } from "../patterns/observer/Observer.js"; /** * A Multiton `View` implementation. @@ -30,237 +30,239 @@ import {Observer} from "../patterns/observer/Observer.js"; * @class View */ class View { + /** + * Constructor. + * + *

      This `View` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Multiton + * Factory method `View.getInstance( multitonKey )` + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key has already been constructed + */ + constructor(key) { + if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG); + /** @protected + * @type {string} */ + this.multitonKey = key; + View.instanceMap.set(this.multitonKey, this); + /** @protected + * @type {Map} */ + this.mediatorMap = new Map(); + /** @protected + * @type {Map.>} */ + this.observerMap = new Map(); + this.initializeView(); + } - /** - * Constructor. - * - *

      This `View` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Multiton - * Factory method `View.getInstance( multitonKey )` - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (View.instanceMap.get(key) != null) throw new Error(View.MULTITON_MSG); - /** @protected - * @type {string} */ - this.multitonKey = key; - View.instanceMap.set(this.multitonKey, this); - /** @protected - * @type {Map} */ - this.mediatorMap = new Map(); - /** @protected - * @type {Map.>} */ - this.observerMap = new Map(); - this.initializeView(); - } + /** + *

      Initialize the Multiton View instance.

      + * + *

      Called automatically by the constructor, this + * is your opportunity to initialize the Multiton + * instance in your subclass without overriding the + * constructor.

      + */ + initializeView() {} - /** - *

      Initialize the Multiton View instance.

      - * - *

      Called automatically by the constructor, this - * is your opportunity to initialize the Multiton - * instance in your subclass without overriding the - * constructor.

      - */ - initializeView() { + /** + * View Multiton factory method. + * + * @static + * @param {string} key + * @param {function(string):View} factory + * @returns {View} the Multiton instance of `View` + */ + static getInstance(key, factory) { + if (View.instanceMap == null) + /** @static + * @type {Map} */ + View.instanceMap = new Map(); + if (View.instanceMap.get(key) == null) + View.instanceMap.set(key, factory(key)); + return View.instanceMap.get(key); + } + /** + *

      Register an `Observer` to be notified + * of `Notifications` with a given name.

      + * + * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of + * @param {Observer} observer the `Observer` to register + */ + registerObserver(notificationName, observer) { + if (this.observerMap.get(notificationName) != null) { + let observers = this.observerMap.get(notificationName); + observers.push(observer); + } else { + this.observerMap.set(notificationName, new Array(observer)); } + } - /** - * View Multiton factory method. - * - * @static - * @param {string} key - * @param {function(string):View} factory - * @returns {View} the Multiton instance of `View` - */ - static getInstance(key, factory) { - if (View.instanceMap == null) - /** @static - * @type {Map} */ - View.instanceMap = new Map(); - if (View.instanceMap.get(key) == null) View.instanceMap.set(key, factory(key)); - return View.instanceMap.get(key); - } + /** + *

      Notify the `Observers` for a particular `Notification`.

      + * + *

      All previously attached `Observers` for this `Notification`'s + * list are notified and are passed a reference to the `Notification` in + * the order in which they were registered.

      + * + * @param {Notification} notification the `Notification` to notify `Observers` of. + */ + notifyObservers(notification) { + if (this.observerMap.has(notification.name)) { + // Copy observers from reference array to working array, + // since the reference array may change during the notification loop + let observers = this.observerMap.get(notification.name).slice(); - /** - *

      Register an `Observer` to be notified - * of `Notifications` with a given name.

      - * - * @param {string} notificationName the name of the `Notifications` to notify this `Observer` of - * @param {Observer} observer the `Observer` to register - */ - registerObserver(notificationName, observer) { - if (this.observerMap.get(notificationName) != null) { - let observers = this.observerMap.get(notificationName); - observers.push(observer); - } else { - this.observerMap.set(notificationName, new Array(observer)); - } + // Notify Observers from the working array + for (let i = 0; i < observers.length; i++) { + observers[i].notifyObserver(notification); + } } + } - /** - *

      Notify the `Observers` for a particular `Notification`.

      - * - *

      All previously attached `Observers` for this `Notification`'s - * list are notified and are passed a reference to the `Notification` in - * the order in which they were registered.

      - * - * @param {Notification} notification the `Notification` to notify `Observers` of. - */ - notifyObservers(notification) { - if (this.observerMap.has(notification.name)) { - // Copy observers from reference array to working array, - // since the reference array may change during the notification loop - let observers = this.observerMap.get(notification.name).slice(); + /** + *

      Remove the observer for a given notifyContext from an observer list for a given Notification name.

      + * + * @param {string} notificationName which observer list to remove from + * @param {Object} notifyContext remove the observer with this object as its notifyContext + */ + removeObserver(notificationName, notifyContext) { + // the observer list for the notification under inspection + let observers = this.observerMap.get(notificationName); - // Notify Observers from the working array - for(let i = 0; i < observers.length; i++) { - observers[i].notifyObserver(notification); - } - } + // find the observer for the notifyContext + for (let i = 0; i < observers.length; i++) { + if (observers[i].compareNotifyContext(notifyContext) === true) { + // there can only be one Observer for a given notifyContext + // in any given Observer list, so remove it and break + observers.splice(i, 1); + break; + } } - /** - *

      Remove the observer for a given notifyContext from an observer list for a given Notification name.

      - * - * @param {string} notificationName which observer list to remove from - * @param {Object} notifyContext remove the observer with this object as its notifyContext - */ - removeObserver(notificationName, notifyContext) { - // the observer list for the notification under inspection - let observers = this.observerMap.get(notificationName); - - // find the observer for the notifyContext - for (let i = 0; i < observers.length; i++) { - if (observers[i].compareNotifyContext(notifyContext) === true) { - // there can only be one Observer for a given notifyContext - // in any given Observer list, so remove it and break - observers.splice(i, 1); - break; - } - } - - // Also, when a Notification's Observer list length falls to - // zero, delete the notification key from the observer map - if (observers.length === 0) { - this.observerMap.delete(notificationName); - } + // Also, when a Notification's Observer list length falls to + // zero, delete the notification key from the observer map + if (observers.length === 0) { + this.observerMap.delete(notificationName); } + } - /** - * Register a `Mediator` instance with the `View`. - * - *

      Registers the `Mediator` so that it can be retrieved by name, - * and further interrogates the `Mediator` for its - * `Notification` interests.

      - * - *

      If the `Mediator` returns any `Notification` - * names to be notified about, an `Observer` is created encapsulating - * the `Mediator` instance's `handleNotification` method - * and registering it as an `Observer` for all `Notifications` the - * `Mediator` is interested in.

      - * - * @param {Mediator} mediator a reference to the `Mediator` instance - */ - registerMediator(mediator) { - // do not allow re-registration (you must to removeMediator fist) - if (this.mediatorMap.has(mediator.mediatorName) !== false) return; + /** + * Register a `Mediator` instance with the `View`. + * + *

      Registers the `Mediator` so that it can be retrieved by name, + * and further interrogates the `Mediator` for its + * `Notification` interests.

      + * + *

      If the `Mediator` returns any `Notification` + * names to be notified about, an `Observer` is created encapsulating + * the `Mediator` instance's `handleNotification` method + * and registering it as an `Observer` for all `Notifications` the + * `Mediator` is interested in.

      + * + * @param {Mediator} mediator a reference to the `Mediator` instance + */ + registerMediator(mediator) { + // do not allow re-registration (you must to removeMediator fist) + if (this.mediatorMap.has(mediator.mediatorName) !== false) return; - mediator.initializeNotifier(this.multitonKey); + mediator.initializeNotifier(this.multitonKey); - // Register the Mediator for retrieval by name - this.mediatorMap.set(mediator.mediatorName, mediator); + // Register the Mediator for retrieval by name + this.mediatorMap.set(mediator.mediatorName, mediator); - // Get Notification interests, if any. - let interests = mediator.listNotificationInterests(); + // Get Notification interests, if any. + let interests = mediator.listNotificationInterests(); - // Register Mediator as an observer for each notification of interests - if (interests.length > 0) { - // Create Observer referencing this mediator's handleNotification method - let observer = new Observer(mediator.handleNotification.bind(mediator), mediator); // check bind + // Register Mediator as an observer for each notification of interests + if (interests.length > 0) { + // Create Observer referencing this mediator's handleNotification method + let observer = new Observer( + mediator.handleNotification.bind(mediator), + mediator, + ); // check bind - // Register Mediator as Observer for its list of Notification interests - for (let i = 0; i < interests.length; i++) { - this.registerObserver(interests[i], observer); - } - } - - // alert the mediator that it has been registered - mediator.onRegister(); + // Register Mediator as Observer for its list of Notification interests + for (let i = 0; i < interests.length; i++) { + this.registerObserver(interests[i], observer); + } } - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName the name of the `Mediator` instance to retrieve. - * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.mediatorMap.get(mediatorName) || null; - } + // alert the mediator that it has been registered + mediator.onRegister(); + } - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` instance to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - // Retrieve the named mediator - let mediator = this.mediatorMap.get(mediatorName); + /** + * Retrieve a `Mediator` from the `View`. + * + * @param {string} mediatorName the name of the `Mediator` instance to retrieve. + * @returns {Mediator} the `Mediator` instance previously registered with the given `mediatorName`. + */ + retrieveMediator(mediatorName) { + return this.mediatorMap.get(mediatorName) || null; + } - if (mediator) { - // for every notification this mediator is interested in... - let interests = mediator.listNotificationInterests(); - for (let i = 0; i < interests.length; i++) { - // remove the observer linking the mediator - // to the notification interest - this.removeObserver(interests[i], mediator); - } + /** + * Remove a `Mediator` from the `View`. + * + * @param {string} mediatorName name of the `Mediator` instance to be removed. + * @returns {Mediator} the `Mediator` that was removed from the `View` + */ + removeMediator(mediatorName) { + // Retrieve the named mediator + let mediator = this.mediatorMap.get(mediatorName); - // remove the mediator from the map - this.mediatorMap.delete(mediatorName); + if (mediator) { + // for every notification this mediator is interested in... + let interests = mediator.listNotificationInterests(); + for (let i = 0; i < interests.length; i++) { + // remove the observer linking the mediator + // to the notification interest + this.removeObserver(interests[i], mediator); + } - // alert the mediator that it has been removed - mediator.onRemove(); - } + // remove the mediator from the map + this.mediatorMap.delete(mediatorName); - return mediator; + // alert the mediator that it has been removed + mediator.onRemove(); } - /** - * Check if a Mediator is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.mediatorMap.has(mediatorName); - } + return mediator; + } - /** - * Remove a View instance - * - * @static - * @param key multitonKey of View instance to remove - */ - static removeView(key) { - this.instanceMap.delete(key); - } + /** + * Check if a Mediator is registered or not + * + * @param {string} mediatorName + * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. + */ + hasMediator(mediatorName) { + return this.mediatorMap.has(mediatorName); + } - /** - * Message Constants - * - * @static - * @type {string} - */ - static get MULTITON_MSG() { return "View instance for this Multiton key already constructed!" }; + /** + * Remove a View instance + * + * @static + * @param key multitonKey of View instance to remove + */ + static removeView(key) { + this.instanceMap.delete(key); + } + /** + * Message Constants + * + * @static + * @type {string} + */ + static get MULTITON_MSG() { + return "View instance for this Multiton key already constructed!"; + } } -export { View } +export { View }; diff --git a/src/index.js b/src/index.js index fef59bb..a142d70 100644 --- a/src/index.js +++ b/src/index.js @@ -4,16 +4,16 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -export { Controller } from "./core/Controller.js" -export { Model } from "./core/Model.js" -export { View } from "./core/View.js" -export { MacroCommand } from "./patterns/command/MacroCommand.js" -export { SimpleCommand } from "./patterns/command/SimpleCommand.js" -export { Facade } from "./patterns/facade/Facade.js" -export { Mediator } from "./patterns/mediator/Mediator.js" -export { Notification } from "./patterns/observer/Notification.js" -export { Notifier } from "./patterns/observer/Notifier.js" -export { Observer } from "./patterns/observer/Observer.js" -export { Proxy } from "./patterns/proxy/Proxy.js" +export { Controller } from "./core/Controller.js"; +export { Model } from "./core/Model.js"; +export { View } from "./core/View.js"; +export { MacroCommand } from "./patterns/command/MacroCommand.js"; +export { SimpleCommand } from "./patterns/command/SimpleCommand.js"; +export { Facade } from "./patterns/facade/Facade.js"; +export { Mediator } from "./patterns/mediator/Mediator.js"; +export { Notification } from "./patterns/observer/Notification.js"; +export { Notifier } from "./patterns/observer/Notifier.js"; +export { Observer } from "./patterns/observer/Observer.js"; +export { Proxy } from "./patterns/proxy/Proxy.js"; diff --git a/src/patterns/command/MacroCommand.js b/src/patterns/command/MacroCommand.js index 25b63ff..2a893ce 100644 --- a/src/patterns/command/MacroCommand.js +++ b/src/patterns/command/MacroCommand.js @@ -4,9 +4,9 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {SimpleCommand} from "./SimpleCommand.js"; +import { SimpleCommand } from "./SimpleCommand.js"; /** * A base `Command` implementation that executes other `Command`s. @@ -33,79 +33,75 @@ import {SimpleCommand} from "./SimpleCommand.js"; * @class MacroCommand */ class MacroCommand extends SimpleCommand { + /** + * Constructor. + * + *

      You should not need to define a constructor, + * instead, override the `initializeMacroCommand` + * method.

      + * + *

      If your subclass does define a constructor, be + * sure to call `super()`.

      + * + * @constructor + */ + constructor() { + super(); + /** @protected + * @type {Array.} */ + this.subCommands = []; + this.initializeMacroCommand(); + } - /** - * Constructor. - * - *

      You should not need to define a constructor, - * instead, override the `initializeMacroCommand` - * method.

      - * - *

      If your subclass does define a constructor, be - * sure to call `super()`.

      - * - * @constructor - */ - constructor() { - super(); - /** @protected - * @type {Array.} */ - this.subCommands = []; - this.initializeMacroCommand(); - } - - /** - * Initialize the `MacroCommand`. - * - *

      In your subclass, override this method to - * initialize the `MacroCommand`'s SubCommand - * list with `Command` class references like - * this:

      - * - *
      `
      -     *		// Initialize MyMacroCommand
      -     *		initializeMacroCommand() {
      -     *			this.addSubCommand(() => new app.FirstCommand());
      -     *			this.addSubCommand(() => new app.SecondCommand());
      -     *			this.addSubCommand(() => new app.ThirdCommand());
      -     *		}
      -     * `
      - * - *

      Note that SubCommands may be any `Command` implementor, - * `MacroCommand`s or `SimpleCommands` are both acceptable. - */ - initializeMacroCommand() { + /** + * Initialize the `MacroCommand`. + * + *

      In your subclass, override this method to + * initialize the `MacroCommand`'s SubCommand + * list with `Command` class references like + * this:

      + * + *
      `
      +   *		// Initialize MyMacroCommand
      +   *		initializeMacroCommand() {
      +   *			this.addSubCommand(() => new app.FirstCommand());
      +   *			this.addSubCommand(() => new app.SecondCommand());
      +   *			this.addSubCommand(() => new app.ThirdCommand());
      +   *		}
      +   * `
      + * + *

      Note that SubCommands may be any `Command` implementor, + * `MacroCommand`s or `SimpleCommands` are both acceptable. + */ + initializeMacroCommand() {} - } + /** + * Add a SubCommand. + * + *

      The SubCommands will be called in First In/First Out (FIFO) + * order.

      + * + * @param {function():SimpleCommand} factory + */ + addSubCommand(factory) { + this.subCommands.push(factory); + } - /** - * Add a SubCommand. - * - *

      The SubCommands will be called in First In/First Out (FIFO) - * order.

      - * - * @param {function():SimpleCommand} factory - */ - addSubCommand(factory) { - this.subCommands.push(factory); + /** + * Execute this `MacroCommand`'s SubCommands. + * + *

      The SubCommands will be called in First In/First Out (FIFO) + * order.

      + * + * @param {Notification} notification + */ + execute(notification) { + while (this.subCommands.length > 0) { + let factory = this.subCommands.shift(); + let commandInstance = factory(); + commandInstance.initializeNotifier(this.multitonKey); + commandInstance.execute(notification); } - - /** - * Execute this `MacroCommand`'s SubCommands. - * - *

      The SubCommands will be called in First In/First Out (FIFO) - * order.

      - * - * @param {Notification} notification - */ - execute(notification) { - while(this.subCommands.length > 0) { - let factory = this.subCommands.shift(); - let commandInstance = factory(); - commandInstance.initializeNotifier(this.multitonKey); - commandInstance.execute(notification); - } - } - + } } -export { MacroCommand } +export { MacroCommand }; diff --git a/src/patterns/command/SimpleCommand.js b/src/patterns/command/SimpleCommand.js index a6c4ab0..4d56ac5 100644 --- a/src/patterns/command/SimpleCommand.js +++ b/src/patterns/command/SimpleCommand.js @@ -4,9 +4,9 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {Notifier} from "../observer/Notifier.js"; +import { Notifier } from "../observer/Notifier.js"; /** * A base `Command` implementation. @@ -21,24 +21,21 @@ import {Notifier} from "../observer/Notifier.js"; * @class SimpleCommand */ class SimpleCommand extends Notifier { + constructor() { + super(); + } - constructor() { - super(); - } - - /** - * Fulfill the use-case initiated by the given `Notification`. - * - *

      In the Command Pattern, an application use-case typically - * begins with some user action, which results in a `Notification` being broadcast, which - * is handled by business logic in the `execute` method of an - * `Command`.

      - * - * @param {Notification} notification - */ - execute(notification) { - - } - + /** + * Fulfill the use-case initiated by the given `Notification`. + * + *

      In the Command Pattern, an application use-case typically + * begins with some user action, which results in a `Notification` being broadcast, which + * is handled by business logic in the `execute` method of an + * `Command`.

      + * + * @param {Notification} notification + */ + // eslint-disable-next-line no-unused-vars + execute(notification) {} } -export { SimpleCommand } +export { SimpleCommand }; diff --git a/src/patterns/facade/Facade.js b/src/patterns/facade/Facade.js index e9c1a57..f7b4f05 100644 --- a/src/patterns/facade/Facade.js +++ b/src/patterns/facade/Facade.js @@ -4,12 +4,12 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {Controller} from "../../core/Controller.js"; -import {Model} from "../../core/Model.js"; -import {View} from "../../core/View.js"; -import {Notification} from "../observer/Notification.js"; +import { Controller } from "../../core/Controller.js"; +import { Model } from "../../core/Model.js"; +import { View } from "../../core/View.js"; +import { Notification } from "../observer/Notification.js"; /** * A base Multiton `Facade` implementation. @@ -21,318 +21,323 @@ import {Notification} from "../observer/Notification.js"; * @class Facade */ class Facade { + /** + * Constructor. + * + *

      This `Facade` implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Factory method, + * passing the unique key for this instance + * `Facade.getInstance( multitonKey )`

      + * + * @constructor + * @param {string} key + * + * @throws {Error} Error if instance for this Multiton key has already been constructed + */ + constructor(key) { + if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG); + this.initializeNotifier(key); + Facade.instanceMap.set(this.multitonKey, this); + this.initializeFacade(); + } - /** - * Constructor. - * - *

      This `Facade` implementation is a Multiton, - * so you should not call the constructor - * directly, but instead call the static Factory method, - * passing the unique key for this instance - * `Facade.getInstance( multitonKey )`

      - * - * @constructor - * @param {string} key - * - * @throws {Error} Error if instance for this Multiton key has already been constructed - */ - constructor(key) { - if (Facade.instanceMap[key] != null) throw new Error(Facade.MULTITON_MSG); - this.initializeNotifier(key); - Facade.instanceMap.set(this.multitonKey, this); - this.initializeFacade(); - } - - /** - * Initialize the Multiton `Facade` instance. - * - *

      Called automatically by the constructor. Override in your - * subclass to do any subclass specific initializations. Be - * sure to call `super.initializeFacade()`, though.

      - */ - initializeFacade() { - this.initializeModel(); - this.initializeController(); - this.initializeView(); - } + /** + * Initialize the Multiton `Facade` instance. + * + *

      Called automatically by the constructor. Override in your + * subclass to do any subclass specific initializations. Be + * sure to call `super.initializeFacade()`, though.

      + */ + initializeFacade() { + this.initializeModel(); + this.initializeController(); + this.initializeView(); + } - /** - * Facade Multiton Factory method - * - * @static - * @param {string} key - * @param {function(string):Facade} factory - * @returns {Facade} the Multiton instance of the Facade - */ - static getInstance(key, factory) { - if (Facade.instanceMap == null) - /** @static - * @type {Map} */ - Facade.instanceMap = new Map(); - if (Facade.instanceMap.get(key) == null) Facade.instanceMap.set(key, factory(key)); - return Facade.instanceMap.get(key); - } + /** + * Facade Multiton Factory method + * + * @static + * @param {string} key + * @param {function(string):Facade} factory + * @returns {Facade} the Multiton instance of the Facade + */ + static getInstance(key, factory) { + if (Facade.instanceMap == null) + /** @static + * @type {Map} */ + Facade.instanceMap = new Map(); + if (Facade.instanceMap.get(key) == null) + Facade.instanceMap.set(key, factory(key)); + return Facade.instanceMap.get(key); + } - /** - * Initialize the `Model`. - * - *

      Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

      - * - *
        - *
      • You wish to initialize a different `Model`.
      • - *
      • You have `Proxy`s to register with the Model that do not - * retrieve a reference to the Facade at construction time.`
      • - *
      - * - * If you don't want to initialize a different `Model`, - * call `super.initializeModel()` at the beginning of your - * method, then register `Proxy`s. - * - *

      Note: This method is rarely overridden; in practice you are more - * likely to use a `Command` to create and register `Proxy`s - * with the `Model`, since `Proxy`s with mutable data will likely - * need to send `Notification`s and thus will likely want to fetch a reference to - * the `Facade` during their construction.

      - */ - initializeModel() { - if (this.model != null) return; - this.model = Model.getInstance(this.multitonKey, key => new Model(key)); - } + /** + * Initialize the `Model`. + * + *

      Called by the `initializeFacade` method. + * Override this method in your subclass of `Facade` + * if one or both of the following are true:

      + * + *
        + *
      • You wish to initialize a different `Model`.
      • + *
      • You have `Proxy`s to register with the Model that do not + * retrieve a reference to the Facade at construction time.`
      • + *
      + * + * If you don't want to initialize a different `Model`, + * call `super.initializeModel()` at the beginning of your + * method, then register `Proxy`s. + * + *

      Note: This method is rarely overridden; in practice you are more + * likely to use a `Command` to create and register `Proxy`s + * with the `Model`, since `Proxy`s with mutable data will likely + * need to send `Notification`s and thus will likely want to fetch a reference to + * the `Facade` during their construction.

      + */ + initializeModel() { + if (this.model != null) return; + this.model = Model.getInstance(this.multitonKey, (key) => new Model(key)); + } - /** - * Initialize the `Controller`. - * - *

      Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

      - * - *
        - *
      • You wish to initialize a different `Controller`.
      • - *
      • You have `Commands` to register with the `Controller` at startup.`.
      • - *
      - * - *

      If you don't want to initialize a different `Controller`, - * call `super.initializeController()` at the beginning of your - * method, then register `Command`s.

      - */ - initializeController() { - if (this.controller != null) return; - this.controller = Controller.getInstance(this.multitonKey, key => new Controller(key)); - } + /** + * Initialize the `Controller`. + * + *

      Called by the `initializeFacade` method. + * Override this method in your subclass of `Facade` + * if one or both of the following are true:

      + * + *
        + *
      • You wish to initialize a different `Controller`.
      • + *
      • You have `Commands` to register with the `Controller` at startup.`.
      • + *
      + * + *

      If you don't want to initialize a different `Controller`, + * call `super.initializeController()` at the beginning of your + * method, then register `Command`s.

      + */ + initializeController() { + if (this.controller != null) return; + this.controller = Controller.getInstance( + this.multitonKey, + (key) => new Controller(key), + ); + } - /** - * Initialize the `View`. - * - *

      Called by the `initializeFacade` method. - * Override this method in your subclass of `Facade` - * if one or both of the following are true:

      - * - *
        - *
      • You wish to initialize a different `View`.
      • - *
      • You have `Observers` to register with the `View`
      • - *
      - * - *

      If you don't want to initialize a different `View`, - * call `super.initializeView()` at the beginning of your - * method, then register `Mediator` instances.

      - * - *

      Note: This method is rarely overridden; in practice you are more - * likely to use a `Command` to create and register `Mediator`s - * with the `View`, since `Mediator` instances will need to send - * `Notification`s and thus will likely want to fetch a reference - * to the `Facade` during their construction.

      - */ - initializeView() { - if (this.view != null) return; - this.view = View.getInstance(this.multitonKey, key => new View(key)); - } + /** + * Initialize the `View`. + * + *

      Called by the `initializeFacade` method. + * Override this method in your subclass of `Facade` + * if one or both of the following are true:

      + * + *
        + *
      • You wish to initialize a different `View`.
      • + *
      • You have `Observers` to register with the `View`
      • + *
      + * + *

      If you don't want to initialize a different `View`, + * call `super.initializeView()` at the beginning of your + * method, then register `Mediator` instances.

      + * + *

      Note: This method is rarely overridden; in practice you are more + * likely to use a `Command` to create and register `Mediator`s + * with the `View`, since `Mediator` instances will need to send + * `Notification`s and thus will likely want to fetch a reference + * to the `Facade` during their construction.

      + */ + initializeView() { + if (this.view != null) return; + this.view = View.getInstance(this.multitonKey, (key) => new View(key)); + } - /** - * Register a `Command` with the `Controller` by Notification name. - * - * @param {string} notificationName the name of the `Notification` to associate the `Command` with - * @param {function():SimpleCommand} factory a reference to the factory of the `Command` - */ - registerCommand(notificationName, factory) { - this.controller.registerCommand(notificationName, factory); - } + /** + * Register a `Command` with the `Controller` by Notification name. + * + * @param {string} notificationName the name of the `Notification` to associate the `Command` with + * @param {function():SimpleCommand} factory a reference to the factory of the `Command` + */ + registerCommand(notificationName, factory) { + this.controller.registerCommand(notificationName, factory); + } - /** - * Check if a Command is registered for a given Notification - * - * @param {string} notificationName - * @returns {boolean} whether a Command is currently registered for the given `notificationName`. - */ - hasCommand(notificationName) { - return this.controller.hasCommand(notificationName); - } + /** + * Check if a Command is registered for a given Notification + * + * @param {string} notificationName + * @returns {boolean} whether a Command is currently registered for the given `notificationName`. + */ + hasCommand(notificationName) { + return this.controller.hasCommand(notificationName); + } - /** - * Remove a previously registered `Command` to `Notification` mapping from the Controller. - * - * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for - */ - removeCommand(notificationName) { - this.controller.removeCommand(notificationName); - } + /** + * Remove a previously registered `Command` to `Notification` mapping from the Controller. + * + * @param {string} notificationName the name of the `Notification` to remove the `Command` mapping for + */ + removeCommand(notificationName) { + this.controller.removeCommand(notificationName); + } - /** - * Register a `Proxy` with the `Model` by name. - * - * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`. - */ - registerProxy(proxy) { - this.model.registerProxy(proxy); - } + /** + * Register a `Proxy` with the `Model` by name. + * + * @param {Proxy} proxy the `Proxy` instance to be registered with the `Model`. + */ + registerProxy(proxy) { + this.model.registerProxy(proxy); + } - /** - * Remove a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the `Proxy` to remove from the `Model`. - * @returns {Proxy} the `Proxy` that was removed from the `Model` - */ - removeProxy(proxyName) { - return this.model.removeProxy(proxyName); - } + /** + * Remove a `Proxy` from the `Model` by name. + * + * @param {string} proxyName the `Proxy` to remove from the `Model`. + * @returns {Proxy} the `Proxy` that was removed from the `Model` + */ + removeProxy(proxyName) { + return this.model.removeProxy(proxyName); + } - /** - * Check if a `Proxy` is registered - * - * @param {string} proxyName - * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. - */ - hasProxy(proxyName) { - return this.model.hasProxy(proxyName); - } + /** + * Check if a `Proxy` is registered + * + * @param {string} proxyName + * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`. + */ + hasProxy(proxyName) { + return this.model.hasProxy(proxyName); + } - /** - * Retrieve a `Proxy` from the `Model` by name. - * - * @param {string} proxyName the name of the proxy to be retrieved. - * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. - */ - retrieveProxy(proxyName) { - return this.model.retrieveProxy(proxyName); - } + /** + * Retrieve a `Proxy` from the `Model` by name. + * + * @param {string} proxyName the name of the proxy to be retrieved. + * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`. + */ + retrieveProxy(proxyName) { + return this.model.retrieveProxy(proxyName); + } - /** - * Register a `Mediator` with the `View`. - * - * @param {Mediator} mediator a reference to the `Mediator` - */ - registerMediator(mediator) { - this.view.registerMediator(mediator); - } + /** + * Register a `Mediator` with the `View`. + * + * @param {Mediator} mediator a reference to the `Mediator` + */ + registerMediator(mediator) { + this.view.registerMediator(mediator); + } - /** - * Remove a `Mediator` from the `View`. - * - * @param {string} mediatorName name of the `Mediator` to be removed. - * @returns {Mediator} the `Mediator` that was removed from the `View` - */ - removeMediator(mediatorName) { - return this.view.removeMediator(mediatorName); - } + /** + * Remove a `Mediator` from the `View`. + * + * @param {string} mediatorName name of the `Mediator` to be removed. + * @returns {Mediator} the `Mediator` that was removed from the `View` + */ + removeMediator(mediatorName) { + return this.view.removeMediator(mediatorName); + } - /** - * Check if a `Mediator` is registered or not - * - * @param {string} mediatorName - * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. - */ - hasMediator(mediatorName) { - return this.view.hasMediator(mediatorName); - } + /** + * Check if a `Mediator` is registered or not + * + * @param {string} mediatorName + * @returns {boolean} whether a Mediator is registered with the given `mediatorName`. + */ + hasMediator(mediatorName) { + return this.view.hasMediator(mediatorName); + } - /** - * Retrieve a `Mediator` from the `View`. - * - * @param {string} mediatorName - * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`. - */ - retrieveMediator(mediatorName) { - return this.view.retrieveMediator(mediatorName); - } + /** + * Retrieve a `Mediator` from the `View`. + * + * @param {string} mediatorName + * @returns {Mediator} the `Mediator` previously registered with the given `mediatorName`. + */ + retrieveMediator(mediatorName) { + return this.view.retrieveMediator(mediatorName); + } - /** - * Create and send an `Notification`. - * - *

      Keeps us from having to construct new notification - * instances in our implementation code.

      - * - * @param {string} notificationName the name of the notification to send - * @param {Object} [body] body the body of the notification (optional) - * @param {string} [type] type the type of the notification (optional) - */ - sendNotification(notificationName, body = null, type = "") { - this.notifyObservers(new Notification(notificationName, body, type)); - } + /** + * Create and send an `Notification`. + * + *

      Keeps us from having to construct new notification + * instances in our implementation code.

      + * + * @param {string} notificationName the name of the notification to send + * @param {Object} [body] body the body of the notification (optional) + * @param {string} [type] type the type of the notification (optional) + */ + sendNotification(notificationName, body = null, type = "") { + this.notifyObservers(new Notification(notificationName, body, type)); + } - /** - * Notify `Observer`s. - * - *

      This method is left public mostly for backward - * compatibility, and to allow you to send custom - * notification classes using the facade.

      - * - *

      Usually you should just call `sendNotification` - * and pass the parameters, never having to - * construct the notification yourself.

      - * - * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of. - */ - notifyObservers(notification) { - this.view.notifyObservers(notification); - } + /** + * Notify `Observer`s. + * + *

      This method is left public mostly for backward + * compatibility, and to allow you to send custom + * notification classes using the facade.

      + * + *

      Usually you should just call `sendNotification` + * and pass the parameters, never having to + * construct the notification yourself.

      + * + * @param {Notification} notification the `Notification` to have the `View` notify `Observers` of. + */ + notifyObservers(notification) { + this.view.notifyObservers(notification); + } - /** - * Set the Multiton key for this facade instance. - * - *

      Not called directly, but instead from the - * constructor when getInstance is invoked. - * It is necessary to be public in order to - * implement Notifier.

      - */ - initializeNotifier(key) { - this.multitonKey = key; - } + /** + * Set the Multiton key for this facade instance. + * + *

      Not called directly, but instead from the + * constructor when getInstance is invoked. + * It is necessary to be public in order to + * implement Notifier.

      + */ + initializeNotifier(key) { + this.multitonKey = key; + } - /** - * Check if a Core is registered or not - * - * @static - * @param {string} key the multiton key for the Core in question - * @returns {boolean} whether a Core is registered with the given `key`. - */ - static hasCore(key) { - return this.instanceMap.has(key); - } + /** + * Check if a Core is registered or not + * + * @static + * @param {string} key the multiton key for the Core in question + * @returns {boolean} whether a Core is registered with the given `key`. + */ + static hasCore(key) { + return this.instanceMap.has(key); + } - /** - * Remove a Core. - * - *

      Remove the Model, View, Controller and Facade - * instances for the given key.

      - * - * @static - * @param {string} key multitonKey of the Core to remove - */ - static removeCore(key) { - if (Facade.instanceMap.get(key) == null) return; - Model.removeModel(key); - View.removeView(key); - Controller.removeController(key); - this.instanceMap.delete(key); - } + /** + * Remove a Core. + * + *

      Remove the Model, View, Controller and Facade + * instances for the given key.

      + * + * @static + * @param {string} key multitonKey of the Core to remove + */ + static removeCore(key) { + if (Facade.instanceMap.get(key) == null) return; + Model.removeModel(key); + View.removeView(key); + Controller.removeController(key); + this.instanceMap.delete(key); + } - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() {return "Facade instance for this Multiton key already constructed!"}; + /** + * Message Constants + * + * @static + * @returns {string} + */ + static get MULTITON_MSG() { + return "Facade instance for this Multiton key already constructed!"; + } } -export { Facade } +export { Facade }; diff --git a/src/patterns/mediator/Mediator.js b/src/patterns/mediator/Mediator.js index 3a64824..35ebf2c 100644 --- a/src/patterns/mediator/Mediator.js +++ b/src/patterns/mediator/Mediator.js @@ -4,9 +4,9 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {Notifier} from "../observer/Notifier.js"; +import { Notifier } from "../observer/Notifier.js"; /** * A base `Mediator` implementation. @@ -16,100 +16,96 @@ import {Notifier} from "../observer/Notifier.js"; * @class Mediator */ class Mediator extends Notifier { + /** + * Constructor. + * + * @constructor + * @param {string | null} [mediatorName=null] + * @param {Object | null} [viewComponent=null] + */ + constructor(mediatorName = null, viewComponent = null) { + super(); + this._mediatorName = mediatorName || Mediator.NAME; + this._viewComponent = viewComponent; + } - /** - * Constructor. - * - * @constructor - * @param {string | null} [mediatorName=null] - * @param {Object | null} [viewComponent=null] - */ - constructor(mediatorName = null, viewComponent = null) { - super(); - this._mediatorName = mediatorName || Mediator.NAME; - this._viewComponent = viewComponent; - } - - /** - * Called by the View when the Mediator is registered - */ - onRegister() { - - } - - /** - * Called by the View when the Mediator is removed - */ - onRemove() { - - } + /** + * Called by the View when the Mediator is registered + */ + onRegister() {} - /** - * List the `Notification` names this - * `Mediator` is interested in being notified of. - * - * @returns {string[]} - */ - listNotificationInterests() { - return []; - } + /** + * Called by the View when the Mediator is removed + */ + onRemove() {} - /** - * Handle `Notification`s. - * - *

      - * Typically this will be handled in a switch statement, - * with one 'case' entry per `Notification` - * the `Mediator` is interested in. - * - * @param {Notification} notification - */ - handleNotification(notification) { + /** + * List the `Notification` names this + * `Mediator` is interested in being notified of. + * + * @returns {string[]} + */ + listNotificationInterests() { + return []; + } - } + /** + * Handle `Notification`s. + * + *

      + * Typically this will be handled in a switch statement, + * with one 'case' entry per `Notification` + * the `Mediator` is interested in. + * + * @param {Notification} notification + */ + // eslint-disable-next-line no-unused-vars + handleNotification(notification) {} - /** - * the mediator name - * - * @returns {string} - */ - get mediatorName() { - return this._mediatorName; - } + /** + * the mediator name + * + * @returns {string} + */ + get mediatorName() { + return this._mediatorName; + } - /** - * Get the `Mediator`'s view component. - * - *

      - * Additionally, an implicit getter will usually - * be defined in the subclass that casts the view - * object to a type, like this:

      - * - * @returns {Object | null} - */ - get viewComponent() { - return this._viewComponent; - } + /** + * Get the `Mediator`'s view component. + * + *

      + * Additionally, an implicit getter will usually + * be defined in the subclass that casts the view + * object to a type, like this:

      + * + * @returns {Object | null} + */ + get viewComponent() { + return this._viewComponent; + } - /** - * Set the `Mediator`'s view component. - * - * @param {Object} viewComponent - */ - set viewComponent(viewComponent) { - this._viewComponent = viewComponent; - } + /** + * Set the `Mediator`'s view component. + * + * @param {Object} viewComponent + */ + set viewComponent(viewComponent) { + this._viewComponent = viewComponent; + } - /** - * The name of the `Mediator`. - * - *

      Typically, a `Mediator` will be written to serve - * one specific control or group controls and so, - * will not have a need to be dynamically named.

      - * - * @static - * @returns {string} - */ - static get NAME() { return "Mediator" } + /** + * The name of the `Mediator`. + * + *

      Typically, a `Mediator` will be written to serve + * one specific control or group controls and so, + * will not have a need to be dynamically named.

      + * + * @static + * @returns {string} + */ + static get NAME() { + return "Mediator"; + } } -export { Mediator } +export { Mediator }; diff --git a/src/patterns/observer/Notification.js b/src/patterns/observer/Notification.js index 3642425..dd12817 100644 --- a/src/patterns/observer/Notification.js +++ b/src/patterns/observer/Notification.js @@ -4,7 +4,7 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ /** * A base `Notification` implementation. @@ -37,77 +37,75 @@ * @class Notification */ class Notification { + /** + * Constructor. + * + * @constructor + * @param {string} name - The name of the notification. + * @param {Object|null} [body=null] - The body of the notification, defaults to `null`. + * @param {string} [type=""] - The type of the notification, defaults to an empty string. + */ + constructor(name, body = null, type = "") { + this._name = name; + this._body = body; + this._type = type; + } - /** - * Constructor. - * - * @constructor - * @param {string} name - The name of the notification. - * @param {Object|null} [body=null] - The body of the notification, defaults to `null`. - * @param {string} [type=""] - The type of the notification, defaults to an empty string. - */ - constructor(name, body = null, type = "") { - this._name = name; - this._body = body; - this._type = type; - } - - /** - * Get the name of the `Notification` instance. - * - * @returns {string} - */ - get name() { - return this._name; - } - - /** - * Get the body of the `Notification` instance. - * - * @returns {Object | null} - */ - get body() { - return this._body; - } + /** + * Get the name of the `Notification` instance. + * + * @returns {string} + */ + get name() { + return this._name; + } - /** - * Set the body of the `Notification` instance. - * - * @param {Object|null} body - */ - set body(body) { - this._body = body; - } + /** + * Get the body of the `Notification` instance. + * + * @returns {Object | null} + */ + get body() { + return this._body; + } - /** - * Get the type of the `Notification` instance. - * - * @returns {string} - */ - get type() { - return this._type; - } + /** + * Set the body of the `Notification` instance. + * + * @param {Object|null} body + */ + set body(body) { + this._body = body; + } - /** - * Set the type of the `Notification` instance. - * - * @param {string} type - */ - set type(type) { - this._type = type; - } + /** + * Get the type of the `Notification` instance. + * + * @returns {string} + */ + get type() { + return this._type; + } - /** - * Get the string representation of the `Notification` instance. - * - * @returns {string} - */ - toString() { - let str= "Notification Name: " + this.name; - str+= "\nBody:" + ((this.body == null ) ? "null" : this.body.toString()); - str+= "\nType:" + ((this.type == null ) ? "null" : this.type); - return str; - } + /** + * Set the type of the `Notification` instance. + * + * @param {string} type + */ + set type(type) { + this._type = type; + } + /** + * Get the string representation of the `Notification` instance. + * + * @returns {string} + */ + toString() { + let str = "Notification Name: " + this.name; + str += "\nBody:" + (this.body == null ? "null" : this.body.toString()); + str += "\nType:" + (this.type == null ? "null" : this.type); + return str; + } } -export { Notification } +export { Notification }; diff --git a/src/patterns/observer/Notifier.js b/src/patterns/observer/Notifier.js index a3cfaa3..870902a 100755 --- a/src/patterns/observer/Notifier.js +++ b/src/patterns/observer/Notifier.js @@ -4,9 +4,9 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {Facade} from "../facade/Facade.js"; +import { Facade } from "../facade/Facade.js"; /** * A Base `Notifier` implementation. @@ -43,64 +43,65 @@ import {Facade} from "../facade/Facade.js"; * @class Notifier */ class Notifier { + constructor() {} - constructor() {} - - /** - * Create and send a `Notification`. - * - *

      Keeps us from having to construct new Notification - * instances in our implementation code.

      - * - * @param {string} notificationName - * @param {Object} [body] body - * @param {string} [type] type - */ - sendNotification (notificationName, body = null, type = "") { - if (this.facade != null) { - this.facade.sendNotification(notificationName, body, type); - } + /** + * Create and send a `Notification`. + * + *

      Keeps us from having to construct new Notification + * instances in our implementation code.

      + * + * @param {string} notificationName + * @param {Object} [body] body + * @param {string} [type] type + */ + sendNotification(notificationName, body = null, type = "") { + if (this.facade != null) { + this.facade.sendNotification(notificationName, body, type); } + } - /** - * Initialize this Notifier instance. - * - *

      This is how a Notifier gets its multitonKey. - * Calls to sendNotification or to access the - * facade will fail until after this method - * has been called.

      - * - *

      Mediators, Commands or Proxies may override - * this method in order to send notifications - * or access the Multiton Facade instance as - * soon as possible. They CANNOT access the facade - * in their constructors, since this method will not - * yet have been called.

      - * - * @param {string} key the multitonKey for this Notifier to use - */ - initializeNotifier(key) { - this.multitonKey = key; - } + /** + * Initialize this Notifier instance. + * + *

      This is how a Notifier gets its multitonKey. + * Calls to sendNotification or to access the + * facade will fail until after this method + * has been called.

      + * + *

      Mediators, Commands or Proxies may override + * this method in order to send notifications + * or access the Multiton Facade instance as + * soon as possible. They CANNOT access the facade + * in their constructors, since this method will not + * yet have been called.

      + * + * @param {string} key the multitonKey for this Notifier to use + */ + initializeNotifier(key) { + this.multitonKey = key; + } - /** - * Return the Multiton Facade instance - * - * @returns {Facade} - * - * @throws {Error} - */ - get facade() { - if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG); - return Facade.getInstance(this.multitonKey, key => new Facade(key)); - } + /** + * Return the Multiton Facade instance + * + * @returns {Facade} + * + * @throws {Error} + */ + get facade() { + if (this.multitonKey == null) throw new Error(Notifier.MULTITON_MSG); + return Facade.getInstance(this.multitonKey, (key) => new Facade(key)); + } - /** - * Message Constants - * - * @static - * @returns {string} - */ - static get MULTITON_MSG() { return "multitonKey for this Notifier not yet initialized!" } + /** + * Message Constants + * + * @static + * @returns {string} + */ + static get MULTITON_MSG() { + return "multitonKey for this Notifier not yet initialized!"; + } } -export { Notifier } +export { Notifier }; diff --git a/src/patterns/observer/Observer.js b/src/patterns/observer/Observer.js index accedde..d06fc62 100644 --- a/src/patterns/observer/Observer.js +++ b/src/patterns/observer/Observer.js @@ -4,7 +4,7 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ /** * A base `Observer` implementation. @@ -25,77 +25,75 @@ * @class Observer */ class Observer { + /** + * Constructor. + * + *

      The notification method on the interested object should take + * one parameter of type `Notification`

      + * + * @param {function(Notification):void | null} [notify = null] + * @param {Object | null} [context = null] + */ + constructor(notify = null, context = null) { + this._notifyMethod = notify; + this._notifyContext = context; + } - /** - * Constructor. - * - *

      The notification method on the interested object should take - * one parameter of type `Notification`

      - * - * @param {function(Notification):void | null} [notify = null] - * @param {Object | null} [context = null] - */ - constructor(notify = null, context = null) { - this._notifyMethod = notify; - this._notifyContext = context; - } - - /** - * Notify the interested object. - * - * @param {Notification} notification - */ - notifyObserver(notification) { - this._notifyMethod.call(this._notifyContext, notification); - } - - /** - * Compare an object to the notification context. - * - * @param {Object} notifyContext - * @returns {boolean} - */ - compareNotifyContext(notifyContext) { - return this._notifyContext === notifyContext; - } + /** + * Notify the interested object. + * + * @param {Notification} notification + */ + notifyObserver(notification) { + this._notifyMethod.call(this._notifyContext, notification); + } - /** - * Get the notification method. - * - * @returns {function(Notification):void} - */ - get notifyMethod() { - return this._notifyMethod - } + /** + * Compare an object to the notification context. + * + * @param {Object} notifyContext + * @returns {boolean} + */ + compareNotifyContext(notifyContext) { + return this._notifyContext === notifyContext; + } - /** - * Set the notification method. - * - *

      The notification method should take one parameter of type `Notification`.

      - * - * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received. - */ - set notifyMethod(notifyMethod) { - this._notifyMethod = notifyMethod; - } + /** + * Get the notification method. + * + * @returns {function(Notification):void} + */ + get notifyMethod() { + return this._notifyMethod; + } - /** - * Get the notifyContext - * - * @returns {Object} - */ - get notifyContext() { - return this._notifyContext; - } + /** + * Set the notification method. + * + *

      The notification method should take one parameter of type `Notification`.

      + * + * @param {function(Notification): void} notifyMethod - The function to be called when a notification is received. + */ + set notifyMethod(notifyMethod) { + this._notifyMethod = notifyMethod; + } - /** - * Set the notification context. - * - * @param {Object} notifyContext - */ - set notifyContext(notifyContext) { - this._notifyContext = notifyContext; - } + /** + * Get the notifyContext + * + * @returns {Object} + */ + get notifyContext() { + return this._notifyContext; + } + /** + * Set the notification context. + * + * @param {Object} notifyContext + */ + set notifyContext(notifyContext) { + this._notifyContext = notifyContext; + } } -export { Observer } +export { Observer }; diff --git a/src/patterns/proxy/Proxy.js b/src/patterns/proxy/Proxy.js index 799a0f0..33c24d2 100755 --- a/src/patterns/proxy/Proxy.js +++ b/src/patterns/proxy/Proxy.js @@ -4,9 +4,9 @@ * * Copyright(c) 2023 Saad Shams * Your reuse is governed by the BSD License -*/ + */ -import {Notifier} from "../observer/Notifier.js"; +import { Notifier } from "../observer/Notifier.js"; /** * A base `Proxy` implementation. @@ -29,65 +29,67 @@ import {Notifier} from "../observer/Notifier.js"; * @class Proxy */ class Proxy extends Notifier { - /** - * Constructor - * - * @constructor - * @param {string | null} [proxyName=null] - * @param {Object | null} [data=null] - */ - constructor(proxyName = null, data = null) { - super(); - /** @protected - * @type {string} */ - this._proxyName = proxyName || Proxy.NAME; - /** @protected - * @type {Object | null} */ - this._data = data; - } + /** + * Constructor + * + * @constructor + * @param {string | null} [proxyName=null] + * @param {Object | null} [data=null] + */ + constructor(proxyName = null, data = null) { + super(); + /** @protected + * @type {string} */ + this._proxyName = proxyName || Proxy.NAME; + /** @protected + * @type {Object | null} */ + this._data = data; + } - /** - * Called by the Model when the Proxy is registered - */ - onRegister() {} + /** + * Called by the Model when the Proxy is registered + */ + onRegister() {} - /** - * Called by the Model when the Proxy is removed - */ - onRemove() {} + /** + * Called by the Model when the Proxy is removed + */ + onRemove() {} - /** - * Get the proxy name - * - * @returns {string} - */ - get proxyName() { - return this._proxyName; - } + /** + * Get the proxy name + * + * @returns {string} + */ + get proxyName() { + return this._proxyName; + } - /** - * Get the data object - * - * @returns {Object | null} - */ - get data () { - return this._data; - } + /** + * Get the data object + * + * @returns {Object | null} + */ + get data() { + return this._data; + } - /** - * Set the data object - * - * @param {Object} data - */ - set data(data) { - this._data = data; - } + /** + * Set the data object + * + * @param {Object} data + */ + set data(data) { + this._data = data; + } - /** - * - * @static - * @returns {string} - */ - static get NAME() { return "Proxy" } + /** + * + * @static + * @returns {string} + */ + static get NAME() { + return "Proxy"; + } } -export { Proxy } +export { Proxy };