Bug 1392340 - Height jumps when opening subviews of different lengths. r=Gijs
The height of the subview being opened was supposedly calculated using an off-screen container independent from the currently displayed views, but this didn't work as expected because of the incorrect box alignment. This is now fixed and the correct minimum and maximum heights are set on the container separately, also preventing the current view from flickering before the transition in case the subview was taller.
With this issue fixed, the height can now be recalculated each time the subview is opened, without the caching that caused incorrect results when the same view was reopened with different elements or text.
Jumping could also occur because of a border applied only during the transition, which could influence the subview height in the presence of wrapping text.
MozReview-Commit-ID: EWHs1hFKXT4
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -63,16 +63,17 @@ toolbar[customizable="true"] {
}
%endif
#toolbar-menubar[autohide="true"] {
-moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
}
panelmultiview {
+ -moz-box-align: start;
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview");
}
panelview {
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview");
-moz-box-orient: vertical;
}
--- a/browser/components/customizableui/PanelMultiView.jsm
+++ b/browser/components/customizableui/PanelMultiView.jsm
@@ -584,47 +584,53 @@ this.PanelMultiView = class {
this._viewContainer.style.height = Math.max(previousRect.height, this._mainViewHeight) + "px";
this._viewContainer.style.width = previousRect.width + "px";
// Lock the dimensions of the window that hosts the popup panel.
let rect = this._panel.popupBoxObject.getOuterScreenRect();
this._panel.setAttribute("width", rect.width);
this._panel.setAttribute("height", rect.height);
let viewRect;
- if (viewNode.__lastKnownBoundingRect) {
+ if (reverse && viewNode.__lastKnownBoundingRect) {
+ // Use the cached size when going back to a previous view, but not when
+ // reopening a subview, because its contents may have changed.
viewRect = viewNode.__lastKnownBoundingRect;
viewNode.setAttribute("in-transition", true);
} else if (viewNode.customRectGetter) {
// Can't use Object.assign directly with a DOM Rect object because its properties
// aren't enumerable.
let {height, width} = previousRect;
viewRect = Object.assign({height, width}, viewNode.customRectGetter());
let {header} = viewNode;
if (header) {
viewRect.height += this._dwu.getBoundsWithoutFlushing(header).height;
}
viewNode.setAttribute("in-transition", true);
} else {
let oldSibling = viewNode.nextSibling || null;
+ this._offscreenViewStack.style.minHeight =
+ this._viewContainer.style.height;
this._offscreenViewStack.appendChild(viewNode);
viewNode.setAttribute("in-transition", true);
// Now that the subview is visible, we can check the height of the
// description elements it contains.
this.descriptionHeightWorkaround(viewNode);
viewRect = await BrowserUtils.promiseLayoutFlushed(this.document, "layout", () => {
return this._dwu.getBoundsWithoutFlushing(viewNode);
});
try {
this._viewStack.insertBefore(viewNode, oldSibling);
} catch (ex) {
this._viewStack.appendChild(viewNode);
}
+
+ this._offscreenViewStack.style.removeProperty("min-height");
}
this._transitioning = true;
details.phase = TRANSITION_PHASES.PREPARE;
// The 'magic' part: build up the amount of pixels to move right or left.
let moveToLeft = (this._dir == "rtl" && !reverse) || (this._dir == "ltr" && reverse);
let deltaX = previousRect.width;
@@ -638,17 +644,18 @@ this.PanelMultiView = class {
// Set the transition style and listen for its end to clean up and make sure
// the box sizing becomes dynamic again.
// Somehow, putting these properties in PanelUI.css doesn't work for newly
// shown nodes in a XUL parent node.
this._viewStack.style.transition = "transform var(--animation-easing-function)" +
" var(--panelui-subview-transition-duration)";
this._viewStack.style.willChange = "transform";
- deepestNode.style.borderInlineStart = "1px solid var(--panel-separator-color)";
+ // Use an outline instead of a border so that the size is not affected.
+ deepestNode.style.outline = "1px solid var(--panel-separator-color)";
// Now set the viewContainer dimensions to that of the new view, which
// kicks of the height animation.
this._viewContainer.style.height = Math.max(viewRect.height, this._mainViewHeight) + "px";
this._viewContainer.style.width = viewRect.width + "px";
this._panel.removeAttribute("width");
this._panel.removeAttribute("height");
// We're setting the width property to prevent flickering during the
@@ -729,17 +736,17 @@ this.PanelMultiView = class {
this._viewContainer.style.removeProperty("width");
}, 500);
}
if (phase >= TRANSITION_PHASES.PREPARE) {
this._transitioning = false;
if (reverse)
this._viewStack.style.removeProperty("margin-inline-start");
let deepestNode = reverse ? previousViewNode : viewNode;
- deepestNode.style.removeProperty("border-inline-start");
+ deepestNode.style.removeProperty("outline");
this._viewStack.style.removeProperty("transition");
}
if (phase >= TRANSITION_PHASES.TRANSITION) {
this._viewStack.style.removeProperty("transform");
viewNode.style.removeProperty("width");
if (listener)
this._viewContainer.removeEventListener("transitionend", listener);
if (cancelListener)
@@ -852,16 +859,17 @@ this.PanelMultiView = class {
// to fit the screen while open.
// autoPosition gets reset after each popuppositioned event, and when the
// popup closes, so we must set it back to false each time.
this._panel.autoPosition = false;
if (this._panel.state == "showing") {
let maxHeight = this._calculateMaxHeight();
this._viewStack.style.maxHeight = maxHeight + "px";
+ this._offscreenViewStack.style.maxHeight = maxHeight + "px";
}
break;
}
case "popupshown":
// Now that the main view is visible, we can check the height of the
// description elements it contains.
this.descriptionHeightWorkaround();
break;
--- a/browser/components/customizableui/content/panelUI.css
+++ b/browser/components/customizableui/content/panelUI.css
@@ -19,17 +19,9 @@
}
panelmultiview[transitioning] {
pointer-events: none;
}
.panel-viewcontainer.offscreen {
position: absolute;
- top: 100000px;
- left: 100000px;
}
-
-.panel-viewcontainer.offscreen,
-.panel-viewcontainer.offscreen > .panel-viewstack {
- margin: 0;
- padding: 0;
-}