/************************************************************************* jquery.dynatree.js Dynamic tree view control, with support for lazy loading of branches. Copyright (c) 2008-2011, Martin Wendt (http://wwWendt.de) Dual licensed under the MIT or GPL Version 2 licenses. http://code.google.com/p/dynatree/wiki/LicenseInfo A current version and some documentation is available at http://dynatree.googlecode.com/ $Version:$ $Revision:$ @depends: jquery.js @depends: jquery.ui.core.js @depends: jquery.cookie.js *************************************************************************/ // Note: We currently allow eval() to parse the 'data' attribtes, when initializing from HTML. /*jslint laxbreak: true, browser: true, evil: true, indent: 0, white: false, onevar: false */ /************************************************************************* * Debug functions */ var _canLog = true; function _log(mode, msg) { /** * Usage: logMsg("%o was toggled", this); */ if (!_canLog) { return; } // Remove first argument var args = Array.prototype.slice.apply(arguments, [1]); // Prepend timestamp var dt = new Date(); var tag = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds() + "." + dt.getMilliseconds(); args[0] = tag + " - " + args[0]; try { switch (mode) { case "info": window.console.info.apply(window.console, args); break; case "warn": window.console.warn.apply(window.console, args); break; default: window.console.log.apply(window.console, args); break; } } catch(e) { if (!window.console) { _canLog = false; // Permanently disable, when logging is not supported by the browser } } } function logMsg(msg) { Array.prototype.unshift.apply(arguments, ["debug"]); _log.apply(this, arguments); } // Forward declaration var getDynaTreePersistData = null; /************************************************************************* * Constants */ var DTNodeStatus_Error = -1; var DTNodeStatus_Loading = 1; var DTNodeStatus_Ok = 0; // Start of local namespace (function($) { /************************************************************************* * Common tool functions. */ var Class = { create: function() { return function() { this.initialize.apply(this, arguments); }; } }; // Tool function to get dtnode from the event target: function getDtNodeFromElement(el) { var iMax = 5; while (el && iMax--) { if (el.dtnode) { return el.dtnode; } el = el.parentNode; } return null; } function noop() { } /************************************************************************* * Class DynaTreeNode */ var DynaTreeNode = Class.create(); DynaTreeNode.prototype = { initialize: function(parent, tree, data) { /** * @constructor */ this.parent = parent; this.tree = tree; if (typeof data === "string") { data = { title: data }; } if (data.key === undefined) { data.key = "_" + tree._nodeCount++; } this.data = $.extend({}, $.ui.dynatree.nodedatadefaults, data); this.li = null; // not yet created this.span = null; // not yet created this.ul = null; // not yet created this.childList = null; // no subnodes yet this.isLoading = false; // Lazy content is being loaded this.hasSubSel = false; this.bExpanded = false; this.bSelected = false; }, toString: function() { return "DynaTreeNode<" + this.data.key + ">: '" + this.data.title + "'"; }, toDict: function(recursive, callback) { var dict = $.extend({}, this.data); dict.activate = ( this.tree.activeNode === this ); dict.focus = ( this.tree.focusNode === this ); dict.expand = this.bExpanded; dict.select = this.bSelected; if (callback) { callback(dict); } if (recursive && this.childList) { dict.children = []; for (var i = 0, l = this.childList.length; i < l; i++) { dict.children.push(this.childList[i].toDict(true, callback)); } } else { delete dict.children; } return dict; }, fromDict: function(dict) { /** * Update node data. If dict contains 'children', then also replace * the hole sub tree. */ var children = dict.children; if (children === undefined) { this.data = $.extend(this.data, dict); this.render(); return; } dict = $.extend({}, dict); dict.children = undefined; this.data = $.extend(this.data, dict); this.removeChildren(); this.addChild(children); }, _getInnerHtml: function() { var tree = this.tree, opts = tree.options, cache = tree.cache, level = this.getLevel(), data = this.data, res = ""; // connector (expanded, expandable or simple) if (level < opts.minExpandLevel) { if (level > 1) { res += cache.tagConnector; } // .. else (i.e. for root level) skip expander/connector altogether } else if (this.hasChildren() !== false) { res += cache.tagExpander; } else { res += cache.tagConnector; } // Checkbox mode if (opts.checkbox && data.hideCheckbox !== true && !data.isStatusNode) { res += cache.tagCheckbox; } // folder or doctype icon if (data.icon) { res += ""; } else if (data.icon === false) { // icon == false means 'no icon' noop(); // keep JSLint happy } else { // icon == null means 'default icon' res += cache.tagNodeIcon; } // node title var nodeTitle = ""; if (opts.onCustomRender) { nodeTitle = opts.onCustomRender.call(tree, this) || ""; } if (!nodeTitle) { var tooltip = data.tooltip ? " title='" + data.tooltip + "'" : ""; if (opts.noLink || data.noLink) { nodeTitle = "" + data.title + ""; // this.tree.logDebug("nodeTitle: " + nodeTitle); } else { nodeTitle = "" + data.title + ""; } } res += nodeTitle; return res; }, _fixOrder: function() { /** * Make sure, that
  • order matches childList order. */ var cl = this.childList; if (!cl || !this.ul) { return; } var childLI = this.ul.firstChild; for (var i = 0, l = cl.length - 1; i < l; i++) { var childNode1 = cl[i]; var childNode2 = childLI.dtnode; if (childNode1 !== childNode2) { this.tree.logDebug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2); this.ul.insertBefore(childNode1.li, childNode2.li); } else { childLI = childLI.nextSibling; } } }, render: function(useEffects, includeInvisible) { /** * Create
  • .. ..
  • tags for this node. * *
  • // This div contains the node's span and list of child div's. * S S S A // Span contains graphic spans and title tag * *
  • */ // this.tree.logDebug("%s.render(%s)", this, useEffects); // --- var tree = this.tree, parent = this.parent, data = this.data, opts = tree.options, cn = opts.classNames, isLastSib = this.isLastSibling(); if (!parent && !this.ul) { // Root node has only a