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)
|
||||
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
|
||||
if (keyListener != null) {
|
||||
keyListener.detach();
|
||||
keyListener = null;
|
||||
}
|
||||
|
||||
//desktop cleanup
|
||||
IDesktop appDesktop = getAppDeskop();
|
||||
if (appDesktop != null)
|
||||
appDesktop.logout();
|
||||
|
||||
//remove all children component
|
||||
getChildren().clear();
|
||||
|
||||
|
@ -648,7 +650,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
this.setPage(page);
|
||||
|
||||
//clear session attributes
|
||||
Enumeration<String> attributes = httpRequest.getSession().getAttributeNames();
|
||||
Enumeration<String> attributes = httpSession.getAttributeNames();
|
||||
while(attributes.hasMoreElements()) {
|
||||
String attribute = attributes.nextElement();
|
||||
|
||||
|
@ -656,7 +658,7 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
if (attribute.contains("zkoss."))
|
||||
continue;
|
||||
|
||||
httpRequest.getSession().removeAttribute(attribute);
|
||||
httpSession.removeAttribute(attribute);
|
||||
}
|
||||
|
||||
//logout ad_session
|
||||
|
|
|
@ -80,6 +80,7 @@ import org.zkoss.zk.ui.Execution;
|
|||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.impl.InputElement;
|
||||
|
||||
import com.lowagie.text.DocumentException;
|
||||
|
@ -881,7 +882,7 @@ public final class AEnv
|
|||
* @param c
|
||||
*/
|
||||
public static void detachInputElement(Component c) {
|
||||
if (c instanceof InputElement) {
|
||||
if (c instanceof InputElement || c instanceof Button) {
|
||||
c.detach();
|
||||
}
|
||||
if (c.getChildren().size() > 0) {
|
||||
|
|
|
@ -184,15 +184,17 @@ public class Tab extends org.zkoss.zul.Tab
|
|||
}
|
||||
|
||||
//Workaround for detached HTML input element leak
|
||||
boolean attached = getDesktop() != 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();
|
||||
|
||||
if (panel != null) {
|
||||
//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]);
|
||||
for(Component c : childs) {
|
||||
AEnv.detachInputElement(c);
|
||||
|
@ -204,6 +206,9 @@ public class Tab extends org.zkoss.zul.Tab
|
|||
if (include instanceof Include) {
|
||||
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.IEventTopics;
|
||||
import org.adempiere.model.MBroadcastMessage;
|
||||
import org.adempiere.util.Callback;
|
||||
import org.adempiere.webui.ClientInfo;
|
||||
import org.adempiere.webui.LayoutUtils;
|
||||
import org.adempiere.webui.adwindow.ADWindow;
|
||||
|
@ -806,7 +807,30 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
|||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
if (dashboardController != null) {
|
||||
dashboardController.onLogOut();
|
||||
|
@ -817,10 +841,17 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
|||
sideController.onLogOut();
|
||||
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;
|
||||
max = null;
|
||||
m_desktop = null;
|
||||
|
@ -1012,6 +1043,7 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
|
|||
updateHelpContext(X_AD_CtxHelp.CTXTYPE_Task, taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPendingWindow() {
|
||||
List<Object> windows = getWindows();
|
||||
if (windows != null) {
|
||||
|
|
|
@ -201,17 +201,60 @@ public interface IDesktop extends UIPart {
|
|||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* update tooltip content in help/info panel
|
||||
* @param 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);
|
||||
|
||||
/**
|
||||
* update quick info (status line) in help/info panel
|
||||
* @param gridTab
|
||||
*/
|
||||
public void updateHelpQuickInfo(GridTab gridTab);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if there are changes not save yet
|
||||
*/
|
||||
public boolean isPendingWindow();
|
||||
|
||||
/**
|
||||
* update tab title by windowNo
|
||||
* @param title
|
||||
* @param windowNo
|
||||
*/
|
||||
public void setTabTitle(String title, int windowNo);
|
||||
|
||||
/**
|
||||
* render home tab
|
||||
*/
|
||||
public void renderHomeTab();
|
||||
}
|
||||
|
|
|
@ -424,7 +424,7 @@ public class WindowContainer extends AbstractUIPart implements EventListener<Eve
|
|||
Tab tab = (Tab)event.getTarget();
|
||||
org.zkoss.zul.Tabpanel panel = tab.getLinkedPanel();
|
||||
if (panel == null) {
|
||||
System.console().printf("error");
|
||||
return;
|
||||
}
|
||||
Component component = panel.getFirstChild();
|
||||
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)
|
||||
{
|
||||
if (tabNo < 0 || tabNo >= tabbox.getTabs().getChildren().size())
|
||||
return;
|
||||
|
||||
org.zkoss.zul.Tabs tabs = tabbox.getTabs();
|
||||
Tab tab = (Tab) tabs.getChildren().get(tabNo);
|
||||
setTabTitle(title, tab);
|
||||
|
|
|
@ -45,6 +45,9 @@ public class ServerPushTemplate {
|
|||
* @param callback
|
||||
*/
|
||||
public void executeAsync(final IServerPushCallback callback) {
|
||||
if (!desktop.isAlive())
|
||||
return;
|
||||
|
||||
try {
|
||||
EventListener<Event> task = new EventListener<Event>() {
|
||||
@Override
|
||||
|
|
|
@ -188,9 +188,9 @@ public class ChartRendererServiceImpl implements IChartRendererService {
|
|||
|
||||
if (Executions.getCurrent() != null)
|
||||
{
|
||||
String script = "var parent = jq('#" + parent.getUuid() + "');";
|
||||
script += "var billboard = parent.children().first(); ";
|
||||
script += "var div = parent.children().eq(1); ";
|
||||
String script = "(function() {let parent = jq('#" + parent.getUuid() + "');";
|
||||
script += "let billboard = parent.children().first(); ";
|
||||
script += "let div = parent.children().eq(1); ";
|
||||
script += "if (billboard.children().length == 0) {";
|
||||
script += "div.show(); ";
|
||||
script += "billboard.hide(); ";
|
||||
|
@ -198,7 +198,7 @@ public class ChartRendererServiceImpl implements IChartRendererService {
|
|||
script += "else {";
|
||||
script += "div.hide(); ";
|
||||
script += "billboard.show(); ";
|
||||
script += "}";
|
||||
script += "}})();";
|
||||
Clients.response(new AuScript(script));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue