Commit 52a35bd6 authored by pfeldman's avatar pfeldman Committed by Commit bot

DevTools: keep widgets in widget hierarchy upon hide, split attach/detach...

DevTools: keep widgets in widget hierarchy upon hide, split attach/detach cycle from show/hide (reland)

TBR=dgozman

Review-Url: https://codereview.chromium.org/2168223002
Cr-Commit-Position: refs/heads/master@{#407209}
parent fbd8d172
...@@ -81,7 +81,7 @@ function test() ...@@ -81,7 +81,7 @@ function test()
dumpBoundingBoxes(widgets); dumpBoundingBoxes(widgets);
InspectorTest.addResult("Detaching sidebar"); InspectorTest.addResult("Detaching sidebar");
secondSidebarWidget.detach(); childsplitWidget.setSidebarWidget(null);
delete widgets["secondSidebarWidget"]; delete widgets["secondSidebarWidget"];
dumpBoundingBoxes(widgets); dumpBoundingBoxes(widgets);
......
...@@ -238,3 +238,9 @@ Parent.detach() ...@@ -238,3 +238,9 @@ Parent.detach()
Child.willHide() Child.willHide()
Parent.willHide() Parent.willHide()
Running: testAlienParent
Parent()
Parent()
Child()
Error: Attempt to show under node belonging to alien widget
...@@ -151,13 +151,13 @@ function test() ...@@ -151,13 +151,13 @@ function test()
var parentWidget = new TestWidget("Parent"); var parentWidget = new TestWidget("Parent");
parentWidget.markAsRoot(); parentWidget.markAsRoot();
var childWidget = new TestWidget("Child"); var childWidget = new TestWidget("Child");
parentWidget.show(WebInspector.inspectorView.element); parentWidget.show(document.body);
parentWidget.doResize(); parentWidget.doResize();
childWidget.show(parentWidget.element); childWidget.show(parentWidget.element);
parentWidget.doResize(); parentWidget.doResize();
parentWidget.detach(); parentWidget.detach();
parentWidget.show(WebInspector.inspectorView.element); parentWidget.show(document.body);
childWidget.detach(); childWidget.detach();
parentWidget.detach(); parentWidget.detach();
next(); next();
...@@ -341,6 +341,20 @@ function test() ...@@ -341,6 +341,20 @@ function test()
parentWidget.show(WebInspector.inspectorView.element); parentWidget.show(WebInspector.inspectorView.element);
parentWidget.detach(); parentWidget.detach();
next(); next();
},
function testAlienParent(next)
{
var parentWidget1 = new TestWidget("Parent");
var parentWidget2 = new TestWidget("Parent");
var childWidget = new TestWidget("Child");
childWidget.attach(parentWidget1);
try {
childWidget.showWidget(parentWidget2.element);
} catch (e) {
InspectorTest.addResult(e);
}
next();
} }
]); ]);
} }
......
...@@ -249,7 +249,7 @@ WebInspector.ExtensionSidebarPane.prototype = { ...@@ -249,7 +249,7 @@ WebInspector.ExtensionSidebarPane.prototype = {
delete this._objectPropertiesView; delete this._objectPropertiesView;
} }
if (this._extensionView) if (this._extensionView)
this._extensionView.detach(true); this._extensionView.detach();
this._extensionView = new WebInspector.ExtensionView(this._server, this._id, url, "extension fill"); this._extensionView = new WebInspector.ExtensionView(this._server, this._id, url, "extension fill");
this._extensionView.show(this.element); this._extensionView.show(this.element);
...@@ -286,7 +286,7 @@ WebInspector.ExtensionSidebarPane.prototype = { ...@@ -286,7 +286,7 @@ WebInspector.ExtensionSidebarPane.prototype = {
if (this._objectPropertiesView) if (this._objectPropertiesView)
return; return;
if (this._extensionView) { if (this._extensionView) {
this._extensionView.detach(true); this._extensionView.detach();
delete this._extensionView; delete this._extensionView;
} }
this._objectPropertiesView = new WebInspector.ExtensionNotifierView(this._server, this._id); this._objectPropertiesView = new WebInspector.ExtensionNotifierView(this._server, this._id);
......
...@@ -1023,7 +1023,7 @@ WebInspector.TargetCrashedScreen.show = function(debuggerModel) ...@@ -1023,7 +1023,7 @@ WebInspector.TargetCrashedScreen.show = function(debuggerModel)
dialog.setWrapsContent(true); dialog.setWrapsContent(true);
dialog.addCloseButton(); dialog.addCloseButton();
dialog.setDimmed(true); dialog.setDimmed(true);
var hideBound = dialog.detach.bind(dialog, false); var hideBound = dialog.detach.bind(dialog);
debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, hideBound); debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, hideBound);
new WebInspector.TargetCrashedScreen(onHide).show(dialog.element); new WebInspector.TargetCrashedScreen(onHide).show(dialog.element);
......
...@@ -108,7 +108,7 @@ WebInspector.Dialog.prototype = { ...@@ -108,7 +108,7 @@ WebInspector.Dialog.prototype = {
{ {
var closeButton = this.contentElement.createChild("div", "dialog-close-button", "dt-close-button"); var closeButton = this.contentElement.createChild("div", "dialog-close-button", "dt-close-button");
closeButton.gray = true; closeButton.gray = true;
closeButton.addEventListener("click", this.detach.bind(this, false), false); closeButton.addEventListener("click", this.detach.bind(this), false);
}, },
/** /**
......
...@@ -23,7 +23,7 @@ WebInspector.RootView.prototype = { ...@@ -23,7 +23,7 @@ WebInspector.RootView.prototype = {
document.defaultView.addEventListener("resize", this.doResize.bind(this), false); document.defaultView.addEventListener("resize", this.doResize.bind(this), false);
this._window = document.defaultView; this._window = document.defaultView;
this.doResize(); this.doResize();
this.show(document.body); this.show(/** @type {!Element} */ (document.body));
}, },
doResize: function() doResize: function()
......
...@@ -46,7 +46,7 @@ WebInspector.SidebarPaneTitle.prototype = { ...@@ -46,7 +46,7 @@ WebInspector.SidebarPaneTitle.prototype = {
_expand: function() _expand: function()
{ {
this.element.classList.add("expanded"); this.element.classList.add("expanded");
this._pane.show(this.element.parentElement, /** @type {?Element} */ (this.element.nextSibling)); this._pane.show(/** @type {!Element} */(this.element.parentElement), /** @type {?Element} */ (this.element.nextSibling));
}, },
_collapse: function() _collapse: function()
......
...@@ -152,15 +152,18 @@ WebInspector.SplitWidget.prototype = { ...@@ -152,15 +152,18 @@ WebInspector.SplitWidget.prototype = {
{ {
if (this._mainWidget === widget) if (this._mainWidget === widget)
return; return;
this.suspendInvalidations();
if (this._mainWidget) if (this._mainWidget)
this._mainWidget.detach(); this._mainWidget.detach();
this._mainWidget = widget; this._mainWidget = widget;
if (widget) { if (widget) {
widget.element.classList.add("insertion-point-main"); widget.element.classList.add("insertion-point-main");
widget.element.classList.remove("insertion-point-sidebar"); widget.element.classList.remove("insertion-point-sidebar");
widget.attach(this);
if (this._showMode === WebInspector.SplitWidget.ShowMode.OnlyMain || this._showMode === WebInspector.SplitWidget.ShowMode.Both) if (this._showMode === WebInspector.SplitWidget.ShowMode.OnlyMain || this._showMode === WebInspector.SplitWidget.ShowMode.Both)
widget.show(this.element); widget.showWidget(this.element);
} }
this.resumeInvalidations();
}, },
/** /**
...@@ -170,15 +173,18 @@ WebInspector.SplitWidget.prototype = { ...@@ -170,15 +173,18 @@ WebInspector.SplitWidget.prototype = {
{ {
if (this._sidebarWidget === widget) if (this._sidebarWidget === widget)
return; return;
this.suspendInvalidations();
if (this._sidebarWidget) if (this._sidebarWidget)
this._sidebarWidget.detach(); this._sidebarWidget.detach();
this._sidebarWidget = widget; this._sidebarWidget = widget;
if (widget) { if (widget) {
widget.element.classList.add("insertion-point-sidebar"); widget.element.classList.add("insertion-point-sidebar");
widget.element.classList.remove("insertion-point-main"); widget.element.classList.remove("insertion-point-main");
widget.attach(this);
if (this._showMode === WebInspector.SplitWidget.ShowMode.OnlySidebar || this._showMode === WebInspector.SplitWidget.ShowMode.Both) if (this._showMode === WebInspector.SplitWidget.ShowMode.OnlySidebar || this._showMode === WebInspector.SplitWidget.ShowMode.Both)
widget.show(this.element); widget.showWidget(this.element);
} }
this.resumeInvalidations();
}, },
/** /**
...@@ -203,8 +209,6 @@ WebInspector.SplitWidget.prototype = { ...@@ -203,8 +209,6 @@ WebInspector.SplitWidget.prototype = {
*/ */
childWasDetached: function(widget) childWasDetached: function(widget)
{ {
if (this._detaching)
return;
if (this._mainWidget === widget) if (this._mainWidget === widget)
delete this._mainWidget; delete this._mainWidget;
if (this._sidebarWidget === widget) if (this._sidebarWidget === widget)
...@@ -316,15 +320,12 @@ WebInspector.SplitWidget.prototype = { ...@@ -316,15 +320,12 @@ WebInspector.SplitWidget.prototype = {
if (sideToShow) { if (sideToShow) {
// Make sure main is first in the children list. // Make sure main is first in the children list.
if (sideToShow === this._mainWidget) if (sideToShow === this._mainWidget)
this._mainWidget.show(this.element, this._sidebarWidget ? this._sidebarWidget.element : null); this._mainWidget.showWidget(this.element);
else else
this._sidebarWidget.show(this.element); this._sidebarWidget.showWidget(this.element);
}
if (sideToHide) {
this._detaching = true;
sideToHide.detach();
delete this._detaching;
} }
if (sideToHide)
sideToHide.hideWidget();
this._resizerElement.classList.add("hidden"); this._resizerElement.classList.add("hidden");
shadowToShow.classList.remove("hidden"); shadowToShow.classList.remove("hidden");
...@@ -379,10 +380,12 @@ WebInspector.SplitWidget.prototype = { ...@@ -379,10 +380,12 @@ WebInspector.SplitWidget.prototype = {
this.setResizable(true); this.setResizable(true);
// Make sure main is the first in the children list. // Make sure main is the first in the children list.
this.suspendInvalidations();
if (this._sidebarWidget) if (this._sidebarWidget)
this._sidebarWidget.show(this.element); this._sidebarWidget.showWidget(this.element);
if (this._mainWidget) if (this._mainWidget)
this._mainWidget.show(this.element, this._sidebarWidget ? this._sidebarWidget.element : null); this._mainWidget.showWidget(this.element);
this.resumeInvalidations();
// Order widgets in DOM properly. // Order widgets in DOM properly.
this.setSecondIsSidebar(this._secondIsSidebar); this.setSecondIsSidebar(this._secondIsSidebar);
......
...@@ -208,6 +208,7 @@ WebInspector.TabbedPane.prototype = { ...@@ -208,6 +208,7 @@ WebInspector.TabbedPane.prototype = {
else else
this._tabs.push(tab); this._tabs.push(tab);
this._tabsHistory.push(tab); this._tabsHistory.push(tab);
view.attach(this);
if (this._tabsHistory[0] === tab && this.isShowing()) if (this._tabsHistory[0] === tab && this.isShowing())
this.selectTab(tab.id, userGesture); this.selectTab(tab.id, userGesture);
this._updateTabElements(); this._updateTabElements();
...@@ -258,6 +259,7 @@ WebInspector.TabbedPane.prototype = { ...@@ -258,6 +259,7 @@ WebInspector.TabbedPane.prototype = {
this._tabs.splice(this._tabs.indexOf(tab), 1); this._tabs.splice(this._tabs.indexOf(tab), 1);
if (tab._shown) if (tab._shown)
this._hideTabElement(tab); this._hideTabElement(tab);
tab.view.detach();
var eventData = { tabId: id, view: tab.view, isUserGesture: userGesture }; var eventData = { tabId: id, view: tab.view, isUserGesture: userGesture };
this.dispatchEventToListeners(WebInspector.TabbedPane.EventTypes.TabClosed, eventData); this.dispatchEventToListeners(WebInspector.TabbedPane.EventTypes.TabClosed, eventData);
...@@ -329,8 +331,10 @@ WebInspector.TabbedPane.prototype = { ...@@ -329,8 +331,10 @@ WebInspector.TabbedPane.prototype = {
if (this._currentTab && this._currentTab.id === id) if (this._currentTab && this._currentTab.id === id)
return true; return true;
this.suspendInvalidations();
this._hideCurrentTab(); this._hideCurrentTab();
this._showTab(tab); this._showTab(tab);
this.resumeInvalidations();
this._currentTab = tab; this._currentTab = tab;
this._tabsHistory.splice(this._tabsHistory.indexOf(tab), 1); this._tabsHistory.splice(this._tabsHistory.indexOf(tab), 1);
...@@ -423,13 +427,19 @@ WebInspector.TabbedPane.prototype = { ...@@ -423,13 +427,19 @@ WebInspector.TabbedPane.prototype = {
changeTabView: function(id, view) changeTabView: function(id, view)
{ {
var tab = this._tabsById[id]; var tab = this._tabsById[id];
if (this._currentTab && this._currentTab.id === tab.id) { if (tab.view === view)
if (tab.view !== view) return;
this._hideTab(tab);
tab.view = view; this.suspendInvalidations();
var isSelected = this._currentTab && this._currentTab.id === id;
if (isSelected)
this._hideTab(tab);
tab.view.detach();
tab.view = view;
tab.view.attach(this);
if (isSelected)
this._showTab(tab); this._showTab(tab);
} else this.resumeInvalidations();
tab.view = view;
}, },
onResize: function() onResize: function()
...@@ -759,7 +769,7 @@ WebInspector.TabbedPane.prototype = { ...@@ -759,7 +769,7 @@ WebInspector.TabbedPane.prototype = {
_showTab: function(tab) _showTab: function(tab)
{ {
tab.tabElement.classList.add("selected"); tab.tabElement.classList.add("selected");
tab.view.show(this.element); tab.view.showWidget(this.element);
this._updateTabSlider(); this._updateTabSlider();
}, },
...@@ -785,7 +795,7 @@ WebInspector.TabbedPane.prototype = { ...@@ -785,7 +795,7 @@ WebInspector.TabbedPane.prototype = {
_hideTab: function(tab) _hideTab: function(tab)
{ {
tab.tabElement.classList.remove("selected"); tab.tabElement.classList.remove("selected");
tab.view.detach(); tab.view.hideWidget();
}, },
/** /**
......
...@@ -41,12 +41,13 @@ WebInspector.Widget = function(isWebComponent) ...@@ -41,12 +41,13 @@ WebInspector.Widget = function(isWebComponent)
} }
this._isWebComponent = isWebComponent; this._isWebComponent = isWebComponent;
this.element.__widget = this; this.element.__widget = this;
this._visible = true; this._visible = false;
this._isRoot = false; this._isRoot = false;
this._isShowing = false; this._isShowing = false;
this._children = []; this._children = [];
this._hideOnDetach = false; this._hideOnDetach = false;
this._notificationDepth = 0; this._notificationDepth = 0;
this._invalidationsSuspended = 0;
} }
WebInspector.Widget.prototype = { WebInspector.Widget.prototype = {
...@@ -119,7 +120,7 @@ WebInspector.Widget.prototype = { ...@@ -119,7 +120,7 @@ WebInspector.Widget.prototype = {
{ {
if (this._isRoot) if (this._isRoot)
return true; return true;
return this._parentWidget && this._parentWidget.isShowing(); return !!this._parentWidget && this._parentWidget.isShowing();
}, },
/** /**
...@@ -205,32 +206,56 @@ WebInspector.Widget.prototype = { ...@@ -205,32 +206,56 @@ WebInspector.Widget.prototype = {
}, },
/** /**
* @param {?Element} parentElement * @param {!Element} parentElement
* @param {?Element=} insertBefore * @param {?Element=} insertBefore
*/ */
show: function(parentElement, insertBefore) show: function(parentElement, insertBefore)
{ {
WebInspector.Widget.__assert(parentElement, "Attempt to attach widget with no parent element"); WebInspector.Widget.__assert(parentElement, "Attempt to attach widget with no parent element");
// Update widget hierarchy. if (!this._isRoot) {
if (this.element.parentElement !== parentElement) { // Update widget hierarchy.
if (this.element.parentElement)
this.detach();
var currentParent = parentElement; var currentParent = parentElement;
while (currentParent && !currentParent.__widget) while (currentParent && !currentParent.__widget)
currentParent = currentParent.parentElementOrShadowHost(); currentParent = currentParent.parentElementOrShadowHost();
WebInspector.Widget.__assert(currentParent, "Attempt to attach widget to orphan node");
this.attach(currentParent.__widget);
}
this.showWidget(parentElement, insertBefore);
},
if (currentParent) { /**
this._parentWidget = currentParent.__widget; * @param {!WebInspector.Widget} parentWidget
this._parentWidget._children.push(this); */
this._isRoot = false; attach: function(parentWidget)
} else {
WebInspector.Widget.__assert(this._isRoot, "Attempt to attach widget to orphan node"); if (parentWidget === this._parentWidget)
} else if (this._visible) {
return; return;
} if (this._parentWidget)
this.detach();
this._parentWidget = parentWidget;
this._parentWidget._children.push(this);
this._isRoot = false;
},
/**
* @param {!Element} parentElement
* @param {?Element=} insertBefore
*/
showWidget: function(parentElement, insertBefore)
{
var currentParent = parentElement;
while (currentParent && !currentParent.__widget)
currentParent = currentParent.parentElementOrShadowHost();
if (this._isRoot)
WebInspector.Widget.__assert(!currentParent, "Attempt to show root widget under another widget");
else
WebInspector.Widget.__assert(currentParent && currentParent.__widget === this._parentWidget, "Attempt to show under node belonging to alien widget");
if (this._visible)
return;
this._visible = true; this._visible = true;
if (this._parentIsShowing()) if (this._parentIsShowing())
...@@ -256,35 +281,47 @@ WebInspector.Widget.prototype = { ...@@ -256,35 +281,47 @@ WebInspector.Widget.prototype = {
this._processOnResize(); this._processOnResize();
}, },
hideWidget: function()
{
if (!this._parentWidget)
return;
this._hideWidget();
},
/** /**
* @param {boolean=} overrideHideOnDetach * @param {boolean=} overrideHideOnDetach
*/ */
detach: function(overrideHideOnDetach) _hideWidget: function(overrideHideOnDetach)
{ {
var parentElement = this.element.parentElement; if (!this._visible)
if (!parentElement)
return; return;
this._visible = false;
var parentElement = this.element.parentElement;
if (this._parentIsShowing()) if (this._parentIsShowing())
this._processWillHide(); this._processWillHide();
if (!overrideHideOnDetach && this.shouldHideOnDetach()) { if (!overrideHideOnDetach && this.shouldHideOnDetach()) {
this.element.classList.add("hidden"); this.element.classList.add("hidden");
this._visible = false; } else {
if (this._parentIsShowing()) // Force legal removal
this._processWasHidden(); WebInspector.Widget._decrementWidgetCounter(parentElement, this.element);
if (this._parentWidget && this._hasNonZeroConstraints()) WebInspector.Widget._originalRemoveChild.call(parentElement, this.element);
this._parentWidget.invalidateConstraints();
return;
} }
// Force legal removal
WebInspector.Widget._decrementWidgetCounter(parentElement, this.element);
WebInspector.Widget._originalRemoveChild.call(parentElement, this.element);
this._visible = false;
if (this._parentIsShowing()) if (this._parentIsShowing())
this._processWasHidden(); this._processWasHidden();
if (this._parentWidget && this._hasNonZeroConstraints())
this._parentWidget.invalidateConstraints();
},
detach: function()
{
if (!this._parentWidget && !this._isRoot)
return;
if (this._visible)
this._hideWidget(true);
// Update widget hierarchy. // Update widget hierarchy.
if (this._parentWidget) { if (this._parentWidget) {
...@@ -294,10 +331,9 @@ WebInspector.Widget.prototype = { ...@@ -294,10 +331,9 @@ WebInspector.Widget.prototype = {
this._parentWidget.childWasDetached(this); this._parentWidget.childWasDetached(this);
var parent = this._parentWidget; var parent = this._parentWidget;
this._parentWidget = null; this._parentWidget = null;
if (this._hasNonZeroConstraints()) } else {
parent.invalidateConstraints();
} else
WebInspector.Widget.__assert(this._isRoot, "Removing non-root widget from DOM"); WebInspector.Widget.__assert(this._isRoot, "Removing non-root widget from DOM");
}
}, },
detachChildWidgets: function() detachChildWidgets: function()
...@@ -479,8 +515,25 @@ WebInspector.Widget.prototype = { ...@@ -479,8 +515,25 @@ WebInspector.Widget.prototype = {
return !!(constraints.minimum.width || constraints.minimum.height || constraints.preferred.width || constraints.preferred.height); return !!(constraints.minimum.width || constraints.minimum.height || constraints.preferred.width || constraints.preferred.height);
}, },
suspendInvalidations()
{
++this._invalidationsSuspended;
},
resumeInvalidations()
{
--this._invalidationsSuspended;
if (!this._invalidationsSuspended && this._invalidationsRequested)
this.invalidateConstraints();
},
invalidateConstraints: function() invalidateConstraints: function()
{ {
if (this._invalidationsSuspended) {
this._invalidationsRequested = true;
return;
}
this._invalidationsRequested = false;
var cached = this._cachedConstraints; var cached = this._cachedConstraints;
delete this._cachedConstraints; delete this._cachedConstraints;
var actual = this.constraints(); var actual = this.constraints();
......
...@@ -476,8 +476,8 @@ WebInspector.TimelineOverview = function() ...@@ -476,8 +476,8 @@ WebInspector.TimelineOverview = function()
WebInspector.TimelineOverview.prototype = { WebInspector.TimelineOverview.prototype = {
/** /**
* @param {?Element} parentElement * @param {!Element} parentElement
* @param {!Element=} insertBefore * @param {?Element=} insertBefore
*/ */
show: function(parentElement, insertBefore) { }, show: function(parentElement, insertBefore) { },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment