(function($) {
$.fn.menuTree = function(options) {
...
Developed using jQuery version 1.4 ... Plugin page
Demo of the plugin behavior showing both lists and definition list... Demo
Event delegation for click event binding to tree/list element, instead of binding to each anchor
Tracer plugin added and featured with demo.
<ul id="list1">
<li><a href="#">Menu - toggle animation</a>
<ul>
<li><a href="#">Top Parent - Tier 1</a>
<ul>
<li><a href="#">Child - Tier 2</a>
<ul>
<li><a href="http://pixelhandler.com">Pixelhandler</a> - Tier 3</li>
<li><a href="http://jquery.com">jQuery</a> - Tier 3</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul id="list1">
<li><a href="#" class="menuTree">Menu - toggle animation</a>
<ul class="collapsed">
<li><a href="#" class="menuTree">Top Parent - Tier 1</a>
<ul class="collapsed">
<li><a href="#" class="menuTree">Child - Tier 2</a>
<ul class="collapsed">
<li><a href="http://pixelhandler.com">Pixelhandler</a> - Tier 3</li>
<li><a href="http://jquery.com">jQuery</a> - Tier 3</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul> and <ol> plugin also works with <dl> element
<dl>
<dt><a href="#">Definition list - Term 1</a></dt>
<dd>Description not targeted,
<em>uses CSS classes to collapse/expanded view</em>
</dd>
<dt><a href="#">Term 2</a></dt>
<dd>Description 2</dd>
</dl>
Choose list type to act on when applying $.fn.menuTree
#myTree .menuTree:before {
content: "[+] ";
}
#myTree .expanded:before {
content: "[-] ";
}
#myTree .collapsed {
display: none;
}
(Leaving the visual to the designers)
$(document).ready(function() {
$('#list1').menuTree({
animation: true, // false
handler: 'toggle', // 'slideToggle'
hrefBegins: '#', // root, use '/' or 'http'
listElement: 'ul', // select ul, ol, or dd for hidden sub-menu(s)
speed: 'slow' // 'fast'
});
});
// setup tree behavior and bind on controller
$.fn.menuTree.init = (function() {
$.fn.menuTree.mtTargets.each(function() {
var $localTarget = $(this);
// set state
$localTarget.data({ state: 'ready', responsive: true });
// set behavior up on all .menuTree anchors create with plugin
$localTarget.addClass('menuTree');
// hide the child elements to reveal later // $.fn.menuTree.
reveal($localTarget).toggleClass('collapsed');
// set Click event handler for targets
// $localTarget.click(clickHandler); // => no event delegation
$.fn.menuTree.mtParent.click(clickHandler);
// bind the Controller to listen for state change on
$.fn.menuTree.mtParent.bind('statechange',$.fn.menuTree.controller);
});
});
return $.fn.menuTree.init();
function clickHandler(event) {
var $target = $(event.target);
// if data value is not ready bail out
if (!$target.data('responsive')){
return;
}
$target.stop();
// choose your animation behavior based on options passed to plugin instance
if (!opts.animation) { // false uses CSS to handle effects
reveal($target).toggleClass('collapsed');
$target.toggleClass('expanded').data('state','ready').trigger('statechange');
}
else { // true uses opts.handler to choose effects
$target.data('state','transition').trigger('statechange');
switch(opts.handler) {
case "slideToggle":
reveal($target).slideToggle( opts.speed, function() {
$(this).prev('.menuTree').toggleClass('expanded').data('state','ready').trigger('statechange');
}).toggleClass('collapsed');
break;
case "toggle":
reveal($target).toggle(opts.speed, function() {
$(this).prev('.menuTree').toggleClass('expanded').data('state','ready').trigger('statechange');
}).toggleClass('collapsed');
break;
default: // css only, but if called with true we should do something
}
}
event.preventDefault();
}
$.fn.menuTree.controller = function(event) {
var $target = $(event.target); // manage link state on local target
if ($target.data('state') != 'ready'){
$target.data('responsive',false);
} else {
$target.data('responsive',true);
// may need to collapse children
if ($target.next(opts.listElement).find('.expanded').length > 0) {
$target.next(opts.listElement).find('.expanded').each(function() {
$(this).removeClass('expanded').next(opts.listElement).hide().addClass('collapsed');
});
}
}
};
Depending on duration of animation the target anchor may not be responsive
// tree behavior only operates on anchor elements in the
// list that begin with a hash '#' unless options called for
$.fn.menuTree.mtParent = $(this);
// targeted links
$.fn.menuTree.mtTargets = $.fn.menuTree.mtParent.find("a[href^='"+opts.hrefBegins+"']");
<li> or <dd>
function reveal(element) {
var $reveal = $(element);
// select targets to reveal based on options we choose what list element to target default is 'ul'
switch(opts.listElement) {
case "dd":
$reveal.mtReveal = $reveal.parent().next(opts.listElement);
break;
case "ol":
$reveal.mtReveal = $reveal.next(opts.listElement);
break;
default:
$reveal.mtReveal = $reveal.next(opts.listElement);
}
return $reveal.mtReveal;
}
When parent list is clicked the event.target is referred to to find collapsed element to reveal
...
};
})(jQuery);
More info: