@eclipse-scout/core
Version:
Eclipse Scout runtime
271 lines (235 loc) • 9.61 kB
text/typescript
/*
* Copyright (c) 2010, 2025 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
import {
App, Desktop, DesktopCancelFormsEvent, DesktopFormActivateEvent, DesktopHistoryState, DesktopNotification, DisplayParent, Event, FileChooser, FileChooserAdapter, Form, FormAdapter, MessageBox, MessageBoxAdapter, ModelAdapter, objects,
Outline, RemoteEvent, Widget
} from '../index';
import $ from 'jquery';
export class DesktopAdapter extends ModelAdapter {
declare widget: Desktop;
constructor() {
super();
this._addRemoteProperties(['benchVisible', 'navigationVisible', 'navigationHandleVisible', 'headerVisible', 'geolocationServiceAvailable', 'inBackground', 'focusedElement']);
}
protected override _goOffline() {
this.widget.goOffline();
}
protected override _goOnline() {
this.widget.goOnline();
}
protected _onWidgetHistoryEntryActivate(event: Event & DesktopHistoryState) {
this._send('historyEntryActivate', {
deepLinkPath: event.deepLinkPath
});
}
protected _onWidgetRender(event: Event<Desktop>) {
this._send('desktopReady');
}
protected _onWidgetFormActivate(event: DesktopFormActivateEvent) {
if (event.form && !ModelAdapter.getModelAdapterForWidget(event.form, true)) {
return; // Ignore ScoutJS forms
}
this._sendFormActivate(event.form);
}
protected _sendFormActivate(form: Form) {
let eventData = {
formId: ModelAdapter.getModelAdapterForWidget(form, true)?.id
};
this._send('formActivate', eventData, {
coalesce: function(previous) {
// Do not coalesce if formId was set to null by the previous event,
// this is the only way the server knows that the desktop was brought to front
return this.target === previous.target && this.type === previous.type &&
!(!previous.formId && this.formId);
}
});
}
protected override _prepareRemoteProperty(propertyName: string, value: any): any {
if (propertyName === 'focusedElement') {
return value;
}
return super._prepareRemoteProperty(propertyName, value);
}
protected _sendFocusedElement(focusedElement: Widget) {
// Find the nearest widget with a model adapter
while (focusedElement && !focusedElement.modelAdapter) {
focusedElement = focusedElement.parent;
}
this._sendProperty('focusedElement', focusedElement ? focusedElement.id : null);
}
protected _logoAction(event: Event) {
this._send('logoAction');
}
protected override _onWidgetEvent(event: Event<Desktop>) {
if (event.type === 'formActivate') {
this._onWidgetFormActivate(event as DesktopFormActivateEvent);
} else if (event.type === 'historyEntryActivate') {
this._onWidgetHistoryEntryActivate(event as Event<Desktop> & DesktopHistoryState);
} else if (event.type === 'logoAction') {
this._logoAction(event);
} else if (event.type === 'cancelForms') {
this._onWidgetCancelAllForms(event as DesktopCancelFormsEvent);
} else if (event.type === 'render') {
this._onWidgetRender(event);
} else {
super._onWidgetEvent(event);
}
}
protected _onFormShow(event: RemoteEvent) {
let displayParent = this.session.getModelAdapter(event.displayParent);
if (displayParent) {
let form = this.session.getOrCreateWidget(event.form, displayParent.widget) as Form;
form.setDisplayParent(displayParent.widget as DisplayParent);
let hasPendingFormActivateEvent = this.session.asyncEvents.some(event => event.type === 'formActivate' && event.target === this.id);
if (!hasPendingFormActivateEvent) {
this.addFilterForWidgetEvent(widgetEvent => widgetEvent.type === 'formActivate' && (widgetEvent as DesktopFormActivateEvent).form === form);
}
this.widget.showForm(form, event.position);
}
}
protected _onFormHide(event: RemoteEvent) {
let displayParent = this.session.getModelAdapter(event.displayParent);
if (displayParent) {
let form = this.session.getModelAdapter(event.form) as FormAdapter;
this.widget.hideForm(form.widget);
}
}
protected _onFormActivate(event: RemoteEvent) {
let form = this.session.getWidget(event.form) as Form;
this.widget.activateForm(form);
}
protected _onWidgetCancelAllForms(event: DesktopCancelFormsEvent) {
const formIds: string[] = [];
const jsForms: Form[] = [];
for (const form of event.forms || []) {
if (form.modelAdapter) {
formIds.push(form.modelAdapter.id);
} else {
jsForms.push(form);
}
}
if (!formIds.length) {
// no remote forms, return without preventDefault
// this will cancel the js forms implicitly
return;
}
event.preventDefault();
// cancel all js forms first
let cancelJsForms: JQuery.Promise<void> = $.resolvedPromise();
if (jsForms.length) {
cancelJsForms = this.widget.cancelViews(jsForms);
}
// cancel remote forms after js forms are canceled (i.e. the promise was resolved) or the js-form-cancellation was cancelled (i.e. the promise was rejected)
if (formIds.length) {
cancelJsForms.always(() => this._send('cancelForms', {formIds}));
}
}
protected _onMessageBoxShow(event: RemoteEvent) {
let displayParent = this.session.getModelAdapter(event.displayParent);
if (displayParent) {
let messageBox = this.session.getOrCreateWidget(event.messageBox, displayParent.widget) as MessageBox;
let parent = displayParent.widget as DisplayParent;
messageBox.setDisplayParent(parent);
parent.messageBoxController.registerAndRender(messageBox);
}
}
protected _onMessageBoxHide(event: RemoteEvent) {
let displayParent = this.session.getModelAdapter(event.displayParent);
if (displayParent) {
let messageBox = this.session.getModelAdapter(event.messageBox) as MessageBoxAdapter;
let parent = displayParent.widget as DisplayParent;
parent.messageBoxController.unregisterAndRemove(messageBox.widget);
}
}
protected _onFileChooserShow(event: RemoteEvent) {
let displayParent = this.session.getModelAdapter(event.displayParent);
if (displayParent) {
let parent = displayParent.widget as DisplayParent;
let fileChooser = this.session.getOrCreateWidget(event.fileChooser, parent) as FileChooser;
fileChooser.setDisplayParent(parent);
parent.fileChooserController.registerAndRender(fileChooser);
}
}
protected _onFileChooserHide(event: RemoteEvent) {
let displayParent = this.session.getModelAdapter(event.displayParent);
if (displayParent) {
let fileChooser = this.session.getModelAdapter(event.fileChooser) as FileChooserAdapter;
let parent = displayParent.widget as DisplayParent;
parent.fileChooserController.unregisterAndRemove(fileChooser.widget);
}
}
protected _onOpenUri(event: RemoteEvent) {
this.widget.openUri(event.uri, event.action);
}
protected _onOutlineChanged(event: RemoteEvent) {
let outline = this.session.getOrCreateWidget(event.outline, this.widget) as Outline;
this.widget.setOutline(outline);
}
protected _onAddNotification(event: RemoteEvent) {
let notification = this.session.getOrCreateWidget(event.notification, this.widget) as DesktopNotification;
this.widget.addNotification(notification);
}
protected _onRemoveNotification(event: RemoteEvent) {
this.widget.removeNotification(event.notification);
}
protected _onOutlineContentActivate(event: RemoteEvent) {
this.widget.bringOutlineToFront();
}
override onModelAction(event: RemoteEvent) {
if (event.type === 'formShow') {
this._onFormShow(event);
} else if (event.type === 'formHide') {
this._onFormHide(event);
} else if (event.type === 'formActivate') {
this._onFormActivate(event);
} else if (event.type === 'messageBoxShow') {
this._onMessageBoxShow(event);
} else if (event.type === 'messageBoxHide') {
this._onMessageBoxHide(event);
} else if (event.type === 'fileChooserShow') {
this._onFileChooserShow(event);
} else if (event.type === 'fileChooserHide') {
this._onFileChooserHide(event);
} else if (event.type === 'openUri') {
this._onOpenUri(event);
} else if (event.type === 'outlineChanged') {
this._onOutlineChanged(event);
} else if (event.type === 'outlineContentActivate') {
this._onOutlineContentActivate(event);
} else if (event.type === 'addNotification') {
this._onAddNotification(event);
} else if (event.type === 'removeNotification') {
this._onRemoveNotification(event);
} else {
super.onModelAction(event);
}
}
/**
* Static method to modify the prototype of Desktop.
*/
static modifyDesktopPrototype() {
if (!App.get().remote) {
return;
}
objects.replacePrototypeFunction(Desktop, '_initTheme', DesktopAdapter._initTheme, true);
}
static _initTheme(this: Desktop & { _initThemeOrig; _activeTheme }) {
if (this.modelAdapter) {
// Write the active theme (defined by the UI server) to the desktop widget
this.setTheme(this._activeTheme());
} else {
this._initThemeOrig();
}
}
}
export interface FormWithModelAdapterId extends Form {
__modelAdapterId?: string;
}
App.addListener('bootstrap', DesktopAdapter.modifyDesktopPrototype);