michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: 'use strict'; michael@0: michael@0: const { Class } = require('../core/heritage'); michael@0: const { Tab } = require('../tabs/tab'); michael@0: const { browserWindows } = require('./fennec'); michael@0: const { windowNS } = require('../window/namespace'); michael@0: const { tabsNS, tabNS } = require('../tabs/namespace'); michael@0: const { openTab, getTabs, getSelectedTab, getTabForBrowser: getRawTabForBrowser, michael@0: getTabContentWindow } = require('../tabs/utils'); michael@0: const { Options } = require('../tabs/common'); michael@0: const { getTabForBrowser, getTabForRawTab } = require('../tabs/helpers'); michael@0: const { on, once, off, emit } = require('../event/core'); michael@0: const { method } = require('../lang/functional'); michael@0: const { EVENTS } = require('../tabs/events'); michael@0: const { EventTarget } = require('../event/target'); michael@0: const { when: unload } = require('../system/unload'); michael@0: const { windowIterator } = require('../deprecated/window-utils'); michael@0: const { List, addListItem, removeListItem } = require('../util/list'); michael@0: const { isPrivateBrowsingSupported } = require('../self'); michael@0: const { isTabPBSupported, ignoreWindow } = require('../private-browsing/utils'); michael@0: michael@0: const mainWindow = windowNS(browserWindows.activeWindow).window; michael@0: michael@0: const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec'; michael@0: michael@0: const supportPrivateTabs = isPrivateBrowsingSupported && isTabPBSupported; michael@0: michael@0: const Tabs = Class({ michael@0: implements: [ List ], michael@0: extends: EventTarget, michael@0: initialize: function initialize(options) { michael@0: let tabsInternals = tabsNS(this); michael@0: let window = tabsNS(this).window = options.window || mainWindow; michael@0: michael@0: EventTarget.prototype.initialize.call(this, options); michael@0: List.prototype.initialize.apply(this, getTabs(window).map(Tab)); michael@0: michael@0: // TabOpen event michael@0: window.BrowserApp.deck.addEventListener(EVENTS.open.dom, onTabOpen, false); michael@0: michael@0: // TabSelect michael@0: window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect, false); michael@0: }, michael@0: get activeTab() { michael@0: return getTabForRawTab(getSelectedTab(tabsNS(this).window)); michael@0: }, michael@0: open: function(options) { michael@0: options = Options(options); michael@0: let activeWin = browserWindows.activeWindow; michael@0: michael@0: if (options.isPinned) { michael@0: console.error(ERR_FENNEC_MSG); // TODO michael@0: } michael@0: michael@0: let rawTab = openTab(windowNS(activeWin).window, options.url, { michael@0: inBackground: options.inBackground, michael@0: isPrivate: supportPrivateTabs && options.isPrivate michael@0: }); michael@0: michael@0: // by now the tab has been created michael@0: let tab = getTabForRawTab(rawTab); michael@0: michael@0: if (options.onClose) michael@0: tab.on('close', options.onClose); michael@0: michael@0: if (options.onOpen) { michael@0: // NOTE: on Fennec this will be true michael@0: if (tabNS(tab).opened) michael@0: options.onOpen(tab); michael@0: michael@0: tab.on('open', options.onOpen); michael@0: } michael@0: michael@0: if (options.onReady) michael@0: tab.on('ready', options.onReady); michael@0: michael@0: if (options.onLoad) michael@0: tab.on('load', options.onLoad); michael@0: michael@0: if (options.onPageShow) michael@0: tab.on('pageshow', options.onPageShow); michael@0: michael@0: if (options.onActivate) michael@0: tab.on('activate', options.onActivate); michael@0: michael@0: return tab; michael@0: } michael@0: }); michael@0: let gTabs = exports.tabs = Tabs(mainWindow); michael@0: michael@0: function tabsUnloader(event, window) { michael@0: window = window || (event && event.target); michael@0: if (!(window && window.BrowserApp)) michael@0: return; michael@0: window.BrowserApp.deck.removeEventListener(EVENTS.open.dom, onTabOpen, false); michael@0: window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect, false); michael@0: } michael@0: michael@0: // unload handler michael@0: unload(function() { michael@0: for (let window in windowIterator()) { michael@0: tabsUnloader(null, window); michael@0: } michael@0: }); michael@0: michael@0: function addTab(tab) { michael@0: addListItem(gTabs, tab); michael@0: return tab; michael@0: } michael@0: michael@0: function removeTab(tab) { michael@0: removeListItem(gTabs, tab); michael@0: return tab; michael@0: } michael@0: michael@0: // TabOpen michael@0: function onTabOpen(event) { michael@0: let browser = event.target; michael@0: michael@0: // Eventually ignore private tabs michael@0: if (ignoreWindow(browser.contentWindow)) michael@0: return; michael@0: michael@0: let tab = getTabForBrowser(browser); michael@0: if (tab === null) { michael@0: let rawTab = getRawTabForBrowser(browser); michael@0: michael@0: // create a Tab instance for this new tab michael@0: tab = addTab(Tab(rawTab)); michael@0: } michael@0: michael@0: tabNS(tab).opened = true; michael@0: michael@0: tab.on('ready', function() emit(gTabs, 'ready', tab)); michael@0: tab.once('close', onTabClose); michael@0: michael@0: tab.on('pageshow', function(_tab, persisted) michael@0: emit(gTabs, 'pageshow', tab, persisted)); michael@0: michael@0: emit(tab, 'open', tab); michael@0: emit(gTabs, 'open', tab); michael@0: } michael@0: michael@0: // TabSelect michael@0: function onTabSelect(event) { michael@0: let browser = event.target; michael@0: michael@0: // Eventually ignore private tabs michael@0: if (ignoreWindow(browser.contentWindow)) michael@0: return; michael@0: michael@0: // Set value whenever new tab becomes active. michael@0: let tab = getTabForBrowser(browser); michael@0: emit(tab, 'activate', tab); michael@0: emit(gTabs, 'activate', tab); michael@0: michael@0: for each (let t in gTabs) { michael@0: if (t === tab) continue; michael@0: emit(t, 'deactivate', t); michael@0: emit(gTabs, 'deactivate', t); michael@0: } michael@0: } michael@0: michael@0: // TabClose michael@0: function onTabClose(tab) { michael@0: removeTab(tab); michael@0: emit(gTabs, EVENTS.close.name, tab); michael@0: }