merge m-c to fx-team
authorTim Taubert <tim.taubert@gmx.de>
Wed, 11 Jul 2012 08:44:05 +0200
changeset 98903 53860f11100c0be29a53210a6017be9d919f8881
parent 98896 8495e311226f6f5f92473008e561b3b9a4c7537e (current diff)
parent 98902 74218d787b063bd69cbf7da3cbc3f8fdb85e48c1 (diff)
child 98904 d070bd19c526914fa87b99c0783ae085d9570889
child 98953 e6f3c420aaa37a2f445c1322bfd2131d0d57935c
push id23089
push usertim.taubert@gmx.de
push dateWed, 11 Jul 2012 06:44:16 +0000
treeherdermozilla-central@53860f11100c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.0a1
first release with
nightly linux32
53860f11100c / 16.0a1 / 20120711030538 / files
nightly linux64
53860f11100c / 16.0a1 / 20120711030538 / files
nightly mac
53860f11100c / 16.0a1 / 20120711030538 / files
nightly win32
53860f11100c / 16.0a1 / 20120711030538 / files
nightly win64
53860f11100c / 16.0a1 / 20120711030538 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge m-c to fx-team
docshell/base/nsDocShell.cpp
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -514,16 +514,17 @@
                     label="&webDeveloperMenu.label;"
                     accesskey="&webDeveloperMenu.accesskey;">
                 <menupopup id="menuWebDeveloperPopup">
                   <menuitem id="menu_devToolbar"
                             type="checkbox"
                             autocheck="false"
                             hidden="true"
                             label="&devToolbarMenu.label;"
+                            accesskey="&devToolbarMenu.accesskey;"
                             key="key_devToolbar"
                             command="Tools:DevToolbar"/>
                   <menuitem id="webConsole"
                             type="checkbox"
                             label="&webConsoleCmd.label;"
                             accesskey="&webConsoleCmd.accesskey;"
                             key="key_webConsole"
                             command="Tools:WebConsole"/>
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -84,16 +84,17 @@
     <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true"/>
+    <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focus();" disabled="true"/>
     <command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
     <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
     <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
     <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true"/>
     <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
     <command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true"/>
@@ -220,16 +221,18 @@
 #ifdef XP_GNOME
     <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
     <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
 #else
     <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
 #endif
     <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
     <key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
+    <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
+         keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
     <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
 #ifdef XP_MACOSX
         modifiers="accel,alt"
 #else
         modifiers="accel,shift"
 #endif
     />
     <key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1389,16 +1389,17 @@ var gBrowserInit = {
         setUrlAndSearchBarWidthForConditionalForwardButton();
     });
 
     // Enable developer toolbar?
     let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
     if (devToolbarEnabled) {
       document.getElementById("menu_devToolbar").hidden = false;
       document.getElementById("Tools:DevToolbar").removeAttribute("disabled");
+      document.getElementById("Tools:DevToolbarFocus").removeAttribute("disabled");
 #ifdef MENUBAR_CAN_AUTOHIDE
       document.getElementById("appmenu_devToolbar").hidden = false;
 #endif
 
       // Show the toolbar if it was previously visible
       if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
         DeveloperToolbar.show(false);
       }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -143,16 +143,17 @@ endif
                  browser_bug623155.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
                  browser_bug710878.js \
                  browser_bug719271.js \
+                 browser_bug724239.js \
                  browser_bug735471.js \
                  browser_bug743421.js \
                  browser_bug749738.js \
                  browser_bug763468.js \
                  browser_bug767836.js \
                  browser_canonizeURL.js \
                  browser_customize.js \
                  browser_findbarClose.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug724239.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+  BrowserOpenTab();
+
+  let tab = gBrowser.selectedTab;
+  let browser = tab.linkedBrowser;
+
+  registerCleanupFunction(function () { gBrowser.removeTab(tab); });
+
+  whenBrowserLoaded(browser, function () {
+    browser.loadURI("http://example.com/");
+
+    whenBrowserLoaded(browser, function () {
+      ok(!gBrowser.canGoBack, "about:newtab wasn't added to the session history");
+      finish();
+    });
+  });
+}
+
+function whenBrowserLoaded(aBrowser, aCallback) {
+  aBrowser.addEventListener("load", function onLoad() {
+    aBrowser.removeEventListener("load", onLoad, true);
+    executeSoon(aCallback);
+  }, true);
+}
--- a/browser/devtools/commandline/GcliCommands.jsm
+++ b/browser/devtools/commandline/GcliCommands.jsm
@@ -18,23 +18,27 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
                                   "resource:///modules/devtools/LayoutHelpers.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource:///modules/devtools/Console.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                  "resource://gre/modules/AddonManager.jsm");
+
 let prefSvc = "@mozilla.org/preferences-service;1";
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
   let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
   return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
 });
 
 Cu.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
+Cu.import("resource:///modules/devtools/GcliCookieCommands.jsm", {});
 
 /**
  * A place to store the names of the commands that we have added as a result of
  * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
  * added commands.
  */
 let commands = [];
 
@@ -328,16 +332,61 @@ gcli.addCommand({
   description: gcli.lookup("consoleopenDesc"),
   exec: function Command_consoleOpen(args, context) {
     let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
     HUDService.activateHUDForContext(tab);
   }
 });
 
 /**
+ * Restart command
+ *
+ * @param boolean nocache
+ *        Disables loading content from cache upon restart.
+ *
+ * Examples :
+ * >> restart
+ * - restarts browser immediately
+ * >> restart --nocache
+ * - restarts immediately and starts Firefox without using cache
+ */
+gcli.addCommand({
+  name: "restart",
+  description: gcli.lookup("restartFirefoxDesc"),
+  params: [
+    {
+      name: "nocache",
+      type: "boolean",
+      defaultValue: false,
+      description: gcli.lookup("restartFirefoxNocacheDesc")
+    }
+  ],
+  returnType: "string",
+  exec: function Restart(args, context) {
+    let canceled = Cc["@mozilla.org/supports-PRBool;1"]
+                     .createInstance(Ci.nsISupportsPRBool);
+    Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
+    if (canceled.data) {
+      return gcli.lookup("restartFirefoxRequestCancelled");
+    }
+
+    // disable loading content from cache.
+    if (args.nocache) {
+      Services.appinfo.invalidateCachesOnRestart();
+    }
+
+    // restart
+    Cc['@mozilla.org/toolkit/app-startup;1']
+      .getService(Ci.nsIAppStartup)
+      .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+    return gcli.lookup("restartFirefoxRestarting");
+  }
+});
+
+/**
  * 'inspect' command
  */
 gcli.addCommand({
   name: "inspect",
   description: gcli.lookup("inspectDesc"),
   manual: gcli.lookup("inspectManual"),
   params: [
     {
@@ -537,8 +586,620 @@ gcli.addCommand({
       });
     } catch (ex) {
       // If the debugger has been closed already, don't scare the user.
       promise.resolve(gcli.lookup("breakdelRemoved"));
     }
     return promise;
   }
 });
+
+/**
+ * 'export' command
+ */
+gcli.addCommand({
+  name: "export",
+  description: gcli.lookup("exportDesc"),
+});
+
+/**
+ * The 'export html' command. This command allows the user to export the page to
+ * HTML after they do DOM changes.
+ */
+gcli.addCommand({
+  name: "export html",
+  description: gcli.lookup("exportHtmlDesc"),
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let window = document.defaultView;
+    let page = document.documentElement.outerHTML;
+    window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
+  }
+});
+
+/**
+ * 'pagemod' command
+ */
+gcli.addCommand({
+  name: "pagemod",
+  description: gcli.lookup("pagemodDesc"),
+});
+
+/**
+ * The 'pagemod replace' command. This command allows the user to search and
+ * replace within text nodes and attributes.
+ */
+gcli.addCommand({
+  name: "pagemod replace",
+  description: gcli.lookup("pagemodReplaceDesc"),
+  params: [
+    {
+      name: "search",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceSearchDesc"),
+    },
+    {
+      name: "replace",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceReplaceDesc"),
+    },
+    {
+      name: "ignoreCase",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
+    },
+    {
+      name: "selector",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceSelectorDesc"),
+      defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodReplaceRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: "attrOnly",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
+    },
+    {
+      name: "contentOnly",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
+    },
+    {
+      name: "attributes",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceAttributesDesc"),
+      defaultValue: null,
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let searchTextNodes = !args.attrOnly;
+    let searchAttributes = !args.contentOnly;
+    let regexOptions = args.ignoreCase ? 'ig' : 'g';
+    let search = new RegExp(escapeRegex(args.search), regexOptions);
+    let attributeRegex = null;
+    if (args.attributes) {
+      attributeRegex = new RegExp(args.attributes, regexOptions);
+    }
+
+    let root = args.root || document;
+    let elements = root.querySelectorAll(args.selector);
+    elements = Array.prototype.slice.call(elements);
+
+    let replacedTextNodes = 0;
+    let replacedAttributes = 0;
+
+    function replaceAttribute() {
+      replacedAttributes++;
+      return args.replace;
+    }
+    function replaceTextNode() {
+      replacedTextNodes++;
+      return args.replace;
+    }
+
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      if (searchTextNodes) {
+        for (let y = 0; y < element.childNodes.length; y++) {
+          let node = element.childNodes[y];
+          if (node.nodeType == node.TEXT_NODE) {
+            node.textContent = node.textContent.replace(search, replaceTextNode);
+          }
+        }
+      }
+
+      if (searchAttributes) {
+        if (!element.attributes) {
+          continue;
+        }
+        for (let y = 0; y < element.attributes.length; y++) {
+          let attr = element.attributes[y];
+          if (!attributeRegex || attributeRegex.test(attr.name)) {
+            attr.value = attr.value.replace(search, replaceAttribute);
+          }
+        }
+      }
+    }
+
+    return gcli.lookupFormat("pagemodReplaceResult",
+                             [elements.length, replacedTextNodes,
+                              replacedAttributes]);
+  }
+});
+
+/**
+ * 'pagemod remove' command
+ */
+gcli.addCommand({
+  name: "pagemod remove",
+  description: gcli.lookup("pagemodRemoveDesc"),
+});
+
+
+/**
+ * The 'pagemod remove element' command.
+ */
+gcli.addCommand({
+  name: "pagemod remove element",
+  description: gcli.lookup("pagemodRemoveElementDesc"),
+  params: [
+    {
+      name: "search",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveElementSearchDesc"),
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodRemoveElementRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: 'stripOnly',
+      type: 'boolean',
+      description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
+    },
+    {
+      name: 'ifEmptyOnly',
+      type: 'boolean',
+      description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let root = args.root || document;
+    let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
+
+    let removed = 0;
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      let parentNode = element.parentNode;
+      if (!parentNode || !element.removeChild) {
+        continue;
+      }
+      if (args.stripOnly) {
+        while (element.hasChildNodes()) {
+          parentNode.insertBefore(element.childNodes[0], element);
+        }
+      }
+      if (!args.ifEmptyOnly || !element.hasChildNodes()) {
+        element.parentNode.removeChild(element);
+        removed++;
+      }
+    }
+
+    return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
+                             [elements.length, removed]);
+  }
+});
+
+/**
+ * The 'pagemod remove attribute' command.
+ */
+gcli.addCommand({
+  name: "pagemod remove attribute",
+  description: gcli.lookup("pagemodRemoveAttributeDesc"),
+  params: [
+    {
+      name: "searchAttributes",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
+    },
+    {
+      name: "searchElements",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: "ignoreCase",
+      type: "boolean",
+      description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+
+    let root = args.root || document;
+    let regexOptions = args.ignoreCase ? 'ig' : 'g';
+    let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
+    let elements = root.querySelectorAll(args.searchElements);
+    elements = Array.prototype.slice.call(elements);
+
+    let removed = 0;
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      if (!element.attributes) {
+        continue;
+      }
+
+      var attrs = Array.prototype.slice.call(element.attributes);
+      for (let y = 0; y < attrs.length; y++) {
+        let attr = attrs[y];
+        if (attributeRegex.test(attr.name)) {
+          element.removeAttribute(attr.name);
+          removed++;
+        }
+      }
+    }
+
+    return gcli.lookupFormat("pagemodRemoveAttributeResult",
+                             [elements.length, removed]);
+  }
+});
+
+
+/**
+ * Make a given string safe to use  in a regular expression.
+ *
+ * @param string aString
+ *        The string you want to use in a regex.
+ * @return string
+ *         The equivalent of |aString| but safe to use in a regex.
+ */
+function escapeRegex(aString) {
+  return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
+
+/**
+ * 'addon' command.
+ */
+gcli.addCommand({
+  name: "addon",
+  description: gcli.lookup("addonDesc")
+});
+
+/**
+ * 'addon list' command.
+ */
+gcli.addCommand({
+  name: "addon list",
+  description: gcli.lookup("addonListDesc"),
+  params: [{
+    name: 'type',
+    type: {
+      name: 'selection',
+      data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
+    },
+    defaultValue: 'all',
+    description: gcli.lookup("addonListTypeDesc"),
+  }],
+  exec: function(aArgs, context) {
+    function representEnabledAddon(aAddon) {
+      return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
+      getAddonStatus(aAddon) + "]]></li>";
+    }
+
+    function representDisabledAddon(aAddon) {
+      return "<li class=\"gcli-addon-disabled\">" +
+        "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
+        "]]></li>";
+    }
+
+    function getAddonStatus(aAddon) {
+      let operations = [];
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
+        operations.push("PENDING_ENABLE");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
+        operations.push("PENDING_DISABLE");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
+        operations.push("PENDING_UNINSTALL");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
+        operations.push("PENDING_INSTALL");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
+        operations.push("PENDING_UPGRADE");
+      }
+
+      if (operations.length) {
+        return " (" + operations.join(", ") + ")";
+      }
+      return "";
+    }
+
+    /**
+     * Compares two addons by their name. Used in sorting.
+     */
+    function compareAddonNames(aNameA, aNameB) {
+      return String.localeCompare(aNameA.name, aNameB.name);
+    }
+
+    /**
+     * Resolves the promise which is the scope (this) of this function, filling
+     * it with an HTML representation of the passed add-ons.
+     */
+    function list(aType, aAddons) {
+      if (!aAddons.length) {
+        this.resolve(gcli.lookup("addonNoneOfType"));
+      }
+
+      // Separate the enabled add-ons from the disabled ones.
+      let enabledAddons = [];
+      let disabledAddons = [];
+
+      aAddons.forEach(function(aAddon) {
+        if (aAddon.isActive) {
+          enabledAddons.push(aAddon);
+        } else {
+          disabledAddons.push(aAddon);
+        }
+      });
+
+      let header;
+      switch(aType) {
+        case "dictionary":
+          header = gcli.lookup("addonListDictionaryHeading");
+          break;
+        case "extension":
+          header = gcli.lookup("addonListExtensionHeading");
+          break;
+        case "locale":
+          header = gcli.lookup("addonListLocaleHeading");
+          break;
+        case "plugin":
+          header = gcli.lookup("addonListPluginHeading");
+          break;
+        case "theme":
+          header = gcli.lookup("addonListThemeHeading");
+        case "all":
+          header = gcli.lookup("addonListAllHeading");
+          break;
+        default:
+          header = gcli.lookup("addonListUnknownHeading");
+      }
+
+      // Map and sort the add-ons, and create an HTML list.
+      this.resolve(header +
+        "<ol>" +
+        enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
+        disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
+        "</ol>");
+    }
+
+    // Create the promise that will be resolved when the add-on listing has
+    // been finished.
+    let promise = context.createPromise();
+    let types = aArgs.type == "all" ? null : [aArgs.type];
+    AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
+    return promise;
+  }
+});
+
+// We need a list of addon names for the enable and disable commands. Because
+// getting the name list is async we do not add the commands until we have the
+// list.
+AddonManager.getAllAddons(function addonAsync(aAddons) {
+  // We listen for installs to keep our addon list up to date. There is no need
+  // to listen for uninstalls because uninstalled addons are simply disabled
+  // until restart (to enable undo functionality).
+  AddonManager.addAddonListener({
+    onInstalled: function(aAddon) {
+      addonNameCache.push({
+        name: representAddon(aAddon).replace(/\s/g, "_"),
+        value: aAddon.name
+      });
+    },
+    onUninstalled: function(aAddon) {
+      let name = representAddon(aAddon).replace(/\s/g, "_");
+
+      for (let i = 0; i < addonNameCache.length; i++) {
+        if(addonNameCache[i].name == name) {
+          addonNameCache.splice(i, 1);
+          break;
+        }
+      }
+    },
+  });
+
+  /**
+   * Returns a string that represents the passed add-on.
+   */
+  function representAddon(aAddon) {
+    let name = aAddon.name + " " + aAddon.version;
+    return name.trim();
+  }
+
+  let addonNameCache = [];
+
+  // The name parameter, used in "addon enable" and "addon disable."
+  let nameParameter = {
+    name: "name",
+    type: {
+      name: "selection",
+      lookup: addonNameCache
+    },
+    description: gcli.lookup("addonNameDesc")
+  };
+
+  for (let addon of aAddons) {
+    addonNameCache.push({
+      name: representAddon(addon).replace(/\s/g, "_"),
+      value: addon.name
+    });
+  }
+
+  /**
+   * 'addon enable' command.
+   */
+  gcli.addCommand({
+    name: "addon enable",
+    description: gcli.lookup("addonEnableDesc"),
+    params: [nameParameter],
+    exec: function(aArgs, context) {
+      /**
+       * Enables the addon in the passed list which has a name that matches
+       * according to the passed name comparer, and resolves the promise which
+       * is the scope (this) of this function to display the result of this
+       * enable attempt.
+       */
+      function enable(aName, addons) {
+        // Find the add-on.
+        let addon = null;
+        addons.some(function(candidate) {
+          if (candidate.name == aName) {
+            addon = candidate;
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        let name = representAddon(addon);
+
+        if (!addon.userDisabled) {
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonAlreadyEnabled", [name]) + "]]>");
+        } else {
+          addon.userDisabled = false;
+          // nl-nl: {$1} is ingeschakeld.
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonEnabled", [name]) + "]]>");
+        }
+      }
+
+      let promise = context.createPromise();
+      // List the installed add-ons, enable one when done listing.
+      AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
+      return promise;
+    }
+  });
+
+  /**
+   * 'addon disable' command.
+   */
+  gcli.addCommand({
+    name: "addon disable",
+    description: gcli.lookup("addonDisableDesc"),
+    params: [nameParameter],
+    exec: function(aArgs, context) {
+      /**
+       * Like enable, but ... you know ... the exact opposite.
+       */
+      function disable(aName, addons) {
+        // Find the add-on.
+        let addon = null;
+        addons.some(function(candidate) {
+          if (candidate.name == aName) {
+            addon = candidate;
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        let name = representAddon(addon);
+
+        if (addon.userDisabled) {
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonAlreadyDisabled", [name]) + "]]>");
+        } else {
+          addon.userDisabled = true;
+          // nl-nl: {$1} is uitgeschakeld.
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonDisabled", [name]) + "]]>");
+        }
+      }
+
+      let promise = context.createPromise();
+      // List the installed add-ons, disable one when done listing.
+      AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
+      return promise;
+    }
+  });
+  Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
+});
+
+/* Responsive Mode commands */
+(function gcli_cmd_resize_container() {
+  function gcli_cmd_resize(args, context) {
+    let browserDoc = context.environment.chromeDocument;
+    let browserWindow = browserDoc.defaultView;
+    let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+    mgr.handleGcliCommand(browserWindow,
+                          browserWindow.gBrowser.selectedTab,
+                          this.name,
+                          args);
+  }
+
+  gcli.addCommand({
+    name: 'resize',
+    description: gcli.lookup('resizeModeDesc')
+  });
+
+  gcli.addCommand({
+    name: 'resize on',
+    description: gcli.lookup('resizeModeOnDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize off',
+    description: gcli.lookup('resizeModeOffDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize toggle',
+    description: gcli.lookup('resizeModeToggleDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize to',
+    description: gcli.lookup('resizeModeToDesc'),
+    params: [
+      {
+        name: 'width',
+        type: 'number',
+        description: gcli.lookup("resizePageArgWidthDesc"),
+      },
+      {
+        name: 'height',
+        type: 'number',
+        description: gcli.lookup("resizePageArgHeightDesc"),
+      },
+    ],
+    exec: gcli_cmd_resize
+  });
+})();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/GcliCookieCommands.jsm
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+
+let EXPORTED_SYMBOLS = [ ];
+
+Components.utils.import("resource:///modules/devtools/gcli.jsm");
+
+
+// We should really be using nsICookieManager so we can read more than just the
+// key/value of cookies. The difficulty is filtering the cookies that are
+// relevant to the current page. See
+// https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
+// For details on how this is done with Firebug
+
+/**
+ * 'cookie' command
+ */
+gcli.addCommand({
+  name: "cookie",
+  description: gcli.lookup("cookieDesc"),
+  manual: gcli.lookup("cookieManual")
+});
+
+/**
+ * The template for the 'cookie list' command.
+ */
+var cookieListHtml = "" +
+  "<table>" +
+  "  <tr>" +
+  "    <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
+  "    <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
+  "    <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
+  "  </tr>" +
+  "  <tr foreach='cookie in ${cookies}'>" +
+  "    <td>${cookie.key}</td>" +
+  "    <td>${cookie.value}</td>" +
+  "    <td>" +
+  "      <span class='gcli-out-shortcut'" +
+  "          onclick='${onclick}' ondblclick='${ondblclick}'" +
+  "          data-command='cookie set ${cookie.key}'" +
+  "          >" + gcli.lookup("cookieListOutEdit") + "</span>" +
+  "      <span class='gcli-out-shortcut'" +
+  "          onclick='${onclick}' ondblclick='${ondblclick}'" +
+  "          data-command='cookie remove ${cookie.key}'" +
+  "          >" + gcli.lookup("cookieListOutRemove") + "</span>" +
+  "    </td>" +
+  "  </tr>" +
+  "</table>" +
+  "";
+
+/**
+ * 'cookie list' command
+ */
+gcli.addCommand({
+  name: "cookie list",
+  description: gcli.lookup("cookieListDesc"),
+  manual: gcli.lookup("cookieListManual"),
+  returnType: "string",
+  exec: function Command_cookieList(args, context) {
+    // Parse out an array of { key:..., value:... } objects for each cookie
+    var doc = context.environment.contentDocument;
+    var cookies = doc.cookie.split("; ").map(function(cookieStr) {
+      var equalsPos = cookieStr.indexOf("=");
+      return {
+        key: cookieStr.substring(0, equalsPos),
+        value: cookieStr.substring(equalsPos + 1)
+      };
+    });
+
+    return context.createView({
+      html: cookieListHtml,
+      data: {
+        cookies: cookies,
+        onclick: createUpdateHandler(context),
+        ondblclick: createExecuteHandler(context),
+      }
+    });
+  }
+});
+
+/**
+ * 'cookie remove' command
+ */
+gcli.addCommand({
+  name: "cookie remove",
+  description: gcli.lookup("cookieRemoveDesc"),
+  manual: gcli.lookup("cookieRemoveManual"),
+  params: [
+    {
+      name: "key",
+      type: "string",
+      description: gcli.lookup("cookieRemoveKeyDesc"),
+    }
+  ],
+  exec: function Command_cookieRemove(args, context) {
+    let document = context.environment.contentDocument;
+    let expDate = new Date();
+    expDate.setDate(expDate.getDate() - 1);
+    document.cookie = escape(args.key) + "=; expires=" + expDate.toGMTString();
+  }
+});
+
+/**
+ * 'cookie set' command
+ */
+gcli.addCommand({
+  name: "cookie set",
+  description: gcli.lookup("cookieSetDesc"),
+  manual: gcli.lookup("cookieSetManual"),
+  params: [
+    {
+      name: "key",
+      type: "string",
+      description: gcli.lookup("cookieSetKeyDesc")
+    },
+    {
+      name: "value",
+      type: "string",
+      description: gcli.lookup("cookieSetValueDesc")
+    },
+    {
+      group: gcli.lookup("cookieSetOptionsDesc"),
+      params: [
+        {
+          name: "path",
+          type: "string",
+          defaultValue: "/",
+          description: gcli.lookup("cookieSetPathDesc")
+        },
+        {
+          name: "domain",
+          type: "string",
+          defaultValue: null,
+          description: gcli.lookup("cookieSetDomainDesc")
+        },
+        {
+          name: "secure",
+          type: "boolean",
+          description: gcli.lookup("cookieSetSecureDesc")
+        }
+      ]
+    }
+  ],
+  exec: function Command_cookieSet(args, context) {
+    let document = context.environment.contentDocument;
+
+    document.cookie = escape(args.key) + "=" + escape(args.value) +
+            (args.domain ? "; domain=" + args.domain : "") +
+            (args.path ? "; path=" + args.path : "") +
+            (args.secure ? "; secure" : ""); 
+  }
+});
+
+/**
+ * Helper to find the 'data-command' attribute and call some action on it.
+ * @see |updateCommand()| and |executeCommand()|
+ */
+function withCommand(element, action) {
+  var command = element.getAttribute("data-command");
+  if (!command) {
+    command = element.querySelector("*[data-command]")
+            .getAttribute("data-command");
+  }
+
+  if (command) {
+    action(command);
+  }
+  else {
+    console.warn("Missing data-command for " + util.findCssSelector(element));
+  }
+}
+
+/**
+ * Create a handler to update the requisition to contain the text held in the
+ * first matching data-command attribute under the currentTarget of the event.
+ * @param context Either a Requisition or an ExecutionContext or another object
+ * that contains an |update()| function that follows a similar contract.
+ */
+function createUpdateHandler(context) {
+  return function(ev) {
+    withCommand(ev.currentTarget, function(command) {
+      context.update(command);
+    });
+  }
+}
+
+/**
+ * Create a handler to execute the text held in the data-command attribute
+ * under the currentTarget of the event.
+ * @param context Either a Requisition or an ExecutionContext or another object
+ * that contains an |update()| function that follows a similar contract.
+ */
+function createExecuteHandler(context) {
+  return function(ev) {
+    withCommand(ev.currentTarget, function(command) {
+      context.exec({
+        visible: true,
+        typed: command
+      });
+    });
+  }
+}
--- a/browser/devtools/commandline/test/Makefile.in
+++ b/browser/devtools/commandline/test/Makefile.in
@@ -7,29 +7,35 @@ DEPTH     = ../../../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 relativesrcdir  = browser/devtools/commandline/test
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES = \
+  browser_gcli_addon.js \
   browser_gcli_break.js \
   browser_gcli_commands.js \
+  browser_gcli_cookie.js \
   browser_gcli_edit.js \
   browser_gcli_inspect.js \
   browser_gcli_integrate.js \
+  browser_gcli_pagemod_export.js \
   browser_gcli_pref.js \
+  browser_gcli_responsivemode.js \
+  browser_gcli_restart.js \
   browser_gcli_settings.js \
   browser_gcli_web.js \
   head.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
   browser_gcli_break.html \
   browser_gcli_inspect.html \
   resources_inpage.js \
   resources_inpage1.css \
   resources_inpage2.css \
   resources.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_addon.js
@@ -0,0 +1,43 @@
+function test() {
+  DeveloperToolbarTest.test("about:blank", function GAT_test() {
+    function GAT_ready() {
+      Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
+
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list dictionary",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list extension",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list locale",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list plugin",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list theme",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list all",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon disable Test_Plug-in_1.0.0.0",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon enable Test_Plug-in_1.0.0.0",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.exec({ completed: false });
+      finish();
+    }
+    Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_cookie.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the cookie commands works as they should
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
+
+function test() {
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testCookieCommands();
+    finish();
+  });
+}
+
+function testCookieCommands() {
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cook",
+    directTabText: "ie",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie l",
+    directTabText: "ist",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie list",
+    status: "VALID",
+    emptyParameters: [ ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie remove",
+    status: "ERROR",
+    emptyParameters: [ " <key>" ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie set",
+    status: "ERROR",
+    emptyParameters: [ " <key>", " <value>" ],
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "cookie set fruit banana",
+    args: {
+      key: "fruit",
+      value: "banana",
+      path: "/",
+      domain: null,
+      secure: false
+    },
+    blankOutput: true,
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "cookie list",
+    outputMatch: /Key/
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "cookie remove fruit",
+    args: { key: "fruit" },
+    blankOutput: true,
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_pagemod_export.js
@@ -0,0 +1,272 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the inspect command works as it should
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
+
+function test() {
+  let initialHtml = "";
+
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    initialHtml = content.document.documentElement.innerHTML;
+
+    testExportHtml();
+    testPageModReplace();
+    testPageModRemoveElement();
+    testPageModRemoveAttribute();
+    finish();
+  });
+
+  function testExportHtml() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "export html",
+      status: "VALID"
+    });
+
+    let oldOpen = content.open;
+    let openURL = "";
+    content.open = function(aUrl) {
+      openURL = aUrl;
+    };
+
+    DeveloperToolbarTest.exec({ blankOutput: true });
+
+    openURL = decodeURIComponent(openURL);
+
+    isnot(openURL.indexOf('<html lang="en">'), -1, "export html works: <html>");
+    isnot(openURL.indexOf("<title>GCLI"), -1, "export html works: <title>");
+    isnot(openURL.indexOf('<p id="someid">#'), -1, "export html works: <p>");
+
+    content.open = oldOpen;
+  }
+
+  function getContent() {
+    return content.document.documentElement.innerHTML;
+  }
+
+  function resetContent() {
+    content.document.documentElement.innerHTML = initialHtml;
+  }
+
+  function testPageModReplace() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace",
+      emptyParameters: [" <search>", " <replace>", " [ignoreCase]",
+                        " [selector]", " [root]", " [attrOnly]",
+                        " [contentOnly]", " [attributes]"],
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo",
+      emptyParameters: [" [ignoreCase]", " [selector]", " [root]",
+                        " [attrOnly]", " [contentOnly]", " [attributes]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo true",
+      emptyParameters: [" [selector]", " [root]", " [attrOnly]",
+                        " [contentOnly]", " [attributes]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo true --attrOnly",
+      emptyParameters: [" [selector]", " [root]", " [contentOnly]",
+                        " [attributes]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace sOme foOBar",
+      outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "no change in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace sOme foOBar true",
+      outputMatch: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 2\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="foOBarclass">.foOBarclass'), -1,
+          ".someclass changed to .foOBarclass");
+    isnot(getContent().indexOf('<p id="foOBarid">#foOBarid'), -1,
+          "#someid changed to #foOBarid");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --contentOnly",
+      outputMatch: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 0\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="someclass">.foobarclass'), -1,
+          ".someclass changed to .foobarclass (content only)");
+    isnot(getContent().indexOf('<p id="someid">#foobarid'), -1,
+          "#someid changed to #foobarid (content only)");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --attrOnly",
+      outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 2\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="foobarclass">.someclass'), -1,
+          ".someclass changed to .foobarclass (attr only)");
+    isnot(getContent().indexOf('<p id="foobarid">#someid'), -1,
+          "#someid changed to #foobarid (attr only)");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --root head",
+      outputMatch: /^[^:]+: 2\. [^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --selector .someclass,div,span",
+      outputMatch: /^[^:]+: 4\. [^:]+: 1\. [^:]+: 1\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="foobarclass">.foobarclass'), -1,
+          ".someclass changed to .foobarclass");
+    isnot(getContent().indexOf('<p id="someid">#someid'), -1,
+          "#someid did not change");
+
+    resetContent();
+  }
+
+  function testPageModRemoveElement() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove",
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove element",
+      emptyParameters: [" <search>", " [root]", " [stripOnly]", " [ifEmptyOnly]"],
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove element foo",
+      emptyParameters: [" [root]", " [stripOnly]", " [ifEmptyOnly]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p",
+      outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+    });
+
+    is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
+    is(getContent().indexOf('<p id="someid">'), -1, "p#someid removed");
+    is(getContent().indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+    isnot(getContent().indexOf("<span>"), -1, "<span> not removed");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p head",
+      outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p --ifEmptyOnly",
+      outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element meta,title --ifEmptyOnly",
+      outputMatch: /^[^:]+: 2\. [^:]+: 1\.\s*$/
+    });
+
+    is(getContent().indexOf("<meta charset="), -1, "<meta> removed");
+    isnot(getContent().indexOf("<title>"), -1, "<title> not removed");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p --stripOnly",
+      outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+    });
+
+    is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
+    is(getContent().indexOf('<p id="someid">'), -1, "p#someid removed");
+    is(getContent().indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+    isnot(getContent().indexOf(".someclass"), -1, ".someclass still exists");
+    isnot(getContent().indexOf("#someid"), -1, "#someid still exists");
+    isnot(getContent().indexOf("<strong>p"), -1, "<strong> still exists");
+
+    resetContent();
+  }
+
+  function testPageModRemoveAttribute() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove attribute",
+      emptyParameters: [" <searchAttributes>", " <searchElements>", " [root]", " [ignoreCase]"],
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove attribute foo bar",
+      emptyParameters: [" [root]", " [ignoreCase]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute foo bar",
+      outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute foo p",
+      outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute id p,span",
+      outputMatch: /^[^:]+: 5\. [^:]+: 1\.\s*$/
+    });
+
+    is(getContent().indexOf('<p id="someid">#someid'), -1,
+       "p#someid attribute removed");
+    isnot(getContent().indexOf("<p>#someid"), -1,
+       "p with someid content still exists");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute Class p",
+      outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute Class p --ignoreCase",
+      outputMatch: /^[^:]+: 3\. [^:]+: 1\.\s*$/
+    });
+
+    is(getContent().indexOf('<p class="someclass">.someclass'), -1,
+       "p.someclass attribute removed");
+    isnot(getContent().indexOf("<p>.someclass"), -1,
+       "p with someclass content still exists");
+
+    resetContent();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_responsivemode.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  DeveloperToolbarTest.test("about:blank", function GAT_test() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize toggle",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize toggle",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize on",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize off",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize to 400 400",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize off",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    executeSoon(finish);
+  });
+
+  function isOpen() {
+    return !!gBrowser.selectedTab.__responsiveUI;
+  }
+
+  function isClosed() {
+    return !isOpen();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_restart.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that restart command works properly (input wise)
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart";
+
+function test() {
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testRestart();
+    finish();
+  });
+}
+
+function testRestart() {
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart",
+    markup: "VVVVVVV",
+    status: "VALID",
+    emptyParameters: [ " [nocache]" ],
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart ",
+    markup: "VVVVVVVV",
+    status: "VALID",
+    directTabText: "false"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart t",
+    markup: "VVVVVVVVI",
+    status: "ERROR",
+    directTabText: "rue"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart --nocache",
+    markup: "VVVVVVVVVVVVVVVVV",
+    status: "VALID"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart --noca",
+    markup: "VVVVVVVVEEEEEE",
+    status: "ERROR",
+  });
+}
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -29,16 +29,48 @@ let ResponsiveUIManager = {
    */
   toggle: function(aWindow, aTab) {
     if (aTab.__responsiveUI) {
       aTab.__responsiveUI.close();
     } else {
       aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
     }
   },
+
+  /**
+   * Handle gcli commands.
+   *
+   * @param aWindow the browser window.
+   * @param aTab the tab targeted.
+   * @param aCommand the command name.
+   * @param aArgs command arguments.
+   */
+  handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
+    switch (aCommand) {
+      case "resize to":
+        if (!aTab.__responsiveUI) {
+          aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+        }
+        aTab.__responsiveUI.setSize(aArgs.width, aArgs.height);
+        break;
+      case "resize on":
+        if (!aTab.__responsiveUI) {
+          aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+        }
+        break;
+      case "resize off":
+        if (aTab.__responsiveUI) {
+          aTab.__responsiveUI.close();
+        }
+        break;
+      case "resize toggle":
+          this.toggle(aWindow, aTab);
+      default:
+    }
+  },
 }
 
 let presets = [
   // Phones
   {key: "320x480", width: 320, height: 480},    // iPhone, B2G, with <meta viewport>
   {key: "360x640", width: 360, height: 640},    // Android 4, phones, with <meta viewport>
 
   // Tablets
@@ -371,18 +403,18 @@ ResponsiveUI.prototype = {
 
   /**
    * Change the size of the browser.
    *
    * @param aWidth width of the browser.
    * @param aHeight height of the browser.
    */
   setSize: function RUI_setSize(aWidth, aHeight) {
-    this.currentWidth = aWidth;
-    this.currentHeight = aHeight;
+    this.currentWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
+    this.currentHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_WIDTH);
 
     // We resize the containing stack.
     let style = "max-width: %width;" +
                 "min-width: %width;" +
                 "max-height: %height;" +
                 "min-height: %height;";
 
     style = style.replace(/%width/g, this.currentWidth + "px");
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -106,16 +106,29 @@ DeveloperToolbar.prototype.toggle = func
   if (this.visible) {
     this.hide();
   } else {
     this.show(true);
   }
 };
 
 /**
+ * Called from browser.xul in response to menu-click or keyboard shortcut to
+ * toggle the toolbar
+ */
+DeveloperToolbar.prototype.focus = function DT_focus()
+{
+  if (this.visible) {
+    this._input.focus();
+  } else {
+    this.show(true);
+  }
+};
+
+/**
  * Even if the user has not clicked on 'Got it' in the intro, we only show it
  * once per session.
  * Warning this is slightly messed up because this.DeveloperToolbar is not the
  * same as this.DeveloperToolbar when in browser.js context.
  */
 DeveloperToolbar.introShownThisSession = false;
 
 /**
--- a/browser/devtools/webconsole/HUDService-content.js
+++ b/browser/devtools/webconsole/HUDService-content.js
@@ -284,17 +284,18 @@ let Manager = {
         ConsoleListener.init(aMessage);
         break;
       case "NetworkMonitor":
         NetworkMonitor.init(aMessage);
         break;
       case "LocationChange":
         ConsoleProgressListener.startMonitor(ConsoleProgressListener
                                              .MONITOR_LOCATION_CHANGE);
-        ConsoleProgressListener.sendLocation();
+        ConsoleProgressListener.sendLocation(this.window.location.href,
+                                             this.window.document.title);
         break;
       default:
         Cu.reportError("Web Console content: unknown feature " + aFeature);
         break;
     }
 
     this._enabledFeatures.push(aFeature);
   },
@@ -2220,17 +2221,17 @@ let NetworkMonitor = {
     let entry = aHttpActivity.log.entries[0];
     let harTimings = entry.timings;
 
     // Not clear how we can determine "blocked" time.
     harTimings.blocked = -1;
 
     // DNS timing information is available only in when the DNS record is not
     // cached.
-    harTimings.dns = timings.STATUS_RESOLVING ?
+    harTimings.dns = timings.STATUS_RESOLVING && timings.STATUS_RESOLVED ?
                      timings.STATUS_RESOLVED.last -
                      timings.STATUS_RESOLVING.first : -1;
 
     if (timings.STATUS_CONNECTING_TO && timings.STATUS_CONNECTED_TO) {
       harTimings.connect = timings.STATUS_CONNECTED_TO.last -
                            timings.STATUS_CONNECTING_TO.first;
     }
     else if (timings.STATUS_SENDING_TO) {
@@ -2466,44 +2467,56 @@ let ConsoleProgressListener = {
    * Check if the current window.top location is changing, given the arguments
    * of nsIWebProgressListener.onStateChange. If that is the case, the remote
    * Web Console instance is notified.
    * @private
    */
   _checkLocationChange:
   function CPL__checkLocationChange(aProgress, aRequest, aState, aStatus)
   {
+    let isStart = aState & Ci.nsIWebProgressListener.STATE_START;
     let isStop = aState & Ci.nsIWebProgressListener.STATE_STOP;
     let isNetwork = aState & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
     let isWindow = aState & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
 
     // Skip non-interesting states.
-    if (!isStop || !isNetwork || !isWindow ||
+    if (!isNetwork || !isWindow ||
         aProgress.DOMWindow != Manager.window) {
       return;
     }
 
-    this.sendLocation();
+    if (isStart && aRequest instanceof Ci.nsIChannel) {
+      this.sendLocation(aRequest.URI.spec, "");
+    }
+    else if (isStop) {
+      this.sendLocation(Manager.window.location.href,
+                        Manager.window.document.title);
+    }
   },
 
   onLocationChange: function() {},
   onStatusChange: function() {},
   onProgressChange: function() {},
   onSecurityChange: function() {},
 
   /**
    * Send the location of the current top window to the remote Web Console.
    * A "WebConsole:LocationChange" message is sent. The JSON object holds two
    * properties: location and title.
+   *
+   * @param string aLocation
+   *        Current page address.
+   * @param string aTitle
+   *        Current page title.
    */
-  sendLocation: function CPL_sendLocation()
+  sendLocation: function CPL_sendLocation(aLocation, aTitle)
   {
     let message = {
-      "location": Manager.window.location.href,
-      "title": Manager.window.document.title,
+      "location": aLocation,
+      "title": aTitle,
     };
     Manager.sendMessage("WebConsole:LocationChange", message);
   },
 
   /**
    * Destroy the ConsoleProgressListener.
    */
   destroy: function CPL_destroy()
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const CONSOLEAPI_CLASS_ID = "{b49c18f8-3379-4fc0-8c90-d7772c1a9ff3}";
 
+const MIXED_CONTENT_LEARN_MORE = "https://developer.mozilla.org/en/Security/MixedContent";
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 var EXPORTED_SYMBOLS = ["HUDService", "ConsoleUtils"];
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
                                    "@mozilla.org/widget/clipboardhelper;1",
                                    "nsIClipboardHelper");
@@ -2145,28 +2147,36 @@ HeadsUpDisplay.prototype = {
     urlNode.setAttribute("flex", "1");
     urlNode.setAttribute("title", request.url);
     urlNode.setAttribute("value", request.url);
     urlNode.classList.add("hud-clickable");
     urlNode.classList.add("webconsole-msg-body-piece");
     urlNode.classList.add("webconsole-msg-url");
     linkNode.appendChild(urlNode);
 
+    let severity = SEVERITY_LOG;
+    if(this.isMixedContentLoad(request.url, this.contentLocation)) {
+      urlNode.classList.add("webconsole-mixed-content");
+      this.makeMixedContentNode(linkNode);
+      //If we define a SEVERITY_SECURITY in the future, switch this to SEVERITY_SECURITY
+      severity = SEVERITY_WARNING;
+    }
+
     let statusNode = this.chromeDocument.createElementNS(XUL_NS, "label");
     statusNode.setAttribute("value", "");
     statusNode.classList.add("hud-clickable");
     statusNode.classList.add("webconsole-msg-body-piece");
     statusNode.classList.add("webconsole-msg-status");
     linkNode.appendChild(statusNode);
 
     let clipboardText = request.method + " " + request.url;
 
     let messageNode = ConsoleUtils.createMessageNode(this.chromeDocument,
                                                      CATEGORY_NETWORK,
-                                                     SEVERITY_LOG,
+                                                     severity,
                                                      msgNode,
                                                      this.hudId,
                                                      null,
                                                      null,
                                                      clipboardText);
 
     messageNode._connectionId = entry.connection;
 
@@ -2946,16 +2956,63 @@ HeadsUpDisplay.prototype = {
     this.positionMenuitems.below.removeEventListener("command",
       this._positionConsoleBelow, false);
     this.positionMenuitems.window.removeEventListener("command",
       this._positionConsoleWindow, false);
 
     this.closeButton.removeEventListener("command",
       this.closeButtonOnCommand, false);
   },
+
+  /**
+   * Determine whether the request should display a Mixed Content warning
+   *
+   * @param string request
+   *        location of the requested content
+   * @param string contentLocation
+   *        location of the current page
+   * @return bool
+   *         True if the content is mixed, false if not
+   */
+  isMixedContentLoad: function HUD_isMixedContentLoad(request, contentLocation) {
+    try {
+      let requestURIObject = Services.io.newURI(request, null, null);
+      let contentWindowURI = Services.io.newURI(contentLocation, null, null);
+      return (contentWindowURI.scheme == "https" && requestURIObject.scheme != "https");
+    } catch(e) {
+      return false;
+    }
+  },
+
+  /**
+   * Create a mixedContentWarningNode and add it the webconsole output.
+   *
+   * @param linkNode
+   *        parent to the requested urlNode
+   */
+  makeMixedContentNode: function HUD_makeMixedContentNode(linkNode) {
+    let mixedContentWarning = "[" + l10n.getStr("webConsoleMixedContentWarning") + "]";
+
+    //mixedContentWarning message links to a Learn More page
+    let mixedContentWarningNode = this.chromeDocument.createElement("label");
+    mixedContentWarningNode.setAttribute("value", mixedContentWarning);
+    mixedContentWarningNode.setAttribute("title", mixedContentWarning);
+
+    //UI for mixed content warning.
+    mixedContentWarningNode.classList.add("hud-clickable");
+    mixedContentWarningNode.classList.add("webconsole-mixed-content-link");
+
+    linkNode.appendChild(mixedContentWarningNode);
+
+    mixedContentWarningNode.addEventListener("click", function(aEvent) {
+      this.chromeWindow.openUILinkIn(MIXED_CONTENT_LEARN_MORE, "tab");
+      aEvent.preventDefault();
+      aEvent.stopPropagation();
+    }.bind(this));
+  },
 };
 
 /**
  * Creates a DOM Node factory for XUL nodes - as well as textNodes
  * @param aFactoryType "xul" or "text"
  * @param ignored This parameter is currently ignored, and will be removed
  * See bug 594304
  * @param aDocument The document, the factory is to generate nodes from
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -241,28 +241,31 @@ var WebConsoleUtils = {
       case "regexp":
         output = aResult.toString();
         break;
       case "null":
       case "undefined":
         output = type;
         break;
       default:
-        if (aResult.toSource) {
-          try {
+        try {
+          if (aResult.toSource) {
             output = aResult.toSource();
-          } catch (ex) { }
+          }
+          if (!output || output == "({})") {
+            output = aResult + "";
+          }
         }
-        if (!output || output == "({})") {
-          output = aResult.toString();
+        catch (ex) {
+          output = ex;
         }
         break;
     }
 
-    return output;
+    return output + "";
   },
 
   /**
    * Format a string for output.
    *
    * @param string aString
    *        The string you want to display.
    * @return string
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -104,16 +104,18 @@ MOCHITEST_BROWSER_FILES = \
 	browser_webconsole_bug_664131_console_group.js \
 	browser_webconsole_bug_704295.js \
 	browser_webconsole_bug_658368_time_methods.js \
 	browser_webconsole_bug_622303_persistent_filters.js \
 	browser_webconsole_window_zombie.js \
 	browser_cached_messages.js \
 	browser_bug664688_sandbox_update_after_navigation.js \
 	browser_webconsole_menustatus.js \
+	browser_result_format_as_string.js \
+	browser_webconsole_bug_737873_mixedcontent.js \
 	head.js \
 	$(NULL)
 
 MOCHITEST_BROWSER_FILES += \
 	test-console.html \
 	test-network.html \
 	test-network-request.html \
 	test-mutation.html \
@@ -176,11 +178,13 @@ MOCHITEST_BROWSER_FILES += \
 	test-bug-585956-console-trace.html \
 	test-bug-644419-log-limits.html \
 	test-bug-632275-getters.html \
 	test-bug-646025-console-file-location.html \
 	test-file-location.js \
 	test-bug-658368-time-methods.html \
 	test-webconsole-error-observer.html \
 	test-for-of.html \
+	test-result-format-as-string.html \
+	test-bug-737873-mixedcontent.html \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_result_format_as_string.js
@@ -0,0 +1,49 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Make sure that JS eval result are properly formatted as strings.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-result-format-as-string.html";
+
+function test()
+{
+  waitForExplicitFinish();
+
+  addTab(TEST_URI);
+
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+    openConsole(null, performTest);
+  }, true);
+}
+
+function performTest(hud)
+{
+  hud.jsterm.clearOutput(true);
+
+  hud.jsterm.execute("document.querySelector('p')");
+  waitForSuccess({
+    name: "eval result shown",
+    validatorFn: function()
+    {
+      return hud.outputNode.querySelector(".webconsole-msg-output");
+    },
+    successFn: function()
+    {
+      is(hud.outputNode.textContent.indexOf("bug772506_content"), -1,
+            "no content element found");
+      ok(!hud.outputNode.querySelector("div"), "no div element found");
+
+      let msg = hud.outputNode.querySelector(".webconsole-msg-output");
+      ok(msg, "eval output node found");
+      isnot(msg.textContent.indexOf("HTMLDivElement"), -1,
+            "HTMLDivElement string found");
+      EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"});
+      ok(!gBrowser._bug772506, "no content variable");
+
+      finishTest();
+    },
+    failureFn: finishTest,
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
@@ -0,0 +1,80 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ *  Tanvi Vyas <tanvi@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console Mixed Content messages are displayed
+
+const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html";
+
+function test() {
+  addTab("data:text/html,Web Console basic network logging test");
+  browser.addEventListener("load", onLoad, true);
+}
+
+function onLoad(aEvent) {
+  browser.removeEventListener("load", onLoad, true);
+  openConsole(null, testMixedContent);
+}
+
+function testMixedContent(hud) {
+  content.location = TEST_HTTPS_URI;
+  var aOutputNode = hud.outputNode;
+
+  waitForSuccess(
+    {
+      name: "mixed content warning displayed successfully",
+      validatorFn: function() {
+        return ( aOutputNode.querySelector(".webconsole-mixed-content") );
+      },
+
+      successFn: function() {
+
+        //tests on the urlnode
+        let node = aOutputNode.querySelector(".webconsole-mixed-content");
+        ok(testSeverity(node), "Severity type is SEVERITY_WARNING.");
+
+        //tests on the warningNode
+        let warningNode = aOutputNode.querySelector(".webconsole-mixed-content-link");
+        is(warningNode.value, "[Mixed Content]", "Message text is accurate." );
+        testClickOpenNewTab(warningNode);
+
+        finishTest();
+      },
+
+      failureFn: finishTest,
+    }
+  );
+
+}
+
+function testSeverity(node) {
+  let linkNode = node.parentNode;
+  let msgNode = linkNode.parentNode;
+  let bodyNode = msgNode.parentNode;
+  let finalNode = bodyNode.parentNode;
+
+  return finalNode.classList.contains("webconsole-msg-warn");
+}
+
+function testClickOpenNewTab(warningNode) {
+  /* Invoke the click event and check if a new tab would open to the correct page */
+  let linkOpened = false;
+  let oldOpenUILinkIn = window.openUILinkIn;
+
+  window.openUILinkIn = function(aLink) {
+   if (aLink == "https://developer.mozilla.org/en/Security/MixedContent");
+     linkOpened = true;
+  }
+
+  EventUtils.synthesizeMouse(warningNode, 2, 2, {});
+
+  ok(linkOpened, "Clicking the Mixed Content Warning node opens the desired page");
+
+  window.openUILinkIn = oldOpenUILinkIn;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+    <title>Mixed Content test - http on https</title>
+    <script src="testscript.js"></script>
+    <!--
+       - Any copyright is dedicated to the Public Domain.
+       - http://creativecommons.org/publicdomain/zero/1.0/
+       -->
+  </head>
+  <body>
+    <iframe src = "http://example.com"></iframe>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-result-format-as-string.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>Web Console test: jsterm eval format as a string</title>
+    <!-- Any copyright is dedicated to the Public Domain.
+         http://creativecommons.org/publicdomain/zero/1.0/ -->
+  </head>
+  <body>
+    <p>Make sure js eval results are formatted as strings.</p>
+    <script>
+      document.querySelector("p").toSource = function() {
+        var element = document.createElement("div");
+        element.textContent = "bug772506_content";
+        element.setAttribute("onmousemove",
+          "(function () {" +
+          "  gBrowser._bug772506 = 'foobar';" +
+          "})();"
+        );
+        return element;
+      };
+    </script>
+  </body>
+</html>
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -232,16 +232,19 @@ These should match what Safari and other
 <!ENTITY scratchpad.accesskey         "s">
 <!ENTITY scratchpad.keycode           "VK_F4">
 <!ENTITY scratchpad.keytext           "F4">
 
 <!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
 
 <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
 <!ENTITY devToolbarMenu.label              "Developer Toolbar">
+<!ENTITY devToolbarMenu.accesskey          "v">
+<!ENTITY devToolbar.keycode                "VK_F2">
+<!ENTITY devToolbar.keytext                "F2">
 
 <!ENTITY webConsoleButton.label "Web Console">
 <!ENTITY inspectorButton.label "Inspector">
 
 <!ENTITY inspectorHTMLCopyInner.label       "Copy Inner HTML">
 <!ENTITY inspectorHTMLCopyInner.accesskey   "I">
 
 <!ENTITY inspectorHTMLCopyOuter.label       "Copy Outer HTML">
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -75,16 +75,34 @@ screenshotDelayManual=The time to wait (
 # a dialog when the user is using this command.
 screenshotFullPageDesc=Entire webpage? (true/false)
 
 # LOCALIZATION NOTE (screenshotFullscreenManual) A fuller description of the
 # 'fullscreen' parameter to the 'screenshot' command, displayed when the user
 # asks for help on what it does.
 screenshotFullPageManual=True if the screenshot should also include parts of the webpage which are outside the current scrolled bounds.
 
+# LOCALIZATION NOTE (restartFirefoxDesc) A very short description of the
+# 'restart' command. This string is designed to be shown in a menu alongside the
+# command name, which is why it should be as short as possible.
+restartFirefoxDesc=Restart Firefox
+
+# LOCALIZATION NOTE (restartFirefoxNocacheDesc) A very short string to
+# describe the 'nocache' parameter to the 'restart' command, which is
+# displayed in a dialog when the user is using this command.
+restartFirefoxNocacheDesc=Disables loading content from cache upon restart
+
+# LOCALIZATION NOTE (restartFirefoxRequestCancelled) A string dispalyed to the
+# user when a scheduled restart has been aborted by the user.
+restartFirefoxRequestCancelled=Restart request cancelled by user.
+
+# LOCALIZATION NOTE (restartFirefoxRestarting) A string dispalyed to the
+# user when a restart has been initiated without a delay.
+restartFirefoxRestarting=Restarting Firefox...
+
 # LOCALIZATION NOTE (inspectDesc) A very short description of the 'inspect'
 # command. See inspectManual for a fuller description of what it does. This
 # string is designed to be shown in a menu alongside the command name, which
 # is why it should be as short as possible.
 inspectDesc=Inspect a node
 
 # LOCALIZATION NOTE (inspectManual) A fuller description of the 'inspect'
 # command, displayed when the user asks for help on what it does.
@@ -328,17 +346,348 @@ editManual2=Edit one of the resources th
 # when the user is using this command.
 editResourceDesc=URL to edit
 
 # LOCALIZATION NOTE (editLineToJumpToDesc) A very short string to describe the
 # 'line' parameter to the 'edit' command, which is displayed in a dialog
 # when the user is using this command.
 editLineToJumpToDesc=Line to jump to
 
+# LOCALIZATION NOTE (resizePageDesc) A very short string to describe the
+# 'resizepage' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizePageDesc=Resize the page
+
+# LOCALIZATION NOTE (resizePageArgWidthDesc) A very short string to describe the
+# 'width' parameter to the 'resizepage' command, which is displayed in a dialog
+# when the user is using this command.
+resizePageArgWidthDesc=Width in pixels
+
+# LOCALIZATION NOTE (resizePageArgWidthDesc) A very short string to describe the
+# 'height' parameter to the 'resizepage' command, which is displayed in a dialog
+# when the user is using this command.
+resizePageArgHeightDesc=Height in pixels
+
+# LOCALIZATION NOTE (resizeModeOnDesc) A very short string to describe the
+# 'resizeon ' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeOnDesc=Enter Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeOffDesc) A very short string to describe the
+# 'resize off' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeOffDesc=Exit Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeToggleDesc) A very short string to describe the
+# 'resize toggle' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeToggleDesc=Toggle Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeToDesc) A very short string to describe the
+# 'resize to' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeToDesc=Alter page size
+
+# LOCALIZATION NOTE (resizeModeDesc) A very short string to describe the
+# 'resize' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeDesc=Control Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeManual) A fuller description of the 'resize'
+# command, displayed when the user asks for help on what it does.
+resizeModeManual=Responsive websites respond to their environment, so they look good on a mobile display, a cinema display and everything in-between. Responsive Design Mode allows you to easily test a variety of page sizes in Firefox without needing to resize your whole browser.
+
 # LOCALIZATION NOTE (cmdDesc) A very short description of the 'cmd'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 cmdDesc=Manipulate the commands
 
 # LOCALIZATION NOTE (cmdRefreshDesc) A very short description of the 'cmd refresh'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 cmdRefreshDesc=Re-read mozcmd directory
+
+# LOCALIZATION NOTE (addonDesc) A very short description of the 'addon'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+addonDesc=Manipulate add-ons
+
+# LOCALIZATION NOTE (addonListDesc) A very short description of the 'addon list'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+addonListDesc=List installed add-ons
+
+# LOCALIZATION NOTE (addonListTypeDesc) A very short description of the
+# 'addon list <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonListTypeDesc=Select an addon type
+
+# LOCALIZATION NOTE (addonListDictionaryHeading, addonListExtensionHeading,
+# addonListLocaleHeading, addonListPluginHeading, addonListThemeHeading,
+# addonListUnknownHeading) Used in the output of the 'addon list' command as the
+# first line of output.
+addonListDictionaryHeading=The following dictionaries are currently installed:
+addonListExtensionHeading=The following extensions are currently installed:
+addonListLocaleHeading=The following locales are currently installed:
+addonListPluginHeading=The following plugins are currently installed:
+addonListThemeHeading=The following themes are currently installed:
+addonListAllHeading=The following addons are currently installed:
+addonListUnknownHeading=The following addons of the selected type are currently installed:
+
+# LOCALIZATION NOTE (addonNameDesc) A very short description of the
+# name parameter of numerous addon commands. This string is designed to be shown
+# in a menu alongside the command name, which is why it should be as short as
+# possible.
+addonNameDesc=The name of the add-on
+
+# LOCALIZATION NOTE (addonNoneOfType) Used in the output of the 'addon list'
+# command when a search for addons of a particular type were not found.
+addonNoneOfType=There are no addons of that type installed.
+
+# LOCALIZATION NOTE (addonEnableDesc) A very short description of the
+# 'addon enable <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonEnableDesc=Enable the specified add-on
+
+# LOCALIZATION NOTE (addonAlreadyEnabled) Used in the output of the
+# 'addon enable' command when an attempt is made to enable an addon is already
+# enabled.
+addonAlreadyEnabled=%S is already enabled.
+
+# LOCALIZATION NOTE (addonEnabled) Used in the output of the 'addon enable'
+# command when an addon is enabled.
+addonEnabled=%S enabled.
+
+# LOCALIZATION NOTE (addonDisableDesc) A very short description of the
+# 'addon disable <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonDisableDesc=Disable the specified add-on
+
+# LOCALIZATION NOTE (addonAlreadyDisabled) Used in the output of the
+# 'addon disable' command when an attempt is made to disable an addon is already
+# disabled.
+addonAlreadyDisabled=%S is already disabled.
+
+# LOCALIZATION NOTE (addonDisabled) Used in the output of the 'addon disable'
+# command when an addon is disabled.
+addonDisabled=%S disabled.
+
+# LOCALIZATION NOTE (exportDesc) A very short description of the 'export'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+exportDesc=Export resources
+
+# LOCALIZATION NOTE (exportHtmlDesc) A very short description of the 'export
+# html' command. This string is designed to be shown in a menu alongside the
+# command name, which is why it should be as short as possible.
+exportHtmlDesc=Export HTML from page
+
+# LOCALIZATION NOTE (pagemodDesc) A very short description of the 'pagemod'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+pagemodDesc=Make page changes
+
+# LOCALIZATION NOTE (pagemodReplaceDesc) A very short description of the
+# 'pagemod replace' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+pagemodReplaceDesc=Search and replace in page elements
+
+# LOCALIZATION NOTE (pagemodReplaceSearchDesc) A very short string to describe
+# the 'search' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceSearchDesc=What to search for
+
+# LOCALIZATION NOTE (pagemodReplaceReplaceDesc) A very short string to describe
+# the 'replace' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceReplaceDesc=Replacement string
+
+# LOCALIZATION NOTE (pagemodReplaceIgnoreCaseDesc) A very short string to
+# describe the 'ignoreCase' parameter to the 'pagemod replace' command, which is
+# displayed in a dialog when the user is using this command.
+pagemodReplaceIgnoreCaseDesc=Perform case-insensitive search
+
+# LOCALIZATION NOTE (pagemodReplaceRootDesc) A very short string to describe the
+# 'root' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceRootDesc=CSS selector to root of search
+
+# LOCALIZATION NOTE (pagemodReplaceSelectorDesc) A very short string to describe
+# the 'selector' parameter to the 'pagemod replace' command, which is displayed
+# in a dialog when the user is using this command.
+pagemodReplaceSelectorDesc=CSS selector to match in search
+
+# LOCALIZATION NOTE (pagemodReplaceAttributesDesc) A very short string to
+# describe the 'attributes' parameter to the 'pagemod replace' command, which is
+# displayed in a dialog when the user is using this command.
+pagemodReplaceAttributesDesc=Attribute match regexp
+
+# LOCALIZATION NOTE (pagemodReplaceAttrOnlyDesc) A very short string to describe
+# the 'attrOnly' parameter to the 'pagemod replace' command, which is displayed
+# in a dialog when the user is using this command.
+pagemodReplaceAttrOnlyDesc=Restrict search to attributes
+
+# LOCALIZATION NOTE (pagemodReplaceContentOnlyDesc) A very short string to
+# describe the 'contentOnly' parameter to the 'pagemod replace' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodReplaceContentOnlyDesc=Restrict search to text nodes
+
+# LOCALIZATION NOTE (pagemodReplaceResultMatchedElements) A string displayed as
+# the result of the 'pagemod replace' command.
+pagemodReplaceResult=Elements matched by selector: %1$S. Replaces in text nodes: %2$S. Replaces in attributes: %3$S.
+
+# LOCALIZATION NOTE (pagemodRemoveDesc) A very short description of the
+# 'pagemod remove' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+pagemodRemoveDesc=Remove elements and attributes from page
+
+# LOCALIZATION NOTE (pagemodRemoveElementDesc) A very short description of the
+# 'pagemod remove element' command. This string is designed to be shown in
+# a menu alongside the command name, which is why it should be as short as
+# possible.
+pagemodRemoveElementDesc=Remove elements from page
+
+# LOCALIZATION NOTE (pagemodRemoveElementSearchDesc) A very short string to
+# describe the 'search' parameter to the 'pagemod remove element' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveElementSearchDesc=CSS selector specifying elements to remove
+
+# LOCALIZATION NOTE (pagemodRemoveElementRootDesc) A very short string to
+# describe the 'root' parameter to the 'pagemod remove element' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveElementRootDesc=CSS selector specifying root of search
+
+# LOCALIZATION NOTE (pagemodRemoveElementStripOnlyDesc) A very short string to
+# describe the 'stripOnly' parameter to the 'pagemod remove element' command,
+# which is displayed in a dialog when the user is using this command.
+pagemodRemoveElementStripOnlyDesc=Remove element, but leave content
+
+# LOCALIZATION NOTE (pagemodRemoveElementIfEmptyOnlyDesc) A very short string to
+# describe the 'ifEmptyOnly' parameter to the 'pagemod remove element' command,
+# which is displayed in a dialog when the user is using this command.
+pagemodRemoveElementIfEmptyOnlyDesc=Remove only empty elements
+
+# LOCALIZATION NOTE (pagemodRemoveElementResultMatchedAndRemovedElements)
+# A string displayed as the result of the 'pagemod remove element' command.
+pagemodRemoveElementResultMatchedAndRemovedElements=Elements matched by selector: %1$S. Elements removed: %2$S.
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeDesc) A very short description of the
+# 'pagemod remove attribute' command. This string is designed to be shown in
+# a menu alongside the command name, which is why it should be as short as
+# possible.
+pagemodRemoveAttributeDesc=Remove matching atributes
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeSearchAttributesDesc) A very short
+# string to describe the 'searchAttributes' parameter to the 'pagemod remove
+# attribute' command, which is displayed in a dialog when the user is using this
+# command.
+pagemodRemoveAttributeSearchAttributesDesc=Regexp specifying attributes to remove
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeSearchElementsDesc) A very short
+# string to describe the 'searchElements' parameter to the 'pagemod remove
+# attribute' command, which is displayed in a dialog when the user is using this
+# command.
+pagemodRemoveAttributeSearchElementsDesc=CSS selector of elements to include
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeRootDesc) A very short string to
+# describe the 'root' parameter to the 'pagemod remove attribute' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveAttributeRootDesc=CSS selector of root of search
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeIgnoreCaseDesc) A very short string
+# to describe the 'ignoreCase' parameter to the 'pagemod remove attribute'
+# command, which is displayed in a dialog when the user is using this command.
+pagemodRemoveAttributeIgnoreCaseDesc=Perform case-insensitive search
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeResult) A string displayed as the
+# result of the 'pagemod remove attribute' command.
+pagemodRemoveAttributeResult=Elements matched by selector: %1$S. Attributes removed: %2$S.
+
+# LOCALIZATION NOTE (cookieDesc) A very short description of the 'cookie'
+# command. See cookieManual for a fuller description of what it does. This
+# string is designed to be shown in a menu alongside the command name, which
+# is why it should be as short as possible.
+cookieDesc=Display and alter cookies
+
+# LOCALIZATION NOTE (cookieManual) A fuller description of the 'cookie'
+# command, displayed when the user asks for help on what it does.
+cookieManual=Commands to list, create, delete and alter cookies for the current domain.
+
+# LOCALIZATION NOTE (cookieListDesc) A very short description of the
+# 'cookie list' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieListDesc=Display cookies
+
+# LOCALIZATION NOTE (cookieListManual) A fuller description of the 'cookie list'
+# command, displayed when the user asks for help on what it does.
+cookieListManual=Display a list of the cookies relevant to the current page.
+
+# LOCALIZATION NOTE (cookieListOutKey) A heading used in the output from the
+# 'cookie list' command above a list of cookie keys
+cookieListOutKey=Key
+
+# LOCALIZATION NOTE (cookieListOutValue) A heading used in the output from the
+# 'cookie list' command above a list of cookie values
+cookieListOutValue=Value
+
+# LOCALIZATION NOTE (cookieListOutActions) A heading used in the output from the
+# 'cookie list' command above a list of actions to take on cookies
+cookieListOutActions=Actions
+
+# LOCALIZATION NOTE (cookieListOutEdit) A title used in the output from the
+# 'cookie list' command on a button which can be used to edit cookie values
+cookieListOutEdit=Edit
+
+# LOCALIZATION NOTE (cookieListOutRemove) A title used in the output from the
+# 'cookie list' command on a button which can be used to remove cookies
+cookieListOutRemove=Remove
+
+# LOCALIZATION NOTE (cookieRemoveDesc) A very short description of the
+# 'cookie remove' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieRemoveDesc=Remove a cookie
+
+# LOCALIZATION NOTE (cookieRemoveManual) A fuller description of the 'cookie remove'
+# command, displayed when the user asks for help on what it does.
+cookieRemoveManual=Remove a cookie, given its key
+
+# LOCALIZATION NOTE (cookieRemoveKeyDesc) A very short string to describe the
+# 'key' parameter to the 'cookie remove' command, which is displayed in a dialog
+# when the user is using this command.
+cookieRemoveKeyDesc=The key of the cookie to remove
+
+# LOCALIZATION NOTE (cookieSetDesc) A very short description of the
+# 'cookie set' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieSetDesc=Set a cookie
+
+# LOCALIZATION NOTE (cookieSetManual) A fuller description of the 'cookie set'
+# command, displayed when the user asks for help on what it does.
+cookieSetManual=Set a cookie by specifying a key name, it's value and optionally one or more of the following attributes: expires (max-age in seconds or the expires date in GMTString format), path, domain, secure
+
+# LOCALIZATION NOTE (cookieSetKeyDesc) A very short string to describe the
+# 'key' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetKeyDesc=The key of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetValueDesc) A very short string to describe the
+# 'value' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetValueDesc=The value of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetOptionsDesc) The title of a set of options to
+# the 'cookie set' command, displayed as a heading to the list of option.
+cookieSetOptionsDesc=Options
+
+# LOCALIZATION NOTE (cookieSetPathDesc) A very short string to describe the
+# 'path' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetPathDesc=The path of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetDomainDesc) A very short string to describe the
+# 'domain' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetDomainDesc=The domain of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetSecureDesc) A very short string to describe the
+# 'secure' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetSecureDesc=Only transmitted over https
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -145,16 +145,21 @@ webConsolePositionBelow=Below
 webConsolePositionWindow=Window
 
 # LOCALIZATION NOTE (webConsoleWindowTitleAndURL): The Web Console floating
 # panel title, followed by the web page URL.
 # For RTL languages you need to set the LRM in the string to give the URL
 # the correct direction.
 webConsoleWindowTitleAndURL=Web Console - %S
 
+# LOCALIZATION NOTE (webConsoleMixedContentWarning): Message displayed after a
+# URL in the Web Console that has been flagged for Mixed Content (i.e. http
+# content in an https page)
+webConsoleMixedContentWarning=Mixed Content
+
 # LOCALIZATION NOTE (scratchpad.linkText):
 # The text used in the right hand side of the web console command line when
 # Javascript is being entered, to indicate how to jump into scratchpad mode
 scratchpad.linkText=Shift+RETURN - Open in Scratchpad
 
 # LOCALIZATION NOTE (gcliterm.instanceLabel): The console displays
 # objects using their type (from the constructor function) in this descriptive
 # string
--- a/browser/themes/gnomestripe/devtools/gcli.css
+++ b/browser/themes/gnomestripe/devtools/gcli.css
@@ -124,8 +124,13 @@
   color: hsl(25,78%,50%);
 }
 
 .gcli-menu-more {
   font-size: 80%;
   text-align: right;
   -moz-padding-end: 8px;
 }
+
+.gcli-addon-disabled {
+  opacity: 0.6;
+  text-decoration: line-through;
+}
--- a/browser/themes/gnomestripe/devtools/webconsole.css
+++ b/browser/themes/gnomestripe/devtools/webconsole.css
@@ -89,16 +89,25 @@
   margin-top: 0;
   margin-bottom: 0;
   -moz-margin-start: 0;
   -moz-margin-end: 6px;
   width: 10em;
   text-align: end;
 }
 
+.webconsole-mixed-content {
+  color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+  color: #0000EE;
+  margin: 0;
+}
+
 .hud-msg-node[selected="true"] > .webconsole-timestamp,
 .hud-msg-node[selected="true"] > .webconsole-location {
   color: inherit;
 }
 
 .jsterm-input-node,
 .jsterm-complete-node {
   font: 12px "DejaVu Sans Mono", monospace;
--- a/browser/themes/pinstripe/devtools/gcli.css
+++ b/browser/themes/pinstripe/devtools/gcli.css
@@ -126,8 +126,13 @@
   color: hsl(25,78%,50%);
 }
 
 .gcli-menu-more {
   font-size: 80%;
   text-align: right;
   -moz-padding-end: 8px;
 }
+
+.gcli-addon-disabled {
+  opacity: 0.6;
+  text-decoration: line-through;
+}
--- a/browser/themes/pinstripe/devtools/webconsole.css
+++ b/browser/themes/pinstripe/devtools/webconsole.css
@@ -249,16 +249,25 @@
 .webconsole-msg-console.webconsole-msg-warn {
   -moz-image-region: rect(24px, 24px, 32px, 16px);
 }
 
 .webconsole-msg-console.webconsole-msg-info {
   -moz-image-region: rect(24px, 32px, 32px, 24px);
 }
 
+.webconsole-mixed-content {
+  color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+  color: #0000EE;
+  margin: 0;
+}
+
 /* Input and output styles */
 .webconsole-msg-input > .webconsole-msg-icon-container,
 .webconsole-msg-output > .webconsole-msg-icon-container {
   border-left: solid #808080 6px;
 }
 
 .webconsole-msg-input {
   -moz-image-region: rect(24px, 40px, 32px, 32px);
--- a/browser/themes/winstripe/devtools/gcli.css
+++ b/browser/themes/winstripe/devtools/gcli.css
@@ -124,8 +124,13 @@
   color: hsl(25,78%,50%);
 }
 
 .gcli-menu-more {
   font-size: 80%;
   text-align: right;
   -moz-padding-end: 8px;
 }
+
+.gcli-addon-disabled {
+  opacity: 0.6;
+  text-decoration: line-through;
+}
--- a/browser/themes/winstripe/devtools/webconsole.css
+++ b/browser/themes/winstripe/devtools/webconsole.css
@@ -200,16 +200,25 @@
 .webconsole-msg-console.webconsole-msg-warn {
   -moz-image-region: rect(24px, 24px, 32px, 16px);
 }
 
 .webconsole-msg-console.webconsole-msg-info {
   -moz-image-region: rect(24px, 32px, 32px, 24px);
 }
 
+.webconsole-mixed-content {
+  color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+  color: #0000EE;
+  margin: 0;
+}
+
 /* Input and output styles */
 .webconsole-msg-input > .webconsole-msg-icon-container,
 .webconsole-msg-output > .webconsole-msg-icon-container {
   border-left: solid #808080 6px;
 }
 
 .webconsole-msg-input {
   -moz-image-region: rect(24px, 40px, 32px, 32px);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10013,32 +10013,39 @@ nsDocShell::AddState(nsIVariant *aData, 
 bool
 nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
 {
     // I believe none of the about: urls should go in the history. But then
     // that could just be me... If the intent is only deny about:blank then we
     // should just do a spec compare, rather than two gets of the scheme and
     // then the path.  -Gagan
     nsresult rv;
-    nsCAutoString buf;
+    nsCAutoString buf, pref;
 
     rv = aURI->GetScheme(buf);
     if (NS_FAILED(rv))
         return false;
 
     if (buf.Equals("about")) {
         rv = aURI->GetPath(buf);
         if (NS_FAILED(rv))
             return false;
 
         if (buf.Equals("blank")) {
             return false;
         }
     }
-    return true;
+
+    rv = aURI->GetSpec(buf);
+    NS_ENSURE_SUCCESS(rv, true);
+
+    rv = Preferences::GetDefaultCString("browser.newtab.url", &pref);
+    NS_ENSURE_SUCCESS(rv, true);
+
+    return !buf.Equals(pref);
 }
 
 nsresult
 nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
                                 nsISupports* aOwner, bool aCloneChildren,
                                 nsISHEntry ** aNewEntry)
 {
     NS_PRECONDITION(aURI, "uri is null");
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -64,18 +64,18 @@
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::widget;
 
-//#define DEBUG_FOCUS 1
-//#define DEBUG_FOCUS_NAVIGATION 1
+#define DEBUG_FOCUS 1
+#define DEBUG_FOCUS_NAVIGATION 1
 #define PRINTTAGF(format, content)                     \
   {                                                    \
     nsAutoString tag(NS_LITERAL_STRING("(none)"));     \
     if (content)                                       \
       content->Tag()->ToString(tag);                   \
     printf(format, NS_ConvertUTF16toUTF8(tag).get());  \
   }