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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 'use strict';
michael@0 5
michael@0 6 const { Trait } = require("../deprecated/traits");
michael@0 7 const { EventEmitter } = require("../deprecated/events");
michael@0 8 const { defer } = require("../lang/functional");
michael@0 9 const { has } = require("../util/array");
michael@0 10 const { EVENTS } = require("./events");
michael@0 11 const { getThumbnailURIForWindow } = require("../content/thumbnail");
michael@0 12 const { getFaviconURIForLocation } = require("../io/data");
michael@0 13 const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle,
michael@0 14 getTabURL, setTabURL, getTabContentType, getTabId } = require('./utils');
michael@0 15 const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
michael@0 16 const viewNS = require('../core/namespace').ns();
michael@0 17 const { deprecateUsage } = require('../util/deprecate');
michael@0 18 const { getURL } = require('../url/utils');
michael@0 19 const { viewFor } = require('../view/core');
michael@0 20
michael@0 21 // Array of the inner instances of all the wrapped tabs.
michael@0 22 const TABS = [];
michael@0 23
michael@0 24 /**
michael@0 25 * Trait used to create tab wrappers.
michael@0 26 */
michael@0 27 const TabTrait = Trait.compose(EventEmitter, {
michael@0 28 on: Trait.required,
michael@0 29 _emit: Trait.required,
michael@0 30 /**
michael@0 31 * Tab DOM element that is being wrapped.
michael@0 32 */
michael@0 33 _tab: null,
michael@0 34 /**
michael@0 35 * Window wrapper whose tab this object represents.
michael@0 36 */
michael@0 37 window: null,
michael@0 38 constructor: function Tab(options) {
michael@0 39 this._onReady = this._onReady.bind(this);
michael@0 40 this._onLoad = this._onLoad.bind(this);
michael@0 41 this._onPageShow = this._onPageShow.bind(this);
michael@0 42 this._tab = options.tab;
michael@0 43 // TODO: Remove this dependency
michael@0 44 let window = this.window = options.window || require('../windows').BrowserWindow({ window: getOwnerWindow(this._tab) });
michael@0 45
michael@0 46 // Setting event listener if was passed.
michael@0 47 for each (let type in EVENTS) {
michael@0 48 let listener = options[type.listener];
michael@0 49 if (listener) {
michael@0 50 this.on(type.name, options[type.listener]);
michael@0 51 }
michael@0 52 // window spreads this event.
michael@0 53 if (!has(['ready', 'load', 'pageshow'], (type.name)))
michael@0 54 window.tabs.on(type.name, this._onEvent.bind(this, type.name));
michael@0 55 }
michael@0 56
michael@0 57 this.on(EVENTS.close.name, this.destroy.bind(this));
michael@0 58
michael@0 59 this._browser.addEventListener(EVENTS.ready.dom, this._onReady, true);
michael@0 60 this._browser.addEventListener(EVENTS.load.dom, this._onLoad, true);
michael@0 61 this._browser.addEventListener(EVENTS.pageshow.dom, this._onPageShow, true);
michael@0 62
michael@0 63 if (options.isPinned)
michael@0 64 this.pin();
michael@0 65
michael@0 66 viewNS(this._public).tab = this._tab;
michael@0 67 getPBOwnerWindow.implement(this._public, getChromeTab);
michael@0 68 viewFor.implement(this._public, getTabView);
michael@0 69
michael@0 70 // Add tabs to getURL method
michael@0 71 getURL.implement(this._public, (function (obj) this._public.url).bind(this));
michael@0 72
michael@0 73 // Since we will have to identify tabs by a DOM elements facade function
michael@0 74 // is used as constructor that collects all the instances and makes sure
michael@0 75 // that they more then one wrapper is not created per tab.
michael@0 76 return this;
michael@0 77 },
michael@0 78 destroy: function destroy() {
michael@0 79 this._removeAllListeners();
michael@0 80 if (this._tab) {
michael@0 81 let browser = this._browser;
michael@0 82 // The tab may already be removed from DOM -or- not yet added
michael@0 83 if (browser) {
michael@0 84 browser.removeEventListener(EVENTS.ready.dom, this._onReady, true);
michael@0 85 browser.removeEventListener(EVENTS.load.dom, this._onLoad, true);
michael@0 86 browser.removeEventListener(EVENTS.pageshow.dom, this._onPageShow, true);
michael@0 87 }
michael@0 88 this._tab = null;
michael@0 89 TABS.splice(TABS.indexOf(this), 1);
michael@0 90 }
michael@0 91 },
michael@0 92
michael@0 93 /**
michael@0 94 * Internal listener that emits public event 'ready' when the page of this
michael@0 95 * tab is loaded, from DOMContentLoaded
michael@0 96 */
michael@0 97 _onReady: function _onReady(event) {
michael@0 98 // IFrames events will bubble so we need to ignore those.
michael@0 99 if (event.target == this._contentDocument)
michael@0 100 this._emit(EVENTS.ready.name, this._public);
michael@0 101 },
michael@0 102
michael@0 103 /**
michael@0 104 * Internal listener that emits public event 'load' when the page of this
michael@0 105 * tab is loaded, for triggering on non-HTML content, bug #671305
michael@0 106 */
michael@0 107 _onLoad: function _onLoad(event) {
michael@0 108 // IFrames events will bubble so we need to ignore those.
michael@0 109 if (event.target == this._contentDocument) {
michael@0 110 this._emit(EVENTS.load.name, this._public);
michael@0 111 }
michael@0 112 },
michael@0 113
michael@0 114 /**
michael@0 115 * Internal listener that emits public event 'pageshow' when the page of this
michael@0 116 * tab is loaded from cache, bug #671305
michael@0 117 */
michael@0 118 _onPageShow: function _onPageShow(event) {
michael@0 119 // IFrames events will bubble so we need to ignore those.
michael@0 120 if (event.target == this._contentDocument) {
michael@0 121 this._emit(EVENTS.pageshow.name, this._public, event.persisted);
michael@0 122 }
michael@0 123 },
michael@0 124 /**
michael@0 125 * Internal tab event router. Window will emit tab related events for all it's
michael@0 126 * tabs, this listener will propagate all the events for this tab to it's
michael@0 127 * listeners.
michael@0 128 */
michael@0 129 _onEvent: function _onEvent(type, tab) {
michael@0 130 if (viewNS(tab).tab == this._tab)
michael@0 131 this._emit(type, tab);
michael@0 132 },
michael@0 133 /**
michael@0 134 * Browser DOM element where page of this tab is currently loaded.
michael@0 135 */
michael@0 136 get _browser() getBrowserForTab(this._tab),
michael@0 137 /**
michael@0 138 * Window DOM element containing this tab.
michael@0 139 */
michael@0 140 get _window() getOwnerWindow(this._tab),
michael@0 141 /**
michael@0 142 * Document object of the page that is currently loaded in this tab.
michael@0 143 */
michael@0 144 get _contentDocument() this._browser.contentDocument,
michael@0 145 /**
michael@0 146 * Window object of the page that is currently loaded in this tab.
michael@0 147 */
michael@0 148 get _contentWindow() this._browser.contentWindow,
michael@0 149
michael@0 150 /**
michael@0 151 * Unique id for the tab, actually maps to tab.linkedPanel but with some munging.
michael@0 152 */
michael@0 153 get id() this._tab ? getTabId(this._tab) : undefined,
michael@0 154
michael@0 155 /**
michael@0 156 * The title of the page currently loaded in the tab.
michael@0 157 * Changing this property changes an actual title.
michael@0 158 * @type {String}
michael@0 159 */
michael@0 160 get title() this._tab ? getTabTitle(this._tab) : undefined,
michael@0 161 set title(title) this._tab && setTabTitle(this._tab, title),
michael@0 162
michael@0 163 /**
michael@0 164 * Returns the MIME type that the document loaded in the tab is being
michael@0 165 * rendered as.
michael@0 166 * @type {String}
michael@0 167 */
michael@0 168 get contentType() this._tab ? getTabContentType(this._tab) : undefined,
michael@0 169
michael@0 170 /**
michael@0 171 * Location of the page currently loaded in this tab.
michael@0 172 * Changing this property will loads page under under the specified location.
michael@0 173 * @type {String}
michael@0 174 */
michael@0 175 get url() this._tab ? getTabURL(this._tab) : undefined,
michael@0 176 set url(url) this._tab && setTabURL(this._tab, url),
michael@0 177 /**
michael@0 178 * URI of the favicon for the page currently loaded in this tab.
michael@0 179 * @type {String}
michael@0 180 */
michael@0 181 get favicon() {
michael@0 182 deprecateUsage(
michael@0 183 'tab.favicon is deprecated, ' +
michael@0 184 'please use require("sdk/places/favicon").getFavicon instead.'
michael@0 185 );
michael@0 186 return this._tab ? getFaviconURIForLocation(this.url) : undefined
michael@0 187 },
michael@0 188 /**
michael@0 189 * The CSS style for the tab
michael@0 190 */
michael@0 191 get style() null, // TODO
michael@0 192 /**
michael@0 193 * The index of the tab relative to other tabs in the application window.
michael@0 194 * Changing this property will change order of the actual position of the tab.
michael@0 195 * @type {Number}
michael@0 196 */
michael@0 197 get index()
michael@0 198 this._tab ?
michael@0 199 this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument) :
michael@0 200 undefined,
michael@0 201 set index(value)
michael@0 202 this._tab && this._window.gBrowser.moveTabTo(this._tab, value),
michael@0 203 /**
michael@0 204 * Thumbnail data URI of the page currently loaded in this tab.
michael@0 205 * @type {String}
michael@0 206 */
michael@0 207 getThumbnail: function getThumbnail()
michael@0 208 this._tab ? getThumbnailURIForWindow(this._contentWindow) : undefined,
michael@0 209 /**
michael@0 210 * Whether or not tab is pinned (Is an app-tab).
michael@0 211 * @type {Boolean}
michael@0 212 */
michael@0 213 get isPinned() this._tab ? this._tab.pinned : undefined,
michael@0 214 pin: function pin() {
michael@0 215 if (!this._tab)
michael@0 216 return;
michael@0 217 this._window.gBrowser.pinTab(this._tab);
michael@0 218 },
michael@0 219 unpin: function unpin() {
michael@0 220 if (!this._tab)
michael@0 221 return;
michael@0 222 this._window.gBrowser.unpinTab(this._tab);
michael@0 223 },
michael@0 224
michael@0 225 /**
michael@0 226 * Create a worker for this tab, first argument is options given to Worker.
michael@0 227 * @type {Worker}
michael@0 228 */
michael@0 229 attach: function attach(options) {
michael@0 230 if (!this._tab)
michael@0 231 return;
michael@0 232 // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946
michael@0 233 // TODO: fix this circular dependency
michael@0 234 let { Worker } = require('./worker');
michael@0 235 return Worker(options, this._contentWindow);
michael@0 236 },
michael@0 237
michael@0 238 /**
michael@0 239 * Make this tab active.
michael@0 240 * Please note: That this function is called asynchronous since in E10S that
michael@0 241 * will be the case. Besides this function is called from a constructor where
michael@0 242 * we would like to return instance before firing a 'TabActivated' event.
michael@0 243 */
michael@0 244 activate: defer(function activate() {
michael@0 245 if (!this._tab)
michael@0 246 return;
michael@0 247 activateTab(this._tab);
michael@0 248 }),
michael@0 249 /**
michael@0 250 * Close the tab
michael@0 251 */
michael@0 252 close: function close(callback) {
michael@0 253 // Bug 699450: the tab may already have been detached
michael@0 254 if (!this._tab || !this._tab.parentNode) {
michael@0 255 if (callback)
michael@0 256 callback();
michael@0 257 return;
michael@0 258 }
michael@0 259 if (callback)
michael@0 260 this.once(EVENTS.close.name, callback);
michael@0 261 this._window.gBrowser.removeTab(this._tab);
michael@0 262 },
michael@0 263 /**
michael@0 264 * Reload the tab
michael@0 265 */
michael@0 266 reload: function reload() {
michael@0 267 if (!this._tab)
michael@0 268 return;
michael@0 269 this._window.gBrowser.reloadTab(this._tab);
michael@0 270 }
michael@0 271 });
michael@0 272
michael@0 273 function getChromeTab(tab) {
michael@0 274 return getOwnerWindow(viewNS(tab).tab);
michael@0 275 }
michael@0 276
michael@0 277 // Implement `viewFor` polymorphic function for the Tab
michael@0 278 // instances.
michael@0 279 const getTabView = tab => viewNS(tab).tab;
michael@0 280
michael@0 281 function Tab(options, existingOnly) {
michael@0 282 let chromeTab = options.tab;
michael@0 283 for each (let tab in TABS) {
michael@0 284 if (chromeTab == tab._tab)
michael@0 285 return tab._public;
michael@0 286 }
michael@0 287 // If called asked to return only existing wrapper,
michael@0 288 // we should return null here as no matching Tab object has been found
michael@0 289 if (existingOnly)
michael@0 290 return null;
michael@0 291
michael@0 292 let tab = TabTrait(options);
michael@0 293 TABS.push(tab);
michael@0 294 return tab._public;
michael@0 295 }
michael@0 296 Tab.prototype = TabTrait.prototype;
michael@0 297 exports.Tab = Tab;

mercurial