I dont know how to approach this. I would like to be able to do the following: I have a icon for a folder that links to another page. When the user clicks on the icon, instead of going to the page, a subfolder(s) appears below the folder icon and when the user clicks on one of these folders, then it directs the user to the page.
Below is what I did orignally:
<h4>
<a href="CalMediConnect_DMgmt.cfm">
<img src="images/folder-documents-icon32.jpg" alt="Custodial" class="float-left">
Disease Management
</a>
</h4>
<br /><br />
UPDATE
I have tried the following and it appears to not be working:
The following is the script:
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for(var i = 0; i < tree.length; i++) {
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if(classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for(var i = 0; i < opensubs.length; i++) {
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
The following is the CSS:
ul.tree li {
list-style-type: none;
position: relative;
}
ul.tree li ul {
display: none;
}
ul.tree li.open > ul {
display: block;
}
ul.tree li a {
color: #4284B0;
text-decoration: none;
}
ul.tree li a:before {
height: 1em;
padding: .1em;
font-size: .8em;
display: block;
position: absolute;
left: -1.3em;
top: .2em;
}
.margin-left {
margin-left: -15px;
}
And the HTML:
<ul class="tree margin-left">
<li>
<h4>
<a href="#">
<img src="images/folder-documents-icon32.jpg" alt="Custodial" class="float-left">
Disease Management
</a>
</h4>
<ul>
<li>
<h5>
<a href="CalMediConnect_DMgmt.cfm">
<img src="images/folder-documents-icon32.jpg" alt="Custodial" class="float-left">
Disease Management
</a>
</h5>
</li>
</ul>
</li>
</ul>
Any help would be appreciated.
Here is a very basic example built with jQuery...
https://jsfiddle.net/kennethcss/8b4e6o42/
$('.folder').on('click', function(e) {
var folder = $(this).find('.sub-folder');
if (e.target !== this) return;
if(folder.hasClass('hidden')) {
folder.removeClass('hidden');
} else {
folder.addClass('hidden');
}
});
.folder {
cursor: pointer;
}
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<ul class="container">
<li class="folder">Primary
<ul class="sub-folder hidden">
<li>Secondary</li>
<li>Secondary</li>
<li>Secondary</li>
</ul>
</li>
<li class="folder">Primary
<ul class="sub-folder hidden">
<li>Secondary</li>
<li>Secondary</li>
<li>Secondary</li>
</ul>
</li>
<li class="folder">Primary
<ul class="sub-folder hidden">
<li>Secondary</li>
<li>Secondary</li>
<li>Secondary</li>
</ul>
</li>
</ul>
Of course, you can style however you'd like; this example merely demonstrates how you might structure your HTML, CSS and JS to create a simple, folder like structure.
Gist
https://gist.github.com/kennethcss/8db1dc3326917c77846e84d263beb67d
Related
I have designed a small panel using the following code, which will display the content to the user by clicking on it:
$('.body_panel').find('li').click(function() {
if ($(this).has("ul")) {
$(this).children('.icon-title-right_panel').hide();
$(this).children('.icon-title-down_panel').show();
} else {
$(this).children('.icon-title-right_panel').show();
$(this).children('.icon-title-down_panel').hide();
}
});
$('.MyPanel').find('li').click(function(evt) {
evt.stopPropagation();
$(this).children('ul').slideToggle();
});
.MyPanel ul li {
cursor: pointer;
position: relative;
}
.MyPanel ul li .icon-title-right_panel,
.MyPanel ul li .icon-title-down_panel {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
}
.MyPanel ul li .icon-title-down_panel {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"/>
<div class="MyPanel">
<ul class="body_panel">
<li class="title_panel">
<h5>title</h5>
<span class="fas fa-circle-chevron-right icon-title-right_panel"></span>
<span class="fas fa-circle-chevron-down icon-title-down_panel"></span>
<ul class="box-contect_panel">
<li class="contect_panel">
<h1>contect</h1>
</li>
</ul>
</li>
</ul>
</div>
By clicking on the title of any icon on the right side, it will be removed. and it appears by clicking again.
As I specified in the script code; What alternative code should I write to delete the icon on the right by clicking on the title and the icon on the bottom appears instead?
Please try to do like this. the key is to catch the toggle status when you click li.
$('.body_panel').find('li').click(function() {
if($(this).parent().find("ul").eq(0).is(':visible')) {
$(this).children('.icon-title-right_panel').show();
$(this).children('.icon-title-down_panel').hide();
} else {
$(this).children('.icon-title-right_panel').hide();
$(this).children('.icon-title-down_panel').show();
}
});
$('.MyPanel').find('li').click(function(evt) {
evt.stopPropagation();
$(this).children('ul').slideToggle();
});
.MyPanel ul li {
cursor: pointer;
position: relative;
}
.MyPanel ul li .icon-title-right_panel,
.MyPanel ul li .icon-title-down_panel {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"/>
<div class="MyPanel">
<ul class="body_panel">
<li class="title_panel">
<h5>title</h5>
<span class="fas fa-circle-chevron-right icon-title-right_panel"></span>
<span class="fas fa-circle-chevron-down icon-title-down_panel"></span>
<ul class="box-contect_panel">
<li class="contect_panel">
<h1>contect</h1>
</li>
</ul>
</li>
</ul>
</div>
how to prevent opening link if parent li hasClass: has-menu ? it must work for all nested level
in example below only Sub Sub cat 1/1 and Sub cat 1/2 should open link but if i make it work then collapse with + and - is broken , how to combinate both collapse and link opening only if li dont have class: has-menu
$('li').click(function(e){
if ($(this).hasClass('has-menu')) {
e.preventDefault();
e.stopPropagation();
$(this).children("div").children("ul").toggleClass("menu-close");
$(this).toggleClass("menu-open");
}
})
ul{
padding: 0px;
list-style: none;
}
ul li{
padding: 5px 0;
}
ul li a{
width: 100%;
display: inline-block;
}
.menu-close{
display: none;
/*background-color:red;*/
}
/* Main menu */
.menu-main{
width: 250px;
}
.menu-main li{
position: relative;
}
.has-menu:before{
content: '+';
position: absolute;
right: 0;
}
.has-menu.menu-open:before{
content: '-' !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="menu-main">
<li class="has-menu">
Test 1
<div class="menu-wrapper">
<ul class="menu-child menu-close">
<li class="has-menu">
Sub cat 1/1
<div class="menu-wrapper">
<ul class="menu-subchild menu-close">
<li>
Sub Sub cat 1/1
</li>
</ul>
</div>
</li>
</ul>
<ul class="menu-child menu-close">
<li>
Sub cat 1/2
</li>
</ul>
</div>
</li>
</ul>
.has-menu>a{
pointer-events: none;
}
Try this.
just disable pointer-events on anchor tags that have parent with class .has-menu
I got the code from w3scgool and modified it. The dropdown menu opens but when I click inside of it - submenu, then it closes. Here is the pure JavaScript code.
var dropdown = document.getElementsByClassName('dropdown-btn');
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener('click', function() {
this.classList.toggle('active');
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display === 'block') {
dropdownContent.style.display = 'none';
} else {
dropdownContent.style.display = 'block';
}
});
}
nav.side-nav {
order: 0;
display: flex;
flex: 1 1;
flex-direction: column;
align-self: stretch;
margin-bottom: 0.67rem;
}
nav.side-nav ul {
margin: 0;
}
nav.side-nav li {
border-bottom: 1px solid #d9dadc;
border-left: 1px solid #d9dadc;
border-right: 1px solid #d9dadc;
list-style: none;
padding: 5px 15px;
font-size: 17px;
line-height: 24px;
}
nav.side-nav li:first-child {
background: #092a31;
color: white;
border: none;
font-size: 20px;
padding: 15px;
line-height: 1.1;
}
nav.side-nav li:not(:first-child):hover {
background: #cda600;
color: white;
cursor: pointer;
}
/*dropdown menu*/
.dropdown-container {
display: none;
background-color: #ffffff;
padding-left: 8px;
}
<html>
<nav class="side-nav">
<ul>
<li style="text-align:left;">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li id="navDrop" class="dropdown-btn">
Menu</li>
<div class="dropdown-container">
<form>
<a class="dropdown-container-link" id="navItem1" href="#">Submenu1</a><br>
<a class="dropdown-container-link" id="navItem2" href="#">Submenu2</a><br>
<a class="dropdown-container-link" id="navItem3" href="#">Submenu3</a><br>
<a class="dropdown-container-link" id="navItem4" href="#">Submenu4</a>
</form>
</div>
<li href="#">Menu</li>
</ul>
</nav>
</html>
I am new to JS. Could someone navigate/show how to edit the code to prevent dropdown from closing when click on its submenu.
Update: took out the onclick feature. Took from my code too.
Any suggestions about the code because it stays the same. In this case I am using just JS without jquery library.
After making the modifications suggested by #Heretic Monkey and #Ganesh chaitanya, you can simplify your code by using map() instead of a for loop, and again classList.toggle() instead of else if.
just modify your css a little with a new class that you add to your div. Like that
var dropdown = document.getElementsByClassName("dropdown-btn");
// here dropdown.map() don't work, use
Array.prototype.map.call(dropdown, function(drop) {
drop.addEventListener("click", function() {
drop.classList.toggle("active");
var dropdownContent = drop.nextElementSibling;
//use classList.toggle with the new class added at the div
dropdownContent.classList.toggle("disp-container");
});
});
nav.side-nav li:not(:first-child):hover {
background: #cda600;
color: white;
cursor: pointer;
}
/*dropdown menu*/
/*remove display here*/
.dropdown-container {
background-color: #ffffff;
padding-left: 8px;
}
/*create a new class and add display here*/
.disp-container {
display: none;
}
<nav class="side-nav">
<ul>
<li style="text-align:left;">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li id="navDrop" class="dropdown-btn">
Menu
</li>
<!-- add your new class here -->
<div class="disp-container dropdown-container">
<form>
<a class="dropdown-container-link" id="navItem1" href="#">Submenu1</a><br />
<a class="dropdown-container-link" id="navItem2" href="#">Submenu2</a><br />
<a class="dropdown-container-link" id="navItem3" href="#">Submenu3</a><br />
<a class="dropdown-container-link" id="navItem4" href="#">Submenu4</a>
</form>
</div>
<li id="navDrop2" class="dropdown-btn">
Menu
</li>
<!-- add your new class here -->
<div class="disp-container dropdown-container">
<form>
<a class="dropdown-container-link" id="navItem1" href="#">Submenu1</a><br />
<a class="dropdown-container-link" id="navItem2" href="#">Submenu2</a><br />
<a class="dropdown-container-link" id="navItem3" href="#">Submenu3</a><br />
<a class="dropdown-container-link" id="navItem4" href="#">Submenu4</a>
</form>
</div>
</ul>
</nav>
I have this dropdown menu solution. http://jsfiddle.net/ftymhs8s/
I need to hide the one dropdown menu that is displayed when I click on a different line and show dropdown menu of it. I also need the first line dropdown menu to be displayed always when people go to the website.
I hope I correctly described my problem, can you please help me?
// Dropdown Menu
var dropdown = document.querySelectorAll('.dropdown');
var dropdownArray = Array.prototype.slice.call(dropdown, 0);
dropdownArray.forEach(function(el) {
var button = el.querySelector('a[data-toggle="dropdown"]'),
menu = el.querySelector('.dropdown-menu'),
arrow = button.querySelector('i.icon-arrow');
button.onclick = function(event) {
if (!menu.hasClass('show')) {
menu.classList.add('show');
menu.classList.remove('hide');
arrow.classList.add('open');
arrow.classList.remove('close');
event.preventDefault();
} else {
menu.classList.remove('show');
menu.classList.add('hide');
arrow.classList.remove('open');
arrow.classList.add('close');
event.preventDefault();
}
};
})
Element.prototype.hasClass = function(className) {
return this.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(this.className);
};
ul {
list-style: none
}
.dropdown a {
text-decoration: none;
}
.dropdown [data-toggle="dropdown"] {
position: relative;
display: block;
color: black;
padding: 10px;
}
.dropdown .dropdown-menu {
max-height: 0;
overflow: hidden;
}
.dropdown .dropdown-menu li {
padding: 0;
}
.dropdown .dropdown-menu li a {
display: block;
padding: 10px 10px;
}
.dropdown .show {
display: block;
max-height: 9999px;
margin-left: 50px;
}
.dropdown .hide {
max-height: 0;
}
<div class="container">
<ul>
<li class="dropdown">
First Menu
<ul class="dropdown-menu">
<li>Home</li>
<li>About Us</li>
<li>Services</li>
<li>Contact</li>
</ul>
</li>
<li class="dropdown">
Second Menu
<ul class="dropdown-menu">
<li>Home</li>
<li>About Us</li>
<li>Services</li>
<li>Contact</li>
</ul>
</li>
<li class="dropdown">
Third Menu
<ul class="dropdown-menu">
<li>Home</li>
<li>About Us</li>
<li>Services</li>
<li>Contact</li>
</ul>
</li>
</ul>
</div>
The behavior of multiple collapsible elements where only one of them can be open at one time is that of an accordion. The general idea is to first close all collapsibles then open the one that was selected by user. The following demo exhibits that behavior by Event Delegation.
BTW I noticed that you made a hasClass... er Class. That's not necessary, just use: node.classList.contains('class')
Details are commented in the demo
Demo
/* Added .main class to parent <ul>
|| By adding the eventListener to the
|| parent of multiple clickable nodes
|| and using e.target property to find
|| the exact node actually clicked, we
|| have just needed the <ul> to listen
|| rather than 3 separate <li>
|| This is part of Event Delagation
*/
var main = document.querySelector('.main');
main.addEventListener('click', accordion, false);
function accordion(e) {
/* Gather all .dropdown-menu to a NodeList
|| then covert it to an array
*/
var dropArray = Array.from(document.querySelectorAll('.dropdown-menu'));
/* Gather all links in the .dropdown-menus to
|| a NodeList then convert it to an array
*/
var linxArray = Array.from(document.querySelectorAll('a + .dropdown-menu a'));
/* if the clicked node (e.target) is NOT the
|| node listening for event (e.currentTarget
|| ul.main) then...
*/
if (e.target !== e.currentTarget) {
// Assign e.target to var tgr
var tgr = e.target;
/* if tgr has data-toggle attribute...
|| Find tgr next sibling (.dropdown-menu)
|| Iterate through dropArray wth a
|| for...of loop
|| Remove .show and add .hide on
|| each .dropdown-menu in dropArray
|| Then add .show and remove .hide
|| on tgt
|| Finally stop the click event from
|| bubbling, thereby preventing anything
|| else from being triggered.
*/
if (tgr.hasAttribute('data-toggle')) {
// Stop <a> from jumping
e.preventDefault();
var tgt = tgr.nextElementSibling;
for (let drop of dropArray) {
drop.classList.remove('show');
drop.classList.add('hide');
}
tgt.classList.add('show');
tgt.classList.remove('hide');
} else {
return;
}
e.stopPropagation();
}
}
html,
body,
.contain {
height: 100%;
width: 100%;
}
.main,
section,
article {
margin-bottom: 100vh;
}
ul {
list-style: none
}
.dropdown a {
text-decoration: none;
}
.dropdown [data-toggle="dropdown"] {
position: relative;
display: block;
color: black;
padding: 10px;
}
.dropdown .dropdown-menu {
max-height: 0;
overflow: hidden;
}
.dropdown .dropdown-menu li {
padding: 0;
}
.dropdown .dropdown-menu li a {
display: block;
padding: 10px 10px;
}
.dropdown .show {
display: block;
max-height: 9999px;
margin-left: 50px;
}
.dropdown .hide {
max-height: 0;
}
<div id='home' class="container">
<ul class='main'>
<li class="dropdown">
First Menu
<ul class="dropdown-menu">
<li>Home</li>
<li>About Us</li>
<li>Services</li>
<li>Contact</li>
</ul>
</li>
<li class="dropdown">
Second Menu
<ul class="dropdown-menu">
<li>Section I</li>
<li>Section II</li>
<li>Section III</li>
<li>Section IV</li>
</ul>
</li>
<li class="dropdown">
Third Menu
<ul class="dropdown-menu">
<li>Example</li>
<li>Example</li>
<li>Example</li>
<li>Example</li>
</ul>
</li>
</ul>
<article id='about'>
<h2>About</h2>
</article>
<article id='services'>
<h2>Services</h2>
</article>
<article id='contact'>
<h2>Contact</h2>
</article>
<hr>
<section id='1'>
<h2>Section I</h2>
</section>
<section id='2'>
<h2>Section II</h2>
</section>
<section id='3'>
<h2>Section III</h2>
</section>
<section id='4'>
<h2>Section IV</h2>
</section>
</div>
I am working on some code for a portfolio where the projects are shown on the left-hand side.
The active class is supposed to be added to the classes of the line left div for any list item, however, when I mouse over any other of the project-title list items it only works for the first one, I am not sure why this is? Here is the code:
HTML:
<ul class="project">
<li class=project-title>
<div class="line-left"></div>
<p class="project-paragraph">Project title</p>
</li>
<li class=project-title>
<div class="line-left"></div>
<p class="project-paragraph">Project title</p>
</li>
<li class=project-title>
<div class="line-left"></div>
<p class="project-paragraph">Project title</p>
</li>
<li class=project-title>
<div class="line-left"></div>
<p class="project-paragraph">Project title</p>
</li>
<li class=project-title>
<div class="line-left"></div>
<p class="project-paragraph">Project title</p>
</li>
<li class=project-title>
<div class="line-left"></div>
<p class="project-paragraph">
Project title</p>
</li>
</ul>
CSS:
.project {
width: 170px;
font-family: Verdana, Geneva, sans-serif;
font-size: 14px;
color: #949394;
}
.project-title {
list-style: none;
cursor: pointer;
}
.project-paragraph {
display: inline-block;
}
.line-left {
border-top: 1px solid #2b2b2b;
width: 20px;
margin-top: 7px;
visibility: hidden;
display: inline-block;
margin-right: 10px;
padding-bottom: 4px;
}
.active {
visibility: visible;
}
JAVASCRIPT:
document.querySelector('.project-title').addEventListener('mouseover', function() {
document.querySelector('.project-title .line-left').classList.add('active');
});
Here is the jsfiddle as well: https://jsfiddle.net/andylyell/ynb7wxk2/
I would love to have only 1 active class present on a line left, anytime but I am unsure how to do this. Any help would be greatly appreciated - Thank you!
You have to subscribe each element that have "project-title" class.
Here is modified js for you solution:
var activeClassName = 'active';
var elements = document.querySelectorAll('.project-title');
for (var i = 0; i < elements.length; i++) {
subscribeEvent(elements[i]);
}
function subscribeEvent(el) {
el.addEventListener('mouseover', function(e) {
var target = e.currentTarget;
if (containsClass(target.querySelector('.line-left'), activeClassName)) {
return;
}
setActiveEl(target);
}, false);
}
function setActiveEl(activeEl) {
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element != activeEl) {
removeClass(element.querySelector('.line-left'), activeClassName);
}
}
addClass(activeEl.querySelector('.line-left'), activeClassName);
}
function addClass(el, className) {
el && el.classList.add(className);
}
function removeClass(el, className) {
el && el.classList.remove(className);
}
function containsClass(el, className) {
return el && el.classList.contains(className);
}
use--
document.querySelectorAll('.project-title').addEventListener('mouseover',
function() {
document.querySelectorAll('.project-title .line-
left').classList.add('active');
});
Then you will be able to add that class to all the elements having that class