mirror of
https://github.com/videojs/video.js.git
synced 2025-07-05 00:58:52 +02:00
@heff enhanced the event listener API to allow for auto-cleanup of listeners on other componenets and elements. closes #1588
This commit is contained in:
@ -9,6 +9,7 @@ CHANGELOG
|
|||||||
* @thijstriemstra added a Dutch translation ([view](https://github.com/videojs/video.js/pull/1566))
|
* @thijstriemstra added a Dutch translation ([view](https://github.com/videojs/video.js/pull/1566))
|
||||||
* @heff updated the poster to use CSS styles to display; fixed the poster not showing if not originally set ([view](https://github.com/videojs/video.js/pull/1568))
|
* @heff updated the poster to use CSS styles to display; fixed the poster not showing if not originally set ([view](https://github.com/videojs/video.js/pull/1568))
|
||||||
* @mmcc fixed an issue where errors on source tags could get missed ([view](https://github.com/videojs/video.js/pull/1575))
|
* @mmcc fixed an issue where errors on source tags could get missed ([view](https://github.com/videojs/video.js/pull/1575))
|
||||||
|
* @heff enhanced the event listener API to allow for auto-cleanup of listeners on other componenets and elements ([view](https://github.com/videojs/video.js/pull/1588))
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -531,46 +531,169 @@ vjs.Component.prototype.buildCSSClass = function(){
|
|||||||
* Add an event listener to this component's element
|
* Add an event listener to this component's element
|
||||||
*
|
*
|
||||||
* var myFunc = function(){
|
* var myFunc = function(){
|
||||||
* var myPlayer = this;
|
* var myComponent = this;
|
||||||
* // Do something when the event is fired
|
* // Do something when the event is fired
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* myPlayer.on("eventName", myFunc);
|
* myComponent.on('eventType', myFunc);
|
||||||
*
|
*
|
||||||
* The context will be the component.
|
* The context of myFunc will be myComponent unless previously bound.
|
||||||
*
|
*
|
||||||
* @param {String} type The event type e.g. 'click'
|
* Alternatively, you can add a listener to another element or component.
|
||||||
* @param {Function} fn The event listener
|
*
|
||||||
* @return {vjs.Component} self
|
* myComponent.on(otherElement, 'eventName', myFunc);
|
||||||
|
* myComponent.on(otherComponent, 'eventName', myFunc);
|
||||||
|
*
|
||||||
|
* The benefit of using this over `vjs.on(otherElement, 'eventName', myFunc)`
|
||||||
|
* and `otherComponent.on('eventName', myFunc)` is that this way the listeners
|
||||||
|
* will be automatically cleaned up when either component is diposed.
|
||||||
|
* It will also bind myComponent as the context of myFunc.
|
||||||
|
*
|
||||||
|
* **NOTE**: When using this on elements in the page other than window
|
||||||
|
* and document (both permanent), if you remove the element from the DOM
|
||||||
|
* you need to call `vjs.trigger(el, 'dispose')` on it to clean up
|
||||||
|
* references to it and allow the browser to garbage collect it.
|
||||||
|
*
|
||||||
|
* @param {String|vjs.Component} first The event type or other component
|
||||||
|
* @param {Function|String} second The event handler or event type
|
||||||
|
* @param {Function} third The event handler
|
||||||
|
* @return {vjs.Component} self
|
||||||
*/
|
*/
|
||||||
vjs.Component.prototype.on = function(type, fn){
|
vjs.Component.prototype.on = function(first, second, third){
|
||||||
vjs.on(this.el_, type, vjs.bind(this, fn));
|
var target, type, fn, removeOnDispose, cleanRemover, thisComponent;
|
||||||
|
|
||||||
|
if (typeof first === 'string' || vjs.obj.isArray(first)) {
|
||||||
|
vjs.on(this.el_, first, vjs.bind(this, second));
|
||||||
|
|
||||||
|
// Targeting another component or element
|
||||||
|
} else {
|
||||||
|
target = first;
|
||||||
|
type = second;
|
||||||
|
fn = vjs.bind(this, third);
|
||||||
|
thisComponent = this;
|
||||||
|
|
||||||
|
// When this component is disposed, remove the listener from the other component
|
||||||
|
removeOnDispose = function(){
|
||||||
|
thisComponent.off(target, type, fn);
|
||||||
|
};
|
||||||
|
// Use the same function ID so we can remove it later it using the ID
|
||||||
|
// of the original listener
|
||||||
|
removeOnDispose.guid = fn.guid;
|
||||||
|
this.on('dispose', removeOnDispose);
|
||||||
|
|
||||||
|
// If the other component is disposed first we need to clean the reference
|
||||||
|
// to the other component in this component's removeOnDispose listener
|
||||||
|
// Otherwise we create a memory leak.
|
||||||
|
cleanRemover = function(){
|
||||||
|
thisComponent.off('dispose', removeOnDispose);
|
||||||
|
};
|
||||||
|
// Add the same function ID so we can easily remove it later
|
||||||
|
cleanRemover.guid = fn.guid;
|
||||||
|
|
||||||
|
// Check if this is a DOM node
|
||||||
|
if (first.nodeName) {
|
||||||
|
// Add the listener to the other element
|
||||||
|
vjs.on(target, type, fn);
|
||||||
|
vjs.on(target, 'dispose', cleanRemover);
|
||||||
|
|
||||||
|
// Should be a component
|
||||||
|
// Not using `instanceof vjs.Component` because it makes mock players difficult
|
||||||
|
} else if (typeof first.on === 'function') {
|
||||||
|
// Add the listener to the other component
|
||||||
|
target.on(type, fn);
|
||||||
|
target.on('dispose', cleanRemover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an event listener from the component's element
|
* Remove an event listener from this component's element
|
||||||
*
|
*
|
||||||
* myComponent.off("eventName", myFunc);
|
* myComponent.off('eventType', myFunc);
|
||||||
*
|
*
|
||||||
* @param {String=} type Event type. Without type it will remove all listeners.
|
* If myFunc is excluded, ALL listeners for the event type will be removed.
|
||||||
* @param {Function=} fn Event listener. Without fn it will remove all listeners for a type.
|
* If eventType is excluded, ALL listeners will be removed from the component.
|
||||||
|
*
|
||||||
|
* Alternatively you can use `off` to remove listeners that were added to other
|
||||||
|
* elements or components using `myComponent.on(otherComponent...`.
|
||||||
|
* In this case both the event type and listener function are REQUIRED.
|
||||||
|
*
|
||||||
|
* myComponent.off(otherElement, 'eventType', myFunc);
|
||||||
|
* myComponent.off(otherComponent, 'eventType', myFunc);
|
||||||
|
*
|
||||||
|
* @param {String=|vjs.Component} first The event type or other component
|
||||||
|
* @param {Function=|String} second The listener function or event type
|
||||||
|
* @param {Function=} third The listener for other component
|
||||||
* @return {vjs.Component}
|
* @return {vjs.Component}
|
||||||
*/
|
*/
|
||||||
vjs.Component.prototype.off = function(type, fn){
|
vjs.Component.prototype.off = function(first, second, third){
|
||||||
vjs.off(this.el_, type, fn);
|
var target, otherComponent, type, fn, otherEl;
|
||||||
|
|
||||||
|
if (!first || typeof first === 'string' || vjs.obj.isArray(first)) {
|
||||||
|
vjs.off(this.el_, first, second);
|
||||||
|
} else {
|
||||||
|
target = first;
|
||||||
|
type = second;
|
||||||
|
// Ensure there's at least a guid, even if the function hasn't been used
|
||||||
|
fn = vjs.bind(this, third);
|
||||||
|
|
||||||
|
// Remove the dispose listener on this component,
|
||||||
|
// which was given the same guid as the event listener
|
||||||
|
this.off('dispose', fn);
|
||||||
|
|
||||||
|
if (first.nodeName) {
|
||||||
|
// Remove the listener
|
||||||
|
vjs.off(target, type, fn);
|
||||||
|
// Remove the listener for cleaning the dispose listener
|
||||||
|
vjs.off(target, 'dispose', fn);
|
||||||
|
} else {
|
||||||
|
target.off(type, fn);
|
||||||
|
target.off('dispose', fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an event listener to be triggered only once and then removed
|
* Add an event listener to be triggered only once and then removed
|
||||||
*
|
*
|
||||||
* @param {String} type Event type
|
* myComponent.one('eventName', myFunc);
|
||||||
* @param {Function} fn Event listener
|
*
|
||||||
|
* Alternatively you can add a listener to another element or component
|
||||||
|
* that will be triggered only once.
|
||||||
|
*
|
||||||
|
* myComponent.one(otherElement, 'eventName', myFunc);
|
||||||
|
* myComponent.one(otherComponent, 'eventName', myFunc);
|
||||||
|
*
|
||||||
|
* @param {String|vjs.Component} first The event type or other component
|
||||||
|
* @param {Function|String} second The listener function or event type
|
||||||
|
* @param {Function=} third The listener function for other component
|
||||||
* @return {vjs.Component}
|
* @return {vjs.Component}
|
||||||
*/
|
*/
|
||||||
vjs.Component.prototype.one = function(type, fn) {
|
vjs.Component.prototype.one = function(first, second, third) {
|
||||||
vjs.one(this.el_, type, vjs.bind(this, fn));
|
var target, type, fn, thisComponent, newFunc;
|
||||||
|
|
||||||
|
if (typeof first === 'string' || vjs.obj.isArray(first)) {
|
||||||
|
vjs.one(this.el_, first, vjs.bind(this, second));
|
||||||
|
} else {
|
||||||
|
target = first;
|
||||||
|
type = second;
|
||||||
|
fn = vjs.bind(this, third);
|
||||||
|
thisComponent = this;
|
||||||
|
|
||||||
|
newFunc = function(){
|
||||||
|
thisComponent.off(target, type, newFunc);
|
||||||
|
fn.apply(this, arguments);
|
||||||
|
};
|
||||||
|
// Keep the same function ID so we can remove it later
|
||||||
|
newFunc.guid = fn.guid;
|
||||||
|
|
||||||
|
this.on(target, type, newFunc);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,19 +10,20 @@ vjs.MuteToggle = vjs.Button.extend({
|
|||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Button.call(this, player, options);
|
vjs.Button.call(this, player, options);
|
||||||
|
|
||||||
player.on('volumechange', vjs.bind(this, this.update));
|
this.on(player, 'volumechange', this.update);
|
||||||
|
|
||||||
// hide mute toggle if the current tech doesn't support volume control
|
// hide mute toggle if the current tech doesn't support volume control
|
||||||
if (player.tech && player.tech['featuresVolumeControl'] === false) {
|
if (player.tech && player.tech['featuresVolumeControl'] === false) {
|
||||||
this.addClass('vjs-hidden');
|
this.addClass('vjs-hidden');
|
||||||
}
|
}
|
||||||
player.on('loadstart', vjs.bind(this, function(){
|
|
||||||
|
this.on(player, 'loadstart', function(){
|
||||||
if (player.tech['featuresVolumeControl'] === false) {
|
if (player.tech['featuresVolumeControl'] === false) {
|
||||||
this.addClass('vjs-hidden');
|
this.addClass('vjs-hidden');
|
||||||
} else {
|
} else {
|
||||||
this.removeClass('vjs-hidden');
|
this.removeClass('vjs-hidden');
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ vjs.PlayToggle = vjs.Button.extend({
|
|||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Button.call(this, player, options);
|
vjs.Button.call(this, player, options);
|
||||||
|
|
||||||
player.on('play', vjs.bind(this, this.onPlay));
|
this.on(player, 'play', this.onPlay);
|
||||||
player.on('pause', vjs.bind(this, this.onPause));
|
this.on(player, 'pause', this.onPause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -32,14 +32,14 @@ vjs.PlayToggle.prototype.onClick = function(){
|
|||||||
|
|
||||||
// OnPlay - Add the vjs-playing class to the element so it can change appearance
|
// OnPlay - Add the vjs-playing class to the element so it can change appearance
|
||||||
vjs.PlayToggle.prototype.onPlay = function(){
|
vjs.PlayToggle.prototype.onPlay = function(){
|
||||||
vjs.removeClass(this.el_, 'vjs-paused');
|
this.removeClass('vjs-paused');
|
||||||
vjs.addClass(this.el_, 'vjs-playing');
|
this.addClass('vjs-playing');
|
||||||
this.el_.children[0].children[0].innerHTML = this.localize('Pause'); // change the button text to "Pause"
|
this.el_.children[0].children[0].innerHTML = this.localize('Pause'); // change the button text to "Pause"
|
||||||
};
|
};
|
||||||
|
|
||||||
// OnPause - Add the vjs-paused class to the element so it can change appearance
|
// OnPause - Add the vjs-paused class to the element so it can change appearance
|
||||||
vjs.PlayToggle.prototype.onPause = function(){
|
vjs.PlayToggle.prototype.onPause = function(){
|
||||||
vjs.removeClass(this.el_, 'vjs-playing');
|
this.removeClass('vjs-playing');
|
||||||
vjs.addClass(this.el_, 'vjs-paused');
|
this.addClass('vjs-paused');
|
||||||
this.el_.children[0].children[0].innerHTML = this.localize('Play'); // change the button text to "Play"
|
this.el_.children[0].children[0].innerHTML = this.localize('Play'); // change the button text to "Play"
|
||||||
};
|
};
|
||||||
|
@ -13,8 +13,8 @@ vjs.PlaybackRateMenuButton = vjs.MenuButton.extend({
|
|||||||
this.updateVisibility();
|
this.updateVisibility();
|
||||||
this.updateLabel();
|
this.updateLabel();
|
||||||
|
|
||||||
player.on('loadstart', vjs.bind(this, this.updateVisibility));
|
this.on(player, 'loadstart', this.updateVisibility);
|
||||||
player.on('ratechange', vjs.bind(this, this.updateLabel));
|
this.on(player, 'ratechange', this.updateLabel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ vjs.PlaybackRateMenuItem = vjs.MenuItem.extend({
|
|||||||
options['selected'] = rate === 1;
|
options['selected'] = rate === 1;
|
||||||
vjs.MenuItem.call(this, player, options);
|
vjs.MenuItem.call(this, player, options);
|
||||||
|
|
||||||
this.player().on('ratechange', vjs.bind(this, this.update));
|
this.on(player, 'ratechange', this.update);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ vjs.SeekBar = vjs.Slider.extend({
|
|||||||
/** @constructor */
|
/** @constructor */
|
||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Slider.call(this, player, options);
|
vjs.Slider.call(this, player, options);
|
||||||
player.on('timeupdate', vjs.bind(this, this.updateARIAAttributes));
|
this.on(player, 'timeupdate', this.updateARIAAttributes);
|
||||||
player.ready(vjs.bind(this, this.updateARIAAttributes));
|
player.ready(vjs.bind(this, this.updateARIAAttributes));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -118,7 +118,7 @@ vjs.LoadProgressBar = vjs.Component.extend({
|
|||||||
/** @constructor */
|
/** @constructor */
|
||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Component.call(this, player, options);
|
vjs.Component.call(this, player, options);
|
||||||
player.on('progress', vjs.bind(this, this.update));
|
this.on(player, 'progress', this.update);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ vjs.PlayProgressBar.prototype.createEl = function(){
|
|||||||
vjs.SeekHandle = vjs.SliderHandle.extend({
|
vjs.SeekHandle = vjs.SliderHandle.extend({
|
||||||
init: function(player, options) {
|
init: function(player, options) {
|
||||||
vjs.SliderHandle.call(this, player, options);
|
vjs.SliderHandle.call(this, player, options);
|
||||||
player.on('timeupdate', vjs.bind(this, this.updateContent));
|
this.on(player, 'timeupdate', this.updateContent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ vjs.CurrentTimeDisplay = vjs.Component.extend({
|
|||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Component.call(this, player, options);
|
vjs.Component.call(this, player, options);
|
||||||
|
|
||||||
player.on('timeupdate', vjs.bind(this, this.updateContent));
|
this.on(player, 'timeupdate', this.updateContent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ vjs.DurationDisplay = vjs.Component.extend({
|
|||||||
// so the value cannot be written out using this method.
|
// so the value cannot be written out using this method.
|
||||||
// Once the order of durationchange and this.player_.duration() being set is figured out,
|
// Once the order of durationchange and this.player_.duration() being set is figured out,
|
||||||
// this can be updated.
|
// this can be updated.
|
||||||
player.on('timeupdate', vjs.bind(this, this.updateContent));
|
this.on(player, 'timeupdate', this.updateContent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ vjs.RemainingTimeDisplay = vjs.Component.extend({
|
|||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Component.call(this, player, options);
|
vjs.Component.call(this, player, options);
|
||||||
|
|
||||||
player.on('timeupdate', vjs.bind(this, this.updateContent));
|
this.on(player, 'timeupdate', this.updateContent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,13 +14,13 @@ vjs.VolumeControl = vjs.Component.extend({
|
|||||||
if (player.tech && player.tech['featuresVolumeControl'] === false) {
|
if (player.tech && player.tech['featuresVolumeControl'] === false) {
|
||||||
this.addClass('vjs-hidden');
|
this.addClass('vjs-hidden');
|
||||||
}
|
}
|
||||||
player.on('loadstart', vjs.bind(this, function(){
|
this.on(player, 'loadstart', function(){
|
||||||
if (player.tech['featuresVolumeControl'] === false) {
|
if (player.tech['featuresVolumeControl'] === false) {
|
||||||
this.addClass('vjs-hidden');
|
this.addClass('vjs-hidden');
|
||||||
} else {
|
} else {
|
||||||
this.removeClass('vjs-hidden');
|
this.removeClass('vjs-hidden');
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ vjs.VolumeBar = vjs.Slider.extend({
|
|||||||
/** @constructor */
|
/** @constructor */
|
||||||
init: function(player, options){
|
init: function(player, options){
|
||||||
vjs.Slider.call(this, player, options);
|
vjs.Slider.call(this, player, options);
|
||||||
player.on('volumechange', vjs.bind(this, this.updateARIAAttributes));
|
this.on(player, 'volumechange', this.updateARIAAttributes);
|
||||||
player.ready(vjs.bind(this, this.updateARIAAttributes));
|
player.ready(vjs.bind(this, this.updateARIAAttributes));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,19 +8,19 @@ vjs.VolumeMenuButton = vjs.MenuButton.extend({
|
|||||||
vjs.MenuButton.call(this, player, options);
|
vjs.MenuButton.call(this, player, options);
|
||||||
|
|
||||||
// Same listeners as MuteToggle
|
// Same listeners as MuteToggle
|
||||||
player.on('volumechange', vjs.bind(this, this.update));
|
this.on(player, 'volumechange', this.update);
|
||||||
|
|
||||||
// hide mute toggle if the current tech doesn't support volume control
|
// hide mute toggle if the current tech doesn't support volume control
|
||||||
if (player.tech && player.tech['featuresVolumeControl'] === false) {
|
if (player.tech && player.tech['featuresVolumeControl'] === false) {
|
||||||
this.addClass('vjs-hidden');
|
this.addClass('vjs-hidden');
|
||||||
}
|
}
|
||||||
player.on('loadstart', vjs.bind(this, function(){
|
this.on(player, 'loadstart', function(){
|
||||||
if (player.tech['featuresVolumeControl'] === false) {
|
if (player.tech['featuresVolumeControl'] === false) {
|
||||||
this.addClass('vjs-hidden');
|
this.addClass('vjs-hidden');
|
||||||
} else {
|
} else {
|
||||||
this.removeClass('vjs-hidden');
|
this.removeClass('vjs-hidden');
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
this.addClass('vjs-menu-button');
|
this.addClass('vjs-menu-button');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ vjs.ErrorDisplay = vjs.Component.extend({
|
|||||||
vjs.Component.call(this, player, options);
|
vjs.Component.call(this, player, options);
|
||||||
|
|
||||||
this.update();
|
this.update();
|
||||||
player.on('error', vjs.bind(this, this.update));
|
this.on(player, 'error', this.update);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -92,10 +92,10 @@ vjs.Flash = vjs.MediaTechController.extend({
|
|||||||
// bugzilla bug: https://bugzilla.mozilla.org/show_bug.cgi?id=836786
|
// bugzilla bug: https://bugzilla.mozilla.org/show_bug.cgi?id=836786
|
||||||
if (vjs.IS_FIREFOX) {
|
if (vjs.IS_FIREFOX) {
|
||||||
this.ready(function(){
|
this.ready(function(){
|
||||||
vjs.on(this.el(), 'mousemove', vjs.bind(this, function(){
|
this.on('mousemove', function(){
|
||||||
// since it's a custom event, don't bubble higher than the player
|
// since it's a custom event, don't bubble higher than the player
|
||||||
this.player().trigger({ 'type':'mousemove', 'bubbles': false });
|
this.player().trigger({ 'type':'mousemove', 'bubbles': false });
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ vjs.Html5.prototype.createEl = function(){
|
|||||||
// Triggers removed using this.off when disposed
|
// Triggers removed using this.off when disposed
|
||||||
vjs.Html5.prototype.setupTriggers = function(){
|
vjs.Html5.prototype.setupTriggers = function(){
|
||||||
for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
|
for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
|
||||||
vjs.on(this.el_, vjs.Html5.Events[i], vjs.bind(this, this.eventHandler));
|
this.on(vjs.Html5.Events[i], this.eventHandler);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -214,16 +214,16 @@ vjs.Html5.prototype.enterFullScreen = function(){
|
|||||||
var video = this.el_;
|
var video = this.el_;
|
||||||
|
|
||||||
if ('webkitDisplayingFullscreen' in video) {
|
if ('webkitDisplayingFullscreen' in video) {
|
||||||
this.one('webkitbeginfullscreen', vjs.bind(this, function(e) {
|
this.one('webkitbeginfullscreen', function() {
|
||||||
this.player_.isFullscreen(true);
|
this.player_.isFullscreen(true);
|
||||||
|
|
||||||
this.one('webkitendfullscreen', vjs.bind(this, function(e) {
|
this.one('webkitendfullscreen', function() {
|
||||||
this.player_.isFullscreen(false);
|
this.player_.isFullscreen(false);
|
||||||
this.player_.trigger('fullscreenchange');
|
this.player_.trigger('fullscreenchange');
|
||||||
}));
|
});
|
||||||
|
|
||||||
this.player_.trigger('fullscreenchange');
|
this.player_.trigger('fullscreenchange');
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.paused && video.networkState <= video.HAVE_METADATA) {
|
if (video.paused && video.networkState <= video.HAVE_METADATA) {
|
||||||
|
@ -53,24 +53,21 @@ vjs.MediaTechController = vjs.Component.extend({
|
|||||||
* any controls will still keep the user active
|
* any controls will still keep the user active
|
||||||
*/
|
*/
|
||||||
vjs.MediaTechController.prototype.initControlsListeners = function(){
|
vjs.MediaTechController.prototype.initControlsListeners = function(){
|
||||||
var player, tech, activateControls, deactivateControls;
|
var player, activateControls;
|
||||||
|
|
||||||
tech = this;
|
|
||||||
player = this.player();
|
player = this.player();
|
||||||
|
|
||||||
var activateControls = function(){
|
activateControls = function(){
|
||||||
if (player.controls() && !player.usingNativeControls()) {
|
if (player.controls() && !player.usingNativeControls()) {
|
||||||
tech.addControlsListeners();
|
this.addControlsListeners();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
deactivateControls = vjs.bind(tech, tech.removeControlsListeners);
|
|
||||||
|
|
||||||
// Set up event listeners once the tech is ready and has an element to apply
|
// Set up event listeners once the tech is ready and has an element to apply
|
||||||
// listeners to
|
// listeners to
|
||||||
this.ready(activateControls);
|
this.ready(activateControls);
|
||||||
player.on('controlsenabled', activateControls);
|
this.on(player, 'controlsenabled', activateControls);
|
||||||
player.on('controlsdisabled', deactivateControls);
|
this.on(player, 'controlsdisabled', this.removeControlsListeners);
|
||||||
|
|
||||||
// if we're loading the playback object after it has started loading or playing the
|
// if we're loading the playback object after it has started loading or playing the
|
||||||
// video (often with autoplay on) then the loadstart event has already fired and we
|
// video (often with autoplay on) then the loadstart event has already fired and we
|
||||||
@ -201,10 +198,12 @@ vjs.MediaTechController.prototype.stopTrackingProgress = function(){ clearInterv
|
|||||||
|
|
||||||
/*! Time Tracking -------------------------------------------------------------- */
|
/*! Time Tracking -------------------------------------------------------------- */
|
||||||
vjs.MediaTechController.prototype.manualTimeUpdatesOn = function(){
|
vjs.MediaTechController.prototype.manualTimeUpdatesOn = function(){
|
||||||
|
var player = this.player_;
|
||||||
|
|
||||||
this.manualTimeUpdates = true;
|
this.manualTimeUpdates = true;
|
||||||
|
|
||||||
this.player().on('play', vjs.bind(this, this.trackCurrentTime));
|
this.on(player, 'play', this.trackCurrentTime);
|
||||||
this.player().on('pause', vjs.bind(this, this.stopTrackingCurrentTime));
|
this.on(player, 'pause', this.stopTrackingCurrentTime);
|
||||||
// timeupdate is also called by .currentTime whenever current time is set
|
// timeupdate is also called by .currentTime whenever current time is set
|
||||||
|
|
||||||
// Watch for native timeupdate event
|
// Watch for native timeupdate event
|
||||||
|
@ -22,13 +22,10 @@ vjs.Slider = vjs.Component.extend({
|
|||||||
this.on('blur', this.onBlur);
|
this.on('blur', this.onBlur);
|
||||||
this.on('click', this.onClick);
|
this.on('click', this.onClick);
|
||||||
|
|
||||||
this.player_.on('controlsvisible', vjs.bind(this, this.update));
|
this.on(player, 'controlsvisible', this.update);
|
||||||
|
this.on(player, this.playerEvent, this.update);
|
||||||
player.on(this.playerEvent, vjs.bind(this, this.update));
|
|
||||||
|
|
||||||
this.boundEvents = {};
|
this.boundEvents = {};
|
||||||
|
|
||||||
|
|
||||||
this.boundEvents.move = vjs.bind(this, this.onMouseMove);
|
this.boundEvents.move = vjs.bind(this, this.onMouseMove);
|
||||||
this.boundEvents.end = vjs.bind(this, this.onMouseUp);
|
this.boundEvents.end = vjs.bind(this, this.onMouseUp);
|
||||||
}
|
}
|
||||||
|
@ -733,7 +733,7 @@ vjs.TextTrackMenuItem = vjs.MenuItem.extend({
|
|||||||
options['selected'] = track.dflt();
|
options['selected'] = track.dflt();
|
||||||
vjs.MenuItem.call(this, player, options);
|
vjs.MenuItem.call(this, player, options);
|
||||||
|
|
||||||
this.player_.on(track.kind() + 'trackchange', vjs.bind(this, this.update));
|
this.on(player, track.kind() + 'trackchange', this.update);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -161,6 +161,132 @@ test('should trigger a listener once using one()', function(){
|
|||||||
comp.trigger('test-event');
|
comp.trigger('test-event');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should add listeners to other components and remove them', function(){
|
||||||
|
var player = getFakePlayer(),
|
||||||
|
comp1 = new vjs.Component(player),
|
||||||
|
comp2 = new vjs.Component(player),
|
||||||
|
listenerFired = 0,
|
||||||
|
testListener;
|
||||||
|
|
||||||
|
testListener = function(){
|
||||||
|
equal(this, comp1, 'listener has the first component as context');
|
||||||
|
listenerFired++;
|
||||||
|
};
|
||||||
|
|
||||||
|
comp1.on(comp2, 'test-event', testListener);
|
||||||
|
comp2.trigger('test-event');
|
||||||
|
equal(listenerFired, 1, 'listener was fired once');
|
||||||
|
|
||||||
|
listenerFired = 0;
|
||||||
|
comp1.off(comp2, 'test-event', testListener);
|
||||||
|
comp2.trigger('test-event');
|
||||||
|
equal(listenerFired, 0, 'listener was not fired after being removed');
|
||||||
|
|
||||||
|
// this component is disposed first
|
||||||
|
listenerFired = 0;
|
||||||
|
comp1.on(comp2, 'test-event', testListener);
|
||||||
|
comp1.dispose();
|
||||||
|
comp2.trigger('test-event');
|
||||||
|
equal(listenerFired, 0, 'listener was removed when this component was disposed first');
|
||||||
|
comp1.off = function(){ throw 'Comp1 off called'; };
|
||||||
|
comp2.dispose();
|
||||||
|
ok(true, 'this component removed dispose listeners from other component');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add listeners to other components and remove when them other component is disposed', function(){
|
||||||
|
var player = getFakePlayer(),
|
||||||
|
comp1 = new vjs.Component(player),
|
||||||
|
comp2 = new vjs.Component(player),
|
||||||
|
listenerFired = 0,
|
||||||
|
testListener;
|
||||||
|
|
||||||
|
testListener = function(){
|
||||||
|
equal(this, comp1, 'listener has the first component as context');
|
||||||
|
listenerFired++;
|
||||||
|
};
|
||||||
|
|
||||||
|
comp1.on(comp2, 'test-event', testListener);
|
||||||
|
comp2.dispose();
|
||||||
|
comp2.off = function(){ throw 'Comp2 off called'; };
|
||||||
|
comp1.dispose();
|
||||||
|
ok(true, 'this component removed dispose listener from this component that referenced other component');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add listeners to other components that are fired once', function(){
|
||||||
|
var player = getFakePlayer(),
|
||||||
|
comp1 = new vjs.Component(player),
|
||||||
|
comp2 = new vjs.Component(player),
|
||||||
|
listenerFired = 0,
|
||||||
|
testListener;
|
||||||
|
|
||||||
|
testListener = function(){
|
||||||
|
equal(this, comp1, 'listener has the first component as context');
|
||||||
|
listenerFired++;
|
||||||
|
};
|
||||||
|
|
||||||
|
comp1.one(comp2, 'test-event', testListener);
|
||||||
|
comp2.trigger('test-event');
|
||||||
|
equal(listenerFired, 1, 'listener was executed once');
|
||||||
|
comp2.trigger('test-event');
|
||||||
|
equal(listenerFired, 1, 'listener was executed only once');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add listeners to other element and remove them', function(){
|
||||||
|
var player = getFakePlayer(),
|
||||||
|
comp1 = new vjs.Component(player),
|
||||||
|
el = document.createElement('div'),
|
||||||
|
listenerFired = 0,
|
||||||
|
testListener;
|
||||||
|
|
||||||
|
testListener = function(){
|
||||||
|
equal(this, comp1, 'listener has the first component as context');
|
||||||
|
listenerFired++;
|
||||||
|
};
|
||||||
|
|
||||||
|
comp1.on(el, 'test-event', testListener);
|
||||||
|
vjs.trigger(el, 'test-event');
|
||||||
|
equal(listenerFired, 1, 'listener was fired once');
|
||||||
|
|
||||||
|
listenerFired = 0;
|
||||||
|
comp1.off(el, 'test-event', testListener);
|
||||||
|
vjs.trigger(el, 'test-event');
|
||||||
|
equal(listenerFired, 0, 'listener was not fired after being removed from other element');
|
||||||
|
|
||||||
|
// this component is disposed first
|
||||||
|
listenerFired = 0;
|
||||||
|
comp1.on(el, 'test-event', testListener);
|
||||||
|
comp1.dispose();
|
||||||
|
vjs.trigger(el, 'test-event');
|
||||||
|
equal(listenerFired, 0, 'listener was removed when this component was disposed first');
|
||||||
|
comp1.off = function(){ throw 'Comp1 off called'; };
|
||||||
|
try {
|
||||||
|
vjs.trigger(el, 'dispose');
|
||||||
|
} catch(e) {
|
||||||
|
ok(false, 'listener was not removed from other element');
|
||||||
|
}
|
||||||
|
vjs.trigger(el, 'dispose');
|
||||||
|
ok(true, 'this component removed dispose listeners from other element');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add listeners to other components that are fired once', function(){
|
||||||
|
var player = getFakePlayer(),
|
||||||
|
comp1 = new vjs.Component(player),
|
||||||
|
el = document.createElement('div'),
|
||||||
|
listenerFired = 0,
|
||||||
|
testListener;
|
||||||
|
|
||||||
|
testListener = function(){
|
||||||
|
equal(this, comp1, 'listener has the first component as context');
|
||||||
|
listenerFired++;
|
||||||
|
};
|
||||||
|
|
||||||
|
comp1.one(el, 'test-event', testListener);
|
||||||
|
vjs.trigger(el, 'test-event');
|
||||||
|
equal(listenerFired, 1, 'listener was executed once');
|
||||||
|
vjs.trigger(el, 'test-event');
|
||||||
|
equal(listenerFired, 1, 'listener was executed only once');
|
||||||
|
});
|
||||||
|
|
||||||
test('should trigger a listener when ready', function(){
|
test('should trigger a listener when ready', function(){
|
||||||
expect(2);
|
expect(2);
|
||||||
|
|
||||||
|
23
test/unit/controls.js
vendored
23
test/unit/controls.js
vendored
@ -35,7 +35,10 @@ test('should test and toggle volume control on `loadstart`', function(){
|
|||||||
language: noop,
|
language: noop,
|
||||||
languages: noop,
|
languages: noop,
|
||||||
on: function(event, callback){
|
on: function(event, callback){
|
||||||
listeners.push(callback);
|
// don't fire dispose listeners
|
||||||
|
if (event !== 'dispose') {
|
||||||
|
listeners.push(callback);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ready: noop,
|
ready: noop,
|
||||||
volume: function(){
|
volume: function(){
|
||||||
@ -53,30 +56,24 @@ test('should test and toggle volume control on `loadstart`', function(){
|
|||||||
volumeControl = new vjs.VolumeControl(player);
|
volumeControl = new vjs.VolumeControl(player);
|
||||||
muteToggle = new vjs.MuteToggle(player);
|
muteToggle = new vjs.MuteToggle(player);
|
||||||
|
|
||||||
ok(volumeControl.el().className.indexOf('vjs-hidden') < 0,
|
equal(volumeControl.hasClass('vjs-hidden'), false, 'volumeControl is hidden initially');
|
||||||
'volumeControl is hidden initially');
|
equal(muteToggle.hasClass('vjs-hidden'), false, 'muteToggle is hidden initially');
|
||||||
ok(muteToggle.el().className.indexOf('vjs-hidden') < 0,
|
|
||||||
'muteToggle is hidden initially');
|
|
||||||
|
|
||||||
player.tech['featuresVolumeControl'] = false;
|
player.tech['featuresVolumeControl'] = false;
|
||||||
for (i = 0; i < listeners.length; i++) {
|
for (i = 0; i < listeners.length; i++) {
|
||||||
listeners[i]();
|
listeners[i]();
|
||||||
}
|
}
|
||||||
|
|
||||||
ok(volumeControl.el().className.indexOf('vjs-hidden') >= 0,
|
equal(volumeControl.hasClass('vjs-hidden'), true, 'volumeControl does not hide itself');
|
||||||
'volumeControl does not hide itself');
|
equal(muteToggle.hasClass('vjs-hidden'), true, 'muteToggle does not hide itself');
|
||||||
ok(muteToggle.el().className.indexOf('vjs-hidden') >= 0,
|
|
||||||
'muteToggle does not hide itself');
|
|
||||||
|
|
||||||
player.tech['featuresVolumeControl'] = true;
|
player.tech['featuresVolumeControl'] = true;
|
||||||
for (i = 0; i < listeners.length; i++) {
|
for (i = 0; i < listeners.length; i++) {
|
||||||
listeners[i]();
|
listeners[i]();
|
||||||
}
|
}
|
||||||
|
|
||||||
ok(volumeControl.el().className.indexOf('vjs-hidden') < 0,
|
equal(volumeControl.hasClass('vjs-hidden'), false, 'volumeControl does not show itself');
|
||||||
'volumeControl does not show itself');
|
equal(muteToggle.hasClass('vjs-hidden'), false, 'muteToggle does not show itself');
|
||||||
ok(muteToggle.el().className.indexOf('vjs-hidden') < 0,
|
|
||||||
'muteToggle does not show itself');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('calculateDistance should use changedTouches, if available', function() {
|
test('calculateDistance should use changedTouches, if available', function() {
|
||||||
|
@ -120,6 +120,7 @@ test('dispose() should stop time tracking', function() {
|
|||||||
var tech = new videojs.MediaTechController({
|
var tech = new videojs.MediaTechController({
|
||||||
id: noop,
|
id: noop,
|
||||||
on: noop,
|
on: noop,
|
||||||
|
off: noop,
|
||||||
trigger: noop
|
trigger: noop
|
||||||
});
|
});
|
||||||
tech.dispose();
|
tech.dispose();
|
||||||
|
Reference in New Issue
Block a user