Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1724 from Gozala/detraitify-observers
Browse files Browse the repository at this point in the history
Bug 724632 - Remove traits from observers. r=@erikvold
  • Loading branch information
Gozala committed Nov 21, 2014
2 parents be781bf + c3e37a8 commit 76fcb01
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 111 deletions.
12 changes: 8 additions & 4 deletions lib/sdk/deprecated/events/assembler.js
Expand Up @@ -4,7 +4,7 @@

"use strict";

const { Trait } = require("../light-traits");
const { Class } = require("../../core/heritage");
const { removeListener, on } = require("../../dom/events");

/**
Expand All @@ -15,20 +15,24 @@ const { removeListener, on } = require("../../dom/events");
* `supportedEventsTypes` and function for handling all those events as
* `handleEvent` property.
*/
exports.DOMEventAssembler = Trait({
exports.DOMEventAssembler = Class({
/**
* Function that is supposed to handle all the supported events (that are
* present in the `supportedEventsTypes`) from all the observed
* `eventTargets`.
* @param {Event} event
* Event being dispatched.
*/
handleEvent: Trait.required,
handleEvent() {
throw new TypeError("Instance of DOMEventAssembler must implement `handleEvent` method");
},
/**
* Array of supported event names.
* @type {String[]}
*/
supportedEventsTypes: Trait.required,
get supportedEventsTypes() {
throw new TypeError("Instance of DOMEventAssembler must implement `handleEvent` field");
},
/**
* Adds `eventTarget` to the list of observed `eventTarget`s. Listeners for
* supported events will be registered on the given `eventTarget`.
Expand Down
52 changes: 26 additions & 26 deletions lib/sdk/keyboard/observer.js
Expand Up @@ -8,21 +8,36 @@ module.metadata = {
"stability": "unstable"
};

const { Trait } = require("../deprecated/light-traits");
const { EventEmitterTrait: EventEmitter } = require("../deprecated/events");
const { Class } = require("../core/heritage");
const { EventTarget } = require("../event/target");
const { emit } = require("../event/core");
const { DOMEventAssembler } = require("../deprecated/events/assembler");
const { browserWindowIterator } = require('../deprecated/window-utils');
const { isBrowser } = require('../window/utils');
const { observer: windowObserver } = require("../windows/observer");

// 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,
const Observer = Class({
implements: [DOMEventAssembler, EventTarget],
initialize() {
// Adding each opened window to a list of observed windows.
windowObserver.on("open", window => {
if (isBrowser(window))
this.observe(window);
});

// Removing each closed window form the list of observed windows.
windowObserver.on("close", window => {
if (isBrowser(window))
this.ignore(window);
});

// Making observer aware of already opened windows.
for (let window of browserWindowIterator()) {
this.observe(window);
}
},
/**
* Events that are supported and emitted by the module.
*/
Expand All @@ -34,24 +49,9 @@ const observer = Trait.compose(DOMEventAssembler, EventEmitter).create({
* @param {Event} event
* Keyboard event being emitted.
*/
handleEvent: function handleEvent(event) {
this._emit(event.type, event, event.target.ownerDocument.defaultView);
handleEvent(event) {
emit(this, event.type, event, event.target.ownerDocument.defaultView);
}
});

// Adding each opened window to a list of observed windows.
windowObserver.on("open", function onOpen(window) {
if (isBrowser(window))
observer.observe(window);
});
// Removing each closed window form the list of observed windows.
windowObserver.on("close", function onClose(window) {
if (isBrowser(window))
observer.ignore(window);
});

// Making observer aware of already opened windows.
for (let window of browserWindowIterator())
observer.observe(window);

exports.observer = observer;
exports.observer = new Observer();
125 changes: 67 additions & 58 deletions lib/sdk/tabs/observer.js
Expand Up @@ -7,12 +7,13 @@ module.metadata = {
"stability": "unstable"
};

const { EventEmitterTrait: EventEmitter } = require("../deprecated/events");
const { EventTarget } = require("../event/target");
const { emit } = require("../event/core");
const { DOMEventAssembler } = require("../deprecated/events/assembler");
const { Trait } = require("../deprecated/light-traits");
const { getActiveTab, getTabs, getTabContainer } = require("./utils");
const { Class } = require("../core/heritage");
const { getActiveTab, getTabs } = require("./utils");
const { browserWindowIterator } = require("../deprecated/window-utils");
const { isBrowser } = require('../window/utils');
const { isBrowser, windows, getMostRecentBrowserWindow } = require("../window/utils");
const { observer: windowObserver } = require("../windows/observer");

const EVENTS = {
Expand All @@ -24,15 +25,69 @@ const EVENTS = {
"TabUnpinned": "unpinned"
};

const selectedTab = Symbol("observer/state/selectedTab");

// 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,
const Observer = Class({
implements: [EventTarget, DOMEventAssembler],
initialize() {
this[selectedTab] = null;
// 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.
this.on("select", tab => {
const selected = this[selectedTab];
if (selected !== tab) {
if (selected) {
emit(this, 'deactivate', selected);
}

if (tab) {
this[selectedTab] = tab;
emit(this, 'activate', this[selectedTab]);
}
}
});


// We also observe opening / closing windows in order to add / remove it's
// containers to the observed list.
windowObserver.on("open", chromeWindow => {
if (isBrowser(chromeWindow)) {
this.observe(chromeWindow);
}
});

windowObserver.on("close", chromeWindow => {
if (isBrowser(chromeWindow)) {
// Bug 751546: Emit `deactivate` event on window close immediatly
// Otherwise we are going to face "dead object" exception on `select` event
if (getActiveTab(chromeWindow) === this[selectedTab]) {
emit(this, "deactivate", this[selectedTab]);
this[selectedTab] = null;
}
this.ignore(chromeWindow);
}
});


// 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", chromeWindow => {
if (isBrowser(chromeWindow)) {
emit(this, "select", getActiveTab(chromeWindow));
}
});

// We should synchronize state, since probably we already have at least one
// window open.
for (let chromeWindow of browserWindowIterator()) {
this.observe(chromeWindow);
}
},
/**
* Events that are supported and emitted by the module.
*/
Expand All @@ -45,54 +100,8 @@ const observer = Trait.compose(DOMEventAssembler, EventEmitter).create({
* Keyboard event being emitted.
*/
handleEvent: function handleEvent(event) {
this._emit(EVENTS[event.type], event.target, event);
emit(this, 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 (let window of browserWindowIterator()) onWindowOpen(window);

exports.observer = observer;
exports.observer = new Observer();
44 changes: 21 additions & 23 deletions lib/sdk/windows/observer.js
Expand Up @@ -7,19 +7,29 @@ module.metadata = {
"stability": "unstable"
};

const { EventEmitterTrait: EventEmitter } = require("../deprecated/events");
const { EventTarget } = require("../event/target");
const { emit } = require("../event/core");
const { WindowTracker, windowIterator } = require("../deprecated/window-utils");
const { DOMEventAssembler } = require("../deprecated/events/assembler");
const { Trait } = require("../deprecated/light-traits");
const { Class } = require("../core/heritage");

// 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,
const Observer = Class({
initialize() {
// Using `WindowTracker` to track window events.
WindowTracker({
onTrack: chromeWindow => {
emit(this, "open", chromeWindow);
this.observe(chromeWindow);
},
onUntrack: chromeWindow => {
emit(this, "close", chromeWindow);
this.ignore(chromeWindow);
}
});
},
implements: [EventTarget, DOMEventAssembler],
/**
* Events that are supported and emitted by the module.
*/
Expand All @@ -31,21 +41,9 @@ const observer = Trait.compose(DOMEventAssembler, EventEmitter).create({
* @param {Event} event
* Keyboard event being emitted.
*/
handleEvent: function handleEvent(event) {
this._emit(event.type, event.target, event);
}
});

// Using `WindowTracker` to track window events.
WindowTracker({
onTrack: function onTrack(chromeWindow) {
observer._emit("open", chromeWindow);
observer.observe(chromeWindow);
},
onUntrack: function onUntrack(chromeWindow) {
observer._emit("close", chromeWindow);
observer.ignore(chromeWindow);
handleEvent(event) {
emit(this, event.type, event.target, event);
}
});

exports.observer = observer;
exports.observer = new Observer();

0 comments on commit 76fcb01

Please sign in to comment.