135 lines
4.0 KiB
JavaScript
135 lines
4.0 KiB
JavaScript
/* 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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
});
|