1
0
mirror of https://github.com/videojs/video.js.git synced 2024-12-25 02:42:10 +02:00

Added support for listening to multiple events through a types array. closes #1231

This commit is contained in:
themicp 2014-07-08 11:51:47 -07:00 committed by Steve Heffernan
parent d5372545a2
commit 392cbda095
5 changed files with 144 additions and 3 deletions

View File

@ -12,6 +12,7 @@ CHANGELOG
* Exported missing Player API methods (remainingTime, supportsFullScreen, enterFullWindow, exitFullWindow, preload) ([view](https://github.com/videojs/video.js/pull/1328))
* Added a base for running saucelabs tests from grunt ([view](https://github.com/videojs/video.js/pull/1215))
* Added additional browsers for saucelabs testing ([view](https://github.com/videojs/video.js/pull/1216))
* Added support for listening to multiple events through a types array ([view](https://github.com/videojs/video.js/pull/1231))
--------------------

View File

@ -11,11 +11,15 @@
* and adds a generic handler to the element's event,
* along with a unique id (guid) to the element.
* @param {Element|Object} elem Element or object to bind listeners to
* @param {String} type Type of event to bind to.
* @param {String|Array} type Type of event to bind to.
* @param {Function} fn Event listener.
* @private
*/
vjs.on = function(elem, type, fn){
if (vjs.obj.isArray(type)) {
return _handleMultipleEvents(vjs.on, elem, type, fn);
}
var data = vjs.getData(elem);
// We need a place to store all our handler data
@ -64,7 +68,7 @@ vjs.on = function(elem, type, fn){
/**
* Removes event listeners from an element
* @param {Element|Object} elem Object to remove listeners from
* @param {String=} type Type of listener to remove. Don't include to remove all events from element.
* @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element.
* @param {Function} fn Specific listener to remove. Don't incldue to remove listeners for an event type.
* @private
*/
@ -77,6 +81,10 @@ vjs.off = function(elem, type, fn) {
// If no events exist, nothing to unbind
if (!data.handlers) { return; }
if (vjs.obj.isArray(type)) {
return _handleMultipleEvents(vjs.off, elem, type, fn);
}
// Utility function
var removeType = function(t){
data.handlers[t] = [];
@ -337,15 +345,33 @@ vjs.trigger = function(elem, event) {
/**
* Trigger a listener only once for an event
* @param {Element|Object} elem Element or object to
* @param {String} type
* @param {String|Array} type
* @param {Function} fn
* @private
*/
vjs.one = function(elem, type, fn) {
if (vjs.obj.isArray(type)) {
return _handleMultipleEvents(vjs.one, elem, type, fn);
}
var func = function(){
vjs.off(elem, type, func);
fn.apply(this, arguments);
};
// copy the guid to the new function so it can removed using the original function's ID
func.guid = fn.guid = fn.guid || vjs.guid++;
vjs.on(elem, type, func);
};
/**
* Loops through an array of event types and calls the requested method for each type.
* @param {Function} fn The event method we want to use.
* @param {Element|Object} elem Element or object to bind listeners to
* @param {String} type Type of event to bind to.
* @param {Function} callback Event listener.
* @private
*/
function _handleMultipleEvents(fn, elem, type, callback) {
vjs.arr.forEach(type, function(type) {
fn(elem, type, callback); //Call the event method for each one of the types
});
}

View File

@ -843,3 +843,28 @@ vjs.findPosition = function(el) {
top: vjs.round(top)
};
};
/**
* Array functions container
* @type {Object}
* @private
*/
vjs.arr = {};
/*
* Loops through an array and runs a function for each item inside it.
* @param {Array} array The array
* @param {Function} callback The function to be run for each item
* @param {*} thisArg The `this` binding of callback
* @returns {Array} The array
* @private
*/
vjs.arr.forEach = function(array, callback, thisArg) {
if (vjs.obj.isArray(array) && callback instanceof Function) {
for (var i = 0, len = array.length; i < len; ++i) {
callback.call(thisArg || vjs, array[i], i, array);
}
}
return array;
};

View File

@ -14,6 +14,32 @@ test('should add and remove an event listener to an element', function(){
vjs.trigger(el, 'click'); // No click should happen.
});
test('should add and remove multiple event listeners to an element with a single call', function(){
expect(6);
var el = document.createElement('div');
var listener = function(){
ok(true, 'Callback triggered');
};
vjs.on(el, ['click', 'event1', 'event2'], listener);
vjs.trigger(el, 'click');
vjs.trigger(el, 'click');
vjs.off(el, 'click', listener);
vjs.trigger(el, 'click'); // No click should happen.
vjs.trigger(el, 'event1');
vjs.trigger(el, 'event1');
vjs.off(el, 'event1', listener);
vjs.trigger(el, 'event1'); // No event1 should happen.
vjs.trigger(el, 'event2');
vjs.trigger(el, 'event2');
vjs.off(el, 'event2', listener);
vjs.trigger(el, 'event2'); // No event2 should happen.
});
test('should remove all listeners of a type', function(){
var el = document.createElement('div');
var clicks = 0;
@ -36,6 +62,30 @@ test('should remove all listeners of a type', function(){
ok(clicks === 2, 'no click listeners fired');
});
test('should remove all listeners of an array of types', function(){
var el = document.createElement('div');
var calls = 0;
var listener = function(){
calls++;
};
var listener2 = function(){
calls++;
};
vjs.on(el, ['click', 'event1'], listener);
vjs.on(el, ['click', 'event1'], listener2);
vjs.trigger(el, 'click'); // 2 calls
vjs.trigger(el, 'event1'); // 2 calls
ok(calls === 4, 'both click listeners fired');
vjs.off(el, ['click', 'event1']);
vjs.trigger(el, 'click'); // No click should happen.
vjs.trigger(el, 'event1'); // No event1 should happen.
ok(calls === 4, 'no event listeners fired');
});
test('should remove all listeners from an element', function(){
expect(2);
@ -73,6 +123,23 @@ test('should listen only once', function(){
vjs.trigger(el, 'click'); // No click should happen.
});
test( 'should listen only once in multiple events from a single call', function(){
expect(3);
var el = document.createElement('div');
var listener = function(){
ok(true, 'Callback Triggered');
};
vjs.one(el, ['click', 'event1', 'event2'], listener);
vjs.trigger(el, 'click'); // 1 click
vjs.trigger(el, 'click'); // No click should happen.
vjs.trigger(el, 'event1'); // event1 must be handled.
vjs.trigger(el, 'event1'); // No event1 should be handled.
vjs.trigger(el, 'event2'); // event2 must be handled.
vjs.trigger(el, 'event2'); // No event2 should be handled.
});
test('should stop immediate propagtion', function(){
expect(1);

View File

@ -332,3 +332,25 @@ test('should confirm logging functions work', function() {
console.error = origError;
}
});
test('should loop through each element of an array', function() {
expect(10);
var a = [1, 2, 3];
var sum = 0;
var i = 0;
var thisArg = {};
vjs.arr.forEach(a, function(item, iterator, array) {
sum += item;
deepEqual(array, a, 'The array arg should match the original array');
equal(i++, iterator, 'The indexes should match');
equal(this, thisArg, 'The context should equal the thisArg');
}, thisArg);
ok(sum, 6);
vjs.arr.forEach(a, function(){
if (this !== vjs) {
ok(false, 'default context should be vjs');
}
});
});