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;
|