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.

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

mercurial