├── .editorconfig
├── .gitignore
├── .travis.yml
├── bower.json
├── demo
├── destroy.html
├── multiple.html
├── node.html
├── nodelist.html
└── selector.html
├── dist
└── good-listener.js
├── karma.conf.js
├── package.json
├── readme.md
├── src
├── is.js
└── listen.js
└── test
├── is.js
└── listen.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # http://editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | # Change these settings to your own preference
9 | indent_style = space
10 | indent_size = 4
11 |
12 | # We recommend you to keep these unchanged
13 | end_of_line = lf
14 | charset = utf-8
15 | trim_trailing_whitespace = true
16 | insert_final_newline = true
17 |
18 | [*.md]
19 | trim_trailing_whitespace = false
20 |
21 | [{package.json,bower.json}]
22 | indent_size = 2
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - stable
4 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "good-listener",
3 | "description": "A more versatile way of adding & removing event listeners",
4 | "version": "1.2.1",
5 | "license": "MIT",
6 | "main": "dist/good-listener.js",
7 | "keywords": [
8 | "event",
9 | "listener"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/demo/destroy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Destroy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/multiple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Selector
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/demo/node.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demo/nodelist.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NodeList
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Selector
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/dist/good-listener.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.listen = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o A more versatile way of adding & removing event listeners.
6 |
7 | 
8 |
9 | ## Install
10 |
11 | You can get it on npm.
12 |
13 | ```
14 | npm install good-listener --save
15 | ```
16 |
17 | Or bower, too.
18 |
19 | ```
20 | bower install good-listener --save
21 | ```
22 |
23 | If you're not into package management, just [download a ZIP](https://github.com/zenorocha/good-listener/archive/master.zip) file.
24 |
25 | ## Setup
26 |
27 | ###### Node (Browserify)
28 |
29 | ```js
30 | var listen = require('good-listener');
31 | ```
32 |
33 | ###### Browser (Standalone)
34 |
35 | ```html
36 |
37 | ```
38 |
39 | ## Usage
40 |
41 | ### Add an event listener
42 |
43 | By passing a string selector [(see full demo)](https://github.com/zenorocha/good-listener/blob/master/demo/selector.html).
44 |
45 | ```js
46 | listen('.btn', 'click', function(e) {
47 | console.log(e);
48 | });
49 | ```
50 |
51 | Or by passing a HTML element [(see full demo)](https://github.com/zenorocha/good-listener/blob/master/demo/node.html).
52 |
53 | ```js
54 | var logo = document.getElementById('logo');
55 |
56 | listen(logo, 'click', function(e) {
57 | console.log(e);
58 | });
59 | ```
60 |
61 | Or by passing a list of HTML elements [(see full demo)](https://github.com/zenorocha/good-listener/blob/master/demo/nodelist.html).
62 |
63 | ```js
64 | var anchors = document.querySelectorAll('a');
65 |
66 | listen(anchors, 'click', function(e) {
67 | console.log(e);
68 | });
69 | ```
70 |
71 | ### Remove an event listener
72 |
73 | By calling the `destroy` function that returned from previous operation [(see full demo)](https://github.com/zenorocha/good-listener/blob/master/demo/destroy.html).
74 |
75 | ```js
76 | var listener = listen('.btn', 'click', function(e) {
77 | console.log(e);
78 | });
79 |
80 | listener.destroy();
81 | ```
82 |
83 | ## Browser Support
84 |
85 | |
|
|
|
|
|
|
86 | |:---:|:---:|:---:|:---:|:---:|:---:|
87 | | Latest ✔ | Latest ✔ | Latest ✔ | 9+ ✔ | Latest ✔ | Latest ✔ |
88 |
89 | ## License
90 |
91 | [MIT License](http://zenorocha.mit-license.org/) © Zeno Rocha
92 |
--------------------------------------------------------------------------------
/src/is.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Check if argument is a HTML element.
3 | *
4 | * @param {Object} value
5 | * @return {Boolean}
6 | */
7 | exports.node = function(value) {
8 | return value !== undefined
9 | && value instanceof HTMLElement
10 | && value.nodeType === 1;
11 | };
12 |
13 | /**
14 | * Check if argument is a list of HTML elements.
15 | *
16 | * @param {Object} value
17 | * @return {Boolean}
18 | */
19 | exports.nodeList = function(value) {
20 | var type = Object.prototype.toString.call(value);
21 |
22 | return value !== undefined
23 | && (type === '[object NodeList]' || type === '[object HTMLCollection]')
24 | && ('length' in value)
25 | && (value.length === 0 || exports.node(value[0]));
26 | };
27 |
28 | /**
29 | * Check if argument is a SVG element.
30 | *
31 | * @param {Object} value
32 | * @return {Boolean}
33 | */
34 | exports.svg = function(value) {
35 | return value !== undefined
36 | && value instanceof SVGElement;
37 | };
38 |
39 | /**
40 | * Check if argument is a string.
41 | *
42 | * @param {Object} value
43 | * @return {Boolean}
44 | */
45 | exports.string = function(value) {
46 | return typeof value === 'string'
47 | || value instanceof String;
48 | };
49 |
50 | /**
51 | * Check if argument is a function.
52 | *
53 | * @param {Object} value
54 | * @return {Boolean}
55 | */
56 | exports.fn = function(value) {
57 | var type = Object.prototype.toString.call(value);
58 |
59 | return type === '[object Function]';
60 | };
61 |
--------------------------------------------------------------------------------
/src/listen.js:
--------------------------------------------------------------------------------
1 | var is = require('./is');
2 | var delegate = require('delegate');
3 |
4 | /**
5 | * Validates all params and calls the right
6 | * listener function based on its target type.
7 | *
8 | * @param {String|HTMLElement|HTMLCollection|NodeList} target
9 | * @param {String} type
10 | * @param {Function} callback
11 | * @return {Object}
12 | */
13 | function listen(target, type, callback) {
14 | if (!target && !type && !callback) {
15 | throw new Error('Missing required arguments');
16 | }
17 |
18 | if (!is.string(type)) {
19 | throw new TypeError('Second argument must be a String');
20 | }
21 |
22 | if (!is.fn(callback)) {
23 | throw new TypeError('Third argument must be a Function');
24 | }
25 |
26 | if (is.node(target)) {
27 | return listenNode(target, type, callback);
28 | }
29 | else if (is.nodeList(target)) {
30 | return listenNodeList(target, type, callback);
31 | }
32 | else if (is.string(target)) {
33 | return listenSelector(target, type, callback);
34 | }
35 | else {
36 | throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
37 | }
38 | }
39 |
40 | /**
41 | * Adds an event listener to a HTML element
42 | * and returns a remove listener function.
43 | *
44 | * @param {HTMLElement} node
45 | * @param {String} type
46 | * @param {Function} callback
47 | * @return {Object}
48 | */
49 | function listenNode(node, type, callback) {
50 | node.addEventListener(type, callback);
51 |
52 | return {
53 | destroy: function() {
54 | node.removeEventListener(type, callback);
55 | }
56 | }
57 | }
58 |
59 | /**
60 | * Add an event listener to a list of HTML elements
61 | * and returns a remove listener function.
62 | *
63 | * @param {NodeList|HTMLCollection} nodeList
64 | * @param {String} type
65 | * @param {Function} callback
66 | * @return {Object}
67 | */
68 | function listenNodeList(nodeList, type, callback) {
69 | Array.prototype.forEach.call(nodeList, function(node) {
70 | node.addEventListener(type, callback);
71 | });
72 |
73 | return {
74 | destroy: function() {
75 | Array.prototype.forEach.call(nodeList, function(node) {
76 | node.removeEventListener(type, callback);
77 | });
78 | }
79 | }
80 | }
81 |
82 | /**
83 | * Add an event listener to a selector
84 | * and returns a remove listener function.
85 | *
86 | * @param {String} selector
87 | * @param {String} type
88 | * @param {Function} callback
89 | * @return {Object}
90 | */
91 | function listenSelector(selector, type, callback) {
92 | return delegate(document.body, selector, type, callback);
93 | }
94 |
95 | module.exports = listen;
96 |
--------------------------------------------------------------------------------
/test/is.js:
--------------------------------------------------------------------------------
1 | var is = require('../src/is');
2 |
3 | describe('is', function() {
4 | before(function() {
5 | global.node = document.createElement('div');
6 | global.node.setAttribute('id', 'foo');
7 | global.node.setAttribute('class', 'foo');
8 | document.body.appendChild(global.node);
9 |
10 | global.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
11 | global.svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
12 | global.svg.setAttribute('id', 'svg');
13 | global.svg.setAttribute('class', 'svg');
14 | document.body.appendChild(global.svg);
15 | });
16 |
17 | after(function() {
18 | document.body.innerHTML = '';
19 | });
20 |
21 | describe('is.node', function() {
22 | it('should be considered as node', function() {
23 | assert.ok(is.node(document.getElementById('foo')));
24 | assert.ok(is.node(document.getElementsByTagName('div')[0]));
25 | assert.ok(is.node(document.getElementsByClassName('foo')[0]));
26 | assert.ok(is.node(document.querySelector('.foo')));
27 | });
28 |
29 | it('should not be considered as node', function() {
30 | // is.nodeList
31 | assert.notOk(is.node(document.getElementsByTagName('div')));
32 | assert.notOk(is.node(document.getElementsByClassName('foo')));
33 | assert.notOk(is.node(document.querySelectorAll('.foo')));
34 |
35 | // is.string
36 | assert.notOk(is.node('abc'));
37 | assert.notOk(is.node(new String('abc')));
38 |
39 | // is.svg
40 | assert.notOk(is.node(document.getElementById('svg')));
41 | assert.notOk(is.node(document.getElementsByTagName('svg')[0]));
42 | assert.notOk(is.node(document.getElementsByClassName('svg')[0]));
43 | assert.notOk(is.node(document.querySelector('.svg')));
44 |
45 | // is.fn
46 | assert.notOk(is.node(function () {}));
47 |
48 | // everything else
49 | assert.notOk(is.node(undefined));
50 | assert.notOk(is.node(null));
51 | assert.notOk(is.node(false));
52 | assert.notOk(is.node(true));
53 | assert.notOk(is.node([]));
54 | assert.notOk(is.node({}));
55 | assert.notOk(is.node(/a/g));
56 | assert.notOk(is.node(new RegExp('a', 'g')));
57 | assert.notOk(is.node(new Date()));
58 | assert.notOk(is.node(42));
59 | assert.notOk(is.node(NaN));
60 | assert.notOk(is.node(Infinity));
61 | assert.notOk(is.node(new Number(42)));
62 | });
63 | });
64 |
65 | describe('is.nodeList', function() {
66 | it('should be considered as nodeList', function() {
67 | assert.ok(is.nodeList(document.getElementsByTagName('div')));
68 | assert.ok(is.nodeList(document.getElementsByClassName('foo')));
69 | assert.ok(is.nodeList(document.querySelectorAll('.foo')));
70 | });
71 |
72 | it('should not be considered as nodeList', function() {
73 | // is.node
74 | assert.notOk(is.nodeList(document.getElementById('foo')));
75 | assert.notOk(is.nodeList(document.getElementsByTagName('div')[0]));
76 | assert.notOk(is.nodeList(document.getElementsByClassName('foo')[0]));
77 | assert.notOk(is.nodeList(document.querySelector('.foo')));
78 |
79 | // is.string
80 | assert.notOk(is.nodeList('abc'));
81 | assert.notOk(is.nodeList(new String('abc')));
82 |
83 | // is.svg
84 | assert.notOk(is.nodeList(document.getElementById('svg')));
85 | assert.notOk(is.nodeList(document.getElementsByTagName('svg')[0]));
86 | assert.notOk(is.nodeList(document.getElementsByClassName('svg')[0]));
87 | assert.notOk(is.nodeList(document.querySelector('.svg')));
88 |
89 | // is.fn
90 | assert.notOk(is.nodeList(function () {}));
91 |
92 | // everything else
93 | assert.notOk(is.nodeList(undefined));
94 | assert.notOk(is.nodeList(null));
95 | assert.notOk(is.nodeList(false));
96 | assert.notOk(is.nodeList(true));
97 | assert.notOk(is.nodeList([]));
98 | assert.notOk(is.nodeList({}));
99 | assert.notOk(is.nodeList(/a/g));
100 | assert.notOk(is.nodeList(new RegExp('a', 'g')));
101 | assert.notOk(is.nodeList(new Date()));
102 | assert.notOk(is.nodeList(42));
103 | assert.notOk(is.nodeList(NaN));
104 | assert.notOk(is.nodeList(Infinity));
105 | assert.notOk(is.nodeList(new Number(42)));
106 | });
107 | });
108 |
109 | describe('is.string', function() {
110 | it('should be considered as string', function() {
111 | assert.ok(is.string('abc'));
112 | assert.ok(is.string(new String('abc')));
113 | });
114 |
115 | it('should not be considered as string', function() {
116 | // is.node
117 | assert.notOk(is.string(document.getElementById('foo')));
118 | assert.notOk(is.string(document.getElementsByTagName('div')[0]));
119 | assert.notOk(is.string(document.getElementsByClassName('foo')[0]));
120 | assert.notOk(is.string(document.querySelector('.foo')));
121 |
122 | // is.nodeList
123 | assert.notOk(is.string(document.getElementsByTagName('div')));
124 | assert.notOk(is.string(document.getElementsByClassName('foo')));
125 | assert.notOk(is.string(document.querySelectorAll('.foo')));
126 |
127 | // is.svg
128 | assert.notOk(is.string(document.getElementById('svg')));
129 | assert.notOk(is.string(document.getElementsByTagName('svg')[0]));
130 | assert.notOk(is.string(document.getElementsByClassName('svg')[0]));
131 | assert.notOk(is.string(document.querySelector('.svg')));
132 |
133 | // is.fn
134 | assert.notOk(is.string(function () {}));
135 |
136 | // everything else
137 | assert.notOk(is.string(undefined));
138 | assert.notOk(is.string(null));
139 | assert.notOk(is.string(false));
140 | assert.notOk(is.string(true));
141 | assert.notOk(is.string([]));
142 | assert.notOk(is.string({}));
143 | assert.notOk(is.string(/a/g));
144 | assert.notOk(is.string(new RegExp('a', 'g')));
145 | assert.notOk(is.string(new Date()));
146 | assert.notOk(is.string(42));
147 | assert.notOk(is.string(NaN));
148 | assert.notOk(is.string(Infinity));
149 | assert.notOk(is.string(new Number(42)));
150 | });
151 | });
152 |
153 | describe('is.svg', function() {
154 | it('should be considered as svg', function() {
155 | assert.ok(is.svg(document.getElementById('svg')));
156 | assert.ok(is.svg(document.getElementsByTagName('svg')[0]));
157 | assert.ok(is.svg(document.getElementsByClassName('svg')[0]));
158 | assert.ok(is.svg(document.querySelector('.svg')));
159 | });
160 |
161 | it('should not be considered as svg', function() {
162 | // is.node
163 | assert.notOk(is.svg(document.getElementById('foo')));
164 | assert.notOk(is.svg(document.getElementsByTagName('div')[0]));
165 | assert.notOk(is.svg(document.getElementsByClassName('foo')[0]));
166 | assert.notOk(is.svg(document.querySelector('.foo')));
167 |
168 | // is.nodeList
169 | assert.notOk(is.svg(document.getElementsByTagName('div')));
170 | assert.notOk(is.svg(document.getElementsByClassName('foo')));
171 | assert.notOk(is.svg(document.querySelectorAll('.foo')));
172 |
173 | // is.string
174 | assert.notOk(is.svg('abc'));
175 | assert.notOk(is.svg(new String('abc')));
176 |
177 | // is.fn
178 | assert.notOk(is.svg(function () {}));
179 |
180 | // everything else
181 | assert.notOk(is.svg(undefined));
182 | assert.notOk(is.svg(null));
183 | assert.notOk(is.svg(false));
184 | assert.notOk(is.svg(true));
185 | assert.notOk(is.svg([]));
186 | assert.notOk(is.svg({}));
187 | assert.notOk(is.svg(/a/g));
188 | assert.notOk(is.svg(new RegExp('a', 'g')));
189 | assert.notOk(is.svg(new Date()));
190 | assert.notOk(is.svg(42));
191 | assert.notOk(is.svg(NaN));
192 | assert.notOk(is.svg(Infinity));
193 | assert.notOk(is.svg(new Number(42)));
194 | });
195 | });
196 |
197 | describe('is.fn', function() {
198 | it('should be considered as function', function() {
199 | assert.ok(is.fn(function () {}));
200 | });
201 |
202 | it('should not be considered as function', function() {
203 | // is.node
204 | assert.notOk(is.fn(document.getElementById('foo')));
205 | assert.notOk(is.fn(document.getElementsByTagName('div')[0]));
206 | assert.notOk(is.fn(document.getElementsByClassName('foo')[0]));
207 | assert.notOk(is.fn(document.querySelector('.foo')));
208 |
209 | // is.nodeList
210 | assert.notOk(is.fn(document.getElementsByTagName('div')));
211 | assert.notOk(is.fn(document.getElementsByClassName('foo')));
212 | assert.notOk(is.fn(document.querySelectorAll('.foo')));
213 |
214 | // is.string
215 | assert.notOk(is.fn('abc'));
216 | assert.notOk(is.fn(new String('abc')));
217 |
218 | // is.svg
219 | assert.notOk(is.fn(document.getElementById('svg')));
220 | assert.notOk(is.fn(document.getElementsByTagName('svg')[0]));
221 | assert.notOk(is.fn(document.getElementsByClassName('svg')[0]));
222 | assert.notOk(is.fn(document.querySelector('.svg')));
223 |
224 | // everything else
225 | assert.notOk(is.fn(undefined));
226 | assert.notOk(is.fn(null));
227 | assert.notOk(is.fn(false));
228 | assert.notOk(is.fn(true));
229 | assert.notOk(is.fn([]));
230 | assert.notOk(is.fn({}));
231 | assert.notOk(is.fn(/a/g));
232 | assert.notOk(is.fn(new RegExp('a', 'g')));
233 | assert.notOk(is.fn(new Date()));
234 | assert.notOk(is.fn(42));
235 | assert.notOk(is.fn(NaN));
236 | assert.notOk(is.fn(Infinity));
237 | assert.notOk(is.fn(new Number(42)));
238 | });
239 | });
240 | });
241 |
--------------------------------------------------------------------------------
/test/listen.js:
--------------------------------------------------------------------------------
1 | var listen = require('../src/listen');
2 | var simulant = require('simulant');
3 |
4 | describe('good-listener', function() {
5 | before(function() {
6 | global.node = document.createElement('div');
7 | global.node.setAttribute('id', 'foo');
8 | global.node.setAttribute('class', 'foo');
9 | document.body.appendChild(global.node);
10 | });
11 |
12 | after(function() {
13 | document.body.innerHTML = '';
14 | });
15 |
16 | describe('listen', function() {
17 | it('should throw an error since arguments were not passed', function(done) {
18 | try {
19 | listen();
20 | }
21 | catch(error) {
22 | assert.equal(error.message, 'Missing required arguments');
23 | done();
24 | }
25 | });
26 |
27 | it('should throw an error since "target" was invalid', function(done) {
28 | try {
29 | listen(null, 'click', function() {});
30 | }
31 | catch(error) {
32 | assert.equal(error.message, 'First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
33 | done();
34 | }
35 | });
36 |
37 | it('should throw an error since "type" was invalid', function(done) {
38 | try {
39 | listen('.btn', false, function() {});
40 | }
41 | catch(error) {
42 | assert.equal(error.message, 'Second argument must be a String');
43 | done();
44 | }
45 | });
46 |
47 | it('should throw an error since "callback" was invalid', function(done) {
48 | try {
49 | listen('.btn', 'click', []);
50 | }
51 | catch(error) {
52 | assert.equal(error.message, 'Third argument must be a Function');
53 | done();
54 | }
55 | });
56 | });
57 |
58 | describe('listenNode', function() {
59 | before(function() {
60 | global.target = document.querySelector('#foo');
61 | global.spy = sinon.spy(global.target, 'removeEventListener');
62 | });
63 |
64 | after(function() {
65 | global.spy.restore();
66 | });
67 |
68 | it('should add an event listener', function(done) {
69 | listen(global.target, 'click', function() {
70 | done();
71 | });
72 |
73 | simulant.fire(global.target, simulant('click'));
74 | });
75 |
76 | it('should remove an event listener', function() {
77 | var listener = listen(global.target, 'click', function() {});
78 |
79 | listener.destroy();
80 | assert.ok(global.spy.calledOnce);
81 | });
82 | });
83 |
84 | describe('listenNodeList', function() {
85 | before(function() {
86 | global.targets = document.querySelectorAll('.foo');
87 | global.spy = sinon.spy(global.targets[0], 'removeEventListener');
88 | });
89 |
90 | after(function() {
91 | global.spy.restore();
92 | });
93 |
94 | it('should add an event listener', function(done) {
95 | listen(global.targets, 'click', function() {
96 | done();
97 | });
98 |
99 | simulant.fire(global.targets[0], simulant('click'));
100 | });
101 |
102 | it('should remove an event listener', function() {
103 | var listener = listen(global.targets, 'click', function() {});
104 |
105 | listener.destroy();
106 | assert.ok(global.spy.calledOnce);
107 | });
108 | });
109 |
110 | describe('listenSelector', function() {
111 | before(function() {
112 | global.target = document.querySelector('.foo');
113 | global.spy = sinon.spy(document.body, 'removeEventListener');
114 | });
115 |
116 | after(function() {
117 | global.spy.restore();
118 | });
119 |
120 | it('should add an event listener', function(done) {
121 | listen('.foo', 'click', function() {
122 | done();
123 | });
124 |
125 | simulant.fire(global.target, simulant('click'));
126 | });
127 |
128 | it('should remove an event listener', function() {
129 | var listener = listen('.foo', 'click', function() {});
130 |
131 | listener.destroy();
132 | assert.ok(global.spy.calledOnce);
133 | });
134 | });
135 | });
136 |
--------------------------------------------------------------------------------