I am working on a project that requires the user to be able to click on a few photos to expand them in a modal view. While we are using Bootstrap 4 for the page formatting, I have been told not to use the Bootstrap Modal framework because of issues with device compatibility. I also can't use plugins because of licensing concerns. So, I found and emulated this: https://www.w3schools.com/howto/howto_css_modal_images.asp
This is my code (with dummy images):
<!-- Code for Modal -->
<div class="popupHolder" id="popup1">
<div class="popupFlex">
<div class="popup">
<div class="popupClose">×</div>
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="popupCnt">
<img class="imgpopup" id="img01">
<br clear="all" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Container that holds gallery -->
<div class="container">
<div class="row">
<div class="col-4">
<div class="imgGridBox">
<img class="img-fluid myImg" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/330px-Image_created_with_a_mobile_phone.png" alt="img1">
<img class="imgOpen" src="https://upload.wikimedia.org/wikipedia/commons/6/6d/Windows_Settings_app_icon.png">
</div>
</div>
<div class="col-4">
<div class="imgGridBox">
<img class="img-fluid myImg" src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Micah_1.jpg/375px-Micah_1.jpg" alt="Img2">
<img class="imgOpen" src="https://upload.wikimedia.org/wikipedia/commons/6/6d/Windows_Settings_app_icon.png">
</div>
</div>
</div>
</div>
CSS:
.imgGridBox {
position: relative;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.imgGridBox img {
display: block;
width: 100%;
}
.imgOpen {
position: absolute;
background-color: #fff;
bottom: 0;
right: 0;
max-width: 20px;
max-height: 20px;
}
.popupHolder {
visibility: hidden;
position: fixed;
top: 0;
left: 0;
max-width: 100vw;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, 0.75);
z-index: 888888;
}
.popupFlex {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
width: 100%;
height: 100%;
}
.popup {
position: relative;
background: #FFF;
border-radius: 0.3rem;
max-width: 95%;
}
.popupClose {
position: absolute;
right: 0.5rem;
top: 0.5rem;
color: #34B233;
font-size: 2rem;
cursor: pointer;
z-index: 999999;
}
.popupCnt {
padding: 2rem;
text-align: center;
}
.popupCnt #img01 {
width: 50vw;
}
Script:
var modal = document.getElementById("popup1");
var images = document.getElementsByClassName("myImg");
var modalImg = document.getElementById("img01");
var open = document.getElementById("imgOpen");
for (var i = 0; i < images.length; i++) {
var img = images[i];
img.onclick = function (evt) {
console.log(evt);
modal.style.visibility = "visible";
modalImg.src = this.src;
};
}
var span = document.getElementsByClassName("popupClose")[0];
span.onclick = function () {
modal.style.visibility = "hidden";
};
$(".popupHolder").click(function () {
modal.style.visibility = "hidden";
});
$(".popupCnt").click(function (event) {
event.stopPropagation();
modal.style.visibility = "hidden";
});
Codepen: https://codepen.io/kaelahc/pen/yLeXwXm
It works great when clicking on the image itself but I'm not sure how to alter the JS to make the icon clickable (preferably instead of the image). Can anyone recommend a fix?
You are looping through images and binding click on images in your code here :
for (var i = 0; i < images.length; i++) {
var img = images[i];
img.onclick = function (evt) {
console.log(evt);
modal.style.visibility = "visible";
modalImg.src = this.src;
};
}
What you need is to loop through gear icon, and then retrieve the image with whatever technique (I used parentNode and querySelector here)
It will look like that :
const opens = document.querySelectorAll(".imgOpen");
opens.forEach(open => {
open.addEventListener('click', e => {
e.preventDefault();
modal.style.visibility = 'visible';
modalImg.src = open.parentNode.querySelector('.myImg').src;
return false;
});
});
If you want a jQuery solution, try adding this event listener to all of the gear icons:
$(".imgOpen").click(function (event) {
modal.style.visibility = "visible";
modalImg.src = $(event.target).siblings('.myImg').attr('src');
});
Related
I'm a bit of a beginner and trying to create a modal that is triggered by mouseenter/mouseleave event handlers tied to a single class that is attached to multiple div blocks, but uses javascript to grab unique title and paragraph info from attributes on each div when the mouse is over it. Is this possible or do I have to create individual modals for each div to achieve this?
(I tentatively set it up to display the info from the first box on all of them to show generally what i'm going for)
https://codepen.io/admaloch/pen/yLKWWew
boxes.forEach((box) => {
box.addEventListener("mouseenter", function (e) {
modalContainer.classList.remove("display-none");
modalTitle.innerText = titleInfo[0].title;
modalParagraph.innerText = dataContent[0].dataset.content;
});
box.addEventListener("mouseleave", function (e) {
modalContainer.classList.add("display-none");
});
});
I'm not sure if I understood correctly, but you can just access these attributes through box
const boxes = document.querySelectorAll(".block");
const modalContainer = document.querySelector(".modal");
const modalTitle = document.querySelector(".modal-title");
const modalParagraph = document.querySelector(".modal-paragraph");
boxes.forEach((box) => {
box.addEventListener("mouseenter", function (e) {
modalContainer.classList.remove("display-none");
modalTitle.innerText = box.title;
modalParagraph.innerText = box.dataset.content;
});
box.addEventListener("mouseleave", function (e) {
modalContainer.classList.add("display-none");
});
});
.block-container {
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
}
.block {
background-color: blue;
height: 50px;
width: 50px;
margin-top: 50px;
}
.display-none {
display: none;
}
.modal {
position: fixed;
background-color: lightblue;
width: 30%;
height: 100px;
left: 35%;
top: 10vh;
border-radius: 14px;
}
.modal-info {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
}
.modal-title,
.modal-paragraph {
margin: 0;
padding: 0;
}
<div class="container">
<div class="block-container">
<div class="block" title="1" data-content="Info for the 1st box"></div>
<div class="block" title="2" data-content="Info for the 2nd box"></div>
<div class="block" title="3" data-content="Info for the 3rd box"></div>
<div class="block" title="4" data-content="Info for the 4th box"></div>
<div class="block" title="5" data-content="Info for the 5th box"></div>
<div class="block" title="6" data-content="Info for the 6th box"></div>
</div>
<div class="modal display-none">
<div class="modal-info">
<h3 class="modal-title"></h3>
<p class="modal-paragraph"></p>
</div>
</div>
</div>
You can pass an index in forEach and use that index instead of titleInfo[0]
boxes.forEach((box, index) => {
box.addEventListener("mouseenter", function (e) {
modalContainer.classList.remove("display-none");
modalTitle.innerText = titleInfo[index].title;
modalParagraph.innerText = dataContent[index].dataset.content;
});
box.addEventListener("mouseleave", function (e) {
modalContainer.classList.add("display-none");
});
});
I'm struggling with infinite carousel below:
let $carousel = document.querySelector('.carousel');
let $ref_ribbon = document.querySelector('.carousel__ribbon');
let $ref_right = document.querySelector('.carousel__button--right');
let $ref_left = document.querySelector('.carousel__button--left');
let $ref_counter = 0;
let $direction;
const transfer = () => {
if ($direction === -1) {
$ref_ribbon.appendChild($ref_ribbon.firstElementChild);
} else if ($direction === 1) {
$ref_ribbon.prepend($ref_ribbon.lastElementChild);
}
$ref_ribbon.style.transition = "none";
$ref_ribbon.style.transform = "translateX(0px)";
setTimeout(function() {
$ref_ribbon.style.transition = "transform .7s ease-in-out";
})
}
const right_button = () => {
if ($direction === 1) {
$ref_ribbon.prepend($ref_ribbon.lastElementChild);
$direction = -1;
}
$direction = -1;
$carousel.style.justifyContent = 'flex-start';
$ref_ribbon.style.transform = `translateX(-${300}px)`;
}
const left_button = () => {
$ref_counter--;
if ($direction === -1) {
$ref_ribbon.appendChild($ref_ribbon.firstElementChild);
$direction = 1;
}
$direction = 1;
$carousel.style.justifyContent = 'flex-end';
$ref_ribbon.style.transform = `translateX(${300}px)`;
}
$ref_right.addEventListener('click', right_button);
$ref_left.addEventListener('click', left_button);
$ref_ribbon.addEventListener('transitionend', transfer)
.carousel {
display: flex;
margin: auto;
position: relative;
height: 200px;
width: 300px;
background-color: red;
justify-content: flex-start;
}
.carousel__button {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 100;
}
.carousel__button--left {
left: 0;
}
.carousel__button--right {
right: 0;
}
.carousel__ribbon {
display: flex;
flex-direction: row;
outline: 3px solid black;
height: 100%;
transition: transform .7s ease-in-out;
}
.carousel__pane {
display: flex;
background-color: skyblue;
height: 100%;
width: 300px;
flex-shrink: 0;
outline: 1px dashed navy;
}
.carousel__content {
text-align: center;
margin: auto;
}
.carousel__indicator {
display: flex;
gap: 10px;
left: 50%;
transform: translateX(-50%);
height: 30px;
position: absolute;
bottom: 0;
}
.carousel__circle {
height: 10px;
width: 10px;
background-color: gray;
border-radius: 50%;
cursor: pointer;
}
.carousel__circle--active {
background-color: black;
}
<div class="carousel">
<button class="carousel__button carousel__button--left"><</button>
<button class="carousel__button carousel__button--right">></button>
<div class="carousel__ribbon">
<div class="carousel__pane">
<p class="carousel__content">Pane 1</p>
</div>
<div class="carousel__pane">
<p class="carousel__content">Pane 2</p>
</div>
<div class="carousel__pane">
<p class="carousel__content">Pane 3</p>
</div>
<div class="carousel__pane">
<p class="carousel__content">Pane 4</p>
</div>
<div class="carousel__pane">
<p class="carousel__content">Pane 5</p>
</div>
</div>
<div class="carousel__indicator">
<div class="carousel__circle carousel__circle--active"></div>
<div class="carousel__circle"></div>
<div class="carousel__circle"></div>
<div class="carousel__circle"></div>
<div class="carousel__circle"></div>
</div>
</div>
I would like to connect indicator so when somebody click on proper circle then carousel will automatically slide to this particular panel. Also, I would like to set this circles that they will show which panel is currently active.
In addition, I would like to get such effect that carousel will jump to this particular panel immediately, ommiting other panels between.
So, if active one is first panel and I click fifth circle, then carousel will smoothly change panel like to the panel number two, but instead of number two I will see number five.
Sadly I always fail to get this effect. I would appriciate if somebody more experienced direct me how to deal with this problem.
currently learning javascript and encounter a problem.
I made a button for mobile screen that if clicked it can expand the background and display the menu. I encounter problem where only the menu content can be clicked back and forth to display and undisplayed, and the background don't.
My goal is
When I clicked the menu button, both the background will expand and the menu will be displayed.
and the background can be toggle on and off by clicking the menu button.
Can anyone help me with this problem ?
document.getElementById("menu_button").addEventListener("click",function()
{
var open1=document.getElementById("opened_menu");
var open2=document.getElementById("menu_background");
open2.style.width = '100%';
open2.style.height = '100vh';
if(open1.style.display=="none")
{
open1.style.display="block";
}
else {
open1.style.display="none";
}
})
.mobile_background {
display: block;
width: 2rem;
height: 3rem;
background-color: red;
}
.mobile_menu {
display: none;
position: relative;
padding-top: 2rem;
padding-left: 2rem;
}
#menu_button {
position: fixed;
top: 0;
left: 0;
}
<div class="mobile_background" id="menu_background">
<div class="mobile_menu" id="opened_menu">
<p>menu 1</p>
<p>menu 2</p>
</div>
<button type="button" name="button" id="menu_button">
<div class="inner_menu">
<p>MENU</p>
</div>
</button>
</div>
Thanks in advance.
I bet this is what you want.
document.getElementById("menu_button").addEventListener("click", function() {
var open1 = document.getElementById("opened_menu");
var open2 = document.getElementById("menu_background");
if (open1.style.display == "none") {
open1.style.display = "block";
open2.style.width = '100%';
open2.style.height = '100vh';
} else {
open1.style.display = "none";
open2.style.width = '0%';
open2.style.height = '0vh';
}
})
.mobile_background {
display: block;
width: 0%;
height: 0vh;
background-color: red;
}
.mobile_menu {
display: none;
position: relative;
padding-top: 2rem;
padding-left: 2rem;
}
#menu_button {
position: fixed;
top: 0;
left: 0;
}
<div class="mobile_background" id="menu_background">
<div class="mobile_menu" id="opened_menu" style="display: none">
<p>menu 1</p>
<p>menu 2</p>
</div>
<button type="button" name="button" id="menu_button">
<div class="inner_menu">
<p>MENU</p>
</div>
</button>
</div>
I have problem with canvas tag. I need to append it into parent div. But when I set precise dimensions of parent and embed canvas tag, I get scrollbars. When I do same think with div, it works good. Here is fiddle:
https://jsfiddle.net/57yovrkx/4/
and here is code:
$(function() {
var content1 = $('#content1');
var div = $('<div/>', {width: content1[0].clientWidth, height: content1[0].clientHeight});
content1.append(div);
var content2 = $('#content2');
var canvas = $('<canvas/>', {width: content2[0].clientWidth, height: content2[0].clientHeight});
content2.append(canvas);
})
* {
box-sizing: border-box;
border: 0;
margin: 0;
padding: 0;
}
#wrap1, #wrap2 {
display: flex;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
overflow: auto;
}
#wrap1 {
top: 0;
bottom: 50%;
}
#wrap2 {
top: 50%;
bottom: 0;
}
.header {
flex: 0 0 2rem;
background: darkgrey;
}
#content1, #content2 {
flex: 1;
}
#content1 {
background: lightblue;
}
#content2 {
background: lightgreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap1">
<div class="header">
Some header
</div>
<div id="content1">
</div>
</div>
<div id="wrap2">
<div class="header">
Some header
</div>
<div id="content2">
</div>
</div>
Does anybody knows why?
Setting canvas.style.height = '100%'; before you append the canvas seems to do the trick.
https://stackoverflow.com/a/10215724/1482623
function toggleOverlay_1() {
var overlay = document.getElementById('overlay');
var specialBox = document.getElementById('specialBox_1');
overlay.style.opacity = .8;
if (overlay.style.display == "block") {
overlay.style.display = "none";
specialBox.style.display = "none";
} else {
overlay.style.display = "block";
specialBox.style.display = "block";
}
}
function toggleOverlay_2() {
var overlay = document.getElementById('overlay');
var specialBox = document.getElementById('specialBox_2');
overlay.style.opacity = .8;
if (overlay.style.display == "block") {
overlay.style.display = "none";
specialBox.style.display = "none";
} else {
overlay.style.display = "block";
specialBox.style.display = "block";
}
}
div#overlay {
display: none;
z-index: 2;
background: #000;
position: fixed;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
text-align: center;
}
div#specialBox_1 {
display: none;
position: fixed;
z-index: 3000;
height: 100%;
width: 100%;
background: #FFF;
color: #000;
}
div#specialBox_2 {
display: none;
position: fixed;
z-index: 3000;
height: 100%;
width: 100%;
background: #FFF;
color: #000;
}
div#wrapper {
position: absolute;
top: 0px;
left: 0px;
padding-left: 24px;
}
.closebtn {
position: absolute;
top: 0%;
right: 45px;
font-size: 40px;
}
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="http://a.vimeocdn.com/js/froogaloop2.min.js"></script>
<div id="overlay">
<div id="specialBox">
<iframe id="myVid_1" src="https://player.vimeo.com/video/183364240?api=1&title=0&byline=0&portrait=0&player_id=myVid_1" width="100%" height="100%" frameborder="0"></iframe>
<div class="closebtn">
×
</div>
</div>
</div>
<div id="overlay">
<div id="specialBox">
<iframe id="myVid_2" src="https://player.vimeo.com/video/183364240?api=1&title=0&byline=0&portrait=0&player_id=myVid_2" width="100%" height="100%" frameborder="0"></iframe>
<div class="closebtn">
×
</div>
</div>
</div>
<div id="wrapper">
<input type="button" name="Google_Red" class="button_red" value="Google" a href="#" onclick="toggleOverlay_1()"></input>
<br>
<input type="button" name="W3Schools Red" class="button_red" value="Sealed Air" a href="#" onclick="toggleOverlay_2()"></input>
<br>
</div>
I am trying to open different videos(in an overlay) on different button clicks. I could this well if I use just one button and its opens the video correctly. But when I try to bind different videos to different buttons, it just binds one videos to all the buttons. Can someone tell me how to solve this issue?
Based on your html and jquery. Here is what you need to do. Instead of making 2 functions. Keep one function for toggle with the iframe id as parameter the toggleOverlay(playerid). As your video iframe id's parent div is the specialbox and the specialbox parent is the overlay itself. You can utilize the .parent() method of jquery to set it up.
function toggleOverlay(playerid){
$("#" + playerid).parent("#specialBox").parent().css("opacity",".8");
$("#" + playerid).parent("#specialBox").parent().toggle();
$("#" + playerid).parent("#specialBox").toggle();
}
Now in the buttons or anywhere you call the toggleOverlay function, add the unique playerid as parameter and your set based on which button handles which overlay.
Also you cant have 2 divs with same ids. So change the second overlay div id to "overlay2".
Here is working example:
http://codepen.io/Nasir_T/pen/pEmEJE
Because you are targeting the div with an ID, the DOM will take the first div with that id (your first video). So you have to target your second overlay with another ID.
Here is a rebuild option, I feel like this might be easier than making all that javascript for each video.
// This part isnt needed but I added it in case you wanted it
// Get the modals
var modal = document.getElementById('id01');
var modal2 = document.getElementById('id02');
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
if (event.target == modal2) {
modal2.style.display = "none";
}
}
.modal {
z-index: 3;
display: none;
padding-top: 100px;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4)
}
.modal-content {
margin: auto;
background-color: #fff;
position: relative;
padding: 0;
outline: 0;
width: 600px
}
.container {
padding: 0.01em 16px
}
.closebtn {
text-decoration: none;
float: right;
font-size: 30px;
font-weight: bold;
}
.closebtn:hover,
.closebtn:focus {
color: red;
cursor: pointer
}
<button onclick="document.getElementById('id01').style.display='block'">Open Video 1</button>
<button onclick="document.getElementById('id02').style.display='block'">Open Video 2</button>
<!-- Video 1 -->
<div id="id01" class="modal">
<div class="modal-content">
<div class="container">
<span onclick="document.getElementById('id01').style.display='none'" class="closebtn">×</span>
<iframe src="https://player.vimeo.com/video/183364240?api=1&title=0&byline=0&portrait=0&player_id=myVid_1" width="100%" height="100%" frameborder="0"></iframe>
</div>
</div>
</div>
<!-- Video 2 -->
<div id="id02" class="modal">
<div class="modal-content">
<div class="container">
<span onclick="document.getElementById('id02').style.display='none'" class="closebtn">×</span>
<iframe src="https://player.vimeo.com/video/183364240?api=1&title=0&byline=0&portrait=0&player_id=myVid_2" width="100%" height="100%" frameborder="0"></iframe>
</div>
</div>
</div>