I'm creating a navigation for the site I'm building that currently slides in as an overlay from the left. What I'm trying to do, though, is get it to slide in from the top.
Below is the current CSS and JS for the menu specifically. I feel like it's simple to rotate where the menu comes in from, but I just can't figure it out.
CSS
.sidenav {
height: 100%;
width: 0;
position: fixed;
z-index: 10;
background-color: rgba(0,162,85,.9);
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
text-align: center;
}
.sidenav a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: #f1f1f1;
display: block;
transition: 0.3s;
}
.sidenav a:hover {
color: lightgray;
opacity: 1;
}
.sidenav .closebtn {
position: absolute;
top: 355px;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
JS
var menuItems = [
{
name: "HowToQuit",
openFunction: "openHow()",
closeFunction: "closeHow()",
state: false //closed
},
{
name: "StayingQuit",
openFunction: "openStay()",
closeFunction: "closeStay()",
state: false
},
{
name: "FactsAndMyths",
openFunction: "openFacts()",
closeFunction: "closeFacts()",
state: false
}
];
function openHow() {
document.getElementById("howtoquitnav").style.width = "100%";
document.getElementById("howtoquitnav").style.maxWidth = "1046px";
}
function closeHow() {
document.getElementById("howtoquitnav").style.width = "0";
}
function openStay() {
document.getElementById("stayquit").style.width = "100%";
document.getElementById("stayquit").style.maxWidth = "1046px";
}
function closeStay() {
document.getElementById("stayquit").style.width = "0";
}
function openFacts() {
document.getElementById("factsmyths").style.width = "100%";
document.getElementById("factsmyths").style.maxWidth = "1046px";
}
function closeFacts() {
document.getElementById("factsmyths").style.width = "0";
}
function handleMenuItem(menuItemName) {
for (var i = 0; i < menuItems.length; i++) {
if (menuItems[i].name === menuItemName && !menuItems[i].state) {
var open = new Function(menuItems[i].openFunction);
open();
menuItems[i].state = true;
} else {
var close = new Function(menuItems[i].closeFunction);
close();
menuItems[i].state = false;
}
}
}
Related
I have a function that turns an array into modal window links as a template literal.
The code that creates the links works fine outside of the function
But once it gets rendered in the function it no longer works. I can't find any errors, but it does NOT work.
However, if I copy the HTML that the function renders and save that as actual HTML, that works fine on its own.
A good chunk of the JavaScript portion of the code is posted below. A full version is on Codepen.
There are two sections in the example on Codepen:
The first section has the code as it's rendered by the function.
The second section is copied from the Elements tab in Developer Tools and saved as actual HTML.
"use strict";
const modalBtns = document.querySelectorAll(".modal-button");
const modalWin = document.querySelector(".modal-window");
const closeBtn = document.querySelector(".close-modal");
const modal_iframe = document.getElementById("modal_iframe");
modalBtns.forEach((item) => {
item.addEventListener("click", function (e) {
let modal = e.currentTarget;
if (modal.dataset.target) {
let modalID = modal.dataset.target;
document.getElementById(modalID).style.display = "block";
}
if (modal.dataset.iframe) {
modal_iframe.src = modal.dataset.iframe;
document
.querySelector(".button-footer")
.addEventListener("click", function () {
window.open(modal.dataset.iframe, "_blank");
});
}
if (modal.dataset.header) {
document.querySelector(
".modal-header"
).innerHTML = `<h1>${modal.dataset.header}</h1>`;
}
if (modal.dataset.dimensions) {
document
.querySelector(".modal-window")
.setAttribute("style", modal.dataset.dimensions);
}
function loadIframe() {
let frame = document.getElementById("modal_window");
frame.style.height =
frame.contentWindow.document.body.scrollHeight + "px";
}
if (document.querySelector("#modal_window")) {
setTimeout(function () {
loadIframe;
}, 2000);
}
if (modal.dataset.reload && modal.dataset.reload === "1") {
document
.querySelector(".close-modal")
.addEventListener("click", function (e) {
console.log("parent.location.reload() pending...");
parent.location.reload();
});
}
/*======= All EventListeners Below Close Modal ================*/
closeBtn.addEventListener("click", function (e) {
document.querySelector(".modal-background").style.display = "none";
});
window.addEventListener("click", function (e) {
if (e.currentTarget === document.querySelector(".modal-background")) {
document.querySelector(".modal-background").style.display = "none";
}
});
document.body.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
document.querySelector(".modal-background").style.display = "none";
}
});
});
});
const main = document.querySelector("main");
const modal_links = [
{
link: "https://notation.netcentrx.net/staff/",
header: "Musical Staff",
thb: "notation",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
},
{
link: "https://wsl.netcentrx.net/",
header: "WSL Commands",
thb: "wsl",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
}
];
let modalLink = "";
function createModalLinks(
link,
modalID,
header,
img,
w_h = "width:90vw;height:600px",
reload = "0"
) {
modalLink = `
<a href="javascript:void(0)" class="modal-button" onclick="console.log('onclick handler:${link}');" data-header="${header}" data-target="${modalID}" data-iframe="${link}" data-dimensions="${w_h};margin-top:20px" data-reload="${reload}">
<img src="https://resume.netcentrx.net/examples/${img}.jpg" title="${img}" width="50">
</a>
`;
return modalLink;
}
let theLinks = "";
modal_links.forEach((item) => {
theLinks += createModalLinks(
item.link,
"modal_window",
item.header,
item.thb,
item.w_h,
item.reload
);
});
main.innerHTML = theLinks;
My apologies in advance for it not being stripped down to just the bare minimum. But in order to replicate the problem, it required more code than it probably should have had. I've been reworking this for the better part of a day without any insight as to what the real problem is. I've been creating functions using template literals just like this for years now, usually with a high success rate. Whatever the problem is, I need to know so I can get past it. The only anomaly that I spotted is that–in the version on Codepen–the only thing that doesn't work in that version is once the modal is displayed clicking on the background does not dismiss the modal like it does elsewhere. If that's significant as to what the problem may be, I'm not sure what the connection is.
Usually when I take the time to painstakingly write everything out like this I typically either spot the problem or figure out an alternative solution so there's no need to actually post a question, but this does not appear to be one of those times. As always, your help is very much appreciated!
The issue appears to just be timing. Your code is executed in order, and the first part gets all of the modal buttons on the page and sets the appropriate event listeners. Then the second part of your code adds 2 modal buttons, which were not present earlier.
By simply wrapping the first part of your code in a function and calling it later (or swapping the order of those two parts of code), everything works as expected.
"use strict";
const _InitModal = () => {
const modalBtns = document.querySelectorAll(".modal-button");
const modalWin = document.querySelector(".modal-window");
const closeBtn = document.querySelector(".close-modal");
const modal_iframe = document.getElementById("modal_iframe");
modalBtns.forEach((item) => {
item.addEventListener("click", function (e) {
console.log("e.currentTarget = " + e.currentTarget);
let modal = e.currentTarget;
console.log("modal = " + modal);
if (modal.dataset.target) {
let modalID = modal.dataset.target;
console.log("modal.dataset.target = " + modal.dataset.target);
document.getElementById(modalID).style.display = "block";
}
if (modal.dataset.iframe) {
modal_iframe.src = modal.dataset.iframe;
document
.querySelector(".button-footer")
.addEventListener("click", function () {
window.open(modal.dataset.iframe, "_blank");
});
}
if (modal.dataset.header) {
document.querySelector(
".modal-header"
).innerHTML = `<h1>${modal.dataset.header}</h1>`;
console.log(`modal.dataset.header = ${modal.dataset.header}`);
}
if (modal.dataset.dimensions) {
document
.querySelector(".modal-window")
.setAttribute("style", modal.dataset.dimensions);
}
function loadIframe() {
let frame = document.getElementById("modal_window");
frame.style.height =
frame.contentWindow.document.body.scrollHeight + "px";
}
if (document.querySelector("#modal_window")) {
setTimeout(function () {
loadIframe;
}, 2000);
}
// e.preventDefault();
if (modal.dataset.reload && modal.dataset.reload === "1") {
document
.querySelector(".close-modal")
.addEventListener("click", function (e) {
console.log("parent.location.reload() pending...");
parent.location.reload();
});
}
/*======= All EventListeners Below Close Modal ================*/
closeBtn.addEventListener("click", function (e) {
document.querySelector(".modal-background").style.display = "none";
});
window.addEventListener("click", function (e) {
console.log("e.currentTarget = " + e.currentTarget);
if (e.currentTarget === document.querySelector(".modal-background")) {
document.querySelector(".modal-background").style.display = "none";
}
});
document.body.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
console.log("e=" + e);
document.querySelector(".modal-background").style.display = "none";
}
});
});
});
}
const main = document.querySelector("main");
const modal_links = [
{
link: "https://notation.netcentrx.net/staff/",
header: "Musical Staff",
thb: "notation",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
},
{
link: "https://wsl.netcentrx.net/",
header: "WSL Commands",
thb: "wsl",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
}
];
function createModalLinks(
link,
modalID,
header,
img,
w_h = "width:90vw;height:600px",
reload = "0"
) {
let modalLink = "";
modalLink = `
<a href="javascript:void(0)" class="modal-button" onclick="console.log('onclick handler:${link}');" data-header="${header}" data-target="${modalID}" data-iframe="${link}" data-dimensions="${w_h};margin-top:20px" data-reload="${reload}">
<img src="https://resume.netcentrx.net/examples/${img}.jpg" title="${img}" width="50">
</a>`;
return modalLink;
}
let theLinks = "";
modal_links.forEach((item) => {
theLinks += createModalLinks(
item.link,
"modal_window",
item.header,
item.thb,
item.w_h,
item.reload
);
});
main.innerHTML = theLinks;
_InitModal();
.modal-background {
font-family: sans-serif;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
overflow: auto;
background-color: rgba(0, 0, 0, 0.9);
z-index: 9999;
background: rgba(55, 55, 55, 0.6);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.modal-window {
position: relative;
background-color: #ffffff;
width: 50%;
margin: 10% auto;
border-radius: 0.5rem;
padding: 0.75rem;
border: 1px groove #ccc;
/* box-shadow: 1px 1px 1px #999, 2px 2px 2px #000; */
}
.close-modal:hover,
.close-modal:focus {
color: rgba(255, 255, 255, 1);
cursor: pointer;
background: red;
transition: 1s;
text-shadow: 1px 1px 1px #999, 2px 2px 2px #000;
}
button.close-modal {
position: absolute;
top: -0.75rem;
right: -0.75rem;
padding: 0.05rem 0.75rem;
background: #999;
color: #ccc;
border-radius: 50%;
border: none;
outline: none;
-webkit-transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1.5s;
animation-name: animatebottom;
animation-duration: 1.5s;
}
button.close-modal::before {
content: "\D7";
font-size: 2rem;
}
.modal-window {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
-webkit-animation-name: animatetop;
-webkit-animation-duration: 0.5s;
animation-name: animatetop;
animation-duration: 0.5s;
}
.modal-header {
height: 30px;
text-align: center;
width: 100%;
background: #fff;
padding: 0.2rem;
}
.modal-header h1 {
font-size: 1.1rem;
}
.modal-footer {
height: 20px;
text-align: center;
width: 100%;
background: #fff;
padding: 0.2rem;
}
.modal-content {
background-color: #fff;
height: calc(100% - 70px);
border-radius: 0.5rem;
border: 0.1rem groove #ddd;
overflow: hidden;
}
.button-footer {
background: #fff;
border-radius: 0.5rem;
border: 1px outset #aaa;
padding: 0.2rem;
color: #999;
transition: 1s;
cursor: pointer;
}
.button-footer:hover {
background: #fdfdfd;
color: #555;
border: 1px inset #ddd;
text-shadow: 0.05rem 0.05rem 0.05rem #ccc, 0.055rem 0.055rem 0.055rem #999,
0.06rem 0.06rem 0.06rem #333;
transition: 1s;
}
.close-btn:hover {
color: white;
background: #f00;
cursor: pointer;
}
#modal_iframe {
width: 100%;
height: 100%;
}
button.modal-button {
border-radius: 0.5rem;
border: 0px solid #aaa;
padding: 0;
cursor: pointer;
}
.modal-button-img {
border-radius: 0.5rem;
border: 0.1rem groove #444;
cursor: pointer;
}
.sepia:hover {
filter: sepia(150%);
}
/*
.none {
display: none;
}
*/
#-webkit-keyframes animatetop {
from {
top: -300px;
opacity: 0;
}
to {
top: 0;
opacity: 1;
}
}
#keyframes animatetop {
from {
top: -300px;
opacity: 0;
}
to {
top: 0;
opacity: 1;
}
}
#-webkit-keyframes animatebottom {
from {
top: 0;
opacity: 1;
}
to {
bottom: -300px;
opacity: 0;
}
}
#keyframes animatebottom {
from {
top: 0;
opacity: 1;
}
to {
bottom: -300px;
opacity: 0;
}
}
.container {
border-radius: 0.5rem;
border: 1px solid #aaa;
max-width: 800px;
width: 500px;
margin: 0 auto;
text-align: center;
font-family: sans-serif;
}
main,
aside {
font-family: sans-serif;
max-width: 800px;
width: 500px;
margin: 0 auto;
text-align: center;
}
h2 {
text-align: center;
font-family: sans-serif;
font-weight: normal;
font-size: 1.2rem;
}
span {
font-size: 75%;
background: #ffff0055;
}
<div id="modal_window" class="modal-background">
<div class="modal-window">
<button class="close-modal" data-dismiss="modal"></button>
<div class="modal-header"></div>
<div class="modal-content">
<iframe src="#" id="modal_iframe" frameborder="0">If you'd have had a real browser, I wouldn't be boring you with this now...</iframe>
</div>
<div class="modal-footer"><button class="button-footer">Open In New Tab</button></div>
</div>
</div>
<div class="container">
<h2><code>main</code> Content Rendered By JavaScript</h2>
<main>
Main
</main>
<span>working now</span>
</div>
When I first load page the game works but when I change grid the game cards don't flip. I'm not sure if it the use of onchange inside the select tag or it something else. If I change the value of a variable named value inside displayCardsDiv manual it also works fine maybe if I could find a way to update it by dropddown list or button click it will work.
Html
<div class="game-container" >
<script>displayCardsDiv();</script>
<div ></div>
</div>
</div>
<div class="game-title">
<label class="changeGrid">change Grid</label>
<select id="grid" name="grid" onchange="displayCardsDiv()">
<option value="first" id="first">2x2</option>
<option value="second" id="second">3x2</option>
<option value="third" id="third">4x3</option>
</select>
<button class="reset-btn" onclick="resetGame()">Reset</button>
</div>
<script src="./src/script.js"></script>
</body>
Javascript
"src/img/apple-eye.png",
"src/img/apple-eye.png",
"src/img/blue-nife.png",
"src/img/blue-nife.png",
"src/img/devil.png",
"src/img/devil.png",
"src/img/headless.png",
"src/img/headless.png",
"src/img/heart.png",
"src/img/heart.png",
"src/img/mommy.png",
"src/img/mommy.png",
];
class MemoryGame {
constructor() {
this.cardsArray = playCard;
}
beforeGameStart() {
this.cardChecker = null;
this.matchingCardsArray = [];
this.isLocked = true;
setTimeout(() => {
this.shuffleCards(this.cardsArray);
this.isLocked = false;
}, 500);
}
handleCardFlip(card) {
if (this.flipCard(card)) {
card.classList.add("showingCard");
if (this.cardChecker) {
this.checkForMatch(card);
} else {
this.cardChecker = card;
}
}
}
checkForMatch(card) {
if (this.findTypeOfCard(card) === this.findTypeOfCard(this.cardChecker))
this.matchCards(card, this.cardChecker);
else this.misMatchCards(card, this.cardChecker);
this.cardChecker = null;
}
matchCards(firstCard, secondCard) {
this.matchingCardsArray.push(firstCard);
this.matchingCardsArray.push(secondCard);
firstCard.classList.add("matched");
secondCard.classList.add("matched");
setTimeout(() => {
if (this.matchingCardsArray.length === this.cardsArray.length) {
alert("All cards matched");
resetGame();
}
}, 1000);
}
misMatchCards(firstCard, secondCard) {
this.isLocked = true;
setTimeout(() => {
firstCard.classList.remove("showingCard");
secondCard.classList.remove("showingCard");
this.isLocked = false;
}, 1000);
}
shuffleCards(cardsArray) {
cardsArray.forEach((card) => {
let randomPos = Math.floor(Math.random() * cardsArray.length);
card.style.order = randomPos;
});
}
findTypeOfCard(card) {
return card.getElementsByClassName("value")[0].src;
}
flipCard(card) {
return (
!this.isLocked &&
!this.matchingCardsArray.includes(card) &&
card !== this.cardChecker
);
}
}
function resetGame() {
location.reload();
}
let gameContainer = document.querySelector(".game-container");
function twoByTwoGrid() {
gameContainer.style.gridTemplateColumns = "repeat(2, auto)";
return imagesArray.slice(0, 4);
}
function threeByTwoGrid() {
gameContainer.style.gridTemplateColumns = "repeat(3, auto)";
return imagesArray.slice(0, 6);
}
function displayCardsDiv() {
let deckOfCards = [];
let displayGameCards = "";
let value = document.querySelector("#grid").value;
if (value == "first") {
deckOfCards = twoByTwoGrid();
}
if (value === "second") {
deckOfCards = threeByTwoGrid();
}
if (value !== "first" && value !== "second") {
gameContainer.style.gridTemplateColumns = "repeat(4, auto)";
deckOfCards = [...imagesArray];
}
for (let i in deckOfCards) {
displayGameCards += `<div class="card">
<div class="card-back card-face"><img class="demonsCards" src="src/img/demons.png"></div>
<div class="card-front card-face"><img class="value" src="${deckOfCards[i]}"></div>
</div>`;
}
document.getElementsByClassName("game-container")[0].innerHTML =
displayGameCards;
}
displayCardsDiv();
const playCard = document.querySelectorAll(".card");
const game = new MemoryGame(playCard);
game.beforeGameStart();
for (let i = 0; i < imagesArray.length; i++) {
playCard[i].addEventListener("click", () => game.handleCardFlip(playCard[i]));
}
module.exports = { game };
CSS
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
min-height: 100vh;
}
body {
margin: 0;
background: radial-gradient(#46bddb, #4672db);
}
h1{
background: -webkit-repeating-linear-gradient(#eee, #333);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
img {
height: 175px;
width: 125px;
}
.game-title {
color: aliceblue;
font-family: 'Noto Sans Mono', monospace;
font-weight: normal;
text-align: center;
font-size: 4em;
margin-top: 0px;
}
.game-info-container {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
}
.game-info {
font-family: 'Pacifico', cursive;
color: aliceblue;
font-size: 4em;
}
.changeGrid{
font-size: large;
}
.game-container {
margin: 50px auto;
display: grid;
grid-template-columns:repeat(4, auto);
grid-gap: 10px;
justify-content: center;
perspective: 500px;
}
.card {
position: relative;
height: 175px;
width: 125px;
cursor: pointer;
}
.card-face {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
border-radius: 12px;
border-width: 1px;
border-style: solid;
overflow: hidden;
transition: transform 500ms ease-in-out;
backface-visibility: hidden;
}
.card.showingCard .card-back {
transform: rotateY(180deg);
}
.card.showingCard .card-front {
transform: rotateY(0);
}
.card-back {
background-color:aliceblue;
border-color: aliceblue;
transform: rotateY(0);
}
.demonsCards {
align-self: flex-start;
transition: transform 100ms ease-in-out;
transform: translateY(-10px);
}
.card:active {
transform: scale(0.79);
transition: transform .1s;
}
.card-front:hover .card-value {
transform: scale(1);
}
.card-front {
background-color: #FFBB89;
border-color: #333;
transform: rotateY(-180deg);
}
#media (max-width: 600px) {
.game-container {
grid-template-columns: repeat(2, auto)
}
.game-info-container {
flex-direction: column;
align-items: center;
}
}
I'm trying to convert the product-page tabs to an accordion on my Woocommerce store, but things won't work. When i click on my links, the dropdown doesn't show, it doesn't do nothing ... The height should animate as well as my "+" icon, but nothing happens. It looks like it doens't wnat to add the "is-open" class on the clicked element. So i think my error lies in my js, but i don't see where!
Here's my tabs.php file :
<?php
/**
* Single Product tabs
*
* This template can be overridden by copying it to yourtheme/woocommerce/single-product/tabs/tabs.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #package WooCommerce\Templates
* #version 3.8.0
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Filter tabs and allow third parties to add their own.
*
* Each tab is an array containing title, callback and priority.
*
* #see woocommerce_default_product_tabs()
*/
$product_tabs = apply_filters('woocommerce_product_tabs', array());
if (!empty($product_tabs)) : ?>
<div class="c-accordion">
<div class="c-accordion__wrapper">
<div class="c-accordion__content-wrapper">
<?php foreach ($product_tabs as $key => $product_tab) : ?>
<div class="c-accordion__content js-accordion">
<div class="c-accordion__content-title">
<span class="c-accordion__plus"></span>
<p class="u-a1">
<?php echo wp_kses_post(apply_filters('woocommerce_product_' . $key . '_tab_title', $product_tab['title'], $key)); ?>
</p>
</div>
<div class="c-accordion__content-main js-content">
<?php
if (isset($product_tab['callback'])) {
call_user_func($product_tab['callback'], $key, $product_tab);
}
?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
Here's my js :
// Custom Tabs
('use strict');
var Accordion = /** #class */ (function () {
function Accordion() {
this.items = document.querySelectorAll('.js-accordion');
this.itemClass = '.js-accordion';
this.contentWrapperClass = '.js-content';
this.css = {
open: 'is-open',
};
if (this.items.length > 0) {
this.init();
}
}
Accordion.prototype.init = function () {
var _this = this;
for (var i = 0; i < this.items.length; i++) {
this.items[i].addEventListener('click', function (ev) {
ev.preventDefault();
var current = ev.currentTarget;
var contentWrapper = current.querySelector(_this.contentWrapperClass);
if (!current.classList.contains(_this.css['open'])) {
_this.slideDown(current, contentWrapper);
return;
}
_this.closeItem();
});
}
};
Accordion.prototype.getActiveElement = function () {
var accordionItems = document.querySelectorAll('' + this.itemClass);
var active = null;
for (var i = 0; i < accordionItems.length; i++) {
if (accordionItems[i].classList.contains(this.css['open'])) {
active = accordionItems[i];
}
}
return active;
};
Accordion.prototype.slideDown = function (element, content) {
var _this = this;
var contentHeight = 0;
var active = this.getActiveElement();
for (var i = 0; i < this.items.length; i++) {
this.items[i].classList.remove(this.css['open']);
}
element.classList.add(this.css['open']);
if (active) {
var activeContent = active.querySelector(this.contentWrapperClass);
TweenMax.to(activeContent, 0.6, {
height: 0,
onStart: function () {
_this.openItem(content, contentHeight);
},
});
return;
}
// else
this.openItem(content, contentHeight);
};
Accordion.prototype.openItem = function (content, contentHeight) {
TweenMax.set(content, {
height: 'auto',
onComplete: function () {
contentHeight = content.clientHeight;
TweenMax.set(content, {
height: 0,
onComplete: function () {
TweenMax.to(content, 0.4, {
height: contentHeight,
onComplete: function () {
TweenMax.set(content, {
height: 'auto',
});
},
});
},
});
},
});
};
Accordion.prototype.closeItem = function () {
var active = this.getActiveElement();
if (active) {
var activeContent = active.querySelector(this.contentWrapperClass);
active.classList.remove(this.css['open']);
TweenMax.to(activeContent, 0.6, {
height: 0,
});
}
};
return Accordion;
})();
new Accordion();
and here's my css (scss) :
.c-accordion {
max-width: 100%;
width: 100%;
font-family: helvetica;
&__wrapper {
display: flex;
flex-wrap: wrap;
justify-content: center;
height: auto;
}
&__content-wrapper {
flex: 1 0 100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-start;
align-items: stretch;
align-content: stretch;
}
&__content-title {
position: relative;
transition: 0.3s;
padding-top: 10px;
padding-bottom: 10px;
padding-left: percentage(1/15);
}
&__content-main {
height: 0;
overflow: hidden;
padding-left: percentage(1/15);
display: flex;
flex-wrap: wrap;
p {
max-width: 300px;
}
}
&__content {
position: relative;
overflow: hidden;
cursor: pointer;
flex: 1 0 auto;
&:first-of-type {
&:before {
display: none;
}
}
&:before {
content: '';
width: 100%;
border-top: 2px solid $black;
position: absolute;
left: 0;
top: 0;
}
&:last-child {
&:after {
content: '';
width: 100%;
border-top: 2px solid $black;
position: absolute;
left: 0;
bottom: 0;
}
}
&__text {
padding-top: 10px;
padding-bottom: 20px;
line-height: 1.38;
}
&:hover {}
&.is-open {
transition: 0.3s;
.c-accordion {
&__plus {
transform: translateY(-50%) rotate(90deg);
&:after {
opacity: 0;
}
}
&__content-main {
height: auto;
}
}
}
}
&__plus {
width: 3vh;
height: 3vh;
position: absolute;
left: 0px;
top: 50%;
cursor: pointer;
opacity: 1;
transform: translateY(-50%) rotate(0deg);
transition: 0.4s;
&:before {
content: '';
height: 100%;
border-left: 2px solid $black;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
opacity: 1;
}
&:after {
content: '';
width: 100%;
border-top: 2px solid $black;
position: absolute;
opacity: 1;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.2s;
}
}
&__left {
padding-top: 10px;
padding-bottom: 75px;
width: percentage(6/14);
padding-right: 10px;
}
&__right {
padding-top: 10px;
padding-bottom: 75px;
width: percentage(8/14);
padding-right: 10px;
}
}
Does someone have any idea what i'm doing wrong ?
Thanks a lot !
Fixed, the error wasn't with this JS but there was a conflict with another plugin. Solved
I'm trying to implement a way to display / hide a div element with vanilla JavaScript triggered by a click event. The hide function works well but I seem to be missing something important when it comes to displaying the div's again. I've verified that the toggler function is working.
Simple sandbox here:
https://codepen.io/pen/eYmOzVe
(function() {
"use strict";
// HTML References
var flags = document.querySelector(".flags");
// Toogle
var toogle = true;
// Flag object
var flagObject = {
init: function(part1, part2, part3, part4, part5) {
this.part1 = part1;
this.part2 = part2;
this.part3 = part3;
this.part4 = part4;
this.part5 = part5;
},
draw: function() {
flags.innerHTML += `
<div id="${this.part1}">
<div class="${this.part2}">
<div class="${this.part3}"></div>
<div class="${this.part4}"></div>
<div class="${this.part5}"></div>
</div>
</div>
`;
},
toogler: function(arg) {
toogle ? flagObject.remove(arg) : flagObject.show(arg);
toogle = !toogle;
},
remove: function(arg) {
if (arg == "1") {
flag1Element.style.visibility = "hidden";
}
if (arg == "2") {
flag2Element.style.visibility = "hidden";
}
},
show: function(arg) {
if (arg == "1") {
flag1Element.style.visibility = "visible";
}
if (arg == "2") {
flag2Element.style.visibility = "visible";
}
}
};
// Create instances of the object
var swedishFlag = Object.create(flagObject);
var japaneseFlag = Object.create(flagObject);
// Init
swedishFlag.init(
"flag1",
"flag-sweden",
"cross-one-sweden",
"cross-two-sweden"
);
japaneseFlag.init("flag2", "flag-japan", "circle-japan");
// Array containing all flags
var allObjects = [swedishFlag, japaneseFlag];
// Draws flags
for (let i = 0; i < allObjects.length; i++) {
allObjects[i].draw();
}
// HTML element refrences
var flag1Element = document.querySelector("#flag1");
var flag2Element = document.querySelector("#flag2");
// Add eventlisteners to remove flags on click
flag1Element.addEventListener("click", function() {
flagObject.toogler(1);
});
flag2Element.addEventListener("click", function() {
flagObject.toogler(2);
});
})();
h1 {
text-align: center;
}
h3 {
color: green;
}
.content {
border: 1px solid black;
background-color: #eee;
padding: 2em;
margin: 0 auto;
height: 1000px;
width: 800px;
border-radius: 30px;
text-align: center;
}
.flags {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
height: 1000px;
}
.flag-sweden {
position: relative;
background-color: #006aa7;
height: 200px;
width: 320px;
margin-bottom: 2em;
}
.cross-one-sweden {
background-color: #fecc00;
position: absolute;
width: 40px;
height: 200px;
top: 0;
left: 100px;
}
.cross-two-sweden {
background-color: #fecc00;
position: absolute;
width: 320px;
height: 40px;
top: 80px;
left: 0;
}
.flag-japan {
position: relative;
height: 200px;
width: 320px;
background-color: white;
margin-bottom: 2em;
}
.circle-japan {
background-color: #bd0029;
height: 125px;
width: 125px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
margin: -62.5px 0 0 -62.5px;
}
<h1>Sandbox</h1>
<div id="content" class="content">
<div class="flags"></div>
</div>
As Pavlin Petkov said in the comments, the image is not clickable when you hide it, so you can't toggle it back on. A simple solution to this that achieves the same result is to change the opacity instead of the visibility:
remove: function(arg) {
if (arg == "1") {
flag1Element.style.opacity = 0;
}
if (arg == "2") {
flag2Element.style.opacity = 0;
}
},
show: function(arg) {
if (arg == "1") {
flag1Element.style.opacity = 1;
}
if (arg == "2") {
flag2Element.style.opacity = 1;
}
}
This will display/hide a div with a click effect, and it will continue to occupy space on the page, as in your codepen. If you need to use visibility for some reason, I'd recommend a container div beneath the now hidden div which can trigger the show function; however, for the question at hand, this is sufficient.
I would please like an explanation to why the slideshow is not working. Below I have used an interval to perpetually change the slideshow, if userClick is false. The white and squared buttons (made of divs) are set to call upon two functions; slideRight() or slideLeft() and clicked(). When the buttons are clicked however, the clicked() function does not seem to change the variable, based on the data on top of the page.
<body>
<div class="page-wrapper">
<header>
<div class="headContent">
<h1 class="titleText">Slideshow</h1>
<h2 class="subTitleText">A slideshow made with JavaScript.</h2>
<p>userClick <span id="uc"></span></p>
</div>
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Gallery</li>
</ul>
</nav>
</header>
<div class="body-wrapper">
<h1 class="titleText">Slideshow</h1>
<div id="slideshow">
<div id="leftSlide" onclick="leftSlide(); clicked()"></div>
<div id="rightSlide" onclick="rightSlide(); clicked()"></div>
</div>
<p>The image is not invoked by a tag, but invoked by the background property using Javascript.</p>
</div>
<footer>
<p id="footerText">© 2017 <br>Designed by JastineRay</p>
</footer>
</div>
<script language="javascript">
// Slide function
var slide = ["minivan", "lifeinthecity", "sunsetbodyoflove"];
var slideTo = 1;
window.onload = getSlide();
// Previous Image
function leftSlide() {
if (slideTo != 0) {
slideTo = slideTo - 1;
} else if (slideTo == 0) {
slideTo = slide.length - 1;
} else {
alert('SLIDE ERROR');
}
getSlide();
}
// Next Image
function rightSlide() {
if (slideTo != (slide.length - 1)) {
slideTo = slideTo + 1;
} else if (slideTo == (slide.length - 1)) {
slideTo = 0;
} else {
alert('SLIDE ERROR');
}
getSlide();
}
function getSlide() {
imageURL = 'url(images/' + slide[slideTo] + '.jpg)';
document.getElementById("slideshow").style.backgroundImage = imageURL;
}
// Interval Slideshow & Check if user clicked (timeout)
var userClick = false;
window.onload = slideInterval(5000);
// Start Slideshow
function slideInterval(interval) {
while (userClick = false) {
setInterval(function() {
rightSlide();
}, interval)
}
}
// Stop Slideshow and start timeout
function clicked() {
userClick = true;
setTimeout(function() {
userClick = false;
slideInterval();
}, 2000)
}
window.onload = function() {
setInterval(document.getElementById("uc").innerHTML = userClick), 100
}
</script>
</body>
CSS coding below.
* {
margin: 0;
padding: 0;
}
.page-wrapper {
width: 100%;
}
// Class Styling
.titleText {
font-family: monospace;
font-size: 40px;
}
.subTitleText {
font-family: monospace;
font-size: 20px;
font-weight: normal;
}
// Header Styling
header {
height: 500px;
}
.headContent {
margin: 30px 7%;
}
// Navigation Styling
nav {
overflow: hidden;
}
nav ul {
background: black;
background: linear-gradient(#595959, black);
list-style-type: none;
font-size: 0;
padding-left: 13.33%;
margin: 40px 0;
}
nav ul li {
padding: 15px 20px;
border-right: 1px solid #595959;
border-left: 1px solid #595959;
color: white;
display: inline-block;
font-size: 20px;
font-family: sans-serif;
}
// Body Styling
.body-wrapper {
}
.body-wrapper > .titleText {
text-align: center;
font-size: 50px;
}
#slideshow {
overflow: hidden;
margin: 20px auto;
border: 2px solid blue;
height: 350px;
max-width: 800px;
background-size: cover;
background-position: center;
position: relative;
}
#leftSlide {
position: absolute;
left: 40px;
top: 175px;
background-color: white;
height: 40px;
width: 40px;
}
#rightSlide {
position: absolute;
left: 100px;
top: 175px;
background-color: white;
height: 40px;
width: 40px;
}
// Footer Styling
Try changing the checking part to:
window.onload = function() {
setInterval(function () {
document.getElementById("uc").innerHTML = userClick;
}, 100);
}
The first argument of setInterval has to be a function (something that can be called), not a generic piece of code.