Step 4 part 4: Extracting playerAdder
Here is what remains of the addPlayer code in the onYouTubeIframeAPIReady function, using color-coding that shows:
- yellow for cover code
- blue for player code
- red for conflicts across the two
There are several problems seen there.
- The top red line involves both the cover and the player. Itâs not possible to remove or rename coverSelector as that goes directly to the manageCover code at the bottom of the function.
- The first yellow line is a long way away from the other yellow line, and there doesnât seem to be any reasonable way to bring them together by moving away the code thatâs between them.
- The second red line is also a conflict, because itâs dealing with the cover, but is using nextElementSibling to gain a reference to the player wrapper.
A suitable solution presents itself though when it comes to the coverSelector. We donât have to call it coverSelector. Instead, if we accept that the player expects to reference things in terms of the wrapper, we can extract out some of that addPlayer code to a separate function:
We canât call that function addPlayer because thereâs already one with that same name in the onYouTubeIframeAPIReady function, but thereâs a bigger reason why we canât call it something like that. When we call it add or addPlayer, there is an expectation that the player gets added to something, and it doesnât. Instead you need to run the returned function, either directly or by assigning it to an event handler.
What is really happening here is that a callback function is being returned. Itâs not an addPlayer function because it doesnât add a player. Instead, itâs a playerAdder callback because you must run the returned function to actually add the player. We can call the function playerAdder instead.
function playerAdder(wrapper, playerOptions) {
const clickHandler = managePlayer.createClickHandler(wrapper, playerOptions);
return clickHandler;
}
We can now move that playerAdder function back in to the managePlayer code, but we canât use add or addPlayer for its public method name. When we use add, there is an expectation that something gets added, but that doesnât occur with this code. You can run the playerAdder all day and nothing gets added. Thatâs because it only returns a function instead of adding anything. It is that returned function must later on be run to actually add the thing. The onYouTubeIframeAPIReady function adds a clickHandler to the page so calling that function addPlayer is suitable, but the managePlayer code doesnât actually add a player. Instead it needs to be run later on to add the player. Thatâs why the names of add and addPlayer arenât suitable, and another name such as adder
is much more suitable for the name instead.
function playerAdder(wrapper, playerOptions) {
const clickHandler = createClickHandler(wrapper, playerOptions);
return clickHandler;
}
return {
adder: playerAdder
};
function onYouTubeIframeAPIReady() {
// function playerAdder(wrapper, playerOptions) {
// const clickHandler = managePlayer.createClickHandler(wrapper, playerOptions);
// return clickHandler;
// }
function addPlayer(coverSelector, playerOptions) {
Lastly with the player code, the clickHandler shouldnât be there either. The player code has no business knowing about click handlers in regard to the cover. Instead itâs a callback function thatâs being returned, which later on is used by the cover code as a click handler.
Here are the current clickhandler and player adder functions:
function createClickHandler(wrapper, playerOptions) {
return function clickHandler() {
initPlayer(wrapper, playerOptions);
};
}
function playerAdder(wrapper, playerOptions) {
const clickHandler = createClickHandler(wrapper, playerOptions);
return clickHandler;
}
We need to remove that clickHandler information from the player code, and just refer to it as a callback instead.
function createCallback(wrapper, playerOptions) {
return function callback() {
initPlayer(wrapper, playerOptions);
};
}
function playerAdder(wrapper, playerOptions) {
const callback = createCallback(wrapper, playerOptions);
return callback;
}
Because playerAdder is basically passing through the function parameters to the click handler, we donât need that createCallback code anymore and can move it into the playerAdder code.
// function createCallback(wrapper, playerOptions) {
// return function callback() {
// initPlayer(wrapper, playerOptions);
// };
// }
function playerAdder(wrapper, playerOptions) {
// const callback = managePlayer.createCallback(wrapper, playerOptions);
return function callback() {
initPlayer(wrapper, playerOptions);
};
// return callback;
}
We now have a better understanding of that playerAdder code. It doesnât actually add anything when it runs. Instead it delays that adding by returning a callback function, which gets run later on.
The onYouTubeIframeAPIReady function also needs updating to remove all ideas of click handler until we actually get to the cover code.
function onYouTubeIframeAPIReady() {
function addPlayer(coverSelector, playerOptions) {
const cover = document.querySelector(coverSelector);
const wrapper = cover.nextElementSibling;
// const clickHandler = managePlayer.adder(wrapper, playerOptions);
const callback = managePlayer.adder(wrapper, playerOptions);
manageCover.addCoverHandler(coverSelector, callback);
}
The last part of this Step 4 work is some final tidying up of the onYouTubeIframeAPIReady addPlayer code in regard to the nextElementSibling that helps to resolve more conflicts between cover and player, which Iâll get to in the next post.