Nested accordion not expanding properly javascript - javascript

I have created a nested accordion using HTML/CSS and javascript. I have multiple main accordions with 2 sub-accordions in each. My intended result is to expand the sub-accordions and have the next main accordion shift down, however the actual result is that the main accordion does not move down and the sub-accordions aren't expanding properly.
If you run my fiddle example, clicking the first sub-accordion pushes down the second sub-accordion but doesn't push Main#2, and the second sub-accordion doesn't expand on either Main#1 or Main#2.
If someone could help point me in the right direction here I'd really appreciate it! Thanks!
Link to fiddle
HTML:
<div class="collapsible">
<h3><strong>Main#1</strong></h3>
</div>
<div class="content">
<div class="collapsible">
<h4>Sub#1</h4>
</div>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
</div>
<div class="collapsible">
<h4>Sub#2</h4>
</div>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
</div>
</div>
<div class="collapsible">
<h3><strong>Main#2</strong></h3>
</div>
<div class="content">
<div class="collapsible">
<h4>Sub#1</h4>
</div>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
</div>
<div class="collapsible">
<h4>Sub#2</h4>
</div>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
</div>
</div>
CSS:
.collapsible {
background-color: white;
color: black;
cursor: pointer;
padding: 1vw;
width:97%;
height: 60px;
max-height: 100%;
margin: 5px 10px 5px 10px;
border: 2px solid black;
text-align: left;
outline: none;
font-size: 25px;
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
background-color: white;
transition: max-height 0.2s ease-out;
}
h3{
display:inline-block;
vertical-align: middle;
}
h4{
display:inline-block;
vertical-align: middle;
font-size: 22px;
}
Javascript:
$(function() {
var coll = document.getElementsByClassName("collapsible");
//setting buttons of class 'collapsible' to extend on click
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function () {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
});

I made some changes in your code.
I add this part to your CSS:
.collapsible ~ .content{
height: 0px;
}
.collapsible.active + .content{
height: 100%;
}
Commented the 'max-height' line:
.content {
padding: 0 18px;
overflow: hidden;
/*max-height: 0;*/
background-color: white;
transition: max-height 0.2s ease-out;
}
And simplify the JS:
$(function() {
var coll = document.getElementsByClassName("collapsible");
//setting buttons of class 'collapsible' to extend on click
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function () {
this.classList.toggle("active");
});
}
});
Here you can check the changes:
https://jsfiddle.net/xpvt214o/501924/
With this, the hide and show is controlled by CSS.
Hope this help you.

Related

Place (fixed) dropdown menus with javascript to avoid z-index inheritance issues

I am working on a project that includes pages to view and select actions on multiple different entities of the same category set. Those entities are presented in the form of cards (e.g. employees, projects etc). On each card there is a classic gear button that expands a hidden drop menu so that the user can select actions (which might be the same or different for each entity/card). In order to avoid z-index inheritance issues (e.g. drop menu appearing on top of the parent but behind the sibling card) I implemented the solution presented in the link below (minimal representation).
The solution seems to be working fine, but i am wondering if it is elegant / acceptable in the context of implementing it on a production environment. If someone could comment on it or propose other solutions if this is not "acceptable" that would be great.
function getFixedElementPosition(el, menuid) {
var dropmenu = document.getElementById(`dropmenu${menuid}`);
if (dropmenu.style.display === "" || dropmenu.style.display === "none") {
var pos = el.getBoundingClientRect();
dropmenu.style.top = `${pos.bottom}px`;
dropmenu.style.left = `${pos.right}px`;
dropmenu.style.display = "block";
} else {
dropmenu.style.display = "none";
}
};
.card {
width: 225px;
height: 295px;
background: #fff;
float: left;
padding: 20px;
margin: 15px;
box-shadow: rgba(100, 100, 111, 0.2) 0px 0px 20px 0px;
transition: all 0.25s linear 0s;
position: relative;
border: 2px solid transparent;
backface-visibility: hidden;
-webkit-font-smoothing: subpixel-antialiased;
}
.card:hover {
box-shadow: rgb(38, 57, 77) 0px 2px 30px -10px;
}
.gear {
cursor: pointer;
float: right;
}
.dropmenu {
display: none;
position: absolute;
background: #fff;
box-shadow: rgba(100, 100, 111, 0.2) 0px 0px 20px 0px;
width: 80px;
padding: 10px;
z-index: 10;
}
a {
text-decoration: none;
display: block;
transition: all 0.2s linear;
}
a:hover {
color: #003a95;
}
p {
margin: 35px 10px;
}
<div class="wrapper">
<div class="card">
<img class="gear" onclick="getFixedElementPosition(this, 1)" src="https://www.indivstock.com/static35/preview2/stock-vector-gear-icon-illustrated-in-vector-on-white-background-520258.jpg" width="34">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt</p>
</div>
<!-- /Card #1 -->
<div id="dropmenu1" class="dropmenu" onmouseleave="this.style.display='none';">
View
Edit
Delete
</div>
<div class="card">
<img class="gear" onclick="getFixedElementPosition(this, 2)" src="https://www.indivstock.com/static35/preview2/stock-vector-gear-icon-illustrated-in-vector-on-white-background-520258.jpg" width="34">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt</p>
</div>
<!-- /Card #2 -->
<div id="dropmenu2" class="dropmenu" onmouseleave="this.style.display='none';">
View
Edit
Delete
</div>
<div class="card">
<img class="gear" onclick="getFixedElementPosition(this, 3)" src="https://www.indivstock.com/static35/preview2/stock-vector-gear-icon-illustrated-in-vector-on-white-background-520258.jpg" width="34">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt</p>
</div>
<!-- /Card #3 -->
<div id="dropmenu3" class="dropmenu" onmouseleave="this.style.display='none';">
View
Edit
Delete
</div>
</div>
https://codepen.io/t3l3machus/pen/GRvbjzM
P.S. The numbered ids (dropmenu1, dropmenu2..) are created by a template engine on document load.
There are a couple of things you could change and also some bugs.
The dropdown only works once because you're setting display = "none" but comparing it with empty string.
You can wrap this on a <div> that has position:absolute and then use position:relative to position the dropdown relative to the wrapper. This way you only have to set the display value.
Check out my updated version:
https://codepen.io/samura_lesi/pen/MWvMpKX

How to make ellipses vertically aligned?

I have several lines of text, each of them is truncated with ellipses.
.container {
display: block;
border: 1px solid;
width: 200px;
}
.text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 20px;
text-align: justify;
}
<div class="container">
<p class="text">
This is text1 that has very very very long string.
</p>
<p class="text">
The ellipses of the line is not vertically aligened with the above one.
</p>
<p class="text">
This is text3 that has very very very long string.
</p>
<p class="text">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
</p>
</div>
As you can see from the demo, all the ellipses are not aligned vertically even though the element width is all the same.
How can I make all of them to be aligned vertically?
P.S. Screenshot attached
The text-align property is only used in cases where the length of the child element is less than the width of the parent (or containing element). If the length of the child element is wider than its parent / containing element then the text-align property isn't used. I get what you are trying to do with text-align: justify, but it doesn't work in this case as the paragraph elements lengths are actually extending past the 200px that you set for the container element.
So, in order to vertically align them, you just need to set a width and add it to the .text class.
Adding
width: 180px to your .text class should do the trick to set a width for the paragraph elements which will get it much closer.
However you'll still have the odd instance where they cut off at different characters and they won't align exactly as you expect, so you can do the below, which is a bit more tricky as you'll have to add a wrapper to each of the paragraph elements. It can potentially look a bit naff, but this would be how you do it:
.container {
display: block;
border: 1px solid;
width: 200px;
}
.text{
text-overflow: clip;
font-size: 20px;
height: 20px;
width: 170px;
overflow: hidden;
word-break: break-all;
}
.ellipsis{
position: relative;
}
.ellipsis::after {
content: "...";
position: absolute;
left: 170px;
top:0;
font-size: 20px;
}
.ellipsis:first-of-type::after {
top: 20px;
}
<div class="container">
<span class="ellipsis"><p class="text">
This is text1 that has very very very long string.
</p></span>
<span class="ellipsis"><p class="text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p></span>
<span class="ellipsis"><p class="text">
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</p></span>
<span class="ellipsis"><p class="text">
This is text1 that has very very very long string.
</p></span>
</div>
Up to you which of those you use though :)
I think it's possible with css tricks.
.container {
border: 1px solid;
width: 200px;
}
.text {
position: relative;
overflow: hidden;
font-size: 20px;
height: 1.5em;
padding-right: 1em;
text-align: justify;
word-break: break-all;
}
.text::after {
content: '...';
position: absolute;
right: 0;
top: 0;
z-index: 1;
width: 1em;
text-align: center;
background: white;
}
<div class="container">
<p class="text">
<span>This is text1 that has very very very long string.</span>
</p>
<p class="text">
<span>The ellipses of the line is not vertically aligened with the above one.</span>
</p>
<p class="text">
<span>This is text3 that has very very very long string.</span>
</p>
<p class="text">
<span>Lorem ipsum dolor sit amet consectetur adipisicing elit.</span>
</p>
</div>
But with this method, if 'text' is smaller than 'container' it looks weird, so apply'::after' to a specific class.
For example,'.overflow::after' and apply the 'overflow' class when 'text' is larger than 'container' via JavaScript.
window.onload = function() {
var tmpContainer = document.getElementsByClassName('container');
var tmpContainerWidth = tmpContainer[0].clientWidth;
var tmpText = document.getElementsByClassName('text');
var tmpTextLen = tmpText.length;
for (var i = 0; i < tmpTextLen; i++) {
var tmpTextWidth = tmpText[i].children[0].offsetWidth;
var tmpTextFontSize = parseFloat(getComputedStyle(tmpText[i]).fontSize);
if (tmpTextWidth + tmpTextFontSize >= tmpContainerWidth) tmpText[i].classList.add('overflow');
}
}
.container {
border: 1px solid;
width: 500px;
}
.text {
position: relative;
overflow: hidden;
font-size: 20px;
height: 1.5em;
padding-right: 1em;
text-align: justify;
word-break: break-all;
}
.overflow::after {
content: '...';
position: absolute;
right: 0;
top: 0;
z-index: 1;
width: 1em;
text-align: center;
background: white;
}
<div class="container">
<p class="text">
<span>This is text1 that has very very very long string.</span>
</p>
<p class="text">
<span>The ellipses of the line is not vertically aligened with the above one.</span>
</p>
<p class="text">
<span>This is text3 that has very very very long string.</span>
</p>
<p class="text">
<span>Lorem ipsum dolor sit amet consectetur adipisicing elit.</span>
</p>
</div>

How to count pageX, pageY for divs with same classes separately from each other

I'm trying to make hover effect like here: https://andstudio.lt/work/
So when user hover on title of project there is image appear which pinned to cursor.
I found some code in internet and created in codepen, here https://codepen.io/ChicagoJostik/pen/abzqXOv
It's actually working, but not properly.
First of all, I got problem here:
function moveCircle(e) {
TweenMax.to(".cursor", 0.5, {
css: {
left: e.pageX,
top: e.pageY
},
});
}
So when I hover on any project all "cursor's" pageX and pageY will be count.
How can I make count only for that "cursor" in which project I hovered?
I don't know maybe it's the problem that makes code working not properly,
but if you have any advice, you can write courageously.
Thanks in advance and sorry for my English.
Here is a working example to play around with.
Snippet:
$(".hoverme a").mouseenter(function() {
img = $(this).attr("data-image");
$(".image-placeholder").attr("style","background:url(" + img + ") no-repeat center center");
$(".image-placeholder").addClass("close");
$(document).on("mousemove", function(e) {
$(".image-placeholder").css({
left: e.pageX,
top: e.pageY
});
});
});
$(".hoverme").mouseleave(function() {
$(".image-placeholder").removeClass("close");
});
body {
background-color: #8f8d8d;
}
.container {
padding: 75px;
position: relative;
z-index: 10;
}
.hoverme {
padding-bottom: 20px;
}
.hoverme a {
opacity: 0.5;
display: inline-block;
font-size: 20px;
color: #fff;
transition: 0.2s;
}
.hoverme a:hover {
opacity: 1;
}
.image-placeholder {
visibility: hidden;
opacity: 0;
width: 30%;
padding-bottom: 21%;
position: absolute;
transform: translate(-50%, -50%) scale(0.7);
z-index: 9;
background-size: cover !important;
transition: opacity 0.1s, visibility 0.1s, transform 0.2s;
left: -100%;
top: -100%;
}
.image-placeholder.close {
display: block;
visibility: visible;
opacity: 1;
transform: translate(-50%, -50%) scale(1.1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="image-placeholder"></div>
<div class="container">
<div class="hoverme">
<a data-image="https://i.imgur.com/kuqQfXB.jpg">
1. Lorem ipsum dolor sit amet, consectetur adipiscing elit</a>
</div>
<div class="hoverme">
<a data-image="https://i.imgur.com/UVP46pV.jpg">
2. Lorem ipsum dolor sit amet, consectetur adipiscing elit</a>
</div>
<div class="hoverme">
<a data-image="https://i.imgur.com/8YLDZ4B.jpg">
3. Lorem ipsum dolor sit amet, consectetur adipiscing eli</a>
</div>
<div class="hoverme">
<a data-image="https://i.imgur.com/9uAL5Oh.jpg">
4. Donec et velit volutpat, posuere orci pulvinar lobortis</a>
</div>
</div>

Fadein/Fadeout a text inside a div

I would like to know how could I make my div that contains text fade in from bottom to top when scrolling down the page? i will be grateful for your help. Here is my Code:
var $text = $('.textBlock');
$(window).on('scroll', function(event, element) {
$text.each(function(event, element) {
if ($(this).visible()) {
$(this).children('p').stop().fadeIn();
} else {
$(this).siblings('.textBlock p').stop().fadeOut();
}
});
});
.textBlock {
text-align: center;
width: 100%;
height: 118px;
float: left;
display: block;
}
.textBlock p {
font-size: 24px;
padding: 30px 0;
line-height: 25px;
letter-spacing: 0.1em;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="blockOne" class="textBlock">
<p>Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
<div id="blockTwo" class="textBlock">
<p>Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
<div id="blockThree" class="textBlock">
<p>Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
You need to use a timer function for this. Check this out:
$(function () {
$(".textBlock").hide();
$("#blockOne").show();
$(window).scroll(function () {
numTextBlocks = $(".textBlock").length;
$(".textBlock:visible").fadeOut(400, function () {
console.log(".textBlock:nth-child(" + ($(window).scrollTop() * 10) % numTextBlocks + ")");
$(".textBlock:nth-child(" + ($(window).scrollTop() * 10) % numTextBlocks + ")").fadeIn(400);
});
});
});
html, body {
height: 150%;
}
.textBlock {
position: fixed;
text-align: center;
width: 100%;
height: 118px;
}
.textBlock p {
font-size: 24px;
padding: 30px 0;
line-height: 25px;
letter-spacing: 0.1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="blockOne" class="textBlock">
<p>One Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
<div id="blockTwo" class="textBlock">
<p>Two Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
<div id="blockThree" class="textBlock">
<p>Three Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
This is what I used:
$(document).on("mousewheel", function () {
$(".textBlock:not(:visible)").first().fadeIn("slow")
});
Here is the JSFiddle demo
Let me know if this code works with you.
Fiddle
$(window).on("load",function() {
function fade() {
$('.fade').each(function() {
/* Check the location of each desired element */
var objectBottom = $(this).offset().top + $(this).outerHeight();
var windowBottom = $(window).scrollTop() + $(window).innerHeight();
/* If the object is completely visible in the window, fade it in */
if (objectBottom < windowBottom) { //object comes into view (scrolling down)
if ($(this).css('opacity')==0) {$(this).fadeTo(500,1);}
} else { //object goes out of view (scrolling up)
if ($(this).css('opacity')==1) {$(this).fadeTo(500,0);}
}
});
}
fade(); //Fade in completely visible elements during page-load
$(window).scroll(function() {fade();}); //Fade in elements during scroll
});

showing a div content after scrolling down

hi there i'm trying to show a hidden div when scrolling down from the top of the browser page, like the Accordion function. What i'm using here is this Code:
HTML:-
// Visible DIV
<div class="firstBlock">
<p>Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
// Hiddden DIV
<div class="textBlock">
<p>Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
// Visible DIV
<div class="secondBlock">
<p>Lorem ipsum dolor sit Amet, consectetuer adipiscing.</p>
</div>
CSS:-
.textBlock {
text-align: center;
height: 104px;
width: 100%;
float: left;
display: none;
}
.textBlock p {
font-size: 16px;
font-family: arial,helvetica,sans-serif;
padding: 10% 5%;
line-height: 20px;
}
jQuery:-
$(document).ready(function(){
$(window).bind("scroll", function() {
if ($(this).scrollTop() > 600) {
$(".textBlock").fadeIn();
} else {
$(".textBlock").stop().fadeOut();
}
});
});
but it needs some modification in order to work like Accordion-Function.
If you want the accordion effect you should use the slideDown and slideUp functions (docs here), like so:
http://jsfiddle.net/b7yomjd0/3/

Categories

Resources