-
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
implement lifecycle hooks and trigger pre/post setup hooks #3639
Conversation
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 don't think that the hook function needs ready
.
Also, would be good to add a guide documenting this feature.
} | ||
|
||
videojs.hooks('presetup').forEach(function(hookFunction) { | ||
options = videojs.mergeOptions(options, hookFunction(tag, options, ready)); |
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.
Why pass ready
to the hook?
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.
we probably don't need to
* @param {String} type the lifecyle event to get hooks from | ||
* @return {Array} an array of hooks, or an empty array if there are none | ||
*/ | ||
videojs.hooks = function(type) { |
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 hooks a too-generic term? would we want any more hooks on the main videojs object beyond presetup
and postsetup
?
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.
maybe pre/post shutdown? (there is no notion of this yet though
return tag.player || Player.players[tag.playerId]; | ||
} | ||
|
||
videojs.hooks('presetup').forEach(function(hookFunction) { |
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.
The ModalDialog
component has similar lifecycle events, but the naming scheme is:
beforefoo
: Happens before the thing.foo
: Happens after the thing.
Maybe we ought to follow that universally and use beforesetup
and setup
?
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.
we could, and previously I had it implemented like that, it just seemed like a lot of duplicate code
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.
Wouldn't changing it just just involve changing postsetup
on line 111 into setup
?
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.
And presetup
to beforesetup
? I don't see where the duplicate code concern comes from...
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.
These are the possible implementations with that naming scheme & the pro's/con's. do you see any other ways to implement it that sound better? (maybe I am just not seeing a good implementation?)
Also I wanted to note that using
setup
seem a bit weird to me since it will actually be calledpostSetup
and not during setup
Add lifecycle setters, getters, removers, and lists in a loop to the prototype
- can make things confusing
- will not duplicate code
- will pollute the video.js object with any lifecycle event functions that we need to add
- may be more intuitive for a new user to call
beforeSetup
andsetup
to access things
use the hooks terminology internally and add lifecycle setters, getters, removers, and lists to the prototype in a loop
- Makes me think we should just use hooks directly
- will only pollute the video.js object with wrapper functions
- will not duplicate code
- may be more intuitive for the user
implement lifecycle functions without any looping or hooks terminology
- Every time we need to expose a new event we have to duplicate functionality (adding a setter, getter, remover, and a list to video.js)
- will pollute video.js with wrapper functions
- lots of duplicate code
- may be intuitive for the user
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 this is resolved
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.
Yep, thanks!
@@ -0,0 +1,85 @@ | |||
# Hooks | |||
Hooks exist so that users can latch on to certain Video.js lifecycle events |
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 we ought to explain that this is a separate concept from per-player events. In fact, we should probably not use the term "events" at all, lest we cause confusion with events-events.
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.
maybe something like:
Hooks exist so that users can hook into the video.js player lifecycle
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.
Conceptually similar to events, hooks provide users a way to intercept universal behaviors of video.js itself rather than individual players.
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.
Are they similar to events though? You don't generally have the ability to do an action like what we're doing with these hooks.
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.
Fair enough, but they are conceptually similar in the sense that you're providing a function to be called when a certain condition is met. But, of course, I'm not married to any particular phrasing. 😄
// automatically | ||
return options; | ||
}; | ||
``` |
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 this example (and the one below) is unclear without the videojs.hook()
call.
|
||
|
||
## Current Hooks | ||
Currently the following lifecycle events are accept and use hooks |
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 the heading can go away. And the phrasing/grammar here is weird. Maybe:
Currently, the following hooks are available:
Currently the following lifecycle events are accept and use hooks | ||
|
||
### beforesetup | ||
Called just before the player is created, so that the user can modify the options passed to the player or modify the video element that will be used for the player |
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.
Missing a period here.
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 we should mention here (and not just in the example) what happens if multiple hooks are.
Also, state that the method takes in the video element and an options object and is expected to return a new options object.
@@ -0,0 +1,85 @@ | |||
# Hooks | |||
Hooks exist so that users can latch on to certain Video.js lifecycle events |
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.
maybe something like:
Hooks exist so that users can hook into the video.js player lifecycle
Currently the following lifecycle events are accept and use hooks | ||
|
||
### beforesetup | ||
Called just before the player is created, so that the user can modify the options passed to the player or modify the video element that will be used for the player |
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 we should mention here (and not just in the example) what happens if multiple hooks are.
Also, state that the method takes in the video element and an options object and is expected to return a new options object.
} | ||
|
||
videojs.hooks('beforesetup').forEach(function(hookFunction) { | ||
options = videojs.mergeOptions(options, hookFunction(tag, videojs.mergeOptions({}, options))); |
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.
what happens if the hookFunction
returns null
or a string?
We probably should write some tests for this.
It may be easier to write tests if these are moved into a separate file and then copied over onto the videojs object but either way should work.
*/ | ||
videojs.hook = function(type, fn) { | ||
videojs.hooks_[type] = videojs.hooks_[type] || []; | ||
videojs.hooks_[type].push(fn); |
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.
instead of using push, we should do videojs.hooks_[type] = videojs.hooks_[type].concat(fn);
.
See videojs/mux.js#121
* @return {Function|undefined} the function that was removed or undef | ||
*/ | ||
videojs.removeHook = function(type, fn) { | ||
const hooks = videojs.hooks_[type] || []; |
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.
we should also slice here as well. See videojs/mux.js#121 again.
I still have to write some unit tests for this functionality |
* @param {String} type the lifecyle event to get hooks from | ||
* @return {Array} an array of hooks, or an empty array if there are none | ||
*/ | ||
videojs.hooks = function(type) { |
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.
Can we add a check to hooks
that if it's called with two arguments either logs an error or calls hook
for the user? Just ran into this problem and took a second to figure it out.
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.
With proposed changes, LGTM.
* @param {Function|Array} fn the function to attach | ||
*/ | ||
videojs.hook = function(type, fn) { | ||
const hooks = videojs.hooks[type]; |
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.
this should be videojs.hooks_[type] || []
or videojs.hooks(type);
videojs.hook = function(type, fn) { | ||
const hooks = videojs.hooks[type]; | ||
|
||
hooks[type].concat(fn); |
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.
should be videojs.hooks_[type] = hooks.concat(fn);
add a guide for hooks
} | ||
|
||
videojs.hooks('beforesetup').forEach(function(hookFunction) { | ||
const opts = hookFunction(tag, videojs.mergeOptions({}, options)); |
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.
basically, each handler that doesn't return an object is ignored?
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.
well they are still run, we just assume they don't want to change options
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.
Yup, makes sense. Meant the response is ignored.
videojs.hooks_[type] = videojs.hooks_[type].slice(); | ||
videojs.hooks_[type].splice(index, 1); | ||
|
||
return index > -1; |
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.
maybe also do this check above so we don't run the extra slice and splice unless necessary?
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.
done
assert.equal(videojs.hooks_.bar.length, 0, 'should have 0 bar hook'); | ||
}); | ||
|
||
QUnit.test('should be get all hooks for a type', function(assert) { |
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.
should be able to get all hooks for a type
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.
done, good catch
let setupCalled = false; | ||
let beforeSetupCalled = false; | ||
const beforeSetup = function(video, options) { | ||
beforeSetupCalled = true; |
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.
what about asserting that setupCalled
is still false in here?
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.
done, also added a check for beforeSetupCalled
in the setup function
assert.equal(setupCalled, true, 'setup was called'); | ||
}); | ||
|
||
QUnit.test('beforesetup returns dont break videojs options', function(assert) { |
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.
Do we want a positive test case for this as well?
Something like: beforesetup
hooks modify options properly and merge each item in the list
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.
good point
|
||
const vid = document.getElementById('test_vid_id'); | ||
|
||
videojs.hook('beforesetup', function(options) { |
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.
can we add another hook that say adds fluid: true
option?
Description
There is no current way to hook into the setup that video.js does, and this functionality would be useful for many plugins to use. (they can even initialize themselves with it)
Specific Changes proposed
Requirements Checklist