Files
tubestation/addon-sdk/source/lib/sdk/tabs/tab-firefox.js

236 lines
7.1 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 { 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, getTabId } = require('./utils');
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
const viewNS = require('sdk/core/namespace').ns();
// 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;
// TODO: Remove this dependency
let window = this.window = options.window || require('../windows').BrowserWindow({ 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();
viewNS(this._public).tab = this._tab;
getPBOwnerWindow.implement(this._public, getChromeTab);
// 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();
if (this._tab) {
this._browser.removeEventListener(EVENTS.ready.dom, this._onReady, true);
this._tab = null;
TABS.splice(TABS.indexOf(this), 1);
}
},
/**
* 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,
/**
* Unique id for the tab, actually maps to tab.linkedPanel but with some munging.
*/
get id() this._tab ? getTabId(this._tab) : undefined,
/**
* The title of the page currently loaded in the tab.
* Changing this property changes an actual title.
* @type {String}
*/
get title() this._tab ? getTabTitle(this._tab) : undefined,
set title(title) this._tab && setTabTitle(this._tab, title),
/**
* Returns the MIME type that the document loaded in the tab is being
* rendered as.
* @type {String}
*/
get contentType() this._tab ? getTabContentType(this._tab) : undefined,
/**
* Location of the page currently loaded in this tab.
* Changing this property will loads page under under the specified location.
* @type {String}
*/
get url() this._tab ? getTabURL(this._tab) : undefined,
set url(url) this._tab && setTabURL(this._tab, url),
/**
* URI of the favicon for the page currently loaded in this tab.
* @type {String}
*/
get favicon() this._tab ? getFaviconURIForLocation(this.url) : undefined,
/**
* 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._tab ?
this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument) :
undefined,
set index(value)
this._tab && this._window.gBrowser.moveTabTo(this._tab, value),
/**
* Thumbnail data URI of the page currently loaded in this tab.
* @type {String}
*/
getThumbnail: function getThumbnail()
this._tab ? getThumbnailURIForWindow(this._contentWindow) : undefined,
/**
* Whether or not tab is pinned (Is an app-tab).
* @type {Boolean}
*/
get isPinned() this._tab ? this._tab.pinned : undefined,
pin: function pin() {
if (!this._tab)
return;
this._window.gBrowser.pinTab(this._tab);
},
unpin: function unpin() {
if (!this._tab)
return;
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) {
if (!this._tab)
return;
// 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() {
if (!this._tab)
return;
activateTab(this._tab);
}),
/**
* Close the tab
*/
close: function close(callback) {
if (!this._tab)
return;
if (callback)
this.once(EVENTS.close.name, callback);
this._window.gBrowser.removeTab(this._tab);
},
/**
* Reload the tab
*/
reload: function reload() {
if (!this._tab)
return;
this._window.gBrowser.reloadTab(this._tab);
}
});
function getChromeTab(tab) {
return getOwnerWindow(viewNS(tab).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;