From f8c72c0451b75f18f45ea9e6c747057e23225b62 Mon Sep 17 00:00:00 2001 From: hengsin Date: Wed, 8 Sep 2021 19:40:00 +0800 Subject: [PATCH] IDEMPIERE-4949 Desktop tab enhancements (#868) * IDEMPIERE-4949 Desktop tab enhancements * ConfigurationLevel=C Co-authored-by: Carlos Ruiz --- .../oracle/202109080800_IDEMPIERE-4949.sql | 27 +++ .../202109080800_IDEMPIERE-4949.sql | 24 +++ .../src/org/compiere/model/MSysConfig.java | 4 + .../WEB-INF/src/metainfo/zk/lang-addon.xml | 2 +- .../org/adempiere/webui/AdempiereWebUI.java | 2 +- .../adempiere/webui/part/WindowContainer.java | 158 +++++++++++++++--- .../default/css/fragment/desktop.css.dsp | 19 ++- 7 files changed, 207 insertions(+), 29 deletions(-) create mode 100644 migration/i8.2z/oracle/202109080800_IDEMPIERE-4949.sql create mode 100644 migration/i8.2z/postgresql/202109080800_IDEMPIERE-4949.sql diff --git a/migration/i8.2z/oracle/202109080800_IDEMPIERE-4949.sql b/migration/i8.2z/oracle/202109080800_IDEMPIERE-4949.sql new file mode 100644 index 0000000000..ad60330a98 --- /dev/null +++ b/migration/i8.2z/oracle/202109080800_IDEMPIERE-4949.sql @@ -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 +; + diff --git a/migration/i8.2z/postgresql/202109080800_IDEMPIERE-4949.sql b/migration/i8.2z/postgresql/202109080800_IDEMPIERE-4949.sql new file mode 100644 index 0000000000..11d4e39ce9 --- /dev/null +++ b/migration/i8.2z/postgresql/202109080800_IDEMPIERE-4949.sql @@ -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 +; + diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index fa5c1677ab..be578e3d3a 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -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"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml b/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml index 73a3a03d11..d2253b03ed 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml +++ b/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml @@ -56,5 +56,5 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI). - + diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java index 153c0cb001..4485b78b9c 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java @@ -255,7 +255,7 @@ public class AdempiereWebUI extends Window implements EventListener, 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 diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/part/WindowContainer.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/part/WindowContainer.java index 7c21419b8b..241f61c209 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/part/WindowContainer.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/part/WindowContainer.java @@ -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 .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 { 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 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 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 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 0) { tabListBtn.setLabel(Integer.toString(cnt)); @@ -492,20 +602,24 @@ public class WindowContainer extends AbstractUIPart implements EventListener