xref: /OK3568_Linux_fs/yocto/bitbake/lib/toaster/toastergui/static/js/jquery.treetable.js (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun * jQuery treetable Plugin 3.1.0
3*4882a593Smuzhiyun * http://ludo.cubicphuse.nl/jquery-treetable
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright 2013, Ludo van den Boom
6*4882a593Smuzhiyun * Dual licensed under the MIT or GPL Version 2 licenses.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun(function() {
9*4882a593Smuzhiyun  var $, Node, Tree, methods;
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun  $ = jQuery;
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun  Node = (function() {
14*4882a593Smuzhiyun    function Node(row, tree, settings) {
15*4882a593Smuzhiyun      var parentId;
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun      this.row = row;
18*4882a593Smuzhiyun      this.tree = tree;
19*4882a593Smuzhiyun      this.settings = settings;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun      // TODO Ensure id/parentId is always a string (not int)
22*4882a593Smuzhiyun      this.id = this.row.data(this.settings.nodeIdAttr);
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun      // TODO Move this to a setParentId function?
25*4882a593Smuzhiyun      parentId = this.row.data(this.settings.parentIdAttr);
26*4882a593Smuzhiyun      if (parentId != null && parentId !== "") {
27*4882a593Smuzhiyun        this.parentId = parentId;
28*4882a593Smuzhiyun      }
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun      this.treeCell = $(this.row.children(this.settings.columnElType)[this.settings.column]);
31*4882a593Smuzhiyun      this.expander = $(this.settings.expanderTemplate);
32*4882a593Smuzhiyun      this.indenter = $(this.settings.indenterTemplate);
33*4882a593Smuzhiyun      this.children = [];
34*4882a593Smuzhiyun      this.initialized = false;
35*4882a593Smuzhiyun      this.treeCell.prepend(this.indenter);
36*4882a593Smuzhiyun    }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun    Node.prototype.addChild = function(child) {
39*4882a593Smuzhiyun      return this.children.push(child);
40*4882a593Smuzhiyun    };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun    Node.prototype.ancestors = function() {
43*4882a593Smuzhiyun      var ancestors, node;
44*4882a593Smuzhiyun      node = this;
45*4882a593Smuzhiyun      ancestors = [];
46*4882a593Smuzhiyun      while (node = node.parentNode()) {
47*4882a593Smuzhiyun        ancestors.push(node);
48*4882a593Smuzhiyun      }
49*4882a593Smuzhiyun      return ancestors;
50*4882a593Smuzhiyun    };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun    Node.prototype.collapse = function() {
53*4882a593Smuzhiyun      if (this.collapsed()) {
54*4882a593Smuzhiyun        return this;
55*4882a593Smuzhiyun      }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun      this.row.removeClass("expanded").addClass("collapsed");
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun      this._hideChildren();
60*4882a593Smuzhiyun      this.expander.attr("title", this.settings.stringExpand);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun      if (this.initialized && this.settings.onNodeCollapse != null) {
63*4882a593Smuzhiyun        this.settings.onNodeCollapse.apply(this);
64*4882a593Smuzhiyun      }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun      return this;
67*4882a593Smuzhiyun    };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun    Node.prototype.collapsed = function() {
70*4882a593Smuzhiyun      return this.row.hasClass("collapsed");
71*4882a593Smuzhiyun    };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun    // TODO destroy: remove event handlers, expander, indenter, etc.
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun    Node.prototype.expand = function() {
76*4882a593Smuzhiyun      if (this.expanded()) {
77*4882a593Smuzhiyun        return this;
78*4882a593Smuzhiyun      }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun      this.row.removeClass("collapsed").addClass("expanded");
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun      if (this.initialized && this.settings.onNodeExpand != null) {
83*4882a593Smuzhiyun        this.settings.onNodeExpand.apply(this);
84*4882a593Smuzhiyun      }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun      if ($(this.row).is(":visible")) {
87*4882a593Smuzhiyun        this._showChildren();
88*4882a593Smuzhiyun      }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun      this.expander.attr("title", this.settings.stringCollapse);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun      return this;
93*4882a593Smuzhiyun    };
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun    Node.prototype.expanded = function() {
96*4882a593Smuzhiyun      return this.row.hasClass("expanded");
97*4882a593Smuzhiyun    };
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun    Node.prototype.hide = function() {
100*4882a593Smuzhiyun      this._hideChildren();
101*4882a593Smuzhiyun      this.row.hide();
102*4882a593Smuzhiyun      return this;
103*4882a593Smuzhiyun    };
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun    Node.prototype.isBranchNode = function() {
106*4882a593Smuzhiyun      if(this.children.length > 0 || this.row.data(this.settings.branchAttr) === true) {
107*4882a593Smuzhiyun        return true;
108*4882a593Smuzhiyun      } else {
109*4882a593Smuzhiyun        return false;
110*4882a593Smuzhiyun      }
111*4882a593Smuzhiyun    };
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun    Node.prototype.updateBranchLeafClass = function(){
114*4882a593Smuzhiyun      this.row.removeClass('branch');
115*4882a593Smuzhiyun      this.row.removeClass('leaf');
116*4882a593Smuzhiyun      this.row.addClass(this.isBranchNode() ? 'branch' : 'leaf');
117*4882a593Smuzhiyun    };
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun    Node.prototype.level = function() {
120*4882a593Smuzhiyun      return this.ancestors().length;
121*4882a593Smuzhiyun    };
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun    Node.prototype.parentNode = function() {
124*4882a593Smuzhiyun      if (this.parentId != null) {
125*4882a593Smuzhiyun        return this.tree[this.parentId];
126*4882a593Smuzhiyun      } else {
127*4882a593Smuzhiyun        return null;
128*4882a593Smuzhiyun      }
129*4882a593Smuzhiyun    };
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun    Node.prototype.removeChild = function(child) {
132*4882a593Smuzhiyun      var i = $.inArray(child, this.children);
133*4882a593Smuzhiyun      return this.children.splice(i, 1)
134*4882a593Smuzhiyun    };
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun    Node.prototype.render = function() {
137*4882a593Smuzhiyun      var handler,
138*4882a593Smuzhiyun          settings = this.settings,
139*4882a593Smuzhiyun          target;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun      if (settings.expandable === true && this.isBranchNode()) {
142*4882a593Smuzhiyun        handler = function(e) {
143*4882a593Smuzhiyun          $(this).parents("table").treetable("node", $(this).parents("tr").data(settings.nodeIdAttr)).toggle();
144*4882a593Smuzhiyun          return e.preventDefault();
145*4882a593Smuzhiyun        };
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun        this.indenter.html(this.expander);
148*4882a593Smuzhiyun        target = settings.clickableNodeNames === true ? this.treeCell : this.expander;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun        target.off("click.treetable").on("click.treetable", handler);
151*4882a593Smuzhiyun        target.off("keydown.treetable").on("keydown.treetable", function(e) {
152*4882a593Smuzhiyun          if (e.keyCode == 13) {
153*4882a593Smuzhiyun            handler.apply(this, [e]);
154*4882a593Smuzhiyun          }
155*4882a593Smuzhiyun        });
156*4882a593Smuzhiyun      }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun      this.indenter[0].style.paddingLeft = "" + (this.level() * settings.indent) + "px";
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun      return this;
161*4882a593Smuzhiyun    };
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun    Node.prototype.reveal = function() {
164*4882a593Smuzhiyun      if (this.parentId != null) {
165*4882a593Smuzhiyun        this.parentNode().reveal();
166*4882a593Smuzhiyun      }
167*4882a593Smuzhiyun      return this.expand();
168*4882a593Smuzhiyun    };
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun    Node.prototype.setParent = function(node) {
171*4882a593Smuzhiyun      if (this.parentId != null) {
172*4882a593Smuzhiyun        this.tree[this.parentId].removeChild(this);
173*4882a593Smuzhiyun      }
174*4882a593Smuzhiyun      this.parentId = node.id;
175*4882a593Smuzhiyun      this.row.data(this.settings.parentIdAttr, node.id);
176*4882a593Smuzhiyun      return node.addChild(this);
177*4882a593Smuzhiyun    };
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun    Node.prototype.show = function() {
180*4882a593Smuzhiyun      if (!this.initialized) {
181*4882a593Smuzhiyun        this._initialize();
182*4882a593Smuzhiyun      }
183*4882a593Smuzhiyun      this.row.show();
184*4882a593Smuzhiyun      if (this.expanded()) {
185*4882a593Smuzhiyun        this._showChildren();
186*4882a593Smuzhiyun      }
187*4882a593Smuzhiyun      return this;
188*4882a593Smuzhiyun    };
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun    Node.prototype.toggle = function() {
191*4882a593Smuzhiyun      if (this.expanded()) {
192*4882a593Smuzhiyun        this.collapse();
193*4882a593Smuzhiyun      } else {
194*4882a593Smuzhiyun        this.expand();
195*4882a593Smuzhiyun      }
196*4882a593Smuzhiyun      return this;
197*4882a593Smuzhiyun    };
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun    Node.prototype._hideChildren = function() {
200*4882a593Smuzhiyun      var child, _i, _len, _ref, _results;
201*4882a593Smuzhiyun      _ref = this.children;
202*4882a593Smuzhiyun      _results = [];
203*4882a593Smuzhiyun      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
204*4882a593Smuzhiyun        child = _ref[_i];
205*4882a593Smuzhiyun        _results.push(child.hide());
206*4882a593Smuzhiyun      }
207*4882a593Smuzhiyun      return _results;
208*4882a593Smuzhiyun    };
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun    Node.prototype._initialize = function() {
211*4882a593Smuzhiyun      var settings = this.settings;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun      this.render();
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun      if (settings.expandable === true && settings.initialState === "collapsed") {
216*4882a593Smuzhiyun        this.collapse();
217*4882a593Smuzhiyun      } else {
218*4882a593Smuzhiyun        this.expand();
219*4882a593Smuzhiyun      }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun      if (settings.onNodeInitialized != null) {
222*4882a593Smuzhiyun        settings.onNodeInitialized.apply(this);
223*4882a593Smuzhiyun      }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun      return this.initialized = true;
226*4882a593Smuzhiyun    };
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun    Node.prototype._showChildren = function() {
229*4882a593Smuzhiyun      var child, _i, _len, _ref, _results;
230*4882a593Smuzhiyun      _ref = this.children;
231*4882a593Smuzhiyun      _results = [];
232*4882a593Smuzhiyun      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
233*4882a593Smuzhiyun        child = _ref[_i];
234*4882a593Smuzhiyun        _results.push(child.show());
235*4882a593Smuzhiyun      }
236*4882a593Smuzhiyun      return _results;
237*4882a593Smuzhiyun    };
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun    return Node;
240*4882a593Smuzhiyun  })();
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun  Tree = (function() {
243*4882a593Smuzhiyun    function Tree(table, settings) {
244*4882a593Smuzhiyun      this.table = table;
245*4882a593Smuzhiyun      this.settings = settings;
246*4882a593Smuzhiyun      this.tree = {};
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun      // Cache the nodes and roots in simple arrays for quick access/iteration
249*4882a593Smuzhiyun      this.nodes = [];
250*4882a593Smuzhiyun      this.roots = [];
251*4882a593Smuzhiyun    }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun    Tree.prototype.collapseAll = function() {
254*4882a593Smuzhiyun      var node, _i, _len, _ref, _results;
255*4882a593Smuzhiyun      _ref = this.nodes;
256*4882a593Smuzhiyun      _results = [];
257*4882a593Smuzhiyun      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
258*4882a593Smuzhiyun        node = _ref[_i];
259*4882a593Smuzhiyun        _results.push(node.collapse());
260*4882a593Smuzhiyun      }
261*4882a593Smuzhiyun      return _results;
262*4882a593Smuzhiyun    };
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun    Tree.prototype.expandAll = function() {
265*4882a593Smuzhiyun      var node, _i, _len, _ref, _results;
266*4882a593Smuzhiyun      _ref = this.nodes;
267*4882a593Smuzhiyun      _results = [];
268*4882a593Smuzhiyun      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
269*4882a593Smuzhiyun        node = _ref[_i];
270*4882a593Smuzhiyun        _results.push(node.expand());
271*4882a593Smuzhiyun      }
272*4882a593Smuzhiyun      return _results;
273*4882a593Smuzhiyun    };
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun    Tree.prototype.findLastNode = function (node) {
276*4882a593Smuzhiyun      if (node.children.length > 0) {
277*4882a593Smuzhiyun        return this.findLastNode(node.children[node.children.length - 1]);
278*4882a593Smuzhiyun      } else {
279*4882a593Smuzhiyun        return node;
280*4882a593Smuzhiyun      }
281*4882a593Smuzhiyun    };
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun    Tree.prototype.loadRows = function(rows) {
284*4882a593Smuzhiyun      var node, row, i;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun      if (rows != null) {
287*4882a593Smuzhiyun        for (i = 0; i < rows.length; i++) {
288*4882a593Smuzhiyun          row = $(rows[i]);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun          if (row.data(this.settings.nodeIdAttr) != null) {
291*4882a593Smuzhiyun            node = new Node(row, this.tree, this.settings);
292*4882a593Smuzhiyun            this.nodes.push(node);
293*4882a593Smuzhiyun            this.tree[node.id] = node;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun            if (node.parentId != null) {
296*4882a593Smuzhiyun              this.tree[node.parentId].addChild(node);
297*4882a593Smuzhiyun            } else {
298*4882a593Smuzhiyun              this.roots.push(node);
299*4882a593Smuzhiyun            }
300*4882a593Smuzhiyun          }
301*4882a593Smuzhiyun        }
302*4882a593Smuzhiyun      }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun      for (i = 0; i < this.nodes.length; i++) {
305*4882a593Smuzhiyun        node = this.nodes[i].updateBranchLeafClass();
306*4882a593Smuzhiyun      }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun      return this;
309*4882a593Smuzhiyun    };
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun    Tree.prototype.move = function(node, destination) {
312*4882a593Smuzhiyun      // Conditions:
313*4882a593Smuzhiyun      // 1: +node+ should not be inserted as a child of +node+ itself.
314*4882a593Smuzhiyun      // 2: +destination+ should not be the same as +node+'s current parent (this
315*4882a593Smuzhiyun      //    prevents +node+ from being moved to the same location where it already
316*4882a593Smuzhiyun      //    is).
317*4882a593Smuzhiyun      // 3: +node+ should not be inserted in a location in a branch if this would
318*4882a593Smuzhiyun      //    result in +node+ being an ancestor of itself.
319*4882a593Smuzhiyun      var nodeParent = node.parentNode();
320*4882a593Smuzhiyun      if (node !== destination && destination.id !== node.parentId && $.inArray(node, destination.ancestors()) === -1) {
321*4882a593Smuzhiyun        node.setParent(destination);
322*4882a593Smuzhiyun        this._moveRows(node, destination);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun        // Re-render parentNode if this is its first child node, and therefore
325*4882a593Smuzhiyun        // doesn't have the expander yet.
326*4882a593Smuzhiyun        if (node.parentNode().children.length === 1) {
327*4882a593Smuzhiyun          node.parentNode().render();
328*4882a593Smuzhiyun        }
329*4882a593Smuzhiyun      }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun      if(nodeParent){
332*4882a593Smuzhiyun        nodeParent.updateBranchLeafClass();
333*4882a593Smuzhiyun      }
334*4882a593Smuzhiyun      if(node.parentNode()){
335*4882a593Smuzhiyun        node.parentNode().updateBranchLeafClass();
336*4882a593Smuzhiyun      }
337*4882a593Smuzhiyun      node.updateBranchLeafClass();
338*4882a593Smuzhiyun      return this;
339*4882a593Smuzhiyun    };
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun    Tree.prototype.removeNode = function(node) {
342*4882a593Smuzhiyun      // Recursively remove all descendants of +node+
343*4882a593Smuzhiyun      this.unloadBranch(node);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun      // Remove node from DOM (<tr>)
346*4882a593Smuzhiyun      node.row.remove();
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun      // Clean up Tree object (so Node objects are GC-ed)
349*4882a593Smuzhiyun      delete this.tree[node.id];
350*4882a593Smuzhiyun      this.nodes.splice($.inArray(node, this.nodes), 1);
351*4882a593Smuzhiyun    }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun    Tree.prototype.render = function() {
354*4882a593Smuzhiyun      var root, _i, _len, _ref;
355*4882a593Smuzhiyun      _ref = this.roots;
356*4882a593Smuzhiyun      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
357*4882a593Smuzhiyun        root = _ref[_i];
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun        // Naming is confusing (show/render). I do not call render on node from
360*4882a593Smuzhiyun        // here.
361*4882a593Smuzhiyun        root.show();
362*4882a593Smuzhiyun      }
363*4882a593Smuzhiyun      return this;
364*4882a593Smuzhiyun    };
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun    Tree.prototype.sortBranch = function(node, sortFun) {
367*4882a593Smuzhiyun      // First sort internal array of children
368*4882a593Smuzhiyun      node.children.sort(sortFun);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun      // Next render rows in correct order on page
371*4882a593Smuzhiyun      this._sortChildRows(node);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun      return this;
374*4882a593Smuzhiyun    };
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun    Tree.prototype.unloadBranch = function(node) {
377*4882a593Smuzhiyun      var children, i;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun      for (i = 0; i < node.children.length; i++) {
380*4882a593Smuzhiyun        this.removeNode(node.children[i]);
381*4882a593Smuzhiyun      }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun      // Reset node's collection of children
384*4882a593Smuzhiyun      node.children = [];
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun      node.updateBranchLeafClass();
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun      return this;
389*4882a593Smuzhiyun    };
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun    Tree.prototype._moveRows = function(node, destination) {
392*4882a593Smuzhiyun      var children = node.children, i;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun      node.row.insertAfter(destination.row);
395*4882a593Smuzhiyun      node.render();
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun      // Loop backwards through children to have them end up on UI in correct
398*4882a593Smuzhiyun      // order (see #112)
399*4882a593Smuzhiyun      for (i = children.length - 1; i >= 0; i--) {
400*4882a593Smuzhiyun        this._moveRows(children[i], node);
401*4882a593Smuzhiyun      }
402*4882a593Smuzhiyun    };
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun    // Special _moveRows case, move children to itself to force sorting
405*4882a593Smuzhiyun    Tree.prototype._sortChildRows = function(parentNode) {
406*4882a593Smuzhiyun      return this._moveRows(parentNode, parentNode);
407*4882a593Smuzhiyun    };
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun    return Tree;
410*4882a593Smuzhiyun  })();
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun  // jQuery Plugin
413*4882a593Smuzhiyun  methods = {
414*4882a593Smuzhiyun    init: function(options, force) {
415*4882a593Smuzhiyun      var settings;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun      settings = $.extend({
418*4882a593Smuzhiyun        branchAttr: "ttBranch",
419*4882a593Smuzhiyun        clickableNodeNames: false,
420*4882a593Smuzhiyun        column: 0,
421*4882a593Smuzhiyun        columnElType: "td", // i.e. 'td', 'th' or 'td,th'
422*4882a593Smuzhiyun        expandable: false,
423*4882a593Smuzhiyun        expanderTemplate: "<a href='#'>&nbsp;</a>",
424*4882a593Smuzhiyun        indent: 10,
425*4882a593Smuzhiyun        indenterTemplate: "<span class='indenter'></span>",
426*4882a593Smuzhiyun        initialState: "collapsed",
427*4882a593Smuzhiyun        nodeIdAttr: "ttId", // maps to data-tt-id
428*4882a593Smuzhiyun        parentIdAttr: "ttParentId", // maps to data-tt-parent-id
429*4882a593Smuzhiyun        stringExpand: "Expand",
430*4882a593Smuzhiyun        stringCollapse: "Collapse",
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun        // Events
433*4882a593Smuzhiyun        onInitialized: null,
434*4882a593Smuzhiyun        onNodeCollapse: null,
435*4882a593Smuzhiyun        onNodeExpand: null,
436*4882a593Smuzhiyun        onNodeInitialized: null
437*4882a593Smuzhiyun      }, options);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun      return this.each(function() {
440*4882a593Smuzhiyun        var el = $(this), tree;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun        if (force || el.data("treetable") === undefined) {
443*4882a593Smuzhiyun          tree = new Tree(this, settings);
444*4882a593Smuzhiyun          tree.loadRows(this.rows).render();
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun          el.addClass("treetable").data("treetable", tree);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun          if (settings.onInitialized != null) {
449*4882a593Smuzhiyun            settings.onInitialized.apply(tree);
450*4882a593Smuzhiyun          }
451*4882a593Smuzhiyun        }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun        return el;
454*4882a593Smuzhiyun      });
455*4882a593Smuzhiyun    },
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun    destroy: function() {
458*4882a593Smuzhiyun      return this.each(function() {
459*4882a593Smuzhiyun        return $(this).removeData("treetable").removeClass("treetable");
460*4882a593Smuzhiyun      });
461*4882a593Smuzhiyun    },
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun    collapseAll: function() {
464*4882a593Smuzhiyun      this.data("treetable").collapseAll();
465*4882a593Smuzhiyun      return this;
466*4882a593Smuzhiyun    },
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun    collapseNode: function(id) {
469*4882a593Smuzhiyun      var node = this.data("treetable").tree[id];
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun      if (node) {
472*4882a593Smuzhiyun        node.collapse();
473*4882a593Smuzhiyun      } else {
474*4882a593Smuzhiyun        throw new Error("Unknown node '" + id + "'");
475*4882a593Smuzhiyun      }
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun      return this;
478*4882a593Smuzhiyun    },
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun    expandAll: function() {
481*4882a593Smuzhiyun      this.data("treetable").expandAll();
482*4882a593Smuzhiyun      return this;
483*4882a593Smuzhiyun    },
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun    expandNode: function(id) {
486*4882a593Smuzhiyun      var node = this.data("treetable").tree[id];
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun      if (node) {
489*4882a593Smuzhiyun        if (!node.initialized) {
490*4882a593Smuzhiyun          node._initialize();
491*4882a593Smuzhiyun        }
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun        node.expand();
494*4882a593Smuzhiyun      } else {
495*4882a593Smuzhiyun        throw new Error("Unknown node '" + id + "'");
496*4882a593Smuzhiyun      }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun      return this;
499*4882a593Smuzhiyun    },
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun    loadBranch: function(node, rows) {
502*4882a593Smuzhiyun      var settings = this.data("treetable").settings,
503*4882a593Smuzhiyun          tree = this.data("treetable").tree;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun      // TODO Switch to $.parseHTML
506*4882a593Smuzhiyun      rows = $(rows);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun      if (node == null) { // Inserting new root nodes
509*4882a593Smuzhiyun        this.append(rows);
510*4882a593Smuzhiyun      } else {
511*4882a593Smuzhiyun        var lastNode = this.data("treetable").findLastNode(node);
512*4882a593Smuzhiyun        rows.insertAfter(lastNode.row);
513*4882a593Smuzhiyun      }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun      this.data("treetable").loadRows(rows);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun      // Make sure nodes are properly initialized
518*4882a593Smuzhiyun      rows.filter("tr").each(function() {
519*4882a593Smuzhiyun        tree[$(this).data(settings.nodeIdAttr)].show();
520*4882a593Smuzhiyun      });
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun      if (node != null) {
523*4882a593Smuzhiyun        // Re-render parent to ensure expander icon is shown (#79)
524*4882a593Smuzhiyun        node.render().expand();
525*4882a593Smuzhiyun      }
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun      return this;
528*4882a593Smuzhiyun    },
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun    move: function(nodeId, destinationId) {
531*4882a593Smuzhiyun      var destination, node;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun      node = this.data("treetable").tree[nodeId];
534*4882a593Smuzhiyun      destination = this.data("treetable").tree[destinationId];
535*4882a593Smuzhiyun      this.data("treetable").move(node, destination);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun      return this;
538*4882a593Smuzhiyun    },
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun    node: function(id) {
541*4882a593Smuzhiyun      return this.data("treetable").tree[id];
542*4882a593Smuzhiyun    },
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun    removeNode: function(id) {
545*4882a593Smuzhiyun      var node = this.data("treetable").tree[id];
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun      if (node) {
548*4882a593Smuzhiyun        this.data("treetable").removeNode(node);
549*4882a593Smuzhiyun      } else {
550*4882a593Smuzhiyun        throw new Error("Unknown node '" + id + "'");
551*4882a593Smuzhiyun      }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun      return this;
554*4882a593Smuzhiyun    },
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun    reveal: function(id) {
557*4882a593Smuzhiyun      var node = this.data("treetable").tree[id];
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun      if (node) {
560*4882a593Smuzhiyun        node.reveal();
561*4882a593Smuzhiyun      } else {
562*4882a593Smuzhiyun        throw new Error("Unknown node '" + id + "'");
563*4882a593Smuzhiyun      }
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun      return this;
566*4882a593Smuzhiyun    },
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun    sortBranch: function(node, columnOrFunction) {
569*4882a593Smuzhiyun      var settings = this.data("treetable").settings,
570*4882a593Smuzhiyun          prepValue,
571*4882a593Smuzhiyun          sortFun;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun      columnOrFunction = columnOrFunction || settings.column;
574*4882a593Smuzhiyun      sortFun = columnOrFunction;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun      if ($.isNumeric(columnOrFunction)) {
577*4882a593Smuzhiyun        sortFun = function(a, b) {
578*4882a593Smuzhiyun          var extractValue, valA, valB;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun          extractValue = function(node) {
581*4882a593Smuzhiyun            var val = node.row.find("td:eq(" + columnOrFunction + ")").text();
582*4882a593Smuzhiyun            // Ignore trailing/leading whitespace and use uppercase values for
583*4882a593Smuzhiyun            // case insensitive ordering
584*4882a593Smuzhiyun            return $.trim(val).toUpperCase();
585*4882a593Smuzhiyun          }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun          valA = extractValue(a);
588*4882a593Smuzhiyun          valB = extractValue(b);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun          if (valA < valB) return -1;
591*4882a593Smuzhiyun          if (valA > valB) return 1;
592*4882a593Smuzhiyun          return 0;
593*4882a593Smuzhiyun        };
594*4882a593Smuzhiyun      }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun      this.data("treetable").sortBranch(node, sortFun);
597*4882a593Smuzhiyun      return this;
598*4882a593Smuzhiyun    },
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun    unloadBranch: function(node) {
601*4882a593Smuzhiyun      this.data("treetable").unloadBranch(node);
602*4882a593Smuzhiyun      return this;
603*4882a593Smuzhiyun    }
604*4882a593Smuzhiyun  };
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun  $.fn.treetable = function(method) {
607*4882a593Smuzhiyun    if (methods[method]) {
608*4882a593Smuzhiyun      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
609*4882a593Smuzhiyun    } else if (typeof method === 'object' || !method) {
610*4882a593Smuzhiyun      return methods.init.apply(this, arguments);
611*4882a593Smuzhiyun    } else {
612*4882a593Smuzhiyun      return $.error("Method " + method + " does not exist on jQuery.treetable");
613*4882a593Smuzhiyun    }
614*4882a593Smuzhiyun  };
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun  // Expose classes to world
617*4882a593Smuzhiyun  this.TreeTable || (this.TreeTable = {});
618*4882a593Smuzhiyun  this.TreeTable.Node = Node;
619*4882a593Smuzhiyun  this.TreeTable.Tree = Tree;
620*4882a593Smuzhiyun}).call(this);
621