How to apply CSS transition effect on a JS triggered event? - javascript

I'm new to HTML/CSS/JS.
I have an HTML form with two input fields: e-mail and favorite website. I have two regular expressions in my JS file which check the input. This works fine, but I want to trigger an error message when the user clicks out of the box(onblur event).
My problem is that I want to apply a transition effect on the error, so it becomes visible over time, not just suddenly appears. Plus, right now, the error message pops up only once.
So my questions are:
How to apply the transition effect on the error message;
How to make it appear as many times as the user fails to enter the right input.
Here is my the HTML file :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="CSS2_2.css">
</head>
<body>
<div id="webpagevalidationerror" class="error">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
<p>Wrong website !</p>
</div>
<div id="emailvalidationerror" class="error">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
<p>Wrong e-mail !</p>
</div>
<form name="myform" class = "relative">
<fieldset>
<legend>Personal information:</legend>
E-mail :<br>
<input id="email" type="text" name="email" onblur="validateEmail(this)"><br>
Favorite website :<br>
<input id="webpage" type="text" name="webpage" onblur="validateWebpage(this)"><br><br>
<input id="submit" type="submit" value="Submit">
</fieldset>
</form>
<script src="JS_2.js"></script>
</body>
And the CSS file :
fieldset {
display: inline;
}
form.relative {
position: relative;
left: 150px;
top: 150px;
}
p {
position: relative;
left: 30px;
top: 16px;
width: 150px;
}
div {
position: relative;
left: 120px;
top: 130px;
width: 250px;
height: 50px;
background-color: #f44336;
color: white;
display: none;
/*transition: 2s; How to apply this transition for the .triggered attributes ?
transition-timing-function: linear;*/
}
.triggered {
display: block;
}
.closebtn {
margin-right: 25px;
margin-top: 13px;
color: white;
font-weight: bold;
float: right;
font-size: 22px;
cursor: pointer;
transition: 0.3s;
}
.closebtn:hover {
color: black;
}
And the Javascript file :
var emailerror = document.getElementById("emailvalidationerror");
var webpageerror = document.getElementById("webpagevalidationerror");
function validateEmail(email) {
var re = new RegExp("^[^#]+#yahoo.com$");
var re2 = new RegExp("^[^#]+#gmail.com$");
if (!(re.test(email.value)) && !(re2.test(email.value)) || email.value == "") {
emailerror.classList.toggle("triggered");
}
}
function validateWebpage(webpage) {
var re = new RegExp("^www\\.[a-zA-Z0-9_-]+\\.[a-z]+\\.[a-z]+$");
if (!(re.test(webpage.value)) || webpage.value == "") {
webpageerror.classList.toggle("triggered");
}
}

You can't animate from display:none to display:block. The trick is to set scale and opacity to 0, then trigger the opacity animation with the delay of the scale animation duration.
Also validation functions may return a boolean, to check if everything is ok when you submit your form (and you don't want to toggle triggered class, as you wish the message to be still displayed as long as the input is wrong. So just add class if it's wrong, remove it if it's ok).
And rather than set inline atributes on your HTML elements (onClick,onBlur,...), set eventlisteners in your js code (to avoid to mix js and html)
Here a working snippet adapted from your existing code:
var emailerror = document.getElementById("emailvalidationerror");
var webpageerror = document.getElementById("webpagevalidationerror");
var closeBtn = document.getElementsByClassName("closebtn");
// loop throught closeBtn nodelist to add listener for each buttons
for(var i = 0; i < closeBtn.length; i++)
{
closeBtn[i].addEventListener("click",function(e){
e.currentTarget.parentElement.classList.remove("triggered");
});
}
document.getElementById("webpage").addEventListener("blur",validateWebpage);
document.getElementById("email").addEventListener("blur",validateEmail);
document.getElementById("submit").addEventListener("click",submitForm);
function validateEmail() {
var valToTest = document.getElementById("email").value;
var re = new RegExp("^[^#]+#yahoo.com$");
var re2 = new RegExp("^[^#]+#gmail.com$");
if (!(re.test(valToTest)) && !(re2.test(valToTest)) || valToTest == "") {
emailerror.classList.add("triggered");
return false;
}
emailerror.classList.remove("triggered");
return true;
}
function validateWebpage() {
var valToTest = document.getElementById("webpage").value;
var re = new RegExp("^www\\.[a-zA-Z0-9_-]+\\.[a-z]+\\.[a-z]+$");
if (!(re.test(valToTest)) || valToTest == "") {
webpageerror.classList.add("triggered");
return false;
}
webpageerror.classList.remove("triggered");
return true;
}
function submitForm(e){
e.preventDefault();
var emailOk = validateEmail();
var webPageOk = validateWebpage();
if(emailOk && webPageOk){
document.getElementById("myform").submit();
}
}
fieldset {
display: inline;
}
form.relative {
position: relative;
left: 150px;
top: 150px;
}
p {
position: relative;
left: 30px;
top: 16px;
width: 150px;
}
div {
position: relative;
left: 120px;
top: 130px;
width: 250px;
height: 50px;
background-color: #f44336;
color: white;
/* display: none;*/
/*transition: 2s; How to apply this transition for the .triggered attributes ?
transition-timing-function: linear;*/
transform-origin:50% 50%;
transform:scale(0);
opacity:0;
transition: transform .2s, opacity 2s .2s;
}
.triggered {
/* display: block;*/
transform:scale(1);
opacity:1;
}
.closebtn {
margin-right: 25px;
margin-top: 13px;
color: white;
font-weight: bold;
float: right;
font-size: 22px;
cursor: pointer;
transition: 0.3s;
}
.closebtn:hover {
color: black;
}
<div id="webpagevalidationerror" class="error">
<span class="closebtn">×</span>
<p>Wrong website !</p>
</div>
<div id="emailvalidationerror" class="error">
<span class="closebtn">×</span>
<p>Wrong e-mail !</p>
</div>
<form id="myform" class = "relative">
<fieldset>
<legend>Personal information:</legend>
E-mail :<br>
<input id="email" type="text" name="email"><br>
Favorite website :<br>
<input id="webpage" type="text" name="webpage"><br><br>
<input id="submit" type="submit" value="Submit">
</fieldset>
</form>

If you just want to show it smoothly just change your triggered class
This will add a transition effect while adding the class to display it.
https://jsfiddle.net/ycLn2fyb/25/
HTML and javascript
<div id="webpagevalidationerror" class="error">
<span class="closebtn" >×</span>
<p>Wrong website !</p>
</div>
<button onClick="myFunction()"> TEST BUTTON</button>
<script type="text/javascript">
var webpageerror = document.getElementById("webpagevalidationerror");
function myFunction()
{
webpageerror.classList.toggle("show");
}
</script>
Css:
div {
position: relative;
left: 120px;
top: 130px;
width: 250px;
height: 50px;
background-color: #f44336;
color: white;
opacity: 0;
}
.show {
opacity: 1;
transition: opacity 2s ease-in;
-moz-transition: opacity 2s ease-in;
-webkit-transition: opacity 2s ease-in;
}
p {
position: relative;
left: 30px;
top: 16px;
width: 150px;
}
.closebtn {
margin-right: 25px;
margin-top: 13px;
color: white;
font-weight: bold;
float: right;
font-size: 22px;
cursor: pointer;
transition: 0.3s;
}
.closebtn:hover {
color: black;
}

Related

how to filter divs by checkbox using multiple classes

I have a product page that fetches the products from a database table, I am using foreach to pull each product & each product displays as a card and using classes to filter them.
The problem is that the checkbox filter isnt working properly with multiple values (classes), if I have 2 classes the filter is only detecting the 1st class rather than all the classes(filters).
So for example, if I check the "Blue" checkbox I wont see any results since the JS is searching for a div that has only that one class ("filt-blue") but I need it to display all divs that contain "filt-blue" as well as any other filters that may be added.
See more on JSFIDDLE
function change() {
var checkboxes = document.getElementsByClassName('checkbox');
var chekboxInputs = Array.from(checkboxes).map(a => a.querySelector('input'));
var allAreUnselected = chekboxInputs.every(function(elem) {
return !elem.checked;
});
if (allAreUnselected) {
chekboxInputs.forEach(function(input) {
Array.from(document.querySelectorAll("." + input.getAttribute("rel"))).forEach(function(item) {
item.style.display = 'block';
});
});
} else {
chekboxInputs.forEach(function(input) {
Array.from(document.querySelectorAll("." + input.getAttribute("rel"))).forEach(function(item) {
item.style.display = input.checked ? 'block' : 'none';
});
});
}
}
change();
#media(max-width:768px){
.card{
width:100% !important;
margin:12px 6px !important;
}
}
.card {
text-align:left;
border-radius:4px;
margin:24px;
width:320px;
min-height:340px;
transition: all 0.2s;
border:var(--image-select-border);
}
.cards {
display: flex;
flex-wrap: wrap;
justify-content:center;
}
.card-body {
flex: 1 1 auto;
padding:12px;
}
.card-title {
margin-bottom:16px;
padding:12px;
}
#media(max-width:768px){
.card-img-top{
width:240px !important;
}
}
#media(max-width:768px){
.filtbtn{
width:90% !important;
margin-left:5% !important;
float:none !important;
}
}
.filterDiv {
display: none;
}
.show {
display: block;
}
#media(max-width:768px){
#opts{
margin-left:5% !important;
}
}
.optsel{
border-bottom:2px solid #0d6efd;
border-top: none;
border-left: none;
border-right: none;
}
.sidebar {
height:100%;
width:0;
position:fixed;
z-index:1;
top:76px;
right:0;
background-color:#111;
overflow-x:hidden;
transition: 0.5s;
padding-top: 60px;
}
.sidebar a {
padding:8px 12px;
text-decoration: none;
font-size:16px;
color: #818181;
display: block;
transition: 0.3s;
}
.sidebar .closebtn {
position: absolute;
top: 0;
margin-right:12px;
font-size:18px;
color:#222 !important;
background-color:#fff;
width:100%;
}
#media(max-width:768px){
.closebtn{
top:4px !important;
}
}
.openbtn {
font-size: 20px;
cursor: pointer;
background-color: #111;
color: white;
padding: 10px 15px;
border: none;
}
.openbtn:hover {
background-color: #444;
}
#main {
transition: margin-right .5s; /* If you want a transition effect */
padding: 20px;
}
/* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */
#media screen and (max-height: 450px) {
.sidebar {padding-top: 15px;}
.sidebar a {font-size: 22px;}
}
.optbtn{
background-color:#fff;
color: #222;
cursor: pointer;
padding:14px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 16px;
transition: 0.4s;
}
.accordion {
background-color:#111;
color: #fff !important;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.notaccordion {
background-color:#111;
color: #fff !important;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: center;
outline: none;
font-size:18px;
transition: 0.4s;
font-weight:bolder;
}
.active, .accordion:hover {
opacity:0.9;
}
.accordion:after {
content: '\002B';
color: #777;
font-weight: bold;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2212";
}
.filterpanel {
padding:0 18px;
background-color:#fff;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.checkbox{
color:#222 !important;
padding:12px 12px;
}
.checkbox-button {
cursor: pointer;
}
.checkbox span{
margin-left:12px;
}
.checkbox input[type=checkbox] {
box-sizing: border-box;
padding: 0;
}
.checkbox input {
font-size: 1rem;
line-height: 1.5;
padding: 11px 23px;
border: 1px solid black;
border-radius: 0;
outline: 0;
background-color: transparent;
}
.checkbox-button__input {
opacity: 0;
position: absolute;
}
.checkbox-button__control {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
vertical-align: middle;
background-color: inherit;
color: #017b5f;
border: 2px solid #666;
}
.checkbox-button__input:checked+.checkbox-button__control:after {
content: "";
display: block;
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
background-color:#0d6efd;
}
.checkbox-button__input:checked+.checkbox-button__control {
border-color:black;
border:2px solid black;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" id="bootstrap-css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
<div class="filter">
<div class="checkbox">
<label class="checkbox-button">
<input type="checkbox" class="checkbox-button__input" id="choice1-1" name="choice1" onchange="change()" rel="filt-blue">
<span class="checkbox-button__control"></span>
</label>
<span><b>blue</b></span>
</div>
</div>
<div class="filter">
<div class="checkbox">
<label class="checkbox-button">
<input type="checkbox" class="checkbox-button__input" id="choice1-2" name="choice1" onchange="change()" rel="filt-red">
<span class="checkbox-button__control"></span>
</label>
<span><b>red</b></span>
</div>
</div>
<hr>
<div class="filter">
<div class="checkbox">
<label class="checkbox-button">
<input type="checkbox" class="checkbox-button__input" id="choice1-1a" name="choice2" onchange="change()" rel="filt-long">
<span class="checkbox-button__control"></span>
</label>
<span><b>long</b></span>
</div>
</div>
<div class="filter">
<div class="checkbox">
<label class="checkbox-button">
<input type="checkbox" class="checkbox-button__input" id="choice1-2a" name="choice2" onchange="change()" rel="filt-short">
<span class="checkbox-button__control"></span>
</label>
<span><b>short</b></span>
</div>
</div>
<div class="cards">
<div class="card filt-blue filt-long">
<h6 class="card-title"><b><?php echo $fetch['title'];?></b></h6>
<center><img src="/images/products/<?php echo $fetch['Img'];?>" class="card-img-top" style="width:160px;margin:0 auto;"></center>
<div class="card-body">
<small><?php echo $fetch['detail'];?></small>
<h6><b>Starting from - £<?php echo $fetch['SFprice'];?></b></h6>
</div>
</div>
<div class="card filt-blue filt-short">
<h6 class="card-title"><b><?php echo $fetch['title'];?></b></h6>
<center><img src="/images/products/<?php echo $fetch['Img'];?>" class="card-img-top" style="width:160px;margin:0 auto;"></center>
<div class="card-body">
<small><?php echo $fetch['detail'];?></small>
<h6><b>Starting from - £<?php echo $fetch['SFprice'];?></b></h6>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
This code should help your filter take into account multiple classes. There's a couple of ways you can filter. For example, if you have "long and blue" do you want to show ONLY long and blue? Or would you want to show a "Red Long" as well. This particular code takes into account multiple filter classes but in a logical OR fashion instead of an AND logic.
<body>
<label>Blue</label>
<input type="checkbox" name="filter-blue" onchange="change()">
<label>Red</label>
<input type="checkbox" name="filter-red" onchange="change()">
<label>Long</label>
<input type="checkbox" name="filter-long" onchange="change()">
<label>Short</label>
<input type="checkbox" name="filter-short" onchange="change()">
<div class="cards">
<p class="filter-blue">Blue Jeans</p>
<p class="filter-blue">Blue Cups</p>
<p class="filter-red">Red Shirt</p>
<p class="filter-red">Red Shirt</p>
<p class="filter-red filter-long">Long Red Shirt</p>
<p class="filter-red filter-short">Short Red Shirt</p>
<p class="filter-blue filter-long">Long Blue Shirt</p>
<p class="filter-blue filter-short">Short Blue Shirt</p>
</div>
<script type="text/javascript">
function change() {
// Step 1 - Get checked filters
let checkboxes = document.querySelectorAll('input[type="checkbox"]'),
filtered = [];
checkboxes.forEach(checkbox => {
if (checkbox.checked) {
filtered.push(checkbox.name);
}
});
// Step 2 - Show cards based on the filters
let cards = document.querySelectorAll('.cards p');
cards.forEach(card => {
if (
filtered.length === 0 || // If no filter is checked then show everything
filtered.some(r => card.classList.contains(r)) // If the filter matches the cards class. Filter it.
) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
}
</script>
</body>
Why doesn't the current code work?
Your code iterates over every input, finding all cards matching that input. The first input is blue, and the code iterates over all cards and correctly displays those matching blue. But it then continues to the next iteration, the red checkbox. No cards match and so they are both immediately hidden. So any matching card(s) are actually shown and then immediately hidden.
OK, how do we fix it?
Here's my approach:
Since we need to evaluate all checkboxes for each indvidual card, flip the order of iteration - for each card, iterate over each checkbox (rather than the other way around as you have);
Evaluate each checkbox: if it is checked and the current card has that attribute, flag it as matching, and continue checking the other checkboxes;
But if the checkbox is checked and the current card does not have that attribute, flag it as a non-match. Now we must immeidately bail out, so a future match doesn't override this failure;
After we've checked all inputs (or bailed out on a failure), display or hide the card depending on the final state of our match;
function change() {
var checkboxes = document.getElementsByClassName('checkbox');
var chekboxInputs = Array.from(checkboxes).map(a => a.querySelector('input'));
var allAreUnselected = chekboxInputs.every(function(elem) {
return !elem.checked;
});
if (allAreUnselected) {
chekboxInputs.forEach(function(input) {
Array.from(document.querySelectorAll("." + input.getAttribute("rel"))).forEach(function(item) {
item.style.display = 'block';
});
});
} else {
Array.from(document.querySelectorAll(".card")).forEach(function(card) {
// console.log('Start card: ', card);
let match = false;
for (const input of chekboxInputs) {
let attribute = input.getAttribute("rel");
// console.log('processing input with rel:', attribute);
if (input.checked && card.classList.contains(attribute)) {
// console.log('input is checked and card matches');
match = true;
} else if (input.checked && ! card.classList.contains(attribute)) {
// console.log('input is checked and card does not match');
match = false;
break;
}
}
// console.log('done checking inputs, match is:', match);
card.style.display = match ? 'block' : 'none';
});
}
}
change();
.card {
border: 1px solid black;
}
<div class="checkbox">
<input type="checkbox" name="choice1" onchange="change()" rel="filt-blue">
<span><b>blue</b></span>
</div>
<div class="checkbox">
<input type="checkbox" name="choice1" onchange="change()" rel="filt-red">
<span><b>red</b></span>
</div>
<div class="checkbox">
<input type="checkbox" name="choice2" onchange="change()" rel="filt-long">
<span><b>long</b></span>
</div>
<div class="checkbox">
<input type="checkbox" name="choice2" onchange="change()" rel="filt-short">
<span><b>short</b></span>
</div>
<br><br>
<div class="cards">
<div class="card filt-blue filt-long">
<b>Blue Long</b>
</div>
<div class="card filt-blue filt-short">
<b>Blue Short</b>
</div>
</div>
Notes
It is generally considered good practice to separate your HTML and JS. Here that would mean removing the inline onchange="change()" in the HTML, and replacing them with an event handler in the JS:
let checkbox = document.querySelector("input[name=checkbox]");
checkbox.addEventListener('change', change);
You will make it so much easier for others to help if you can create a minimal, complete, and verifiable example of the problem. In this case a good chunk of the time I spent on this problem was evaulating what I could strip out - a lot of the HTML and most of the CSS classes are irrlevant. The PHP obviously does not work, and none of the CSS matters. Neither Bootstrap nor jQuery CSS or JS refs are necessary.
When you strip out everything not related to the problem it is that much easier to understand, debug, and work with.

CSS/JS: Put a smooth transition when you add a child to a div container thank to JS

It's a div container that represents a notification widget at the bottom of the screen, JS adds notifications that are child elements to the main div. When notifications are added, they appear promptly. I would like to make the current notification moves up to make place for the incoming notification, I tried to give to the main div the css property "transition" but it's not working. Here's the code that you can run:
function doit() {
var notifcontainer = document.getElementById("notif");
var title = document.getElementById("title").value;
var desc = document.getElementById("desc").value;
if(title != "" && desc != "") {
notifcontainer.innerHTML+= `
<div class="notif">
<h3>${title}</h3>
<p>${desc}</p>
</div>`
}
}
#import url('https://fonts.googleapis.com/css2?family=Poppins:wght#400&display=swap');
body {
display: flex;
flex-direction: column;
width: 300px;
}
button { width: fit-content;}
* {
padding: 0;
margin: 0;
font-family: 'Poppins';
}
.notif {
background: #212121;
color: white;
border-radius: 5px;
padding: 8px 16px;
margin: 8px 0;
}
#notif {
position: absolute;
left: 50%;
bottom: 0px;
width: 300px;
transform: translateX(-50%);
transition: 1s;
}
<div id="notif">
</div>
<label for="title">Title</label>
<input id="title" name="title" type="text">
<label for="desc">Description</label>
<input id="desc" name="desc" type="text">
<button onclick="doit()">Add</button>

How can I get my modal box in Bootstrap to close?

I have a modal box which I can call okay but I can't close it, regardless of whether you click on the x or anywhere else on the screen. Sorry if I'm not describing it well enough - I'm very new.
I've tried the w3 schools demo and also other s/o examples and I just can't for the life of me figure out what I'm doing wrong. Full code supplied below as requested.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Benny the virtual blob</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="virtualpet.css">
<link href="https://fonts.googleapis.com/css?family=Barriecito|Special+Elite&display=swap" rel="stylesheet">
<script src="https://kit.fontawesome.com/de2b0ad954.js"></script>
</head>
<body>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<i class="fas fa-skull-crossbones"></i><br>
<p>"Oh, no! You killed Benny!"<br>
"He was <span id="dead">x</span> days young"</p>
</div>
</div>
<div class="container">
<h1>Benny the Blob</h1>
<p>Look after Benny, the blob. Play with him, feed him, care for him when he's sick. But if you ignore him for too long, he'll die. How long will you be able to keep him alive?</p>
<button type="button" class="btn reset">Birth Benny</button>
</div>
<div class="action">
<img id="age" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561857600/virtual%20pet/item-box.png" alt="window for life span">
<img id="backing" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561670551/virtual%20pet/little-board.png" alt="pin board image">
<div id="bennyNormal" class="start"></div>
<p id="ageStatus" class="start" ><span id="days">0</span> days old</p>
<img id="heart" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561725918/virtual%20pet/l1.png" alt="health points image">
<img id="star" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561725934/virtual%20pet/s1.png" alt="happy points image">
<img id="hungry" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561725898/virtual%20pet/h1.png" alt="hunger points image">
<div id="tasks">
<img id="medicine" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561857719/virtual%20pet/medicene.png" alt="medicine">
<img id="food" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561857661/virtual%20pet/sandwich.png" alt="food">
<img id="toys" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561857776/virtual%20pet/gamesbox.png" alt="toys">
<img id="drink" class="start" src="https://res.cloudinary.com/dytmcam8b/image/upload/v1561857689/virtual%20pet/red-smoothie.png" alt="glass of juice">
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="virtualpet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
var resetBtn = document.querySelector(".reset");
var start = document.querySelectorAll(".start");
var ageing = document.getElementById("days");
var heart= document.getElementById("heart");
var star = document.getElementById("star");
var tummy = document.getElementById("hungry");
var modal = document.getElementById("myModal");
var span = document.getElementsByClassName("close")[0];
var content = document.getElementsByClassName("modal-content")
var dead = document.getElementById("dead");
$(document).ready(function () {
var count=0;
var c = count;
var cd = $('#days');
$(resetBtn).click(function(){
$(".start").toggle();
if ($(this).text() == "Birth Benny") {
$(this).text("Restart");
} else {
$(this).text("Birth Benny");
}});
var interv = setInterval(function() {
c++;
cd.html(c);
randomNum();
happyStatus();
hungerStatus();
healthStatus();
}, 60000);
var health = 4;
var happy = 4;
var hungry = 4;
function randomNum(){
//pick a 'health'
var h=Math.random();
//pick a happy
var s=Math.random();
//pick a hungry
var f=Math.random();
if (h <0.5) {
health--;
}
if (s <0.5) {
happy--;
}
if (f <0.5) {
hungry--;
}
};
function healthStatus(){
if (health===4){
$(heart).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725918/virtual%20pet/l1.png");
}if(health===3){
$(heart).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725919/virtual%20pet/l2.png");
}if (health===2){
$(heart).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725919/virtual%20pet/l3.png");
}if(health===1){
$(heart).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725919/virtual%20pet/l4.png");
}if (health===0){
deathScreen();
}
};
function happyStatus(){
if (happy===4){
$(star).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725934/virtual%20pet/s1.png");
}if(happy===3){
$(star).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725934/virtual%20pet/s2.png");
}if (happy===2){
$(star).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725934/virtual%20pet/s3.png");
}if(happy===1){
$(star).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725934/virtual%20pet/s4.png");
}if (happy===0){
deathScreen();
}
};
function hungerStatus(){
if (hungry===4){
$(tummy).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725898/virtual%20pet/h1.png");
}if(hungry===3){
$(tummy).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725898/virtual%20pet/h2.png");
}if (hungry===2){
$(tummy).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725898/virtual%20pet/h3.png");
}if(hungry===1){
$(tummy).attr("src", "https://res.cloudinary.com/dytmcam8b/image/upload/v1561725898/virtual%20pet/h4.png");
}if (hungry===0){
deathScreen();
}
};
function deathScreen(){
$(start).hide();
$('#myModal').modal('show');
$(dead).text(c);
clearInterval(interv);
};
$(span).on("click", function(){
$('#myModal').modal('toggle');
});
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
$('#myModal').modal('toggle');
}
}
});
body {
margin: 0;
text-align: center;
}
h1 {
font-family: 'Barriecito', cursive;
text-align: center;
}
p {
font-family: 'Special Elite', cursive;
text-align: left;
}
#ageStatus {
top: -850px;
left: 150px;
position: relative;
font-size: 2em;
display: none;
}
.container {
width: 600px;
margin: 0 auto;
text-align: center;
}
.btn{
background-color: pink!important;
font-family: 'Barriecito', cursive;
}
#backing {
width: 800px;
margin: 0 auto;
z-index: -10;
position: relative;
top: 0px;
display: none;
}
#bennyNormal {
width:327px;
height: 444px;
display: none;
background-image:url("https://res.cloudinary.com/dytmcam8b/image/upload/v1561677299/virtual%20pet/Sheet.png");
top: -450px;
left:250px;
position: relative;
transform: scale(0.5);
-webkit-animation: benny 3s steps(10) infinite;
-moz-animation: benny 1.5s steps(10) infinite;
-ms-animation: benny 1.5s steps(10) infinite;
-o-animation: benny 1.5s steps(10) infinite;
animation: benny 1.5s steps(10) infinite;
}
#-webkit-keyframes benny{
from{background-position:0px;}
to{background-position:-3270px;}
}
}
#keyframes normal{
from {background-position:0px;}
to {background-position:-3270px;}
}
#heart {
height: 150px;
width: 150px;
transform: scale(0.5);
top: -970px;
left: 400px;
position: relative;
display: none;
}
#star {
height: 150px;
width: 150px;
top: -970px;
left: 350px;
transform: scale(0.5);
position: relative;
display: none;
}
#hungry {
height: 80px;
width: 80px;
position: relative;
left: 330px;
top: -970px;
display: none;
}
#age {
width: 250px;
position: relative;
top: 180px;
left: 100px;
display: none;
}
#medicine {
width: 100px;
position: relative;
top: -870px;
left: 150px;
display: none;
}
#toys {
width: 100px;
position: relative;
top:-1000px;
left:-50px;
display: none;
}
.action {
position: relative;
height: 400px;
width: 800px;
margin: 0 auto;
}
#food {
width: 100px;
position: relative;
left: 440px;
top: -1000px;
display: none;
}
#drink{
width: 100px;
position: relative;
left: 240px;
top: -900px;
display: none;
}
.hidden {
display: block;
}
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 100; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(242, 114, 223); /* Fallback color */
background-color: rgb(242, 114, 223); /* Black w/ opacity */
}
/* Modal Content/Box */
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid rgb(242, 114, 223);
width: 20%;
font-family: 'Barriecito', cursive;
font-size: 2em;
text-align: center;
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#dead {
text-align: center;
}
My x is non-responsive and neither can I click anywhere else on the screen to close it. There's no error message in Chrome developer. When I put my cursor over the x the link appears 'dead'.
Use .modal('toggle') according the docs here: https://getbootstrap.com/docs/4.0/components/modal/#modaltoggle
$('#myModal').modal('toggle');
But on the default modal behavior, when user click out the modal window (gray area) it is closed automatically, see this working here: https://jsfiddle.net/Lc8ayf9k/
Consider review the javascript and stylesheet references in your page
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
Try this
$('#myModal').modal('toggle');
If you are using Bootstrap, then the modal settings bootstrap.js file should be able to close the modal.
Here is an example of Bootstrap modal.
`<div id="myModal" class="modal fade" role='dialog'>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4>myModal</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" title="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>"Oh, no! You killed Benny!"<br>
"He was <span id="dead">x</span> days young"</p>
</div>
</div>
</div>
</div>`
If you need a custom JavaScript to close the modal, you can try out this script:
`<script type="text/javascript">
// Get the modal object
var modal = document.getElementById('myModal');
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
</script>`
I believe the way you attached your event listeners is wrong. If you're using vanilla javascript, you should assign the DOM inside a variable first:
var thisSpan = document.getElementById("close");
thisSpan.addEventListener("click", function(){
modal.style.display = "none";
});
With jQuery, it is a bit simpler, especially if you're using bootstrap modal plugin. You can follow the other solutions given by the fellow peers here. If it is a custom modal, then we can have a similar pattern as the previous code:
$("#close").on("click", function(){
modal.style.display = "none";
});

how to make hover captions work at tap on touch screens

I've created a gallery using just CSS that when a thumbnail is hovered on, the title slides into view. It sort of works on touch screens that if the button is touched and held, the title appears. I would like to make it so that a tap brings up the title and a second tap enters the gallery. I've tried all sorts of jQuery code but nothing seems to enable the second tap. I'd also wouldn't mind if it was one tap with a second or two delay to read the title before entering the gallery. I'm new to javascript and this site so I apologize if I don't ask this properly. Thanks for your help!
Here's my code:
<head>
<script src="js/jquery-1.12.0.min.js"></script>
<script type="text/javascript">
$("target").click(function(){ $(this).toggleClass("titleBox"); });
</script>
</head>
<body ontouchstart="" class="no-touch">
<div class="wrap">
<!-- Define all of the tiles: -->
<div class="box">
<div class="boxInner">
<a href="buildings/colorclock.html">
<img src="images/buildings/thumbs/06.jpg" alt="Color Clock House">
<div class="titleBox">Color Clock House</div>
</a>
</div>
</div>
<div class="box">
<div class="boxInner">
<a href="buildings/treetriangle.html">
<img src="images/buildings/thumbs/07.jpg" alt="Tree Triangle House">
<div class="titleBox">Tree Triangle House</div>
</a>
</div>
</div>
</div>
</body>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
.wrap {
overflow: hidden;
margin: auto;
padding: 0 10%;
margin-top: 40px;
}
.box {
float: left;
position: relative;
width: 20%;
padding-bottom: 20%;
}
.boxInner {
position: absolute;
left: 20px;
right: 20px;
top: 20px;
bottom: 20px;
overflow: hidden;
}
.boxInner img {
width: 100%;
}
.boxInner .titleBox {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin-bottom: -50px;
font-size: .9em;
background: #fff;
background-size: 105%;
color: #A59E97;
padding: 5px;
text-align: center;
-webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out;
-o-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
}
body.no-touch .boxInner:hover .titleBox, body.touch .boxInner.touchFocus .titleBox {
margin-bottom: 0;
}
.boxInner:focus {
cursor: pointer;
}
I was finally able to solve the click once, activate hover, click twice to to open the link on touch screens. If anyone is interested in the code here it is.
jQuery(function($) {
$('.boxInner').on("touchstart", function (e) {
'use strict'; //satisfy code inspectors
var link = $(this); //preselect the link
if (link.hasClass('hover')) {
return true;
} else {
link.addClass('hover');
$('a.taphover').not(this).removeClass('hover');
e.preventDefault();
return false;
}
});

Ability to flip div boxes, changing their size, and interacting with the content

I'm trying to create a design with small clickable div boxes, that once clicked they flip by 180° and show content. Content which you can interact with: like clicking links, copy text or change the content with the use of more buttons.
I've managed to accomplish this, but my question follows: Is there a better way for this?
Found this website of a basic example
But being CSS based the content on the other side isn't interactable.
This is the code:
HTML
<div id="saos">
<div id="pg1" style="display:none;">
<blockquote>Page1</blockquote><br>
Yay content.
</div>
<div id="pg2" style="display:none;">
<blockquote>Page2</blockquote><br>
More content.
</div>
<div class="x" style="display:none;" onclick="closePage()">
<p>X</p>
</div>
<div id="2" class="an2 start startbak" onclick="openPage()">
<p class="sp">Click!</p>
</div>
<div id="cont" style="display:none;">
<p class="sp">Click!</p>
</div>
</div>
CSS
.write {
position: absolute;
width: 100px;
height: 50px;
background: #0055ff;
-webkit-transition: all 1.5s cubic-bezier(.08, 1, .08, 1);
left: 10px;
text-align: center;
font-family: Verdana;
}
.write:hover {
-webkit-transform: perspective(600px)scale(1.2);
-moz-transform: perspective(600px)scale(1.2);
}
.write p {
color: #002164;
text-align: center;
margin-top: 10px;
font-size: 22px;
}
.an {
-webkit-transition: all 1.5s cubic-bezier(.08, 1, .08, 1);
}
.an2 {
-webkit-transition: all .5s ease;
}
.page {
background-color: rgba(17, 17, 17, .8);
position: absolute;
left: 120px;
border: 2px solid #252525;
height: 330px;
width: 530px;
overflow: auto;
font-size: 14px;
color: #818181;
}
.start {
text-align: center;
font-family: Verdana;
position: absolute;
top: 150px;
left: 290px;
height: 120px;
width: 120px;
-webkit-transform: perspective(600px)rotateY(180deg)translateZ(-10px);
-moz-transform: perspective(600px)rotateY(180deg);
}
.start:hover {
background-color: #0055ff;
cursor: pointer;
}
.startbak {
background-color: #0036a3;
}
.mainbak {
background: #252525;
}
.sp {
color: #002164;
margin-top: 43px;
font-size: 30px;
-webkit-transform: rotateY(180deg)rotateZ(-45deg)translateZ(-10px);
-moz-transform: rotateY(180deg)rotateZ(-45deg);
}
.frame {
top: 0px;
left: 0px;
position: absolute;
width: 751px;
height: 452px;
-webkit-transform: perspective(600px)rotateY(0deg);
-moz-transform: perspective(600px)rotateY(0deg);
}
.x {
position: absolute;
left: 700px;
height: 18px;
width: 45px;
background-color: #c75050;
color: #fff;
display: table;
text-align: center;
font-size: 10px;
font-family: Verdana;
z-index: 2;
}
.x:hover {
background-color: #e04343;
cursor: default;
}
.x:active {
background-color: #993d3d;
}
.x p {
display: table-cell;
vertical-align: middle;
}
JavaScript
var htmlString = '<div class="f an write" style="top: 10px;" name="Home" onClick="openTab(\'pg1\',\'0\')"><p>Home</p></div>\n'
htmlString += '<div class="f an write" style="top: 65px;" name="About" onClick="openTab(\'pg2\',\'1\')"><p>About</p></div>\n'
function openTab(id, n){
for (var i=0;i<write.length;i++){
write[i].className = 'f an write';
write[i].style.top = i*55+10+'px';
name = write[i].getAttribute('name');
write[i].innerHTML = '<p>'+name+'</p>';
}
write[n].className = 'f an page';
write[n].style.top = '10px';
write[n].innerHTML= '<div class="ins">'+document.getElementById(id).innerHTML+'</div>';
}
var id2 = document.getElementById('2'),
x = document.getElementsByClassName('x')[0];
function openPage(){
id2.className = 'an2 frame mainbak';
setTimeout(function() {
id2.className = 'an2 frame mainbak'
id2.setAttribute('onclick','')
document.getElementById('2').innerHTML=htmlString
}, 150);
setTimeout(function() {
x.style.display='';
}, 600);
}
function closePage(){
id2.className = 'an2 start mainbak';
setTimeout(function() {
id2.className = 'an2 start startbak'
id2.setAttribute('onclick','openPage()')
document.getElementById('2').innerHTML=document.getElementById('cont2').innerHTML
}, 150);
x.style.display='none';
}
Also made a JSFiddle but it doesn't seem to work..
While on my browser does.
It should be possible to do this with only a couple of lines of Javascript. Rich Bradshaw's example that you posted was an excellent starting point.
Rather than starting the flip on hover (via css selectors) I added a couple of lines of Javascript - actually jQuery, but plain JS would work - to add the relevant class on click. It works really nicely...
See jsFiddle Demo
I also managed to get the back face clickable (as in that demo) so it should meet all of your needs.
By that method the HTML is reduced to:
<div id="f1_container">
<div id="f1_card" class="shadow">
<div class="front face">
<img src="http://lorempixel.com/450/281/" />
</div>
<div class="back face center">
<p>This is nice for exposing more information about an image.</p>
<p>Any content can go here.</p>
<p>Including interactive HTML like
links</p>
</div>
</div>
</div>
And the Javascript is just:
$('#f1_container').click(function() {
$('#f1_container').addClass('clicked');
});

Categories