compago-listener
Advanced tools
Comparing version
'use strict'; | ||
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; })(); | ||
Object.defineProperty(exports, "__esModule", { | ||
@@ -9,7 +7,15 @@ value: true | ||
/** Used to split event names */ | ||
const reEventSplitter = /\s+/; | ||
const _reEventSplitter = /\s+/; | ||
/** | ||
* The Listener is an interface that provide methods to handle custom events. | ||
* Methods can be mixed in to any object to make it capable of listening to or emitting custom events. | ||
* Provides methods for event handling. | ||
* | ||
* @mixin | ||
* @example | ||
* | ||
* const emitter = Object.assign({}, Listener); | ||
* const listener = Object.assign({}, Listener); | ||
* listener.on(emitter, 'someEvent', listener.doSomething); | ||
* emitter.emit('someEvent'); | ||
* // listener.doSomething is invoked. | ||
*/ | ||
@@ -24,19 +30,20 @@ const Listener = exports.Listener = { | ||
* Adds an event listener for the specified event(s). | ||
* | ||
* The `callback` will be called with `this` being the listener | ||
* whenever `obj` emits event `name`. | ||
* whenever `obj` emits the `name` event. | ||
* | ||
* @param {Object} obj The object to listen to. | ||
* @param {string} name The event (or events separated by whitespace) to listen to. | ||
* @param {Function} callback The function called when the event is fired. | ||
* @return {Object} The host object. | ||
* @param {Object} obj the object to listen to | ||
* @param {string} name the event name or names separated by whitespace | ||
* @param {Function} callback the function to be called when the event is emitted | ||
* @returns {this} | ||
* @example | ||
* | ||
* View.on(Model, 'change', View.render); | ||
* // `View.render` will be invoked with `this` set to `View` when `Model` emits `change` event. | ||
* // `View.render` will be invoked with `this` set to the View when Model emits a `change` event. | ||
* | ||
* Collection.on(Model, 'add remove', Collection.count); | ||
* // `Collection.count` will be invoked every time `Model` fires `add` or `remove` events. | ||
* // `Collection.count` will be invoked every time the Model emits an `add` or a `remove` event. | ||
*/ | ||
on(obj, name, callback) { | ||
const names = reEventSplitter.test(name) ? name.split(reEventSplitter) : [name]; | ||
const names = _reEventSplitter.test(name) ? name.split(_reEventSplitter) : [name]; | ||
const events = obj._events || (obj._events = new Map()); | ||
@@ -58,19 +65,19 @@ const listeners = this._listeners || (this._listeners = new Map()); | ||
* | ||
* @param {Object} [obj] The object to stop listening to. | ||
* @param {string} [name] The event (or events) to stop listening to. | ||
* @param {Function} [callback] The callback function to be removed. | ||
* @return {Object} | ||
* @param {Object} [obj] the object to stop listening to | ||
* @param {string} [name] the event name or names | ||
* @param {Function} [callback] the callback function to be removed | ||
* @returns {this} | ||
* @example | ||
* | ||
* View.off(); | ||
* // `View` no longer listens to any event on any object. | ||
* // the View no longer listens to any event on any object. | ||
* | ||
* View.off(Model); | ||
* // `View` no longer listens to any event on `Model`. | ||
* // the View no longer listens to any event on the Model. | ||
* | ||
* View.off(Model, 'change'); | ||
* // no callback will be invoked when `Model` emits 'change' event. | ||
* // no callback will be invoked when the Model emits a `change` event. | ||
* | ||
* View.off(Model, 'change', this.render); | ||
* // `this.render` won't be invoked when `Model` emits 'change' event. | ||
* // `this.render` won't be invoked when the Model emits a `change` event. | ||
*/ | ||
@@ -81,3 +88,3 @@ off(obj, name, callback) { | ||
if (!allListeners || !allListeners.size) return this; | ||
name = name ? reEventSplitter.test(name) ? name.split(reEventSplitter) : [name] : undefined; | ||
const nameList = name ? _reEventSplitter.test(name) ? name.split(_reEventSplitter) : [name] : undefined; | ||
const deleteListener = !name && !callback; | ||
@@ -90,4 +97,4 @@ let listeners = allListeners; | ||
} | ||
listeners.forEach(function (listensTo, listener) { | ||
const names = name || listensTo; | ||
listeners.forEach((listensTo, listener) => { | ||
const names = nameList || listensTo; | ||
for (let i = names.length - 1; i >= 0; i--) { | ||
@@ -121,6 +128,6 @@ let hasListener; | ||
* | ||
* @param {string} name The event name. | ||
* @param {Object} [data] The hash of additional parameters that are sent to event listeners. | ||
* @param {Object} [emitter] The emitter of the event. | ||
* @return {Object} | ||
* @param {string} name the event name | ||
* @param {Object} [data] the hash of additional parameters that are sent to event listeners | ||
* @param {Object} [emitter] the emitter of the event | ||
* @returns {this} | ||
* @example | ||
@@ -130,10 +137,10 @@ * | ||
* Model.emit('change'); | ||
* //View.render is invoked with a parameter: {event: 'change', emitter: Model} | ||
* // `View.render` is invoked with a parameter: `{event: 'change', emitter: Model}` | ||
* | ||
* Model.emit('change', {previous: 'Zaphod'}); | ||
* //View.render is invoked with a parameter {event: 'change', emitter: Model, previous: `Zaphod`} | ||
* // `View.render` is invoked with a parameter `{event: 'change', emitter: Model, previous: 'Zaphod'}` | ||
* | ||
* Collection.emit('change', {}, Model); | ||
* //the third argument can be used to change event emitter, | ||
* //listeners will be invoked with a parameter {event: 'change', emitter: Model} | ||
* // the third argument can be used to change event emitter, | ||
* // listeners will be invoked with a parameter `{event: 'change', emitter: Model}` | ||
*/ | ||
@@ -152,3 +159,3 @@ emit(name) { | ||
if (handlers.length) { | ||
for (var i = 0, l = handlers.length; i < l; i++) { | ||
for (let i = 0, l = handlers.length; i < l; i++) { | ||
handlers[i][1].call(handlers[i][0], data); | ||
@@ -162,5 +169,6 @@ } | ||
* Removes all callbacks bound by other objects to the host object. | ||
* | ||
* It is used to easily dispose of the object. | ||
* | ||
* @return {Object} The host object. | ||
* @returns {this} | ||
* @example | ||
@@ -172,3 +180,3 @@ * | ||
* // both event listeners are now removed | ||
* // equivalent to Collection.off(Model), View.off(Model) | ||
* // equivalent to `Collection.off(Model), View.off(Model)` | ||
*/ | ||
@@ -179,9 +187,4 @@ free() { | ||
events.forEach(event => { | ||
for (let _ref of event) { | ||
var _ref2 = _slicedToArray(_ref, 2); | ||
let listener = _ref2[0]; | ||
let cb = _ref2[1]; | ||
listener._listeners.delete(this); | ||
for (const listener of event) { | ||
listener[0]._listeners.delete(this); | ||
} | ||
@@ -188,0 +191,0 @@ }); |
{ | ||
"name": "compago-listener", | ||
"version": "1.0.3", | ||
"description": "", | ||
"version": "1.0.4", | ||
"description": "A mixin that provides methods to handle events.", | ||
"main": "dist/node/index.js", | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"repository": { | ||
@@ -27,8 +24,6 @@ "type": "git", | ||
"build-node": "babel src/index.js --out-file dist/node/index.js", | ||
"build-browser": "npm run browserify && npm run uglify", | ||
"browserify": "browserify src/index.js -o dist/browser/listener.js -t [ babelify --presets [ es2015 ] ]", | ||
"uglify": "uglifyjs -mc < dist/browser/listener.js > dist/browser/listener.min.js", | ||
"clean": "rimraf dist && mkdirp dist dist/node dist/browser", | ||
"clean": "rimraf dist && mkdirp dist dist/node", | ||
"report-coverage": "cat ./coverage/lcov.info | codecov", | ||
"build": "npm run clean && npm run build-node && npm run build-browser", | ||
"lint": "eslint src/index.js tests/unit.test.js", | ||
"build": "npm run clean && npm run build-node", | ||
"test": "babel-node ./node_modules/istanbul/lib/cli cover node_modules/mocha/bin/_mocha -- -R spec tests/unit.test.js" | ||
@@ -51,2 +46,8 @@ }, | ||
}, | ||
"eslintConfig": { | ||
"extends": "airbnb", | ||
"rules": { | ||
"no-nested-ternary": 1 | ||
} | ||
}, | ||
"devDependencies": { | ||
@@ -56,5 +57,6 @@ "babel-cli": "^6.3.17", | ||
"babel-preset-node5": "^10.1.1", | ||
"babelify": "^7.2.0", | ||
"browserify": "^12.0.1", | ||
"codecov.io": "^0.1.6", | ||
"eslint": "^1.10.3", | ||
"eslint-config-airbnb": "^2.1.1", | ||
"eslint-plugin-react": "^3.13.1", | ||
"expect": "^1.13.4", | ||
@@ -64,5 +66,4 @@ "istanbul": "^1.0.0-alpha.2", | ||
"mocha": "^2.3.4", | ||
"rimraf": "^2.5.0", | ||
"uglify-js": "^2.6.1" | ||
"rimraf": "^2.5.0" | ||
} | ||
} |
100
src/index.js
/** Used to split event names */ | ||
const reEventSplitter = /\s+/; | ||
const _reEventSplitter = /\s+/; | ||
/** | ||
* The Listener is an interface that provide methods to handle custom events. | ||
* Methods can be mixed in to any object to make it capable of listening to or emitting custom events. | ||
* Provides methods for event handling. | ||
* | ||
* @mixin | ||
* @example | ||
* | ||
* const emitter = Object.assign({}, Listener); | ||
* const listener = Object.assign({}, Listener); | ||
* listener.on(emitter, 'someEvent', listener.doSomething); | ||
* emitter.emit('someEvent'); | ||
* // listener.doSomething is invoked. | ||
*/ | ||
@@ -16,19 +24,20 @@ export const Listener = { | ||
* Adds an event listener for the specified event(s). | ||
* | ||
* The `callback` will be called with `this` being the listener | ||
* whenever `obj` emits event `name`. | ||
* whenever `obj` emits the `name` event. | ||
* | ||
* @param {Object} obj The object to listen to. | ||
* @param {string} name The event (or events separated by whitespace) to listen to. | ||
* @param {Function} callback The function called when the event is fired. | ||
* @return {Object} The host object. | ||
* @param {Object} obj the object to listen to | ||
* @param {string} name the event name or names separated by whitespace | ||
* @param {Function} callback the function to be called when the event is emitted | ||
* @returns {this} | ||
* @example | ||
* | ||
* View.on(Model, 'change', View.render); | ||
* // `View.render` will be invoked with `this` set to `View` when `Model` emits `change` event. | ||
* // `View.render` will be invoked with `this` set to the View when Model emits a `change` event. | ||
* | ||
* Collection.on(Model, 'add remove', Collection.count); | ||
* // `Collection.count` will be invoked every time `Model` fires `add` or `remove` events. | ||
* // `Collection.count` will be invoked every time the Model emits an `add` or a `remove` event. | ||
*/ | ||
on(obj, name, callback){ | ||
const names = reEventSplitter.test(name) ? name.split(reEventSplitter) : [name]; | ||
on(obj, name, callback) { | ||
const names = _reEventSplitter.test(name) ? name.split(_reEventSplitter) : [name]; | ||
const events = obj._events || (obj._events = new Map()); | ||
@@ -38,3 +47,3 @@ const listeners = this._listeners || (this._listeners = new Map()); | ||
for(let i = 0, l = names.length; i < l; i++){ | ||
for (let i = 0, l = names.length; i < l; i++) { | ||
const eventName = names[i]; | ||
@@ -51,19 +60,19 @@ const event = events.get(eventName) || events.set(eventName, []).get(eventName); | ||
* | ||
* @param {Object} [obj] The object to stop listening to. | ||
* @param {string} [name] The event (or events) to stop listening to. | ||
* @param {Function} [callback] The callback function to be removed. | ||
* @return {Object} | ||
* @param {Object} [obj] the object to stop listening to | ||
* @param {string} [name] the event name or names | ||
* @param {Function} [callback] the callback function to be removed | ||
* @returns {this} | ||
* @example | ||
* | ||
* View.off(); | ||
* // `View` no longer listens to any event on any object. | ||
* // the View no longer listens to any event on any object. | ||
* | ||
* View.off(Model); | ||
* // `View` no longer listens to any event on `Model`. | ||
* // the View no longer listens to any event on the Model. | ||
* | ||
* View.off(Model, 'change'); | ||
* // no callback will be invoked when `Model` emits 'change' event. | ||
* // no callback will be invoked when the Model emits a `change` event. | ||
* | ||
* View.off(Model, 'change', this.render); | ||
* // `this.render` won't be invoked when `Model` emits 'change' event. | ||
* // `this.render` won't be invoked when the Model emits a `change` event. | ||
*/ | ||
@@ -74,3 +83,3 @@ off(obj, name, callback) { | ||
if (!allListeners || !allListeners.size) return this; | ||
name = name ? reEventSplitter.test(name) ? name.split(reEventSplitter) : [name] : undefined; | ||
const nameList = name ? _reEventSplitter.test(name) ? name.split(_reEventSplitter) : [name] : undefined; | ||
const deleteListener = !name && !callback; | ||
@@ -83,4 +92,4 @@ let listeners = allListeners; | ||
} | ||
listeners.forEach(function(listensTo, listener){ | ||
const names = name || listensTo; | ||
listeners.forEach((listensTo, listener) => { | ||
const names = nameList || listensTo; | ||
for (let i = names.length - 1; i >= 0; i--) { | ||
@@ -92,4 +101,4 @@ let hasListener; | ||
for (let j = events.length - 1; j >= 0; j--) { | ||
if(events[j][0] === emitter){ | ||
if(callback && callback !== events[j][1]) { | ||
if (events[j][0] === emitter) { | ||
if (callback && callback !== events[j][1]) { | ||
hasListener = true; | ||
@@ -115,6 +124,6 @@ continue; | ||
* | ||
* @param {string} name The event name. | ||
* @param {Object} [data] The hash of additional parameters that are sent to event listeners. | ||
* @param {Object} [emitter] The emitter of the event. | ||
* @return {Object} | ||
* @param {string} name the event name | ||
* @param {Object} [data] the hash of additional parameters that are sent to event listeners | ||
* @param {Object} [emitter] the emitter of the event | ||
* @returns {this} | ||
* @example | ||
@@ -124,12 +133,12 @@ * | ||
* Model.emit('change'); | ||
* //View.render is invoked with a parameter: {event: 'change', emitter: Model} | ||
* // `View.render` is invoked with a parameter: `{event: 'change', emitter: Model}` | ||
* | ||
* Model.emit('change', {previous: 'Zaphod'}); | ||
* //View.render is invoked with a parameter {event: 'change', emitter: Model, previous: `Zaphod`} | ||
* // `View.render` is invoked with a parameter `{event: 'change', emitter: Model, previous: 'Zaphod'}` | ||
* | ||
* Collection.emit('change', {}, Model); | ||
* //the third argument can be used to change event emitter, | ||
* //listeners will be invoked with a parameter {event: 'change', emitter: Model} | ||
* // the third argument can be used to change event emitter, | ||
* // listeners will be invoked with a parameter `{event: 'change', emitter: Model}` | ||
*/ | ||
emit(name, data={}, emitter=this){ | ||
emit(name, data = {}, emitter = this) { | ||
if (!name) return this; | ||
@@ -143,3 +152,3 @@ if (!this._events || !this._events.size) return this; | ||
if (handlers.length) { | ||
for (var i = 0, l = handlers.length; i < l; i++) { | ||
for (let i = 0, l = handlers.length; i < l; i++) { | ||
handlers[i][1].call(handlers[i][0], data); | ||
@@ -153,5 +162,6 @@ } | ||
* Removes all callbacks bound by other objects to the host object. | ||
* | ||
* It is used to easily dispose of the object. | ||
* | ||
* @return {Object} The host object. | ||
* @returns {this} | ||
* @example | ||
@@ -163,10 +173,10 @@ * | ||
* // both event listeners are now removed | ||
* // equivalent to Collection.off(Model), View.off(Model) | ||
* // equivalent to `Collection.off(Model), View.off(Model)` | ||
*/ | ||
free(){ | ||
free() { | ||
const events = this._events; | ||
if(!events) return this; | ||
events.forEach((event)=>{ | ||
for(let [listener, cb] of event){ | ||
listener._listeners.delete(this); | ||
if (!events) return this; | ||
events.forEach((event) => { | ||
for (const listener of event) { | ||
listener[0]._listeners.delete(this); | ||
} | ||
@@ -176,3 +186,3 @@ }); | ||
return this; | ||
} | ||
}; | ||
}, | ||
}; |
@@ -0,8 +1,13 @@ | ||
/* eslint-env node, mocha */ | ||
const Listener = require('../src/index').Listener; | ||
const expect = require('expect'); | ||
describe('Listener', function(){ | ||
var a, b, c; | ||
describe('Listener', () => { | ||
let a; | ||
let b; | ||
let c; | ||
beforeEach(function(){ | ||
beforeEach(() => { | ||
a = Object.assign({}, Listener); | ||
@@ -16,4 +21,4 @@ b = Object.assign({}, Listener); | ||
describe('on', function(){ | ||
it('adds an event listener', function() { | ||
describe('on', () => { | ||
it('adds an event listener', () => { | ||
a.on(b, 'someEvent anotherEvent', a.firstMethod); | ||
@@ -31,9 +36,9 @@ a.on(b, 'someEvent', a.secondMethod); | ||
describe('off', function(){ | ||
it('removes an event listener', function() { | ||
describe('off', () => { | ||
it('removes an event listener', () => { | ||
a.on(b, 'someEvent', a.firstMethod); | ||
a.on(b, 'someEvent', a.secondMethod); | ||
c.on(b, 'someEvent', c.someMethod); | ||
b.on(b, 'otherEvent', ()=>{}); | ||
b.on(b, 'otherEvent', () => { | ||
}); | ||
a.off(b, 'someEvent', a.firstMethod); | ||
@@ -47,3 +52,3 @@ expect(b._events.get('someEvent')[0][1]).toBe(a.secondMethod); | ||
it('returns if no valid listener is present', function() { | ||
it('returns if no valid listener is present', () => { | ||
expect(a.off()).toBe(a); | ||
@@ -56,3 +61,3 @@ a.on(b, 'someEvent', a.firstMethod); | ||
it('removes all listeners for an event', function(){ | ||
it('removes all listeners for an event', () => { | ||
a.on(b, 'someEvent', a.firstMethod); | ||
@@ -69,3 +74,3 @@ a.on(b, 'someEvent', a.secondMethod); | ||
it('removes all listeners set up by the object', function(){ | ||
it('removes all listeners set up by the object', () => { | ||
a.on(b, 'someEvent', a.firstMethod); | ||
@@ -81,25 +86,27 @@ a.on(b, 'someEvent', a.secondMethod); | ||
}); | ||
}); | ||
describe('emit', function(){ | ||
it('fires an event', function(){ | ||
describe('emit', () => { | ||
it('fires an event', () => { | ||
a.on(b, 'someEvent', a.firstMethod); | ||
a.on(b, 'otherEvent', a.secondMethod); | ||
b.emit('someEvent', {width:1}); | ||
expect(a.firstMethod.calls[0].arguments[0]).toEqual({event:'someEvent', emitter:b, width:1}); | ||
b.emit('someEvent', { width: 1 }); | ||
expect(a.firstMethod.calls[0].arguments[0]).toEqual({ | ||
event: 'someEvent', | ||
emitter: b, | ||
width: 1, | ||
}); | ||
b.emit('otherEvent'); | ||
expect(a.secondMethod.calls[0].arguments[0]).toEqual({event:'otherEvent', emitter:b}); | ||
expect(a.secondMethod.calls[0].arguments[0]).toEqual({ event: 'otherEvent', emitter: b }); | ||
}); | ||
it('returns if no event is specified', function(){ | ||
it('returns if no event is specified', () => { | ||
expect(b.emit()).toBe(b); | ||
}); | ||
it('returns if there is no listener for any event', function(){ | ||
it('returns if there is no listener for any event', () => { | ||
expect(b.emit('event')).toBe(b); | ||
}); | ||
it('returns if there is no listener for the event', function(){ | ||
it('returns if there is no listener for the event', () => { | ||
a.on(b, 'someEvent', a.firstMethod); | ||
@@ -110,12 +117,20 @@ expect(b.emit('otherEvent')).toBe(b); | ||
it('emits `all` event every time an event is fired', function(){ | ||
it('emits `all` event every time an event is fired', () => { | ||
a.on(b, 'someEvent', a.secondMethod); | ||
a.on(b, 'all', a.firstMethod); | ||
b.emit('someEvent', {width:1}); | ||
expect(a.secondMethod.calls[0].arguments[0]).toEqual({event:'someEvent', emitter:b, width:1}); | ||
expect(a.firstMethod.calls[0].arguments[0]).toEqual({event:'someEvent', emitter:b, width:1}); | ||
b.emit('someEvent', { width: 1 }); | ||
expect(a.secondMethod.calls[0].arguments[0]).toEqual({ | ||
event: 'someEvent', | ||
emitter: b, | ||
width: 1, | ||
}); | ||
expect(a.firstMethod.calls[0].arguments[0]).toEqual({ | ||
event: 'someEvent', | ||
emitter: b, | ||
width: 1, | ||
}); | ||
b.emit('otherEvent'); | ||
expect(a.firstMethod.calls[1].arguments[0]).toEqual({event:'otherEvent', emitter:b}); | ||
expect(a.firstMethod.calls[1].arguments[0]).toEqual({ event: 'otherEvent', emitter: b }); | ||
b.emit('someEvent'); | ||
expect(a.firstMethod.calls[2].arguments[0]).toEqual({event:'someEvent', emitter:b}); | ||
expect(a.firstMethod.calls[2].arguments[0]).toEqual({ event: 'someEvent', emitter: b }); | ||
expect(a.secondMethod.calls.length).toBe(2); | ||
@@ -125,12 +140,11 @@ expect(a.firstMethod.calls.length).toBe(3); | ||
it('passes custom emitter to the event listeners if specified', function(){ | ||
it('passes custom emitter to the event listeners if specified', () => { | ||
a.on(b, 'someEvent', a.firstMethod); | ||
b.emit('someEvent', {}, a); | ||
expect(a.firstMethod.calls[0].arguments[0]).toEqual({event:'someEvent', emitter:a}); | ||
expect(a.firstMethod.calls[0].arguments[0]).toEqual({ event: 'someEvent', emitter: a }); | ||
}); | ||
}); | ||
describe('free', function(){ | ||
it('removes all listeners from the object set up by other objects', function(){ | ||
describe('free', () => { | ||
it('removes all listeners from the object set up by other objects', () => { | ||
expect(b.free()).toBe(b); | ||
@@ -145,3 +159,2 @@ a.on(b, 'someEvent', a.firstMethod); | ||
}); | ||
}); | ||
}); |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1
-50%0
-100%21534
-32.02%9
-10%475
-26.24%