IDEMPIERE-4421 Html asset versioning should allow fluent deployment (#420)

* IDEMPIERE-4421 Html asset versioning should allow fluent deployment

use classpath loading and lang-addon versioning for theme resources

* IDEMPIERE-4421 Html asset versioning should allow fluent deployment

Incorporate backward compatibility patch from Carlos.
This commit is contained in:
hengsin 2020-11-30 22:33:23 +08:00 committed by GitHub
parent 60e584655c
commit 5d236de30c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
281 changed files with 93 additions and 54 deletions

View File

@ -51,4 +51,8 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI).
<javascript-module name="org.idempiere.commons" version="202011230530"/> <javascript-module name="org.idempiere.commons" version="202011230530"/>
<javascript-module name="jquery.maskedinput" version="1.4.1" /> <javascript-module name="jquery.maskedinput" version="1.4.1" />
<javascript-module name="photobooth" version="0.7-rsd3" /> <javascript-module name="photobooth" version="0.7-rsd3" />
<!-- this js module doesn't actually exists and it is here for default theme version -->
<!-- since loading of js module is on demand, it doesn't cause any error as long as you don't try to load it -->
<javascript-module name="idempiere.theme.default" version="202011282132" />
</language> </language>

View File

@ -22,7 +22,6 @@ import org.adempiere.webui.adwindow.ADWindow;
import org.adempiere.webui.desktop.FavouriteController; import org.adempiere.webui.desktop.FavouriteController;
import org.adempiere.webui.exception.ApplicationException; import org.adempiere.webui.exception.ApplicationException;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ITheme;
import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.window.FDialog; import org.adempiere.webui.window.FDialog;
import org.compiere.model.MMenu; import org.compiere.model.MMenu;
@ -175,7 +174,7 @@ public class DPFavourites extends DashboardPanel implements EventListener<Event>
btnFavItem.setTooltiptext(description); btnFavItem.setTooltiptext(description);
if (ThemeManager.isUseFontIconForImage()) if (ThemeManager.isUseFontIconForImage())
btnFavItem.setIconSclass(imageSrc); btnFavItem.setIconSclass(imageSrc);
else if (imageSrc.startsWith(ITheme.THEME_PATH_PREFIX)) else if (imageSrc.startsWith(ThemeManager.THEME_PATH_PREFIX))
btnFavItem.setImage(imageSrc); btnFavItem.setImage(imageSrc);
else else
btnFavItem.setImage(ThemeManager.getThemeResource(imageSrc)); btnFavItem.setImage(ThemeManager.getThemeResource(imageSrc));

View File

@ -21,8 +21,9 @@ package org.adempiere.webui.theme;
public interface ITheme { public interface ITheme {
//default theme //default theme
public static final String ZK_THEME_DEFAULT = "default"; public static final String ZK_THEME_DEFAULT = "default";
//theme resource url prefix //theme resource url prefix. ~./ is the zk url prefix for resources loaded from classpath (typically at src/web folder)
public static final String THEME_PATH_PREFIX = "/theme/"; public static final String THEME_PATH_PREFIX_V8 = "~./theme/";
public static final String THEME_PATH_PREFIX_V7 = "/theme/"; // for backward compatibility
//css for login window and box //css for login window and box
public static final String LOGIN_WINDOW_CLASS = "login-window"; public static final String LOGIN_WINDOW_CLASS = "login-window";

View File

@ -32,18 +32,26 @@ import org.zkoss.image.AImage;
*/ */
public final class ThemeManager { public final class ThemeManager {
//zk predefined starting path for classpath resources (src/web)
public static final String ZK_PREFIX_FOR_CLASSPATH_RESOURCE = "/web";
//zk predefined url prefix for resources loaded from classpath
public static final String ZK_URL_PREFIX_FOR_CLASSPATH_RESOURCE = "~./";
/** Logger */ /** Logger */
private static CLogger log = CLogger.getCLogger(ThemeManager.class); private static CLogger log = CLogger.getCLogger(ThemeManager.class);
private static String m_theme = null; private static String m_theme = ITheme.ZK_THEME_DEFAULT;
private static String m_brokenTheme = null; private static String m_brokenTheme = null;
public static String THEME_PATH_PREFIX = ITheme.THEME_PATH_PREFIX_V8;
/** /**
* @return url for large logo * @return url for large logo
*/ */
public static String getLargeLogo() { public static String getLargeLogo() {
String theme = getTheme(); String theme = getTheme();
String def = ITheme.THEME_PATH_PREFIX+theme+ITheme.LOGIN_LOGO_IMAGE; String def = THEME_PATH_PREFIX+theme+ITheme.LOGIN_LOGO_IMAGE;
return MSysConfig.getValue(MSysConfig.ZK_LOGO_LARGE, def); return MSysConfig.getValue(MSysConfig.ZK_LOGO_LARGE, def);
} }
@ -52,7 +60,7 @@ public final class ThemeManager {
*/ */
public static String getSmallLogo() { public static String getSmallLogo() {
String theme = getTheme(); String theme = getTheme();
String def = ITheme.THEME_PATH_PREFIX+theme+ITheme.HEADER_LOGO_IMAGE; String def = THEME_PATH_PREFIX+theme+ITheme.HEADER_LOGO_IMAGE;
String url = MSysConfig.getValue(MSysConfig.ZK_LOGO_SMALL, null); String url = MSysConfig.getValue(MSysConfig.ZK_LOGO_SMALL, null);
if (url == null) if (url == null)
url = MSysConfig.getValue(MSysConfig.WEBUI_LOGOURL, def); url = MSysConfig.getValue(MSysConfig.WEBUI_LOGOURL, def);
@ -72,11 +80,21 @@ public final class ThemeManager {
if (! theme.equals(m_theme)) { if (! theme.equals(m_theme)) {
if (! ITheme.ZK_THEME_DEFAULT.equals(theme)) { if (! ITheme.ZK_THEME_DEFAULT.equals(theme)) {
// Verify the theme.css.dsp exists in the theme folder // Verify the theme.css.dsp exists in the theme folder
if (ThemeManager.class.getResource(ITheme.THEME_PATH_PREFIX + theme + ITheme.THEME_STYLESHEET) == null) { String themeCSSURL = THEME_PATH_PREFIX + theme + ITheme.THEME_STYLESHEET;
log.warning("The theme " + theme + " does not exist or is not properly configured, falling back to default"); if (ThemeManager.class.getResource(toClassPathResourcePath(themeCSSURL)) == null) {
m_brokenTheme = theme; // verify if is a v7 theme
theme = ITheme.ZK_THEME_DEFAULT; themeCSSURL = ITheme.THEME_PATH_PREFIX_V7 + theme + ITheme.THEME_STYLESHEET;
if (ThemeManager.class.getResource(toClassPathResourcePath(themeCSSURL)) != null) {
THEME_PATH_PREFIX = ITheme.THEME_PATH_PREFIX_V7;
} else {
log.warning("The theme " + theme + " does not exist or is not properly configured, falling back to default");
m_brokenTheme = theme;
THEME_PATH_PREFIX = ITheme.THEME_PATH_PREFIX_V8;
theme = ITheme.ZK_THEME_DEFAULT;
}
} }
} else {
THEME_PATH_PREFIX = ITheme.THEME_PATH_PREFIX_V8;
} }
m_theme = theme; m_theme = theme;
} }
@ -88,21 +106,21 @@ public final class ThemeManager {
* @return url of theme stylesheet * @return url of theme stylesheet
*/ */
public static String getStyleSheet() { public static String getStyleSheet() {
return ITheme.THEME_PATH_PREFIX + getTheme() + ITheme.THEME_STYLESHEET; return THEME_PATH_PREFIX + getTheme() + ITheme.THEME_STYLESHEET;
} }
/** /**
* @return url of theme stylesheet by browser * @return url of theme stylesheet by browser
*/ */
public static String getStyleSheetByBrowser() { public static String getStyleSheetByBrowser() {
return ITheme.THEME_PATH_PREFIX + getTheme() + ITheme.THEME_STYLESHEET_BY_BROWSER; return THEME_PATH_PREFIX + getTheme() + ITheme.THEME_STYLESHEET_BY_BROWSER;
} }
/** /**
* @return url of theme preference page * @return url of theme preference page
*/ */
public static String getPreference() { public static String getPreference() {
return ITheme.THEME_PATH_PREFIX + getTheme() + ITheme.THEME_PREFERENCE; return THEME_PATH_PREFIX + getTheme() + ITheme.THEME_PREFERENCE;
} }
/** /**
@ -117,7 +135,7 @@ public final class ThemeManager {
*/ */
public static String getBrowserIcon() { public static String getBrowserIcon() {
String theme = getTheme(); String theme = getTheme();
String def = ITheme.THEME_PATH_PREFIX + theme + ITheme.BROWSER_ICON_IMAGE; String def = THEME_PATH_PREFIX + theme + ITheme.BROWSER_ICON_IMAGE;
return MSysConfig.getValue(MSysConfig.ZK_BROWSER_ICON, def); return MSysConfig.getValue(MSysConfig.ZK_BROWSER_ICON, def);
} }
@ -127,7 +145,7 @@ public final class ThemeManager {
* @return full resource url * @return full resource url
*/ */
public static String getThemeResource(String name) { public static String getThemeResource(String name) {
StringBuilder builder = new StringBuilder(ITheme.THEME_PATH_PREFIX); StringBuilder builder = new StringBuilder(THEME_PATH_PREFIX);
builder.append(getTheme()); builder.append(getTheme());
builder.append("/").append(name); builder.append("/").append(name);
String url = builder.toString().intern(); String url = builder.toString().intern();
@ -173,7 +191,7 @@ public final class ThemeManager {
} }
private static final CCache<String, Boolean> s_themeHasCustomCSSCache = new CCache<String, Boolean>(null, "ThemeHasCustomCSSCache", 2, -1, false); private static final CCache<String, Boolean> s_themeHasCustomCSSCache = new CCache<String, Boolean>(null, "ThemeHasCustomCSSCache", 2, -1, false);
/** /**
* @return true if custom css exists * @return true if custom css exists
*/ */
@ -182,7 +200,8 @@ public final class ThemeManager {
Boolean flag = s_themeHasCustomCSSCache.get(theme); Boolean flag = s_themeHasCustomCSSCache.get(theme);
if (flag != null) if (flag != null)
return flag; return flag;
if (ThemeManager.class.getResource(ITheme.THEME_PATH_PREFIX + theme + "/css/fragment/custom.css.dsp") == null) { String customCSSURL = THEME_PATH_PREFIX + theme + "/css/fragment/custom.css.dsp";
if (ThemeManager.class.getResource(toClassPathResourcePath(customCSSURL)) == null) {
flag = Boolean.FALSE; flag = Boolean.FALSE;
} else { } else {
flag = Boolean.TRUE; flag = Boolean.TRUE;
@ -197,5 +216,19 @@ public final class ThemeManager {
public static boolean isUseFontIconForImage() { public static boolean isUseFontIconForImage() {
return "Y".equals(Env.getContext(Env.getCtx(), ITheme.USE_FONT_ICON_FOR_IMAGE)); return "Y".equals(Env.getContext(Env.getCtx(), ITheme.USE_FONT_ICON_FOR_IMAGE));
} }
/**
* @param zkResourceURL zk resource url for classpath resources (url start with ~./)
* @return Resource path for lookup/loading through class loader (absolute path start with /web)
*/
public static String toClassPathResourcePath(String zkResourceURL) {
if (zkResourceURL == null)
return zkResourceURL;
if (!zkResourceURL.startsWith(ZK_URL_PREFIX_FOR_CLASSPATH_RESOURCE))
return zkResourceURL;
return ZK_PREFIX_FOR_CLASSPATH_RESOURCE+zkResourceURL.substring(2);
}
} }

View File

@ -74,13 +74,21 @@ public class WebUIResourceFinder implements IResourceFinder {
} }
} else if (url == null && name.startsWith("images/")) { } else if (url == null && name.startsWith("images/")) {
String t = ThemeManager.getThemeResource(name); String t = ThemeManager.getThemeResource(name);
e = find(t); if (t.startsWith(ThemeManager.ZK_URL_PREFIX_FOR_CLASSPATH_RESOURCE)) {
url = e != null && e.hasMoreElements() ? e.nextElement() : null; url = ThemeManager.class.getResource(ThemeManager.toClassPathResourcePath(t));
if (url == null && t.endsWith(".gif")) { } else {
t = t.replace(".gif", ".png");
e = find(t); e = find(t);
url = e != null && e.hasMoreElements() ? e.nextElement() : null; url = e != null && e.hasMoreElements() ? e.nextElement() : null;
} }
if (url == null && t.endsWith(".gif")) {
t = t.replace(".gif", ".png");
if (t.startsWith(ThemeManager.ZK_URL_PREFIX_FOR_CLASSPATH_RESOURCE)) {
url = ThemeManager.class.getResource(ThemeManager.toClassPathResourcePath(t));
} else {
e = find(t);
url = e != null && e.hasMoreElements() ? e.nextElement() : null;
}
}
} else if (url == null && name.endsWith(".gif")) { } else if (url == null && name.endsWith(".gif")) {
String t = name.replace(".gif", ".png"); String t = name.replace(".gif", ".png");
e = find(t); e = find(t);

View File

@ -7,7 +7,7 @@
.z-grid tbody tr.grid-inactive-row td.row-indicator-selected { .z-grid tbody tr.grid-inactive-row td.row-indicator-selected {
background-color: #DCDAD4 !important; background-color: #DCDAD4 !important;
background-image: url(${c:encodeURL('/theme/default/images/EditRecord16.png')}) !important; background-image: url(${c:encodeURL('~./theme/default/images/EditRecord16.png')}) !important;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 16px 16px; background-size: 16px 16px;
@ -27,7 +27,7 @@
.z-grid tbody tr.highlight td.row-indicator-selected { .z-grid tbody tr.highlight td.row-indicator-selected {
background-color: #FFFFCC !important; background-color: #FFFFCC !important;
background-image: url(${c:encodeURL('/theme/default/images/EditRecord16.png')}) !important; background-image: url(${c:encodeURL('~./theme/default/images/EditRecord16.png')}) !important;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 16px 16px; background-size: 16px 16px;

View File

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 588 B

View File

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 933 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 503 B

After

Width:  |  Height:  |  Size: 503 B

View File

Before

Width:  |  Height:  |  Size: 645 B

After

Width:  |  Height:  |  Size: 645 B

View File

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 466 B

View File

Before

Width:  |  Height:  |  Size: 636 B

After

Width:  |  Height:  |  Size: 636 B

View File

Before

Width:  |  Height:  |  Size: 622 B

After

Width:  |  Height:  |  Size: 622 B

View File

Before

Width:  |  Height:  |  Size: 639 B

After

Width:  |  Height:  |  Size: 639 B

View File

Before

Width:  |  Height:  |  Size: 808 B

After

Width:  |  Height:  |  Size: 808 B

View File

Before

Width:  |  Height:  |  Size: 592 B

After

Width:  |  Height:  |  Size: 592 B

View File

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 916 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 464 B

View File

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 678 B

View File

Before

Width:  |  Height:  |  Size: 616 B

After

Width:  |  Height:  |  Size: 616 B

View File

Before

Width:  |  Height:  |  Size: 815 B

After

Width:  |  Height:  |  Size: 815 B

View File

Before

Width:  |  Height:  |  Size: 961 B

After

Width:  |  Height:  |  Size: 961 B

View File

Before

Width:  |  Height:  |  Size: 551 B

After

Width:  |  Height:  |  Size: 551 B

View File

Before

Width:  |  Height:  |  Size: 719 B

After

Width:  |  Height:  |  Size: 719 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 589 B

After

Width:  |  Height:  |  Size: 589 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

View File

Before

Width:  |  Height:  |  Size: 546 B

After

Width:  |  Height:  |  Size: 546 B

View File

Before

Width:  |  Height:  |  Size: 656 B

After

Width:  |  Height:  |  Size: 656 B

View File

Before

Width:  |  Height:  |  Size: 619 B

After

Width:  |  Height:  |  Size: 619 B

View File

Before

Width:  |  Height:  |  Size: 843 B

After

Width:  |  Height:  |  Size: 843 B

View File

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 603 B

View File

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 678 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 773 B

After

Width:  |  Height:  |  Size: 773 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 844 B

After

Width:  |  Height:  |  Size: 844 B

View File

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 310 B

View File

Before

Width:  |  Height:  |  Size: 737 B

After

Width:  |  Height:  |  Size: 737 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 603 B

View File

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 691 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 974 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 803 B

After

Width:  |  Height:  |  Size: 803 B

View File

Before

Width:  |  Height:  |  Size: 267 B

After

Width:  |  Height:  |  Size: 267 B

View File

Before

Width:  |  Height:  |  Size: 619 B

After

Width:  |  Height:  |  Size: 619 B

View File

Before

Width:  |  Height:  |  Size: 920 B

After

Width:  |  Height:  |  Size: 920 B

View File

Before

Width:  |  Height:  |  Size: 793 B

After

Width:  |  Height:  |  Size: 793 B

View File

Before

Width:  |  Height:  |  Size: 913 B

After

Width:  |  Height:  |  Size: 913 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show More