1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | 3x 2x 15x 15x 15x 15x 2x 2x 2x 2x 2x 2x 1x 1x 1x 5x 5x 5x 3x 3x 2x 3x 3x 1x 1x 1x 1x 1x 3x 3x 1x 1x 2x 3x 3x 3x 3x 1x 1x 2x 3x | // @client-side import ns from '../../namespace'; import AbstractPageManager from './AbstractPageManager'; import PageFactory from '../PageFactory'; import PageRenderer from '../renderer/PageRenderer'; import PageStateManager from '../state/PageStateManager'; import EventBus from '../../event/EventBus'; import Window from '../../window/Window'; ns.namespace('ima.page.manager'); /** * Page manager for controller on the client side. */ export default class ClientPageManager extends AbstractPageManager { static get $dependencies() { return [PageFactory, PageRenderer, PageStateManager, Window, EventBus]; } /** * Initializes the client-side page manager. * * @param {PageFactory} pageFactory Factory used by the page manager to * create instances of the controller for the current route, and * decorate the controllers and page state managers. * @param {PageRenderer} pageRenderer The current renderer of the page. * @param {PageStateManager} stateManager The current page state manager. * @param {Window} window The utility for manipulating the global context * and global client-side-specific APIs. * @param {EventBus} eventBus The event bus for dispatching and listening * for custom IMA events propagated through the DOM. */ constructor(pageFactory, pageRenderer, stateManager, window, eventBus) { super(pageFactory, pageRenderer, stateManager); /** * The utility for manipulating the global context and global * client-side-specific APIs. * * @type {ima.window.Window} */ this._window = window; /** * The event bus for dispatching and listening for custom IMA events * propagated through the DOM. * * @type {ima.event.EventBus} */ this._eventBus = eventBus; /** * Event listener for the custom DOM events used by the event bus, * bound to this instance. * * @type {function(this: ClientPageManager, Event)} */ this._boundOnCustomEventHandler = event => { this._onCustomEventHandler(event); }; } /** * @inheritdoc */ init() { super.init(); this._eventBus.listenAll( this._window.getWindow(), this._boundOnCustomEventHandler ); } /** * @inheritdoc */ manage(controller, view, options, params = {}) { return super.manage(controller, view, options, params).then(response => { this._activatePageSource(); return response; }); } /** * @inheritdoc */ scrollTo(x = 0, y = 0) { setTimeout(() => { this._window.scrollTo(x, y); }, 0); } /** * @inheritdoc */ destroy() { super.destroy(); this._eventBus.unlistenAll( this._window.getWindow(), this._boundOnCustomEventHandler ); } /** * Custom DOM event handler. * * The handler invokes the event listener in the active controller, if such * listener is present. The name of the controller's listener method is * created by turning the first symbol of the event's name to upper case, * and then prefixing the result with the 'on' prefix. * * For example: for an event named 'toggle' the controller's listener * would be named 'onToggle'. * * The controller's listener will be invoked with the event's data as an * argument. * * @param {CustomEvent} event The encountered event bus DOM event. */ _onCustomEventHandler(event) { let { method, data, eventName } = this._parseCustomEvent(event); let controllerInstance = this._managedPage.controllerInstance; if (controllerInstance) { let handled = this._handleEventWithController(method, data); if (!handled) { handled = this._handleEventWithExtensions(method, data); } Eif ($Debug) { if (!handled) { console.warn( `The active controller has no listener for ` + `the encountered event '${eventName}'. Check ` + `your event name for typos, or create an ` + `'${method}' event listener method on the ` + `active controller or add an event listener ` + `that stops the propagation of this event to ` + `an ancestor component of the component that ` + `fired this event.` ); } } } } /** * Extracts the details of the provided event bus custom DOM event, along * with the expected name of the current controller's method for * intercepting the event. * * @param {CustomEvent} event The encountered event bus custom DOM event. * @return {{ method: string, data: *, eventName: string }} The event's * details. */ _parseCustomEvent(event) { let eventName = event.detail.eventName; let method = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1); let data = event.detail.data; return { method, data, eventName }; } /** * Attempts to handle the currently processed event bus custom DOM event * using the current controller. The method returns {@code true} if the * event is handled by the controller. * * @param {string} method The name of the method the current controller * should use to process the currently processed event bus custom * DOM event. * @param {Object<string, *>} data The custom event's data. * @return {boolean} {@code true} if the event has been handled by the * controller, {@code false} if the controller does not have a * method for processing the event. */ _handleEventWithController(method, data) { let controllerInstance = this._managedPage.controllerInstance; if (typeof controllerInstance[method] === 'function') { controllerInstance[method](data); return true; } return false; } /** * Attempts to handle the currently processed event bus custom DOM event * using the registered extensions of the current controller. The method * returns {@code true} if the event is handled by the controller. * * @param {string} method The name of the method the current controller * should use to process the currently processed event bus custom * DOM event. * @param {Object<string, *>} data The custom event's data. * @return {boolean} {@code true} if the event has been handled by one of * the controller's extensions, {@code false} if none of the * controller's extensions has a method for processing the event. */ _handleEventWithExtensions(method, data) { let controllerInstance = this._managedPage.controllerInstance; let extensions = controllerInstance.getExtensions(); for (let extension of extensions) { if (typeof extension[method] === 'function') { extension[method](data); return true; } } return false; } } ns.ima.page.manager.ClientPageManager = ClientPageManager; |