summaryrefslogtreecommitdiffstats
path: root/toolkit/jetpack/sdk/tabs/tabs-firefox.js
blob: 1eefecb4ca616d8ab85b35d5023b7cd42ea8283f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

const { Class } = require('../core/heritage');
const { Tab, tabEvents } = require('./tab');
const { EventTarget } = require('../event/target');
const { emit, setListeners } = require('../event/core');
const { pipe } = require('../event/utils');
const { observer: windowObserver } = require('../windows/observer');
const { List, addListItem, removeListItem } = require('../util/list');
const { modelFor } = require('../model/core');
const { viewFor } = require('../view/core');
const { getTabs, getSelectedTab } = require('./utils');
const { getMostRecentBrowserWindow, isBrowser } = require('../window/utils');
const { Options } = require('./common');
const { isPrivate } = require('../private-browsing');
const { ignoreWindow, isWindowPBSupported } = require('../private-browsing/utils')
const { isPrivateBrowsingSupported } = require('sdk/self');

const supportPrivateTabs = isPrivateBrowsingSupported && isWindowPBSupported;

const Tabs = Class({
  implements: [EventTarget],
  extends: List,
  initialize: function() {
    List.prototype.initialize.call(this);

    // We must do the list manipulation here where the object is extensible
    this.on("open", tab => {
      addListItem(this, tab);
    });

    this.on("close", tab => {
      removeListItem(this, tab);
    });
  },

  get activeTab() {
    let activeDomWin = getMostRecentBrowserWindow();
    if (!activeDomWin)
      return null;
    return modelFor(getSelectedTab(activeDomWin));
  },

  open: function(options) {
    options = Options(options);

    // TODO: Remove the dependency on the windows module: bug 792670
    let windows = require('../windows').browserWindows;
    let activeWindow = windows.activeWindow;

    let privateState = supportPrivateTabs && options.isPrivate;
    // When no isPrivate option was passed use the private state of the active
    // window
    if (activeWindow && privateState === undefined)
      privateState = isPrivate(activeWindow);

    function getWindow(privateState) {
      for (let window of windows) {
        if (privateState === isPrivate(window)) {
          return window;
        }
      }
      return null;
    }

    function openNewWindowWithTab() {
      windows.open({
        url: options.url,
        isPrivate: privateState,
        onOpen: function(newWindow) {
          let tab = newWindow.tabs[0];
          setListeners(tab, options);

          if (options.isPinned)
            tab.pin();

          // We don't emit the open event for the first tab in a new window so
          // do it now the listeners are attached
          emit(tab, "open", tab);
        }
      });
    }

    if (options.inNewWindow)
      return openNewWindowWithTab();

    // if the active window is in the state that we need then use it
    if (activeWindow && (privateState === isPrivate(activeWindow)))
      return activeWindow.tabs.open(options);

    // find a window in the state that we need
    let window = getWindow(privateState);
    if (window)
      return window.tabs.open(options);

    return openNewWindowWithTab();
  }
});

const allTabs = new Tabs();
// Export a new object with allTabs as the prototype, otherwise allTabs becomes
// frozen and addListItem and removeListItem don't work correctly.
module.exports = Object.create(allTabs);
pipe(tabEvents, module.exports);

function addWindowTab(window, tabElement) {
  let tab = new Tab(tabElement);
  if (window)
    addListItem(window.tabs, tab);
  addListItem(allTabs, tab);
  emit(allTabs, "open", tab);
}

// Find tabs in already open windows
for (let tabElement of getTabs())
  addWindowTab(null, tabElement);

// Detect tabs in new windows
windowObserver.on('open', domWindow => {
  if (!isBrowser(domWindow) || ignoreWindow(domWindow))
    return;

  let window = null;
  try {
    modelFor(domWindow);
  }
  catch (e) { }

  for (let tabElement of getTabs(domWindow)) {
    addWindowTab(window, tabElement);
  }
});