pax_global_header 0000666 0000000 0000000 00000000064 13060566071 0014516 g ustar 00root root 0000000 0000000 52 comment=12558bc80c7d0b3600107108b51e260713319cda
d3-dispatch-1.0.3/ 0000775 0000000 0000000 00000000000 13060566071 0013622 5 ustar 00root root 0000000 0000000 d3-dispatch-1.0.3/.eslintrc 0000664 0000000 0000000 00000000147 13060566071 0015450 0 ustar 00root root 0000000 0000000 parserOptions:
sourceType: module
extends:
"eslint:recommended"
rules:
no-cond-assign: 0
d3-dispatch-1.0.3/.gitignore 0000664 0000000 0000000 00000000100 13060566071 0015601 0 ustar 00root root 0000000 0000000 *.sublime-workspace
.DS_Store
build/
node_modules
npm-debug.log
d3-dispatch-1.0.3/.npmignore 0000664 0000000 0000000 00000000036 13060566071 0015620 0 ustar 00root root 0000000 0000000 *.sublime-*
build/*.zip
test/
d3-dispatch-1.0.3/LICENSE 0000664 0000000 0000000 00000002703 13060566071 0014631 0 ustar 00root root 0000000 0000000 Copyright 2010-2016 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-dispatch-1.0.3/README.md 0000664 0000000 0000000 00000012234 13060566071 0015103 0 ustar 00root root 0000000 0000000 # d3-dispatch
Dispatching is a convenient mechanism for separating concerns with loosely-coupled code: register named callbacks and then call them with arbitrary arguments. A variety of D3 components, such as [d3-request](https://github.com/d3/d3-request), use this mechanism to emit events to listeners. Think of this like Node’s [EventEmitter](https://nodejs.org/api/events.html), except every listener has a well-defined name so it’s easy to remove or replace them.
For example, to create a dispatch for *start* and *end* events:
```js
var dispatch = d3.dispatch("start", "end");
```
You can then register callbacks for these events using [*dispatch*.on](#dispatch_on):
```js
dispatch.on("start", callback1);
dispatch.on("start.foo", callback2);
dispatch.on("end", callback3);
```
Then, you can invoke all the *start* callbacks using [*dispatch*.call](#dispatch_call) or [*dispatch*.apply](#dispatch_apply):
```js
dispatch.call("start");
```
Like *function*.call, you may also specify the `this` context and any arguments:
```js
dispatch.call("start", {about: "I am a context object"}, "I am an argument");
```
Want a more involved example? See how to use [d3-dispatch for coordinated views](http://bl.ocks.org/mbostock/5872848).
## Installing
If you use NPM, `npm install d3-dispatch`. Otherwise, download the [latest release](https://github.com/d3/d3-dispatch/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-dispatch.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
```html
```
[Try d3-dispatch in your browser.](https://tonicdev.com/npm/d3-dispatch)
## API Reference
# d3.dispatch(types…) [<>](https://github.com/d3/d3-dispatch/blob/master/src/dispatch.js "Source")
Creates a new dispatch for the specified event *types*. Each *type* is a string, such as `"start"` or `"end"`.
# *dispatch*.on(typenames[, callback]) [<>](https://github.com/d3/d3-dispatch/blob/master/src/dispatch.js#L26 "Source")
Adds, removes or gets the *callback* for the specified *typenames*. If a *callback* function is specified, it is registered for the specified (fully-qualified) *typenames*. If a callback was already registered for the given *typenames*, the existing callback is removed before the new callback is added.
The specified *typenames* is a string, such as `start` or `end.foo`. The type may be optionally followed by a period (`.`) and a name; the optional name allows multiple callbacks to be registered to receive events of the same type, such as `start.foo` and `start.bar`. To specify multiple typenames, separate typenames with spaces, such as `start end` or `start.foo start.bar`.
To remove all callbacks for a given name `foo`, say `dispatch.on(".foo", null)`.
If *callback* is not specified, returns the current callback for the specified *typenames*, if any. If multiple typenames are specified, the first matching callback is returned.
# *dispatch*.copy() [<>](https://github.com/d3/d3-dispatch/blob/master/src/dispatch.js#L49 "Source")
Returns a copy of this dispatch object. Changes to this dispatch do not affect the returned copy and vice versa.
# *dispatch*.call(type[, that[, arguments…]]) [<>](https://github.com/d3/d3-dispatch/blob/master/src/dispatch.js#L54 "Source")
Like [*function*.call](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call), invokes each registered callback for the specified *type*, passing the callback the specified *arguments*, with *that* as the `this` context. See [*dispatch*.apply](#dispatch_apply) for more information.
# *dispatch*.apply(type[, that[, arguments]]) [<>](https://github.com/d3/d3-dispatch/blob/master/src/dispatch.js#L59 "Source")
Like [*function*.apply](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call), invokes each registered callback for the specified *type*, passing the callback the specified *arguments*, with *that* as the `this` context. For example, if you wanted to dispatch your *custom* callbacks after handling a native *click* event, while preserving the current `this` context and arguments, you could say:
```js
selection.on("click", function() {
dispatch.apply("custom", this, arguments);
});
```
You can pass whatever arguments you want to callbacks; most commonly, you might create an object that represents an event, or pass the current datum (*d*) and index (*i*). See [function.call](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Call) and [function.apply](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Apply) for further information.
d3-dispatch-1.0.3/d3-dispatch.sublime-project 0000664 0000000 0000000 00000000271 13060566071 0020753 0 ustar 00root root 0000000 0000000 {
"folders": [
{
"path": ".",
"file_exclude_patterns": [
"*.sublime-workspace"
],
"folder_exclude_patterns": [
"build"
]
}
]
}
d3-dispatch-1.0.3/index.js 0000664 0000000 0000000 00000000064 13060566071 0015267 0 ustar 00root root 0000000 0000000 export {default as dispatch} from "./src/dispatch";
d3-dispatch-1.0.3/package.json 0000664 0000000 0000000 00000002704 13060566071 0016113 0 ustar 00root root 0000000 0000000 {
"name": "d3-dispatch",
"version": "1.0.3",
"description": "Register named callbacks and call them with arguments.",
"keywords": [
"d3",
"d3-module",
"event",
"listener",
"dispatch"
],
"homepage": "https://d3js.org/d3-dispatch/",
"license": "BSD-3-Clause",
"author": {
"name": "Mike Bostock",
"url": "http://bost.ocks.org/mike"
},
"main": "build/d3-dispatch.js",
"module": "index",
"jsnext:main": "index",
"repository": {
"type": "git",
"url": "https://github.com/d3/d3-dispatch.git"
},
"scripts": {
"pretest": "rm -rf build && mkdir build && rollup --banner \"$(preamble)\" -f umd -n d3 -o build/d3-dispatch.js -- index.js",
"test": "tape 'test/**/*-test.js' && eslint index.js src",
"prepublish": "npm run test && uglifyjs --preamble \"$(preamble)\" build/d3-dispatch.js -c -m -o build/d3-dispatch.min.js",
"postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../d3-dispatch/build/d3-dispatch.js d3-dispatch.v1.js && cp ../d3-dispatch/build/d3-dispatch.min.js d3-dispatch.v1.min.js && git add d3-dispatch.v1.js d3-dispatch.v1.min.js && git commit -m \"d3-dispatch ${npm_package_version}\" && git push && cd - && zip -j build/d3-dispatch.zip -- LICENSE README.md build/d3-dispatch.js build/d3-dispatch.min.js"
},
"devDependencies": {
"eslint": "3",
"package-preamble": "0.0",
"rollup": "0.41",
"tape": "4",
"uglify-js": "^2.8.11"
}
}
d3-dispatch-1.0.3/src/ 0000775 0000000 0000000 00000000000 13060566071 0014411 5 ustar 00root root 0000000 0000000 d3-dispatch-1.0.3/src/dispatch.js 0000664 0000000 0000000 00000005251 13060566071 0016551 0 ustar 00root root 0000000 0000000 var noop = {value: function() {}};
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {type: t, name: name};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._,
T = parseTypenames(typename + "", _),
t,
i = -1,
n = T.length;
// If no callback was specified, return the callback of the given type and name.
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
return;
}
// If a type was specified, set the callback for the given type and name.
// Otherwise, if a null callback was specified, remove callbacks of the given name.
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) {
if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
}
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) {
if ((c = type[i]).name === name) {
return c.value;
}
}
}
function set(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) {
if (type[i].name === name) {
type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
}
if (callback != null) type.push({name: name, value: callback});
return type;
}
export default dispatch;
d3-dispatch-1.0.3/test/ 0000775 0000000 0000000 00000000000 13060566071 0014601 5 ustar 00root root 0000000 0000000 d3-dispatch-1.0.3/test/dispatch-test.js 0000664 0000000 0000000 00000031613 13060566071 0017717 0 ustar 00root root 0000000 0000000 var tape = require("tape"),
dispatch = require("../");
tape("dispatch(type…) returns a dispatch object with the specified types", function(test) {
var d = dispatch.dispatch("foo", "bar");
test.ok(d instanceof dispatch.dispatch);
test.equal(d.constructor.name, "Dispatch");
test.end();
});
tape("dispatch(type…) does not throw an error if a specified type name collides with a dispatch method", function(test) {
var d = dispatch.dispatch("on");
test.ok(d instanceof dispatch.dispatch);
test.end();
});
tape("dispatch(type…) throws an error if a specified type name is illegal", function(test) {
test.throws(function() { dispatch.dispatch("__proto__"); });
test.throws(function() { dispatch.dispatch("hasOwnProperty"); });
test.throws(function() { dispatch.dispatch(""); });
test.end();
});
tape("dispatch(type…) throws an error if a specified type name is a duplicate", function(test) {
test.throws(function() { dispatch.dispatch("foo", "foo"); });
test.end();
});
tape("dispatch(type).call(type, object, arguments…) invokes callbacks of the specified type", function(test) {
var foo = 0,
bar = 0,
d = dispatch.dispatch("foo", "bar").on("foo", function() { ++foo; }).on("bar", function() { ++bar; });
d.call("foo");
test.equal(foo, 1);
test.equal(bar, 0);
d.call("foo");
d.call("bar");
test.equal(foo, 2);
test.equal(bar, 1);
test.end();
});
tape("dispatch(type).call(type, object, arguments…) invokes callbacks with specified arguments and context", function(test) {
var results = [],
foo = {},
bar = {},
d = dispatch.dispatch("foo").on("foo", function() { results.push({this: this, arguments: [].slice.call(arguments)}); });
d.call("foo", foo, bar);
test.deepEqual(results, [{this: foo, arguments: [bar]}]);
d.call("foo", bar, foo, 42, "baz");
test.deepEqual(results, [{this: foo, arguments: [bar]}, {this: bar, arguments: [foo, 42, "baz"]}]);
test.end();
});
tape("dispatch(type).call(type, object, arguments…) invokes callbacks in the order they were added", function(test) {
var results = [],
d = dispatch.dispatch("foo");
d.on("foo.a", function() { results.push("A"); });
d.on("foo.b", function() { results.push("B"); });
d.call("foo");
d.on("foo.c", function() { results.push("C"); });
d.on("foo.a", function() { results.push("A"); }); // move to end
d.call("foo");
test.deepEqual(results, ["A", "B", "B", "C", "A"]);
test.end();
});
tape("dispatch(type).call(type, object, arguments…) returns undefined", function(test) {
var d = dispatch.dispatch("foo");
test.equal(d.call("foo"), undefined);
test.end();
});
tape("dispatch(type).apply(type, object, arguments) invokes callbacks of the specified type", function(test) {
var foo = 0,
bar = 0,
d = dispatch.dispatch("foo", "bar").on("foo", function() { ++foo; }).on("bar", function() { ++bar; });
d.apply("foo");
test.equal(foo, 1);
test.equal(bar, 0);
d.apply("foo");
d.apply("bar");
test.equal(foo, 2);
test.equal(bar, 1);
test.end();
});
tape("dispatch(type).apply(type, object, arguments) invokes callbacks with specified arguments and context", function(test) {
var results = [],
foo = {},
bar = {},
d = dispatch.dispatch("foo").on("foo", function() { results.push({this: this, arguments: [].slice.call(arguments)}); });
d.apply("foo", foo, [bar]);
test.deepEqual(results, [{this: foo, arguments: [bar]}]);
d.apply("foo", bar, [foo, 42, "baz"]);
test.deepEqual(results, [{this: foo, arguments: [bar]}, {this: bar, arguments: [foo, 42, "baz"]}]);
test.end();
});
tape("dispatch(type).apply(type, object, arguments) invokes callbacks in the order they were added", function(test) {
var results = [],
d = dispatch.dispatch("foo");
d.on("foo.a", function() { results.push("A"); });
d.on("foo.b", function() { results.push("B"); });
d.apply("foo");
d.on("foo.c", function() { results.push("C"); });
d.on("foo.a", function() { results.push("A"); }); // move to end
d.apply("foo");
test.deepEqual(results, ["A", "B", "B", "C", "A"]);
test.end();
});
tape("dispatch(type).apply(type, object, arguments) returns undefined", function(test) {
var d = dispatch.dispatch("foo");
test.equal(d.apply("foo"), undefined);
test.end();
});
tape("dispatch(type).on(type, f) returns the dispatch object", function(test) {
var d = dispatch.dispatch("foo");
test.equal(d.on("foo", function() {}), d);
test.end();
});
tape("dispatch(type).on(type, f) replaces an existing callback, if present", function(test) {
var foo = 0,
bar = 0,
d = dispatch.dispatch("foo", "bar");
d.on("foo", function() { ++foo; });
d.call("foo");
test.equal(foo, 1);
test.equal(bar, 0);
d.on("foo", function() { ++bar; });
d.call("foo");
test.equal(foo, 1);
test.equal(bar, 1);
test.end();
});
tape("dispatch(type).on(type, f) replacing an existing callback with itself has no effect", function(test) {
var foo = 0,
FOO = function() { ++foo; },
d = dispatch.dispatch("foo").on("foo", FOO);
d.call("foo");
test.equal(foo, 1);
d.on("foo", FOO).on("foo", FOO).on("foo", FOO);
d.call("foo");
test.equal(foo, 2);
test.end();
});
tape("dispatch(type).on(type., …) is equivalent to dispatch(type).on(type, …)", function(test) {
var d = dispatch.dispatch("foo"),
foos = 0,
bars = 0,
foo = function() { ++foos; },
bar = function() { ++bars; };
test.equal(d.on("foo.", foo), d);
test.equal(d.on("foo."), foo);
test.equal(d.on("foo"), foo);
test.equal(d.on("foo.", bar), d);
test.equal(d.on("foo."), bar);
test.equal(d.on("foo"), bar);
test.equal(d.call("foo"), undefined);
test.equal(foos, 0);
test.equal(bars, 1);
test.equal(d.on(".", null), d);
test.equal(d.on("foo"), undefined);
test.equal(d.call("foo"), undefined);
test.equal(foos, 0);
test.equal(bars, 1);
test.end();
});
tape("dispatch(type).on(type, null) removes an existing callback, if present", function(test) {
var foo = 0,
d = dispatch.dispatch("foo", "bar");
d.on("foo", function() { ++foo; });
d.call("foo");
test.equal(foo, 1);
d.on("foo", null);
d.call("foo");
test.equal(foo, 1);
test.end();
});
tape("dispatch(type).on(type, null) does not remove a shared callback", function(test) {
var a = 0,
A = function() { ++a; },
d = dispatch.dispatch("foo", "bar").on("foo", A).on("bar", A);
d.call("foo");
d.call("bar");
test.equal(a, 2);
d.on("foo", null);
d.call("bar");
test.equal(a, 3);
test.end();
});
tape("dispatch(type).on(type, null) removing a missing callback has no effect", function(test) {
var d = dispatch.dispatch("foo"), a = 0;
function A() { ++a; }
d.on("foo.a", null).on("foo", A).on("foo", null).on("foo", null);
d.call("foo");
test.equal(a, 0);
test.end();
});
tape("dispatch(type).on(type, null) during a callback does not invoke the old callback", function(test) {
var a = 0,
b = 0,
c = 0,
A = function() { ++a; d.on("foo.B", null); }, // remove B
B = function() { ++b; },
C = function() { ++c; },
d = dispatch.dispatch("foo").on("foo.A", A).on("foo.B", B);
d.call("foo");
test.equal(a, 1);
test.equal(b, 0);
test.equal(c, 0);
test.end();
});
tape("dispatch(type).on(type, f) during a callback does not invoke the old or the new callback", function(test) {
var a = 0,
b = 0,
c = 0,
A = function() { ++a; d.on("foo.B", C); }, // replace B with C
B = function() { ++b; },
C = function() { ++c; },
d = dispatch.dispatch("foo").on("foo.A", A).on("foo.B", B);
d.call("foo");
test.equal(a, 1);
test.equal(b, 0);
test.equal(c, 0);
test.end();
});
tape("dispatch(type).on(type, f) during a callback does not invoke the new callback", function(test) {
var a = 0,
b = 0,
A = function() { ++a; d.on("foo.B", B); }, // add B
B = function() { ++b; },
d = dispatch.dispatch("foo").on("foo.A", A);
d.call("foo");
test.equal(a, 1);
test.equal(b, 0);
test.end();
});
tape("dispatch(type).on(type, f) coerces type to a string", function(test) {
var f = function() {},
g = function() {},
d = dispatch.dispatch(null, undefined).on(null, f).on(undefined, g);
test.equal(d.on(null), f);
test.equal(d.on(undefined), g);
test.end();
});
tape("dispatch(\"foo\", \"bar\").on(\"foo bar\", f) adds a callback for both types", function(test) {
var foos = 0,
foo = function() { ++foos; },
d = dispatch.dispatch("foo", "bar").on("foo bar", foo);
test.equal(d.on("foo"), foo);
test.equal(d.on("bar"), foo);
d.call("foo");
test.equal(foos, 1);
d.call("bar");
test.equal(foos, 2);
test.end();
});
tape("dispatch(\"foo\").on(\"foo.one foo.two\", f) adds a callback for both typenames", function(test) {
var foos = 0,
foo = function() { ++foos; },
d = dispatch.dispatch("foo").on("foo.one foo.two", foo);
test.equal(d.on("foo.one"), foo);
test.equal(d.on("foo.two"), foo);
d.call("foo");
test.equal(foos, 2);
test.end();
});
tape("dispatch(\"foo\", \"bar\").on(\"foo bar\") returns the callback for either type", function(test) {
var foos = 0,
foo = function() { ++foos; },
d = dispatch.dispatch("foo", "bar");
d.on("foo", foo);
test.equal(d.on("foo bar"), foo);
test.equal(d.on("bar foo"), foo);
d.on("foo", null).on("bar", foo);
test.equal(d.on("foo bar"), foo);
test.equal(d.on("bar foo"), foo);
test.end();
});
tape("dispatch(\"foo\").on(\"foo.one foo.two\") returns the callback for either typename", function(test) {
var foos = 0,
foo = function() { ++foos; },
d = dispatch.dispatch("foo");
d.on("foo.one", foo);
test.equal(d.on("foo.one foo.two"), foo);
test.equal(d.on("foo.two foo.one"), foo);
test.equal(d.on("foo foo.one"), foo);
test.equal(d.on("foo.one foo"), foo);
d.on("foo.one", null).on("foo.two", foo);
test.equal(d.on("foo.one foo.two"), foo);
test.equal(d.on("foo.two foo.one"), foo);
test.equal(d.on("foo foo.two"), foo);
test.equal(d.on("foo.two foo"), foo);
test.end();
});
tape("dispatch(\"foo\").on(\".one .two\", null) removes the callback for either typename", function(test) {
var foos = 0,
foo = function() { ++foos; },
d = dispatch.dispatch("foo");
d.on("foo.one", foo);
d.on("foo.two", foo);
d.on("foo.one foo.two", null);
test.equal(d.on("foo.one"), undefined);
test.equal(d.on("foo.two"), undefined);
test.end();
});
tape("dispatch(type).on(type, f) throws an error if f is not a function", function(test) {
test.throws(function() { dispatch.dispatch("foo").on("foo", 42); });
test.end();
});
tape("dispatch(…).on(type, f) throws an error if the type is unknown", function(test) {
test.throws(function() { dispatch.dispatch("foo").on("bar", function() {}); });
test.throws(function() { dispatch.dispatch("foo").on("__proto__", function() {}); });
test.end();
});
tape("dispatch(…).on(type) throws an error if the type is unknown", function(test) {
test.throws(function() { dispatch.dispatch("foo").on("bar"); });
test.throws(function() { dispatch.dispatch("foo").on("__proto__"); });
test.end();
});
tape("dispatch(type).on(type) returns the expected callback", function(test) {
var d = dispatch.dispatch("foo");
function A() {}
function B() {}
function C() {}
d.on("foo.a", A).on("foo.b", B).on("foo", C);
test.equal(d.on("foo.a"), A);
test.equal(d.on("foo.b"), B);
test.equal(d.on("foo"), C);
test.end();
});
tape("dispatch(type).on(.name) returns undefined when retrieving a callback", function(test) {
var d = dispatch.dispatch("foo").on("foo.a", function() {});
test.equal(d.on(".a"), undefined);
test.end();
});
tape("dispatch(type).on(.name, null) removes all callbacks with the specified name", function(test) {
var d = dispatch.dispatch("foo", "bar"), a = {}, b = {}, c = {}, those = [];
function A() { those.push(a); }
function B() { those.push(b); }
function C() { those.push(c); }
d.on("foo.a", A).on("bar.a", B).on("foo", C).on(".a", null);
d.call("foo");
d.call("bar");
test.deepEqual(those, [c]);
test.end();
});
tape("dispatch(type).on(.name, f) has no effect", function(test) {
var d = dispatch.dispatch("foo", "bar"), a = {}, b = {}, those = [];
function A() { those.push(a); }
function B() { those.push(b); }
d.on(".a", A).on("foo.a", B).on("bar", B);
d.call("foo");
d.call("bar");
test.deepEqual(those, [b, b]);
test.equal(d.on(".a"), undefined);
test.end();
});
tape("dispatch(type…).copy() returns an isolated copy", function(test) {
var foo = function() {},
bar = function() {},
d0 = dispatch.dispatch("foo", "bar").on("foo", foo).on("bar", bar),
d1 = d0.copy();
test.equal(d1.on("foo"), foo);
test.equal(d1.on("bar"), bar);
// Changes to d1 don’t affect d0.
test.equal(d1.on("bar", null), d1);
test.equal(d1.on("bar"), undefined);
test.equal(d0.on("bar"), bar);
// Changes to d0 don’t affect d1.
test.equal(d0.on("foo", null), d0);
test.equal(d0.on("foo"), undefined);
test.equal(d1.on("foo"), foo);
test.end();
});