Bug 855108 - Disable tools toggled by the developer toolbar when it closes. r=jwalker
☠☠ backed out by 12e6b44a4a8b ☠ ☠
authorDavid Creswick <dcrewi@gyrae.net>
Sun, 21 Apr 2013 18:35:53 -0500
changeset 130112 229cd2ebe225bc6d6aa4038d491f04fcd958ae6d
parent 129935 d360244c69ab7874374baceeccdb7c611816645c
child 130113 8911b764dc1e9b65d94facac590a737f10e6f958
push id24598
push userttaubert@mozilla.com
push dateSat, 27 Apr 2013 15:33:40 +0000
treeherdermozilla-central@40dafc376794 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalker
bugs855108
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 855108 - Disable tools toggled by the developer toolbar when it closes. r=jwalker
browser/devtools/shared/DeveloperToolbar.jsm
browser/devtools/shared/test/Makefile.in
browser/devtools/shared/test/browser_toolbar_buttons_nopersist.js
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -102,17 +102,19 @@ let CommandUtils = {
         }
         if (command.tooltipText != null) {
           button.setAttribute("tooltiptext", command.tooltipText);
         }
         else if (command.description != null) {
           button.setAttribute("tooltiptext", command.description);
         }
 
+        let buttonWasClickedAtLeastOnce = false;
         button.addEventListener("click", function() {
+          buttonWasClickedAtLeastOnce = true;
           requisition.update(buttonSpec.typed);
           //if (requisition.getStatus() == Status.VALID) {
             requisition.exec();
           /*
           }
           else {
             console.error('incomplete commands not yet supported');
           }
@@ -129,19 +131,37 @@ let CommandUtils = {
               }
               else if (button.hasAttribute("checked")) {
                 button.removeAttribute("checked");
               }
             }
           };
           command.state.onChange(target, onChange);
           onChange(null, target.tab);
-          document.defaultView.addEventListener("unload", function() {
+          let cleanUp = function () {
+            document.defaultView.removeEventListener("unload", cleanUp, false);
+            target.off("close", cleanUp);
+
             command.state.offChange(target, onChange);
-          }, false);
+
+            // If the command toggles state and if that state has been
+            // modified by the button, then make sure the state is
+            // cleared when the button's document unloads. This is so
+            // that the effects of buttons on the developer toolbar do
+            // not persist after the toolbar is closed.
+            if (buttonWasClickedAtLeastOnce &&
+                command.state.isChecked(target)) {
+              // toggle state to the off position
+              requisition.update(buttonSpec.typed);
+              requisition.exec();
+              buttonWasClickedAtLeastOnce = false;
+            }
+          };
+          document.defaultView.addEventListener("unload", cleanUp, false);
+          target.on("close", cleanUp);
         }
       }
     });
 
     requisition.update('');
 
     return reply;
   },
--- a/browser/devtools/shared/test/Makefile.in
+++ b/browser/devtools/shared/test/Makefile.in
@@ -17,16 +17,17 @@ MOCHITEST_BROWSER_FILES = \
   browser_browser_basic.js \
   browser_require_basic.js \
   browser_templater_basic.js \
   browser_toolbar_basic.js \
   browser_toolbar_tooltip.js \
   browser_toolbar_webconsole_errors_count.js \
   browser_layoutHelpers.js \
   browser_eventemitter_basic.js \
+  browser_toolbar_buttons_nopersist.js \
   head.js \
   leakhunt.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
   browser_templater_basic.html \
   browser_toolbar_basic.html \
   browser_toolbar_webconsole_errors_count.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/test/browser_toolbar_buttons_nopersist.js
@@ -0,0 +1,151 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 855108 - Commands toggled by the developer toolbar should not persist after the toolbar closes
+
+function test() {
+  waitForExplicitFinish();
+
+  let Toolbox = Cu.import("resource:///modules/devtools/Toolbox.jsm", {}).Toolbox;
+  let TargetFactory = Cu.import("resource:///modules/devtools/Target.jsm", {}).TargetFactory;
+  let gDevTools = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools;
+  let CommandUtils = Cu.import("resource:///modules/devtools/DeveloperToolbar.jsm", {}).CommandUtils;
+  let Requisition = (function () {
+    let require = Cu.import("resource://gre/modules/devtools/Require.jsm", {}).require;
+    Cu.import("resource:///modules/devtools/gcli.jsm", {});
+    return require('gcli/cli').Requisition;
+  })();
+  let Services = Cu.import("resource://gre/modules/Services.jsm", {}).Services;
+  let TiltGL = Cu.import("resource:///modules/devtools/TiltGL.jsm", {}).TiltGL;
+  let Promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+
+  // only test togglable items on the toolbar
+  const commandsToTest =
+          CommandUtils.getCommandbarSpec("devtools.toolbox.toolbarSpec")
+          .filter(function (command) {
+            if ( !(typeof command == "string" &&
+                   command.indexOf("toggle") >= 0))
+              return false;
+            if (command == "tilt toggle") {
+              // Is it possible to run the tilt tool?
+              let XHTML_NS = "http://www.w3.org/1999/xhtml";
+              let canvas = document.createElementNS(XHTML_NS, "canvas");
+              return (TiltGL.isWebGLSupported() &&
+                      TiltGL.create3DContext(canvas));
+            }
+            return true;
+          });
+
+  const URL = "data:text/html;charset=UTF-8," + encodeURIComponent(
+    [ "<!DOCTYPE html>",
+      "<html>",
+      "  <head>",
+      "    <title>Bug 855108</title>",
+      "  </head>",
+      "  <body>",
+      "    <p>content</p>",
+      "  </body>",
+      "</html>"
+    ].join("\n"));
+
+  function clearHostPref() {
+    let pref = Toolbox.prototype._prefs.LAST_HOST;
+    Services.prefs.getBranch("").clearUserPref(pref);
+  }
+
+  registerCleanupFunction(clearHostPref);
+
+  let requisition;
+
+  function testNextCommand(tab) {
+    if (commandsToTest.length ==  0) {
+      finish();
+      return null;
+    }
+    let commandSpec = commandsToTest.pop();
+    requisition.update(commandSpec);
+    let command = requisition.commandAssignment.value;
+
+    let target = TargetFactory.forTab(tab);
+    function checkToggle(expected, msg) {
+      is(!!command.state.isChecked(target), expected, commandSpec+" "+msg);
+    }
+    let toolbox;
+
+    clearHostPref();
+
+    // Actions: Toggle the command on using the toolbox button, then
+    //          close the toolbox.
+    // Expected result: The command should no longer be toggled on.
+    return gDevTools.showToolbox(target)
+      .then(catchFail(function (aToolbox) {
+        toolbox = aToolbox;
+        let button = toolbox.doc.getElementById(command.buttonId);
+        return clickElement(button);
+      })).then(catchFail(function () {
+        checkToggle(true, "was toggled on by toolbox");
+        return toolbox.destroy();
+      }))
+      .then(catchFail(function () {
+        target = TargetFactory.forTab(tab);
+        checkToggle(false, "is untoggled after toobox closed");
+      }))
+
+    // Actions: Open the toolbox, toggle the command on use means
+    //          OTHER than the toolbox, then close the toolbox.
+    // Expected result: The command should still be toggled.
+    // Cleanup: Toggle the command off again.
+      .then(function () gDevTools.showToolbox(target))
+      .then(catchFail(function (toolbox) {
+        requisition.update(commandSpec);
+        requisition.exec();
+        checkToggle(true, "was toggled on by command");
+        return toolbox.destroy();
+      }))
+      .then(catchFail(function () {
+        target = TargetFactory.forTab(tab);
+        checkToggle(true, "is still toggled after toolbox closed");
+        requisition.update(commandSpec);
+        requisition.exec();
+      }))
+
+    // Actions: Toggle the command on using the button on a docked
+    //          toolbox, detach the toolbox into a window, then close
+    //          the toolbox.
+    // Expected result: The command should no longer be toggled on.
+      .then(function () gDevTools.showToolbox(target, null,
+                                              Toolbox.HostType.BOTTOM))
+      .then(catchFail(function (aToolbox) {
+        toolbox = aToolbox;
+        let button = toolbox.doc.getElementById(command.buttonId);
+        return clickElement(button);
+      })).then(catchFail(function () {
+        checkToggle(true, "was toggled by docked toolbox");
+        return toolbox.switchHost(Toolbox.HostType.WINDOW);
+      }))
+      .then(function () toolbox.destroy())
+      .then(catchFail(function () {
+        target = TargetFactory.forTab(tab);
+        checkToggle(false, "is untoggled after detached toobox closed");
+      }))
+
+      .then(function () target.destroy())
+      .then(function () testNextCommand(tab));
+  }
+
+  function clickElement(el) {
+    let deferred = Promise.defer();
+    let window = el.ownerDocument.defaultView;
+    waitForFocus(function () {
+      EventUtils.synthesizeMouseAtCenter(el, {}, window);
+      deferred.resolve();
+    }, window);
+    return deferred.promise;
+  }
+
+  addTab(URL, function (browser, tab) {
+    let environment = { chromeDocument: tab.ownerDocument };
+    requisition = new Requisition(environment);
+    testNextCommand(tab);
+  });
+}