IDEMPIERE-5520 Navigation between Tabs leave Detached DOM objects (Leak) (#1648)
* IDEMPIERE-5520 Navigation between Tabs leave Detached DOM objects (Leak) - Fix NPE * IDEMPIERE-5520 Navigation between Tabs leave Detached DOM objects (Leak) - refine NPE fix - fix a potential leak in billboard * IDEMPIERE-5520 Navigation between Tabs leave Detached DOM objects (Leak) - reduce detached html elemenet leak for change role
This commit is contained in:
parent
a9ae3b8652
commit
d4c3685761
|
@ -628,17 +628,19 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
||||||
if (Env.getCtx().get(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER) != null)
|
if (Env.getCtx().get(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER) != null)
|
||||||
properties.put(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER, Env.getCtx().get(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER));
|
properties.put(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER, Env.getCtx().get(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER));
|
||||||
|
|
||||||
|
//desktop cleanup
|
||||||
|
IDesktop appDesktop = getAppDeskop();
|
||||||
|
if (appDesktop != null)
|
||||||
|
appDesktop.logout(T -> {if (T) asyncChangeRole(httpRequest.getSession(), locale, properties);});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void asyncChangeRole(HttpSession httpSession, Locale locale, Properties properties) {
|
||||||
//stop key listener
|
//stop key listener
|
||||||
if (keyListener != null) {
|
if (keyListener != null) {
|
||||||
keyListener.detach();
|
keyListener.detach();
|
||||||
keyListener = null;
|
keyListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//desktop cleanup
|
|
||||||
IDesktop appDesktop = getAppDeskop();
|
|
||||||
if (appDesktop != null)
|
|
||||||
appDesktop.logout();
|
|
||||||
|
|
||||||
//remove all children component
|
//remove all children component
|
||||||
getChildren().clear();
|
getChildren().clear();
|
||||||
|
|
||||||
|
@ -648,7 +650,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
||||||
this.setPage(page);
|
this.setPage(page);
|
||||||
|
|
||||||
//clear session attributes
|
//clear session attributes
|
||||||
Enumeration<String> attributes = httpRequest.getSession().getAttributeNames();
|
Enumeration<String> attributes = httpSession.getAttributeNames();
|
||||||
while(attributes.hasMoreElements()) {
|
while(attributes.hasMoreElements()) {
|
||||||
String attribute = attributes.nextElement();
|
String attribute = attributes.nextElement();
|
||||||
|
|
||||||
|
@ -656,7 +658,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
||||||
if (attribute.contains("zkoss."))
|
if (attribute.contains("zkoss."))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
httpRequest.getSession().removeAttribute(attribute);
|
httpSession.removeAttribute(attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
//logout ad_session
|
//logout ad_session
|
||||||
|
|
|
@ -80,6 +80,7 @@ import org.zkoss.zk.ui.Execution;
|
||||||
import org.zkoss.zk.ui.Executions;
|
import org.zkoss.zk.ui.Executions;
|
||||||
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.zul.Button;
|
||||||
import org.zkoss.zul.impl.InputElement;
|
import org.zkoss.zul.impl.InputElement;
|
||||||
|
|
||||||
import com.lowagie.text.DocumentException;
|
import com.lowagie.text.DocumentException;
|
||||||
|
@ -881,7 +882,7 @@ public final class AEnv
|
||||||
* @param c
|
* @param c
|
||||||
*/
|
*/
|
||||||
public static void detachInputElement(Component c) {
|
public static void detachInputElement(Component c) {
|
||||||
if (c instanceof InputElement) {
|
if (c instanceof InputElement || c instanceof Button) {
|
||||||
c.detach();
|
c.detach();
|
||||||
}
|
}
|
||||||
if (c.getChildren().size() > 0) {
|
if (c.getChildren().size() > 0) {
|
||||||
|
|
|
@ -184,15 +184,17 @@ public class Tab extends org.zkoss.zul.Tab
|
||||||
}
|
}
|
||||||
|
|
||||||
//Workaround for detached HTML input element leak
|
//Workaround for detached HTML input element leak
|
||||||
|
boolean attached = getDesktop() != null;
|
||||||
if (panel != null) {
|
if (panel != null) {
|
||||||
Executions.schedule(getDesktop(), e -> panel.detach(), new Event("onCloseLinkedPanel"));
|
if (attached)
|
||||||
|
Executions.schedule(getDesktop(), e -> panel.detach(), new Event("onCloseLinkedPanel"));
|
||||||
}
|
}
|
||||||
|
|
||||||
detach();
|
detach();
|
||||||
|
|
||||||
if (panel != null) {
|
if (panel != null) {
|
||||||
//Workaround for detached HTML input element leak
|
//Workaround for detached HTML input element leak
|
||||||
if (panel.getChildren().size() > 0) {
|
if (attached && panel.getChildren().size() > 0) {
|
||||||
Component[] childs = panel.getChildren().toArray(new Component[0]);
|
Component[] childs = panel.getChildren().toArray(new Component[0]);
|
||||||
for(Component c : childs) {
|
for(Component c : childs) {
|
||||||
AEnv.detachInputElement(c);
|
AEnv.detachInputElement(c);
|
||||||
|
@ -204,6 +206,9 @@ public class Tab extends org.zkoss.zul.Tab
|
||||||
if (include instanceof Include) {
|
if (include instanceof Include) {
|
||||||
include.detach();
|
include.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!attached)
|
||||||
|
panel.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.adempiere.base.event.EventManager;
|
||||||
import org.adempiere.base.event.IEventManager;
|
import org.adempiere.base.event.IEventManager;
|
||||||
import org.adempiere.base.event.IEventTopics;
|
import org.adempiere.base.event.IEventTopics;
|
||||||
import org.adempiere.model.MBroadcastMessage;
|
import org.adempiere.model.MBroadcastMessage;
|
||||||
|
import org.adempiere.util.Callback;
|
||||||
import org.adempiere.webui.ClientInfo;
|
import org.adempiere.webui.ClientInfo;
|
||||||
import org.adempiere.webui.LayoutUtils;
|
import org.adempiere.webui.LayoutUtils;
|
||||||
import org.adempiere.webui.adwindow.ADWindow;
|
import org.adempiere.webui.adwindow.ADWindow;
|
||||||
|
@ -806,7 +807,30 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void logout() {
|
public void logout() {
|
||||||
|
logout(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logout(Callback<Boolean> callback) {
|
||||||
|
if (layout != null && layout.getDesktop() != null
|
||||||
|
&& Executions.getCurrent() != null && Executions.getCurrent().getNativeRequest() != null) {
|
||||||
|
//close all tabs
|
||||||
|
List<Component> tabs = windowContainer.getComponent().getTabs().getChildren();
|
||||||
|
int end = tabs.size() - 1;
|
||||||
|
for (int i = end; i >= 0; i--) {
|
||||||
|
((Tab)tabs.get( i )).close();
|
||||||
|
}
|
||||||
|
AEnv.detachInputElement(layout);
|
||||||
|
//schedule async logout
|
||||||
|
Executions.schedule(layout.getDesktop(), e -> asyncLogout(callback), new Event("onAsyncLogout"));
|
||||||
|
} else {
|
||||||
|
asyncLogout(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void asyncLogout(Callback<Boolean> callback) {
|
||||||
unbindEventManager();
|
unbindEventManager();
|
||||||
if (dashboardController != null) {
|
if (dashboardController != null) {
|
||||||
dashboardController.onLogOut();
|
dashboardController.onLogOut();
|
||||||
|
@ -817,10 +841,17 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
||||||
sideController.onLogOut();
|
sideController.onLogOut();
|
||||||
sideController = null;
|
sideController = null;
|
||||||
}
|
}
|
||||||
if (layout != null) {
|
|
||||||
layout.detach();
|
if (callback != null) {
|
||||||
|
if (layout != null && layout.getDesktop() != null
|
||||||
|
&& Executions.getCurrent() != null && Executions.getCurrent().getNativeRequest() != null) {
|
||||||
|
Executions.schedule(layout.getDesktop(), e -> callback.onCallback(Boolean.TRUE), new Event("onAsyncLogoutCallback"));
|
||||||
|
} else {
|
||||||
|
callback.onCallback(Boolean.TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
layout = null;
|
|
||||||
|
layout = null;
|
||||||
pnlHead = null;
|
pnlHead = null;
|
||||||
max = null;
|
max = null;
|
||||||
m_desktop = null;
|
m_desktop = null;
|
||||||
|
@ -1012,6 +1043,7 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
||||||
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Task, taskId);
|
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Task, taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isPendingWindow() {
|
public boolean isPendingWindow() {
|
||||||
List<Object> windows = getWindows();
|
List<Object> windows = getWindows();
|
||||||
if (windows != null) {
|
if (windows != null) {
|
||||||
|
|
|
@ -201,17 +201,60 @@ public interface IDesktop extends UIPart {
|
||||||
*/
|
*/
|
||||||
public void logout();
|
public void logout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param callback callback after logout
|
||||||
|
*/
|
||||||
|
public default void logout(Callback<Boolean> callback) {
|
||||||
|
logout();
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onCallback(Boolean.TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update help content in help/info panel
|
||||||
|
* @param ctxTypes
|
||||||
|
* @param recordId
|
||||||
|
*/
|
||||||
public void updateHelpContext(String ctxType, int recordId);
|
public void updateHelpContext(String ctxType, int recordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update tooltip content in help/info panel
|
||||||
|
* @param gridField
|
||||||
|
*/
|
||||||
public void updateHelpTooltip(GridField gridField);
|
public void updateHelpTooltip(GridField gridField);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update tooltip content in help/info panel
|
||||||
|
* @param hdr
|
||||||
|
* @param desc
|
||||||
|
* @param help
|
||||||
|
* @param otherContent
|
||||||
|
*/
|
||||||
public void updateHelpTooltip(String hdr, String desc, String help, String otherContent);
|
public void updateHelpTooltip(String hdr, String desc, String help, String otherContent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update quick info (status line) in help/info panel
|
||||||
|
* @param gridTab
|
||||||
|
*/
|
||||||
public void updateHelpQuickInfo(GridTab gridTab);
|
public void updateHelpQuickInfo(GridTab gridTab);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return true if there are changes not save yet
|
||||||
|
*/
|
||||||
public boolean isPendingWindow();
|
public boolean isPendingWindow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update tab title by windowNo
|
||||||
|
* @param title
|
||||||
|
* @param windowNo
|
||||||
|
*/
|
||||||
public void setTabTitle(String title, int windowNo);
|
public void setTabTitle(String title, int windowNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* render home tab
|
||||||
|
*/
|
||||||
public void renderHomeTab();
|
public void renderHomeTab();
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,7 +424,7 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
|
||||||
Tab tab = (Tab)event.getTarget();
|
Tab tab = (Tab)event.getTarget();
|
||||||
org.zkoss.zul.Tabpanel panel = tab.getLinkedPanel();
|
org.zkoss.zul.Tabpanel panel = tab.getLinkedPanel();
|
||||||
if (panel == null) {
|
if (panel == null) {
|
||||||
System.console().printf("error");
|
return;
|
||||||
}
|
}
|
||||||
Component component = panel.getFirstChild();
|
Component component = panel.getFirstChild();
|
||||||
if (component != null && component.getAttribute(ITabOnSelectHandler.ATTRIBUTE_KEY) instanceof ITabOnSelectHandler)
|
if (component != null && component.getAttribute(ITabOnSelectHandler.ATTRIBUTE_KEY) instanceof ITabOnSelectHandler)
|
||||||
|
@ -740,6 +740,9 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
|
||||||
*/
|
*/
|
||||||
public void setTabTitle(int tabNo, String title, String tooltip)
|
public void setTabTitle(int tabNo, String title, String tooltip)
|
||||||
{
|
{
|
||||||
|
if (tabNo < 0 || tabNo >= tabbox.getTabs().getChildren().size())
|
||||||
|
return;
|
||||||
|
|
||||||
org.zkoss.zul.Tabs tabs = tabbox.getTabs();
|
org.zkoss.zul.Tabs tabs = tabbox.getTabs();
|
||||||
Tab tab = (Tab) tabs.getChildren().get(tabNo);
|
Tab tab = (Tab) tabs.getChildren().get(tabNo);
|
||||||
setTabTitle(title, tab);
|
setTabTitle(title, tab);
|
||||||
|
|
|
@ -45,6 +45,9 @@ public class ServerPushTemplate {
|
||||||
* @param callback
|
* @param callback
|
||||||
*/
|
*/
|
||||||
public void executeAsync(final IServerPushCallback callback) {
|
public void executeAsync(final IServerPushCallback callback) {
|
||||||
|
if (!desktop.isAlive())
|
||||||
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
EventListener<Event> task = new EventListener<Event>() {
|
EventListener<Event> task = new EventListener<Event>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -188,9 +188,9 @@ public class ChartRendererServiceImpl implements IChartRendererService {
|
||||||
|
|
||||||
if (Executions.getCurrent() != null)
|
if (Executions.getCurrent() != null)
|
||||||
{
|
{
|
||||||
String script = "var parent = jq('#" + parent.getUuid() + "');";
|
String script = "(function() {let parent = jq('#" + parent.getUuid() + "');";
|
||||||
script += "var billboard = parent.children().first(); ";
|
script += "let billboard = parent.children().first(); ";
|
||||||
script += "var div = parent.children().eq(1); ";
|
script += "let div = parent.children().eq(1); ";
|
||||||
script += "if (billboard.children().length == 0) {";
|
script += "if (billboard.children().length == 0) {";
|
||||||
script += "div.show(); ";
|
script += "div.show(); ";
|
||||||
script += "billboard.hide(); ";
|
script += "billboard.hide(); ";
|
||||||
|
@ -198,7 +198,7 @@ public class ChartRendererServiceImpl implements IChartRendererService {
|
||||||
script += "else {";
|
script += "else {";
|
||||||
script += "div.hide(); ";
|
script += "div.hide(); ";
|
||||||
script += "billboard.show(); ";
|
script += "billboard.show(); ";
|
||||||
script += "}";
|
script += "}})();";
|
||||||
Clients.response(new AuScript(script));
|
Clients.response(new AuScript(script));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue