Bug 786803 - GCLI help command panel is too big; r=jwalker
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Thu, 04 Oct 2012 10:32:36 +0100
changeset 109635 003656caed2a481eb7976423e3ea40a516b9b170
parent 109634 b34419698e9690c61da628e316a87bbcfb9c9392
child 109636 f3af7601c307d92a76acaf0b9d61e731d53eaa4b
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjwalker
bugs786803
milestone18.0a1
Bug 786803 - GCLI help command panel is too big; r=jwalker
browser/devtools/shared/DeveloperToolbar.jsm
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const EXPORTED_SYMBOLS = [ "DeveloperToolbar" ];
 
 const NS_XHTML = "http://www.w3.org/1999/xhtml";
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 const WEBCONSOLE_CONTENT_SCRIPT_URL =
   "chrome://browser/content/devtools/HUDService-content.js";
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource:///modules/devtools/Commands.jsm");
 
@@ -633,17 +634,16 @@ function OutputPanel(aChromeDoc, aInput,
     this._panel.setAttribute("height", "1px");
   }
 
   this._toolbar.parentElement.insertBefore(this._panel, this._toolbar);
 
   this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
   this._frame.id = "gcli-output-frame";
   this._frame.setAttribute("src", "chrome://browser/content/devtools/commandlineoutput.xhtml");
-  this._frame.setAttribute("flex", "1");
   this._panel.appendChild(this._frame);
 
   this.displayedOutput = undefined;
 
   this._onload = this._onload.bind(this);
   this._frame.addEventListener("load", this._onload, true);
 
   this.loaded = false;
@@ -670,61 +670,116 @@ OutputPanel.prototype._onload = function
   this.loaded = true;
   if (this._loadCallback) {
     this._loadCallback();
     delete this._loadCallback;
   }
 };
 
 /**
+ * Determine the scrollbar width in the current document.
+ *
+ * @private
+ */
+Object.defineProperty(OutputPanel.prototype, 'scrollbarWidth', {
+  get: function() {
+    if (this.__scrollbarWidth) {
+      return this.__scrollbarWidth;
+    }
+
+    let hbox = this.document.createElementNS(XUL_NS, "hbox");
+    hbox.setAttribute("style", "height: 0%; overflow: hidden");
+
+    let scrollbar = this.document.createElementNS(XUL_NS, "scrollbar");
+    scrollbar.setAttribute("orient", "vertical");
+    hbox.appendChild(scrollbar);
+
+    this.document.documentElement.appendChild(hbox);
+    this.__scrollbarWidth = scrollbar.clientWidth;
+    this.document.documentElement.removeChild(hbox);
+
+    return this.__scrollbarWidth;
+  },
+  enumerable: true
+};
+
+/**
  * Prevent the popup from hiding if it is not permitted via this.canHide.
  */
 OutputPanel.prototype._onpopuphiding = function OP_onpopuphiding(aEvent)
 {
   // TODO: When we switch back from tooltip to panel we can remove this hack:
   // https://bugzilla.mozilla.org/show_bug.cgi?id=780102
   if (isLinux && !this.canHide) {
     aEvent.preventDefault();
   }
 };
 
 /**
  * Display the OutputPanel.
  */
 OutputPanel.prototype.show = function OP_show()
 {
-  // This is nasty, but displaying the panel causes it to re-flow, which can
-  // change the size it should be, so we need to resize the iframe after the
-  // panel has displayed
-  this._panel.ownerDocument.defaultView.setTimeout(function() {
-    this._resize();
-  }.bind(this), 0);
-
   if (isLinux) {
     this.canHide = false;
   }
 
+  // We need to reset the iframe size in order for future size calculations to
+  // be correct
+  this._frame.style.minHeight = this._frame.style.maxHeight = 0;
+  this._frame.style.minWidth = 0;
+
   this._panel.openPopup(this._input, "before_start", 0, 0, false, false, null);
   this._resize();
 
   this._input.focus();
 };
 
 /**
  * Internal helper to set the height of the output panel to fit the available
  * content;
  */
 OutputPanel.prototype._resize = function CLP_resize()
 {
   if (this._panel == null || this.document == null || !this._panel.state == "closed") {
     return
   }
 
-  this._frame.height = this.document.body.scrollHeight;
-  this._frame.width = this._input.clientWidth + 2;
+  // Set max panel width to match any content with a max of the width of the
+  // browser window.
+  let maxWidth = this._panel.ownerDocument.documentElement.clientWidth;
+  let width = Math.min(maxWidth, this.document.documentElement.scrollWidth);
+
+  // Add scrollbar width to content size in case a scrollbar is needed.
+  width += this.scrollbarWidth;
+
+  // Set the width of the iframe.
+  this._frame.style.minWidth = width + "px";
+
+  // browserAdjustment is used to correct the panel height according to the
+  // browsers borders etc.
+  const browserAdjustment = 15;
+
+  // Set max panel height to match any content with a max of the height of the
+  // browser window.
+  let maxHeight =
+    this._panel.ownerDocument.documentElement.clientHeight - browserAdjustment;
+  let height = Math.min(maxHeight, this.document.documentElement.scrollHeight);
+
+  // Set the height of the iframe. Setting iframe.height does not work.
+  this._frame.style.minHeight = this._frame.style.maxHeight = height + "px";
+
+  // Set the height and width of the panel to match the iframe.
+  this._panel.sizeTo(width, height);
+
+  // Move the panel to the correct position in the case that it has been
+  // positioned incorrectly.
+  let screenX = this._input.boxObject.screenX;
+  let screenY = this._toolbar.boxObject.screenY;
+  this._panel.moveTo(screenX, screenY - height);
 };
 
 /**
  * Called by GCLI when a command is executed.
  */
 OutputPanel.prototype._outputChanged = function OP_outputChanged(aEvent)
 {
   if (aEvent.output.hidden) {