diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0bf7ec3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2023, Saad Shams + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 5070574..de22f88 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ This demo illustrates techniques for performing routine client-side maintenance * [plainJS](https://plainjs.com/javascript/) * Vanilla JS Animations using [Robert Penner's Easing Functions](http://robertpenner.com/easing/) | [Cheat Sheet](https://easings.net/) +## Installation +```shell +npm run build +npm run preview +``` + ## Semantic HTML Components ```html diff --git a/bin/index.html b/bin/index.html index 91e96b5..65d477f 100644 --- a/bin/index.html +++ b/bin/index.html @@ -4,8 +4,8 @@ Employee Admin - - + +
@@ -46,27 +46,27 @@

User Form

- \ No newline at end of file + diff --git a/build/playwright.js b/build/playwright.js index 06884e2..87d038d 100644 --- a/build/playwright.js +++ b/build/playwright.js @@ -1,3 +1,11 @@ +// +// playwright.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + // @ts-check import {defineConfig, devices} from "@playwright/test"; diff --git a/build/vite.js b/build/vite.js index f084fca..ff97b59 100644 --- a/build/vite.js +++ b/build/vite.js @@ -1,4 +1,10 @@ -import path from 'path'; +// +// vite.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// export default { root: "src", diff --git a/package-lock.json b/package-lock.json index ef15e0b..cae1237 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "puremvc-js-demo-employeeadmin", "version": "2.0.0", "license": "CC-BY-3.0", + "dependencies": { + "@puremvc/puremvc-js-multicore-framework": "2.0.7" + }, "devDependencies": { "@playwright/test": "^1.40.1", "@types/node": "^20.10.5", @@ -398,6 +401,14 @@ "node": ">=18" } }, + "node_modules/@puremvc/puremvc-js-multicore-framework": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@puremvc/puremvc-js-multicore-framework/-/puremvc-js-multicore-framework-2.0.7.tgz", + "integrity": "sha512-cpBmacRnkaOivij1TLwN6tzxlxINPknpmQJCDH3Y7oNuEzASKJplYBGevvaxMFgOUknJzZHVy66R9jEM6yw0oA==", + "bin": { + "puremvc-js-multicore-framework": "bin/puremvc.js" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", diff --git a/package.json b/package.json index b055ba0..a0ba61a 100755 --- a/package.json +++ b/package.json @@ -36,5 +36,8 @@ "browserslist": [ "defaults", "cover 99.5%" - ] + ], + "dependencies": { + "@puremvc/puremvc-js-multicore-framework": "2.0.7" + } } diff --git a/src/css/app.css b/src/css/app.css index 18d60df..209dc92 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -1,5 +1,11 @@ @charset "UTF-8"; +/** + app.css + PureMVC JS Demo - EmployeeAdmin + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ @import url("base.css"); @import url("layout.css"); @import url("module_user.css"); diff --git a/src/css/base.css b/src/css/base.css index 47d42ed..e3af66b 100644 --- a/src/css/base.css +++ b/src/css/base.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + base.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ *, *::before, *::after { box-sizing: border-box; } diff --git a/src/css/layout.css b/src/css/layout.css index 1d916b8..250eb27 100644 --- a/src/css/layout.css +++ b/src/css/layout.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + layout.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ html { height: 100%; } diff --git a/src/css/module_form.css b/src/css/module_form.css index d4b0a84..5fb5785 100644 --- a/src/css/module_form.css +++ b/src/css/module_form.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + module_form.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ #userForm .wrapper { display: flex; flex-direction: column; diff --git a/src/css/module_role.css b/src/css/module_role.css index 41742a5..d30e842 100644 --- a/src/css/module_role.css +++ b/src/css/module_role.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + module_role.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ #userRole .wrapper { display: flex; flex-direction: column; @@ -66,4 +73,4 @@ padding: 0 7px; margin-right: 10px; } -} \ No newline at end of file +} diff --git a/src/css/module_user.css b/src/css/module_user.css index 7e98eaa..907a529 100644 --- a/src/css/module_user.css +++ b/src/css/module_user.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + module_user.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ #userList .wrapper { display: flex; flex-direction: column; @@ -51,6 +58,7 @@ padding: 10px; margin-top: auto; } + @media screen and (max-width: 767px) { /* Small screens (phones) */ #userList main ul li label span:nth-child(n+2), #userList main ul li:first-child span:nth-child(n+2) { /* Hide all columns starting from the 2nd column */ diff --git a/src/css/theme-dark.css b/src/css/theme-dark.css index 3ddf1af..651c28d 100644 --- a/src/css/theme-dark.css +++ b/src/css/theme-dark.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + theme-dark.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ :root { --dark-theme-color: #ffffff; --dark-theme-background: #121212; diff --git a/src/css/theme.css b/src/css/theme.css index e6d14b4..6fa79a2 100644 --- a/src/css/theme.css +++ b/src/css/theme.css @@ -1,4 +1,11 @@ @charset "UTF-8"; +/** + theme.css + PureMVC JS Demo - EmployeeAdmin + + Copyright(c) 2023 Saad Shams + Your reuse is governed by the BSD 3-Clause License +*/ :root { --light-theme-color: #ffffff; --light-theme-disabled: #eaeded; diff --git a/src/index.html b/src/index.html index d15e812..11ca1d5 100644 --- a/src/index.html +++ b/src/index.html @@ -5,7 +5,7 @@ Employee Admin - +
@@ -102,4 +102,4 @@

User Roles

- \ No newline at end of file + diff --git a/src/js/Application.js b/src/js/Application.js new file mode 100644 index 0000000..2aec8e3 --- /dev/null +++ b/src/js/Application.js @@ -0,0 +1,14 @@ +// +// Application.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + +import {ApplicationFacade} from "./ApplicationFacade.js"; + +document.addEventListener("DOMContentLoaded", () => { + ApplicationFacade.getInstance("EmployeeAdmin").startup(); +}); + diff --git a/src/js/ApplicationFacade.js b/src/js/ApplicationFacade.js index bf2a73e..0eb0592 100644 --- a/src/js/ApplicationFacade.js +++ b/src/js/ApplicationFacade.js @@ -1,7 +1,15 @@ -import {puremvc} from "./api/puremvc-2.0.0.js" +// +// ApplicationFacade.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + +import {Facade} from "@puremvc/puremvc-js-multicore-framework"; import {StartupCommand} from "./controller/StartupCommand.js"; -export class ApplicationFacade extends puremvc.Facade { +export class ApplicationFacade extends Facade { static get STARTUP () { return "startup" } @@ -29,11 +37,11 @@ export class ApplicationFacade extends puremvc.Facade { } static getInstance(key) { - return puremvc.Facade.getInstance(key, k => new ApplicationFacade(k)); + return Facade.getInstance(key, k => new ApplicationFacade(k)); } startup(app) { this.sendNotification(ApplicationFacade.STARTUP, app); } -} \ No newline at end of file +} diff --git a/src/js/api/puremvc-2.0.0.js b/src/js/api/puremvc-2.0.0.js deleted file mode 100644 index 0f47675..0000000 --- a/src/js/api/puremvc-2.0.0.js +++ /dev/null @@ -1,1640 +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} notifyMethod - * @param {Object} notifyContext - */ - constructor(notifyMethod, notifyContext) { - this._notifyMethod = notifyMethod; - this._notifyContext = notifyContext; - } - - /** - * 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 )`

- * - * @throws {Error} Error if instance for this Multiton key has already been constructed - * - * @constructor - * @param {string} key - */ - 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} - */ - 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} mediatorName - * @param {Object} [viewComponent] viewComponent - */ - constructor(mediatorName, 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} - */ - 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} proxyName - * @param {Object} [data] - */ - constructor(proxyName, data = null) { - super(); - /** @protected - * @type {string} */ - this._proxyName = proxyName || Proxy.NAME; - /** @protected - * @type {Object} */ - 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} - */ - 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" } -} - -/* - * index.js - * PureMVC JavaScript Multicore - * - * Copyright(c) 2023 Saad Shams - * Your reuse is governed by the BSD License -*/ - - -const puremvc = { - Controller, Model, View, - SimpleCommand, MacroCommand, Facade, - Mediator, Notification, Notifier, Observer, Proxy -}; - -export { puremvc }; diff --git a/src/js/app.js b/src/js/app.js deleted file mode 100644 index fe0c761..0000000 --- a/src/js/app.js +++ /dev/null @@ -1,6 +0,0 @@ -import {ApplicationFacade} from "./ApplicationFacade.js"; - -document.addEventListener("DOMContentLoaded", () => { - ApplicationFacade.getInstance("EmployeeAdmin").startup(); -}); - diff --git a/src/js/controller/StartupCommand.js b/src/js/controller/StartupCommand.js index 7c2a1ac..c3e266f 100644 --- a/src/js/controller/StartupCommand.js +++ b/src/js/controller/StartupCommand.js @@ -1,4 +1,12 @@ -import {puremvc} from "../api/puremvc-2.0.0.js" +// +// StartupCommand.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + +import {SimpleCommand} from "@puremvc/puremvc-js-multicore-framework"; import {Department} from "../model/enum/Department.js"; import {Role} from "../model/enum/Role.js"; import {User} from "../model/vo/User.js"; @@ -8,9 +16,9 @@ import {UserListMediator} from "../view/UserListMediator.js"; import {UserFormMediator} from "../view/UserFormMediator.js"; import {UserRoleMediator} from "../view/UserRoleMediator.js"; -export class StartupCommand extends puremvc.SimpleCommand { +export class StartupCommand extends SimpleCommand { - /** @param notification {puremvc.Notification} */ + /** @param notification {Notification} */ execute(notification) { let userProxy = new UserProxy(); userProxy.add(new User(1, "lstooge","Larry", "Stooge", "larry@stooges.com", "ijk456", Department.ACCT, [Role.EMP_BENEFITS])); @@ -25,4 +33,4 @@ export class StartupCommand extends puremvc.SimpleCommand { this.facade.registerMediator(new UserRoleMediator()); } -} \ No newline at end of file +} diff --git a/src/js/model/RoleProxy.js b/src/js/model/RoleProxy.js index 3969826..42ac11c 100644 --- a/src/js/model/RoleProxy.js +++ b/src/js/model/RoleProxy.js @@ -1,6 +1,14 @@ -import {puremvc} from "../api/puremvc-2.0.0.js" +// +// RoleProxy.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// -export class RoleProxy extends puremvc.Proxy { +import {Proxy} from "@puremvc/puremvc-js-multicore-framework"; + +export class RoleProxy extends Proxy { static get NAME() { return "RoleProxy" } @@ -29,4 +37,4 @@ export class RoleProxy extends puremvc.Proxy { } } -} \ No newline at end of file +} diff --git a/src/js/model/UserProxy.js b/src/js/model/UserProxy.js index 538252d..bc4512b 100644 --- a/src/js/model/UserProxy.js +++ b/src/js/model/UserProxy.js @@ -1,6 +1,14 @@ -import {puremvc} from "../api/puremvc-2.0.0.js" +// +// UserProxy.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// -export class UserProxy extends puremvc.Proxy { +import {Proxy} from "@puremvc/puremvc-js-multicore-framework"; + +export class UserProxy extends Proxy { static get NAME () { return "UserProxy"; } diff --git a/src/js/model/enum/Department.js b/src/js/model/enum/Department.js index 623ff8c..d013a8c 100644 --- a/src/js/model/enum/Department.js +++ b/src/js/model/enum/Department.js @@ -1,3 +1,11 @@ +// +// Department.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + export class Department { static NONE_SELECTED = new Department(0, "---None Selected---"); diff --git a/src/js/model/enum/Role.js b/src/js/model/enum/Role.js index adc50e3..98d3ed5 100644 --- a/src/js/model/enum/Role.js +++ b/src/js/model/enum/Role.js @@ -1,3 +1,11 @@ +// +// Role.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + export class Role { static NONE_SELECTED = new Role(0, "--None Selected---"); @@ -60,4 +68,4 @@ export class Role { return this.id === role.id && this.name === role.name; } -} \ No newline at end of file +} diff --git a/src/js/model/vo/User.js b/src/js/model/vo/User.js index 2bca33b..7699241 100644 --- a/src/js/model/vo/User.js +++ b/src/js/model/vo/User.js @@ -1,3 +1,11 @@ +// +// User.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + import {Department} from "../enum/Department.js"; export class User { @@ -32,4 +40,4 @@ export class User { this.password !== "" && this.password === confirm && this.department.id !== 0; } -} \ No newline at end of file +} diff --git a/src/js/view/UserFormMediator.js b/src/js/view/UserFormMediator.js index 0511594..35dbea4 100644 --- a/src/js/view/UserFormMediator.js +++ b/src/js/view/UserFormMediator.js @@ -1,9 +1,17 @@ -import {puremvc} from "../api/puremvc-2.0.0.js" +// +// UserFormMediator.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + +import {Mediator} from "@puremvc/puremvc-js-multicore-framework"; import {UserForm} from "./components/UserForm.js"; import {ApplicationFacade} from "../ApplicationFacade.js"; import {UserProxy} from "../model/UserProxy.js"; -export class UserFormMediator extends puremvc.Mediator { +export class UserFormMediator extends Mediator { static get NAME() { return "UserFormMediator" } @@ -55,7 +63,7 @@ export class UserFormMediator extends puremvc.Mediator { ]; } - /** @param notification {puremvc.Notification} */ + /** @param notification {Notification} */ handleNotification(notification) { switch (notification.name) { case ApplicationFacade.NEW_USER: @@ -73,4 +81,4 @@ export class UserFormMediator extends puremvc.Mediator { get userForm() { return this.viewComponent } -} \ No newline at end of file +} diff --git a/src/js/view/UserListMediator.js b/src/js/view/UserListMediator.js index d54dd8a..4152582 100644 --- a/src/js/view/UserListMediator.js +++ b/src/js/view/UserListMediator.js @@ -1,9 +1,17 @@ -import {puremvc} from "../api/puremvc-2.0.0.js" +// +// UserListMediator.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + +import {Mediator} from "@puremvc/puremvc-js-multicore-framework"; import {UserList} from "./components/UserList.js"; import {UserProxy} from "../model/UserProxy.js"; import {ApplicationFacade} from "../ApplicationFacade.js"; -export class UserListMediator extends puremvc.Mediator { +export class UserListMediator extends Mediator { static get NAME() { return "UserListMediator" } @@ -49,7 +57,7 @@ export class UserListMediator extends puremvc.Mediator { ]; } - /** @param notification {puremvc.Notification} */ + /** @param notification {Notification} */ handleNotification(notification) { switch (notification.name) { case ApplicationFacade.USER_ADDED: @@ -69,4 +77,4 @@ export class UserListMediator extends puremvc.Mediator { get userList() { return this.viewComponent; } -} \ No newline at end of file +} diff --git a/src/js/view/UserRoleMediator.js b/src/js/view/UserRoleMediator.js index 6e776a0..4f8c035 100644 --- a/src/js/view/UserRoleMediator.js +++ b/src/js/view/UserRoleMediator.js @@ -1,9 +1,17 @@ -import {puremvc} from "../api/puremvc-2.0.0.js" +// +// UserRoleMediator.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + +import {Mediator} from "@puremvc/puremvc-js-multicore-framework"; import {UserRole} from "./components/UserRole.js"; import {ApplicationFacade} from "../ApplicationFacade.js"; import {RoleProxy} from "../model/RoleProxy.js"; -export class UserRoleMediator extends puremvc.Mediator { +export class UserRoleMediator extends Mediator { static get NAME() { return "UserRoleMediator" } @@ -44,7 +52,7 @@ export class UserRoleMediator extends puremvc.Mediator { ]; } - /** @param notification {puremvc.Notification} */ + /** @param notification {Notification} */ handleNotification(notification) { switch (notification.name) { case ApplicationFacade.NEW_USER: @@ -75,4 +83,4 @@ export class UserRoleMediator extends puremvc.Mediator { get userRole() { return this.viewComponent } -} \ No newline at end of file +} diff --git a/src/js/view/components/UserForm.js b/src/js/view/components/UserForm.js index 656a41e..d022252 100644 --- a/src/js/view/components/UserForm.js +++ b/src/js/view/components/UserForm.js @@ -1,3 +1,11 @@ +// +// UserForm.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + import {Easing} from "../../api/easing.js"; import {User} from "../../model/vo/User.js"; import {Department} from "../../model/enum/Department.js"; @@ -115,4 +123,4 @@ export class UserForm { get delegate() { return this._delegate } -} \ No newline at end of file +} diff --git a/src/js/view/components/UserList.js b/src/js/view/components/UserList.js index 681ae47..ce5a3d6 100644 --- a/src/js/view/components/UserList.js +++ b/src/js/view/components/UserList.js @@ -1,3 +1,11 @@ +// +// UserList.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + import {Easing} from "../../api/easing.js"; export class UserList { @@ -125,4 +133,4 @@ export class UserList { get delegate() { return this._delegate; } -} \ No newline at end of file +} diff --git a/src/js/view/components/UserRole.js b/src/js/view/components/UserRole.js index 3556ffd..4d26a47 100644 --- a/src/js/view/components/UserRole.js +++ b/src/js/view/components/UserRole.js @@ -1,3 +1,11 @@ +// +// UserRole.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + import {Easing} from "../../api/easing.js"; import {Role} from "../../model/enum/Role.js"; diff --git a/test/UITest.spec.js b/test/UITest.spec.js index 3f165e4..b07f23a 100644 --- a/test/UITest.spec.js +++ b/test/UITest.spec.js @@ -1,3 +1,11 @@ +// +// UITest.spec.js +// PureMVC JS Demo - EmployeeAdmin +// +// Copyright(c) 2023 Saad Shams +// Your reuse is governed by the BSD 3-Clause License +// + import {expect, test} from "@playwright/test"; test.describe("UI Tests", () => {