IDEMPIERE-4949 Desktop tab enhancements (#868)

* IDEMPIERE-4949 Desktop tab enhancements
* ConfigurationLevel=C

Co-authored-by: Carlos Ruiz <carg67@gmail.com>
This commit is contained in:
hengsin 2021-09-08 19:40:00 +08:00 committed by GitHub
parent 7f09b1adc5
commit f8c72c0451
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 207 additions and 29 deletions

View File

@ -0,0 +1,27 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-4949 Desktop tab enhancements
-- Sep 8, 2021, 11:58:54 AM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200181,0,0,TO_DATE('2021-09-08 11:58:53','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2021-09-08 11:58:53','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_TAB_MAX_TITLE_LENGTH','30','Define the maximum length of desktop tab title.','D','C','d658c5ed-c215-4e3d-ba99-cb9e0c005a0f')
;
-- Sep 8, 2021, 12:04:08 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200182,0,0,TO_DATE('2021-09-08 12:04:08','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2021-09-08 12:04:08','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_SHOW_HOME_BUTTON','Y','Y/N - Define if the Home toolbar button is show on desktop browser','D','C','2ff5aab3-79bf-41b7-bbf2-929f9ef3b3d2')
;
-- Sep 8, 2021, 12:33:31 PM MYT
UPDATE AD_SysConfig SET Description='Y/N - Define if the Home toolbar button is visible in desktop browser',Updated=TO_DATE('2021-09-08 12:33:31','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200182
;
-- Sep 8, 2021, 12:40:32 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200183,0,0,TO_DATE('2021-09-08 12:40:30','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2021-09-08 12:40:30','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_SHOW_TAB_LIST_BUTTON','Y','Y/N - Define if the Dropdown menu for open tabs is visible in desktop browser','D','C','7a37f592-1aae-4d13-8648-d8e3e8e88fc0')
;
-- Sep 8, 2021, 12:47:05 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200184,0,0,TO_DATE('2021-09-08 12:47:04','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2021-09-08 12:47:04','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT','N','Y/N - Define if each desktop tab will auto shrink in size to fit more tabs on screen. When Y, the dropdown menu for open tabs is visible regardless of the setting for ZK_DESKTOP_SHOW_TAB_LIST_BUTTON','D','C','0fe51a4e-aa01-4787-8361-94c411c5e74d')
;
SELECT register_migration_script('202109080800_IDEMPIERE-4949.sql') FROM dual
;

View File

@ -0,0 +1,24 @@
-- IDEMPIERE-4949 Desktop tab enhancements
-- Sep 8, 2021, 11:58:54 AM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200181,0,0,TO_TIMESTAMP('2021-09-08 11:58:53','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2021-09-08 11:58:53','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_TAB_MAX_TITLE_LENGTH','30','Define the maximum length of desktop tab title.','D','C','d658c5ed-c215-4e3d-ba99-cb9e0c005a0f')
;
-- Sep 8, 2021, 12:04:08 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200182,0,0,TO_TIMESTAMP('2021-09-08 12:04:08','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2021-09-08 12:04:08','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_SHOW_HOME_BUTTON','Y','Y/N - Define if the Home toolbar button is show on desktop browser','D','C','2ff5aab3-79bf-41b7-bbf2-929f9ef3b3d2')
;
-- Sep 8, 2021, 12:33:31 PM MYT
UPDATE AD_SysConfig SET Description='Y/N - Define if the Home toolbar button is visible in desktop browser',Updated=TO_TIMESTAMP('2021-09-08 12:33:31','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200182
;
-- Sep 8, 2021, 12:40:32 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200183,0,0,TO_TIMESTAMP('2021-09-08 12:40:30','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2021-09-08 12:40:30','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_SHOW_TAB_LIST_BUTTON','Y','Y/N - Define if the Dropdown menu for open tabs is visible in desktop browser','D','C','7a37f592-1aae-4d13-8648-d8e3e8e88fc0')
;
-- Sep 8, 2021, 12:47:05 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200184,0,0,TO_TIMESTAMP('2021-09-08 12:47:04','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2021-09-08 12:47:04','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT','N','Y/N - Define if each desktop tab will auto shrink in size to fit more tabs on screen. When Y, the dropdown menu for open tabs is visible regardless of the setting for ZK_DESKTOP_SHOW_TAB_LIST_BUTTON','D','C','0fe51a4e-aa01-4787-8361-94c411c5e74d')
;
SELECT register_migration_script('202109080800_IDEMPIERE-4949.sql') FROM dual
;

View File

@ -178,6 +178,10 @@ public class MSysConfig extends X_AD_SysConfig
public static final String ZK_DASHBOARD_REFRESH_INTERVAL = "ZK_DASHBOARD_REFRESH_INTERVAL";
public static final String ZK_DECIMALBOX_PROCESS_DOTKEYPAD = "ZK_DECIMALBOX_PROCESS_DOTKEYPAD";
public static final String ZK_DESKTOP_CLASS = "ZK_DESKTOP_CLASS";
public static final String ZK_DESKTOP_SHOW_HOME_BUTTON = "ZK_DESKTOP_SHOW_HOME_BUTTON";
public static final String ZK_DESKTOP_SHOW_TAB_LIST_BUTTON = "ZK_DESKTOP_SHOW_TAB_LIST_BUTTON";
public static final String ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT = "ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT";
public static final String ZK_DESKTOP_TAB_MAX_TITLE_LENGTH = "ZK_DESKTOP_TAB_MAX_TITLE_LENGTH";
public static final String ZK_FOOTER_SERVER_DATETIME_FORMAT = "ZK_FOOTER_SERVER_DATETIME_FORMAT";
public static final String ZK_FOOTER_SERVER_MSG = "ZK_FOOTER_SERVER_MSG";
public static final String ZK_GRID_AFTER_FIND = "ZK_GRID_AFTER_FIND";

View File

@ -56,5 +56,5 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI).
<!-- 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="202108252028" />
<javascript-module name="idempiere.theme.default" version="202109080650" />
</language>

View File

@ -255,7 +255,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
keyListener = new Keylistener();
keyListener.setPage(this.getPage());
keyListener.setCtrlKeys("@a@c@d@e@f@h@l@m@n@o@p@r@s@t@z@x@#left@#right@#up@#down@#home@#end#enter^u@u@#pgdn@#pgup$#f2^#f2");
keyListener.setCtrlKeys("@a@c@d@e@f@h@l@m@n@o@p@r@s@t@w@x@z@#left@#right@#up@#down@#home@#end#enter^u@u@#pgdn@#pgup$#f2^#f2");
keyListener.setAutoBlur(false);
//create new desktop

View File

@ -30,9 +30,11 @@ import org.adempiere.webui.panel.IHelpContext;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.ZKUpdateUtil;
import org.compiere.model.MSysConfig;
import org.compiere.model.X_AD_CtxHelp;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
@ -42,6 +44,7 @@ import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.event.SwipeEvent;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Style;
/**
*
@ -66,7 +69,7 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
public static final String DEFER_SET_SELECTED_TAB = "deferSetSelectedTab";
private static final int MAX_TITLE_LENGTH = 30;
private static final int DEFAULT_MAX_TITLE_LENGTH = 30;
private Tabbox tabbox;
private ToolBar toolbar;
@ -91,6 +94,18 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
protected Component doCreatePart(Component parent)
{
if (isDesktopAutoShrinkTabTitle())
{
//style to enable auto shrink tab title and hide tab scroll buttons
Style style = new Style();
style.setContent(".desktop-tabbox > .z-tabs > .z-tabs-content {display:flex;width: auto !important;} "
+ ".desktop-tabbox > .z-tabs > .z-tabs-content > .z-tab {text-overflow: ellipsis;flex-shrink: 1;flex-basis: auto;min-width: 70px;} "
+ ".desktop-tabbox.z-tabbox > .z-tabbox-icon.z-tabbox-left-scroll,"
+ ".desktop-tabbox.z-tabbox > .z-tabbox-icon.z-tabbox-right-scroll {color:transparent;border:none;background:none;width:0px;} "
+ ".desktop-tabbox.z-tabbox-scroll > .z-tabs {margin:0px;} ");
parent.getParent().getParent().appendChild(style);
}
tabbox = new Tabbox();
tabbox.addEventListener("onPageAttached", this);
tabbox.addEventListener("onPageDetached", this);
@ -110,13 +125,68 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
});
tabbox.addEventListener(ON_AFTER_TAB_CLOSE, evt -> {
if (isMobile()) {
updateMobileTabState(tabbox.getSelectedTab());
updateTabListButton();
updateMobileTabState(tabbox.getSelectedTab());
}
if (isShowTabList()) {
updateTabListButton();
}
});
Tabpanels tabpanels = new Tabpanels();
Tabs tabs = new Tabs();
//fix tabs scrolling issue for multiple tabs + tab toolbar
//not needed for mobile since mobile only show one tab at a time
if (!isMobile())
{
StringBuilder f = new StringBuilder();
f.append("function(way, tb) {\n")
.append(" var tabbox = this.getTabbox();var tabs = this.$n();\n")
.append(" this.$_scrollcheck(way,tb);\n")
.append(" if (tabs && !tabbox.isVertical() && !tabbox.inAccordionMold()) {\n")
.append(" this.__offsetWidth=tabs.offsetWidth;this.__scrollLeft=tabs.scrollLeft;\n")
.append(" this.__selectedIndex=tabbox.getSelectedIndex();\n")
.append(" this.__selectedTab=tabbox.getSelectedTab();\n")
.append(" } else {\n")
.append(" this.__offsetWidth=this.__scrollLeft==0;this.__selectedTab=null;this.__selectedIndex=-1;\n")
.append(" }\n")
.append("}");
tabs.setWidgetOverride("_scrollcheck", f.toString());
f = new StringBuilder();
f.append("function (toSel) {\n")
.append(" var tabbox = this.getTabbox();\n")
.append(" var tabs = this.$n();\n")
.append(" var tabsOffsetWidth=tabs.offsetWidth;\n")
.append(" this.$_fixWidth(toSel);\n")
.append(" if(this.__selectedTab && this.__selectedTab == tabbox.getSelectedTab() && this.__selectedIndex == tabbox.getSelectedIndex()) {\n")
.append(" if(tabs.offsetWidth == this.__offsetWidth) {\n")
.append(" if(tabsOffsetWidth != this.__offsetWidth && tabs.scrollLeft != this.__scrollLeft) {\n")
.append(" this._fixTabsScrollLeft(this.__scrollLeft);\n")
.append(" }\n")
.append(" }\n")
.append(" }\n")
.append("}");
tabs.setWidgetOverride("_fixWidth", f.toString());
//change _doScroll to immediate
f = new StringBuilder();
f.append("function (to, move) {\n")
.append(" if (move <= 0) return;\n")
.append(" var self=this,tabs = this.$n();\n")
.append(" switch (to) {\n")
.append(" case 'right':\n")
.append(" self._fixTabsScrollLeft(self._tabsScrollLeft + move);break;")
.append(" case 'left':\n")
.append(" self._fixTabsScrollLeft(self._tabsScrollLeft - move);break;")
.append(" case 'up':\n")
.append(" self._fixTabsScrollTop(self._tabsScrollTop - move);break;")
.append(" default:\n")
.append(" self._fixTabsScrollTop(self._tabsScrollTop + move);\n")
.append(" }\n")
.append(" var tabsScrollLeft = self._tabsScrollLeft, tabsScrollTop = self._tabsScrollTop;\n")
.append(" self._fixTabsScrollLeft(tabsScrollLeft <= 0 ? 0 : tabsScrollLeft);\n")
.append(" self._fixTabsScrollTop(tabsScrollTop <= 0 ? 0 : tabsScrollTop);\n")
.append("}");
tabs.setWidgetOverride("_doScroll", f.toString());
}
tabbox.appendChild(tabs);
tabbox.appendChild(tabpanels);
@ -125,15 +195,13 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
ZKUpdateUtil.setVflex(tabbox, "1");
ZKUpdateUtil.setHflex(tabbox, "1");
if (parent != null)
tabbox.setParent(parent);
else
tabbox.setPage(page);
tabbox.setParent(parent);
toolbar = new ToolBar();
toolbar.setSclass("window-container-toolbar");
tabbox.appendChild(toolbar);
if (isMobile())
if (isShowHomeButton())
{
ToolBarButton homeButton = new ToolBarButton();
if (ThemeManager.isUseFontIconForImage())
@ -141,9 +209,13 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
else
homeButton.setImage(ThemeManager.getThemeResource("images/Home16.png"));
homeButton.setSclass("window-container-toolbar-btn");
homeButton.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Home")));
homeButton.addEventListener(Events.ON_CLICK, evt -> setSelectedTab(tabbox.getTabpanel(0).getLinkedTab()));
toolbar.appendChild(homeButton);
}
if (isShowTabList())
{
tabListBtn = new ToolBarButton();
if (ThemeManager.isUseFontIconForImage())
{
@ -153,30 +225,66 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
{
tabListBtn.setImage(ThemeManager.getThemeResource("images/expand-header.png"));
}
tabListBtn.setSclass("window-container-toolbar-btn");
tabListBtn.setSclass("window-container-toolbar-btn tab-list");
tabListBtn.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "ShowAllWindow")) + " Alt+W");
tabListBtn.addEventListener(Events.ON_CLICK, evt -> showTabList());
tabListBtn.setVisible(false);
toolbar.appendChild(tabListBtn);
}
SessionManager.getSessionApplication().getKeylistener().addEventListener(Events.ON_CTRL_KEY, (KeyEvent e) -> onCtrlKey(e));
return tabbox;
}
private void showTabList() {
private void onCtrlKey(KeyEvent e) {
//alt+w
if (e.isAltKey() && !e.isCtrlKey() && !e.isShiftKey()) {
if (e.getKeyCode() == 87) {
if (tabListBtn != null && tabListBtn.isVisible())
Events.postEvent(Events.ON_CLICK, tabListBtn, null);
}
}
}
private boolean isShowHomeButton() {
return isMobile() || isDesktopShowHomeButton();
}
private boolean isDesktopShowHomeButton() {
return MSysConfig.getBooleanValue(MSysConfig.ZK_DESKTOP_SHOW_HOME_BUTTON, true, Env.getAD_Client_ID(Env.getCtx()));
}
private boolean isShowTabList() {
return isMobile() || isDesktopAutoShrinkTabTitle() || isDesktopShowTabList();
}
private boolean isDesktopShowTabList() {
return MSysConfig.getBooleanValue(MSysConfig.ZK_DESKTOP_SHOW_TAB_LIST_BUTTON, true, Env.getAD_Client_ID(Env.getCtx()));
}
private boolean isDesktopAutoShrinkTabTitle() {
return MSysConfig.getBooleanValue(MSysConfig.ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT, false, Env.getAD_Client_ID(Env.getCtx()));
}
private void showTabList() {
org.zkoss.zul.Tabs tabs = tabbox.getTabs();
List<Component> list = tabs.getChildren();
Menupopup popup = new Menupopup();
for(int i = 1; i < list.size(); i++) {
Tab tab = (Tab) list.get(i);
Menuitem item = new Menuitem(tab.getLabel());
Menuitem item = new Menuitem(tab.getLabel().endsWith("...") && !Util.isEmpty(tab.getTooltiptext(), true) ? tab.getTooltiptext() : tab.getLabel());
item.setValue(Integer.toString(i));
item.setTooltiptext(tab.getTooltiptext());
if (!Util.isEmpty(tab.getTooltiptext(), true) && !(item.getLabel().equals(tab.getTooltiptext())))
item.setTooltiptext(tab.getTooltiptext());
if (i == tabbox.getSelectedIndex())
item.setSclass("selected");
popup.appendChild(item);
item.addEventListener(Events.ON_CLICK, evt -> {
Menuitem t = (Menuitem) evt.getTarget();
String s = t.getValue();
Integer ti = Integer.parseInt(s);
setSelectedTab(tabbox.getTabpanel(ti.intValue()).getLinkedTab());
setSelectedTab(tabbox.getTabpanel(ti.intValue()).getLinkedTab());
});
}
popup.setPage(tabbox.getPage());
@ -430,7 +538,9 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
popupClose.setPage(tab.getPage());
tab.setContext(popupClose);
updateTabListButton();
if (isShowTabList())
updateTabListButton();
return tab;
}
@ -448,7 +558,7 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
}
private void updateTabListButton() {
if (isMobile() && tabListBtn != null) {
if (isShowTabList() && tabListBtn != null) {
int cnt = tabbox.getTabs().getChildren().size()-1;
if (cnt > 0) {
tabListBtn.setLabel(Integer.toString(cnt));
@ -492,20 +602,24 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
public void setTabTitle(String title, org.zkoss.zul.Tab tab) {
if (tab == null)
return;
if (title.length() <= MAX_TITLE_LENGTH)
tab.setTooltiptext(title);
if (title.length() <= getMaxTitleLength())
{
tab.setTooltiptext(null);
tab.setLabel(title);
}
else
{
tab.setTooltiptext(title);
title = title.substring(0, MAX_TITLE_LENGTH-3) + "...";
{
title = title.substring(0, getMaxTitleLength()-3) + "...";
tab.setLabel(title);
}
}
/**
private int getMaxTitleLength() {
return MSysConfig.getIntValue(MSysConfig.ZK_DESKTOP_TAB_MAX_TITLE_LENGTH, DEFAULT_MAX_TITLE_LENGTH, Env.getAD_Client_ID(Env.getCtx()));
}
/**
*
* @param refTab
* @param comp

View File

@ -76,10 +76,6 @@
background-color: #E4E4E4;
}
.desktop-tabbox .z-tabs-content {
width: 5555px !important;
}
.desktop-tabbox .z-tab {
height: 24px;
}
@ -172,7 +168,6 @@
.z-anchorchildren { overflow:visible }
.desktop-hometab {
margin-left: 2px !important;
}
.desktop-tabbox .z-tabs .z-toolbar-tabs-body {
@ -270,3 +265,17 @@
overflow-x: auto;
padding: 8px;
}
.z-menuitem.selected .z-menuitem-text {
font-weight: bold;
}
.window-container-toolbar-btn.tab-list {
font-size: smaller;
padding-right: 6px;
}
.window-container-toolbar-btn.tab-list i {
padding-right: 0px;
margin-right: -4px;
font-size: larger;
}