diff --git a/browser/components/places/PlacesUIUtils.jsm b/browser/components/places/PlacesUIUtils.jsm
index 8faaa9d53400..07a4126ab844 100644
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -461,21 +461,17 @@ this.PlacesUIUtils = {
showBookmarkDialog:
function PUIU_showBookmarkDialog(aInfo, aParentWindow) {
// Preserve size attributes differently based on the fact the dialog has
- // a folder picker or not. If the picker is visible, the dialog should
- // be resizable since it may not show enough content for the folders
- // hierarchy.
+ // a folder picker or not, since it needs more horizontal space than the
+ // other controls.
let hasFolderPicker = !("hiddenRows" in aInfo) ||
aInfo.hiddenRows.indexOf("folderPicker") == -1;
- // Use a different chrome url, since this allows to persist different sizes,
- // based on resizability of the dialog.
+ // Use a different chrome url to persist different sizes.
let dialogURL = hasFolderPicker ?
"chrome://browser/content/places/bookmarkProperties2.xul" :
"chrome://browser/content/places/bookmarkProperties.xul";
- let features =
- "centerscreen,chrome,modal,resizable=" + (hasFolderPicker ? "yes" : "no");
-
- aParentWindow.openDialog(dialogURL, "", features, aInfo);
+ let features = "centerscreen,chrome,modal,resizable=yes";
+ aParentWindow.openDialog(dialogURL, "", features, aInfo);
return ("performed" in aInfo && aInfo.performed);
},
diff --git a/browser/components/places/content/bookmarkProperties.js b/browser/components/places/content/bookmarkProperties.js
index 940443dd7f47..016a3578fd32 100644
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -72,6 +72,8 @@ const LIVEMARK_CONTAINER = 2;
const ACTION_EDIT = 0;
const ACTION_ADD = 1;
+let elementsHeight = new Map();
+
var BookmarkPropertiesPanel = {
/** UI Text Strings */
@@ -271,6 +273,43 @@ var BookmarkPropertiesPanel = {
var acceptButton = document.documentElement.getButton("accept");
acceptButton.label = this._getAcceptLabel();
+ // Do not use sizeToContent, otherwise, due to bug 90276, the dialog will
+ // grow at every opening.
+ // Since elements can be uncollapsed asynchronously, we must observe their
+ // mutations and resize the dialog using a cached element size.
+ this._height = window.outerHeight;
+ this._mutationObserver = new MutationObserver(mutations => {
+ for (let mutation of mutations) {
+ let target = mutation.target;
+ let id = target.id;
+ if (!/^editBMPanel_.*(Row|Checkbox)$/.test(id))
+ continue;
+
+ let collapsed = target.getAttribute("collapsed") === "true";
+ let wasCollapsed = mutation.oldValue === "true";
+ if (collapsed == wasCollapsed)
+ continue;
+
+ if (collapsed) {
+ this._height -= elementsHeight.get(id);
+ elementsHeight.delete(id);
+ } else {
+ elementsHeight.set(id, target.boxObject.height);
+ this._height += elementsHeight.get(id);
+ }
+ window.resizeTo(window.outerWidth, this._height);
+ }
+ });
+
+ this._mutationObserver.observe(document,
+ { subtree: true,
+ attributeOldValue: true,
+ attributeFilter: ["collapsed"] });
+
+ // Some controls are flexible and we want to update their cached size when
+ // the dialog is resized.
+ window.addEventListener("resize", this);
+
this._beginBatch();
switch (this._action) {
@@ -300,25 +339,6 @@ var BookmarkPropertiesPanel = {
break;
}
- // Adjust the dialog size to the changes done by initPanel. This is necessary because
- // initPanel, which shows and hides elements, may run after some async work was done
- // here - i.e. after the DOM load event was processed.
- window.sizeToContent();
-
- // When collapsible elements change their collapsed attribute we must
- // resize the dialog.
- // sizeToContent is not usable due to bug 90276, so we'll use resizeTo
- // instead and cache the element size. See WSucks in the legacy
- // UI code (addBookmark2.js).
- if (!this._element("tagsRow").collapsed) {
- this._element("tagsSelectorRow")
- .addEventListener("DOMAttrModified", this, false);
- }
- if (!this._element("folderRow").collapsed) {
- this._element("folderTreeRow")
- .addEventListener("DOMAttrModified", this, false);
- }
-
if (!gEditItemOverlay.readOnly) {
// Listen on uri fields to enable accept button if input is valid
if (this._itemType == BOOKMARK_ITEM) {
@@ -330,12 +350,9 @@ var BookmarkPropertiesPanel = {
}
}
}
-
- window.sizeToContent();
}),
// nsIDOMEventListener
- _elementsHeight: [],
handleEvent: function BPP_handleEvent(aEvent) {
var target = aEvent.target;
switch (aEvent.type) {
@@ -347,24 +364,11 @@ var BookmarkPropertiesPanel = {
.getButton("accept").disabled = !this._inputIsValid();
}
break;
-
- case "DOMAttrModified":
- // this is called when collapsing a node, but also its direct children,
- // we only need to resize when the original node changes.
- if ((target.id == "editBMPanel_tagsSelectorRow" ||
- target.id == "editBMPanel_folderTreeRow") &&
- aEvent.attrName == "collapsed" &&
- target == aEvent.originalTarget) {
- var id = target.id;
- var newHeight = window.outerHeight;
- if (aEvent.newValue) // is collapsed
- newHeight -= this._elementsHeight[id];
- else {
- this._elementsHeight[id] = target.boxObject.height;
- newHeight += this._elementsHeight[id];
- }
-
- window.resizeTo(window.outerWidth, newHeight);
+ case "resize":
+ for (let [id, oldHeight] of elementsHeight) {
+ let newHeight = document.getElementById(id).boxObject.height;
+ this._height += - oldHeight + newHeight;
+ elementsHeight.set(id, newHeight);
}
break;
}
@@ -418,12 +422,13 @@ var BookmarkPropertiesPanel = {
onDialogUnload() {
// gEditItemOverlay does not exist anymore here, so don't rely on it.
+ this._mutationObserver.disconnect();
+ delete this._mutationObserver;
+
+ window.removeEventListener("resize", this);
+
// Calling removeEventListener with arguments which do not identify any
// currently registered EventListener on the EventTarget has no effect.
- this._element("tagsSelectorRow")
- .removeEventListener("DOMAttrModified", this, false);
- this._element("folderTreeRow")
- .removeEventListener("DOMAttrModified", this, false);
this._element("locationField")
.removeEventListener("input", this, false);
},
diff --git a/browser/components/places/content/editBookmarkOverlay.xul b/browser/components/places/content/editBookmarkOverlay.xul
index 2f6f8e7bc007..140e752c0484 100644
--- a/browser/components/places/content/editBookmarkOverlay.xul
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -24,7 +24,9 @@
-
+
-
+
-
+
@@ -76,7 +82,9 @@
-
+
-
+
-
+
-
+