Bug 1203395 - Repair view selection source in window mode. r=mconley
authorJ. Ryan Stinnett <jryans@gmail.com>
Tue, 29 Sep 2015 14:12:54 -0500
changeset 265683 5636e295717a1d4f45b3f5b5350a3f33b418b7af
parent 265682 b07f2f312b9b54fbece4fec5861163debc92cd10
child 265684 b276c71ae78e61b4c2e9038128437af6138e6ae2
push id66003
push usercbook@mozilla.com
push dateFri, 02 Oct 2015 11:37:40 +0000
treeherdermozilla-inbound@3fd732d24f46 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1203395
milestone44.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 1203395 - Repair view selection source in window mode. r=mconley
toolkit/components/viewsource/content/viewPartialSource.js
toolkit/components/viewsource/content/viewSource.js
toolkit/components/viewsource/test/browser/browser_contextmenu.js
toolkit/components/viewsource/test/browser/head.js
--- a/toolkit/components/viewsource/content/viewPartialSource.js
+++ b/toolkit/components/viewsource/content/viewPartialSource.js
@@ -11,12 +11,12 @@ function onLoadViewPartialSource() {
   // and set the menuitem's checked attribute accordingly
   let wrapLongLines = Services.prefs.getBoolPref("view_source.wrap_long_lines");
   document.getElementById("menu_wrapLongLines")
           .setAttribute("checked", wrapLongLines);
   document.getElementById("menu_highlightSyntax")
           .setAttribute("checked",
                         Services.prefs.getBoolPref("view_source.syntax_highlight"));
 
-  let args = window.arguments;
+  let args = window.arguments[0];
   viewSourceChrome.loadViewSourceFromSelection(args.URI, args.drawSelection, args.baseURI);
   window.content.focus();
 }
--- a/toolkit/components/viewsource/content/viewSource.js
+++ b/toolkit/components/viewsource/content/viewSource.js
@@ -213,16 +213,23 @@ ViewSourceChrome.prototype = {
    * the document source out of the network cache), we automatically re-load
    * the frame script.
    */
   get mm() {
     return window.messageManager;
   },
 
   /**
+   * Getter for the nsIWebNavigation of the view source browser.
+   */
+  get webNav() {
+    return this.browser.webNavigation;
+  },
+
+  /**
    * Send the browser forward in its history.
    */
   goForward() {
     this.browser.goForward();
   },
 
   /**
    * Send the browser backward in its history.
--- a/toolkit/components/viewsource/test/browser/browser_contextmenu.js
+++ b/toolkit/components/viewsource/test/browser/browser_contextmenu.js
@@ -3,44 +3,65 @@
  */
 
 var source = "data:text/html,text<link%20href='http://example.com/'%20/>more%20text<a%20href='mailto:abc@def.ghi'>email</a>";
 var gViewSourceWindow, gContextMenu, gCopyLinkMenuItem, gCopyEmailMenuItem;
 
 var expectedData = [];
 
 add_task(function *() {
+  // Full source in view source window
   let newWindow = yield loadViewSourceWindow(source);
   yield SimpleTest.promiseFocus(newWindow);
 
   yield* onViewSourceWindowOpen(newWindow, false);
 
   let contextMenu = gViewSourceWindow.document.getElementById("viewSourceContextMenu");
 
   for (let test of expectedData) {
     yield* checkMenuItems(contextMenu, false, test[0], test[1], test[2], test[3]);
   }
 
   yield new Promise(resolve => {
     closeViewSourceWindow(newWindow, resolve);
   });
 
+  // Selection source in view source tab
   expectedData = [];
   let newTab = yield openDocumentSelect(source, "body");
   yield* onViewSourceWindowOpen(window, true);
 
   contextMenu = document.getElementById("contentAreaContextMenu");
 
   // Prepend view-source to this one as it opens in a tab.
   expectedData[0][3] = "view-source:" + expectedData[0][3];
   for (let test of expectedData) {
     yield* checkMenuItems(contextMenu, true, test[0], test[1], test[2], test[3]);
   }
 
   gBrowser.removeTab(newTab);
+
+  // Selection source in view source window
+  yield pushPrefs(["view_source.tab", false]);
+
+  expectedData = [];
+  newWindow = yield openDocumentSelect(source, "body");
+  yield SimpleTest.promiseFocus(newWindow);
+
+  yield* onViewSourceWindowOpen(newWindow, false);
+
+  contextMenu = newWindow.document.getElementById("viewSourceContextMenu");
+
+  for (let test of expectedData) {
+    yield* checkMenuItems(contextMenu, false, test[0], test[1], test[2], test[3]);
+  }
+
+  yield new Promise(resolve => {
+    closeViewSourceWindow(newWindow, resolve);
+  });
 });
 
 function* onViewSourceWindowOpen(aWindow, aIsTab) {
   gViewSourceWindow = aWindow;
 
   gCopyLinkMenuItem = aWindow.document.getElementById(aIsTab ? "context-copylink" : "context-copyLink");
   gCopyEmailMenuItem = aWindow.document.getElementById(aIsTab ? "context-copyemail" : "context-copyEmail");
 
--- a/toolkit/components/viewsource/test/browser/head.js
+++ b/toolkit/components/viewsource/test/browser/head.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 Cu.import("resource://gre/modules/PromiseUtils.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 
+const WINDOW_TYPE = "navigator:view-source";
+
 function openViewSourceWindow(aURI, aCallback) {
   let viewSourceWindow = openDialog("chrome://global/content/viewSource.xul", null, null, aURI);
   viewSourceWindow.addEventListener("pageshow", function pageShowHandler(event) {
     // Wait for the inner window to load, not viewSourceWindow.
     if (event.target.location == "view-source:" + aURI) {
       info("View source window opened: " + event.target.location);
       viewSourceWindow.removeEventListener("pageshow", pageShowHandler, false);
       aCallback(viewSourceWindow);
@@ -35,43 +37,72 @@ function closeViewSourceWindow(aWindow, 
 
 function testViewSourceWindow(aURI, aTestCallback, aCloseCallback) {
   openViewSourceWindow(aURI, function(aWindow) {
     aTestCallback(aWindow);
     closeViewSourceWindow(aWindow, aCloseCallback);
   });
 }
 
+function waitForViewSourceWindow() {
+  return new Promise(resolve => {
+    let windowListener = {
+      onOpenWindow(xulWindow) {
+        let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIDOMWindow);
+        win.addEventListener("load", function listener() {
+          win.removeEventListener("load", listener, false);
+          if (win.document.documentElement.getAttribute("windowtype") !=
+              WINDOW_TYPE) {
+            return;
+          }
+          // Found the window
+          resolve(win);
+          Services.wm.removeListener(windowListener);
+        }, false);
+      },
+      onCloseWindow() {},
+      onWindowTitleChange() {}
+    };
+    Services.wm.addListener(windowListener);
+  });
+}
+
 /**
- * Opens a view source tab for a selection (View Selection Source) within the
- * currently selected browser in gBrowser.
+ * Opens a view source tab / window for a selection (View Selection Source)
+ * within the currently selected browser in gBrowser.
  *
  * @param aCSSSelector - used to specify a node within the selection to
  *                       view the source of. It is expected that this node is
  *                       within an existing selection.
- * @returns the new tab which shows the source.
+ * @returns the new tab / window which shows the source.
  */
-function* openViewPartialSourceTab(aCSSSelector) {
+function* openViewPartialSource(aCSSSelector) {
   let contentAreaContextMenuPopup =
     document.getElementById("contentAreaContextMenu");
   let popupShownPromise =
     BrowserTestUtils.waitForEvent(contentAreaContextMenuPopup, "popupshown");
   yield BrowserTestUtils.synthesizeMouseAtCenter(aCSSSelector,
           { type: "contextmenu", button: 2 }, gBrowser.selectedBrowser);
   yield popupShownPromise;
 
-  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null);
+  let openPromise;
+  if (Services.prefs.getBoolPref("view_source.tab")) {
+    openPromise = BrowserTestUtils.waitForNewTab(gBrowser, null);
+  } else {
+    openPromise = waitForViewSourceWindow();
+  }
 
   let popupHiddenPromise =
     BrowserTestUtils.waitForEvent(contentAreaContextMenuPopup, "popuphidden");
   let item = document.getElementById("context-viewpartialsource-selection");
   EventUtils.synthesizeMouseAtCenter(item, {});
   yield popupHiddenPromise;
 
-  return (yield newTabPromise);
+  return (yield openPromise);
 }
 
 /**
  * Opens a view source tab for a frame (View Frame Source) within the
  * currently selected browser in gBrowser.
  *
  * @param aCSSSelector - used to specify the frame to view the source of.
  * @returns the new tab which shows the source.
@@ -98,61 +129,69 @@ function* openViewFrameSourceTab(aCSSSel
   let item = document.getElementById("context-viewframesource");
   EventUtils.synthesizeMouseAtCenter(item, {});
   yield popupHiddenPromise;
 
   return (yield newTabPromise);
 }
 
 registerCleanupFunction(function() {
-  var windows = Services.wm.getEnumerator("navigator:view-source");
+  var windows = Services.wm.getEnumerator(WINDOW_TYPE);
   ok(!windows.hasMoreElements(), "No remaining view source windows still open");
   while (windows.hasMoreElements())
     windows.getNext().close();
 });
 
 /**
- * For a given view source tab, wait for the source loading step to complete.
+ * For a given view source tab / window, wait for the source loading step to
+ * complete.
  */
-function waitForSourceLoaded(tab) {
+function waitForSourceLoaded(tabOrWindow) {
   return new Promise(resolve => {
-    let mm = tab.linkedBrowser.messageManager;
+    let mm = tabOrWindow.messageManager ||
+             tabOrWindow.linkedBrowser.messageManager;
     mm.addMessageListener("ViewSource:SourceLoaded", function sourceLoaded() {
       mm.removeMessageListener("ViewSource:SourceLoaded", sourceLoaded);
       setTimeout(resolve, 0);
     });
   });
 }
 
 /**
  * Open a new document in a new tab, select part of it, and view the source of
  * that selection. The document is not closed afterwards.
  *
  * @param aURI - url to load
  * @param aCSSSelector - used to specify a node to select. All of this node's
  *                       children will be selected.
- * @returns the new tab which shows the source.
+ * @returns the new tab / window which shows the source.
  */
 function* openDocumentSelect(aURI, aCSSSelector) {
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, aURI);
   registerCleanupFunction(function() {
     gBrowser.removeTab(tab);
   });
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, { selector: aCSSSelector }, function* (arg) {
     let element = content.document.querySelector(arg.selector);
     content.getSelection().selectAllChildren(element);
   });
 
-  let newtab = yield openViewPartialSourceTab(aCSSSelector);
+  let tabOrWindow = yield openViewPartialSource(aCSSSelector);
 
   // Wait until the source has been loaded.
-  yield waitForSourceLoaded(newtab);
+  yield waitForSourceLoaded(tabOrWindow);
+
+  return tabOrWindow;
+}
 
-  return newtab;
+function pushPrefs(...aPrefs) {
+  return new Promise(resolve => {
+    SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
+  });
 }
 
 function waitForPrefChange(pref) {
   let deferred = PromiseUtils.defer();
   let observer = () => {
     Preferences.ignore(pref, observer);
     deferred.resolve();
   };