Right now the addPlayer code is very fragile, in that it refuses to work when given no settings. That won’t do. It needs to be much more reliable than that. After fixing that we’ll add settings so that a video can load (but not play) before a button is clicked.
Improve addPlayer
With the addPlayer code, we want it to work properly when no settings are given to it. That means copying the default settings code over to the addPlayer code, with a plan to remove that code from the loadPlayer code.
I’ll also update the updateOpts code to instead be updateParams as that more accurately represents what happens there.
function updateParams(playerParams, params) {
const entries = Object.entries(params);
const paramsToUpdate = entries.forEach(function([key, value]) {
if (key in playerParams) {
playerParams[key] = value;
}
});
return playerParams;
}
The addPlayer code now becomes a lot simpler, with the defaults being updated by values from the settings.
function addPlayer(video, settings) {
const playerParamDefaults = {
videoId: video.dataset.id,
host: "https://www.youtube-nocookie.com",
width: 198,
height: 198,
playerVars: {
autoplay: 1,
controls: 1,
loop: 0,
rel: 0,
enablejsapi: 1,
iv_load_policy: 3,
cc_load_policy: 0,
fs: 0,
disablekb: 1
},
events: {
"onReady": onPlayerReady,
"onStateChange": onPlayerStateChange
}
};
const playerParams = updateParams(playerParamDefaults, settings);
playerParams.playerVars = updateParams(playerParams.playerVars, settings);
players.push(new YT.Player(video, playerParams));
}
That is a lot more stable now, and we can remove from the initPlayer code a lot of stuff that’s no longer needed, resulting in initPlayer code that now only consists of:
function initPlayer(wrapper) {
const video = wrapper.querySelector(".video");
videoPlayer.addPlayer(video, opts);
}
That has resulted in the addPlayer code being more robust, and has simplified the initPlayer code too in the process.
Showing the player without playing it
Right now the loadPlayer code doesn’t actually load the player. Instead it sets up a cover click handler that when clicked will load the player. We need to be able to instruct whether a video gets automatically loaded, which happens with jacketc, or whether clicking on the cover loads the player.
We can add an autoload parameter that defaults to false:
loadPlayer({
target: ".jacketc",
autoload: true,
autoplay: 0,
...
});
The coverClickHandler can now be updated. If autoload is true, we shouldn’t init the player when the cover is clicked.
function coverClickHandler(evt) {
const wrapper = evt.currentTarget.nextElementSibling;
show(wrapper);
if (!opts.autoload) {
initPlayer(wrapper);
}
}
Before we go much further though, we need to do something about loadPlayer and initPlayer.
- loadPlayer doesn’t load the player, it initializes things for the player.
- initPlayer doesn’t init the player. Instead it loads the player.
Those two names need to be switched.
// function loadPlayer(opts) {
function initPlayer(opts) {
...
// function initPlayer(wrapper) {
function loadPlayer(wrapper) {
...
function coverClickHandler(evt) {
...
// initPlayer(wrapper);
loadPlayer(wrapper);
}
...
function onYouTubeIframeAPIReady() {
// loadPlayer({
initPlayer({
Now the coverClickHandler code makes better sense, where if the autoload has happened we don’t need to load the player.
function coverClickHandler(evt) {
const wrapper = evt.currentTarget.nextElementSibling;
show(wrapper);
if (!opts.autoload) {
loadPlayer(wrapper);
}
}
Where do we load the autoloaded video from then? It will be after the event handler is assigned.
function initPlayer(opts) {
...
const cover = document.querySelector(opts.target);
cover.addEventListener("click", coverClickHandler);
if (opts.autoload) {
const wrapper = cover.nextElementSibling;
loadPlayer(wrapper);
}
}
And as a bit of cleanup, because we have two sets of code using nextElementSibling to get the video, we really should have a small getVideo function too.
function getWrapper(cover) {
return cover.nextElementSibling;
}
function getVideo(cover) {
return getWrapper(cover).querySelector(".video");
}
...
// function loadPlayer(wrapper) {
function loadPlayer(video) {
// const video = wrapper.querySelector(".video");
videoPlayer.addPlayer(video, opts);
}
...
if (!opts.autoload) {
const video = getVideo(cover);
// loadPlayer(wrapper);
loadPlayer(video);
}
...
function coverClickHandler(evt) {
// const wrapper = evt.currentTarget.nextElementSibling;
const cover = evt.currentTarget;
const wrapper = getWrapper(evt.currentTarget);
show(wrapper);
if (!opts.autoload) {
const video = getVideo(wrapper);
// loadPlayer(wrapper);
loadPlayer(video);
}
}
...
if (opts.autoload) {
// const wrapper = cover.nextElementSibling;
const video = getVideo(cover);
// loadPlayer(wrapper);
loadPlayer(video);
}
We now have code that reliably lets us autoplay videos, and also lets us autoload videos before the cover is clicked.
Now we need the clicking on a cover to trigger the playing of the video, which is the next post.