IDEMPIERE-231 Zk6: Improve the tablet experience. Fixed compatibility with Chrome for Android ( Tested on Nexus 7 4.2.2 with Chrome 25 ). Added swipe gesture support - swipe left to hide the left desktop column, swipe right to hide the right desktop column ( tooltips ), swipe down to hide the detail tabs and swipe left/right on the tab header to close a tab. Hide the login info for mobile devices.
This commit is contained in:
parent
e0279e57d4
commit
ad42f1bf83
|
@ -449,14 +449,8 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
||||||
appDesktop.setClientInfo(clientInfo);
|
appDesktop.setClientInfo(clientInfo);
|
||||||
String ua = Servlets.getUserAgent((ServletRequest) Executions.getCurrent().getNativeRequest());
|
String ua = Servlets.getUserAgent((ServletRequest) Executions.getCurrent().getNativeRequest());
|
||||||
clientInfo.userAgent = ua;
|
clientInfo.userAgent = ua;
|
||||||
if (Servlets.getBrowser(ua).equals("webkit")) {
|
ua = ua.toLowerCase();
|
||||||
ua = ua.toLowerCase();
|
clientInfo.tablet = ua.indexOf("ipad") >= 0 || ua.indexOf("iphone") >= 0 || ua.indexOf("android") >= 0;
|
||||||
if (ua.indexOf("ipad") >= 0) {
|
|
||||||
clientInfo.tablet = true;
|
|
||||||
} else if (ua.indexOf("android") >= 0 && ua.indexOf("chrome") >= 0 && ua.indexOf("mobile") < 0) {
|
|
||||||
clientInfo.tablet = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (getDesktop() != null && getDesktop().getSession() != null) {
|
if (getDesktop() != null && getDesktop().getSession() != null) {
|
||||||
getDesktop().getSession().setAttribute(CLIENT_INFO, clientInfo);
|
getDesktop().getSession().setAttribute(CLIENT_INFO, clientInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,14 @@ package org.adempiere.webui;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
|
||||||
import org.adempiere.webui.apps.AEnv;
|
import org.adempiere.webui.apps.AEnv;
|
||||||
import org.adempiere.webui.part.AbstractUIPart;
|
import org.adempiere.webui.part.AbstractUIPart;
|
||||||
import org.adempiere.webui.theme.ITheme;
|
import org.adempiere.webui.theme.ITheme;
|
||||||
import org.adempiere.webui.theme.ThemeManager;
|
import org.adempiere.webui.theme.ThemeManager;
|
||||||
import org.adempiere.webui.window.LoginWindow;
|
import org.adempiere.webui.window.LoginWindow;
|
||||||
|
import org.zkoss.web.servlet.Servlets;
|
||||||
import org.zkoss.zhtml.Text;
|
import org.zkoss.zhtml.Text;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.Executions;
|
import org.zkoss.zk.ui.Executions;
|
||||||
|
@ -123,6 +126,13 @@ public class WLogin extends AbstractUIPart
|
||||||
West west = new West();
|
West west = new West();
|
||||||
west.setSclass(ITheme.LOGIN_WEST_PANEL_CLASS);
|
west.setSclass(ITheme.LOGIN_WEST_PANEL_CLASS);
|
||||||
addContent(west, pageDefintion);
|
addContent(west, pageDefintion);
|
||||||
|
String ua = Servlets.getUserAgent((ServletRequest) Executions.getCurrent().getNativeRequest());
|
||||||
|
ua = ua.toLowerCase();
|
||||||
|
boolean mobile = ua.indexOf("ipad") >= 0 || ua.indexOf("iphone") >= 0 || ua.indexOf("android") >= 0;
|
||||||
|
if (mobile) {
|
||||||
|
west.setCollapsible(true);
|
||||||
|
west.setOpen(false);
|
||||||
|
}
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
//ignore page not found exception
|
//ignore page not found exception
|
||||||
if (e instanceof UiException) {
|
if (e instanceof UiException) {
|
||||||
|
|
|
@ -83,6 +83,7 @@ import org.zkoss.zk.ui.event.Event;
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
import org.zkoss.zk.ui.event.EventListener;
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
import org.zkoss.zk.ui.event.OpenEvent;
|
import org.zkoss.zk.ui.event.OpenEvent;
|
||||||
|
import org.zkoss.zk.ui.event.SwipeEvent;
|
||||||
import org.zkoss.zk.ui.util.Clients;
|
import org.zkoss.zk.ui.util.Clients;
|
||||||
import org.zkoss.zul.Button;
|
import org.zkoss.zul.Button;
|
||||||
import org.zkoss.zul.Cell;
|
import org.zkoss.zul.Cell;
|
||||||
|
@ -186,6 +187,14 @@ DataStatusListener, IADTabpanel, IdSpace
|
||||||
|
|
||||||
public static final String ON_TOGGLE_EVENT = "onToggle";
|
public static final String ON_TOGGLE_EVENT = "onToggle";
|
||||||
|
|
||||||
|
private static enum SouthEvent {
|
||||||
|
SLIDE(),
|
||||||
|
OPEN(),
|
||||||
|
CLOSE();
|
||||||
|
|
||||||
|
private SouthEvent() {}
|
||||||
|
}
|
||||||
|
|
||||||
public ADTabpanel()
|
public ADTabpanel()
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
@ -238,6 +247,21 @@ DataStatusListener, IADTabpanel, IdSpace
|
||||||
"var se = new zk.Event(this, 'onSlide', null, {toServer: true}); zAu.send(se); } }");
|
"var se = new zk.Event(this, 'onSlide', null, {toServer: true}); zAu.send(se); } }");
|
||||||
south.addEventListener(Events.ON_OPEN, this);
|
south.addEventListener(Events.ON_OPEN, this);
|
||||||
south.addEventListener("onSlide", this);
|
south.addEventListener("onSlide", this);
|
||||||
|
|
||||||
|
south.addEventListener(Events.ON_SWIPE, new EventListener<SwipeEvent>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(SwipeEvent event) throws Exception {
|
||||||
|
if ("down".equals(event.getSwipeDirection())) {
|
||||||
|
Borderlayout borderLayout = (Borderlayout) formContainer;
|
||||||
|
South south = borderLayout.getSouth();
|
||||||
|
if (south.isOpen()) {
|
||||||
|
south.setOpen(false);
|
||||||
|
onSouthEvent(SouthEvent.CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
south.appendChild(component);
|
south.appendChild(component);
|
||||||
|
|
||||||
|
@ -973,23 +997,11 @@ DataStatusListener, IADTabpanel, IdSpace
|
||||||
if (detailPane != null) {
|
if (detailPane != null) {
|
||||||
boolean openEvent = event instanceof OpenEvent;
|
boolean openEvent = event instanceof OpenEvent;
|
||||||
if (openEvent) {
|
if (openEvent) {
|
||||||
Events.echoEvent(ON_SAVE_OPEN_PREFERENCE_EVENT, this, ((OpenEvent)event).isOpen());
|
OpenEvent oe = (OpenEvent)event;
|
||||||
if (!((OpenEvent)event).isOpen()) {
|
onSouthEvent(oe.isOpen() ? SouthEvent.OPEN : SouthEvent.CLOSE);
|
||||||
return;
|
} else {
|
||||||
}
|
onSouthEvent(SouthEvent.SLIDE);
|
||||||
}
|
}
|
||||||
if (detailPane.getParent() == null) {
|
|
||||||
formContainer.appendSouth(detailPane);
|
|
||||||
}
|
|
||||||
IADTabpanel tabPanel = detailPane.getSelectedADTabpanel();
|
|
||||||
if (tabPanel != null) {
|
|
||||||
if (!tabPanel.isActivated()) {
|
|
||||||
tabPanel.activate(true);
|
|
||||||
}
|
|
||||||
if (!tabPanel.isGridView()) {
|
|
||||||
tabPanel.switchRowPresentation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event.getName().equals(ON_SAVE_OPEN_PREFERENCE_EVENT)) {
|
else if (event.getName().equals(ON_SAVE_OPEN_PREFERENCE_EVENT)) {
|
||||||
|
@ -1037,6 +1049,28 @@ DataStatusListener, IADTabpanel, IdSpace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onSouthEvent(SouthEvent event) {
|
||||||
|
if (event == SouthEvent.OPEN || event == SouthEvent.CLOSE) {
|
||||||
|
boolean open = event == SouthEvent.OPEN ? true : false;
|
||||||
|
Events.echoEvent(ON_SAVE_OPEN_PREFERENCE_EVENT, this, open);
|
||||||
|
if (!open)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detailPane.getParent() == null) {
|
||||||
|
formContainer.appendSouth(detailPane);
|
||||||
|
}
|
||||||
|
IADTabpanel tabPanel = detailPane.getSelectedADTabpanel();
|
||||||
|
if (tabPanel != null) {
|
||||||
|
if (!tabPanel.isActivated()) {
|
||||||
|
tabPanel.activate(true);
|
||||||
|
}
|
||||||
|
if (!tabPanel.isGridView()) {
|
||||||
|
tabPanel.switchRowPresentation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isOpenDetailPane() {
|
private boolean isOpenDetailPane() {
|
||||||
boolean open = true;
|
boolean open = true;
|
||||||
int windowId = getGridTab().getAD_Window_ID();
|
int windowId = getGridTab().getAD_Window_ID();
|
||||||
|
|
|
@ -374,9 +374,14 @@ public class GridView extends Vbox implements EventListener<Event>, IdSpace
|
||||||
|
|
||||||
Columns columns = new Columns();
|
Columns columns = new Columns();
|
||||||
|
|
||||||
Frozen frozen = new Frozen();
|
//frozen not working well on tablet devices yet
|
||||||
frozen.setColumns(1);
|
if (!AEnv.isTablet())
|
||||||
listbox.appendChild(frozen);
|
{
|
||||||
|
Frozen frozen = new Frozen();
|
||||||
|
frozen.setColumns(1);
|
||||||
|
listbox.appendChild(frozen);
|
||||||
|
}
|
||||||
|
|
||||||
org.zkoss.zul.Column indicator = new Column();
|
org.zkoss.zul.Column indicator = new Column();
|
||||||
indicator.setWidth("18px");
|
indicator.setWidth("18px");
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -73,6 +73,7 @@ import org.zkoss.zk.ui.event.EventQueue;
|
||||||
import org.zkoss.zk.ui.event.EventQueues;
|
import org.zkoss.zk.ui.event.EventQueues;
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
import org.zkoss.zk.ui.event.OpenEvent;
|
import org.zkoss.zk.ui.event.OpenEvent;
|
||||||
|
import org.zkoss.zk.ui.event.SwipeEvent;
|
||||||
import org.zkoss.zk.ui.util.Clients;
|
import org.zkoss.zk.ui.util.Clients;
|
||||||
import org.zkoss.zk.ui.util.DesktopCleanup;
|
import org.zkoss.zk.ui.util.DesktopCleanup;
|
||||||
import org.zkoss.zul.Borderlayout;
|
import org.zkoss.zul.Borderlayout;
|
||||||
|
@ -177,9 +178,20 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(Event event) throws Exception {
|
public void onEvent(Event event) throws Exception {
|
||||||
OpenEvent oe = (OpenEvent) event;
|
OpenEvent oe = (OpenEvent) event;
|
||||||
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
|
updateMenuCollapsedPreference(!oe.isOpen());
|
||||||
pref.setProperty(UserPreference.P_MENU_COLLAPSED, !oe.isOpen());
|
}
|
||||||
pref.savePreference();
|
});
|
||||||
|
w.addEventListener(Events.ON_SWIPE, new EventListener<SwipeEvent>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(SwipeEvent event) throws Exception {
|
||||||
|
if ("left".equals(event.getSwipeDirection())) {
|
||||||
|
West w = (West) event.getTarget();
|
||||||
|
if (w.isOpen()) {
|
||||||
|
w.setOpen(false);
|
||||||
|
updateMenuCollapsedPreference(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
|
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
|
||||||
|
@ -199,11 +211,24 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(Event event) throws Exception {
|
public void onEvent(Event event) throws Exception {
|
||||||
OpenEvent oe = (OpenEvent) event;
|
OpenEvent oe = (OpenEvent) event;
|
||||||
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
|
updateHelpCollapsedPreference(!oe.isOpen());
|
||||||
pref.setProperty(UserPreference.P_HELP_COLLAPSED, !oe.isOpen());
|
|
||||||
pref.savePreference();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
e.addEventListener(Events.ON_SWIPE, new EventListener<SwipeEvent>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(SwipeEvent event) throws Exception {
|
||||||
|
if ("right".equals(event.getSwipeDirection())) {
|
||||||
|
East e = (East) event.getTarget();
|
||||||
|
if (e.isOpen()) {
|
||||||
|
e.setOpen(false);
|
||||||
|
updateHelpCollapsedPreference(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
boolean helpCollapsed= pref.isPropertyBool(UserPreference.P_HELP_COLLAPSED);
|
boolean helpCollapsed= pref.isPropertyBool(UserPreference.P_HELP_COLLAPSED);
|
||||||
e.setOpen(!helpCollapsed);
|
e.setOpen(!helpCollapsed);
|
||||||
|
|
||||||
|
@ -258,6 +283,18 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateMenuCollapsedPreference(boolean collapsed) {
|
||||||
|
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
|
||||||
|
pref.setProperty(UserPreference.P_MENU_COLLAPSED, collapsed);
|
||||||
|
pref.savePreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateHelpCollapsedPreference(boolean collapsed) {
|
||||||
|
UserPreference pref = SessionManager.getSessionApplication().getUserPreference();
|
||||||
|
pref.setProperty(UserPreference.P_HELP_COLLAPSED, collapsed);
|
||||||
|
pref.savePreference();
|
||||||
|
}
|
||||||
|
|
||||||
private void renderHomeTab()
|
private void renderHomeTab()
|
||||||
{
|
{
|
||||||
homeTab.getChildren().clear();
|
homeTab.getChildren().clear();
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.compiere.util.Util;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
import org.zkoss.zk.ui.event.Event;
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
import org.zkoss.zk.ui.event.EventListener;
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
|
import org.zkoss.zk.ui.event.SwipeEvent;
|
||||||
import org.zkoss.zul.Center;
|
import org.zkoss.zul.Center;
|
||||||
import org.zkoss.zul.South;
|
import org.zkoss.zul.South;
|
||||||
|
|
||||||
|
@ -302,6 +303,15 @@ public class InfoProductWindow extends InfoWindow {
|
||||||
south.setSplittable(true);
|
south.setSplittable(true);
|
||||||
south.setTitle(Msg.translate(Env.getCtx(), "WarehouseStock"));
|
south.setTitle(Msg.translate(Env.getCtx(), "WarehouseStock"));
|
||||||
south.setTooltiptext(Msg.translate(Env.getCtx(), "WarehouseStock"));
|
south.setTooltiptext(Msg.translate(Env.getCtx(), "WarehouseStock"));
|
||||||
|
south.addEventListener(Events.ON_SWIPE, new EventListener<SwipeEvent>() {
|
||||||
|
@Override
|
||||||
|
public void onEvent(SwipeEvent event) throws Exception {
|
||||||
|
South south = (South) event.getTarget();
|
||||||
|
if ("down".equals(event.getSwipeDirection())) {
|
||||||
|
south.setOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
contentBorderLayout.appendChild(south);
|
contentBorderLayout.appendChild(south);
|
||||||
tabbedPane.setSclass("info-product-tabbedpane");
|
tabbedPane.setSclass("info-product-tabbedpane");
|
||||||
south.appendChild(tabbedPane);
|
south.appendChild(tabbedPane);
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
import org.zkoss.zk.ui.event.Event;
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
import org.zkoss.zk.ui.event.EventListener;
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
|
import org.zkoss.zk.ui.event.SwipeEvent;
|
||||||
import org.zkoss.zul.Anchorlayout;
|
import org.zkoss.zul.Anchorlayout;
|
||||||
import org.zkoss.zul.Vlayout;
|
import org.zkoss.zul.Vlayout;
|
||||||
|
|
||||||
|
@ -127,6 +128,17 @@ public class WindowContainer extends AbstractUIPart
|
||||||
setTabTitle(title, tab);
|
setTabTitle(title, tab);
|
||||||
}
|
}
|
||||||
tab.setClosable(closeable);
|
tab.setClosable(closeable);
|
||||||
|
tab.addEventListener(Events.ON_SWIPE, new EventListener<SwipeEvent>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(SwipeEvent event) throws Exception {
|
||||||
|
Tab tab = (Tab) event.getTarget();
|
||||||
|
if (tab.isClosable()
|
||||||
|
&& ("right".equals(event.getSwipeDirection()) || "left".equals(event.getSwipeDirection()))) {
|
||||||
|
tab.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// fix scroll position lost coming back into a grid view tab
|
// fix scroll position lost coming back into a grid view tab
|
||||||
tab.addEventListener(Events.ON_SELECT, new EventListener<Event>() {
|
tab.addEventListener(Events.ON_SELECT, new EventListener<Event>() {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div class="tabs arrows" xmlns:w="client" forward="onMoveDate(${arg.type})"
|
<div class="tabs arrows" xmlns:w="client" forward="onMoveDate(${arg.type})"
|
||||||
w:unbind_="function(){this.$unbind_();jq(this).unbind('mouseover').unbind('mouseout');}">
|
w:unbind_="function(skipper, after){this.$unbind_(skipper, after);jq(this).unbind('mouseover').unbind('mouseout');}">
|
||||||
<attribute w:name="bind_"><![CDATA[
|
<attribute w:name="bind_"><![CDATA[
|
||||||
function () {
|
function (desktop, skipper, after) {
|
||||||
this.$bind_();
|
this.$bind_(desktop, skipper, after);
|
||||||
jq(this).bind('mouseover',function(evt){jq(evt.currentTarget).addClass('arrow-over');})
|
jq(this).bind('mouseover',function(evt){jq(evt.currentTarget).addClass('arrow-over');})
|
||||||
.bind('mouseout',function(evt){jq(evt.currentTarget).removeClass('arrow-over');});
|
.bind('mouseout',function(evt){jq(evt.currentTarget).removeClass('arrow-over');});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue