comindware.core.ui
Version:
Comindware Core UI provides the basic components like editors, lists, dropdowns, popups that we so desperately need while creating Marionette-based single-page applications.
225 lines (188 loc) • 8.84 kB
text/typescript
import CTEventsService from '../services/CTEventsService';
import WebSocketService from '../services/WebSocketService';
import ToastNotificationService from '../services/ToastNotificationService';
import RoutingService from '../services/RoutingService';
import PresenterService from '../services/PresenterService';
import Backbone from 'backbone';
export default class Controller {
constructor(options = {}) {
this.moduleRegion = options.region || window.contentRegion;
this.options = options;
/*
this.listenTo(CTEventsService, 'cbEvent', this.__handleEvent);
if (WebSocketService.isConnected()) {
this.listenTo(WebSocketService, 'ws:open ws:close ws:message ws:error', this.__handleSocketEvent);
}
*/
this.moduleId = options.config.id;
this.initialize && this.initialize(options);
}
leave(isCalledByUnloadEvent) {
if (typeof this.onLeave === 'function') {
const moduleLeaveConfig = this.onLeave();
if (typeof moduleLeaveConfig === 'boolean') {
return this.__checkPromisesAndLeave(moduleLeaveConfig);
}
if (isCalledByUnloadEvent) {
return false;
}
return Core.services.MessageService.showSystemMessage(moduleLeaveConfig);
}
return this.__checkPromisesAndLeave(true);
}
static setLoading(isLoading: boolean, message: string | undefined): void {
RoutingService.setModuleLoading(isLoading, { message });
if (isLoading === false) {
Core.Controller.__onModuleReady();
}
}
triggerEvent(eventId, data) {
CTEventsService.triggerStorageEvent(eventId, data);
}
sendWebSocketMessage(data) {
WebSocketService.send(this.moduleId, data);
}
async handleRouterEvent(configuration, callParams) {
const { view, viewModel, additionalViewOptions, errorView, viewEvents, routingAction, urlParams } = configuration;
const methodParams = this.__applyCallParamsFilter(callParams, urlParams, routingAction);
if (configuration.url) {
const { data, error } = await this.__request(configuration, methodParams, callParams);
if (error !== null) {
if (errorView) {
const presentingView = new errorView();
if (viewEvents) {
Object.keys(viewEvents).forEach(key => presentingView.listenTo(presentingView, key, viewEvents[key].bind(this)));
}
this.moduleRegion.show(presentingView);
}
}
if (viewModel) {
const model = new viewModel(data, { parse: true });
if (view) {
const viewParams = additionalViewOptions ? Object.assign({ model }, additionalViewOptions) : { model };
viewParams.viewState = this.currentState;
const presentingView = new view(viewParams);
if (viewEvents) {
Object.keys(viewEvents).forEach(key => presentingView.listenTo(presentingView, key, viewEvents[key].bind(this)));
}
presentingView.request = this.__handleViewResourceRequest.bind(this);
this.moduleRegion.show(presentingView);
}
}
} else {
const model = new viewModel();
if (view) {
const viewParams = additionalViewOptions ? Object.assign({ model }, additionalViewOptions) : { model };
viewParams.currentState = callParams;
const presentingView = new view(viewParams);
if (viewEvents) {
Object.keys(viewEvents).forEach(key => presentingView.listenTo(presentingView, key, viewEvents[key].bind(this)));
}
presentingView.request = this.__handleViewResourceRequest.bind(this);
this.moduleRegion.show(presentingView);
}
}
}
destroy(...rest) {
this.moduleRegion.empty();
this.onDestroy?.(...rest);
}
__checkPromisesAndLeave(canLeave: boolean) {
if (Core.services.PromiseService.checkBeforeLeave()) {
return Core.services.MessageService.showSystemMessage({
type: Core.services.MessageService.systemMessagesTypes.unsavedChanges
});
}
return canLeave;
}
__handleEvent(data) {
if (this.eventsHandlers && this.eventsHandlers[data.id]) {
this.eventsHandlers[data.id](data.data);
}
}
__handleSocketEvent(data) {
if (this.eventsHandlers && this.moduleId === data.id && this.eventsHandlers.onWebSocketMessage) {
this.eventsHandlers.onWebSocketMessage.call(this, data.data);
}
}
//todo extract view params and pass to failure
async __request(configuration, methodParams, callParams) {
const { notifications, onFailure, onSuccess } = configuration;
const params = configuration.url.split('/');
const showMask = configuration.showLoadingMask !== false;
showMask && RoutingService.setModuleLoading(true);
try {
const requestFn = Ajax[params[0]][params[1]];
if (requestFn) {
const functionSignature = window.ajaxMap.find(requestTemplate => requestTemplate.className === params[0] && requestTemplate.methodName === params[1]);
const requestType = functionSignature.httpMethod;
const parameters = functionSignature.parameters;
callParams && this.__applyState(callParams, parameters);
const data = await requestFn.apply(this, methodParams);
notifications && notifications.onSuccess && ToastNotificationService.add(notifications.onSuccess);
onSuccess && onSuccess.call(this, data, methodParams);
return { data, requestType, error: null };
}
throw new Error('Please, provide a valid URL');
} catch (error) {
notifications && notifications.onFailure && ToastNotificationService.add(notifications.onFailure);
onFailure && onFailure.call(this, error);
return { data: null, requestType: null, error };
} finally {
showMask && RoutingService.setModuleLoading(false);
}
}
async __handleViewResourceRequest(requestId, requestData) {
const requestConfig = this.requests[requestId];
if (requestConfig) {
const { data, requestType, error } = await this.__request(requestConfig, [requestData.data]);
if (error === null) {
switch (requestType) {
case 'POST':
if (requestData.model) {
if (requestData.model.model) {
const newModel = new requestData.model.model(Object.assign({ id: data }, requestData.data));
requestData.model.add(newModel, { remove: false });
}
}
break;
case 'DELETE': {
const callParamsDeletionItems = requestData.data;
if (requestData.model) {
requestData.model.remove(callParamsDeletionItems);
}
break;
}
case 'PUT': {
requestData.model && requestData.model.set(new Backbone.Model(requestData.data), { remove: false });
break;
}
case 'GET':
default:
break;
}
}
return data;
}
return null; //todo handle error
}
__applyState(callParams, parameters) {
this.currentState = {};
parameters.forEach((param, i) => (this.currentState[param.name] = callParams[i]));
}
__applyCallParamsFilter(callParams, urlParams, routingAction) {
if (routingAction && urlParams) {
const queryString = this.options.config.navigationUrl[routingAction];
const params = queryString.split('/');
const filteredParams = [];
urlParams.forEach(param => params.indexOf(param) > -1 && filteredParams.push(callParams[params.indexOf(param) / 2]));
return filteredParams;
}
return callParams;
}
static __onModuleReady() {
if (this.componentQuery) {
PresenterService.presentComponentSequence(this.componentQuery);
}
}
}