observer.js 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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';
  5. module.metadata = {
  6. "stability": "unstable"
  7. };
  8. const { EventEmitterTrait: EventEmitter } = require("../deprecated/events");
  9. const { DOMEventAssembler } = require("../deprecated/events/assembler");
  10. const { Trait } = require("../deprecated/light-traits");
  11. const { getActiveTab, getTabs, getTabContainer } = require("./utils");
  12. const { browserWindowIterator } = require("../deprecated/window-utils");
  13. const { isBrowser } = require('../window/utils');
  14. const { observer: windowObserver } = require("../windows/observer");
  15. const EVENTS = {
  16. "TabOpen": "open",
  17. "TabClose": "close",
  18. "TabSelect": "select",
  19. "TabMove": "move",
  20. "TabPinned": "pinned",
  21. "TabUnpinned": "unpinned"
  22. };
  23. // Event emitter objects used to register listeners and emit events on them
  24. // when they occur.
  25. const observer = Trait.compose(DOMEventAssembler, EventEmitter).create({
  26. /**
  27. * Method is implemented by `EventEmitter` and is used just for emitting
  28. * events on registered listeners.
  29. */
  30. _emit: Trait.required,
  31. /**
  32. * Events that are supported and emitted by the module.
  33. */
  34. supportedEventsTypes: Object.keys(EVENTS),
  35. /**
  36. * Function handles all the supported events on all the windows that are
  37. * observed. Method is used to proxy events to the listeners registered on
  38. * this event emitter.
  39. * @param {Event} event
  40. * Keyboard event being emitted.
  41. */
  42. handleEvent: function handleEvent(event) {
  43. this._emit(EVENTS[event.type], event.target, event);
  44. }
  45. });
  46. // Currently Gecko does not dispatch any event on the previously selected
  47. // tab before / after "TabSelect" is dispatched. In order to work around this
  48. // limitation we keep track of selected tab and emit "deactivate" event with
  49. // that before emitting "activate" on selected tab.
  50. var selectedTab = null;
  51. function onTabSelect(tab) {
  52. if (selectedTab !== tab) {
  53. if (selectedTab) observer._emit('deactivate', selectedTab);
  54. if (tab) observer._emit('activate', selectedTab = tab);
  55. }
  56. };
  57. observer.on('select', onTabSelect);
  58. // We also observe opening / closing windows in order to add / remove it's
  59. // containers to the observed list.
  60. function onWindowOpen(chromeWindow) {
  61. if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window.
  62. observer.observe(getTabContainer(chromeWindow));
  63. }
  64. windowObserver.on("open", onWindowOpen);
  65. function onWindowClose(chromeWindow) {
  66. if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window.
  67. // Bug 751546: Emit `deactivate` event on window close immediatly
  68. // Otherwise we are going to face "dead object" exception on `select` event
  69. if (getActiveTab(chromeWindow) == selectedTab) {
  70. observer._emit("deactivate", selectedTab);
  71. selectedTab = null;
  72. }
  73. observer.ignore(getTabContainer(chromeWindow));
  74. }
  75. windowObserver.on("close", onWindowClose);
  76. // Currently gecko does not dispatches "TabSelect" events when different
  77. // window gets activated. To work around this limitation we emulate "select"
  78. // event for this case.
  79. windowObserver.on("activate", function onWindowActivate(chromeWindow) {
  80. if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window.
  81. observer._emit("select", getActiveTab(chromeWindow));
  82. });
  83. // We should synchronize state, since probably we already have at least one
  84. // window open.
  85. for each (let window in browserWindowIterator()) onWindowOpen(window);
  86. exports.observer = observer;