| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 | /* 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;
 |