diff options
Diffstat (limited to 'tools/addon-sdk-1.12/lib/sdk/tabs')
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/common.js | 23 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/events.js | 30 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/helpers.js | 17 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/namespace.js | 9 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/observer.js | 99 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/tab-fennec.js | 141 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/tab-firefox.js | 201 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/tab.js | 21 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/tabs-firefox.js | 26 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/tabs.js | 21 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/utils.js | 222 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/tabs/worker.js | 17 |
12 files changed, 827 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/common.js b/tools/addon-sdk-1.12/lib/sdk/tabs/common.js new file mode 100644 index 0000000..dd5bb22 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/common.js @@ -0,0 +1,23 @@ +/* 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 { validateOptions } = require('../deprecated/api-utils'); + +function Options(options) { + if ('string' === typeof options) + options = { url: options }; + + return validateOptions(options, { + url: { is: ["string"] }, + inBackground: { is: ["undefined", "boolean"] }, + isPinned: { is: ["undefined", "boolean"] }, + onOpen: { is: ["undefined", "function"] }, + onClose: { is: ["undefined", "function"] }, + onReady: { is: ["undefined", "function"] }, + onActivate: { is: ["undefined", "function"] }, + onDeactivate: { is: ["undefined", "function"] } + }); +} +exports.Options = Options; diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/events.js b/tools/addon-sdk-1.12/lib/sdk/tabs/events.js new file mode 100644 index 0000000..eb99f40 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/events.js @@ -0,0 +1,30 @@ +/* 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"; + +module.metadata = { + "stability": "unstable" +}; + +const ON_PREFIX = "on"; +const TAB_PREFIX = "Tab"; + +const EVENTS = { + ready: "DOMContentLoaded", + open: "TabOpen", + close: "TabClose", + activate: "TabSelect", + deactivate: null, + pinned: "TabPinned", + unpinned: "TabUnpinned" +} +exports.EVENTS = EVENTS; + +Object.keys(EVENTS).forEach(function(name) { + EVENTS[name] = { + name: name, + listener: ON_PREFIX + name.charAt(0).toUpperCase() + name.substr(1), + dom: EVENTS[name] + } +}); diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/helpers.js b/tools/addon-sdk-1.12/lib/sdk/tabs/helpers.js new file mode 100644 index 0000000..aaff5cb --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/helpers.js @@ -0,0 +1,17 @@ +/* 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 { getTabForContentWindow } = require('./utils'); +const { Tab } = require('./tab'); + +function getTabForWindow(win) { + let tab = getTabForContentWindow(win); + // We were unable to find the related tab! + if (!tab) + return null; + + return Tab({ tab: tab }); +} +exports.getTabForWindow = getTabForWindow; diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/namespace.js b/tools/addon-sdk-1.12/lib/sdk/tabs/namespace.js new file mode 100644 index 0000000..d359cee --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/namespace.js @@ -0,0 +1,9 @@ +/* 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'; + +let { ns } = require('../core/namespace'); + +exports.tabsNS = ns(); +exports.tabNS = ns(); diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/observer.js b/tools/addon-sdk-1.12/lib/sdk/tabs/observer.js new file mode 100644 index 0000000..19a048c --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/observer.js @@ -0,0 +1,99 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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'; + +module.metadata = { + "stability": "unstable" +}; + +const { EventEmitterTrait: EventEmitter } = require("../deprecated/events"); +const { DOMEventAssembler } = require("../deprecated/events/assembler"); +const { Trait } = require("../deprecated/light-traits"); +const { getActiveTab, getTabs, getTabContainer } = require("./utils"); +const { browserWindowIterator } = require("../deprecated/window-utils"); +const { isBrowser } = require('../window/utils'); +const { observer: windowObserver } = require("../windows/observer"); + +const EVENTS = { + "TabOpen": "open", + "TabClose": "close", + "TabSelect": "select", + "TabMove": "move", + "TabPinned": "pinned", + "TabUnpinned": "unpinned" +}; + + +// Event emitter objects used to register listeners and emit events on them +// when they occur. +const observer = Trait.compose(DOMEventAssembler, EventEmitter).create({ + /** + * Method is implemented by `EventEmitter` and is used just for emitting + * events on registered listeners. + */ + _emit: Trait.required, + /** + * Events that are supported and emitted by the module. + */ + supportedEventsTypes: Object.keys(EVENTS), + /** + * Function handles all the supported events on all the windows that are + * observed. Method is used to proxy events to the listeners registered on + * this event emitter. + * @param {Event} event + * Keyboard event being emitted. + */ + handleEvent: function handleEvent(event) { + this._emit(EVENTS[event.type], event.target, event); + } +}); + +// Currently Gecko does not dispatch any event on the previously selected +// tab before / after "TabSelect" is dispatched. In order to work around this +// limitation we keep track of selected tab and emit "deactivate" event with +// that before emitting "activate" on selected tab. +var selectedTab = null; +function onTabSelect(tab) { + if (selectedTab !== tab) { + if (selectedTab) observer._emit('deactivate', selectedTab); + if (tab) observer._emit('activate', selectedTab = tab); + } +}; +observer.on('select', onTabSelect); + +// We also observe opening / closing windows in order to add / remove it's +// containers to the observed list. +function onWindowOpen(chromeWindow) { + if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window. + observer.observe(getTabContainer(chromeWindow)); +} +windowObserver.on("open", onWindowOpen); + +function onWindowClose(chromeWindow) { + if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window. + // Bug 751546: Emit `deactivate` event on window close immediatly + // Otherwise we are going to face "dead object" exception on `select` event + if (getActiveTab(chromeWindow) == selectedTab) { + observer._emit("deactivate", selectedTab); + selectedTab = null; + } + observer.ignore(getTabContainer(chromeWindow)); +} +windowObserver.on("close", onWindowClose); + + +// Currently gecko does not dispatches "TabSelect" events when different +// window gets activated. To work around this limitation we emulate "select" +// event for this case. +windowObserver.on("activate", function onWindowActivate(chromeWindow) { + if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window. + observer._emit("select", getActiveTab(chromeWindow)); +}); + +// We should synchronize state, since probably we already have at least one +// window open. +for each (let window in browserWindowIterator()) onWindowOpen(window); + +exports.observer = observer; diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/tab-fennec.js b/tools/addon-sdk-1.12/lib/sdk/tabs/tab-fennec.js new file mode 100644 index 0000000..42bf91b --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/tab-fennec.js @@ -0,0 +1,141 @@ +/* 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 { Cc, Ci } = require('chrome'); +const { Class } = require('../core/heritage'); +const { tabNS } = require('./namespace'); +const { EventTarget } = require('../event/target'); +const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, + setTabURL, getOwnerWindow, getTabContentType } = require('./utils'); +const { emit } = require('../event/core'); +const { when: unload } = require('../system/unload'); + +const { EVENTS } = require('./events'); +const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec'; + +const Tab = Class({ + extends: EventTarget, + initialize: function initialize(options) { + options = options.tab ? options : { tab: options }; + + EventTarget.prototype.initialize.call(this, options); + let tabInternals = tabNS(this); + + tabInternals.window = options.window || getOwnerWindow(options.tab); + tabInternals.tab = options.tab; + }, + + /** + * The title of the page currently loaded in the tab. + * Changing this property changes an actual title. + * @type {String} + */ + get title() getTabTitle(tabNS(this).tab), + set title(title) setTabTitle(tabNS(this).tab, title), + + /** + * Location of the page currently loaded in this tab. + * Changing this property will loads page under under the specified location. + * @type {String} + */ + get url() getTabURL(tabNS(this).tab), + set url(url) setTabURL(tabNS(this).tab, url), + + /** + * URI of the favicon for the page currently loaded in this tab. + * @type {String} + */ + get favicon() { + // TODO: provide the real favicon when it is available + console.error(ERR_FENNEC_MSG); + + // return 16x16 blank default + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAEklEQVQ4jWNgGAWjYBSMAggAAAQQAAF/TXiOAAAAAElFTkSuQmCC'; + }, + + getThumbnail: function() { + // TODO: implement! + console.error(ERR_FENNEC_MSG); + + // return 80x45 blank default + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC'; + }, + + /** + * The index of the tab relative to other tabs in the application window. + * Changing this property will change order of the actual position of the tab. + * @type {Number} + */ + get index() { + let tabs = tabNS(this).window.BrowserApp.tabs; + let tab = tabNS(this).tab; + for (var i = tabs.length; i >= 0; i--) { + if (tabs[i] === tab) + return i; + } + return null; + }, + set index(value) { + console.error(ERR_FENNEC_MSG); // TODO + }, + + /** + * Whether or not tab is pinned (Is an app-tab). + * @type {Boolean} + */ + get isPinned() { + console.error(ERR_FENNEC_MSG); // TODO + return false; // TODO + }, + pin: function pin() { + console.error(ERR_FENNEC_MSG); // TODO + }, + unpin: function unpin() { + console.error(ERR_FENNEC_MSG); // TODO + }, + + /** + * Returns the MIME type that the document loaded in the tab is being + * rendered as. + * @type {String} + */ + get contentType() getTabContentType(tabNS(this).tab), + + /** + * Create a worker for this tab, first argument is options given to Worker. + * @type {Worker} + */ + attach: function attach(options) { + // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946 + // TODO: fix this circular dependency + let { Worker } = require('./worker'); + return Worker(options, tabNS(this).tab.browser.contentWindow); + }, + + /** + * Make this tab active. + */ + activate: function activate() { + activateTab(tabNS(this).tab, tabNS(this).window); + }, + + /** + * Close the tab + */ + close: function close(callback) { + if (callback) + this.once(EVENTS.close.name, callback); + + closeTab(tabNS(this).tab); + }, + + /** + * Reload the tab + */ + reload: function reload() { + tabNS(this).tab.browser.reload(); + } +}); +exports.Tab = Tab; diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/tab-firefox.js b/tools/addon-sdk-1.12/lib/sdk/tabs/tab-firefox.js new file mode 100644 index 0000000..5a36302 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/tab-firefox.js @@ -0,0 +1,201 @@ +/* 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 { Trait } = require("../deprecated/traits"); +const { EventEmitter } = require("../deprecated/events"); +const { defer } = require("../lang/functional"); +const { EVENTS } = require("./events"); +const { getThumbnailURIForWindow } = require("../content/thumbnail"); +const { getFaviconURIForLocation } = require("../io/data"); +const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle, + getTabURL, setTabURL, getTabContentType } = require('./utils'); + +// Array of the inner instances of all the wrapped tabs. +const TABS = []; + +/** + * Trait used to create tab wrappers. + */ +const TabTrait = Trait.compose(EventEmitter, { + on: Trait.required, + _emit: Trait.required, + /** + * Tab DOM element that is being wrapped. + */ + _tab: null, + /** + * Window wrapper whose tab this object represents. + */ + window: null, + constructor: function Tab(options) { + this._onReady = this._onReady.bind(this); + this._tab = options.tab; + let window = this.window = options.window || getOwnerWindow(this._tab); + + // Setting event listener if was passed. + for each (let type in EVENTS) { + let listener = options[type.listener]; + if (listener) + this.on(type.name, options[type.listener]); + if ('ready' != type.name) // window spreads this event. + window.tabs.on(type.name, this._onEvent.bind(this, type.name)); + } + + this.on(EVENTS.close.name, this.destroy.bind(this)); + this._browser.addEventListener(EVENTS.ready.dom, this._onReady, true); + + if (options.isPinned) + this.pin(); + + // Since we will have to identify tabs by a DOM elements facade function + // is used as constructor that collects all the instances and makes sure + // that they more then one wrapper is not created per tab. + return this; + }, + destroy: function destroy() { + this._removeAllListeners(); + this._browser.removeEventListener(EVENTS.ready.dom, this._onReady, true); + }, + + /** + * Internal listener that emits public event 'ready' when the page of this + * tab is loaded. + */ + _onReady: function _onReady(event) { + // IFrames events will bubble so we need to ignore those. + if (event.target == this._contentDocument) + this._emit(EVENTS.ready.name, this._public); + }, + /** + * Internal tab event router. Window will emit tab related events for all it's + * tabs, this listener will propagate all the events for this tab to it's + * listeners. + */ + _onEvent: function _onEvent(type, tab) { + if (tab == this._public) + this._emit(type, tab); + }, + /** + * Browser DOM element where page of this tab is currently loaded. + */ + get _browser() getBrowserForTab(this._tab), + /** + * Window DOM element containing this tab. + */ + get _window() getOwnerWindow(this._tab), + /** + * Document object of the page that is currently loaded in this tab. + */ + get _contentDocument() this._browser.contentDocument, + /** + * Window object of the page that is currently loaded in this tab. + */ + get _contentWindow() this._browser.contentWindow, + + /** + * The title of the page currently loaded in the tab. + * Changing this property changes an actual title. + * @type {String} + */ + get title() getTabTitle(this._tab), + set title(title) setTabTitle(this._tab, title), + + /** + * Returns the MIME type that the document loaded in the tab is being + * rendered as. + * @type {String} + */ + get contentType() getTabContentType(this._tab), + + /** + * Location of the page currently loaded in this tab. + * Changing this property will loads page under under the specified location. + * @type {String} + */ + get url() getTabURL(this._tab), + set url(url) setTabURL(this._tab, url), + /** + * URI of the favicon for the page currently loaded in this tab. + * @type {String} + */ + get favicon() getFaviconURIForLocation(this.url), + /** + * The CSS style for the tab + */ + get style() null, // TODO + /** + * The index of the tab relative to other tabs in the application window. + * Changing this property will change order of the actual position of the tab. + * @type {Number} + */ + get index() + this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument), + set index(value) this._window.gBrowser.moveTabTo(this._tab, value), + /** + * Thumbnail data URI of the page currently loaded in this tab. + * @type {String} + */ + getThumbnail: function getThumbnail() + getThumbnailURIForWindow(this._contentWindow), + /** + * Whether or not tab is pinned (Is an app-tab). + * @type {Boolean} + */ + get isPinned() this._tab.pinned, + pin: function pin() { + this._window.gBrowser.pinTab(this._tab); + }, + unpin: function unpin() { + this._window.gBrowser.unpinTab(this._tab); + }, + + /** + * Create a worker for this tab, first argument is options given to Worker. + * @type {Worker} + */ + attach: function attach(options) { + // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946 + // TODO: fix this circular dependency + let { Worker } = require('./worker'); + return Worker(options, this._contentWindow); + }, + + /** + * Make this tab active. + * Please note: That this function is called asynchronous since in E10S that + * will be the case. Besides this function is called from a constructor where + * we would like to return instance before firing a 'TabActivated' event. + */ + activate: defer(function activate() { + activateTab(this._tab); + }), + /** + * Close the tab + */ + close: function close(callback) { + if (callback) + this.once(EVENTS.close.name, callback); + this._window.gBrowser.removeTab(this._tab); + }, + /** + * Reload the tab + */ + reload: function reload() { + this._window.gBrowser.reloadTab(this._tab); + } +}); + +function Tab(options) { + let chromeTab = options.tab; + for each (let tab in TABS) { + if (chromeTab == tab._tab) + return tab._public; + } + let tab = TabTrait(options); + TABS.push(tab); + return tab._public; +} +Tab.prototype = TabTrait.prototype; +exports.Tab = Tab; diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/tab.js b/tools/addon-sdk-1.12/lib/sdk/tabs/tab.js new file mode 100644 index 0000000..420baee --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/tab.js @@ -0,0 +1,21 @@ +/* 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'; + +module.metadata = { + 'stability': 'unstable' +}; + +if (require('../system/xul-app').is('Firefox')) { + module.exports = require('./tab-firefox'); +} +else if (require('../system/xul-app').is('Fennec')) { + module.exports = require('./tab-fennec'); +} +else { + throw new Error([ + 'The tabs module currently supports only Firefox & Fennec. In the future', + ' we would like it to support other applications, however.' + ].join('')); +} diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/tabs-firefox.js b/tools/addon-sdk-1.12/lib/sdk/tabs/tabs-firefox.js new file mode 100644 index 0000000..92834c2 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/tabs-firefox.js @@ -0,0 +1,26 @@ +/* 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'; + +// TODO: BUG 792670 - remove dependency below +const { browserWindows } = require('../windows'); +const { tabs } = require('../windows/tabs-firefox'); + +Object.defineProperties(tabs, { + open: { value: function open(options) { + if (options.inNewWindow) + // `tabs` option is under review and may be removed. + return browserWindows.open({ tabs: [ options ] }); + // Open in active window if new window was not required. + return browserWindows.activeWindow.tabs.open(options); + }} +}); + +// Workaround for bug 674195. Freezing objects from other compartments fail, +// so we use `Object.freeze` from the same component as objects +// `hasOwnProperty`. Since `hasOwnProperty` here will be from other component +// we override it to support our workaround. +module.exports = Object.create(tabs, { + isPrototypeOf: { value: Object.prototype.isPrototypeOf } +}); diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/tabs.js b/tools/addon-sdk-1.12/lib/sdk/tabs/tabs.js new file mode 100644 index 0000000..fcb3868 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/tabs.js @@ -0,0 +1,21 @@ +/* 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'; + +module.metadata = { + 'stability': 'unstable' +}; + +if (require('../system/xul-app').is('Firefox')) { + module.exports = require('./tabs-firefox'); +} +else if (require('../system/xul-app').is('Fennec')) { + module.exports = require('../windows/tabs-fennec').tabs; +} +else { + throw new Error([ + 'The tabs module currently supports only Firefox & Fennec. In the future', + ' we would like it to support other applications, however.' + ].join('')); +} diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/utils.js b/tools/addon-sdk-1.12/lib/sdk/tabs/utils.js new file mode 100644 index 0000000..d923e4b --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/utils.js @@ -0,0 +1,222 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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'; + +module.metadata = { + 'stability': 'unstable' +}; + +const { defer } = require("../lang/functional"); +const { windows } = require('../window/utils'); +const { Ci } = require('chrome'); + +function activateTab(tab, window) { + let gBrowser = getTabBrowserForTab(tab); + + // normal case + if (gBrowser) { + gBrowser.selectedTab = tab; + } + // fennec ? + else if (window && window.BrowserApp) { + window.BrowserApp.selectTab(tab); + } + return null; +} +exports.activateTab = activateTab; + +function getTabBrowser(window) { + return window.gBrowser; +} +exports.getTabBrowser = getTabBrowser; + +function getTabContainer(window) { + return getTabBrowser(window).tabContainer; +} +exports.getTabContainer = getTabContainer; + +function getTabs(window) { + // fennec + if (window.BrowserApp) + return window.BrowserApp.tabs; + + // firefox - default + return Array.slice(getTabContainer(window).children); +} +exports.getTabs = getTabs; + +function getActiveTab(window) { + return window.gBrowser.selectedTab; +} +exports.getActiveTab = getActiveTab; + +function getOwnerWindow(tab) { + // normal case + if (tab.ownerDocument) + return tab.ownerDocument.defaultView; + + // try fennec case + return getWindowHoldingTab(tab); +} +exports.getOwnerWindow = getOwnerWindow; + +// fennec +function getWindowHoldingTab(rawTab) { + for each (let window in windows()) { + // this function may be called when not using fennec + if (!window.BrowserApp) + continue; + + for each (let tab in window.BrowserApp.tabs) { + if (tab === rawTab) + return window; + } + } + + return null; +} + +function openTab(window, url, options) { + options = options || {}; + + // fennec? + if (window.BrowserApp) { + return window.BrowserApp.addTab(url, { + selected: options.inBackground ? false : true, + pinned: options.isPinned || false + }); + } + return window.gBrowser.addTab(url); +}; +exports.openTab = openTab; + +function isTabOpen(tab) { + // try normal case then fennec case + return !!((tab.linkedBrowser) || getWindowHoldingTab(tab)); +} +exports.isTabOpen = isTabOpen; + +function closeTab(tab) { + let gBrowser = getTabBrowserForTab(tab); + // normal case? + if (gBrowser) + return gBrowser.removeTab(tab); + + let window = getWindowHoldingTab(tab); + // fennec? + if (window && window.BrowserApp) + return window.BrowserApp.closeTab(tab); + return null; +} +exports.closeTab = closeTab; + +function getURI(tab) { + if (tab.browser) // fennec + return tab.browser.currentURI.spec; + return tab.linkedBrowser.currentURI.spec; +} +exports.getURI = getURI; + +function getTabBrowserForTab(tab) { + let outerWin = getOwnerWindow(tab); + if (outerWin) + return getOwnerWindow(tab).gBrowser; + return null; +} +exports.getTabBrowserForTab = getTabBrowserForTab; + +function getBrowserForTab(tab) { + if (tab.browser) // fennec + return tab.browser; + + return tab.linkedBrowser; +} +exports.getBrowserForTab = getBrowserForTab; + +function getTabTitle(tab) { + return getBrowserForTab(tab).contentDocument.title || tab.label || ""; +} +exports.getTabTitle = getTabTitle; + +function setTabTitle(tab, title) { + title = String(title); + if (tab.browser) + tab.browser.contentDocument.title = title; + tab.label = String(title); +} +exports.setTabTitle = setTabTitle; + +function getTabContentWindow(tab) { + return getBrowserForTab(tab).contentWindow; +} +exports.getTabContentWindow = getTabContentWindow; + +function getTabForContentWindow(window) { + // Retrieve the topmost frame container. It can be either <xul:browser>, + // <xul:iframe/> or <html:iframe/>. But in our case, it should be xul:browser. + let browser = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler; + // Is null for toplevel documents + if (!browser) + return false; + // Retrieve the owner window, should be browser.xul one + let chromeWindow = browser.ownerDocument.defaultView; + + // Ensure that it is top-level browser window. + // We need extra checks because of Mac hidden window that has a broken + // `gBrowser` global attribute. + if ('gBrowser' in chromeWindow && chromeWindow.gBrowser && + 'browsers' in chromeWindow.gBrowser) { + // Looks like we are on Firefox Desktop + // Then search for the position in tabbrowser in order to get the tab object + let browsers = chromeWindow.gBrowser.browsers; + let i = browsers.indexOf(browser); + if (i !== -1) + return chromeWindow.gBrowser.tabs[i]; + return null; + } + else if ('BrowserApp' in chromeWindow) { + // Looks like we are on Firefox Mobile + return chromeWindow.BrowserApp.getTabForWindow(window) + } + + return null; +} +exports.getTabForContentWindow = getTabForContentWindow; + +function getTabURL(tab) { + if (tab.browser) // fennec + return String(tab.browser.currentURI.spec); + return String(getBrowserForTab(tab).currentURI.spec); +} +exports.getTabURL = getTabURL; + +function setTabURL(tab, url) { + url = String(url); + if (tab.browser) + return tab.browser.loadURI(url); + return getBrowserForTab(tab).loadURI(url); +} +// "TabOpen" event is fired when it's still "about:blank" is loaded in the +// changing `location` property of the `contentDocument` has no effect since +// seems to be either ignored or overridden by internal listener, there for +// location change is enqueued for the next turn of event loop. +exports.setTabURL = defer(setTabURL); + +function getTabContentType(tab) { + return getBrowserForTab(tab).contentDocument.contentType; +} +exports.getTabContentType = getTabContentType; + +function getSelectedTab(window) { + if (window.BrowserApp) // fennec? + return window.BrowserApp.selectedTab; + if (window.gBrowser) + return window.gBrowser.selectedTab; + return null; +} +exports.getSelectedTab = getSelectedTab; diff --git a/tools/addon-sdk-1.12/lib/sdk/tabs/worker.js b/tools/addon-sdk-1.12/lib/sdk/tabs/worker.js new file mode 100644 index 0000000..d2ba336 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/tabs/worker.js @@ -0,0 +1,17 @@ +/* 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 ContentWorker = require('../content/worker').Worker; + +function Worker(options, window) { + options.window = window; + + let worker = ContentWorker(options); + worker.once("detach", function detach() { + worker.destroy(); + }); + return worker; +} +exports.Worker = Worker;
\ No newline at end of file |