Release
This commit is contained in:
138
client/islets/core/y-event-manager/y-event-manager.js
Normal file
138
client/islets/core/y-event-manager/y-event-manager.js
Normal file
@@ -0,0 +1,138 @@
|
||||
modules.define(
|
||||
'y-event-manager',
|
||||
[
|
||||
'inherit',
|
||||
'y-event-emitter',
|
||||
'jquery'
|
||||
],
|
||||
function (
|
||||
provide,
|
||||
inherit,
|
||||
YEventEmitter,
|
||||
$
|
||||
) {
|
||||
|
||||
/**
|
||||
* Адаптер для YEventEmitter, jQuery. Позволяет привязывать обработчики к разным эмиттерам событий
|
||||
* и отвязывать их, используя вызов одной функции. Менеджер всегда привязан к какому-либо объекту, который
|
||||
* является контекстом для всех обработчиков.
|
||||
*
|
||||
* Полезен, когда нужно отвязать все обработчики сразу. Например, при уничтожении объекта.
|
||||
*
|
||||
* @example
|
||||
* function UserView(model, el) {
|
||||
* this._eventManager = new YEventManager(this);
|
||||
*
|
||||
* // Привязываем обработчик к YEventEmitter
|
||||
* this._eventManager.bindTo(model, 'change-name', this._changeName);
|
||||
*
|
||||
* // Привязываем обработчик к jQuery объекту
|
||||
* var hideEl = el.find('.hide');
|
||||
* this._eventManager.bindTo(hideEl, 'click', this._hide);
|
||||
* }
|
||||
*
|
||||
* UserView.prototype.destruct = function () {
|
||||
* // Удаляем все обработчики
|
||||
* this._eventManager.unbindAll();
|
||||
* };
|
||||
*
|
||||
* UserView.prototype._changeName = function () {};
|
||||
*
|
||||
* UserView.prototype._hide = function () {};
|
||||
*/
|
||||
var YEventManager = inherit({
|
||||
/**
|
||||
* Создает менджер событий для переданного объекта.
|
||||
*
|
||||
* @param {Object} owner Контекст для всех обработчиков событий.
|
||||
*/
|
||||
__constructor: function (owner) {
|
||||
this._owner = owner;
|
||||
this._listeners = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Привязывает обработчик к переданному эмиттеру событий.
|
||||
*
|
||||
* @param {YEventEmitter|jQuery} emitter
|
||||
* @param {String} event
|
||||
* @param {Function} callback
|
||||
* @returns {YEventManager}
|
||||
*/
|
||||
bindTo: function (emitter, event, callback) {
|
||||
if (emitter instanceof YEventEmitter) {
|
||||
this._listeners.push({
|
||||
type: 'islets',
|
||||
emitter: emitter.on(event, callback, this._owner),
|
||||
event: event,
|
||||
callback: callback
|
||||
});
|
||||
} else if (emitter instanceof $) {
|
||||
var proxy = callback.bind(this._owner);
|
||||
this._listeners.push({
|
||||
type: 'jquery',
|
||||
emitter: emitter.on(event, proxy),
|
||||
event: event,
|
||||
callback: callback,
|
||||
proxy: proxy
|
||||
});
|
||||
} else {
|
||||
throw new Error('Unsupported emitter type');
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Отвязывает обработчик от переданного эмиттера событий.
|
||||
*
|
||||
* @param {YEventEmitter|jQuery} emitter
|
||||
* @param {String} event
|
||||
* @param {Function} callback
|
||||
* @returns {YEventManager}
|
||||
*/
|
||||
unbindFrom: function (emitter, event, callback) {
|
||||
for (var i = 0; i < this._listeners.length; i++) {
|
||||
var listener = this._listeners[i];
|
||||
if (listener.emitter === emitter &&
|
||||
listener.event === event &&
|
||||
listener.callback === callback
|
||||
) {
|
||||
this._unbind(listener);
|
||||
this._listeners.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Отвязывает все обработчики от всех эмиттеров событий.
|
||||
*
|
||||
* @returns {YEventManager}
|
||||
*/
|
||||
unbindAll: function () {
|
||||
while (this._listeners.length) {
|
||||
var listener = this._listeners.pop();
|
||||
this._unbind(listener);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Отвязывает обработчик события.
|
||||
*
|
||||
* @param {Object} listener
|
||||
*/
|
||||
_unbind: function (listener) {
|
||||
switch (listener.type) {
|
||||
case 'islets':
|
||||
listener.emitter.off(listener.event, listener.callback, this._owner);
|
||||
break;
|
||||
case 'jquery':
|
||||
listener.emitter.off(listener.event, listener.proxy);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
provide(YEventManager);
|
||||
});
|
||||
5
client/islets/core/y-event-manager/y-event-manager.md
Normal file
5
client/islets/core/y-event-manager/y-event-manager.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Адаптер для YEventEmitter, jQuery. Позволяет привязывать обработчики к разным эмиттерам событий
|
||||
и отвязывать их, используя вызов одной функции. Менеджер всегда привязан к какому-либо объекту, который
|
||||
является контекстом для всех обработчиков.
|
||||
|
||||
<!--JS_API-->
|
||||
267
client/islets/core/y-event-manager/y-event-manager.test.js
Normal file
267
client/islets/core/y-event-manager/y-event-manager.test.js
Normal file
@@ -0,0 +1,267 @@
|
||||
modules.define(
|
||||
'test',
|
||||
[
|
||||
'y-event-manager',
|
||||
'y-event-emitter',
|
||||
'jquery'
|
||||
],
|
||||
function (
|
||||
provide,
|
||||
YEventManager,
|
||||
YEventEmitter,
|
||||
$
|
||||
) {
|
||||
|
||||
describe('YEventManager', function () {
|
||||
var manager;
|
||||
var owner;
|
||||
|
||||
beforeEach(function () {
|
||||
owner = {};
|
||||
manager = new YEventManager(owner);
|
||||
});
|
||||
|
||||
describe('bindTo()', function () {
|
||||
it('should bind event listeners to YEventEmitter', function () {
|
||||
var emitter = new YEventEmitter();
|
||||
var spy1 = sinon.spy();
|
||||
var spy2 = sinon.spy();
|
||||
var spy3 = sinon.spy();
|
||||
|
||||
manager.bindTo(emitter, 'event1', spy1).should.eq(manager);
|
||||
manager.bindTo(emitter, 'event2', spy2);
|
||||
manager.bindTo(emitter, 'event2', spy3);
|
||||
|
||||
emitter.emit('event1', 1, 2);
|
||||
spy1.callCount.should.eq(1);
|
||||
spy1.calledWithExactly(1, 2).should.be.true;
|
||||
spy1.calledOn(owner).should.be.true;
|
||||
spy2.callCount.should.eq(0);
|
||||
spy3.callCount.should.eq(0);
|
||||
|
||||
emitter.emit('event2', 3, 4);
|
||||
spy1.callCount.should.eq(1);
|
||||
spy2.callCount.should.eq(1);
|
||||
spy2.calledWithExactly(3, 4).should.be.true;
|
||||
spy2.calledOn(owner).should.be.true;
|
||||
spy3.callCount.should.eq(1);
|
||||
spy3.calledWithExactly(3, 4).should.be.true;
|
||||
spy3.calledOn(owner).should.be.true;
|
||||
});
|
||||
|
||||
it('should bind event listeners to jQuery', function () {
|
||||
var jqObj = $({});
|
||||
var spy1 = sinon.spy();
|
||||
var spy2 = sinon.spy();
|
||||
var spy3 = sinon.spy();
|
||||
|
||||
manager.bindTo(jqObj, 'event1', spy1).should.eq(manager);
|
||||
manager.bindTo(jqObj, 'event2', spy2);
|
||||
manager.bindTo(jqObj, 'event2', spy3);
|
||||
|
||||
var data = {};
|
||||
jqObj.trigger('event1', data);
|
||||
spy1.callCount.should.eq(1);
|
||||
var args = spy1.getCall(0).args;
|
||||
args[1].should.eq(data);
|
||||
spy2.called.should.be.false;
|
||||
spy3.called.should.be.false;
|
||||
|
||||
jqObj.trigger('event2', [3, 4]);
|
||||
spy1.callCount.should.eq(1);
|
||||
spy2.callCount.should.eq(1);
|
||||
args = spy2.getCall(0).args;
|
||||
args[1].should.eq(3);
|
||||
args[2].should.eq(4);
|
||||
spy3.callCount.should.eq(1);
|
||||
args = spy3.getCall(0).args;
|
||||
args[1].should.eq(3);
|
||||
args[2].should.eq(4);
|
||||
});
|
||||
|
||||
it('should throw error for unsupported emitter type', function () {
|
||||
/* jshint -W068 */
|
||||
(function () {
|
||||
var FakeEmitter = {
|
||||
events: [],
|
||||
on: function () {}
|
||||
};
|
||||
manager.bindTo(FakeEmitter, 'event', function () {});
|
||||
}).should.throw(Error, 'Unsupported emitter type');
|
||||
});
|
||||
|
||||
it('should work with different emitters together', function () {
|
||||
var emitter = new YEventEmitter();
|
||||
var jqObj = $({});
|
||||
var emitterSpy1 = sinon.spy();
|
||||
var emitterSpy2 = sinon.spy();
|
||||
var jqSpy1 = sinon.spy();
|
||||
var jqSpy2 = sinon.spy();
|
||||
|
||||
manager.bindTo(emitter, 'event', emitterSpy2);
|
||||
manager.bindTo(jqObj, 'event', jqSpy1);
|
||||
manager.bindTo(jqObj, 'event', jqSpy2);
|
||||
manager.bindTo(emitter, 'event', emitterSpy1);
|
||||
|
||||
jqObj.trigger('event');
|
||||
jqSpy1.callCount.should.eq(1);
|
||||
jqSpy2.callCount.should.eq(1);
|
||||
emitterSpy1.callCount.should.eq(0);
|
||||
emitterSpy2.callCount.should.eq(0);
|
||||
|
||||
emitter.emit('event');
|
||||
jqSpy1.callCount.should.eq(1);
|
||||
jqSpy2.callCount.should.eq(1);
|
||||
emitterSpy1.callCount.should.eq(1);
|
||||
emitterSpy2.callCount.should.eq(1);
|
||||
|
||||
jqSpy1.alwaysCalledOn(owner);
|
||||
jqSpy2.alwaysCalledOn(owner);
|
||||
emitterSpy1.alwaysCalledOn(owner);
|
||||
emitterSpy2.alwaysCalledOn(owner);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unbindFrom()', function () {
|
||||
function testUnbind(emitter, anotherEmitter, emitFn) {
|
||||
var spy1 = sinon.spy();
|
||||
var spy2 = sinon.spy();
|
||||
var spy3 = sinon.spy();
|
||||
|
||||
manager.bindTo(anotherEmitter, 'event1', spy1);
|
||||
manager.bindTo(emitter, 'event1', spy1);
|
||||
manager.bindTo(emitter, 'event1', spy2);
|
||||
manager.bindTo(emitter, 'event2', spy3);
|
||||
|
||||
manager.unbindFrom(emitter, 'event1', spy1).should.eq(manager);
|
||||
|
||||
emitter[emitFn]('event1');
|
||||
spy1.called.should.be.false;
|
||||
spy2.calledOnce.should.be.true;
|
||||
spy2.calledOn(owner);
|
||||
|
||||
emitter[emitFn]('event2');
|
||||
spy3.calledOnce.should.be.true;
|
||||
spy3.calledOn(owner);
|
||||
|
||||
manager.unbindFrom(emitter, 'event1', spy2);
|
||||
manager.unbindFrom(emitter, 'event2', spy3);
|
||||
|
||||
emitter[emitFn]('event1');
|
||||
emitter[emitFn]('event2');
|
||||
|
||||
spy1.called.should.be.false;
|
||||
spy2.calledOnce.should.be.true;
|
||||
spy3.calledOnce.should.be.true;
|
||||
|
||||
anotherEmitter[emitFn]('event1');
|
||||
spy1.calledOnce.should.be.true;
|
||||
}
|
||||
|
||||
function testUnbindFirst(emitter, emitFn) {
|
||||
var spy = sinon.spy();
|
||||
|
||||
manager.bindTo(emitter, 'test', spy);
|
||||
manager.bindTo(emitter, 'test', spy);
|
||||
manager.bindTo(emitter, 'test', spy);
|
||||
manager.unbindFrom(emitter, 'test', spy);
|
||||
|
||||
emitter[emitFn]('test');
|
||||
spy.callCount.should.eq(2);
|
||||
|
||||
manager.unbindFrom(emitter, 'test', spy);
|
||||
emitter[emitFn]('test');
|
||||
spy.callCount.should.eq(3);
|
||||
|
||||
manager.unbindFrom(emitter, 'test', spy);
|
||||
emitter[emitFn]('test');
|
||||
spy.callCount.should.eq(3);
|
||||
}
|
||||
|
||||
it('should unbind event listeners from YEventEmitter', function () {
|
||||
var emitter1 = new YEventEmitter();
|
||||
var emitter2 = new YEventEmitter();
|
||||
testUnbind(emitter1, emitter2, 'emit');
|
||||
});
|
||||
|
||||
it('should unbind event listeners from jQuery', function () {
|
||||
var jqObj1 = $({});
|
||||
var jqObj2 = $({});
|
||||
testUnbind(jqObj1, jqObj2, 'trigger');
|
||||
});
|
||||
|
||||
it('should unbind first listener from list of same listeners', function () {
|
||||
var emitter = new YEventEmitter();
|
||||
testUnbindFirst(emitter, 'emit');
|
||||
var jqObj = $({});
|
||||
testUnbindFirst(jqObj, 'trigger');
|
||||
});
|
||||
|
||||
it('should work with different emitters together', function () {
|
||||
var emitter = new YEventEmitter();
|
||||
var jqObj = $({});
|
||||
|
||||
var emitterSpy1 = sinon.spy();
|
||||
var emitterSpy2 = sinon.spy();
|
||||
var jqSpy1 = sinon.spy();
|
||||
var jqSpy2 = sinon.spy();
|
||||
|
||||
manager.bindTo(emitter, 'event', emitterSpy2);
|
||||
manager.bindTo(jqObj, 'event', jqSpy1);
|
||||
manager.bindTo(jqObj, 'event', jqSpy2);
|
||||
manager.bindTo(emitter, 'event', emitterSpy1);
|
||||
|
||||
manager.unbindFrom(emitter, 'event', emitterSpy1);
|
||||
manager.unbindFrom(jqObj, 'event', jqSpy2);
|
||||
|
||||
jqObj.trigger('event');
|
||||
jqSpy1.callCount.should.eq(1);
|
||||
emitterSpy2.callCount.should.eq(0);
|
||||
|
||||
emitter.emit('event');
|
||||
jqSpy1.callCount.should.eq(1);
|
||||
emitterSpy2.callCount.should.eq(1);
|
||||
|
||||
emitterSpy1.called.should.be.false;
|
||||
jqSpy2.called.should.be.false;
|
||||
jqSpy1.alwaysCalledOn(owner);
|
||||
emitterSpy2.alwaysCalledOn(owner);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unbindAll()', function () {
|
||||
it('should unbind all events from different emitters', function () {
|
||||
var emitter = new YEventEmitter();
|
||||
var jqObj = $({});
|
||||
var spy = sinon.spy();
|
||||
|
||||
emitter.on('event5', spy);
|
||||
jqObj.on('event5', spy);
|
||||
|
||||
manager.bindTo(emitter, 'event1', spy);
|
||||
manager.bindTo(emitter, 'event2', spy);
|
||||
manager.bindTo(emitter, 'event2', spy);
|
||||
manager.bindTo(jqObj, 'event3', spy);
|
||||
manager.bindTo(jqObj, 'event4', spy);
|
||||
manager.bindTo(jqObj, 'event4', spy);
|
||||
|
||||
manager.unbindAll().should.eq(manager);
|
||||
|
||||
emitter.emit('event1');
|
||||
emitter.emit('event2');
|
||||
|
||||
jqObj.trigger('event3');
|
||||
jqObj.trigger('event4');
|
||||
|
||||
spy.called.should.be.false;
|
||||
|
||||
emitter.emit('event5');
|
||||
spy.calledOnce.should.be.true;
|
||||
jqObj.trigger('event5');
|
||||
spy.calledTwice.should.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
provide();
|
||||
});
|
||||
Reference in New Issue
Block a user