I'm trying to have only one button working at one time .. and it does not work in any way ..
Although I do listener on both separately, and ID changed ..
I tried different options and could not reach a solution
help please
https://codepen.io/ido4560/pen/dZxqvZ
html
<div class="buttons">
<button id="buttonStart">Start Game</button>
<button id="buttonReset">Reset</button>
</div>
<div id="main">
<div id="first">
<div data-il="The Zombie" class="anim1"></div>
</div>
<div id="second">
<div data-il="The Man" class="anim2"></div>
</div>
<div id="third">
<div data-il="The Woman" class="anim3"></div>
</div>
</div>
<span>Score: </span>
css
#keyframes zombieWalk {
0% {
background-position: 0px 0px;
}
100% {
background-position: 1191px 0px;
}
}
#keyframes manWalk {
0% {
background-position: -5px 2px;
}
100% {
background-position: -993px 6px;
}
}
#keyframes womanWalk {
0% {
background-position: -21px 0px;
}
100% {
background-position: -1020px 0px;
}
}
body {
background-color: black;
margin: 10px auto;
width: 1000px;
text-align: center;
}
#main {
border: 2px solid white;
}
#main>#first {
background-color: red;
height: 179px;
}
#main>#first>div {
height: 167px;
width: 133px;
background: url(zombie.png) 0px 0px;
background-size: 1323px 168px;
background-color:white;
}
#main>#second {
background-color: blue;
height: 173px;
}
#main>#second>div {
height: 162px;
width: 133px;
background: url(man.png) -5px 2px;
background-size: 1126px 163px;
background-color:white;
}
#main>#third {
background-color: yellow;
height: 168px;
}
#main>#third>div {
height: 167px;
width: 133px;
background: url(woman.png) -21px 0px;
background-size: cover;
background-color:white;
}
#main>#first>.zombieWalk {
animation: zombieWalk 1s steps(9) infinite;
transform: translate(860px, 0px);
animation-play-state: running;
}
#main>#second>.manWalk {
animation: manWalk 1s steps(7) infinite;
transform: translate(860px, 0px);
animation-play-state: running;
}
#main>#third>.womanWalk {
animation: womanWalk 1s steps(6) infinite;
transform: translate(860px, 0px);
animation-play-state: running;
}
.buttons>button {
font-size: 20px;
margin: 10px 50px 20px 50px;
}
span {
color: red;
font-weight: bold;
line-height: 20px;
font-family: arial;
}
abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgab
js
/* Global var */
var div = document.querySelectorAll("#main>div>div");
var flag = 1;
var span = document.querySelector("span");
function runGame() {
var buttonStart = document.getElementById("buttonStart");
console.log(buttonStart);
buttonStart = addEventListener("click", startGame);
var buttonReset = document.getElementById("buttonReset");
console.log(buttonReset);
buttonReset = addEventListener("click", startAgain);
var number = rndNumber();
div[0].style.transition = 'transform ' + (rndNumber()) + 'ms';
//console.log(number);
var number = rndNumber();
div[1].style.transition = 'transform ' + (rndNumber()) + 'ms';
//console.log(number);
var number = rndNumber();
div[2].style.transition = 'transform ' + (rndNumber()) + 'ms';
//console.log(number);
div[0].addEventListener("transitionend", animEnd);
div[1].addEventListener("transitionend", animEnd);
div[2].addEventListener("transitionend", animEnd);
}
function animEnd(e) {
//console.log('im end');
//console.log(e);
console.log(flag);
if (flag == 1) {
var player = e.target.getAttribute("data-il");
//console.log(player + ' first');
span.innerHTML += "<br>";
span.innerText += '#1 ' + player;
//console.log(span);
flag++;
} else if (flag == '2') {
var player = e.target.getAttribute("data-il");
//console.log(player + ' second');
span.innerHTML += "<br>";
span.innerText += '#2 ' + player;
span.innerHTML += "<br>";
flag++;
} else if (flag == '3') {
var player = e.target.getAttribute("data-il");
//console.log(player + ' third');
span.innerText += '#3 ' + player;
}
}
function startGame() {
div[0].className = "zombieWalk";
div[1].className = "manWalk";
div[2].className = "womanWalk";
}
function rndNumber() {
return Math.floor(Math.random() * 10000);
}
function startAgain(){
window.location.reload(false);
}
runGame();
I played around with your code a bit on codepen. Though your question is
a bit vague, but I suspect that the issue you are having is that you are doing:
buttonStart = addEventListener("click", startGame);
buttonReset = addEventListener("click", startAgain);
Instead of
buttonStart.addEventListener("click", startGame);
buttonReset.addEventListener("click", startAgain);
Explanation: You are supposed to apply event listeners to buttonStart and buttonReset and not equate it to them.
Related
I'm trying to get to grips with javascript, and have followed a tutorial for a simple image slider. I'm trying to add to it and have the background fade to different colours as the slides move. I've managed to figure it out with the right and left arrows (not sure on best practise), but I can't seem to get it right when selecting the indicators. Can anyone advise on a solution?
Thanks in advance.
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
var background = 1;
function indicatorBg(val){
var background = val;
changeBg();
}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background <= 1) {
return false;
} else {
background--;
}
changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background >= 4) {
return false;
} else {
background++;
}
changeBg();
});
function changeBg (){
if (background == 1) {
document.getElementById("carousel__track").className = 'slide-1';
} else if (background == 2) {
document.getElementById("carousel__track").className = 'slide-2';
} else if (background == 3) {
document.getElementById("carousel__track").className = 'slide-3';
} else if (background == 4) {
document.getElementById("carousel__track").className = 'slide-4';
}
}
window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" onclick="indicatorBg(this.value)" class="selected"></li>
<li value="2" onclick="indicatorBg(this.value)"></li>
<li value="3" onclick="indicatorBg(this.value)"></li>
<li value="4" onclick="indicatorBg(this.value)"></li>
</ol>
</div>
</div>
</section>
You forgot to change the background inside the click event handler of the indicators.
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
background = index + 1;
changeBg();
});
});
As far as best practice goes, I typically use class names for CSS and IDs for JavaScript. Personally, I wouldn't recommend you worry about best practices at this stage, but instead, focus on getting the code working and understanding what's going on line-by-line.
There is a lot of solutions, but the simplest solution that I advice is to use odd and even numbers to style the divs in the carousel (meaning that eg. first is green second is orange third is green and so on...
.carousel__slider div:nth-child(2n) /*Selects even numbered elements*/
.carousel__slider div:nth-child(2n+1) /*Selects odd numbered elements*/
Check out the snippet
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
//var background = 1;
//function indicatorBg(val){
// var background = val;
// changeBg();
//}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background <= 1) {
// return false;
// } else {
// background--;
// }
// changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background >= 4) {
// return false;
// } else {
// background++;
// }
// changeBg();
});
//function changeBg (){
// if (background == 1) {
// document.getElementById("carousel__track").className = 'slide-1';
// } else if (background == 2) {
// document.getElementById("carousel__track").className = 'slide-2';
// } else if (background == 3) {
// document.getElementById("carousel__track").className = 'slide-3';
// } else if (background == 4) {
// document.getElementById("carousel__track").className = 'slide-4';
// }
//}
//window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
/*.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}*/
.carousel__slider div:nth-child(2n) {
background-color:orange;
}
.carousel__slider div:nth-child(2n+1) {
background-color:green;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" class="selected"></li>
<li value="2" ></li>
<li value="3" ></li>
<li value="4" ></li>
</ol>
</div>
</div>
</section>
Having a bit of problem with something surely most of you will find trivial, but still would appreciate your help. It's our favorite Rock Papaer Scissors game:
var user = document.querySelector(".userchoice");
var computer = document.querySelector(".computerchoice");
var startBtn = document.querySelector(".startBtn");
var result = document.querySelector(".result");
var winStates = ["Rock", "Paper", "Scissors"];
startBtn.addEventListener("click", playGame);
function playGame() {
startBtn.disabled = true;
user.classList.add("count-in");
computer.classList.add("count-in");
}
document.addEventListener("animationend", function () {
user.classList.remove("count-in");
computer.classList.remove("count-in");
startBtn.disabled = false;
var randomU = winStates[Math.floor(Math.random() * 3)];
var randomC = winStates[Math.floor(Math.random() * 3)];
computer.className = "computerchoice " + randomC;
user.className = "userchoice " + randomU;
});
.container {
width: 650px;
margin: 0 auto;
text-align: center;
padding: 25px;
}
.player {
width: 150px;
height: 150px;
margin: 100px 50px;
display: inline-block;
}
.player p {
font-weight: 700;
}
.player div {
width: 100%;
height: 100%;
}
.Rock {
background-image: url(https://placehold.it/100x100?text=Rock);
}
.Paper {
background-image: url(https://placehold.it/100x100?text=Paper);
}
.Scissors {
background-image: url(https://placehold.it/100x100?text=Scissors);
}
.Rock,
.Paper,
.Scissors {
background-size: contain;
background-repeat: no-repeat;
}
.startBtn {
border: none;
padding: 10px 100px;
}
#keyframes count-in {
0% {
transform: translateY(0);
}
60% {
transform: translateY(-100px);
}
100% {
transform: translateY(0);
}
}
.count-in {
animation: 0.7s count-in 3;
}
<div class="container">
<h1>Rock, Paper, Scissors</h1>
<div class="player">
<div class="userchoice Rock"></div>
<p>Player 1</p>
</div>
<div class="player">
<div class="computerchoice Rock"></div>
<p>Computer</p>
</div>
<div class="result"></div>
<button class="startBtn">Play</button>
</div>
<script src="app.js"></script>
The problem gets when Math.random is executed, it seems like it is being triggered two times and getting two values out of the winStates array. Naturaly it should pick one value and concat it with the css class already defined
The count-in class is added to two elements so the animationend event listener will fire twice.
Since the animations run concurrently, and therefore end at the same moment, you should be able to get away with binding the event to a single element, userchoice or computerchoice by using...
document.querySelector('.userchoice').addEventListener("animationend", ...
var user = document.querySelector(".userchoice");
var computer = document.querySelector(".computerchoice");
var startBtn = document.querySelector(".startBtn");
var result = document.querySelector(".result");
var winStates = ["Rock", "Paper", "Scissors"];
startBtn.addEventListener("click", playGame);
function playGame() {
startBtn.disabled = true;
user.classList.add("count-in");
computer.classList.add("count-in");
}
document.querySelector('.userchoice').addEventListener("animationend", function () {
console.log('animationend event');
user.classList.remove("count-in");
computer.classList.remove("count-in");
startBtn.disabled = false;
var randomU = winStates[Math.floor(Math.random() * 3)];
var randomC = winStates[Math.floor(Math.random() * 3)];
computer.className = "computerchoice " + randomC;
user.className = "userchoice " + randomU;
});
.container {
width: 650px;
margin: 0 auto;
text-align: center;
padding: 25px;
}
.player {
width: 150px;
height: 150px;
margin: 100px 50px;
display: inline-block;
}
.player p {
font-weight: 700;
}
.player div {
width: 100%;
height: 100%;
}
.Rock {
background-image: url(https://placehold.it/100x100?text=Rock);
}
.Paper {
background-image: url(https://placehold.it/100x100?text=Paper);
}
.Scissors {
background-image: url(https://placehold.it/100x100?text=Scissors);
}
.Rock,
.Paper,
.Scissors {
background-size: contain;
background-repeat: no-repeat;
}
.startBtn {
border: none;
padding: 10px 100px;
}
#keyframes count-in {
0% {
transform: translateY(0);
}
60% {
transform: translateY(-100px);
}
100% {
transform: translateY(0);
}
}
.count-in {
animation: 0.7s count-in 3;
}
<div class="container">
<h1>Rock, Paper, Scissors</h1>
<div class="player">
<div class="userchoice Rock"></div>
<p>Player 1</p>
</div>
<div class="player">
<div class="computerchoice Rock"></div>
<p>Computer</p>
</div>
<div class="result"></div>
<button class="startBtn">Play</button>
</div>
<script src="app.js"></script>
I'm working on a simple card stack which rotates when clicked, my problem is I cant select a specific card and send it to the front and arrange again the cards according to number. I change the codes but luck, I consumed half a day to make it works, still not working.
I hope you understand me.
Thanks
here is a sample code.
codepen
var cardStack = document.getElementsByClassName('card');
var cardArray = []; // Does not change
var stateArray = []; // Changes - keeps track of card state
var prevStateArray = [];
function cardInit() {
for (var i=0; i<cardStack.length; i++) {
var cNum = i + 1;
var cName = 'card' + cNum.toString();
cardStack[i].classList.add(cName);
cardArray.push(cNum);
stateArray = cardArray;
};
};
function stackRefresh() {
prevStateArray = stateArray.slice(0);
stateArray.unshift(stateArray.pop());
}
function nextCard() {
stackRefresh();
for (var i=0; i<cardStack.length; i++) {
var cName = 'card' + prevStateArray[i].toString();
var cNameNew = 'card' + stateArray[i].toString();
cardStack[i].classList.remove(cName);
cardStack[i].classList.add(cNameNew);
};
}
cardInit();
body {
background-color: #2a2a2a;
}
.card {
width: 200px;
height: 320px;
background-color: #fff;
box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.4);
border-radius: 5px;
display: inline-block;
position: absolute;
transform-origin: 0% 50%;
transition: all 1s ease;
}
.card-stack {
display: inline-block;
text-align: center;
position: relative;
left: 50%;
transform: translateX(-100px);
}
.card1 {
z-index: 1000;
left: 0;
}
.card2 {
z-index: 800;
transform: scale(0.99);
filter: brightness(0.9);
left: 20px;
}
.card3 {
z-index: 600;
transform: scale(0.98);
filter: brightness(0.8);
left: 40px;
}
.card4 {
z-index: 400;
transform: scale(0.97);
filter: brightness(0.7);
left: 60px;
animation-name: remove;
animation-duration: 1s;
}
#keyframes remove {
0% {transform: translateX(0px); opacity: 1};
50% {transform: translateX(-80px); opacity: 0};
51% {transform: translateX(10px) scale(0.97); opacity: 0};
100% {transform: translateX(0px) scale(0.97); opacity: 1;}
}
<div class="card-stack" onclick="nextCard();">
<div class="card">A</div>
<div class="card">B</div>
<div class="card">C</div>
<div class="card">D</div>
</div>
Try this sample
I changed html
<div class="card-stack" onclick="nextCard(event);">
...
And js function
function nextCard(e) {
var clickedCssClass = e.srcElement.classList[1];
if (!clickedCssClass) return;
var match = /(\d+)/.exec(clickedCssClass);
var clickedNumber = match[0];
for(var j = 1; j < clickedNumber ; j++){
stackRefresh();
for (var i=0; i<cardStack.length; i++) {
var cName = 'card' + prevStateArray[i].toString();
var cNameNew = 'card' + stateArray[i].toString();
cardStack[i].classList.remove(cName);
cardStack[i].classList.add(cNameNew);
};
}
}
First include the following statement in head section of the html:
<script src="http://code.jquery.com/jquery-3.2.1.js"></script>
Add then change the following tag
<div class="card-stack" onclick="nextCard();">
To
<div class="card-stack">
Finally, I modified the function cardInit as follow:
function cardInit() {
for (var i=0; i<cardStack.length; i++) {
var cNum = i + 1;
var cName = 'card' + cNum.toString();
cardStack[i].classList.add(cName);
$(cardStack[i]).on("click",function()
{
prevClassName=this.classList[1];
$(".card1").removeClass("card1").addClass(prevClassName);
this.className=this.className.replace(prevClassName,"card1");
});
cardArray.push(cNum);
stateArray = cardArray;
};
};
did you mean this?
I have added a moveTop function like
function moveTop() {
event.preventDefault();
event.stopPropagation();
var index = Array.prototype.slice.call(event.target.parentNode.querySelectorAll('.card')).indexOf(event.target)
var temp = stateArray[index];
prevStateArray = stateArray.slice(0);
stateArray.splice(index, 1);
stateArray.unshift(temp);
refreshCards();
}
var cardStack = document.getElementsByClassName('card');
var cardArray = []; // Does not change
var stateArray = []; // Changes - keeps track of card state
var prevStateArray = [];
function cardInit() {
for (var i = 0; i < cardStack.length; i++) {
var cNum = i + 1;
var cName = 'card' + cNum.toString();
cardStack[i].classList.add(cName);
cardArray.push(cNum);
stateArray = cardArray;
};
};
function stackRefresh() {
prevStateArray = stateArray.slice(0);
stateArray.unshift(stateArray.pop());
}
function nextCard() {
stackRefresh();
refreshCards();
}
function refreshCards() {
for (var i = 0; i < cardStack.length; i++) {
var cName = 'card' + prevStateArray[i].toString();
var cNameNew = 'card' + stateArray[i].toString();
cardStack[i].classList.remove(cName);
cardStack[i].classList.add(cNameNew);
};
}
function moveTop() {
event.preventDefault();
event.stopPropagation();
var index = Array.prototype.slice.call(event.target.parentNode.querySelectorAll('.card')).indexOf(event.target)
var temp = stateArray[index];
prevStateArray = stateArray.slice(0);
stateArray.splice(index, 1);
stateArray.unshift(temp);
refreshCards();
}
cardInit();
body {
background-color: #2a2a2a;
}
.card {
width: 200px;
height: 320px;
background-color: #fff;
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
border-radius: 5px;
display: inline-block;
position: absolute;
transform-origin: 0% 50%;
transition: all 1s ease;
text-align: right;
}
.card-stack {
display: inline-block;
text-align: center;
position: relative;
left: 50%;
transform: translateX(-100px);
}
.card1 {
z-index: 1000;
left: 0;
}
.card2 {
z-index: 800;
transform: scale(0.99);
filter: brightness(0.9);
left: 20px;
}
.card3 {
z-index: 600;
transform: scale(0.98);
filter: brightness(0.8);
left: 40px;
}
.card4 {
z-index: 400;
transform: scale(0.97);
filter: brightness(0.7);
left: 60px;
animation-name: remove;
animation-duration: 1s;
}
#keyframes remove {
0% {
transform: translateX(0px);
opacity: 1
}
;
50% {
transform: translateX(-80px);
opacity: 0
}
;
51% {
transform: translateX(10px) scale(0.97);
opacity: 0
}
;
100% {
transform: translateX(0px) scale(0.97);
opacity: 1;
}
}
<div class="card-stack" onclick="nextCard();">
<div class="card" onclick="moveTop()">A</div>
<div class="card" onclick="moveTop()">B</div>
<div class="card" onclick="moveTop()">C</div>
<div class="card" onclick="moveTop()">D</div>
</div>
The problem you are having is that you don't know which card was clicked. My guess is to pass the event when calling nextCard():
onclick="nextCard(event)"
And within the function:
function nextCard(event) {
// detect which card was picked
console.log(event.target);
// logic to bring picked card to the top
...
}
I've done a research on this question and found some solutions. However, not every one of them worked. As I understand, async false makes a UI block, which shouldn't be. I could use an overlay until ajax request is completed and on the request success, hide the overlay.
That was my try using a callback argument in the getNewQuote() function (only a small snippet of it):
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
callback();
return quote;
}, 4000);
};
getNewQuote(function() {
console.log("DONE");
var getRandomColor = function() {
var colors = [
"#ff9966",
"#7f00ff",
"#396afc",
"#0cebeb",
"#06beb6",
"#642b73",
"#36d1dc",
"#cb356b",
"#3a1c71",
"#ef3b36",
"#159957",
"#000046",
"#007991",
"#56ccf2",
"#f2994a",
"#e44d26",
"#4ac29a",
"#f7971e",
"#34e89e",
"#6190e8",
"#3494e6",
"#ee0979"
],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t, qt) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + qt.text + '" ';
twitter += qt.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += qt.author;
tumblr += "&content=";
tumblr += qt.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>")
.prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, qt.text);
$t.find(".quote-author").html("- " + qt.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append(
"<style id='modStyle'>#new-quote:before {background:" + newColor + ";}</style>"
);
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";}");
}
};
var getQuote = function() {
var nq, nc, nh = 0;
nq = getNewQuote();
nc = getRandomColor();
nh = calcNewHeight(nq);
$(".quote-container").children().css("opacity", 0);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh,
}, {
duration: 1000,
queue: false
});
$(".quote-container").animate({
padding: "2.5em"
}, {
duration: 1000,
queue: false
});
$("#new-quote").animate({
padding: "2.5em .75em"
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), nq);
$(".quote-container").children().fadeTo(750, 1);
};
$("#new-quote").on("click", getQuote);
$(".quote-container, #new-quote").css({
visibility: "visible",
height: 0
});
$("#new-quote").css("padding", "0 .75em");
getQuote();
});
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
background: #333;
color: #333;
font-family: sans-serif;
}
.v-wrap {
height: 100%;
text-align: center;
}
.v-wrap:before {
content: "";
display: inline-block;
vertical-align: middle;
width: 0;
height: 100%;
}
.quote-container {
width: 31.25rem;
background: #fff;
margin: 0;
display: inline-block;
vertical-align: middle;
border-radius: 0.1875rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
visibility: hidden;
padding: 0 2.5rem;
}
.quote-text {
font-size: 1.625rem;
}
.quote-text i {
margin-right: 0.6rem;
}
.quote-text p {
display: inline;
}
.quote-author {
font-size: 1rem;
margin: 0 0.4rem 2rem 0;
text-align: right;
}
.button {
padding: 0.75rem;
text-align: center;
font-size: 1rem;
color: #fff;
border-radius: .1875rem;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.button:not(#new-quote):hover {
opacity: .8 !important;
}
.button:not(#new-quote) {
min-width: 1rem;
min-height: 1rem;
}
.button i {
vertical-align: middle;
}
#new-quote {
white-space: nowrap;
writing-mode: vertical-lr;
height: 50%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
vertical-align: middle;
background: #fff !important;
margin: 0;
position: relative;
right: 0.25625rem;
color: #333;
visibility: hidden;
}
#new-quote:before {
content: "";
position: absolute;
height: 100%;
width: 0.0625rem;
bottom: 0;
left: 0;
visibility: hidden;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transition: all .3s ease-in-out;
transition: all .3s ease-in-out;
}
#new-quote:hover:before {
visibility: visible;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
footer {
font-size: 0.85rem;
margin-bottom: 1rem;
}
footer a {
text-decoration: none;
color: #fff;
position: relative;
}
footer a:before {
content: "";
position: absolute;
width: 100%;
height: .0625rem;
bottom: 0;
left: 0;
background: #fff;
visibility: hidden;
-webkit-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: all .3s ease-in-out 0s;
transition: all .3s ease-in-out 0s;
}
footer a:hover:before {
visibility: visible;
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="v-wrap">
<div class="quote-container" style="">
<div class="quote-text">
</div>
<div class="quote-author"></div>
<a id="tweet-quote" class="button"><i class="fa fa-twitter"></i></a>
<a id="tumblr-quote" class="button"><i class="fa fa-tumblr"></i></a>
</div>
<div id="new-quote" class="button">New quote</div>
<footer>
Created by LukasLSC
</footer>
</div>
Code output:
As you can see, ajax wasn't success
Uncaught TypeError: callback is not a function and Uncaught TypeError: Cannot read property 'text' of undefined (only in the stack snippet).
I found out this error disappears if I remove the getQuote(); function call. However, I need to call it, overwise, my project won't work. I also tried to use return $.ajax but there was a return quote line so I couldn't use it. The full code can be found here on codepen: https://codepen.io/Kestis500/pen/ZvyxKB?editors=0110.
Then I switched to another method using jQuery promises and used information in this thread: https://stackoverflow.com/a/40658281/8889739. Full code: https://codepen.io/Kestis500/pen/qpjxoq?editors=0110.
var MyFirstFunction = function() {
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
return quote;
}, 4000);
};
}
var MySecondFunction = function() {
console.log("DONE");
var getRandomColor = function() {
var colors = [
"#ff9966",
"#7f00ff",
"#396afc",
"#0cebeb",
"#06beb6",
"#642b73",
"#36d1dc",
"#cb356b",
"#3a1c71",
"#ef3b36",
"#159957",
"#000046",
"#007991",
"#56ccf2",
"#f2994a",
"#e44d26",
"#4ac29a",
"#f7971e",
"#34e89e",
"#6190e8",
"#3494e6",
"#ee0979"
],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t, qt) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + qt.text + '" ';
twitter += qt.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += qt.author;
tumblr += "&content=";
tumblr += qt.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>")
.prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, qt.text);
$t.find(".quote-author").html("- " + qt.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append(
"<style id='modStyle'>#new-quote:before {background:" + newColor + ";}</style>"
);
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";}");
}
};
var getQuote = function() {
var nq, nc, nh = 0;
nq = getNewQuote();
nc = getRandomColor();
nh = calcNewHeight(nq);
$(".quote-container").children().css("opacity", 0);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh,
}, {
duration: 1000,
queue: false
});
$(".quote-container").animate({
padding: "2.5em"
}, {
duration: 1000,
queue: false
});
$("#new-quote").animate({
padding: "2.5em .75em"
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), nq);
$(".quote-container").children().fadeTo(750, 1);
};
$("#new-quote").on("click", getQuote);
$(".quote-container, #new-quote").css({
visibility: "visible",
height: 0
});
$("#new-quote").css("padding", "0 .75em");
getQuote();
}
MyFirstFunction().done(MySecondFunction);
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
background: #333;
color: #333;
font-family: sans-serif;
}
.v-wrap {
height: 100%;
text-align: center;
}
.v-wrap:before {
content: "";
display: inline-block;
vertical-align: middle;
width: 0;
height: 100%;
}
.quote-container {
width: 31.25rem;
background: #fff;
margin: 0;
display: inline-block;
vertical-align: middle;
border-radius: 0.1875rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
visibility: hidden;
padding: 0 2.5rem;
}
.quote-text {
font-size: 1.625rem;
}
.quote-text i {
margin-right: 0.6rem;
}
.quote-text p {
display: inline;
}
.quote-author {
font-size: 1rem;
margin: 0 0.4rem 2rem 0;
text-align: right;
}
.button {
padding: 0.75rem;
text-align: center;
font-size: 1rem;
color: #fff;
border-radius: .1875rem;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.button:not(#new-quote):hover {
opacity: .8 !important;
}
.button:not(#new-quote) {
min-width: 1rem;
min-height: 1rem;
}
.button i {
vertical-align: middle;
}
#new-quote {
white-space: nowrap;
writing-mode: vertical-lr;
height: 50%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
vertical-align: middle;
background: #fff !important;
margin: 0;
position: relative;
right: 0.25625rem;
color: #333;
visibility: hidden;
}
#new-quote:before {
content: "";
position: absolute;
height: 100%;
width: 0.0625rem;
bottom: 0;
left: 0;
visibility: hidden;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transition: all .3s ease-in-out;
transition: all .3s ease-in-out;
}
#new-quote:hover:before {
visibility: visible;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
footer {
font-size: 0.85rem;
margin-bottom: 1rem;
}
footer a {
text-decoration: none;
color: #fff;
position: relative;
}
footer a:before {
content: "";
position: absolute;
width: 100%;
height: .0625rem;
bottom: 0;
left: 0;
background: #fff;
visibility: hidden;
-webkit-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: all .3s ease-in-out 0s;
transition: all .3s ease-in-out 0s;
}
footer a:hover:before {
visibility: visible;
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="v-wrap">
<div class="quote-container" style="">
<div class="quote-text">
</div>
<div class="quote-author"></div>
<a id="tweet-quote" class="button"><i class="fa fa-twitter"></i></a>
<a id="tumblr-quote" class="button"><i class="fa fa-tumblr"></i></a>
</div>
<div id="new-quote" class="button">New quote</div>
<footer>
Created by LukasLSC
</footer>
</div>
Code output:
It broke everything, the gray screen is because of the default codepen background
Uncaught TypeError: Cannot read property 'done' of undefined
You're using return from the asynchronous operation's callback. That just sets the return value of that callback (which is ignored in the case of setTimeout's or XHR's callback), it doesn't set the return value of your function.
You can't return the value from your function, which is why you're adding a callback. Instead:
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
callback(quote); // <====
}, 4000);
};
...and use the parameter of the callback, e.g.:
getNewQuote(function(quote) {
// Use quote here...
});
Live Example:
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
callback(quote); // <====
}, 1000);
};
getNewQuote(function(quote) {
console.log("quote:", quote);
});
I have made a slider/seeker out of mousedown and mousemove for my <audio> element. My problem is that as soon as the user leaves the element while still holding their mouse button down, it does not register the mousemove. Here's my code:
/** Variables **/
isPlaying = false;
isBuffering = false;
isScrubbing = false;
isScrubberHolding = false;
tempProgress = 0;
time = playerE.currentTime;
dur = playerE.duration;
/** Binds and Properties **/
player.bind("timeupdate", timeUpdate);
scrubber.bind("mousemove", scrubberGrab);
scrubber.bind("mousedown", scrubberClick);
/** Progress and Buffer **/
function progressWidth(progress) {
var calcProgress = ((progress * 100) + "%");
$(".progress").width(calcProgress);
}
/** Time events **/
function timeUpdate(e) {
/** Update Variables **/
time = playerE.currentTime;
dur = playerE.duration;
/** Update Progress and Buffer **/
if (isScrubbing === false) {
var progress = time / dur;
}
var buffered = playerE.buffered.end(0) / dur;
timeConvert(time);
progressWidth(progress);
}
function setPlayerTime(timeset) {
playerE.currentTime = timeset * dur;
}
function timeConvert(s) {
var h = Math.floor(s / 3600);
s -= h * 3600;
var m = Math.floor(s / 60);
s -= m * 60;
var resultSubstring = ((m < 10 ? '0' + m : m) + ":" + (s < 10 ? '0' + s : s)).substring(0, 5);
$('#playerTime').text(resultSubstring);
}
/** Scrubber **/
$(".player-small").mouseenter(function () {
knob.stop().fadeIn(200);
});
setTimeout(function () {
$(".player-small").mouseleave(function () {
knob.stop().fadeOut(200);
});
}, 3000);
function scrubberClick(e) {
isScrubberHolding = true;
isScrubbing = true;
player.trigger('pause');
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
progressWidth(percent);
tempProgress = percent;
}
$(document).mouseup(function () {
if (isScrubberHolding === true) {
isScrubberHolding = false;
isScrubbing = false;
setPlayerTime(tempProgress)
player.trigger('play');
} else {
isScrubberHolding = false;
}
})
function scrubberGrab(e) {
if (isScrubberHolding === true) {
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
tempProgress = percent;
progressWidth(percent);
setPlayerTime(percent)
} else {}
}
See it in action:
var player = $('audio');
var playerE = $('audio')[0];
var playerE = $('audio').get(0);
var canvasviz = $('canvas');
var playbutton = $("#playButton");
var buffering = $("#buffering");
var scrubber = $(".scrubber-con");
var progress = $(".progress");
var buffered = $(".buffered");
var knob = $(".knob");
var analyser = $("#analyzer");
var currentAlbum = "";
var countElement = $('#playlistCount');
var titleElement = $('#trackTitle');
/** Variables **/
isPlaying = false;
isBuffering = false;
isScrubbing = false;
isScrubberHolding = false;
tempProgress = 0;
time = playerE.currentTime;
dur = playerE.duration;
/** Binds and Properties **/
player.bind("timeupdate", timeUpdate);
scrubber.bind("mousemove", scrubberGrab);
scrubber.bind("mousedown", scrubberClick);
/** Progress and Buffer **/
function progressWidth(progress) {
var calcProgress = ((progress * 100) + "%");
$(".progress").width(calcProgress);
}
/** Time events **/
function timeUpdate(e) {
/** Update Variables **/
time = playerE.currentTime;
dur = playerE.duration;
/** Update Progress and Buffer **/
if (isScrubbing === false) {
var progress = time / dur;
}
var buffered = playerE.buffered.end(0) / dur;
timeConvert(time);
progressWidth(progress);
}
function setPlayerTime(timeset) {
playerE.currentTime = timeset * dur;
}
function timeConvert(s) {
var h = Math.floor(s / 3600);
s -= h * 3600;
var m = Math.floor(s / 60);
s -= m * 60;
var resultSubstring = ((m < 10 ? '0' + m : m) + ":" + (s < 10 ? '0' + s : s)).substring(0, 5);
$('#playerTime').text(resultSubstring);
}
/** Scrubber **/
$(".player-small").mouseenter(function () {
knob.stop().fadeIn(200);
});
setTimeout(function () {
$(".player-small").mouseleave(function () {
knob.stop().fadeOut(200);
});
}, 3000);
function scrubberClick(e) {
isScrubberHolding = true;
isScrubbing = true;
player.trigger('pause');
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
progressWidth(percent);
tempProgress = percent;
}
$(document).mouseup(function () {
if (isScrubberHolding === true) {
isScrubberHolding = false;
isScrubbing = false;
setPlayerTime(tempProgress)
player.trigger('play');
} else {
isScrubberHolding = false;
}
})
function scrubberGrab(e) {
if (isScrubberHolding === true) {
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
tempProgress = percent;
progressWidth(percent);
setPlayerTime(percent)
} else {}
}
.player-small {
height: 55px;
width: 100%;
background: #ff4081;
}
.player-height-anim {}
.player-small .left {
height: 55px;
float: left;
width: 56%;
overflow: hidden;
}
.player-small .right {
height: 40px;
position: relative;
top: 8px;
float: right;
width: calc(44% - 2px);
overflow: hidden;
border-left: solid 2px rgba(0, 0, 0, .05);
}
.transport {
overflow: auto;
}
.play-button-con {
height: 55px;
width: 55px;
float: left;
overflow: hidden;
}
#buffering {
height: 55px;
width: 55px;
animation: rotating 900ms ease infinite;
background-image: url(img/player-buffering.svg);
background-size: contain;
display: none;
}
#-webkit-keyframes rotating {
from {
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#keyframes rotating {
from {
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotating {
-webkit-animation: rotating 2s linear infinite;
-moz-animation: rotating 2s linear infinite;
-ms-animation: rotating 2s linear infinite;
-o-animation: rotating 2s linear infinite;
animation: rotating 2s linear infinite;
}
#playButton {
width: 55px;
height: 55px;
font-size: 18px;
text-align: center;
background-image: url(img/player-play.svg);
background-size: contain;
image-rendering: crisp-edges;
-webkit-image-rendering: crisp-edges;
}
.playFailed {
pointer-events: none;
}
.next-button-con {
height: 55px;
width: 55px;
float: left;
}
#nextButton {
width: 55px;
height: 55px;
text-align: center;
font-size: 11px;
background-image: url(img/player-next.svg);
background-size: contain;
}
.scrubber-con {
margin: auto;
margin-top: 12px;
height: 30px;
width: calc(100% - 40px);
overflow: visible;
cursor: pointer;
}
.scrubber-container {
float: left;
height: 55px;
width: calc(100% - 154px);
overflow: hidden;
}
.scrubber {
margin: auto;
height: 5px;
background: rgba(0, 0, 0, .04);
position: relative;
top: 13px;
}
.scrubber .knob {
float: right;
height: 13px;
width: 13px;
position: relative;
bottom: 4px;
left: 5px;
background: white;
border-radius: 50px;
display: none;
}
.scrubber .knob:hover {
cursor: grab;
}
.scrubber .knob:active {
cursor: grabbing;
}
.scrubber .progress {
height: 100%;
float: left;
background: white;
width: 0%;
position: relative;
z-index: 1;
}
.scrubber .buffered {
height: 5px;
position: relative;
width: 0%;
background: rgba(0, 0, 0, .2);
transition: ease 1000ms;
}
.time-con {
float: left;
width: 30px;
height: 55px;
}
.time {
position: relative;
top: 20px;
color: white;
font-size: 13px;
}
.player-small .button {
color: white;
float: left;
cursor: pointer;
}
.player-small .button:hover {
background: rgba(0, 0, 0, .12);
}
.analyzer-con {
float: left;
position: relative;
margin-left: 235px;
width: calc(100% - 650px);
height: 60px;
}
#analyzer {
width: 100%;
height: 45px;
margin-top: 8px;
display: none;
}
audio {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="player-small">
<div class="w-ctrl">
<div class="controls">
<div class="left">
<div class="transport">
<div class="play-button-con">
<div class="button playFailed" id="playButton" onclick="togglePlay()">
</div>
<div id="buffering">
</div>
</div>
<div class="next-button-con">
<div class="button" id="nextButton" onclick="next()"></div>
</div>
<div class="scrubber-container" nmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="scrubber-con" nmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="scrubber" draggable="false" nmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="progress" draggable="false" onmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="knob" draggable="false" onmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false"></div>
</div>
<div class="buffered"></div>
</div>
</div>
</div>
<div class="time-con">
<div class="time" id="playerTime">0:00</div>
</div>
</div>
</div>
<div class="right">
<audio id="player" src="your track here" controls="controls" preload="none"></audio>
<div class="info">
<div class="count" id="playlistCount">0/0</div>
<div class="title" id="trackTitle">Track title</div>
</div>
</div>
</div>
</div>
</div>
Grab my custom seeker (left) and move your mouse off the pink area. Now do the same for the audio element (right) you need a track for it to play in order to be able to move its seeker. See how you can drag it even if your mouse is not inside it?
So how can I get this behaviour for my custom seeker?
Since you are binding the mousemove to scrubber, scrubberGrab() will only run when the mouse is over the scrubber element.
Change
scrubber.bind("mousemove", scrubberGrab);
To
$(document).bind("mousemove", scrubberGrab);
function scrubberGrab(e) {
if (isScrubberHolding === true) {
var x = e.pageX - scrubber.offset().left;
var percent = Math.min(Math.max(x / scrubber.width(), 0), 1.0);
tempProgress = percent;
progressWidth(percent);
setPlayerTime(percent);
} else {}
}