summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/lib/sdk/event
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2018-02-09 06:46:43 -0500
committerMatt A. Tobin <email@mattatobin.com>2018-02-09 06:46:43 -0500
commitac46df8daea09899ce30dc8fd70986e258c746bf (patch)
tree2750d3125fc253fd5b0671e4bd268eff1fd97296 /addon-sdk/source/lib/sdk/event
parent8cecf8d5208f3945b35f879bba3015bb1a11bec6 (diff)
downloadUXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.gz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.lz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.xz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.zip
Move Add-on SDK source to toolkit/jetpack
Diffstat (limited to 'addon-sdk/source/lib/sdk/event')
-rw-r--r--addon-sdk/source/lib/sdk/event/chrome.js65
-rw-r--r--addon-sdk/source/lib/sdk/event/core.js193
-rw-r--r--addon-sdk/source/lib/sdk/event/dom.js78
-rw-r--r--addon-sdk/source/lib/sdk/event/target.js74
-rw-r--r--addon-sdk/source/lib/sdk/event/utils.js328
5 files changed, 0 insertions, 738 deletions
diff --git a/addon-sdk/source/lib/sdk/event/chrome.js b/addon-sdk/source/lib/sdk/event/chrome.js
deleted file mode 100644
index 9044fef99..000000000
--- a/addon-sdk/source/lib/sdk/event/chrome.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/* 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, Cr, Cu } = require("chrome");
-const { emit, on, off } = require("./core");
-var observerService = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
-
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
-const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
-
-const { when: unload } = require("../system/unload");
-
-// Simple class that can be used to instantiate event channel that
-// implements `nsIObserver` interface. It's will is used by `observe`
-// function as observer + event target. It basically proxies observer
-// notifications as to it's registered listeners.
-function ObserverChannel() {}
-Object.freeze(Object.defineProperties(ObserverChannel.prototype, {
- QueryInterface: {
- value: function(iid) {
- if (!iid.equals(Ci.nsIObserver) &&
- !iid.equals(Ci.nsISupportsWeakReference) &&
- !iid.equals(Ci.nsISupports))
- throw Cr.NS_ERROR_NO_INTERFACE;
- return this;
- }
- },
- observe: {
- value: function(subject, topic, data) {
- emit(this, "data", {
- type: topic,
- target: subject,
- data: data
- });
- }
- }
-}));
-
-function observe(topic) {
- let observerChannel = new ObserverChannel();
-
- // Note: `nsIObserverService` will not hold a weak reference to a
- // observerChannel (since third argument is `true`). There for if it
- // will be GC-ed with all it's event listeners once no other references
- // will be held.
- addObserver(observerChannel, topic, true);
-
- // We need to remove any observer added once the add-on is unloaded;
- // otherwise we'll get a "dead object" exception.
- // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833
- unload(() => removeObserver(observerChannel, topic));
-
- return observerChannel;
-}
-
-exports.observe = observe;
diff --git a/addon-sdk/source/lib/sdk/event/core.js b/addon-sdk/source/lib/sdk/event/core.js
deleted file mode 100644
index c16dd2df5..000000000
--- a/addon-sdk/source/lib/sdk/event/core.js
+++ /dev/null
@@ -1,193 +0,0 @@
-/* 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 UNCAUGHT_ERROR = 'An error event was emitted for which there was no listener.';
-const BAD_LISTENER = 'The event listener must be a function.';
-
-const { ns } = require('../core/namespace');
-
-const event = ns();
-
-const EVENT_TYPE_PATTERN = /^on([A-Z]\w+$)/;
-exports.EVENT_TYPE_PATTERN = EVENT_TYPE_PATTERN;
-
-// Utility function to access given event `target` object's event listeners for
-// the specific event `type`. If listeners for this type does not exists they
-// will be created.
-const observers = function observers(target, type) {
- if (!target) throw TypeError("Event target must be an object");
- let listeners = event(target);
- return type in listeners ? listeners[type] : listeners[type] = [];
-};
-
-/**
- * Registers an event `listener` that is called every time events of
- * specified `type` is emitted on the given event `target`.
- * @param {Object} target
- * Event target object.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
-function on(target, type, listener) {
- if (typeof(listener) !== 'function')
- throw new Error(BAD_LISTENER);
-
- let listeners = observers(target, type);
- if (!~listeners.indexOf(listener))
- listeners.push(listener);
-}
-exports.on = on;
-
-
-var onceWeakMap = new WeakMap();
-
-
-/**
- * Registers an event `listener` that is called only the next time an event
- * of the specified `type` is emitted on the given event `target`.
- * @param {Object} target
- * Event target object.
- * @param {String} type
- * The type of the event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
-function once(target, type, listener) {
- let replacement = function observer(...args) {
- off(target, type, observer);
- onceWeakMap.delete(listener);
- listener.apply(target, args);
- };
- onceWeakMap.set(listener, replacement);
- on(target, type, replacement);
-}
-exports.once = once;
-
-/**
- * Execute each of the listeners in order with the supplied arguments.
- * All the exceptions that are thrown by listeners during the emit
- * are caught and can be handled by listeners of 'error' event. Thrown
- * exceptions are passed as an argument to an 'error' event listener.
- * If no 'error' listener is registered exception will be logged into an
- * error console.
- * @param {Object} target
- * Event target object.
- * @param {String} type
- * The type of event.
- * @params {Object|Number|String|Boolean} args
- * Arguments that will be passed to listeners.
- */
-function emit (target, type, ...args) {
- emitOnObject(target, type, target, ...args);
-}
-exports.emit = emit;
-
-/**
- * A variant of emit that allows setting the this property for event listeners
- */
-function emitOnObject(target, type, thisArg, ...args) {
- let all = observers(target, '*').length;
- let state = observers(target, type);
- let listeners = state.slice();
- let count = listeners.length;
- let index = 0;
-
- // If error event and there are no handlers (explicit or catch-all)
- // then print error message to the console.
- if (count === 0 && type === 'error' && all === 0)
- console.exception(args[0]);
- while (index < count) {
- try {
- let listener = listeners[index];
- // Dispatch only if listener is still registered.
- if (~state.indexOf(listener))
- listener.apply(thisArg, args);
- }
- catch (error) {
- // If exception is not thrown by a error listener and error listener is
- // registered emit `error` event. Otherwise dump exception to the console.
- if (type !== 'error') emit(target, 'error', error);
- else console.exception(error);
- }
- index++;
- }
- // Also emit on `"*"` so that one could listen for all events.
- if (type !== '*') emit(target, '*', type, ...args);
-}
-exports.emitOnObject = emitOnObject;
-
-/**
- * Removes an event `listener` for the given event `type` on the given event
- * `target`. If no `listener` is passed removes all listeners of the given
- * `type`. If `type` is not passed removes all the listeners of the given
- * event `target`.
- * @param {Object} target
- * The event target object.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
-function off(target, type, listener) {
- let length = arguments.length;
- if (length === 3) {
- if (onceWeakMap.has(listener)) {
- listener = onceWeakMap.get(listener);
- onceWeakMap.delete(listener);
- }
-
- let listeners = observers(target, type);
- let index = listeners.indexOf(listener);
- if (~index)
- listeners.splice(index, 1);
- }
- else if (length === 2) {
- observers(target, type).splice(0);
- }
- else if (length === 1) {
- let listeners = event(target);
- Object.keys(listeners).forEach(type => delete listeners[type]);
- }
-}
-exports.off = off;
-
-/**
- * Returns a number of event listeners registered for the given event `type`
- * on the given event `target`.
- */
-function count(target, type) {
- return observers(target, type).length;
-}
-exports.count = count;
-
-/**
- * Registers listeners on the given event `target` from the given `listeners`
- * dictionary. Iterates over the listeners and if property name matches name
- * pattern `onEventType` and property is a function, then registers it as
- * an `eventType` listener on `target`.
- *
- * @param {Object} target
- * The type of event.
- * @param {Object} listeners
- * Dictionary of listeners.
- */
-function setListeners(target, listeners) {
- Object.keys(listeners || {}).forEach(key => {
- let match = EVENT_TYPE_PATTERN.exec(key);
- let type = match && match[1].toLowerCase();
- if (!type) return;
-
- let listener = listeners[key];
- if (typeof(listener) === 'function')
- on(target, type, listener);
- });
-}
-exports.setListeners = setListeners;
diff --git a/addon-sdk/source/lib/sdk/event/dom.js b/addon-sdk/source/lib/sdk/event/dom.js
deleted file mode 100644
index da99dec7a..000000000
--- a/addon-sdk/source/lib/sdk/event/dom.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/* 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 { Ci } = require("chrome");
-
-var { emit } = require("./core");
-var { when: unload } = require("../system/unload");
-var listeners = new WeakMap();
-
-const { Cu } = require("chrome");
-const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
-const { ThreadSafeChromeUtils } = Cu.import("resource://gre/modules/Services.jsm", {});
-
-var getWindowFrom = x =>
- x instanceof Ci.nsIDOMWindow ? x :
- x instanceof Ci.nsIDOMDocument ? x.defaultView :
- x instanceof Ci.nsIDOMNode ? x.ownerDocument.defaultView :
- null;
-
-function removeFromListeners() {
- ShimWaiver.getProperty(this, "removeEventListener")("DOMWindowClose", removeFromListeners);
- for (let cleaner of listeners.get(this))
- cleaner();
-
- listeners.delete(this);
-}
-
-// Simple utility function takes event target, event type and optional
-// `options.capture` and returns node style event stream that emits "data"
-// events every time event of that type occurs on the given `target`.
-function open(target, type, options) {
- let output = {};
- let capture = options && options.capture ? true : false;
- let listener = (event) => emit(output, "data", event);
-
- // `open` is currently used only on DOM Window objects, however it was made
- // to be used to any kind of `target` that supports `addEventListener`,
- // therefore is safer get the `window` from the `target` instead assuming
- // that `target` is the `window`.
- let window = getWindowFrom(target);
-
- // If we're not able to get a `window` from `target`, there is something
- // wrong. We cannot add listeners that can leak later, or results in
- // "dead object" exception.
- // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833
- if (!window)
- throw new Error("Unable to obtain the owner window from the target given.");
-
- let cleaners = listeners.get(window);
- if (!cleaners) {
- cleaners = [];
- listeners.set(window, cleaners);
-
- // We need to remove from our map the `window` once is closed, to prevent
- // memory leak
- ShimWaiver.getProperty(window, "addEventListener")("DOMWindowClose", removeFromListeners);
- }
-
- cleaners.push(() => ShimWaiver.getProperty(target, "removeEventListener")(type, listener, capture));
- ShimWaiver.getProperty(target, "addEventListener")(type, listener, capture);
-
- return output;
-}
-
-unload(() => {
- let keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(listeners)
- for (let window of keys)
- removeFromListeners.call(window);
-});
-
-exports.open = open;
diff --git a/addon-sdk/source/lib/sdk/event/target.js b/addon-sdk/source/lib/sdk/event/target.js
deleted file mode 100644
index 3a1f5e5f0..000000000
--- a/addon-sdk/source/lib/sdk/event/target.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/* 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": "stable"
-};
-
-const { on, once, off, setListeners } = require('./core');
-const { method, chainable } = require('../lang/functional/core');
-const { Class } = require('../core/heritage');
-
-/**
- * `EventTarget` is an exemplar for creating an objects that can be used to
- * add / remove event listeners on them. Events on these objects may be emitted
- * via `emit` function exported by 'event/core' module.
- */
-const EventTarget = Class({
- /**
- * Method initializes `this` event source. It goes through properties of a
- * given `options` and registers listeners for the ones that look like an
- * event listeners.
- */
- /**
- * Method initializes `this` event source. It goes through properties of a
- * given `options` and registers listeners for the ones that look like an
- * event listeners.
- */
- initialize: function initialize(options) {
- setListeners(this, options);
- },
- /**
- * Registers an event `listener` that is called every time events of
- * specified `type` are emitted.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- * @example
- * worker.on('message', function (data) {
- * console.log('data received: ' + data)
- * })
- */
- on: chainable(method(on)),
- /**
- * Registers an event `listener` that is called once the next time an event
- * of the specified `type` is emitted.
- * @param {String} type
- * The type of the event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
- once: chainable(method(once)),
- /**
- * Removes an event `listener` for the given event `type`.
- * @param {String} type
- * The type of event.
- * @param {Function} listener
- * The listener function that processes the event.
- */
- removeListener: function removeListener(type, listener) {
- // Note: We can't just wrap `off` in `method` as we do it for other methods
- // cause skipping a second or third argument will behave very differently
- // than intended. This way we make sure all arguments are passed and only
- // one listener is removed at most.
- off(this, type, listener);
- return this;
- },
- // but we can wrap `off` here, as the semantics are the same
- off: chainable(method(off))
-
-});
-exports.EventTarget = EventTarget;
diff --git a/addon-sdk/source/lib/sdk/event/utils.js b/addon-sdk/source/lib/sdk/event/utils.js
deleted file mode 100644
index f193b6785..000000000
--- a/addon-sdk/source/lib/sdk/event/utils.js
+++ /dev/null
@@ -1,328 +0,0 @@
-/* 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"
-};
-
-var { emit, on, once, off, EVENT_TYPE_PATTERN } = require("./core");
-const { Cu } = require("chrome");
-
-// This module provides set of high order function for working with event
-// streams (streams in a NodeJS style that dispatch data, end and error
-// events).
-
-// Function takes a `target` object and returns set of implicit references
-// (non property references) it keeps. This basically allows defining
-// references between objects without storing the explicitly. See transform for
-// more details.
-var refs = (function() {
- let refSets = new WeakMap();
- return function refs(target) {
- if (!refSets.has(target)) refSets.set(target, new Set());
- return refSets.get(target);
- };
-})();
-
-function transform(input, f) {
- let output = new Output();
-
- // Since event listeners don't prevent `input` to be GC-ed we wanna presrve
- // it until `output` can be GC-ed. There for we add implicit reference which
- // is removed once `input` ends.
- refs(output).add(input);
-
- const next = data => receive(output, data);
- once(output, "start", () => start(input));
- on(input, "error", error => emit(output, "error", error));
- on(input, "end", function() {
- refs(output).delete(input);
- end(output);
- });
- on(input, "data", data => f(data, next));
- return output;
-}
-
-// High order event transformation function that takes `input` event channel
-// and returns transformation containing only events on which `p` predicate
-// returns `true`.
-function filter(input, predicate) {
- return transform(input, function(data, next) {
- if (predicate(data))
- next(data);
- });
-}
-exports.filter = filter;
-
-// High order function that takes `input` and returns input of it's values
-// mapped via given `f` function.
-const map = (input, f) => transform(input, (data, next) => next(f(data)));
-exports.map = map;
-
-// High order function that takes `input` stream of streams and merges them
-// into single event stream. Like flatten but time based rather than order
-// based.
-function merge(inputs) {
- let output = new Output();
- let open = 1;
- let state = [];
- output.state = state;
- refs(output).add(inputs);
-
- function end(input) {
- open = open - 1;
- refs(output).delete(input);
- if (open === 0) emit(output, "end");
- }
- const error = e => emit(output, "error", e);
- function forward(input) {
- state.push(input);
- open = open + 1;
- on(input, "end", () => end(input));
- on(input, "error", error);
- on(input, "data", data => emit(output, "data", data));
- }
-
- // If `inputs` is an array treat it as a stream.
- if (Array.isArray(inputs)) {
- inputs.forEach(forward);
- end(inputs);
- }
- else {
- on(inputs, "end", () => end(inputs));
- on(inputs, "error", error);
- on(inputs, "data", forward);
- }
-
- return output;
-}
-exports.merge = merge;
-
-const expand = (inputs, f) => merge(map(inputs, f));
-exports.expand = expand;
-
-const pipe = (from, to) => on(from, "*", emit.bind(emit, to));
-exports.pipe = pipe;
-
-
-// Shim signal APIs so other modules can be used as is.
-const receive = (input, message) => {
- if (input[receive])
- input[receive](input, message);
- else
- emit(input, "data", message);
-
- // Ideally our input will extend Input and already provide a weak value
- // getter. If not, opportunistically shim the weak value getter on
- // other types passed as the input.
- if (!("value" in input)) {
- Object.defineProperty(input, "value", WeakValueGetterSetter);
- }
- input.value = message;
-};
-receive.toString = () => "@@receive";
-exports.receive = receive;
-exports.send = receive;
-
-const end = input => {
- if (input[end])
- input[end](input);
- else
- emit(input, "end", input);
-};
-end.toString = () => "@@end";
-exports.end = end;
-
-const stop = input => {
- if (input[stop])
- input[stop](input);
- else
- emit(input, "stop", input);
-};
-stop.toString = () => "@@stop";
-exports.stop = stop;
-
-const start = input => {
- if (input[start])
- input[start](input);
- else
- emit(input, "start", input);
-};
-start.toString = () => "@@start";
-exports.start = start;
-
-const lift = (step, ...inputs) => {
- let args = null;
- let opened = inputs.length;
- let started = false;
- const output = new Output();
- const init = () => {
- args = [...inputs.map(input => input.value)];
- output.value = step(...args);
- };
-
- inputs.forEach((input, index) => {
- on(input, "data", data => {
- args[index] = data;
- receive(output, step(...args));
- });
- on(input, "end", () => {
- opened = opened - 1;
- if (opened <= 0)
- end(output);
- });
- });
-
- once(output, "start", () => {
- inputs.forEach(start);
- init();
- });
-
- init();
-
- return output;
-};
-exports.lift = lift;
-
-const merges = inputs => {
- let opened = inputs.length;
- let output = new Output();
- output.value = inputs[0].value;
- inputs.forEach((input, index) => {
- on(input, "data", data => receive(output, data));
- on(input, "end", () => {
- opened = opened - 1;
- if (opened <= 0)
- end(output);
- });
- });
-
- once(output, "start", () => {
- inputs.forEach(start);
- output.value = inputs[0].value;
- });
-
- return output;
-};
-exports.merges = merges;
-
-const foldp = (step, initial, input) => {
- let output = map(input, x => step(output.value, x));
- output.value = initial;
- return output;
-};
-exports.foldp = foldp;
-
-const keepIf = (p, base, input) => {
- let output = filter(input, p);
- output.value = base;
- return output;
-};
-exports.keepIf = keepIf;
-
-function Input() {}
-Input.start = input => emit(input, "start", input);
-Input.prototype.start = Input.start;
-
-Input.end = input => {
- emit(input, "end", input);
- stop(input);
-};
-Input.prototype[end] = Input.end;
-
-// The event channel system caches the last event seen as input.value.
-// Unfortunately, if the last event is a DOM object this is a great way
-// leak windows. Mitigate this by storing input.value using a weak
-// reference. This allows the system to work for normal event processing
-// while also allowing the objects to be reclaimed. It means, however,
-// input.value cannot be accessed long after the event was dispatched.
-const WeakValueGetterSetter = {
- get: function() {
- return this._weakValue ? this._weakValue.get() : this._simpleValue
- },
- set: function(v) {
- if (v && typeof v === "object") {
- try {
- // Try to set a weak reference. This can throw for some values.
- // For example, if the value is a native object that does not
- // implement nsISupportsWeakReference.
- this._weakValue = Cu.getWeakReference(v)
- this._simpleValue = undefined;
- return;
- } catch (e) {
- // Do nothing. Fall through to setting _simpleValue below.
- }
- }
- this._simpleValue = v;
- this._weakValue = undefined;
- },
-}
-Object.defineProperty(Input.prototype, "value", WeakValueGetterSetter);
-
-exports.Input = Input;
-
-// Define an Output type with a weak value getter for the transformation
-// functions that produce new channels.
-function Output() { }
-Object.defineProperty(Output.prototype, "value", WeakValueGetterSetter);
-exports.Output = Output;
-
-const $source = "@@source";
-const $outputs = "@@outputs";
-exports.outputs = $outputs;
-
-// NOTE: Passing DOM objects through a Reactor can cause them to leak
-// when they get cached in this.value. We cannot use a weak reference
-// in this case because the Reactor design expects to always have both the
-// past and present value. If we allow past values to be collected the
-// system breaks.
-
-function Reactor(options={}) {
- const {onStep, onStart, onEnd} = options;
- if (onStep)
- this.onStep = onStep;
- if (onStart)
- this.onStart = onStart;
- if (onEnd)
- this.onEnd = onEnd;
-}
-Reactor.prototype.onStep = _ => void(0);
-Reactor.prototype.onStart = _ => void(0);
-Reactor.prototype.onEnd = _ => void(0);
-Reactor.prototype.onNext = function(present, past) {
- this.value = present;
- this.onStep(present, past);
-};
-Reactor.prototype.run = function(input) {
- on(input, "data", message => this.onNext(message, input.value));
- on(input, "end", () => this.onEnd(input.value));
- start(input);
- this.value = input.value;
- this.onStart(input.value);
-};
-exports.Reactor = Reactor;
-
-/**
- * Takes an object used as options with potential keys like 'onMessage',
- * used to be called `require('sdk/event/core').setListeners` on.
- * This strips all keys that would trigger a listener to be set.
- *
- * @params {Object} object
- * @return {Object}
- */
-
-function stripListeners (object) {
- return Object.keys(object || {}).reduce((agg, key) => {
- if (!EVENT_TYPE_PATTERN.test(key))
- agg[key] = object[key];
- return agg;
- }, {});
-}
-exports.stripListeners = stripListeners;
-
-const when = (target, type) => new Promise(resolve => {
- once(target, type, resolve);
-});
-exports.when = when;