1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/core/observer.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,87 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +module.metadata = { 1.11 + "stability": "experimental" 1.12 +}; 1.13 + 1.14 + 1.15 +const { Cc, Ci, Cr } = require("chrome"); 1.16 +const { Class } = require("./heritage"); 1.17 +const { isWeak } = require("./reference"); 1.18 +const method = require("../../method/core"); 1.19 + 1.20 +const { addObserver, removeObserver } = Cc['@mozilla.org/observer-service;1']. 1.21 + getService(Ci.nsIObserverService); 1.22 + 1.23 + 1.24 +// This is a method that will be invoked when notification observer 1.25 +// subscribed to occurs. 1.26 +const observe = method("observer/observe"); 1.27 +exports.observe = observe; 1.28 + 1.29 +// Method to subscribe to the observer notification. 1.30 +const subscribe = method("observe/subscribe"); 1.31 +exports.subscribe = subscribe; 1.32 + 1.33 + 1.34 +// Method to unsubscribe from the observer notifications. 1.35 +const unsubscribe = method("observer/unsubscribe"); 1.36 +exports.unsubscribe = unsubscribe; 1.37 + 1.38 + 1.39 +// This is wrapper class that takes a `delegate` and produces 1.40 +// instance of `nsIObserver` which will delegate to a given 1.41 +// object when observer notification occurs. 1.42 +const ObserverDelegee = Class({ 1.43 + initialize: function(delegate) { 1.44 + this.delegate = delegate; 1.45 + }, 1.46 + QueryInterface: function(iid) { 1.47 + const isObserver = iid.equals(Ci.nsIObserver); 1.48 + const isWeakReference = iid.equals(Ci.nsISupportsWeakReference); 1.49 + 1.50 + if (!isObserver && !isWeakReference) 1.51 + throw Cr.NS_ERROR_NO_INTERFACE; 1.52 + 1.53 + return this; 1.54 + }, 1.55 + observe: function(subject, topic, data) { 1.56 + observe(this.delegate, subject, topic, data); 1.57 + } 1.58 +}); 1.59 + 1.60 + 1.61 +// Class that can be either mixed in or inherited from in 1.62 +// order to subscribe / unsubscribe for observer notifications. 1.63 +const Observer = Class({}); 1.64 +exports.Observer = Observer; 1.65 + 1.66 +// Weak maps that associates instance of `ObserverDelegee` with 1.67 +// an actual observer. It ensures that `ObserverDelegee` instance 1.68 +// won't be GC-ed until given `observer` is. 1.69 +const subscribers = new WeakMap(); 1.70 + 1.71 +// Implementation of `subscribe` for `Observer` type just registers 1.72 +// observer for an observer service. If `isWeak(observer)` is `true` 1.73 +// observer service won't hold strong reference to a given `observer`. 1.74 +subscribe.define(Observer, (observer, topic) => { 1.75 + if (!subscribers.has(observer)) { 1.76 + const delegee = new ObserverDelegee(observer); 1.77 + subscribers.set(observer, delegee); 1.78 + addObserver(delegee, topic, isWeak(observer)); 1.79 + } 1.80 +}); 1.81 + 1.82 +// Unsubscribes `observer` from observer notifications for the 1.83 +// given `topic`. 1.84 +unsubscribe.define(Observer, (observer, topic) => { 1.85 + const delegee = subscribers.get(observer); 1.86 + if (delegee) { 1.87 + subscribers.delete(observer); 1.88 + removeObserver(delegee, topic); 1.89 + } 1.90 +});