I am struggling with a collapsible vertical menu. The first part of the script below works, so that the upper UL display its sibling LIs, while the other ULs keep their sibling LIs hidden.
My difficult task (to me at least) is to make the parent UL to the active link keep its sibling LIs visible. This is what I tried in the lower part of the script.
My a-links some times get a trailing hash (#) which I want to remove in order to compare i to the active URL. This is done through the trimHash(string)-function--which works when tested on a simple string, but not in this script.
Any good advice out there?
$(document).ready(function() {
// Collapse everything but the first menu:
$(".mainmenu > li > a").not(":first").find("+ ul").slideUp(1);
// Expand or collapse:
$(".mainmenu > li > a").click(function() {
$(this).find("+ ul").slideToggle("fast");
});
$(".mainmenu li").each(function () {
var li = $(this);
var a = rtrimHash(li[0].firstChild);
if (a.href == location.href) {
$(this).find("+ ul").slideDown(1);
}
});
I ended up with this solution. As it is a Wordpress site, while stepping through the menu items in the menu I could check if each link is active by comparing the link to the active post, and insert the class "current" to these menu items:
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
And then use jQuery to find all instances of the li "current" class, and trigger the parent ul's to slideDown:
$(document).ready(function() {
// Collapse everything:
$("li.cat").find("+ ul").slideUp(1);
// Collapse everything but the first menu:
//$("li.cat").not(":first").find("+ ul").slideUp(1);
// Expand or collapse:
$("li.cat").click(function() {
$(this).find("+ ul").slideToggle("fast");
});
$("li.current").parent().slideDown(1);
});
Sorry I didn't solve this through javascript as I intended, but I achieved what I wanted.
Related
For this website I'm having a menu like, generated by markdown via MIIS
<h4><a>title</a></h4>
<ul>
<li><a>foo</a></li>
<li> <a>foo</a>
<ul>
<li><a>sub</a></li>
</ul>
</li>
<li><a>foo</a></li>
</ul>
<h4><a>other title</a></h4>
<ul>
<li><a>other…</a></li>
...
</ul>
By default I only want to show the h4 titles, not the lists below it. Only when you click a title, it show show the ul content (only showing the first level below). clicking on another title should hide the other ul content of other section and show current ul below the title.
I'm currently stuck with the collapsing code in common.js, everything is always collapsed:
$('.miis-toc > ul > li > a').filter(function(){
return ($(this).attr('href') != '');
}).parent().find('ul > li').hide();
$('.miis-toc > h4').filter(function(){
return ($(this).attr('href') != '');
}).parent().find('ul').hide();
currLink.parentsUntil('.miis-toc > ul').last().find('li').show()
If I understand your question correctly, and understand the way your menu HTML is defined and structured, then a possible solution might be to revise your jQuery like so:
// Hide all ul sublists that are direct children of .miis-toc by
// default
$('> ul', '.miis-toc').hide()
// Listen for click event on h4 elements that are directly under
// .miis-toc
$('> h4', '.miis-toc').click(function() {
// Hide all ul sublists that are direct children of .miis-toc
$('> ul', '.miis-toc').hide()
// Show the ul sublist that is "after" the h4 that has been clicked
// (ie this)
$('+ ul', this).show()
// Prevent default click behaviour
return false;
})
Please see a completed example of this solution on jsFiddle
Updated answer
For the new details that were clarified in the comments below, the following solution should meet all requirements. Note that the JS code will "pre-toggle" menu UL or sub-UL based on URL matching (ie based on the browsers URL pathname).
You will need to update you HTML as follows:
<div class="miis-toc">
<h4>title</h4>
<!-- If path name is /title/, entire tree to this point will be
preopened to here -->
<ul>
<li><a>foo</a></li>
<li>foo
<!-- If path name is /foo/, entire tree to this point will
be preopened to here -->
<ul>
<li><a>sub</a></li>
</ul>
</li>
<li><a>foo</a></li>
</ul>
<h4><a>other title</a></h4>
<ul>
<li><a>other…</a></li>
...
</ul>
</div>
And your updated jQuery as follows:
// This code block sets up the menu when the page first loads, and
// decides which UL or UL sublist to display based on current URL
{
// Hide all UL's that are under .miis-toc
$('ul', '.miis-toc').hide()
// Look for a UL sublist after an anchor with href matching our
// browsers current pathname
var node = $('a[href="'+location.pathname+'"] + ul', '.miis-toc')
// If not found, look for a UL after an h4 with child anchors href
// matching our browsers current pathname
if(node.length === 0) {
var a = $('h4 a[href="'+location.pathname+'"]', '.miis-toc')
node = $('+ ul', a.parent())
}
// If we have found a UL or UL sublist, we need to walk back up the
// "menu tree" and "show" each node (ie UL and/or UL sublist)
if(node.length) {
var parent = node
// When we reach to top of the menu (ie .miis-toc), terminate the
// loop
while(!parent.hasClass('miis-toc')) {
parent.show()
parent = parent.parent()
}
}
}
// Listen for click event on h4 and nested li > a elements under
// .miis-toc
$('h4, li > a', '.miis-toc').click(function(event) {
// Toggle (show/hide) adjacent ul sublist when clicked
$('+ ul', this).toggle()
// Prevent default click behaviour
return false;
})
I am using the below script to hide/show my main nav menu items. You can see it live here: http://205.134.239.12/~artscr6/artscrush/#!
One part of my menu uses down arrows (represented using font awesome with the <i> tags) and when the user hovers over the menu item, the arrow appears. This works in the initial state, but once the user clicks one of the menu items to show the flyout, the hover effect no longer works to show the arrows.
What would I need to add to keep that hover effect happening, but still keep the current behavior as well?
/Remove the link elements from the main nav top level
$('.menuItem a').attr('href', '#!');
//Show the down arrows on hover
$('menuItem').hover(function() {
$(this).find('i').css('opacity', '1');
})
//Once menu is clicked
$('.menuItem').click(function() {
//Reset
menuReset();
//Find the correct flyout
var item = $(this).attr('id');
var id = item.substring(item.indexOf("_") + 1);
var findFlyout = '#acFly_' + id;
//Make this item active
$(this).addClass('active');
//Bumps the current down arrow down a bit and shows it
$(this).find('i').css('opacity', '1');
$(this).find('i').css('top', '7px');
//Show the flyout
event.stopPropagation(); //This prevents dom from overriding us
$(findFlyout).toggle();
//Prevent clicks on the current menu from hiding the flyout
$(findFlyout).click(function(){
event.stopPropagation();
})
})
//Hide the menu when the user clicks anywhere
$(document).click( function(){
menuReset();
})
function menuReset() {
$('.flyMenu').hide();
//Resets the down arrows to orig position and hidden
$('.menuItem').find('i').css('opacity', '0');
$('.menuItem').find('i').css('top', '0px');
$('.menuItem').removeClass('active');
}
//Show the down arrows on hover
$('menuItem').hover(function() { // Shouldn't this be .menuItem instead?
$(this).find('i').css('opacity', '1');
})
Also, in the css file on the link you gave me I find the following:
#menu .ul .li:hover i{
opacity: 1;
}
I don't think ul and li are classes, so why is there a . ?
EDIT: Oh, I see now. You named your divs ul and li. :)
I am trying to sort from two li. If i will delete any div it will be sort by asc.
The fiddle is
i am using jquery append to to move div.
please take a look in my delete function
function del_slide(no,sdiv)
{
$('.s'+no).remove();
if(sdiv==1)
{
alert("first");
$($('.bxslider .btm-slides').last()).appendTo(".bs1");
}
else if($('.bxslider .btm-slides').last())
{
alert("last");
$($('.bxslider .btm-slides').last()).appendTo(".bs1");
}
}
If i am deleting any item !. Then divs are not in order.
How to do all the items in ascending order? I can't do this sort. Please help me.
I need to put first li full. If i will delete any div from first li then one of 2nd li's div should move to the first div. If i will delete from last li the div will be on the same position.
If i will delete any div then last li will blank. But first li will contain 3 div.If I will delete a div from first li then one div from second li will come to first one.
Did you want something that works like this?
JSFiddle: http://jsfiddle.net/TrueBlueAussie/H6PY6/3/
I removed all the unnecessary classes and links and inline javascript as you can connect it all with jQuery and work out the positions via jQuery DOM traversing.
$(function () {
$(".bxslider").on('click', '.editText', function (e) {
// Stop click of link
event.preventDefault();
// Edit code goes here
}).on('click', '.delSlide', function (e) {
// Stop click of link
event.preventDefault();
var $this = $(this);
// Find current slide we clicked
var $slide = $this.closest('.btm-slides');
// Get parent of slide
var $parent = $slide.closest(".bottom-slides");
// if parent li is the first li
if ($parent.closest('li').index() == 0)
{
// Move up one slide from the last li
var $from = $parent.closest(".bxslider").children().last();
// Move up one item from second section
$parent.append($from.find('.btm-slides:first'));
}
// Empty the contents of the deleted slide
$slide.html('');
});
});
Basically I have 2 buttons that when hovered show/hide 2 hidden unordered lists so I use .toggle() for these
What I would also like to do however is when i hover and then click the link the unordered list remains visible, then when i hover and click the other link the previous hidden list is hidden again and the new clicked list is shown? Just not managing to work out how this can be best achieved, at the moment when i hover and then click as soon as i hover off the list disappears.
Hope this makes sense, fiddle is here http://jsfiddle.net/kyllle/D5Lmp/5/
Thanks
EDITED: I see now, updating based on your comment.
Basically, you just have to walk through the set of possibilities:
Hover over something active
Hover over something not active
Click on something active
Click on something not active
It's a logic problem more than anything, and here's the code and the fiddle to solve it:
$('#menu > li > a').hover(function() {
if(!$(this).is('.active')) {
var anyActive = $('#menu > li > a.active');
if (anyActive.length == 0) {
$('ul.inner:visible').hide();
$(this).next().show();
}
}
});
$('#menu > li > a').click(function(e) {
if(!$(this).is('.active')) {
var anyActive = $('#menu > li > a.active');
if (anyActive.length > 0) {
anyActive.next().hide();
anyActive.removeClass('active');
}
$(this).addClass('active');
$(this).next().show();
}
e.preventDefault();
});
Working fiddle: http://jsfiddle.net/D5Lmp/22/
I think I was able to get your desired functionality by excluding the hover toggle based on the active class. You can see it here: http://jsfiddle.net/D5Lmp/9/
code:
$('#menu > li a').hover(function() {
$(this).not(".active").next().toggle();
});
I needed some method of adding/removing classes of a parent element when it's children are clicked to reflect which child is currently selected. In this case a UL parent and LI children in a tab scheme. I needed a way to mark the current tab on the UL so I could style a background sprite on the UL; since styling my LI's backgrounds would not work with the graphics in this case.
I am a jQuery/Javascript/DOM novice, but was able to piece together an ugly solution for starters,
HTML
<!-- tabs -->
<ul class="tabs currenttab-info">
<li id="tab-info" class="info"><strong>Information</strong></li>
<li id="tab-write" class="write"><strong>Write Feedback</strong></li>
<li id="tab-read" class="read"><strong>Read Feedback</strong></li>
</ul>
Javascript
// send '.currenttab-x' to '.tabs' and remove '.currenttab-y' + '.currenttab-z'
// when LI #tab-X is clicked ...
$( '#tab-info' ).click(function() {
// ... find the UL and remove the first possible conflicting class
$('.tabs').removeClass("currenttab-read");
// ... find the UL and remove the other possible conflicting class
$('.tabs').removeClass("currenttab-write");
// ... find the UL and add the class for this LI
$('.tabs').addClass("currenttab-info");
});
// ... repeat ...
$( '#tab-write' ).click(function() {
$('.tabs').removeClass("currenttab-info");
$('.tabs').removeClass("currenttab-read");
$('.tabs').addClass("currenttab-write");
});
$( '#tab-read' ).click(function() {
$('.tabs').removeClass("currenttab-info");
$('.tabs').removeClass("currenttab-write");
$('.tabs').addClass("currenttab-read");
});
This actually seems to be working, BUT it's a fumbling solution and I am sure there is a better way. Some of you jQuery ninjas will know how to put this functionality together really elegantly, any help?
Also I would like to add onto this so that the clicked LI is also given a class to show it is selected while the other LIs are stripped of any such class. The same sort of thing I already am doing for the UL; I can see how to do that with my awkward approach, but it will mean even more and more lines of messy code. If your improvement also included a way to do change classes of the LIs I'd appreciate it
FYI: I'm using jQuery Tools Tabs with this so there is more jQuery then I showed, but only the bit I quoted seems relevant.
html
I will remove ids of li if you are not using it for other purposes.
<ul class="tabs currenttab-info">
<li class="info"><strong>Information</strong></li>
<li class="write"><strong>Write Feedback</strong></li>
<li class="read"><strong>Read Feedback</strong></li>
</ul>
jQuery
$('.tabs li').click(function() {
var $li = $(this);
$li.addClass('current').siblings().removeClass('current'); // adds a current class to the clicked li
var $ul = $li.parent();
$ul.removeClass("currenttab-info currenttab-read currenttab-write")
.addClass("currenttab-" + this.class ); // assuming li only holds one class e.g. class="write"
});
You can just do something like this:
$('.tabs > li').click(function() {
$(this).parent().attr('class', 'tabs').addClass('currenttab-'+$(this).attr('class'));
});
$("UL.tabs LI A").bind('click',function(e){ //bind a Click-Event handler to the Links
var $target = $(e.target); //the jQuery-Object-Reference to the clicked target ( $(this) should work too)
var LIClasses = $target.parents('LI').attr('class'); //A list of all Classes the parrent LI of the clicked Link have
$target
.parents('UL.tabs')
//now you can remove and add classes to the parent "UL.tabs"
.removeClass('...')
.addClass('...')
.end() //after .end() the chain for .parents-match is broken
.parents('LI')
//here you can add and remove classes from the parent LI
.removeClass('...')
.addClass('...')
.end() //after .end() the chain for .parents-match is broken
;
});
Notes:
jQuery is chainable.
.removeClass() and .addClass() can work with multiple classnames at the same time by speration with a space (like .removeClass('class1 class2'))
The full solution:
var relevantClasses = ['read','write','info'];
$("UL.tabs LI A").bind('click',function(e){
var $target = $(e.target);
var relevantClass = '';
for( var cl in $target.parents('LI').attr('class').split(' ') )
if( jQuery.inArray(relevantClasses , cl) > -1 ){
relevantClass = cl;
break;
}
$target
.parents('UL.tabs')
.removeClass(jQuery.map(relevantClasses , function (className) { return 'currenttab-' + className; }).join(' '))
.addClass('currenttab-'+relevantClass )
.end()
;
});
First of all you can chain the method calls...
$('.tabs').removeClass("currenttab-read currenttab-write").addClass("currenttab-write");
This would make the code much cleaner...
EDIT: I'll try such things in Fiddle http://jsfiddle.net/JvtAz/