Bug 1322408 - Use `gBrowser.loadTabs` to open all tabs when middle-clicking a client in Synced Tabs. r=markh a=gchang
authorKit Cambridge <kit@yakshaving.ninja>
Wed, 07 Dec 2016 11:46:36 -1000
changeset 353086 70c74e162506f62cbb5023659a7237604c037bd7
parent 353085 06fd54cb05583d9ae414d747b03d885e1a09b5b6
child 353087 18ca74ed9f75b19ff614801c27e2ab50b10bd704
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarkh, gchang
bugs1322408
milestone52.0a2
Bug 1322408 - Use `gBrowser.loadTabs` to open all tabs when middle-clicking a client in Synced Tabs. r=markh a=gchang MozReview-Commit-ID: 6phgHjAAXUs
browser/components/syncedtabs/SyncedTabsDeckComponent.js
browser/components/syncedtabs/TabListComponent.js
browser/components/syncedtabs/TabListView.js
browser/components/syncedtabs/test/xpcshell/test_TabListComponent.js
--- a/browser/components/syncedtabs/SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/SyncedTabsDeckComponent.js
@@ -47,16 +47,17 @@ function SyncedTabsDeckComponent({
   this._syncedTabsListStore = listStore || new SyncedTabsListStore(SyncedTabs);
   this.tabListComponent = listComponent || new TabListComponent({
     window: this._window,
     store: this._syncedTabsListStore,
     View: TabListView,
     SyncedTabs: SyncedTabs,
     clipboardHelper: Cc["@mozilla.org/widget/clipboardhelper;1"]
                        .getService(Ci.nsIClipboardHelper),
+    getChromeWindow: this._getChromeWindow,
   });
 }
 
 SyncedTabsDeckComponent.prototype = {
   PANELS: {
     TABS_CONTAINER: "tabs-container",
     TABS_FETCHING: "tabs-fetching",
     NOT_AUTHED_INFO: "notAuthedInfo",
--- a/browser/components/syncedtabs/TabListComponent.js
+++ b/browser/components/syncedtabs/TabListComponent.js
@@ -24,21 +24,23 @@ this.EXPORTED_SYMBOLS = [
  * TabListComponent
  *
  * The purpose of this component is to compose the view, state, and actions.
  * It defines high level actions that act on the state and passes them to the
  * view for it to trigger during user interaction. It also subscribes the view
  * to state changes so it can rerender.
  */
 
-function TabListComponent({window, store, View, SyncedTabs, clipboardHelper}) {
+function TabListComponent({window, store, View, SyncedTabs, clipboardHelper,
+                           getChromeWindow}) {
   this._window = window;
   this._store = store;
   this._View = View;
   this._clipboardHelper = clipboardHelper;
+  this._getChromeWindow = getChromeWindow;
   // used to trigger Sync from context menu
   this._SyncedTabs = SyncedTabs;
 }
 
 TabListComponent.prototype = {
   get container() {
     return this._view.container;
   },
@@ -111,27 +113,26 @@ TabListComponent.prototype = {
       .catch(Cu.reportError);
   },
 
   onOpenTab(url, where, params) {
     this._window.openUILinkIn(url, where, params);
     BrowserUITelemetry.countSyncedTabEvent("open", "sidebar");
   },
 
-  onOpenTabs(urls, where, params) {
+  onOpenTabs(urls, where) {
     if (!PlacesUIUtils.confirmOpenInTabs(urls.length, this._window)) {
       return;
     }
     if (where == "window") {
       this._window.openDialog(this._window.getBrowserURL(), "_blank",
                               "chrome,dialog=no,all", urls.join("|"));
     } else {
-      for (let url of urls) {
-        this._window.openUILinkIn(url, where, params);
-      }
+      let loadInBackground = where == "tabshifted" ? true : false;
+      this._getChromeWindow(this._window).gBrowser.loadTabs(urls, loadInBackground, false);
     }
     BrowserUITelemetry.countSyncedTabEvent("openmultiple", "sidebar");
   },
 
   onCopyTabLocation(url) {
     this._clipboardHelper.copyString(url);
   },
 
--- a/browser/components/syncedtabs/TabListView.js
+++ b/browser/components/syncedtabs/TabListView.js
@@ -284,17 +284,17 @@ TabListView.prototype = {
     }
 
     // Middle click on a client
     if (itemNode.classList.contains("client")) {
       let where = getChromeWindow(this._window).whereToOpenLink(event);
       if (where != "current") {
         const tabs = itemNode.querySelector(".item-tabs-list").childNodes;
         const urls = [...tabs].map(tab => tab.dataset.url);
-        this.props.onOpenTabs(urls, where, {});
+        this.props.onOpenTabs(urls, where);
       }
     }
 
     if (event.target.classList.contains("item-twisty-container")
         && event.which != 2) {
       this.props.onToggleBranch(itemNode.dataset.id);
       return;
     }
--- a/browser/components/syncedtabs/test/xpcshell/test_TabListComponent.js
+++ b/browser/components/syncedtabs/test/xpcshell/test_TabListComponent.js
@@ -63,33 +63,41 @@ add_task(function* testInitUninit() {
     "view.render is called on state change");
 
   component.uninit();
   Assert.ok(view.destroy.calledOnce, "view is destroyed on uninit");
 });
 
 add_task(function* testActions() {
   let store = new SyncedTabsListStore();
+  let chromeWindowMock = {
+    gBrowser: {
+      loadTabs() {},
+    },
+  };
+  let getChromeWindowMock = sinon.stub();
+  getChromeWindowMock.returns(chromeWindowMock);
   let clipboardHelperMock = {
     copyString() {},
   };
   let windowMock = {
     top: {
       PlacesCommandHook: {
         bookmarkLink() { return Promise.resolve(); }
       },
       PlacesUtils: { bookmarksMenuFolderId: "id" }
     },
     getBrowserURL() {},
     openDialog() {},
     openUILinkIn() {}
   };
   let component = new TabListComponent({
     window: windowMock, store, View: null, SyncedTabs,
-    clipboardHelper: clipboardHelperMock});
+    clipboardHelper: clipboardHelperMock,
+    getChromeWindow: getChromeWindowMock });
 
   sinon.stub(store, "getData");
   component.onFilter("query");
   Assert.ok(store.getData.calledWith("query"));
 
   sinon.stub(store, "clearFilter");
   component.onClearFilter();
   Assert.ok(store.clearFilter.called);
@@ -122,22 +130,23 @@ add_task(function* testActions() {
   component.onBookmarkTab("uri", "title");
   Assert.equal(windowMock.top.PlacesCommandHook.bookmarkLink.args[0][1], "uri");
   Assert.equal(windowMock.top.PlacesCommandHook.bookmarkLink.args[0][2], "title");
 
   sinon.spy(windowMock, "openUILinkIn");
   component.onOpenTab("uri", "where", "params");
   Assert.ok(windowMock.openUILinkIn.calledWith("uri", "where", "params"));
 
-  component.onOpenTabs(["uri1", "uri2"], "where", "params");
-  Assert.ok(windowMock.openUILinkIn.calledWith("uri1", "where", "params"));
-  Assert.ok(windowMock.openUILinkIn.calledWith("uri2", "where", "params"));
-  sinon.spy(windowMock, "openDialog");
-  component.onOpenTabs(["uri1", "uri2"], "window", "params");
-  Assert.deepEqual(windowMock.openDialog.args[0][3], ["uri1", "uri2"].join("|"));
+  sinon.spy(chromeWindowMock.gBrowser, "loadTabs");
+  let tabsToOpen = ["uri1", "uri2"];
+  component.onOpenTabs(tabsToOpen, "where");
+  Assert.ok(getChromeWindowMock.calledWith(windowMock));
+  Assert.ok(chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, false, false));
+  component.onOpenTabs(tabsToOpen, "tabshifted");
+  Assert.ok(chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, true, false));
 
   sinon.spy(clipboardHelperMock, "copyString");
   component.onCopyTabLocation("uri");
   Assert.ok(clipboardHelperMock.copyString.calledWith("uri"));
 
   sinon.stub(SyncedTabs, "syncTabs");
   component.onSyncRefresh();
   Assert.ok(SyncedTabs.syncTabs.calledWith(true));