How to make custom video player applicable to multiple videos? - javascript

I have multiple HTML videos on my page, and want to apply this custom video player to them. The thing is, this only works for the first video, and not for the second, third and fourth.
I have no idea where to start.
I made a fiddle of the current state: JSFiddle
My Javascript
/* Get Our Elements */
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚❚';
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listners */
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
$('video').on('ended', function() {
$.fn.fullpage.moveSlideRight();
});
I want this script to work on every video element on the page:
JSFiddle
Thanks,
Max

You can try something like this :
/* Get Our Elements */
$('.player').each(function() {
var player = $(this).get(0);
var video = player.querySelector('.viewer');
var progress = player.querySelector('.progress');
var progressBar = player.querySelector('.progress__filled');
var toggle = player.querySelector('.toggle');
var skipButtons = player.querySelectorAll('[data-skip]');
var ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚❚';
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listners */
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
$('video').on('ended', function() {
$.fn.fullpage.moveSlideRight();
});
});
https://jsfiddle.net/kq5hdw0m/

Related

How do I make a media Query responsive in JavaScript?

I really need some help with media queries. I have made a testimonial slider and when it gets to a 800px breakpoint, I want to disable the JS for the slider and change the layout.
The problem is that I am unable to deactivate the js once it has been activated, I'm not sure if the problem is from the event handler, the if statement of from the deactivation function.
I have managed to deactivate the JS but I have to reload the page to do it, I want it to be responsive so that I don't have to reload the page every time.
If you can help, that would be a huge help, thanks!
Here is my JS code:
(All my css code works, hence, it hasn't been added).
const mQ = window.matchMedia('(max-width: 800px)');
const testimonialSlider = function () {
const slides = document.querySelectorAll('.slide');
const btnLeft = document.querySelector('.slider__btn--left');
const btnRight = document.querySelector('.slider__btn--right');
const dotContainer = document.querySelector('.dots');
const testimonialContainer = document.querySelector(
'.testimonial-outer-container'
);
//Deactivate functions
const deactivateJs = function (slide) {
slides.forEach(
(s, i) => (s.style.transform = `translateX(${0 * (i - slide)}%)`)
);
testimonialContainer.removeChild(dotContainer);
console.log('DeactivatingJs');
};
// Activate functions
const activateJs = function () {
console.log('ActivateJS');
let curSlide = 0;
const maxSlide = slides.length;
//Functions
const createDots = function () {
testimonialContainer.appendChild(dotContainer);
slides.forEach(function (_, i) {
dotContainer.insertAdjacentHTML(
'beforeend',
`<button class="dots__dot" data-slide="${i}"></button>`
);
});
};
const slideReady = function () {
createDots();
activateDot(0);
goToSlide(0);
};
const goToSlide = function (slide) {
slides.forEach(
(s, i) => (s.style.transform = `translateX(${100 * (i - slide)}%)`)
);
};
// Activate dots
const activateDot = function (slide) {
// First we remove the active class on all of the dots and then we add it to the one that it is active
document
.querySelectorAll('.dots__dot')
.forEach(dot => dot.classList.remove('dots__dot--active'));
document
.querySelector(`.dots__dot[data-slide="${slide}"]`)
.classList.add('dots__dot--active');
};
// Next slide
const nextSlide = function () {
if (curSlide === maxSlide - 1) {
curSlide = 0;
} else {
curSlide++;
}
goToSlide(curSlide);
activateDot(curSlide);
};
const prevSlide = function () {
if (curSlide === 0) {
curSlide = maxSlide - 1;
} else {
curSlide--;
}
goToSlide(curSlide);
activateDot(curSlide);
};
slideReady();
//Event Handlers
btnRight.addEventListener('click', nextSlide);
btnLeft.addEventListener('click', prevSlide);
// Creating an event with the arrows
document.addEventListener('keydown', function (e) {
console.log(e);
if (e.key === 'ArrowLeft') prevSlide();
if (e.key === 'ArrowRight') nextSlide();
});
dotContainer.addEventListener('click', function (e) {
if (e.target.classList.contains('dots__dot')) {
/// const slide = e.target.dataset.slide;
//This is the same as above, the slide part is from the html and the dataset is an HTML attribute
const { slide } = e.target.dataset;
goToSlide(slide);
activateDot(slide);
}
});
};
// if (mQ.matches) {
// deactivateJs();
// } else {
// activateJs();
// }
const js = function () {
if (mQ.matches) {
console.log('deactivate');
deactivateJs();
} else {
activateJs();
}
};
mQ.addEventListener('change', js);
};
testimonialSlider();

How to make play button disabled after the animation is finished?

I have this problem: I have two buttons btStop and btRace . BtPlays clicks all the buttons bt1 and all my cars are driving at the same time. BtStop works exactly the same but it stops the animation. My problem is, that when I once click btRace and animation is done I cannot click it again unless I click btStop, which is misleading because animation is already stopped.
Is there a way to make btPlay active again after the animation is finished?
I have long code so I am pasting showButtons method
showButtons(bt1, bt2, img, editingCarId) {
let playBts = document.querySelectorAll('.play')
function animation(img) {
let status = 'started';
let aPICallCarEngineState = new APICallCarEngineState(editingCarId, status);
aPICallCarEngineState.processRequestJSON((res) => {
// let resStr = JSON.stringify(res);
// console.log('I got ' + res)
res.velocity = res.velocity * 0.01
// res.distance = res.distance * 0.001
res.distance = 500;
// ===========Animation===================
img.style.animation = `car_move ${res.velocity}s ease-in`
})
}
//================Stop Animation===============
function stopAnimation() {
img.style.animation = 'none'
console.log(bt2 + 'stopp')
}
bt1.addEventListener('click', () => {
animation(img)
});
bt2.addEventListener('click', () => {
stopAnimation()
})
//=================Button start all animations ====================
this.btRace.addEventListener('click', () => {
bt1.click();
})
//=================Button stop all animations ====================
this.btStop.addEventListener('click', () => {
bt2.click();
})
}
invoke:
constructor:
this.table.appendTableHeadButton('RACE!')
this.table.appendTableHeadButtonStop('stop')
Buttoncreator:
appendTableHeadButtonStop(text) {
let td = document.createElement('td');
this.btStop = document.createElement('button');
this.btStop.innerText = text;
this.btStop.style.backgroundColor = 'red';
td.appendChild(this.btStop);
let bt = this.btStop;
this.headeRow.appendChild(td);
}
showButtons(bt1, bt2, img, editingCarId) {
let playBts = document.querySelectorAll('.play')
let isAnimating = false;
function animation(img) {
isAnimating = true;
btRace.disabled = true;
let status = 'started';
let aPICallCarEngineState = new APICallCarEngineState(editingCarId, status);
aPICallCarEngineState.processRequestJSON((res) => {
// let resStr = JSON.stringify(res);
// console.log('I got ' + res)
res.velocity = res.velocity * 0.01
// res.distance = res.distance * 0.001
res.distance = 500;
// ===========Animation===================
img.style.animation = `car_move ${res.velocity}s ease-in`
img.addEventListener('animationend', () => {
isAnimating = false;
btRace.disabled = false;
});
});
}
//================Stop Animation===============
function stopAnimation() {
isAnimating = false;
btRace.disabled = false;
img.style.animation = 'none'
console.log(bt2 + 'stopp')
}
bt1.addEventListener('click', () => {
animation(img)
});
bt2.addEventListener('click', () => {
stopAnimation()
});
//=================Button start all animations ====================
this.btRace.addEventListener('click', () => {
bt1.click();
});
//=================Button stop all animations ====================
this.btStop.addEventListener('click', () => {
bt2.click();
});
}
I am adding a flag to check the state of animation, and then toggle disabled property of btRace button respectively.

useState not working as expected - selectedElement in the state is resetting to initial value supplied in starting

I have two events drag start and drag end. At the time of drag start I am deciding whether to move it or copy depending on some logic and setSelectedElement is running and setting the new element to it but as you can see console of new element in drag end and console for previously selected in drag start are both empty.
after some debugging, I found out it is turning to an empty string supplied in the very beginning of use state.
App.js
export default function App() {
const [selectedElement, setSelectedElement] = useState("");
const [diffX, setDiffX] = useState(0);
const [diffY, setDiffY] = useState(0);
const [group, setGroup] = useState([]);
useEffect(() => {
console.log("selected element changed");
}, [selectedElement]);
const handleDragStart = (event) => {
console.log("drag start ");
// console.log("class list", event.currentTarget.classList);
console.log("previous selected element is ", selectedElement);
let functionalityType = "";
let elementSelected = "";
let classList = event.currentTarget.classList;
for (let i = 0; i < classList.length; i++) {
//move element
if (classList[i].includes("group")) {
functionalityType = "move";
break;
}
}
if (functionalityType !== "move") {
console.log("inside copy");
elementSelected = event.currentTarget.cloneNode(true);
elementSelected.style.position = "absolute";
elementSelected.addEventListener("dragstart", handleDragStart);
elementSelected.addEventListener("dragend", handleDragEnd);
} else {
console.log("inside move");
elementSelected = event.currentTarget;
// console.log("event current target", event.currentTarget);
}
setDiffX(event.clientX - event.currentTarget.getBoundingClientRect().left);
setDiffY(event.clientY - event.currentTarget.getBoundingClientRect().top);
setSelectedElement(elementSelected);
};
const handleDragEnd = (event) => {
console.log("drag end");
let newElement = selectedElement;
console.log("new element is", newElement);
newElement.style.top = event.clientY - diffY + "px";
newElement.style.left = event.clientX - diffX + "px";
document.getElementById("MidArea").appendChild(newElement);
}
return (
<div
draggable={true}
onDragStart={props.handleDragStart}
onDragEnd={props.handleDragEnd}
className="draggable"
>);
}
Is there any reason you're doing setSelectedElement(elementSelected); outside else statement
Your code lacks some details to debug and find the missing piece however, drag and drop, I had this implemented sometime back, try the below
const stopDrag = () => {
document.onmouseup = null;
document.onmousemove = null;
};
export const dragComponent = (dragRef) => {
let coordinateOne = 0;
let coordinateTwo = 0;
let coordinateThree = 0;
let coordinateFour = 0;
const dragHandle = dragRef.current;
const elementDrag = (event) => {
event.preventDefault();
coordinateOne = coordinateThree - event.clientX;
coordinateTwo = coordinateFour - event.clientY;
coordinateThree = event.clientX;
coordinateFour = event.clientY;
dragHandle.style.top = `${dragHandle.offsetTop - coordinateTwo}px`;
dragHandle.style.left = `${dragHandle.offsetLeft - coordinateOne}px`;
};
const dragDown = (event) => {
event.preventDefault();
coordinateThree = event.clientX;
coordinateFour = event.clientY;
document.onmouseup = stopDrag;
document.onmousemove = elementDrag;
};
dragHandle.onmousedown = dragDown;
};
function MyComponent(){
const dragRef = useRef();
useEffect(() => {
dragComponent(dragRef);
}, []);
return (
<div draggable ref={dragRef}>
<h1> I am draggable..drag me around</h1>
</div>
)
}
Did you try this:
setDiffX(event.clientX - event.currentTarget.getBoundingClientRect().left);
setDiffY(event.clientY - event.currentTarget.getBoundingClientRect().top);
dragElementRef.current = elementSelected;
setSelectedElement(elementSelected);
};
let dragElementRef = useRef(selectedElement);
....
....
const handleDragEnd = (event) => {
//setTimeout(() => {
console.log("drag end");
let newElement = dragElementRef.current;
console.log("new element is", newElement);
newElement.style.top = event.clientY - diffY + "px";
newElement.style.left = event.clientX - diffX + "px";
document.getElementById("MidArea").appendChild(newElement);
//},500);
}
What I think is happening is your handleDragEnd() is being called before the next render cycle with updated value of state exists.
Try adding a setTimeout to add some delay.

How to make custom audio player applicable to multiple audio?

I have multiple HTML audio on my page, and want to apply this custom audio player to them. The thing is, this only works for the first audio, and not for the second, third and fourth. Is there any way where I can solve this problem?
My JavaScript code:
const audio = document.getElementById('audio');
const playPauseButton = document.querySelector('.play-button');
const progressBar = document.querySelector('.progress-bar');
const progress = document.querySelector('.progress-controls');
const playButton = document.querySelector('.playing');
const pauseButton = document.querySelector('.paused');
const playPause = () => {
if(audio.paused){
audio.play()
playButton.style.display = 'none';
pauseButton.style.display = '';
}
else{
audio.pause()
playButton.style.display = '';
pauseButton.style.display = 'none';
}
}
function pause(){
pauseButton.style.display = 'none'
}
window.addEventListener('load', pause);
playPauseButton.addEventListener('click', playPause);
audio.addEventListener('timeupdate', function(){
var progress = audio.currentTime / audio.duration;
progressBar.style.width = progress * 100 + "%";
});
document.addEventListener('keyup', (event) => {
if (event.code === 'Space') {
playPause();
}
if (event.code === 'KeyP') {
playPause();
}
});

Creating Video Controls

window.onload = function () {
"use strict";
var video = document.getElementById("video"),
playButton = document.getElementById("play-pause"),
muteButton = document.getElementById("mute"),
fullScreenButton = document.getElementById("full-screen"),
seekBar = document.getElementById("seek-bar"),
volumeBar = document.getElementById("volume-bar");
muteButton.addEventListener("click", function () {
if (video.muted === false) {
video.muted = true;
muteButton.innerHTML = "Unmute";
} else {
video.muted = false;
muteButton.innerHTML = "Mute";
}
});
fullScreenButton.addEventListener("click", function () {
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.mozRequestFullScreen) {
video.mozRequestFullScreen(); // Firefox
} else if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen(); // Chrome and Safari
}
});
seekBar.addEventListener("change", function () {
var time = video.duration * (seekBar.value / 100);
video.currentTime = time;
});
video.addEventListener("timeupdate", function () {
var value = (100 / video.duration) * video.currentTime;
seekBar.value = value;
});
seekBar.addEventListener("mousedown", function () {
video.pause();
});
seekBar.addEventListener("mouseup", function () {
video.play();
});
volumeBar.addEventListener("change", function () {
video.volume = volumeBar.value;
});
This is my code and I'm receiving 3 error codes from JSLint.
1. Expected '(end)' at column 1, not column 7.
2. Expected '}' to match '{' from line 1 and instead saw '(end)'.
3. Expected ';' and instead saw '(end)'.
Any help getting this working would be greatly appreciated.
/*jslint browser: true*/
window.onload = function () {
"use strict";
var video = document.getElementById("video"),
//playButton = document.getElementById("play-pause"),
muteButton = document.getElementById("mute"),
fullScreenButton = document.getElementById("full-screen"),
seekBar = document.getElementById("seek-bar"),
volumeBar = document.getElementById("volume-bar");
muteButton.addEventListener("click", function () {
if (video.muted === false) {
video.muted = true;
muteButton.innerHTML = "Unmute";
} else {
video.muted = false;
muteButton.innerHTML = "Mute";
}
});
fullScreenButton.addEventListener("click", function () {
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.mozRequestFullScreen) {
video.mozRequestFullScreen(); // Firefox
} else if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen(); // Chrome and Safari
}
});
seekBar.addEventListener("change", function () {
var time = video.duration * (seekBar.value / 100);
video.currentTime = time;
});
video.addEventListener("timeupdate", function () {
var value = (100 / video.duration) * video.currentTime;
seekBar.value = value;
});
seekBar.addEventListener("mousedown", function () {
video.pause();
});
seekBar.addEventListener("mouseup", function () {
video.play();
});
volumeBar.addEventListener("change", function () {
video.volume = volumeBar.value;
});
};
This gives me no errors. /*jslint browser: true*/ is to let jslint know window, document and so on are defined. I commented you unused playButton. And you forgot ; at the end of your code.

Categories

Resources