diff --git a/CHANGELOG.md b/CHANGELOG.md index 351cdb573..3b1339da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ _(none)_ -------------------- +## 4.6.2 (2014-06-10) +* Fixed an issue with the firstplay event not firing when autoplaying ([view](https://github.com/videojs/video.js/pull/1271)) + ## 4.6.1 (2014-05-20) * Udpated playbackRate menu to work in minified version ([view](https://github.com/videojs/video.js/pull/1223)) diff --git a/bower.json b/bower.json index d0a92c9f0..9a691dcef 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "video.js", "description": "An HTML5 and Flash video player with a common API and skin for both.", - "version": "4.6.1", + "version": "4.6.2", "main": [ "dist/video-js/video.js", "dist/video-js/video-js.css" diff --git a/component.json b/component.json index 5f0098146..128dadddc 100644 --- a/component.json +++ b/component.json @@ -1,7 +1,7 @@ { "name": "video.js", "description": "An HTML5 and Flash video player with a common API and skin for both.", - "version": "4.6.1", + "version": "4.6.2", "keywords": [ "videojs", "html5", diff --git a/docs/api/vjs.Player.md b/docs/api/vjs.Player.md index 6c8acb735..24988e298 100644 --- a/docs/api/vjs.Player.md +++ b/docs/api/vjs.Player.md @@ -164,7 +164,7 @@ _inherited from_: [src/js/component.js#L663](https://github.com/videojs/video.js ##### RETURNS: * `Object` A mock TimeRange object (following HTML spec) -_defined in_: [src/js/player.js#L751](https://github.com/videojs/video.js/blob/master/src/js/player.js#L751) +_defined in_: [src/js/player.js#L767](https://github.com/videojs/video.js/blob/master/src/js/player.js#L767) --- @@ -179,7 +179,7 @@ _defined in_: [src/js/player.js#L751](https://github.com/videojs/video.js/blob/m ##### RETURNS: * `Number` A decimal between 0 and 1 representing the percent -_defined in_: [src/js/player.js#L777](https://github.com/videojs/video.js/blob/master/src/js/player.js#L777) +_defined in_: [src/js/player.js#L793](https://github.com/videojs/video.js/blob/master/src/js/player.js#L793) --- @@ -197,7 +197,7 @@ _inherited from_: [src/js/component.js#L506](https://github.com/videojs/video.js > Old naming for exitFullscreen **Deprecated** true -_defined in_: [src/js/player.js#L974](https://github.com/videojs/video.js/blob/master/src/js/player.js#L974) +_defined in_: [src/js/player.js#L990](https://github.com/videojs/video.js/blob/master/src/js/player.js#L990) --- @@ -233,7 +233,7 @@ _inherited from_: [src/js/component.js#L224](https://github.com/videojs/video.js ##### RETURNS: * `Boolean` Controls are showing -_defined in_: [src/js/player.js#L1234](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1234) +_defined in_: [src/js/player.js#L1250](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1250) --- @@ -267,7 +267,7 @@ _inherited from_: [src/js/component.js#L194](https://github.com/videojs/video.js * `Number` The time in seconds, when not setting * `vjs.Player` self, when the current time is set -_defined in_: [src/js/player.js#L674](https://github.com/videojs/video.js/blob/master/src/js/player.js#L674) +_defined in_: [src/js/player.js#L690](https://github.com/videojs/video.js/blob/master/src/js/player.js#L690) --- @@ -293,7 +293,7 @@ _inherited from_: [src/js/component.js#L775](https://github.com/videojs/video.js > This is especially helpful if you are dynamically adding and removing videos > to/from the DOM. -_defined in_: [src/js/player.js#L126](https://github.com/videojs/video.js/blob/master/src/js/player.js#L126) +_defined in_: [src/js/player.js#L112](https://github.com/videojs/video.js/blob/master/src/js/player.js#L112) --- @@ -312,7 +312,7 @@ _defined in_: [src/js/player.js#L126](https://github.com/videojs/video.js/blob/m ##### RETURNS: * `Number` The duration of the video in seconds -_defined in_: [src/js/player.js#L705](https://github.com/videojs/video.js/blob/master/src/js/player.js#L705) +_defined in_: [src/js/player.js#L721](https://github.com/videojs/video.js/blob/master/src/js/player.js#L721) --- @@ -365,7 +365,7 @@ _inherited from_: [src/js/component.js#L954](https://github.com/videojs/video.js * `vjs.MediaError|null` when getting * `vjs.Player` when setting -_defined in_: [src/js/player.js#L1319](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1319) +_defined in_: [src/js/player.js#L1335](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1335) --- @@ -377,7 +377,7 @@ _defined in_: [src/js/player.js#L1319](https://github.com/videojs/video.js/blob/ ##### RETURNS: * `vjs.Player` self -_defined in_: [src/js/player.js#L953](https://github.com/videojs/video.js/blob/master/src/js/player.js#L953) +_defined in_: [src/js/player.js#L969](https://github.com/videojs/video.js/blob/master/src/js/player.js#L969) --- @@ -505,7 +505,7 @@ _inherited from_: [src/js/component.js#L466](https://github.com/videojs/video.js ##### PARAMETERS: * __isFS__ -_defined in_: [src/js/player.js#L876](https://github.com/videojs/video.js/blob/master/src/js/player.js#L876) +_defined in_: [src/js/player.js#L892](https://github.com/videojs/video.js/blob/master/src/js/player.js#L892) --- @@ -529,7 +529,7 @@ _defined in_: [src/js/player.js#L876](https://github.com/videojs/video.js/blob/m * `Boolean` true if fullscreen, false if not * `vjs.Player` self, when setting -_defined in_: [src/js/player.js#L864](https://github.com/videojs/video.js/blob/master/src/js/player.js#L864) +_defined in_: [src/js/player.js#L880](https://github.com/videojs/video.js/blob/master/src/js/player.js#L880) --- @@ -549,7 +549,7 @@ _defined in_: [src/js/player.js#L864](https://github.com/videojs/video.js/blob/m * `Boolean` True if mute is on, false if not, when getting * `vjs.Player` self, when setting mute -_defined in_: [src/js/player.js#L826](https://github.com/videojs/video.js/blob/master/src/js/player.js#L826) +_defined in_: [src/js/player.js#L842](https://github.com/videojs/video.js/blob/master/src/js/player.js#L842) --- @@ -674,7 +674,7 @@ _inherited from_: [src/js/component.js#L173](https://github.com/videojs/video.js ##### RETURNS: * `vjs.Player` self -_defined in_: [src/js/player.js#L643](https://github.com/videojs/video.js/blob/master/src/js/player.js#L643) +_defined in_: [src/js/player.js#L659](https://github.com/videojs/video.js/blob/master/src/js/player.js#L659) --- @@ -687,7 +687,7 @@ _defined in_: [src/js/player.js#L643](https://github.com/videojs/video.js/blob/m ##### RETURNS: * `Boolean` false if the media is currently playing, or true otherwise -_defined in_: [src/js/player.js#L656](https://github.com/videojs/video.js/blob/master/src/js/player.js#L656) +_defined in_: [src/js/player.js#L672](https://github.com/videojs/video.js/blob/master/src/js/player.js#L672) --- @@ -699,7 +699,7 @@ _defined in_: [src/js/player.js#L656](https://github.com/videojs/video.js/blob/m ##### RETURNS: * `vjs.Player` self -_defined in_: [src/js/player.js#L631](https://github.com/videojs/video.js/blob/master/src/js/player.js#L631) +_defined in_: [src/js/player.js#L647](https://github.com/videojs/video.js/blob/master/src/js/player.js#L647) --- @@ -731,7 +731,7 @@ _inherited from_: [src/js/component.js#L120](https://github.com/videojs/video.js * `String` poster URL when getting * `vjs.Player` self when setting -_defined in_: [src/js/player.js#L1207](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1207) +_defined in_: [src/js/player.js#L1223](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1223) --- @@ -779,7 +779,7 @@ _inherited from_: [src/js/component.js#L674](https://github.com/videojs/video.js > Old naming for requestFullscreen **Deprecated** true -_defined in_: [src/js/player.js#L940](https://github.com/videojs/video.js/blob/master/src/js/player.js#L940) +_defined in_: [src/js/player.js#L956](https://github.com/videojs/video.js/blob/master/src/js/player.js#L956) --- @@ -798,7 +798,7 @@ _defined in_: [src/js/player.js#L940](https://github.com/videojs/video.js/blob/m ##### RETURNS: * `vjs.Player` self -_defined in_: [src/js/player.js#L895](https://github.com/videojs/video.js/blob/master/src/js/player.js#L895) +_defined in_: [src/js/player.js#L911](https://github.com/videojs/video.js/blob/master/src/js/player.js#L911) --- @@ -847,7 +847,7 @@ _inherited from_: [src/js/component.js#L684](https://github.com/videojs/video.js * `String` The current video source when getting * `String` The player when setting -_defined in_: [src/js/player.js#L1084](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1084) +_defined in_: [src/js/player.js#L1100](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1100) --- @@ -895,7 +895,7 @@ _inherited from_: [src/js/component.js#L635](https://github.com/videojs/video.js * `Number` The current volume, when getting * `vjs.Player` self, when setting -_defined in_: [src/js/player.js#L796](https://github.com/videojs/video.js/blob/master/src/js/player.js#L796) +_defined in_: [src/js/player.js#L812](https://github.com/videojs/video.js/blob/master/src/js/player.js#L812) --- @@ -924,14 +924,14 @@ _inherited from_: [src/js/component.js#L747](https://github.com/videojs/video.js ### durationchange `EVENT` > Fired when the duration of the media resource is first known or changed -_defined in_: [src/js/player.js#L526](https://github.com/videojs/video.js/blob/master/src/js/player.js#L526) +_defined in_: [src/js/player.js#L542](https://github.com/videojs/video.js/blob/master/src/js/player.js#L542) --- ### ended `EVENT` > Fired when the end of the media resource is reached (currentTime == duration) -_defined in_: [src/js/player.js#L515](https://github.com/videojs/video.js/blob/master/src/js/player.js#L515) +_defined in_: [src/js/player.js#L531](https://github.com/videojs/video.js/blob/master/src/js/player.js#L531) --- @@ -942,63 +942,63 @@ _defined in_: [src/js/player.js#L515](https://github.com/videojs/video.js/blob/m > implementation yet, so use sparingly. If you don't have a reason to > prevent playback, use `myPlayer.one('play');` instead. -_defined in_: [src/js/player.js#L472](https://github.com/videojs/video.js/blob/master/src/js/player.js#L472) +_defined in_: [src/js/player.js#L488](https://github.com/videojs/video.js/blob/master/src/js/player.js#L488) --- ### fullscreenchange `EVENT` > Fired when the player switches in or out of fullscreen mode -_defined in_: [src/js/player.js#L555](https://github.com/videojs/video.js/blob/master/src/js/player.js#L555) +_defined in_: [src/js/player.js#L571](https://github.com/videojs/video.js/blob/master/src/js/player.js#L571) --- ### loadedalldata `EVENT` > Fired when the player has finished downloading the source data -_defined in_: [src/js/player.js#L452](https://github.com/videojs/video.js/blob/master/src/js/player.js#L452) +_defined in_: [src/js/player.js#L468](https://github.com/videojs/video.js/blob/master/src/js/player.js#L468) --- ### loadeddata `EVENT` > Fired when the player has downloaded data at the current playback position -_defined in_: [src/js/player.js#L446](https://github.com/videojs/video.js/blob/master/src/js/player.js#L446) +_defined in_: [src/js/player.js#L462](https://github.com/videojs/video.js/blob/master/src/js/player.js#L462) --- ### loadedmetadata `EVENT` > Fired when the player has initial duration and dimension information -_defined in_: [src/js/player.js#L440](https://github.com/videojs/video.js/blob/master/src/js/player.js#L440) +_defined in_: [src/js/player.js#L456](https://github.com/videojs/video.js/blob/master/src/js/player.js#L456) --- ### loadstart `EVENT` > Fired when the user agent begins looking for media data -_defined in_: [src/js/player.js#L410](https://github.com/videojs/video.js/blob/master/src/js/player.js#L410) +_defined in_: [src/js/player.js#L412](https://github.com/videojs/video.js/blob/master/src/js/player.js#L412) --- ### pause `EVENT` > Fired whenever the media has been paused -_defined in_: [src/js/player.js#L486](https://github.com/videojs/video.js/blob/master/src/js/player.js#L486) +_defined in_: [src/js/player.js#L502](https://github.com/videojs/video.js/blob/master/src/js/player.js#L502) --- ### play `EVENT` > Fired whenever the media begins or resumes playback -_defined in_: [src/js/player.js#L458](https://github.com/videojs/video.js/blob/master/src/js/player.js#L458) +_defined in_: [src/js/player.js#L474](https://github.com/videojs/video.js/blob/master/src/js/player.js#L474) --- ### progress `EVENT` > Fired while the user agent is downloading media data -_defined in_: [src/js/player.js#L504](https://github.com/videojs/video.js/blob/master/src/js/player.js#L504) +_defined in_: [src/js/player.js#L520](https://github.com/videojs/video.js/blob/master/src/js/player.js#L520) --- @@ -1015,14 +1015,14 @@ _inherited from_: [src/js/component.js#L854](https://github.com/videojs/video.js > During playback this is fired every 15-250 milliseconds, depnding on the > playback technology in use. -_defined in_: [src/js/player.js#L498](https://github.com/videojs/video.js/blob/master/src/js/player.js#L498) +_defined in_: [src/js/player.js#L514](https://github.com/videojs/video.js/blob/master/src/js/player.js#L514) --- ### volumechange `EVENT` > Fired when the volume changes -_defined in_: [src/js/player.js#L549](https://github.com/videojs/video.js/blob/master/src/js/player.js#L549) +_defined in_: [src/js/player.js#L565](https://github.com/videojs/video.js/blob/master/src/js/player.js#L565) --- diff --git a/package.json b/package.json index ddf4efa80..4e3be330c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "video.js", "description": "An HTML5 and Flash video player with a common API and skin for both.", - "version": "4.6.1", + "version": "4.6.2", "copyright": "Copyright 2014 Brightcove, Inc. https://github.com/videojs/video.js/blob/master/LICENSE", "keywords": [ "videojs", diff --git a/src/js/media/html5.js b/src/js/media/html5.js index 6cb8ff46c..66fcdb158 100644 --- a/src/js/media/html5.js +++ b/src/js/media/html5.js @@ -32,10 +32,7 @@ vjs.Html5 = vjs.MediaTechController.extend({ // If the element source is already set, we may have missed the loadstart event, and want to trigger it. // We don't want to set the source again and interrupt playback. if (source && this.el_.currentSrc === source.src && this.el_.networkState > 0) { - // wait for the player to be ready so the player listeners are attached - player.ready(function(){ - player.trigger('loadstart'); - }); + player.trigger('loadstart'); // Otherwise set the source if one was provided. } else if (source) { this.el_.src = source.src; diff --git a/src/js/player.js b/src/js/player.js index 9fdd95cca..c8d461682 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -58,20 +58,6 @@ vjs.Player = vjs.Component.extend({ // see enableTouchActivity in Component options.reportTouchActivity = false; - // Make sure the event listeners are the first things to happen when - // the player is ready. See #1208 - // If not, the tech might fire events before the listeners are attached. - this.ready(function(){ - this.on('loadstart', this.onLoadStart); - this.on('ended', this.onEnded); - this.on('play', this.onPlay); - this.on('firstplay', this.onFirstPlay); - this.on('pause', this.onPause); - this.on('progress', this.onProgress); - this.on('durationchange', this.onDurationChange); - this.on('fullscreenchange', this.onFullscreenChange); - }); - // Run base component initializing with new options. // Builds the element through createEl() // Inits and embeds any child components in opts @@ -230,6 +216,22 @@ vjs.Player.prototype.createEl = function(){ } vjs.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup. + // The event listeners need to be added before the children are added + // in the component init because the tech (loaded with mediaLoader) may + // fire events, like loadstart, that these events need to capture. + // Long term it might be better to expose a way to do this in component.init + // like component.initEventListeners() that runs between el creation and + // adding children + this.el_ = el; + this.on('loadstart', this.onLoadStart); + this.on('ended', this.onEnded); + this.on('play', this.onPlay); + this.on('firstplay', this.onFirstPlay); + this.on('pause', this.onPause); + this.on('progress', this.onProgress); + this.on('durationchange', this.onDurationChange); + this.on('fullscreenchange', this.onFullscreenChange); + return el; }; @@ -408,30 +410,44 @@ vjs.Player.prototype.stopTrackingCurrentTime = function(){ * @event loadstart */ vjs.Player.prototype.onLoadStart = function() { - // remove any first play listeners that weren't triggered from a previous video. - this.off('play', initFirstPlay); - this.one('play', initFirstPlay); + // TODO: Update to use `emptied` event instead. See #1277. - if (this.error()) { - this.error(null); + // reset the error state + this.error(null); + + // If it's already playing we want to trigger a firstplay event now. + // The firstplay event relies on both the play and loadstart events + // which can happen in any order for a new source + if (!this.paused()) { + this.trigger('firstplay'); + } else { + // reset the hasStarted state + this.hasStarted(false); + this.one('play', function(){ + this.hasStarted(true); + }); } - - vjs.removeClass(this.el_, 'vjs-has-started'); }; - // Need to create this outside the scope of onLoadStart so it - // can be added and removed (to avoid piling first play listeners). -function initFirstPlay(e) { - var fpEvent = { type: 'firstplay', target: this.el_ }; - // Using vjs.trigger so we can check if default was prevented - var keepGoing = vjs.trigger(this.el_, fpEvent); +vjs.Player.prototype.hasStarted_ = false; - if (!keepGoing) { - e.preventDefault(); - e.stopPropagation(); - e.stopImmediatePropagation(); +vjs.Player.prototype.hasStarted = function(hasStarted){ + if (hasStarted !== undefined) { + // only update if this is a new value + if (this.hasStarted_ !== hasStarted) { + this.hasStarted_ = hasStarted; + if (hasStarted) { + this.addClass('vjs-has-started'); + // trigger the firstplay event if this newly has played + this.trigger('firstplay'); + } else { + this.removeClass('vjs-has-started'); + } + } + return this; } -} + return this.hasStarted_; +}; /** * Fired when the player has initial duration and dimension information diff --git a/test/unit/mediafaker.js b/test/unit/mediafaker.js index 124e5a555..222a9c10e 100644 --- a/test/unit/mediafaker.js +++ b/test/unit/mediafaker.js @@ -40,6 +40,7 @@ vjs.MediaFaker.prototype.src = function(){ return 'movie.mp4'; }; vjs.MediaFaker.prototype.volume = function(){ return 0; }; vjs.MediaFaker.prototype.muted = function(){ return false; }; vjs.MediaFaker.prototype.pause = function(){ return false; }; +vjs.MediaFaker.prototype.paused = function(){ return true; }; vjs.MediaFaker.prototype.supportsFullScreen = function(){ return false; }; vjs.MediaFaker.prototype.features = {}; vjs.MediaFaker.prototype.buffered = function(){ return {}; }; diff --git a/test/unit/player.js b/test/unit/player.js index 70831b45d..7eb6db94e 100644 --- a/test/unit/player.js +++ b/test/unit/player.js @@ -378,7 +378,7 @@ test('should not add multiple first play events despite subsequent loads', funct var player = PlayerTest.makePlayer({}); player.on('firstplay', function(){ - ok('First play should fire once.'); + ok(true, 'First play should fire once.'); }); // Checking to make sure onLoadStart removes first play listener before adding a new one. @@ -387,6 +387,35 @@ test('should not add multiple first play events despite subsequent loads', funct player.trigger('play'); }); +test('should fire firstplay after resetting the player', function() { + var player = PlayerTest.makePlayer({}); + + var fpFired = false; + player.on('firstplay', function(){ + fpFired = true; + }); + + // init firstplay listeners + player.trigger('loadstart'); + player.trigger('play'); + ok(fpFired, 'First firstplay fired'); + + // reset the player + player.trigger('loadstart'); + fpFired = false; + player.trigger('play'); + ok(fpFired, 'Second firstplay fired'); + + // the play event can fire before the loadstart event. + // in that case we still want the firstplay even to fire. + player.tech.paused = function(){ return false; }; + fpFired = false; + // reset the player + player.trigger('loadstart'); + // player.trigger('play'); + ok(fpFired, 'Third firstplay fired'); +}); + test('should remove vjs-has-started class', function(){ expect(3);