| /* |
| * Treeview 1.4.1 - jQuery plugin to hide and show branches of a tree |
| * |
| * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ |
| * http://docs.jquery.com/Plugins/Treeview |
| * |
| * Copyright (c) 2007 Jörn Zaefferer |
| * |
| * Dual licensed under the MIT and GPL licenses: |
| * http://www.opensource.org/licenses/mit-license.php |
| * http://www.gnu.org/licenses/gpl.html |
| * |
| * Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $ |
| * |
| */ |
| |
| ;(function($) { |
| |
| // TODO rewrite as a widget, removing all the extra plugins |
| $.extend($.fn, { |
| swapClass: function(c1, c2) { |
| var c1Elements = this.filter('.' + c1); |
| this.filter('.' + c2).removeClass(c2).addClass(c1); |
| c1Elements.removeClass(c1).addClass(c2); |
| return this; |
| }, |
| replaceClass: function(c1, c2) { |
| return this.filter('.' + c1).removeClass(c1).addClass(c2).end(); |
| }, |
| hoverClass: function(className) { |
| className = className || "hover"; |
| return this.hover(function() { |
| $(this).addClass(className); |
| }, function() { |
| $(this).removeClass(className); |
| }); |
| }, |
| heightToggle: function(animated, callback) { |
| animated ? |
| this.animate({ height: "toggle" }, animated, callback) : |
| this.each(function(){ |
| jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); |
| if(callback) |
| callback.apply(this, arguments); |
| }); |
| }, |
| heightHide: function(animated, callback) { |
| if (animated) { |
| this.animate({ height: "hide" }, animated, callback); |
| } else { |
| this.hide(); |
| if (callback) |
| this.each(callback); |
| } |
| }, |
| prepareBranches: function(settings) { |
| if (!settings.prerendered) { |
| // mark last tree items |
| this.filter(":last-child:not(ul)").addClass(CLASSES.last); |
| // collapse whole tree, or only those marked as closed, anyway except those marked as open |
| this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide(); |
| } |
| // return all items with sublists |
| return this.filter(":has(>ul)"); |
| }, |
| applyClasses: function(settings, toggler) { |
| // TODO use event delegation |
| this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) { |
| // don't handle click events on children, eg. checkboxes |
| if ( this == event.target ) |
| toggler.apply($(this).next()); |
| }).add( $("a", this) ).hoverClass(); |
| |
| if (!settings.prerendered) { |
| // handle closed ones first |
| this.filter(":has(>ul:hidden)") |
| .addClass(CLASSES.expandable) |
| .replaceClass(CLASSES.last, CLASSES.lastExpandable); |
| |
| // handle open ones |
| this.not(":has(>ul:hidden)") |
| .addClass(CLASSES.collapsable) |
| .replaceClass(CLASSES.last, CLASSES.lastCollapsable); |
| |
| // create hitarea if not present |
| var hitarea = this.find("div." + CLASSES.hitarea); |
| if (!hitarea.length) |
| hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea); |
| hitarea.removeClass().addClass(CLASSES.hitarea).each(function() { |
| var classes = ""; |
| $.each($(this).parent().attr("class").split(" "), function() { |
| classes += this + "-hitarea "; |
| }); |
| $(this).addClass( classes ); |
| }) |
| } |
| |
| // apply event to hitarea |
| this.find("div." + CLASSES.hitarea).click( toggler ); |
| }, |
| treeview: function(settings) { |
| |
| settings = $.extend({ |
| cookieId: "treeview" |
| }, settings); |
| |
| if ( settings.toggle ) { |
| var callback = settings.toggle; |
| settings.toggle = function() { |
| return callback.apply($(this).parent()[0], arguments); |
| }; |
| } |
| |
| // factory for treecontroller |
| function treeController(tree, control) { |
| // factory for click handlers |
| function handler(filter) { |
| return function() { |
| // reuse toggle event handler, applying the elements to toggle |
| // start searching for all hitareas |
| toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { |
| // for plain toggle, no filter is provided, otherwise we need to check the parent element |
| return filter ? $(this).parent("." + filter).length : true; |
| }) ); |
| return false; |
| }; |
| } |
| // click on first element to collapse tree |
| $("a:eq(0)", control).click( handler(CLASSES.collapsable) ); |
| // click on second to expand tree |
| $("a:eq(1)", control).click( handler(CLASSES.expandable) ); |
| // click on third to toggle tree |
| $("a:eq(2)", control).click( handler() ); |
| } |
| |
| // handle toggle event |
| function toggler() { |
| $(this) |
| .parent() |
| // swap classes for hitarea |
| .find(">.hitarea") |
| .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) |
| .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) |
| .end() |
| // swap classes for parent li |
| .swapClass( CLASSES.collapsable, CLASSES.expandable ) |
| .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) |
| // find child lists |
| .find( ">ul" ) |
| // toggle them |
| .heightToggle( settings.animated, settings.toggle ); |
| if ( settings.unique ) { |
| $(this).parent() |
| .siblings() |
| // swap classes for hitarea |
| .find(">.hitarea") |
| .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) |
| .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) |
| .end() |
| .replaceClass( CLASSES.collapsable, CLASSES.expandable ) |
| .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) |
| .find( ">ul" ) |
| .heightHide( settings.animated, settings.toggle ); |
| } |
| } |
| this.data("toggler", toggler); |
| |
| function serialize() { |
| function binary(arg) { |
| return arg ? 1 : 0; |
| } |
| var data = []; |
| branches.each(function(i, e) { |
| data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0; |
| }); |
| $.cookie(settings.cookieId, data.join(""), settings.cookieOptions ); |
| } |
| |
| function deserialize() { |
| var stored = $.cookie(settings.cookieId); |
| if ( stored ) { |
| var data = stored.split(""); |
| branches.each(function(i, e) { |
| $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ](); |
| }); |
| } |
| } |
| |
| // add treeview class to activate styles |
| this.addClass("treeview"); |
| |
| // prepare branches and find all tree items with child lists |
| var branches = this.find("li").prepareBranches(settings); |
| |
| switch(settings.persist) { |
| case "cookie": |
| var toggleCallback = settings.toggle; |
| settings.toggle = function() { |
| serialize(); |
| if (toggleCallback) { |
| toggleCallback.apply(this, arguments); |
| } |
| }; |
| deserialize(); |
| break; |
| case "location": |
| var current = this.find("a").filter(function() { |
| return this.href.toLowerCase() == location.href.toLowerCase(); |
| }); |
| if ( current.length ) { |
| // TODO update the open/closed classes |
| var items = current.addClass("selected").parents("ul, li").add( current.next() ).show(); |
| if (settings.prerendered) { |
| // if prerendered is on, replicate the basic class swapping |
| items.filter("li") |
| .swapClass( CLASSES.collapsable, CLASSES.expandable ) |
| .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) |
| .find(">.hitarea") |
| .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) |
| .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ); |
| } |
| } |
| break; |
| } |
| |
| branches.applyClasses(settings, toggler); |
| |
| // if control option is set, create the treecontroller and show it |
| if ( settings.control ) { |
| treeController(this, settings.control); |
| $(settings.control).show(); |
| } |
| |
| return this; |
| } |
| }); |
| |
| // classes used by the plugin |
| // need to be styled via external stylesheet, see first example |
| $.treeview = {}; |
| var CLASSES = ($.treeview.classes = { |
| open: "open", |
| closed: "closed", |
| expandable: "expandable", |
| expandableHitarea: "expandable-hitarea", |
| lastExpandableHitarea: "lastExpandable-hitarea", |
| collapsable: "collapsable", |
| collapsableHitarea: "collapsable-hitarea", |
| lastCollapsableHitarea: "lastCollapsable-hitarea", |
| lastCollapsable: "lastCollapsable", |
| lastExpandable: "lastExpandable", |
| last: "last", |
| hitarea: "hitarea" |
| }); |
| |
| })(jQuery); |