Bug 1203395 - Repair view selection source in window mode. r=mconley, a=lizzard
authorJ. Ryan Stinnett <jryans@gmail.com>
Tue, 29 Sep 2015 14:12:54 -0500
changeset 296268 d6f44c82219bb6e493c8db63f21c7d64f975727a
parent 296267 9dfec714d1dfdddbccc0a86cbf00a8caf90b0efc
child 296269 105321e376719eca102954c003344a9db25571fd
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley, lizzard
bugs1203395
milestone43.0a2
Bug 1203395 - Repair view selection source in window mode. r=mconley, a=lizzard
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();
   };