Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically move a tab to another window in a firefox Addon-SDK extension?

While it looks like you can change the order of a tab within a window by updating the tab .index property, it doesn't look like the tabs api directly supports the move of a tab to another window.

Am I missing something? Is there a viable workaround?

like image 409
Hans Avatar asked Oct 09 '14 00:10

Hans


3 Answers

It is possible through the low level module window/utils. The example below duplicates the active tab across every open window

const { getMostRecentBrowserWindow, windows: getWindows } = require("sdk/window/utils");

const { ActionButton } = require("sdk/ui/button/action");

var button = ActionButton({
  id: "duplicatetab-button",
  label: "Duplicate tab",
  icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACUElEQVQ4jaWTTWtTURCGjzc33CCpbVKN4kexC9EUY1Hov+iqPyDrbgtuCrViKUERqsWVguBGQaW4UiKiaEVxoShFGgnuBMUqNW3zce49Z+ZxUWtwoRR8YXbzPswM7xj+JgVEiXGsYVknxgII4Ltt5p8AB8RArOAUVQfqQJNtAFA8QgvF6i9PR1Dt0KbVBTjncM4hIni/OZv3HsRB+wvefiP2LcQnJIkQe49FEJFNQLPZZHh4mEwmQyqVoqenh3K5TGvlK1dOlageH+HG4DFar1/S0A6Lr99xdN8QxWKRXC6HGR0dJZvNMjk5Sb1ep1gskk6nuTo/D+/ec7dvkBdhP9cKeX7UXxEZQ2/YRxRFLC8vY+bm5qhUKnjvsdYyPj5OFEWcnTnHujiS5TfcPDbAw50h9w7u5f7UadLZFLVaDRHBiGzuY61lbGyMXC5HoVBgrbGGWAW/TvvxHR7s7udFKs/1oyfZ+PSRTqeDqm7eoFqtEoYhmUyG2dlZVJU4iREfI/WP3Nt9iMUdu7jdf5Anly5i0oaVlRWazSZmYWGBIAiIoohyucz09DQTExPMnJli9dlT5vcM8Kh3gFsHDuNqb9mb7yXMRBhjWFpawpRKJVKpFMYYgiAgDEOCIOD81BkunBjh8pEhKqUhGkvP6bQ/U//wgUP5/YRhSDabxbTbbVQV5xyq2q0kgR8NdOM7JKuo/Y5qggqIdPvMlnkrQCKCquJFsOrxeHAJxA48eFU6Xv4EqOpv41YqnQirqliv4MEmQtN7RBSs7wL+/gvb038DfgJnyUabbHzUbQAAAABJRU5ErkJggg==",
  onClick: function() {
    var xulwindows = getWindows("navigator:browser");
    var xulactivewindow = getMostRecentBrowserWindow();
    var xulactivetab = xulactivewindow.gBrowser.selectedTab;

    xulwindows.forEach(function(win){
      if(win === xulactivewindow)
        return;
      var duplicatedtab = win.gBrowser.duplicateTab(xulactivetab);
      win.gBrowser.moveTabTo(duplicatedtab, 0); // the second argument is the index
    });
  }
});
like image 54
paa Avatar answered Nov 15 '22 12:11

paa


@paa's solution is nice but it doesn't move a tab. His is duplicating the tab. So flash movies will not retain their position etc. And its not a move its a duplicatio, like he explained.

I did a lot of research was real fun. The way they move tabs in Firefox is via docShell swapping. This will accomplish what you want. It's written for bootstrap though so needs touch up for addon sdk.

Pass second argument as string of tabbed or non-tabbed if you want to move it to a new window. Else pass second argument an existing window and it will be moved there. can copy paste and run this code from sratchpad.

this uses the gBrowser.swapBrowsersAndCloseOther function

function moveTabToWin(aTab, tDOMWin) {
  //tDOMWin means target DOMWindow means the window you want the tab in
  //if tDOMWin == 'tabbed' or == 'non-tabbed' it opens in a new window
  //if aTopContWin is the last in its window, then its window is closed
  if (tDOMWin == 'tabbed' || tDOMWin == 'non-tabbed') {
    var sa = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
    var wuri = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
    wuri.data = 'about:blank';
    sa.AppendElement(wuri);
    let features = "chrome,dialog=no";
    if (tDOMWin == 'tabbed') {
      features += ',all';
    }
    var sDOMWin = aTab.ownerGlobal; //source DOMWindow
    if (PrivateBrowsingUtils.permanentPrivateBrowsing || PrivateBrowsingUtils.isWindowPrivate(sDOMWin)) {
       features += ",private";
    } else {
       features += ",non-private";
    }
    var XULWindow = Services.ww.openWindow(null, 'chrome://browser/content/browser.xul', null, features, sa);
    XULWindow.addEventListener('load', function() {
      var DOMWindow = XULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
      DOMWindow.gBrowser.selectedTab.linkedBrowser.webNavigation.stop(Ci.nsIWebNavigation.STOP_ALL);
      DOMWindow.gBrowser.swapBrowsersAndCloseOther(DOMWindow.gBrowser.selectedTab, aTab);
      //DOMWindow.gBrowser.selectedTab = newTab;
    }, false);
  } else if (tDOMWin) {
    //existing dom window
    var newTab = tDOMWin.gBrowser.addTab('about:blank');
    newTab.linkedBrowser.webNavigation.stop(Ci.nsIWebNavigation.STOP_ALL);
    tDOMWin.gBrowser.swapBrowsersAndCloseOther(newTab, aTab);
    tDOMWin.gBrowser.selectedTab = newTab;
  }
}

moveTabToWin(gBrowser.selectedTab, 'tabbed');
like image 45
Noitidart Avatar answered Nov 15 '22 13:11

Noitidart


I'v got inspired by @Noitidart's answer and came up with my solution.

I'm adding setWindow(window, index) method to Tab's prototype, so that any SDK tab can be moved to another window from anywhere in the addon with a simple call like this:

browserWindows[0].activeTab.setWindow(browserWindows.activeWindow, 0);

This will move active tab of window 0 to the beginning of active window.

And here is the method:

Update:

I've put together a module to do exactly this: jetpack-tab-setwindow


Old solution (breaks in FF43)

var Tab = require("sdk/tabs/tab").Tab;

Tab.prototype.setWindow = function (window, index) {
    var tab = this;
    var oldWindow = tab.window;
    if ( oldWindow !== window ) {
        // We have to use lower-level API here
        var Ci      = require('chrome').Ci;
        var viewFor = require("sdk/view/core").viewFor;

        var aTab = viewFor(tab);
        var aWin = viewFor(window);
        var gBrowser = aWin.gBrowser;

        // Get tab properties
        var isSelected = oldWindow.activeTab == tab;
        var isPinned   = aTab.pinned;

        // Log for debugging:
        var tabId = tab.id;
        console.log('setWindow', {index, isSelected, isPinned, tab, tabId});

        // Create a placeholder-tab on destination windows
        var newTab = gBrowser.addTab('about:newtab');
        newTab.linkedBrowser.webNavigation.stop(Ci.nsIWebNavigation.STOP_ALL); // we don't need this tab anyways

        // If index specified, move placeholder-tab to desired index
        if ( index != undefined ) {
            var length = gBrowser.tabContainer.childElementCount;
            if ( index < 0 ) index = length - index;
            if( 0 <= index && index < length ) {
                gBrowser.moveTabTo(newTab, index);
            }
        }
        // Copy tab properties to placeholder-tab
        if ( isPinned ) {
            gBrowser.pinTab(newTab);
        }

        // For some reason this doesn't seem to work :-(
        if ( isSelected ) {
            gBrowser.selectedTab = newTab;
        }

        // Swap tabs and remove placeholder-tab
        gBrowser.swapBrowsersAndCloseOther(newTab, aTab);
    }
};
like image 25
DUzun Avatar answered Nov 15 '22 12:11

DUzun