Problem executing multiple-times script on the bottom of body with javascript

I’m using a video player library (ckin) on my website.

This script library has to be placed at the bottom, before the /body.
At this point everything is fine.

My website has an + add button that creates a new video div that will run with this library script.
But the problem is this library doesn’t detect when a new div is added because it runs only one time on the page load, and then converts all the DIVS that it finds, but all the new DIVS created after that will not work with that script.

I have “managed” to fix that executing this script after creating the new video div:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://xxxxxxxxxx/ckin.min.js';        
document.body.appendChild(script);

But the problem with this is the OLD DIVS get broken because of the new script, and the only div that will work is the new one (until the script runs again on a new div).

I have created an example, so you can see what happens to the old DIVS

JSFIDDLE EXAMPLE
1- Add new video button
2- Use the run script button

As you can see the new video looks good, but the olds not.

I have tried sending a message to the author, but it seems he abandoned the project, so I have no faith getting an answer on this, and that’s the only reason I’m posting this here to see if someone has any great workaround or idea to “patch” this…

Thanks.

Well I can’t say that it is a “patch” since it would essentially be rewriting part of the script design. Half way down the ckin.js script you will see a call to wrapPlayers() which essentially queries all video tags in the page and wraps them in some custom div. That is step 1 that needs to be figured out with your new added player. Make sure it follows the same format.

Step 2 is that right after this you see where it queries all video tags and runs through a forEach on them? That function it uses, you might want to try pulling that out into its own stand alone function.

Step 3, now with that function as a stand alone, the forEach can still call on it, giving it a player. But what this will do for you is now allow you to call that function too, passing it your newly wrapped player and in theory should hook it all up with the player skin.

Hopefully you get what I am saying. The “meat and potatoes” part here is that players.forEach(function (player) { part. Instead of calling it anonymously, it would now call on the new stand along function. But now a function that you can call with your own player instances. :slight_smile:

1 Like

Hey @Martyr2, thanks for your answer.
Yeah, I figured out that like 1 hour ago and started to edit the wrapPlayers () function but still not working.

However, I’m figuring out I would like to convert this “forEach” to single action, so every time a new video is added I could run a small snippet after with one target which is that last added video.

Can I add an ID to a <video poster …> ? Like <video id=“customvid12831723” poster …>

This is the original wrapPlayers function:

function wrapPlayers() {

    var videos = document.querySelectorAll('video');

    videos.forEach(function (video) {

        var wrapper = document.createElement('div');
        wrapper.classList.add('ckin__player');

        video.parentNode.insertBefore(wrapper, video);

        wrapper.appendChild(video);
    });
}

I would like to do something like:

function wrapPlayers() {

    var videos = document.getElementById('customvid12831723');

    videos(function (video) {

        var wrapper = document.createElement('div');
        wrapper.classList.add('ckin__player12831723');

        video.parentNode.insertBefore(wrapper, video);

        wrapper.appendChild(video);
    });
}

Then after the wrapPlayers is executed it starts the entire script which I would like to point it using the custom class ckin__player12831723 so old (different class ID) wouldn’t be affected.

Not sure if I should try pointing to the video using class or just with ID.

What do you think?

Thanks.

Can you add an ID attribute? Sure. Not sure why, but it wouldn’t hurt anything. If you want to make a stand alone wrap player function you could do…

function wrapMyPlayer(video) {

        var wrapper = document.createElement('div');
        wrapper.classList.add('ckin__player');

        video.parentNode.insertBefore(wrapper, video);

        wrapper.appendChild(video); 
}

Here you pass in your video, it wraps it. Now mind you this is going to work completely independent of the other code. That stuff still runs on initial page load. You would just call this custom wrap function and the stand alone function (extracted from the forEach) and it will run that code on just your newly added players.

Not sure you need anything with the IDs honestly.

1 Like

I see, thanks for pointing @Martyr2. That’s exactly the same I did, and I thought It was wrong :smiley:

Now I’m figuring how to remove this forEach after the wrapPlayers();

Original:

var players = document.querySelectorAll('.ckin__player');

var iconPlay = '<i class="ckin-play"></i>';
var iconPause = '<i class="ckin-pause"></i>';
var iconVolumeMute = '<i class="ckin-volume-mute"></i>';
var iconVolumeMedium = '<i class="ckin-volume-medium"></i>';
var iconVolumeLow = '<i class="ckin-volume-low"></i>';
var iconExpand = '<i class="ckin-expand"></i>';
var iconCompress = '<i class="ckin-compress"></i>';

players.forEach(function (player) {
    var video = player.querySelector('video');

I have changed the video = document … because as said before I only want to target a specific video with X ID.

//var players = document.querySelectorAll('.ckin__player');

var iconPlay = '<i class="ckin-play"></i>';
var iconPause = '<i class="ckin-pause"></i>';
var iconVolumeMute = '<i class="ckin-volume-mute"></i>';
var iconVolumeMedium = '<i class="ckin-volume-medium"></i>';
var iconVolumeLow = '<i class="ckin-volume-low"></i>';
var iconExpand = '<i class="ckin-expand"></i>';
var iconCompress = '<i class="ckin-compress"></i>';

startplayer();  
function startplayer (player) {
var video = document.getElementById('customvid12831723');

But still not working, what I’m doing wrong here?

Error: Uncaught TypeError: Cannot read property 'classList' of undefined:18

Thanks.

Here is a fiddle for you. It is commented to show you how it was done.

https://jsfiddle.net/coderslexicon/3jh2uf7o/23/

As mentioned I pulled out the function from the forEach and called it “attachMySkin” and then created the one off custom wrap function “wrapMyPlayer”.

Just because I didn’t want to host this script anywhere, I just put it inline in the fiddle. But this should give you an idea of how this works. Notice that other than pulling that function out of the forEach I didn’t modify any of the existing code.

Edit: I had to modify what I told you about the wrapMyPlayer function because of feeding the string test through the function and needing to turn it to an element. Ideally you would give the function a straight element from the page and so won’t need the part about converting it to an element.

1 Like

Awesome work @Martyr2. However, I still can’t understand where is “player” defined?

Why my code is telling me that player is not defined? It’s because of the getElementById?

Yours:

function attachMySkin(player) {
    var video = player.querySelector('video');
[....
....]
}

players.forEach(function(player) {
    attachMySkin(player);
});

Mine:

function startplayer(player) {
    var video = document.getElementById('customvid12831723');
[....
....]
}

startplayer(player); 

I love what you did, but just trying to learn and understand what’s going on with my code. I will be using your fix 100%, but I would like to finish the code to make it uni-target.

The idea is removing the .js file from the body and just run the JavaScript when needed.

This is what I have ATM: https://codepen.io/yukyolol/pen/JjEyVyW

Thanks again :heart:

Are you familiar with the console.log command and how to use it? If so, I would put a console.log command echoing out your player variable. It would tell you if it is first finding the player instance you are trying to pass. Sounds like how you are selecting the player is not working and it is trying to pass something like undefined as your player variable’s value.

1 Like

Hi @Martyr2, thanks for your answer. Yeah, I have been using them, but I was very stuck, so I decided to stop for a while.

I’m back again today and modified your jsfiddle a little in order to make it purely with JavaScript.

The problem is this:

document.querySelectorAll('.ckin__player');

Instead of the last video ID or something that references only to the last created video (instead of all).

So I have changed some lines and commented // the lines that “do group actions” (because when tried to remove the function it breaks the code) (If you can’t remove the function, disable the actions inside :rofl: :rofl: :rofl:)

https://jsfiddle.net/0jgpr7dt/1/

Actually is working as I wanted to

What you think? Something to improve? Or something to change?

Thanks in advance!