-
Notifications
You must be signed in to change notification settings - Fork 7.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed the issue where the firstplay event wouldn't fire if the play even... #1271
Conversation
…vent was fired before loadstart
@@ -33,9 +33,9 @@ vjs.Html5 = vjs.MediaTechController.extend({ | |||
// 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment out of date now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the commented code there needs to be removed.
@dmlap @gkatsev do either of you know anything that uses the I remember ads being the main reason for adding that, and it doesn't appear ads is even using the firstplay event. |
I do not remember anything that depends on |
I added a hasStarted property that makes it cleaner to add/remove the has-started class and trigger the firstplay event. It also kills that firstplay feature of stopping the play event, but that was never documented and as far as I can tell, never used. |
We had discussed using |
Great, thanks. |
vjs.removeClass(this.el_, 'vjs-has-started'); | ||
// reset the hasStarted state | ||
this.hasStarted(false); | ||
this.one('play', function(){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are still scenarios where the loadstart-play relationship is going to get messed up. For instance, loading a video initially and then replacing it before play()
. That would produce two loadstarts and then a play, and would cause the hasStarted
handler to get invoked twice. I don't think that particular order would cause errors but it could be confusing. I was proposing something more like this:
/* in Player.init */
this.on('play', function() {
if (!player.hasClass('vjs-has-started')) {
player.addClass('vjs-has-started');
player.trigger('firstplay');
}
});
this.on('loadstart', function() {
if (player.hasClass('vjs-has-started')) {
player.removeClass('vjs-has-started');
}
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would cause the hasStarted handler to get invoked twice
The hasStarted function has a built-in check to see if it's actually being changed, and only trigger events/change classes if it is. So the firstplay event will on get fired once in that scenario, and amazingly enough there was already a test for that.
I could change it to always call hasStarted(true) whenever the play event is fired. That would prevent the double hasStarted and then be almost identical to your example. I'm essentially using the "local variable" part of your previous suggestion instead of using hasClass. I'm not sure exactly why but I don't love the idea using hasClass to determine the current state.
I don't think you mean for it to fix everything but your example wouldn't work for the play-happens-first scenario when loading a new source. The loadstart event would happen after the play event and remove the has-started class, causing the big play button to keep showing while the video plays. Basically the firstplay event is dependent on both the play and loadstart events, which can happen in any order for a new source, so somewhere we have to check that both have happened before triggering firstplay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point, my example code is busted. My main concern is that listeners-that-set-listeners are a finicky way of managing state. It takes a lot of thinking to be sure that everything is being setup and cleaned up correctly and it's easy to break down the line. I wish we could come up with a way of formulating the conditions for firstplay that localized and minimized the state management. I still think it's possible to do a little bit better on that front.
Follow-up question: do we actually want the big play button to show up again once some amount of video has been played? Can we dodge the entire issue if vjs-has-started is set on the first |
I may have found a better approach... The video element fires an
Yeah, we actually had a number of issues around how to reset the player to its original state for later videos. It used to work the way you're describing before that. |
That sounds much nicer. We can avoid using |
No, haven't checked that yet. It's a standard event and works in Chrome, Firefox, and Safari desktop, so I'd be surprised if it doesn't work the same on mobile. But then again, that might be naive. Would you guys be able to try on some devices? You can use this jsbin http://jsbin.com/baqoc/1/edit |
Results loading the example. On iOS and Android, I tried to hit the play button as quickly as possible to force bad behavior.
|
Nice, thanks. That looks pretty consistent to me. We'll just have to make sure the Win 8 first emptied event does mess anything up, but it shouldn't. |
Closed by 71c0a72 |
...t was fired before loadstart