Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UiSession: fix theme initialization #1001

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eclipse-scout-core/src/desktop/Desktop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1682,7 +1682,7 @@ export class Desktop extends Widget implements DesktopModel, DisplayParent {
let theme = this.theme;
if (this.url.hasParameter('theme')) {
theme = strings.nullIfEmpty(this.url.getParameter('theme') as string) || Desktop.DEFAULT_THEME;
} else if (theme === null) {
} else if (!theme) {
theme = this._activeTheme();
}
this.setTheme(theme);
Expand Down
28 changes: 25 additions & 3 deletions eclipse-scout-core/src/desktop/DesktopAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
* Copyright (c) 2010, 2024 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -8,8 +8,8 @@
* SPDX-License-Identifier: EPL-2.0
*/
import {
Desktop, DesktopCancelFormsEvent, DesktopFormActivateEvent, DesktopHistoryState, DesktopNotification, DisplayParent, Event, FileChooser, FileChooserAdapter, Form, FormAdapter, MessageBox, MessageBoxAdapter, ModelAdapter, Outline,
RemoteEvent, Widget
App, Desktop, DesktopCancelFormsEvent, DesktopFormActivateEvent, DesktopHistoryState, DesktopNotification, DisplayParent, Event, FileChooser, FileChooserAdapter, Form, FormAdapter, MessageBox, MessageBoxAdapter, ModelAdapter, objects,
Outline, RemoteEvent, Widget
} from '../index';
import $ from 'jquery';

Expand Down Expand Up @@ -255,4 +255,26 @@ export class DesktopAdapter extends ModelAdapter {
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();
}
}
}

App.addListener('bootstrap', DesktopAdapter.modifyDesktopPrototype);
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,16 @@ protected void updatePreferredLocaleCookie(Locale locale) {
}
}

protected boolean initUiTheme(HttpServletRequest req, HttpServletResponse resp, Map<String, String> sessionStartupParams) {
// Run in a model job, because the computed theme is written to the model ("theme" property on the desktop)
IFuture<Boolean> future = ModelJobs.schedule(
() -> initUiThemeInternal(req, resp, sessionStartupParams),
ModelJobs.newInput(ClientRunContexts.copyCurrent().withSession(m_clientSession, true))
.withName("Initializing UI theme")
.withExceptionHandling(null, false /* propagate */)); // exception handling done by caller
return BEANS.get(UiJobs.class).awaitAndGet(future);
}

/**
* Info: instead of reload the current page in the browser, we could build a servlet-filter which determines what
* theme the user has _before_ the client-session is created. However, the 'reload' will only be performed in the case
Expand All @@ -412,32 +422,39 @@ protected void updatePreferredLocaleCookie(Locale locale) {
* @return Whether the page must be reloaded by the browser (required when theme changes after client-session has been
* initialized)
*/
protected boolean initUiTheme(HttpServletRequest req, HttpServletResponse resp, Map<String, String> sessionStartupParams) {
protected boolean initUiThemeInternal(HttpServletRequest req, HttpServletResponse resp, Map<String, String> sessionStartupParams) {
ModelJobs.assertModelThread(); // because we change the model ("theme" property on the desktop)
UiThemeHelper helper = UiThemeHelper.get();

String modelTheme = m_clientSession.getDesktop().getTheme();
String currentTheme = helper.getTheme(req);

// Ensure the model theme is valid, otherwise it could result in an endless reload loop
String validTheme = UiThemeHelper.get().validateTheme(modelTheme);
if (!ObjectUtility.equals(validTheme, modelTheme)) {
LOG.info("Model theme ({}) is not valid, switching to a valid one ({})", modelTheme, validTheme);
modelTheme = validTheme;
}

// If a theme is requested via URL this has priority before the theme from the session or the model
// If a theme is requested via URL, that has priority over the theme from the session or the model
String requestedTheme = sessionStartupParams.get(URL_PARAM_THEME);
if (requestedTheme != null) {
modelTheme = helper.validateTheme(requestedTheme);
modelTheme = requestedTheme;
}

if (modelTheme == null) {
modelTheme = ObjectUtility.nvl(currentTheme, helper.getConfiguredTheme());
m_clientSession.getDesktop().setTheme(currentTheme);
// "currentTheme" is valid by definition (see JavaDoc of UiThemeHelper#getTheme)
modelTheme = currentTheme;
}
else {
// Ensure the model theme is valid, otherwise it could result in an endless reload loop
String validTheme = helper.validateTheme(modelTheme);
if (!ObjectUtility.equals(validTheme, modelTheme)) {
LOG.warn("{} theme ({}) is not valid, switching to a valid one ({})", requestedTheme != null ? "Requested" : "Model", modelTheme, validTheme);
modelTheme = validTheme;
}
}

boolean reloadPage = !modelTheme.equals(currentTheme);
// Write the valid theme to the client session, so the desktop logo can be adjusted (but this is not stored in the user settings)
m_clientSession.getDesktop().setTheme(modelTheme);
// Set as current theme for subsequent requests with the same UI session
helper.storeTheme(resp, req.getSession(), modelTheme);
LOG.debug("UI theme model={} current={} reloadPage={}", modelTheme, currentTheme, reloadPage);

boolean reloadPage = !modelTheme.equals(currentTheme);
LOG.debug("UI theme requested={} current={} model={} reloadPage={}", requestedTheme, currentTheme, modelTheme, reloadPage);
return reloadPage;
}

Expand Down