/framework/web/js/source/jquery.treeview.js
JavaScript | 256 lines | 190 code | 20 blank | 46 comment | 18 complexity | d126d4df16d920bdd60f5124e140c9a0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause, GPL-3.0, LGPL-3.0
- /*
- * Treeview 1.5pre - 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);