@ima/core
Version:
IMA.js framework for isomorphic javascript application
200 lines (199 loc) • 8.03 kB
JavaScript
/* @if server **
export class ClientPageManager {};
/* @else */ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "ClientPageManager", {
enumerable: true,
get: function() {
return ClientPageManager;
}
});
const _task = require("@esmj/task");
const _AbstractPageManager = require("./AbstractPageManager");
const _Dispatcher = require("../../event/Dispatcher");
const _EventBus = require("../../event/EventBus");
const _Window = require("../../window/Window");
const _PageFactory = require("../PageFactory");
const _PageRenderer = require("../renderer/PageRenderer");
const _PageStateManager = require("../state/PageStateManager");
class ClientPageManager extends _AbstractPageManager.AbstractPageManager {
/**
* The utility for manipulating the global context and global
* client-side-specific APIs.
*/ _window;
/**
* The event bus for dispatching and listening for custom IMA events
* propagated through the DOM.
*/ _eventBus;
/**
* Event listener for the custom DOM events used by the event bus,
* bound to this instance.
*/ _boundOnCustomEventHandler = (event)=>{
this._onCustomEventHandler(event);
};
static get $dependencies() {
return [
_PageFactory.PageFactory,
_PageRenderer.PageRenderer,
_PageStateManager.PageStateManager,
'$PageHandlerRegistry',
_Dispatcher.Dispatcher,
_Window.Window,
_EventBus.EventBus
];
}
/**
* Initializes the client-side page manager.
*
* @param 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 The current renderer of the page.
* @param stateManager The current page state manager.
* @param handlerRegistry Instance of HandlerRegistry that
* holds a list of pre-manage and post-manage handlers.
* @param window The utility for manipulating the global context
* and global client-side-specific APIs.
* @param dispatcher IMA Dispatcher.
* @param eventBus The event bus for dispatching and listening
* for custom IMA events propagated through the DOM.
*/ constructor(pageFactory, pageRenderer, pageStateManager, handlerRegistry, dispatcher, window, eventBus){
super(pageFactory, pageRenderer, pageStateManager, handlerRegistry, dispatcher);
this._window = window;
this._eventBus = eventBus;
}
/**
* @inheritDoc
*/ init() {
super.init();
this._pageStateManager.onChange = (newState)=>{
this._onChangeStateHandler(newState);
};
this._eventBus.listenAll(this._window.getWindow(), this._boundOnCustomEventHandler);
}
/**
* @inheritDoc
*/ async manage({ route, options, params = {}, action = {} }) {
const response = await super.manage({
route,
options,
params,
action
});
await (0, _task.autoYield)();
await this._activatePageSource();
return response;
}
/**
* @inheritDoc
*/ async destroy() {
await 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 event The encountered event bus DOM event.
*/ _onCustomEventHandler(event) {
const { prefix, method, data, eventName } = this._parseCustomEvent(event);
const controllerInstance = this._managedPage.controllerInstance;
if (controllerInstance) {
let handled = this._handleEventWithController(prefix, method, data);
if (!handled) {
handled = this._handleEventWithExtensions(prefix, method, data);
}
if ($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 event The encountered event bus custom DOM event.
* @return The event's
* details.
*/ _parseCustomEvent(event) {
const eventName = event.detail.eventName;
const splitEventName = eventName.split('.');
let method = splitEventName.pop();
method = 'on' + method.charAt(0).toUpperCase() + eventName.slice(1);
const prefix = splitEventName.pop() ?? '';
const data = event.detail.data;
return {
prefix,
method,
data,
eventName
};
}
/**
* Attempts to handle the currently processed event bus custom DOM event
* using the current controller. The method returns `true` if the
* event is handled by the controller.
*
* @param method The name of the method the current controller
* should use to process the currently processed event bus custom
* DOM event.
* @param data The custom event's data.
* @return `true` if the event has been handled by the
* controller, `false` if the controller does not have a
* method for processing the event.
*/ _handleEventWithController(prefix, method, data) {
const controllerInstance = this._managedPage.controllerInstance;
if (((controllerInstance?.constructor).$name ?? '') === prefix && 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 `true` if the event is handled by the controller.
*
* @param method The name of the method the current controller
* should use to process the currently processed event bus custom
* DOM event.
* @param data The custom event's data.
* @return `true` if the event has been handled by one of
* the controller's extensions, `false` if none of the
* controller's extensions has a method for processing the event.
*/ _handleEventWithExtensions(prefix, method, data) {
const controllerInstance = this._managedPage.controllerInstance;
const extensions = controllerInstance.getExtensions();
for (const extension of extensions){
if ((extension.constructor.$name ?? '') === prefix && typeof extension[method] === 'function') {
extension[method](data);
return true;
}
}
return false;
}
/**
* On change event handler set state to view.
*/ _onChangeStateHandler(state) {
const controller = this._managedPage.controllerInstance;
if (controller) {
this._pageRenderer.setState(state);
}
}
} // @endif
//# sourceMappingURL=ClientPageManager.js.map