I'm trying to create a slideshow type effect on the homepage of my app, but I am fairly new to JS and am having trouble with some of the intricacies. I have a working slideshow with delays and setTimeouts that looks like this:
<script>
setTimeout(function() {
$("#hero-image-index").fadeOut().empty();
}, 6000);
setTimeout(function() {
$("#slide-1").fadeOut(500);
}, 6000);
$('#slide-2').delay(6000).fadeIn(3000);
setTimeout(function() {
$("#slide-2").fadeOut(500);
}, 12000);
$('#slide-3').delay(12000).fadeIn(3000);
setTimeout(function() {
$("#slide-3").fadeOut(500);
}, 18000);
$('#slide-4').delay(18000).fadeIn(3000);
setTimeout(function() {
$("#slide-4").fadeOut(500);
}, 25000);
$('#slide-5').delay(25000).fadeIn(3000);
setTimeout(function() {
$("#slide-5").fadeOut(500);
}, 32000);
$('#slide-6').delay(32000).fadeIn(3000);
setTimeout(function() {
$("#slide-6").fadeOut(500);
}, 39000);
$('#slide-7').delay(39000).fadeIn(3000);
$('#hero-image-index-2').delay(39000).fadeIn(3000);
</script>
However, now the client wants a navigation so the user can go from slide to slide at will, which I have set up using ionicons on each "slide". Here's a sample "slide":
<div class="slide text-center" id="slide-1">
<h1 style="margin: 75px 0 40px 0; font-size: 52px; color: white; font-weight: bolder">Genetic Golf</h1>
<h2 style="color: white">We don't guess, we test to find what works best for you!</h2>
<div class="index-icon-box" style="color: white">
<i class="icon go-to-7 ion-chevron-left"></i>
<i class="icon go-to-1 ion-android-radio-button-on"></i>
<i class="icon go-to-2 ion-android-radio-button-off"></i>
<i class="icon go-to-3 ion-android-radio-button-off"></i>
<i class="icon go-to-4 ion-android-radio-button-off"></i>
<i class="icon go-to-5 ion-android-radio-button-off"></i>
<i class="icon go-to-6 ion-android-radio-button-off"></i>
<i class="icon go-to-7 ion-android-radio-button-off"></i>
<i class="icon go-to-2 ion-chevron-right"></i>
</div> <!-- index icon box -->
</div> <!-- slide 1 -->
I was hoping to do something with the JS like "if user doesn't click inside .index-icon-box then run the js as I already have it, but if they click on an .icon then do something like this:
<script>
$(document).ready(function() {
$(".go-to-1").click(function(){
$("#slide-1").show();
$("#slide-2").hide();
$("#slide-3").hide();
$("#slide-4").hide();
$("#slide-5").hide();
$("#slide-6").hide();
$("#slide-7").hide();
});
$(".go-to-2").click(function(){
$("#slide-1").hide();
$("#slide-2").show();
$("#slide-3").hide();
$("#slide-4").hide();
$("#slide-5").hide();
$("#slide-6").hide();
$("#slide-7").hide();
});
};
</script>
However, any way I attempt this just ends up breaking the part I do have working. Can any js-wizards straighten me out?
If your intent on doing this yourself without using a library, you might want to try the following.
First consider putting your slides together in a container, and overlaying
the icons to select the slide over them. Then keep track of the images using the indexes of both the slides and the containers. This provides for an easily edited slideshow setup.
A simple example is shown below, this should be in the neighborhood of what you are looking for.
jQuery(document).ready(function($) {
// Hides all images except for one, the one is given by an
// index. Also updates the controller.
function showSlide(index) {
$('.slides .slide').each(function(i) {
if (i == index) {
$(this).fadeIn(500);
} else {
$(this).fadeOut(500);
}
});
var spans = $('.controller span').removeClass('active');
spans.eq(index).addClass('active');
}
// Show only the first element and set an interval to
// continue to cycle through elements.
var index = 0;
showSlide(index);
var intervalFunc = function() {
index = index >= $('.slides .slide').length ? 0 : index + 1;
showSlide(index);
};
var interval = setInterval(intervalFunc, 6000);
// Handle clicks which will reset the interval to each time.
$('.controller span').click(function() {
// Set the current picture.
index = $(this).index();
showSlide(index);
// Reset the interval
clearInterval(interval);
interval = setInterval(intervalFunc, 6000);
});
});
.slideshow-contianer {
position: relative;
/* For Deomnstation purposes*/
width: 400px;
height: 200px;
margin: 2em;
}
.slides img {
width: 100%;
height: auto;
position: absolute;
left: 0;
top: 0;
}
.controller {
position: absolute;
bottom: 10px;
left: 0;
width: 100%;
-webkit-display: flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
}
.controller span {
width: 4px;
height: 4px;
border-radius: 50%;
border: 2px solid #ccc;
cursor: pointer;
margin: 10px;
/* Transition is a personal asthetic. */
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
.controller span.active,
.controller span:hover {
-webkit-transform: scale(1.5);
transform: scale(1.5);
background-color: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<div class="slideshow-contianer">
<div class="slides">
<img class="slide" src="https://unsplash.it/400/200?random" />
<img class="slide" src="https://unsplash.it/400/200?random" />
<img class="slide" src="https://unsplash.it/400/200?random" />
<img class="slide" src="https://unsplash.it/400/200?random" />
<img class="slide" src="https://unsplash.it/400/200?random" />
</div>
<div class="controller">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
Related
Ok... I'm struggling here. I'm particularly new at JavaScript and am trying to fetch data from the Art Institute of Chicago's API. My goal is to display the information for a particular piece of art in a modal window after clicking on the relevant artwork. I've gotten the CSS and HTML down, I think. Everything displays properly as far as the images and titles and such. However, when I click the image to open the modal, all I can get to display is the Art itself.
I've found a similar question on here and tried some of its code, but their solution didn't quite get me to where I need to be.
Here's my HTML:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="index.css">
<script src="index.js" defer></script>
<title>Art Institute of Chicago API</title>
</head>
<body>
<h1>From the Art Institute of Chicago:<br>A Sampling of Monet, Van Gogh, and Hokusai</h1>
<div class="container">
<!-- ARTic Banner -->
<div class="gallery-container w-4 h-3">
<div class="gallery-item">
<div class="image banner" onclick="openInNewTab('https:/\/www.artic.edu');">
<img src="/images/bannerArtIC.jpg"
alt="Art Institute of Chicago banner">
</div>
<div class="text">
The Art Institute of Chicago
</div>
</div>
</div>
<!-- Fig 1 - Monet: Water Lilies -->
<div class="gallery-container w-2 h-3">
<div class="gallery-item">
<div class="image" id="16568">
<img src="images/monetWaterLilies_1933.1157.jpg"
alt="Painting of a pond seen up close spotted with thickly
painted pink and white water lilies and a shadow across the
top third of the picture."
onclick="openModal(event); event.stopPropagation(); getArtwork(this.id, event)">
</div>
<div class="text">
Claude Monet:<br>Water Lilies
</div>
</div>
</div>
<!-- Fig 2 - Van Gogh: Self Portrait -->
<div class="gallery-container w-2 h-6">
<div class="gallery-item">
<div class="image" id="80607">
<img src="images/vanGoghSelfPortrait_1954.326.jpg"
alt="Painting of a red-haired, bearded man with light skin,
painted in short brushstrokes and multicolored dots. The
background is likewise a mass of small, closely spaced colored
dots, these in green, blue, and red-orange."
onclick="openModal(event); event.stopPropagation(); getArtwork(this.id, event)">
</div>
<div class="text">
Vincent Van Gogh:<br>Self Portrait
</div>
</div>
</div>
<!-- Fig 3 - Monet: Water Lily Pond -->
<div class="gallery-container w-4 h-3">
<div class="gallery-item">
<div class="image" id="87088">
<img src="images/monetWaterLilyPond_1933.441.jpg"
alt="Painting of a small pond dense with pink water lilies,
their roots visible through the water, a railed footbridge
arching over the pond and lush, dark green folliage surrounding
it."
onclick="openModal(event); event.stopPropagation(); getArtwork(this.id, event)">
</div>
<div class="text">
Claude Monet:<br>Water Lily Pond
</div>
</div>
</div>
<!-- Fig 4 - Van Gogh: The Poet's Garden -->
<div class="gallery-container w-2 h-3">
<div class="gallery-item">
<div class="image" id="14586">
<img src="images/vanGoghThePoetsGarden_1933.433.jpg"
alt="Lush tall grasses with small white flowers foreground a
grove of bushy trees of varying types and heights, their leaves
ranging from deep green to golden. Beneath a dense and heavy
yellow sky, a small blue triangle suggesting a mountain peak
crests above the treeline at far left."
onclick="openModal(event); event.stopPropagation(); getArtwork(this.id, event)">
</div>
<div class="text">
Vincent Van Gogh:<br>The Poet's Garden
</div>
</div>
</div>
<!-- Fig 5 - Hokusai: Under the Wave Off Kanagawa -->
<div class="gallery-container w-4 h-3">
<div class="gallery-item">
<div class="image" id="24645">
<img src="images/hokusaiUnderTheWaveOffKanagawa_1925.3245.jpg"
alt="A crashing wave looms over two small ships, Mount Fuji
in the background."
onclick="openModal(event); event.stopPropagation(); getArtwork(this.id, event)">
</div>
<div class="text">
Katsushika Hokusai:<br>Under the Wave Off Kanagawa
</div>
</div>
</div>
<!-- Fig 6 - Hokusai: Chrysanthemums and Bee -->
<div class="gallery-container w-2 h-6">
<div class="gallery-item">
<div class="image" id="25110">
<img src="images/hokusaiChrysanthemumsAndBee_1925.3373.jpg"
alt="A color woodblock print of pink, orange and yellow
chrysanthemums. In the upper rihgt a tiny bee flies above the
flowers. Signature and seals in the lower left corner."
onclick="openModal(event); event.stopPropagation(); getArtwork(this.id, event)">
</div>
<div class="text">
Katsushika Hokusai:<br>Chrysanthemums and Bee
</div>
</div>
</div>
<!-- div for modal -->
<div id="myModal" class="modal">
<span class="closebtn" onclick="closeModal(event)">×</span>
<img class="modal-content" id="expandedImg">
<div id="caption">
</div>
</div>
</div>
</body>
</html>
And here's my JS (with additions from answers found on stack overflow):
// function to open the AIC homepage in new tab
function openInNewTab(url) {
var win = window.open(url, 'blank');
win.focus();
}
// function to open each image as a modal once it is clicked
function openModal(event) {
var modal = document.getElementById("myModal");
modal.style.display = "block";
document.getElementById("expandedImg").setAttribute('src', event.target.getAttribute("src"));
}
// function to close the image modal
function closeModal(event) {
const modal = document.getElementById("myModal");
modal.style.display = "none";
}
// // // // // // // // // // // // // // // // // // // // // // // // // // //
// //
// functions and methods to pull data for art pieces //
// let art;
let showArtInfo;
/**
* #param art_index
* #param info_index
*
* function to pull the info on the art from AIC
*/
async function clickedEvent(art_index, info_index) { // is the info_index actually necessary here if it's not used again? is that for the API's benefit?
// Get id of artwork
let elem = document.getElementsByTagName('img')[art_index];
let id = elem.attributes[2].value;
let headers = new Headers([
['Content-Type', 'application/json'],
['Accept', 'application/json']
]);
let request = new Request(
`https://api.artic.edu/api/v1/artworks${id}?fields=id,title,artist_display,date_display`, {
method: 'GET',
headers: headers
});
let result = await fetch(request);
let response = await result.json();
console.log(response)
if (showArtInfo) {
stopShow();
} else {
let title = response.data.title;
let artist = response.data['artist_display'];
let date = response.data['date_display'];
let div = document.getElementById('caption');
div.innerHTML = `<br> Title: ${title}<br> Artist: ${artist}<br> Date Display: ${date}`;
elem.parentElement.appendChild(div);
};
}
/**
* #param id // art id
* #param event // 'onClick' event
*
* function to display the pulled info of the artpiece when clicked on
*/
function getArtwork(id, event) {
switch(id) {
case '16568': { // Water Lilies by Claude Monet, id# 16568
event.stopPropagation();
clickedEvent(0, 0)
break;
}
case '80607': { // Self Portrait by Vincent Van Gogh, id# 80607
event.stopPropagation();
clickedEvent(1, 0)
break;
}
case '87088': { // Water Lily Pond by Claude Monet, id# 87088
event.stopPropagation();
clickedEvent(2, 0)
break;
}
case '14586': { // The Poet's Garden by Vincent Van Gogh, id# 14586
event.stopPropagation();
clickedEvent(3, 0)
break;
}
case '24645': { // Under the Wave Off Kanagawa by Katsushika Hokusai, id# 24645
event.stopPropagation();
clickedEvent(4, 0)
break;
}
case '25110': { // Chrysanthemums and Bee by Katsushika Hokusai, id# 25110
event.stopPropagation();
clickedEvent(5, 0)
break;
}
}
}
And lastly, my CSS (in case you want to fully replicate my page to see what I'm going for in real time):
body {
margin: 50px;
padding: 0;
text-align: center;
background-color: #292C33;
}
h1 {
margin-bottom: 50px;
padding: 20px;
outline: 5px solid white;
color: white;
border-radius: 5px;
background-color: #b60235;
}
.container {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-auto-rows: 100px 100px;
grid-gap: 18px;
grid-auto-flow: dense;
}
.gallery-item {
width: 100%;
height: 100%;
position: relative;
}
.gallery-item .image {
width: 100%;
height: 100%;
overflow: hidden;
border: 2px solid white;
border-radius: 5px;
}
.gallery-item .image img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: 50% 50%;
cursor: pointer;
transition: .66s ease-in-out;
border-radius: 5px;
}
.gallery-item:hover .image img {
transform: scale(1.12);
}
.gallery-item .text {
opacity: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 30px;
pointer-events: none;
z-index: 4;
-webkit-backdrop-filter: blur(22px) saturate(1.5);
backdrop-filter: blur(22px) saturate(1.5);
}
.gallery-item:hover .text {
opacity: 1;
animation: move-up .33s linear;
padding: 1em;
width: 77.5%;
outline: 2px solid #b60235;
border-radius: 5px;
}
#keyframes move-up {
0% {top:77.5%}
50% {top:63.75%}
100% {top:50%}
}
.w-1 {
grid-column: span 1;
}
.w-2 {
grid-column: span 2;
}
.w-3 {
grid-column: span 3;
}
.w-4 {
grid-column: span 4;
}
.w-5 {
grid-column: span 5;
}
.w-6 {
grid-column: span 6;
}
.h-1 {
grid-row: span 1;
}
.h-2 {
grid-row: span 2;
}
.h-3 {
grid-row: span 3;
}
.h-4 {
grid-row: span 4;
}
.h-5 {
grid-row: span 5;
}
.h-6 {
grid-row: span 6;
}
#media screen and (max-width: 850px) {
.container {
grid-template-columns: repeat(3,1fr);
}
.w-1, .w-2, .w-3, .w-4, .w-5, .w-6 {
grid-column: span 3;
}
}
/* -------------------------------------------------------------------------- */
.closebtn {
position: absolute;
top: 15px;
right: 35px;
color: #f1f1f1;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
}
.closebtn:hover, .closebtn:focus {
color: #bbb;
text-decoration: none;
cursor: pointer;
}
.modal {
display: none;
position: fixed;
z-index: 10;
padding-top: 5%;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.9);
}
.modal-content {
/* leave it centered and just display info underneath -- maybe?
margin-left: 5%;
display: block; */
width: 80%;
max-width: 750px;
max-height: 650px;
object-fit: contain;
}
#caption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
.modal-content {
animation-name: zoom;
animation-duration: 0.5s;
}
#keyframes zoom {
from {
transform: scale(0)
} to {
transform: scale(1)
}
}
So, hopefully you'll see that nearly every thing else I'm programming functions as it should, but I can't quite get the data pulled from the API and displaying inside of the modal when opened. I believe my problem rests fully in the JS code and how I'm attempting to fetch and display the data from the API. Also, I have a div with an id of 'info' placed inside of the 'modal' div in my HTML, but I've got a sneaking suspicion that I'm not using that properly either. Let me know if there's any additional information required on my end.
I have a website with a few icons/buttons that trigger a simple menu when you click them. However, I need to be able to load more data, with more of these buttons, and since the existing buttons are initialized with a function, using jquery onclick, i figured I would just re-run that function whenever the number of buttons are changed.
I expected the existing onclick functions to be simply overwritten, with the same content as before. Even though it is not optimal code, I expected it to work fast, and simple.
But then I discovered that running the onclick initializing function simply toggles the working elements. In other words the newly generated elements now works, but the existing ones does not. Calling the function a third time toggles them all back, meaning the original works, but not the new. This baffles me.
I made a JSFiddle, showing what I mean:
To see the different scenarios of original state, added button and toggled, and thirdly toggled back, just comment out lines in the document ready function in javascript
$(document).ready(function() {
initContextMenuButtons(); //initializes cog-icon buttons
addThirdButton(); //adds a third button, and calls init again, toggling all
initContextMenuButtons(); //toggles back
});
HTML:
<div id="wrapper">
<div class="relative-wrapper">
<i class="fa fa-2x fa-cog context-menu-button"></i>
<div class="tooltip-wrapper">
<div class="tooltip">
<div class="edit-button"><i class="fa fa-fw fa-pencil-square-o" aria-hidden="true"></i>Edit button</div>
<div class="delete-button"><i class="fa fa-fw fa-trash-o" aria-hidden="true"></i> Delete button</div>
<div class="close-button"><i class="fa fa-fh fa-times" aria-hidden="true"></i></div>
<div class="tooltip-arrow-wrapper"><b class="tooltip-arrow"></b></div>
</div>
</div>
</div>
<div class="relative-wrapper">
<i class="fa fa-2x fa-cog context-menu-button"></i>
<div class="tooltip-wrapper">
<div class="tooltip">
<div class="edit-button"><i class="fa fa-fw fa-pencil-square-o" aria-hidden="true"></i>Edit button</div>
<div class="delete-button"><i class="fa fa-fw fa-trash-o" aria-hidden="true"></i> Delete button</div>
<div class="close-button"><i class="fa fa-fh fa-times" aria-hidden="true"></i></div>
<div class="tooltip-arrow-wrapper"><b class="tooltip-arrow"></b></div>
</div>
</div>
</div>
</div>
Javascript:
$(document).ready(function() {
initContextMenuButtons();
addThirdButton();
initContextMenuButtons();
});
function initContextMenuButtons() {
$('.context-menu-button').click(function() {
var this_wrapper = $(this).siblings(".tooltip-wrapper").toggle();
$(".tooltip-wrapper").not(this_wrapper).hide();
});
$('.tooltip .close-button').click(function() {
$(this).closest(".tooltip-wrapper").hide();
});
}
function addThirdButton() {
var html = ' <div class="relative-wrapper">' +
'<i class="fa fa-2x fa-cog context-menu-button"></i>' +
'<div class="tooltip-wrapper">' +
'<div class="tooltip">' +
'<div class="edit-button"><i class="fa fa-fw fa-pencil-square-o" aria-hidden="true"></i>Edit button</div>' +
'<div class="delete-button"><i class="fa fa-fw fa-trash-o" aria-hidden="true"></i> Delete button</div>' +
'<div class="close-button"><i class="fa fa-fh fa-times" aria-hidden="true"></i></div>' +
'<div class="tooltip-arrow-wrapper"><b class="tooltip-arrow"></b></div>' +
'</div>' +
'</div>' +
'</div>'
$('#wrapper').append(html);
initContextMenuButtons();
}
CSS:
.relative-wrapper {
position: relative;
}
.tooltip .close-button {
position: absolute;
top: 0px;
right: 1px;
color: #999;
}
.tooltip .close-button:hover {
color: #555;
}
.tooltip-wrapper {
display: none;
position: absolute;
top: -6px;
left: 38px;
z-index: 1;
}
.tooltip {
transition: none 0s ease 0s;
width: 200px;
height: 55px;
background-color: rgb(246, 246, 246);
border: 1px solid #ccc;
border-radius: 4px;
position: relative;
box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 4px 0px;
}
.tooltip .edit-button {
position: absolute;
top: 7px;
left: 8px;
width: 185px;
cursor: pointer;
}
.milestone-tooltip .edit-button:hover {
background-color: #ddd;
}
.tooltip .delete-button {
position: absolute;
top: 28px;
left: 6px;
width: 185px;
cursor: pointer;
}
.tooltip .delete-button:hover {
background-color: #ddd;
}
.tooltip-arrow-wrapper {
height: 24.8px;
width: 16px;
display: block;
transition: none 0s ease 0s;
left: -14px;
top: 11px;
position: absolute;
}
.tooltip-arrow {
height: 10px;
width: 10px;
border-top: 1px solid rgb(187, 187, 187);
border-left: 1px solid rgb(187, 187, 187);
background-color: rgb(246, 246, 246);
transform: translate(8px, 4px) rotate(-45deg);
position: absolute;
}
.context-menu-button {
cursor: pointer;
}
Existing event handlers don't get overwritten. The new event handlers simply stack on top of them. One click now fires the event multiple times.
I'd highly recomment using Event Delegation for the following reasons:
Dynamically created elements will just work. No need to attach new events.
With your current method, hypothetically, if you have 10 elements, that's 10 event handlers. Event delegation allows you to have just 1, whether you have 1 element or 1,000.
It's nearly identical to your existing code. You're simply attaching the event to the document instead of the element itself.
function initContextMenuButtons() {
$(document).on('click', '.context-menu-button', function() {
var this_wrapper = $(this).siblings(".tooltip-wrapper").toggle();
$(".tooltip-wrapper").not(this_wrapper).hide();
});
$(document).on('click', '.tooltip .close-button', function() {
$(this).closest(".tooltip-wrapper").hide();
});
}
initContextMenuButtons() should now only be fired once throughout the life of the page, so be sure to remove the call from your addThirdButton() method, as well as the second call from your $(document).ready( ... ).
Your event listeners add up. To make multiple initializations work, you can remove existing ones first.
$('.context-menu-button').off().click(function() {
// ...
$('.tooltip .close-button').off().click(function() {
In general, you can also use namespaces to prevent accidentally removing other event listeners.
$('.context-menu-button').off('.init').on('click.init', function() {
// ...
$('.tooltip .close-button').off('.init').on('click.init', function() {
SOLUTION:
Remove initContextMenuButtons() function and its references. Add the following code.
$('#wrapper').on('click', '.context-menu-button', function () {
var this_wrapper = $(this).siblings(".tooltip-wrapper").toggle();
$(".tooltip-wrapper").not(this_wrapper).hide();
});
$('#wrapper').on('click', '.tooltip .close-button', function() {
$(this).closest(".tooltip-wrapper").hide();
});
I need help with loading a URL one time into a HTML5 audio player and then be able to click on an elements to do additional controls.
This is the code so far:
<div class="primary">
<article id="145">
<div class="loaddata" data-rel="http://www.jplayer.org/audio/mp3/Miaow-01-Tempered-song.mp3" onclick="setTimeout(function() { document.getElementById('145').classList.add('dataloaded'); }, 1)"> Load "Song1" </div>
</article>
<article id="139">
<div class="loaddata" data-rel="http://feeds.soundcloud.com/stream/327164631-scott-johnson-27-tms-1281.mp3" onclick="setTimeout(function() { document.getElementById('139').classList.add('dataloaded'); }, 1)"> Load "Song2" </div>
</article>
<article id="133" class="dataloaded">
<div class="loaddata" data-rel="http://archive.org/download/DTH20170611/DTH20170611.mp3" onclick="setTimeout(function() { document.getElementById('133').classList.add('dataloaded'); }, 1)"> Load "Song3" </div>
</article>
The player:
<div class="audio-player-wrapper">
<div class="mejs__button mejs__group-left">
<div class="rewind-btn">
<button title="Rewind 15 seconds">15</button>
</div>
<div class="playpause-btn">
<button title="Play" class="play" id="ppbtn"></button>
</div>
<div class="forward-btn">
<button title="Forward 15 seconds">15</button>
</div>
</div>
<div class="current-time">00:00</div>
<div class="duration-time">00:00</div>
<div class="mejs__button mobile-mute">
<button class="mobile-mute-btn mobile-mute-off"></button>
</div>
<audio width="100%" height="75px" id="audio-player" controls="controls">
<source id="sourceMp3" src="#" type="audio/mp3">
</audio>
</div>
JS:
$(".loaddata").on("click", function() {
var mp3Url = $(this).data('rel');
$("#audio-player_html5").attr('src', mp3Url);
});
$(".loaddata").click(function(){
$('.dataloaded').removeClass();
$('#ppbtn').click();
});
What the code above does is when a user clicks on loaddata the JS loads the url in data-rel into the src in sourceMP3. Then it scans 'primary' for any class called dataloaded and removes it. One millisecond later, it adds dataloaded to the article ID. Then the player starts playing the loaded URL in jquery $('#ppbtn').click();.
What I'm trying to find is a way to load the URL on the first click then be able to control the play/pause button after the first click. I tried doing .one() on loading the URL once but when all three elements have been clicked once, it won't load the URL in the clicked element and all three elements div.loaddata can control the player.
I guess the easy way of explaining it: remove existing .dataloaded, add URL to player, add .dataloaded to the article that was clicked then be able to click on play/pause button only on the div.loaddata with 'dataloaded'.
New question: is there a way to change a function when you click on an element? Like a new onclick?
I saw this answer this morning (but had a busy day!) .. I created a jsfiddle for playing multiple sounds some time ago but when I re-read the question this evening, it seemed not quite enough to cover what you were trying to do.
I found that there is a library called MediaElement.js available; the source code is outlined extensively in this article and there is a demo also
Alternately there is very good (slightly lengthy!) article about designing a custom audio player by Rose (second name not given) on her website where there is also a demo
Best of all though, a fellow SO-er gives a wonderful answer to a similar question (about a year ago) and there is a jsfiddle provided in that answer (top pick i think..)
the code (hope there's room!):
var audio_player = $("#audio-player");
var play_button = $('#play');
var progress_bar = $("#progressbar");
var time = $("#time");
var mute_button = $('#mute');
var volume_bar = $('#volume');
var more_info = $('#more-info-box');
var info_tray = $("#info-tray");
var player = document.getElementById('player');
var duration = 0;
var volume = 0.75;
player.onloadedmetadata = function() {
duration = player.duration;
progress_bar.progressbar("option", { 'max' : duration });
};
player.load();
player.volume = 0.75;
player.addEventListener("timeupdate", function() {
progress_bar.progressbar('value', player.currentTime);
time.text(getTime(player.currentTime));
}, false);
function getTime(t) {
var m=~~(t/60), s=~~(t % 60);
return (m<10?"0"+m:m)+':'+(s<10?"0"+s:s);
}
function getProgressBarClickInfo(progress_bar, e) {
var offset = progress_bar.position();
var x = e.pageX - offset.left; // or e.offsetX (less support, though)
var y = e.pageY - offset.top; // or e.offsetY
var max = progress_bar.progressbar("option", "max");
var value = x * max / progress_bar.width();
return { x: x, y: y, max: max, value: value };
}
volume_bar.progressbar({
value : player.volume*100,
});
volume_bar.click(function(e) {
var info = getProgressBarClickInfo($(this), e);
volume_bar.progressbar('value', info.value);
player.volume = info.value / info.max;
});
progress_bar.progressbar({
value : player.currentTime,
});
progress_bar.click(function(e) {
var info = getProgressBarClickInfo($(this), e);
player.currentTime = player.duration / info.max * info.value;
});
play_button.click(function() {
player[player.paused ? 'play' : 'pause']();
$(this).toggleClass("fa-play", !player.paused);
$(this).toggleClass("fa-pause", player.paused);
});
mute_button.click(function() {
if (player.volume == 0) {
player.volume = volume;
} else {
volume = player.volume;
player.volume = 0;
}
volume_bar.progressbar('value', player.volume * 100);
$(this).toggleClass("fa-volume-up", player.volume != 0);
$(this).toggleClass("fa-volume-off", player.volume == 0);
});
more_info.click(function() {
audio_player.animate({
height: (audio_player.height() == 50) ? 100 : 50
}, 1000);
});
#audio-player {
height: 50px;
width: 500px;
overflow: hidden;
background-color: #2B2B2B;
color: white;
-webkit-user-select: none; /* webkit (safari, chrome) browsers */
-moz-user-select: none; /* mozilla browsers */
-khtml-user-select: none; /* webkit (konqueror) browsers */
-ms-user-select: none; /* IE10+ */
}
#controls {
height: 50px;
background-color: #808080;
width: 350px;
}
.time {
font-size: 10px;
color: white;
position: relative;
top: 14px;
margin: 5px;
}
.ui-progressbar {
background: #2B2B2B;
}
.ui-progressbar-value {
background: white;
}
#progressbar, #volume {
height: 10px;
display: inline-block;
border-radius: 0px;
border: none;
position: relative;
top: 16px;
}
#progressbar {
width: 150px;
}
#play, #mute {
font-size: 16px;
width: 20px;
position: relative;
top: 17px;
}
#play {
margin-left: 15px;
}
#volume {
width: 50px;
}
#more-info-box {
display: inline-block;
width: 150px;
height: 50px;
position: relative;
left: 350px;
top: -50px;
padding-top: 18px;
text-align: center;
font-family: sans-serif;
font-size: 12px;
color: white;
}
#more-info-box, #more-info-box > span {
cursor: context-menu;
}
#info-tray {
display: inline-block;
color: white;
position: relative;
width: 100%;
top: -65px;
height: 50px;
padding: 5px;
}
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<audio id="player">
<source src="http://www.noiseaddicts.com/samples_1w72b820/2543.mp3" type="audio/mpeg" />
</audio>
<div id="audio-player">
<div id="controls">
<i id="play" class="fa fa-pause"></i>
<span id="start-time" class="time">00:00</span>
<div id="progressbar"></div>
<span id="time" class="time">00:00</span>
<i id="mute" class="fa fa-volume-up"></i>
<div id="volume"></div>
</div>
<div id="more-info-box">
<span id="more-info">MORE INFO</span>
</div>
<div id="info-tray">
Track: <span id="track">Semper Fidelis March</span>
</div>
</div>
Hope one of these solutions helps!
I was able to find a working solution. It's not pretty but it works.
First I had two elements, one that loads the data and other controls the player.
<article id="145">
<div class="loaddata" data-rel="http://www.jplayer.org/audio/mp3/Miaow-01-Tempered-song.mp3" onclick="setTimeout(function() { document.getElementById('145').classList.add('dataloaded');document.getElementById('145').classList.add('dataloaded'); }, 1);"> Load "Song1" </div>
<div class="front-playpause">song loaded</div>
</article>
JS:
$(".loaddata").on("click", function() {
var mp3Url = $(this).data('rel');
$("#audio-player_html5").attr('src', mp3Url);
$('.dataloaded').removeClass();
$('#ppbtn').click();
});
$(".front-playpause").click(function(){
$('#ppbtn').click();
});
CSS:
.front-playpause {display:none}
.dataloaded .front-playpause {display:block}
.dataloaded .loaddata {display:none}
When loaddata is clicked, it adds the class 'dataloadedto the article ID and then the CSS hidesloaddataand then displaysfront-playpause` and that's how I found a work around.
Thanks everyone for the help.
I have a list which serves as a menu. Every time user clicks on one of the elements in the list, I want a more detailed div to slide in from left to right.
So if the user was to click menu item A first, A slides from left to right. If the user then clicks B, A slides out from right to left (disappears off screen) and B slides in.
I searched for this problem and found this post. I incorporated the code from the jsfiddle, but it didn't work. No errors are being shown in the js log in Chrome debugging tool. Nothing happens when I click any item from the menu. What am I doing wrong?
<div class="project">
<ul id="project_menu" class="project_menu">
<li id="menu-php-mysql" data-projectID="php-project">PHP/MySQL</li>
<li id="menu-nodejs" data-projectID="node-project">NodeJS</li>
<!-- more code -->
</ul>
<div class="project-detail">
<div id="php-project">
<i class="ion-ios-close-empty close-icon js-close-icon"></i>
<div classs="project-text">
<!-- data about project -->
</div>
</div>
<div id="node-project">
<i class="ion-ios-close-empty close-icon js-close-icon"></i>
<div classs="project-text">
<!-- data about project -->
</div>
</div>
<!-- and so on.. -->
#php-project {
background-color: #9b59b6;
margin: 30px;
display: none;
}
$(document).ready(function() {
itemsToRender = [];
$('ul#project_menu li').click(function(e) {
menuItemId = (e.currentTarget.id);
$('.common').hide();
$(getProjectId(menuItemId)).css('display', 'inline');
var value = $(getProjectId(menuItemId)).css('right') === '100px' ? '-100px' : '100px';
$(getProjectId(menuItemId)).animate({
right: value
}, 800);
});
});
function getProjectId(menuItemId) {
if (menuItemId.indexOf('php') > 0) {
return '#php-project';
} else if (menuItemId.indexOf('node') > 0) {
return '#node-project';
} else if (menuItemId.indexOf('angular') > 0) {
return '#angular-project';
} else if (menuItemId.indexOf('mean') > 0) {
return '#mean-project';
}
}
Update1: #user5325596 pointed out that my display property for the detail div was set to none, so I fixed that by adding the following:
$(getProjectId(menuItemId)).css('display', 'inline-block');
right after $('.common').hide().
Now, I can see the detail div when I click on the menu item, but it does not animate.
Update2: I have uploaded a jsFiddle, it includes the jquery animation that I am successfully using (fadeIn, which is commented out), as well as the code suggested by elchininet.
Not sure if this is what you need or not
JS Fiddle - updated 2
// initializing
var prevID = '',
divs = $('.sliding-divs');
$("li").on("click", function() {
var theID, theDiv, theDivW, theCenter;
// get the id letter from the li, then pick the corresponding sliding
// div depending on its value.
theID = $(this).attr('id');
theID = theID.replace('li-', '');
theDiv = $('#div-' + theID);
// get the divs width to slide it into the center of the view
theDivW = theDiv.width();
theCenter = $(window).width()/2 - theDivW/2;
// if the user didn't click the link which its slide already
// in the view, this to avoid sliding out and in same div.
if(theID != prevID){
if (prevID == '') {
// if we don't have a previously slided in div, we just slide
// the just click link's div into the view
theDiv.animate({'left': theCenter}, 1000);
} else {
// animated the previous div to the right out of the view, then
// move all divs to their original position out from the left
// this is because if we don't do this, an already slided div
// will later be slided in from right instead in from left
// because we have already changed its position.
// slide the just clicked link's div into the view from left
$('#div-' + prevID).animate({'left': '110%'}, 800);
divs.css({'left':-(theDivW + 100)});
theDiv.animate({'left': theCenter}, 1000);
}
}
// change the value of the id representing previously slided in div
prevID = theID;
});
body {
overflow-x: hidden;
}
ul {
list-style: none;
padding: 0;
}
li {
width: 100px;
height: 25px;
margin: 2px 0;
color: white;
padding: 3px;
text-align: center;
background-color: green;
cursor:pointer;
}
.sliding-divs {
position: absolute;
width: 500px;
line-height: 250px;
background-color: orange;
font-size: 30px;
border: 2px gold solid;
text-align: center;
display: inline-block;
top: 150px;
left: -510px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul>
<li id="li-A">item 1</li>
<li id="li-B">item 2</li>
<li id="li-C">item 3</li>
<li id="li-D">item 4</li>
</ul>
<div class="sliding-divs" id="div-A">
DIV A
</div>
<div class="sliding-divs" id="div-B">
DIV B
</div>
<div class="sliding-divs" id="div-C">
DIV C
</div>
<div class="sliding-divs" id="div-D">
DIV D
</div>
Try with CSS transitions, will save a lot of code. Maybe this is not exactly that you want but I'm sure it'll helps you with your task.
HTML Code
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
</ul>
CSS Code
li{
-webkit-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
}
li.open{
-webkit-transform: translateX(100px);
-moz-transform: translateX(100px);
transform: translateX(100px);
}
jQuery Code
$("li").on("click", function(){
$("li.open").removeClass("open");
$(this).addClass("open");
});
jsfiddle
Here you have a jsfiddle with your code modified and the div animations in css.
jsfiddle with part of your code.
There are some minor mistakes i found on fiddle like , comma between class name. : class="project-container,common"
You are hiding all div with class .common, but not show it after. so its style property get display:none even if you add class open to that div.
Here is my Updated and running code:
$(document).ready(function() {
itemsToRender = [];
$('ul#project_menu li').click(function(e) {
$('.common').hide();
menuItemId = (e.currentTarget.id);
var projectId = getProjectId(menuItemId);
console.log(projectId);
$('.project-container.open').removeClass('open');
$(projectId).addClass('open');
$(projectId).show();
/* $(projectId).fadeIn('slow'); <--- THIS WORKS! But I want the slide effect instead */
});
function getProjectId(menuItemId) {
if (menuItemId.indexOf('php') > 0) {
return '#php-project';
} else if (menuItemId.indexOf('node') > 0) {
return '#node-project';
} else if (menuItemId.indexOf('angular') > 0) {
return '#angular-project';
} else if (menuItemId.indexOf('mean') > 0) {
return '#mean-project';
} else if (menuItemId.indexOf('html5-css3-js') > 0) {
return '#html-css-js-project';
}
}
});
.project-detail {
float: right;
max-width: 50%;
margin-right: 75px;
color: #fff;
}
#php-project {
background-color:#9b59b6;
margin: 30px;
display:none;
}
#node-project {
background-color:#27ae60;
margin: 30px;
display:none;
}
.project-container{
transition: all 1s;
-webkit-transition: all 1s;
-moz-transition: all 1s;
}
.project-container.open{
transform: translateX(-200px);
-webkit-transform: translateX(-200px);
-moz-transform: translateX(-200px);
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="project">
<ul id="project_menu" class="project_menu">
<li id="menu-php-mysql" data-projectID="php-project">PHP/MySQL</li>
<li id="menu-nodejs" data-projectID="node-project">NodeJS</li>
</ul>
<div class="project-detail">
<div id="php-project" class="project-container common">
<i class="ion-ios-close-empty close-icon js-close-icon"></i>
<div classs="project-text">
<h2 class="project-label">Project title: <span class="project-name"> php project</span></h2>
</div>
</div> <!-- end of php-project -->
<div id="node-project" class="project-container common">
<i class="ion-ios-close-empty close-icon js-close-icon"></i>
<div classs="project-text">
<h2 class="project-label">Project title: <span class="project-name"> node project</span></h2>
</div>
</div> <!-- end of node-project -->
</div> <!-- end of project-detail -->
</div> <!-- end of project -->
I think you want this to work like in this fiddle
HTML Code
<div class="project">
<ul id="project_menu" class="project_menu">
<li id="menu-php-mysql" data-projectID="php-project">PHP/MySQL</li>
<li id="menu-nodejs" data-projectID="node-project">NodeJS</li>
<!-- more code -->
</ul>
<div class="project-detail">
<div id="php-project">
<i class="ion-ios-close-empty close-icon js-close-icon"></i>
<div classs="project-text">
PHP project text
<!-- data about project -->
</div>
</div>
<div id="node-project">
<i class="ion-ios-close-empty close-icon js-close-icon"></i>
<div classs="project-text">
Node Project Text
<!-- data about project -->
</div>
<!-- and so on.. -->
</div>
</div>
</div>
CSS Code
.project_menu > li{
cursor: pointer;
}
.project-detail{
width: 300px;
height: 100px;
background-color: #dedede;
overflow: hidden;
position: relative;
}
JQuery
$(document).ready(function() {
$('.project-detail > div:first-child').css("right","0px");
itemsToRender = [];
$('#project_menu li').click(function(e) {
menuItemId = (e.currentTarget.id);
$('.common').hide();
$(getProjectId(menuItemId)).css('display', 'inline');
var value = '0px';
$(getProjectId(menuItemId)).animate({
right: '0px'
}, 800);
var req = '.project-detail > div';
$('.project-detail > div').not($(getProjectId(menuItemId))).animate({
right: '300px'
}, 800);
});
});
function getProjectId(menuItemId) {
if (menuItemId.indexOf('php') > 0) {
return '#php-project';
} else if (menuItemId.indexOf('node') > 0) {
return '#node-project';
} else if (menuItemId.indexOf('angular') > 0) {
return '#angular-project';
} else if (menuItemId.indexOf('mean') > 0) {
return '#mean-project';
}
}
I am working on creating a website and I am stuck on a certain function I am trying to build. I am trying to slide back a div to its original place if anyplace outside the div is clicked. I've looked everywhere on stack but to no avail. What happens to me is that the background clicks remain active at all times, I only need it to be active when the div has slid to become sort of a popup.
Here is my jsfiddle: https://jsfiddle.net/DTcHh/10567/
Here is the jquery for one of the divs (the rest are similar)
var text = 1;
$('.login1').click(function(e){
e.preventDefault();
$('.loginform_hidden').toggleClass('loginform_visible');
$(".animateSlide").toggle(300, function(){
$(this).focus();
});
if(text == 1){
$(".div1").toggleClass("animateSlide col-xs-12");
$('.login1').html('Go Back');
$('.imageOne').toggleClass('animateSlideTop');
// If an event gets to the body
$('.div2, .div3, .patientAccess').toggle("fast");
document.addEventListener('mouseup', function(event){
var box = document.getElementsByClassName('animateSlide');
if (event.target != box && event.target.parentNode != box){
$('.div2, .div3, .patientAccess').toggle("fast");
$(".div1").toggleClass("animateSlide ");
text=0;
}
});
text = 0;
} else {
$(".div1").toggleClass("animateSlide");
$('.login1').html('Start Animation');
$('.imageOne').toggleClass('animateSlideTop');
$('.div2, .div3, .patientAccess').toggle("fast");
text = 1;
}
});
$(".div1").on('blur', function() {
$(this).fadeOut(300);
});
EDIT: The jsfiddle now incorporates what I have been trying to utilize.
As a demonstration, I built a simplified version of what I think you're aiming to achieve.
I'm using the "event.target" method described in this answer.
Since you are using CSS transitions, I'm using jQuery to detect the end of those transitions using a method found here.
I've given all boxes a class of "animbox" so that they can all be referenced as a group. I've also given each box its own ID so it can be styled individually with CSS.
I've commented the code in an attempt to explain what's going on.
// define all box elements
var $allBoxes = jQuery('.animbox');
// FUNCTION TO SHOW A SELECTED BOX
function showBox($thisBox) {
$allBoxes.hide(); // hide all boxes
$thisBox.show().addClass('animateSlide'); // show and animate selected box
$('div.login', $thisBox).text("Go Back"); // change the selected box's link text
}
// FUNCTION TO RETURN BOXES TO THE DEFAULT STATE
function restoreDefaultState() {
var $thisBox = jQuery('div.animbox.animateSlide'); // identify an open box
if ($thisBox.length) { // if a box is open...
$thisBox.removeClass('animateSlide'); // close this box
$thisBox.one('webkitTransitionEnd'+
' otransitionend'+
' oTransitionEnd'+
' msTransitionEnd'+
' transitionend', function(e) { // when the box is closed...
$allBoxes.show(); // show all boxes
$('div.login', $thisBox).text("Start Animation"); // change the link text
});
}
}
// CLICK HANDLER FOR ALL "login" TRIGGERS
$('div.login').click(function(e) {
var $thisBox = $(this).closest('div.animbox'); // identify clicked box
if (!$thisBox.hasClass('animateSlide')) { // if the box is not open...
showBox($thisBox); // open it
} else { // otherwise...
restoreDefaultState(); // restore the default state
}
});
// CLICK HANDLER TO RESTORE DEFAULT STATE WHEN CLICK HAPPENS OUTSIDE A BOX
$('body').click(function(evt) {
if ($(evt.target).hasClass('animbox') || // if a box is clicked...
$(evt.target).closest('div.animbox').length > 0) { // or a child of a box...
return; // cancel
}
restoreDefaultState(); // restore the default state
});
div.container-fluid {
background-color: #464646;
}
.v-center {
display: table;
height: 100vh;
}
.content {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.patientAccess {
transition: all .5s;
background: white;
height: 200px;
width: 90%;
position: absolute;
opacity: 0.7;
margin-top: -100px;
}
.patientAccess p {
font-size: 1.5em;
font-weight: bold;
}
div.animbox {
transition: all .5s;
position: absolute;
cursor: pointer;
width: 90%;
height: 100px;
opacity: 0.7;
}
div#animbox1 {
background: #e76700;
}
div#animbox2 {
background: #74b8fe;
}
div#animbox3 {
background: #848484;
}
div.login {
color: white;
font-size: 1em;
cursor: pointer;
}
div#animbox1.animateSlide {
width: 200px;
height: 300px;
margin-left: 100px;
opacity: 1;
}
div#animbox2.animateSlide {
width: 250px;
height: 450px;
margin-left: -25px;
margin-top: -150px;
}
div#animbox3.animateSlide {
width: 150px;
height: 150px;
opacity: .5;
margin-left: -100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<div class="container-fluid">
<div class="row-fluid">
<div class="col-xs-12 v-center">
<div class="content text-center">
<div class="col-xs-2 animated slideInRight "></div>
<div class="col-xs-2 animated slideInRight ">
<div class="patientAccess">
<p>Patient Resource Access</p>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox1">
<div class="login">Start Animation</div>
<div class="loginform_hidden "></div>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox2">
<div class="login">Start Animation</div>
<div class="registrationform_hidden"></div>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox3">
<div class="login">Start Animation</div>
</div>
</div>
</div>
</div>
</div>
</div>
You can namespace an event handler using this syntax:
$("#myElement").on("click.myEventHandlerName", function() { ... });
At any point, you can remove the event handler again by calling
$("#myElement").off("click.myEventHandlerName", "#myElement");