what is the best approach to implement Tree View? - javascript

I'm working Tree View constructed by using nested ul li tag as below:
<ul>
<li>Level 1 a
<ul>
<li>Level 2 a</li>
<li>Level 2 b
<ul>
<li>Level 3 a</li>
<li>Level 3 b</li>
</ul>
</li>
</ul>
</li>
<li>Level 1 b</li>
</ul>
I wanted the list item is clickable on cell when navigate across the Tree View like below:
I know that we can added JavaScript function on list item as below:
<li onClick="redicrectPage(url)">
and add event.cancelBubble = true to avoid parent event is trigger when child item clicked.
My question is, any better cross-browser workaround on the implementation above?
Thank you in advanced.

You can make a nested menu structure in CSS alone which would remove the bubbling problem. The example at http://jsfiddle.net/steveukx/HfDBA/ uses the direct descendent selector to be able to repeat the same selectors without needing to know the depth of the menu, but if you are supporting browsers that don't have this functionality you should change the HTML to add classes to name the depth in the tree and specify those in the CSS.
HTML:
<ul class="menu">
<li>Level 1 a
<ul>
<li>Level 2 a</li>
<li>Level 2 b
<ul>
<li>Level 3 a</li>
<li>Level 3 b</li>
</ul>
</li>
</ul>
</li>
<li>Level 1 b</li>
</ul>​
CSS
* { font-family: tahoma, sans-serif; font-size: 10pt; }
a { text-decoration: none; color: #fff; display: block; }
ul { display: none; }
ul.menu, li:hover > ul { display: block; }
li > ul { position: absolute; top: 25%; left: 100%; margin-left: -1em;
box-shadow: -1px 1px 1px rgba(0,0,0,0.5); z-index: 1000; }
li { position: relative; padding: 0.1em 0.5em; width: 100px; background: silver;
box-shadow: -1px 1px 1px rgba(0,0,0,0.5); margin: 1px 1px 0; }
li:hover { background-color: #333; }
li:hover > a { color: #FAFAFE; }
​

Related

Show Bootstrap Multi level Dropdown Menu on Hover

I understand there are couple of posts on this title. What I want , to implement the same in my existing code and by using jQuery since I have already added ample of CSS lines for it's styling purpose.
The Piece of codes I have used in my web application for implementing Multi drop-down .
HTML :
<div class="dropdown" style="position:relative">
Click Here <span class="caret"></span>
<ul class="dropdown-menu">
<li>
<a class="trigger right-caret">Level 1</a>
<ul class="dropdown-menu sub-menu">
<li>Level 2</li>
<li>
<a class="trigger right-caret">Level 2</a>
<ul class="dropdown-menu sub-menu">
<li>Level 3</li>
<li>Level 3</li>
<li>
<a class="trigger right-caret">Level 3</a>
<ul class="dropdown-menu sub-menu">
<li>Level 4</li>
<li>Level 4</li>
<li>Level 4</li>
</ul>
</li>
</ul>
</li>
<li>Level 2</li>
</ul>
</li>
<li>Level 1</li>
<li>Level 1</li>
</ul>
css
.dropdown-menu>li
{ position:relative;
-webkit-user-select: none; /* Chrome/Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
/* Rules below not implemented in browsers yet */
-o-user-select: none;
user-select: none;
cursor:pointer;
}
.dropdown-menu .sub-menu {
left: 100%;
position: absolute;
top: 0;
display:none;
margin-top: -1px;
border-top-left-radius:0;
border-bottom-left-radius:0;
border-left-color:#fff;
box-shadow:none;
}
.right-caret:after,.left-caret:after
{ content:"";
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
display: inline-block;
height: 0;
vertical-align: middle;
width: 0;
margin-left:5px;
}
.right-caret:after
{ border-left: 5px solid #ffaf46;
}
.left-caret:after
{ border-right: 5px solid #ffaf46;
}
JS
$(function(){
$(".dropdown-menu > li > a.trigger").on("click",function(e){
var current=$(this).next();
var grandparent=$(this).parent().parent();
if($(this).hasClass('left-caret')||$(this).hasClass('right-caret'))
$(this).toggleClass('right-caret left-caret');
grandparent.find('.left-caret').not(this).toggleClass('right-caret left-caret');
grandparent.find(".sub-menu:visible").not(current).hide();
current.toggle();
e.stopPropagation();
});
$(".dropdown-menu > li > a:not(.trigger)").on("click",function(){
var root=$(this).closest('.dropdown');
root.find('.left-caret').toggleClass('right-caret left-caret');
root.find('.sub-menu:visible').hide();
});
});
I have only go far a bit only. I am able to show the 1st dropdown menu on hover.
js
$(".dropdown > a").hover(function(){
$(this).parent().addClass('open');
});
When I will hover on any "li" element of 1st level navigation , if any 2nd level navigation present , It should be shown.

How to programmatically open my accordion menu

I'm using a very simple jQuery accordion script but what I'd like to achieve is a way to programmatically open a menu item on page load. Ultimately this will be when a user browses directly to a page within a submenu, that menu opens to identify where they are. I just cannot figure out how to trigger the opening on load... Any help appreciated.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JQuery navigation test 2</title>
<script src="js/jquery-1.11.1.min.js" type="text/javascript"></script>
<style>
#nav {
float: left;
width: 280px;
border-top: 1px solid #999;
border-right: 1px solid #999;
border-left: 1px solid #999;
}
#nav li a {
display: block;
padding: 10px 15px;
background: #ccc;
border-top: 1px solid #eee;
border-bottom: 1px solid #999;
text-decoration: none;
color: #000;
}
#nav li a:hover, #nav li a.active {
background: #999;
color: #fff;
}
#nav li ul {
display: none;
}
#nav li ul li a {
padding: 10px 25px;
background: #ececec;
border-bottom: 1px dotted #ccc;
}
</style>
</head>
<body>
<ul id="nav">
<li>Menu 1
<ul>
<li>Sub-Item 1 a</li>
<li>Sub-Item 1 b</li>
<li>Sub-Item 1 c</li>
</ul>
</li>
<li>Link 1
</li>
<li>Menu 2
<ul>
<li>Sub-Item 3 a</li>
<li>Sub-Item 3 b</li>
<li>Sub-Item 3 c</li>
<li>Sub-Item 3 d</li>
</ul>
</li>
<li>Menu 3
<ul>
<li>Sub-Item 4 a</li>
<li>Sub-Item 4 b</li>
<li>Sub-Item 4 c</li>
</ul>
</li>
<li>Link 2
</li>
</ul>
<script type="text/javascript">
$(document).ready(function () {
$('#nav > li > a').click(function(){
if ($(this).attr('class') != 'active'){
$(this).next().slideToggle();
$(this).addClass('active');
}
else {
$(this).next().slideToggle();
$('#nav li a').removeClass('active');
}
});
});
</script>
</body>
</html>
You can manually apply the active class to the element and then when document is ready slideToggle the element with active class. For instance:
In the HTML:
<li>Menu 3
<ul>
<li>Sub-Item 4 a</li>
<li>Sub-Item 4 b</li>
<li>Sub-Item 4 c</li>
</ul>
</li>
And in the Javascript part:
$(document).ready(function () {
$('#nav > li > a').click(function(){
if ($(this).attr('class') != 'active'){
$(this).next().slideToggle();
$(this).addClass('active');
}
else {
$(this).next().slideToggle();
$('#nav li a').removeClass('active');
}
});
var toActivate = $('.activate-on-load');
toActivate.next().slideToggle();
toActivate.addClass('active');
});
This should work.
What I'd also suggest is adding additional classes for those menu elements instead of using such complexed selectors.
Just putting code within the $(document).ready(function() { ... }); will make it run on load (once the document is ready). To open the correct accordion, you can use window.location to get your URL to determine what page the user is on and open the accordion accordingly.
This could be made easier by adding ids to your menus so you can easily select and open it.
You have to use locationor pathname(it's up to you) in order to compare your current page with your accordion HREFs.
Here is an exemple
Added JS:
var pagePath = window.location.pathname; // To be used
var splitedPath = pagePath.split("/"); //Split to match your href formating
//Find A tag that match your path, find its parent UL and the A tag before (the one which has click event);
$("#nav > li > ul > li > a[href='" + splitedPath[splitedPath.length - 1] + "']").closest("ul").prev("a").trigger("click");
First get the location/pathname
Split it in order to match your current href formating
Select the parent A to simulate a click

Different styles for childs before and after specifed element using jQuery and CSS?

I need to set special styles for li.done depending on whether they are before or after li.current. How can I do that using jQuery or CSS?
ul { list-style: none; padding: 0; margin: 0; }
ul li {
display:inline-table;
padding: 5px 12px;
color: #ddd;
background-color: #bbb;
margin: 0;
}
.done {
background-color: #ddd;
color: #aaa
}
.current {
background-color: #99f;
color: #dee
}
<ul>
<li class="done">step 1</li>
<li class="done">step 2</li>
<li class="current">step 3</li>
<li class="done">step 4</li>
<li>step 5</li>
</ul>
You should take a look at jQuerys .prevAll() and .nextAll().
var current = $(".current");
current.prevAll(".done").addClass("before");
current.nextAll(".done").addclass("after");
Please note that you will have to redo this every time you change the current element.
The documentation can be found here and here.
You can achieve this just with CSS by using the ~ selector. From the W3 documentation:
General sibling combinator
The general sibling combinator is made of the "tilde" (U+007E, ~) character that separates two sequences of simple selectors. The elements represented by the two sequences share the same parent in the document tree and the element represented by the first sequence precedes (not necessarily immediately) the element represented by the second one.
That means that you could set the styles for the .done that happen after .current by applying the selector: .current ~ .done.
One example:
ul { list-style: none; padding: 0; margin: 0; }
ul li {
display:inline-table;
padding: 5px 12px;
color: #ddd;
background-color: #bbb;
margin: 0;
}
.done {
background-color: #ddd;
color: #aaa
}
.current {
background-color: #99f;
color: #dee
}
.current ~ .done {
background-color:#f99;
color:white;
}
<ul>
<li class="done">step 1</li>
<li class="done">step 2</li>
<li class="current">step 3</li>
<li class="done">step 4</li>
<li class="done">step 5</li>
<li>step 6</li>
</ul>

Horizontal Javascript menu error

I have a small problem with my JavaScript menu.
When I choose an item it shows me always the last sub menu.
This is very simple for people who are professionals in Javascript :p
Here is the sample:
CSS
ul#midnav {
border-width: 1px 0;
list-style: none;
margin-bottom: 5px;
text-align: center;
border-bottom: solid thin #c8c8c8;
padding: 0px 0px 13px 0px;
}
ul#midnav li {
display: inline;
padding: 0px 0px;
}
ul#midnav li a {
text-transform:uppercase;
font-size:11px;
padding: 5px 13px 0px 5px;
background: url('../image/arrow-topdown-gray.png') 100% 9px no-repeat;
}
ul#midnav li ul {
line-height: 28px;
padding: 0;
position: absolute;
top: -30px;
background: none;
display: none;
/* --Hide by default--*/
width: 960px;
height:28px;
background: #fff;
border-top: solid thin #eeeeed;
}
ul#midnav li ul a {
background: url('../image/arrow-left-gray.png') 100% 9px no-repeat;
}
HTML
<div id="navigation">
<div id="mid-nav">
<ul id="midnav">
<li>Item 1
<ul>
<li>Item 1.1
</li>
<li>Item 1.2
</li>
</ul>
</li>
<li>Item 2
<ul>
<li>Item 2.1
</li>
<li>Item 2.2
</li>
</ul>
</li>
<li>Item 3
<ul>
<li>Item 3.1
</li>
<li>Item 3.2
</li>
</ul>
</li>
<li>Item 4
<ul>
<li>Contact Us
</li>
<li>Item 4.1
</li>
<li>Item 4.2
</li>
</ul>
</li>
<li>Item 5
<ul>
<li>Item 5.1
</li>
<li>Item 5.2
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
JavaScript
$(document).ready(function () {
$('ul#midnav li a').on('click', function (event) {
event.preventDefault();
$('#mid-nav > ul').find('ul').slideUp(function () {
$(this).closest('li').find('ul').slideToggle();
});
});
});
this in your ready handler refers to the wrong object:
$(document).ready(function () {
$('ul#midnav li a').on('click', function(event){
event.preventDefault();
var e=this;
// must alias or 'this' will refer to
// the last submenu slid into hiding
// instead of the one to open
$('#mid-nav > ul').find('ul').slideUp(
function(){
$(e).closest('li').find('ul').slideToggle(); // 'e' instaed of 'this'
});
});
});

How to make superfish dropdown menu responsive?

I am using superfish dropdown menu with skelton framework. I wanted it to work on mobiles as well. By default its showing the dropdown items but it hover over the items below it. I wants to have it in a way so that it push parent items below it. Any solution?
Here's a better answer
I was able to convert the same HTML for Superfish into a responsive drawer menu. The JS is ultra simple and the whole thing is basically done using CSS. Check it out and let me know what you guys think!
// TRIGGER ACTIVE STATE
$('#mobnav-btn').click(
function() {
$('.sf-menu').toggleClass("xactive");
});
// TRIGGER DROP DOWN SUBS
$('.mobnav-subarrow').click(
function() {
$(this).parent().toggleClass("xpopdrop");
});
body {
font-family: Arial;
font-size: 12px;
padding: 20px;
}
#mobnav-btn {
display: none;
font-size: 20px;
font-weight: bold;
background-color: blue;
color: white;
padding: 10px;
cursor: pointer;
}
.mobnav-subarrow {
display: none;
}
#media only screen and (max-width: 480px) {
#mobnav-btn {
display: block;
}
.mobnav-subarrow {
display: block;
background-color: #0f3975;
opacity: .3;
border-bottom: 1px solid white;
border-top: 1px solid black;
height: 20px;
width: 30px;
background-position: top left!important;
position: absolute;
top: 8px;
right: 10px;
-webkit-border-radius: 5px;
border-radius: 5px;
cursor: pointer;
-webkit-border-radius: 5px;
border-radius: 5px;
cursor: pointer;
-webkit-transition: all .1s ease-in-out;
-moz-transition: all .1s ease-in-out;
-ms-transition: all .1s ease-in-out;
-o-transition: all .1s ease-in-out;
transition: all .1s ease-in-out;
}
.sf-menu {
width: 100%!important;
display: none;
}
.sf-menu.xactive {
display: block!important;
}
.sf-menu li {
float: none!important;
display: block!important;
width: 100%!important;
}
.sf-menu li a {
float: none!important;
}
.sf-menu ul {
position: static!important;
display: none!important;
}
.xpopdrop ul {
display: block!important;
}
}
<script src="http://code.jquery.com/jquery-compat-git.js"></script>
<script src="http://users.tpg.com.au/j_birch/plugins/superfish/js/superfish.js"></script>
<link href="http://users.tpg.com.au/j_birch/plugins/superfish/css/superfish.css" rel="stylesheet" />
<small>This is a responsive Superfish Menu by Ryan Brackett. <br/>
<br/>In this demo, you can drag the middle bar to see the responsive menu. I have already included the default css and js files for Superfish</small>
<br/>
<br/>
<div id="mobnav-btn">Button</div>
<ul class="sf-menu">
<li>Item 1
<div class="mobnav-subarrow"></div>
<ul>
<li>Subitem 1.1
</li>
<li>Subitem 1.2
</li>
<li>Subitem 1.3
</li>
<li>Subitem 1.4
</li>
</ul>
</li>
<li>Item 2
<div class="mobnav-subarrow"></div>
<ul>
<li>Subitem 2.1
</li>
<li>Subitem 2.2
</li>
<li>Subitem 2.3
</li>
<li>Subitem 2.4
</li>
</ul>
</li>
<li>Item 3
<div class="mobnav-subarrow"></div>
<ul>
<li>Subitem 3.1
</li>
<li>Subitem 3.2
</li>
<li>Subitem 3.3
</li>
<li>Subitem 3.4
</li>
</ul>
</li>
<li>Item 4
<div class="mobnav-subarrow"></div>
<ul>
<li>Subitem 4.1
</li>
<li>Subitem 4.2
</li>
<li>Subitem 4.3
</li>
<li>Subitem 4.4
</li>
</ul>
</li>
<li>Item 5
<div class="mobnav-subarrow"></div>
<ul>
<li>Subitem 5.1
</li>
<li>Subitem 5.2
</li>
<li>Subitem 5.3
</li>
<li>Subitem 5.4
</li>
</ul>
</li>
<li>Item 6
<div class="mobnav-subarrow"></div>
<ul>
<li>Subitem 6.1
</li>
<li>Subitem 6.2
</li>
<li>Subitem 6.3
</li>
<li>Subitem 6.4
</li>
</ul>
</li>
</ul>
Update:
See the answer by Ryan Brackett
Dropdown menus don't work well on mobile. I would suggest hiding the superfish menu on mobile and replacing it with something else.
Resources:
Off canvas
http://www.lukew.com/ff/entry.asp?1569
http://www.zurb.com/playground/off-canvas-layouts
Mobile navigation patterns
http://bradfrostweb.com/blog/web/responsive-nav-patterns/
For others looking for a solution, make sure you are using the newest jQuery. I had some older sites where I found using a newer version of jQuery made the Superfish menus work on mobile devices.
As Ed pointed out it seems problematic to solve all the different superfish/css issues for a responsive menu.
After looking through the options here and elsewhere I found a Pure CSS responsive menu which has been quicker and easier to modify than superfish, and does not have the overheads of jquery or javascript. It also has second level menus.
I checked the demo with screenfly to check responsiveness and mobile layout before using it. The CSSscript.com version (link above) gives a horizontal responsive layout for mobiles, unlike the codepen demo page.
The code is in a single HTML file which you can easily split into a linked CSS file, only 2 media queries manage the responsive changes and even then only with minimal changes. The '+' symbols can be deleted without issues.
Only one tiny downside: the first link downloads a HTML has a javascript at the bottom adding obvious google analytics tracking, easily removed and not on codepen.
Explanation author andor nagy - code from codepen
/* CSS Document */
#import url(http://fonts.googleapis.com/css?family=Open+Sans);
#import url(http://fonts.googleapis.com/css?family=Bree+Serif);
body {
background: #212121;
font-size:22px;
line-height: 32px;
color: #ffffff;
word-wrap:break-word !important;
font-family: 'Open Sans', sans-serif;
}
h1 {
font-size: 60px;
text-align: center;
color: #FFF;
}
h3 {
font-size: 30px;
text-align: center;
color: #FFF;
}
h3 a {
color: #FFF;
}
a {
color: #FFF;
}
h1 {
margin-top: 100px;
text-align:center;
font-size:60px;
font-family: 'Bree Serif', 'serif';
}
#container {
margin: 0 auto;
max-width: 890px;
}
p {
text-align: center;
}
#relatedContent {
max-width: 800px;
margin: 200px auto;
}
#relatedContent .item {
max-width: 44%;
padding: 3%;
float: left;
text-align: center;
}
#relatedContent .item a img {
max-width: 100%;
}
nav {
margin: 50px 0;
background-color: #E64A19;
}
nav ul {
padding:0;
margin:0;
list-style: none;
position: relative;
}
nav ul li {
display:inline-block;
background-color: #E64A19;
}
nav a {
display:block;
padding:0 10px;
color:#FFF;
font-size:20px;
line-height: 60px;
text-decoration:none;
}
nav a:hover {
background-color: #000000;
}
/* Hide Dropdowns by Default */
nav ul ul {
display: none;
position: absolute;
top: 60px;
}
/* Display Dropdowns on Hover */
nav ul li:hover > ul {
display:inherit;
}
/* Fisrt Tier Dropdown */
nav ul ul li {
width:170px;
float:none;
display:list-item;
position: relative;
}
/* Second, Third and more Tiers */
nav ul ul ul li {
position: relative;
top:-60px;
left:170px;
}
/* Change this in order to change the Dropdown symbol */
li > a:after { content: ' +'; }
li > a:only-child:after { content: ''; }
<div id="container">
<nav>
<ul>
<li>Home</li>
<li>WordPress
<!-- First Tier Drop Down -->
<ul>
<li>Themes</li>
<li>Plugins</li>
<li>Tutorials</li>
</ul>
</li>
<li>Web Design
<!-- First Tier Drop Down -->
<ul>
<li>Resources</li>
<li>Links</li>
<li>Tutorials
<!-- Second Tier Drop Down -->
<ul>
<li>HTML/CSS</li>
<li>jQuery</li>
<li>Other
<!-- Third Tier Drop Down -->
<ul>
<li>Stuff</li>
<li>Things</li>
<li>Other Stuff</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Graphic Design</li>
<li>Inspiration</li>
<li>Contact</li>
<li>About</li>
</ul>
</nav>
<h1>Pure CSS Drop Down Menu</h1>
<p> A simple dropdown navigation menu made with CSS Only. Dropdowns are marked with a plus sign ( + )</p>
<p>Read tutorial <a target="_blank" href="http://webdesignerhut.com/css-dropdown-menu/">here</a></p>
</div>
This is what I use:
isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
$(".menu a").click(function(event){
if($(this).parents("ul").length == 1 && !$(this).hasClass("lastClick") && isMobile)
event.preventDefault();
$(".menu a").removeClass("lastClick");
$(this).addClass("lastClick");
});
Replace ".menu a" with your navigation links and this snippet will navigate the user to the clicked site after the second click and the first click will only show him the subpages.
Reshad: Simply change your CSS like this:
.xpopdrop > ul {
display: block!important;
}
And you will be fine.

Categories