Bug 1253128: [webext] Support type=popup in the browser.windows API. r?billm draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 03 Mar 2016 18:44:18 -0800
changeset 336680 c65d56378aa77f1c83af6ba67627b937f5486f67
parent 336674 f7363283cd918f60328eb97ff33d052bc543f9df
child 515490 29799e7d7a8a2ae8a0da2706b0faf10c48ce9310
push id12171
push usermaglione.k@gmail.com
push dateFri, 04 Mar 2016 03:10:50 +0000
reviewersbillm
bugs1253128
milestone47.0a1
Bug 1253128: [webext] Support type=popup in the browser.windows API. r?billm MozReview-Commit-ID: ALgprY2w7w9
browser/components/extensions/ext-utils.js
browser/components/extensions/ext-windows.js
browser/components/extensions/schemas/windows.json
browser/components/extensions/test/browser/browser_ext_windows_create.js
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -620,16 +620,26 @@ global.WindowManager = {
   WINDOW_ID_CURRENT: -2,
 
   get topWindow() {
     return Services.wm.getMostRecentWindow("navigator:browser");
   },
 
   windowType(window) {
     // TODO: Make this work.
+
+    let {chromeFlags} = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDocShell)
+                              .treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIXULWindow);
+
+    if (chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG) {
+      return "popup";
+    }
+
     return "normal";
   },
 
   getId(window) {
     if (this._windows.has(window)) {
       return this._windows.get(window);
     }
     let id = this._nextId++;
@@ -692,18 +702,16 @@ global.WindowManager = {
     let result = {
       id: this.getId(window),
       focused: window.document.hasFocus(),
       top: window.screenY,
       left: window.screenX,
       width: window.outerWidth,
       height: window.outerHeight,
       incognito: PrivateBrowsingUtils.isWindowPrivate(window),
-
-      // We fudge on these next two.
       type: this.windowType(window),
       state,
     };
 
     if (getInfo && getInfo.populate) {
       result.tabs = TabManager.for(extension).getTabs(window);
     }
 
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -106,27 +106,35 @@ extensions.registerSchemaAPI("windows", 
             args.AppendElement(array);
           } else {
             args.AppendElement(mkstr(createData.url));
           }
         } else {
           args.AppendElement(mkstr(aboutNewTabService.newTabURL));
         }
 
-        let extraFeatures = "";
+        let features = ["chrome"];
+
+        if (createData.type === null || createData.type == "normal") {
+          features.push("dialog=no", "all");
+        } else {
+          // All other types create "popup"-type windows by default.
+          features.push("dialog", "resizable", "minimizable", "centerscreen", "titlebar", "close");
+        }
+
         if (createData.incognito !== null) {
           if (createData.incognito) {
-            extraFeatures += ",private";
+            features.push("private");
           } else {
-            extraFeatures += ",non-private";
+            features.push("non-private");
           }
         }
 
         let window = Services.ww.openWindow(null, "chrome://browser/content/browser.xul", "_blank",
-                                            "chrome,dialog=no,all" + extraFeatures, args);
+                                            features.join(","), args);
 
         if (createData.left !== null || createData.top !== null) {
           let left = createData.left !== null ? createData.left : window.screenX;
           let top = createData.top !== null ? createData.top : window.screenY;
           window.moveTo(left, top);
         }
         if (createData.width !== null || createData.height !== null) {
           let width = createData.width !== null ? createData.width : window.outerWidth;
--- a/browser/components/extensions/schemas/windows.json
+++ b/browser/components/extensions/schemas/windows.json
@@ -330,17 +330,16 @@
                 "description": "If true, opens an active window. If false, opens an inactive window."
               },
               "incognito": {
                 "type": "boolean",
                 "optional": true,
                 "description": "Whether the new window should be an incognito window."
               },
               "type": {
-                "unsupported": true,
                 "$ref": "CreateType",
                 "optional": true,
                 "description": "Specifies what type of browser window to create. The 'panel' and 'detached_panel' types create a popup unless the '--enable-panels' flag is set."
               },
               "state": {
                 "$ref": "WindowState",
                 "optional": true,
                 "description": "The initial state of the window. The 'minimized', 'maximized' and 'fullscreen' states cannot be combined with 'left', 'top', 'width' or 'height'."
--- a/browser/components/extensions/test/browser/browser_ext_windows_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create.js
@@ -15,33 +15,48 @@ add_task(function* testWindowCreate() {
 
       function checkWindow(expected) {
         return new Promise(resolve => {
           _checkWindowPromise = {resolve};
           browser.test.sendMessage("check-window", expected);
         });
       }
 
-      function createWindow(params, expected) {
+      function createWindow(params, expected, keep = false) {
         return browser.windows.create(params).then(window => {
           for (let key of Object.keys(params)) {
             browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
           }
 
           return checkWindow(expected).then(() => {
+            if (keep) {
+              return window;
+            }
             return browser.windows.remove(window.id);
           });
         });
       }
 
       createWindow({state: "minimized"}, {state: "STATE_MINIMIZED"})
       .then(() => createWindow({state: "maximized"}, {state: "STATE_MAXIMIZED"}))
-      .then(() => createWindow({state: "normal"}, {state: "STATE_NORMAL"}))
+      .then(() => createWindow({state: "normal"}, {state: "STATE_NORMAL", hiddenChrome: []}))
       .then(() => createWindow({state: "fullscreen"}, {state: "STATE_FULLSCREEN"}))
       .then(() => {
+        return createWindow({type: "popup"},
+                            {hiddenChrome: ["menubar", "toolbar", "location", "directories", "status", "extrachrome"],
+                             chromeFlags: ["CHROME_OPENAS_DIALOG"]},
+                            true);
+      }).then(window => {
+        return browser.tabs.query({windowType: "popup", active: true}).then(tabs => {
+          browser.test.assertEq(1, tabs.length, "Expected only one popup");
+          browser.test.assertEq(window.id, tabs[0].windowId, "Expected new window to be returned in query");
+
+          return browser.windows.remove(window.id);
+        });
+      }).then(() => {
         browser.test.notifyPass("window-create");
       }).catch(e => {
         browser.test.fail(`${e} :: ${e.stack}`);
         browser.test.notifyFail("window-create");
       });
     },
   });
 
@@ -58,16 +73,32 @@ add_task(function* testWindowCreate() {
       let {windowState} = latestWindow;
       if (latestWindow.fullScreen) {
         windowState = latestWindow.STATE_FULLSCREEN;
       }
 
       is(windowState, latestWindow[expected.state],
          `Expected window state to be ${expected.state}`);
     }
+    if (expected.hiddenChrome) {
+      let chromeHidden = latestWindow.document.documentElement.getAttribute("chromehidden");
+      is(chromeHidden.trim().split(/\s+/).sort().join(" "),
+         expected.hiddenChrome.sort().join(" "),
+         "Got expected hidden chrome");
+    }
+    if (expected.chromeFlags) {
+      let {chromeFlags} = latestWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                      .getInterface(Ci.nsIDocShell)
+                                      .treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)
+                                      .getInterface(Ci.nsIXULWindow);
+      for (let flag of expected.chromeFlags) {
+        ok(chromeFlags & Ci.nsIWebBrowserChrome[flag],
+           `Expected window to have the ${flag} flag`);
+      }
+    }
 
     extension.sendMessage("checked-window");
   });
 
   yield extension.startup();
   yield extension.awaitFinish("window-create");
   yield extension.unload();