123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- /* 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 { Cc, Ci } = require('chrome');
- const { Unknown } = require('../platform/xpcom');
- const { Class } = require('../core/heritage');
- const { ns } = require('../core/namespace');
- const { addObserver, removeObserver, notifyObservers } =
- Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
- const Subject = Class({
- extends: Unknown,
- initialize: function initialize(object) {
- // Double-wrap the object and set a property identifying the
- // wrappedJSObject as one of our wrappers to distinguish between
- // subjects that are one of our wrappers (which we should unwrap
- // when notifying our observers) and those that are real JS XPCOM
- // components (which we should pass through unaltered).
- this.wrappedJSObject = {
- observersModuleSubjectWrapper: true,
- object: object
- };
- },
- getHelperForLanguage: function() {},
- getInterfaces: function() {}
- });
- function emit(type, event) {
- // From bug 910599
- // We must test to see if 'subject' or 'data' is a defined property
- // of the event object, but also allow primitives to be passed in,
- // which the `in` operator breaks, yet `null` is an object, hence
- // the long conditional
- let subject = event && typeof event === 'object' && 'subject' in event ?
- Subject(event.subject) :
- null;
- let data = event && typeof event === 'object' ?
- // An object either returns its `data` property or null
- ('data' in event ? event.data : null) :
- // All other types return themselves (and cast to strings/null
- // via observer service)
- event;
- notifyObservers(subject, type, data);
- }
- exports.emit = emit;
- const Observer = Class({
- extends: Unknown,
- initialize: function initialize(listener) {
- this.listener = listener;
- },
- interfaces: [ 'nsIObserver', 'nsISupportsWeakReference' ],
- observe: function(subject, topic, data) {
- // Extract the wrapped object for subjects that are one of our
- // wrappers around a JS object. This way we support both wrapped
- // subjects created using this module and those that are real
- // XPCOM components.
- if (subject && typeof(subject) == 'object' &&
- ('wrappedJSObject' in subject) &&
- ('observersModuleSubjectWrapper' in subject.wrappedJSObject))
- subject = subject.wrappedJSObject.object;
- try {
- this.listener({
- type: topic,
- subject: subject,
- data: data
- });
- }
- catch (error) {
- console.exception(error);
- }
- }
- });
- const subscribers = ns();
- function on(type, listener, strong) {
- // Unless last optional argument is `true` we use a weak reference to a
- // listener.
- let weak = !strong;
- // Take list of observers associated with given `listener` function.
- let observers = subscribers(listener);
- // If `observer` for the given `type` is not registered yet, then
- // associate an `observer` and register it.
- if (!(type in observers)) {
- let observer = Observer(listener);
- observers[type] = observer;
- addObserver(observer, type, weak);
- }
- }
- exports.on = on;
- function once(type, listener) {
- // Note: this code assumes order in which listeners are called, which is fine
- // as long as dispatch happens in same order as listener registration which
- // is the case now. That being said we should be aware that this may break
- // in a future if order will change.
- on(type, listener);
- on(type, function cleanup() {
- off(type, listener);
- off(type, cleanup);
- }, true);
- }
- exports.once = once;
- function off(type, listener) {
- // Take list of observers as with the given `listener`.
- let observers = subscribers(listener);
- // If `observer` for the given `type` is registered, then
- // remove it & unregister.
- if (type in observers) {
- let observer = observers[type];
- delete observers[type];
- removeObserver(observer, type);
- }
- }
- exports.off = off;
|