browse-everything 1.0.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +82 -133
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +43 -35
  5. data/CONTRIBUTING.md +3 -3
  6. data/Gemfile +3 -6
  7. data/LICENSE.txt +205 -22
  8. data/README.md +7 -6
  9. data/app/assets/javascripts/browse_everything/behavior.js +16 -8
  10. data/app/assets/javascripts/treetable.webpack.js +687 -0
  11. data/app/controllers/browse_everything_controller.rb +60 -60
  12. data/app/helpers/browse_everything_helper.rb +4 -0
  13. data/app/views/browse_everything/_files.html.erb +4 -2
  14. data/browse-everything.gemspec +6 -7
  15. data/lib/browse_everything.rb +2 -1
  16. data/lib/browse_everything/auth/google/credentials.rb +5 -5
  17. data/lib/browse_everything/auth/google/request_parameters.rb +38 -38
  18. data/lib/browse_everything/driver/base.rb +14 -14
  19. data/lib/browse_everything/driver/box.rb +62 -55
  20. data/lib/browse_everything/driver/dropbox.rb +34 -33
  21. data/lib/browse_everything/driver/file_system.rb +30 -18
  22. data/lib/browse_everything/driver/google_drive.rb +40 -39
  23. data/lib/browse_everything/driver/s3.rb +61 -45
  24. data/lib/browse_everything/file_entry.rb +1 -1
  25. data/lib/browse_everything/retriever.rb +69 -69
  26. data/lib/browse_everything/version.rb +1 -1
  27. data/spec/features/test_compiling_stylesheets_spec.rb +1 -1
  28. data/spec/lib/browse_everything/driver_spec.rb +43 -3
  29. data/spec/spec_helper.rb +9 -3
  30. data/spec/support/capybara.rb +0 -5
  31. data/spec/test_app_templates/Gemfile.extra +9 -0
  32. data/spec/test_app_templates/lib/generators/test_app_generator.rb +54 -3
  33. metadata +49 -45
  34. data/.travis.yml +0 -30
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Code:
4
4
  [![Gem Version](https://badge.fury.io/rb/browse-everything.png)](http://badge.fury.io/rb/browse-everything)
5
- [![Build Status](https://travis-ci.org/samvera/browse-everything.svg?branch=master)](https://travis-ci.org/samvera/browse-everything)
5
+ [![CircleCI](https://circleci.com/gh/samvera/browse-everything.svg?style=svg)](https://circleci.com/gh/samvera/browse-everything)
6
6
  [![Coverage Status](https://coveralls.io/repos/samvera/browse-everything/badge.svg?branch=master&service=github)](https://coveralls.io/github/samvera/browse-everything?branch=master)
7
7
 
8
8
  Docs:
@@ -39,14 +39,15 @@ what this means can be found
39
39
 
40
40
  ## Supported Ruby Releases
41
41
  Currently, the following releases of Ruby are supported:
42
- - 2.6.1
43
- - 2.5.3
44
- - 2.4.5
42
+ - 2.6.3
43
+ - 2.5.5
44
+ - 2.4.6
45
45
 
46
46
  ## Supported Rails Releases
47
47
  The supported Rail releases follow those specified by [the security policy of the Rails Community](https://rubyonrails.org/security/). As is the case with the supported Ruby releases, it is recommended that one upgrades from any Rails release no longer receiving security updates.
48
- - 5.2.2
49
- - 5.1.6.1
48
+ - 6.0.3
49
+ - 5.2.3
50
+ - 5.1.7
50
51
 
51
52
  ## Installation
52
53
 
@@ -262,21 +262,29 @@ $(function () {
262
262
 
263
263
  $.fn.browseEverything = function (options) {
264
264
  var ctx = $(this).data('ev-state');
265
+
266
+ // Try and load the options from the HTML data attributes
265
267
  if (ctx == null && options == null) {
266
268
  options = $(this).data();
267
269
  }
270
+
268
271
  if (options != null) {
269
272
  ctx = initialize(this[0], options);
270
- $(this).click(function () {
271
- dialog.data('ev-state', ctx);
272
- return dialog.load(ctx.opts.route, function () {
273
- setTimeout(refreshFiles, 500);
274
- ctx.callbacks.show.fire();
275
- return dialog.modal('show');
276
- });
277
- });
278
273
  }
279
274
 
275
+ $(this).click(function () {
276
+ dialog.data('ev-state', ctx);
277
+ return dialog.load(ctx.opts.route, function () {
278
+ setTimeout(refreshFiles, 50);
279
+ ctx.callbacks.show.fire();
280
+ dialog.removeClass('fade')
281
+ .removeClass('in')
282
+ .addClass('show');
283
+
284
+ return dialog.modal('show');
285
+ });
286
+ });
287
+
280
288
  if (ctx) {
281
289
  return ctx.callback_proxy;
282
290
  } else {
@@ -0,0 +1,687 @@
1
+ /*
2
+ * jQuery treetable Plugin 3.2.0
3
+ * http://ludo.cubicphuse.nl/jquery-treetable
4
+ *
5
+ * Copyright 2013, Ludo van den Boom
6
+ * Dual licensed under the MIT or GPL Version 2 licenses.
7
+ */
8
+
9
+ /**
10
+ * Callback defining the Node Class
11
+ */
12
+ var defineNode = function() {
13
+
14
+ function Node(row, tree, settings) {
15
+ var parentId;
16
+
17
+ this.row = row;
18
+ this.tree = tree;
19
+ this.settings = settings;
20
+
21
+ // TODO Ensure id/parentId is always a string (not int)
22
+ this.id = this.row.data(this.settings.nodeIdAttr);
23
+
24
+ // TODO Move this to a setParentId function?
25
+ parentId = this.row.data(this.settings.parentIdAttr);
26
+ if (parentId != null && parentId !== "") {
27
+ this.parentId = parentId;
28
+ }
29
+
30
+ this.treeCell = jQuery(this.row.children(this.settings.columnElType)[this.settings.column]);
31
+ this.expander = jQuery(this.settings.expanderTemplate);
32
+ this.indenter = jQuery(this.settings.indenterTemplate);
33
+ this.children = [];
34
+ this.initialized = false;
35
+ this.treeCell.prepend(this.indenter);
36
+ }
37
+
38
+ Node.prototype.addChild = function(child) {
39
+ return this.children.push(child);
40
+ };
41
+
42
+ Node.prototype.ancestors = function() {
43
+ var ancestors, node;
44
+ node = this;
45
+ ancestors = [];
46
+ while (node = node.parentNode()) {
47
+ ancestors.push(node);
48
+ }
49
+ return ancestors;
50
+ };
51
+
52
+ Node.prototype.collapse = function() {
53
+ if (this.collapsed()) {
54
+ return this;
55
+ }
56
+
57
+ this.row.removeClass("expanded").addClass("collapsed");
58
+
59
+ this._hideChildren();
60
+ this.expander.attr("title", this.settings.stringExpand);
61
+
62
+ if (this.initialized && this.settings.onNodeCollapse != null) {
63
+ this.settings.onNodeCollapse.apply(this);
64
+ }
65
+
66
+ return this;
67
+ };
68
+
69
+ Node.prototype.collapsed = function() {
70
+ return this.row.hasClass("collapsed");
71
+ };
72
+
73
+ // TODO destroy: remove event handlers, expander, indenter, etc.
74
+
75
+ Node.prototype.expand = function() {
76
+ if (this.expanded()) {
77
+ return this;
78
+ }
79
+
80
+ this.row.removeClass("collapsed").addClass("expanded");
81
+
82
+ if (this.initialized && this.settings.onNodeExpand != null) {
83
+ this.settings.onNodeExpand.apply(this);
84
+ }
85
+
86
+ if (jQuery(this.row).is(":visible")) {
87
+ this._showChildren();
88
+ }
89
+
90
+ this.expander.attr("title", this.settings.stringCollapse);
91
+
92
+ return this;
93
+ };
94
+
95
+ Node.prototype.expanded = function() {
96
+ return this.row.hasClass("expanded");
97
+ };
98
+
99
+ Node.prototype.hide = function() {
100
+ this._hideChildren();
101
+ this.row.hide();
102
+ return this;
103
+ };
104
+
105
+ Node.prototype.isBranchNode = function() {
106
+ if(this.children.length > 0 || this.row.data(this.settings.branchAttr) === true) {
107
+ return true;
108
+ } else {
109
+ return false;
110
+ }
111
+ };
112
+
113
+ Node.prototype.updateBranchLeafClass = function(){
114
+ this.row.removeClass('branch');
115
+ this.row.removeClass('leaf');
116
+ this.row.addClass(this.isBranchNode() ? 'branch' : 'leaf');
117
+ };
118
+
119
+ Node.prototype.level = function() {
120
+ return this.ancestors().length;
121
+ };
122
+
123
+ Node.prototype.parentNode = function() {
124
+ if (this.parentId != null) {
125
+ return this.tree[this.parentId];
126
+ } else {
127
+ return null;
128
+ }
129
+ };
130
+
131
+ Node.prototype.removeChild = function(child) {
132
+ var i = jQuery.inArray(child, this.children);
133
+ return this.children.splice(i, 1)
134
+ };
135
+
136
+ Node.prototype.render = function() {
137
+ var handler,
138
+ settings = this.settings,
139
+ target;
140
+
141
+ if (settings.expandable === true && this.isBranchNode()) {
142
+ handler = function(e) {
143
+ jQuery(this).parents("table").treetable("node", jQuery(this).parents("tr").data(settings.nodeIdAttr)).toggle();
144
+ return e.preventDefault();
145
+ };
146
+
147
+ this.indenter.html(this.expander);
148
+ target = settings.clickableNodeNames === true ? this.treeCell : this.expander;
149
+
150
+ target.off("click.treetable").on("click.treetable", handler);
151
+ target.off("keydown.treetable").on("keydown.treetable", function(e) {
152
+ if (e.keyCode == 13) {
153
+ handler.apply(this, [e]);
154
+ }
155
+ });
156
+ }
157
+
158
+ this.indenter[0].style.paddingLeft = "" + (this.level() * settings.indent) + "px";
159
+
160
+ return this;
161
+ };
162
+
163
+ Node.prototype.reveal = function() {
164
+ if (this.parentId != null) {
165
+ this.parentNode().reveal();
166
+ }
167
+ return this.expand();
168
+ };
169
+
170
+ Node.prototype.setParent = function(node) {
171
+ if (this.parentId != null) {
172
+ this.tree[this.parentId].removeChild(this);
173
+ }
174
+ this.parentId = node.id;
175
+ this.row.data(this.settings.parentIdAttr, node.id);
176
+ return node.addChild(this);
177
+ };
178
+
179
+ Node.prototype.show = function() {
180
+ if (!this.initialized) {
181
+ this._initialize();
182
+ }
183
+ this.row.show();
184
+ if (this.expanded()) {
185
+ this._showChildren();
186
+ }
187
+ return this;
188
+ };
189
+
190
+ Node.prototype.toggle = function() {
191
+ if (this.expanded()) {
192
+ this.collapse();
193
+ } else {
194
+ this.expand();
195
+ }
196
+ return this;
197
+ };
198
+
199
+ Node.prototype._hideChildren = function() {
200
+ var child, _i, _len, _ref, _results;
201
+ _ref = this.children;
202
+ _results = [];
203
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
204
+ child = _ref[_i];
205
+ _results.push(child.hide());
206
+ }
207
+ return _results;
208
+ };
209
+
210
+ Node.prototype._initialize = function() {
211
+ var settings = this.settings;
212
+
213
+ this.render();
214
+
215
+ if (settings.expandable === true && settings.initialState === "collapsed") {
216
+ this.collapse();
217
+ } else {
218
+ this.expand();
219
+ }
220
+
221
+ if (settings.onNodeInitialized != null) {
222
+ settings.onNodeInitialized.apply(this);
223
+ }
224
+
225
+ return this.initialized = true;
226
+ };
227
+
228
+ Node.prototype._showChildren = function() {
229
+ var child, _i, _len, _ref, _results;
230
+ _ref = this.children;
231
+ _results = [];
232
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
233
+ child = _ref[_i];
234
+ _results.push(child.show());
235
+ }
236
+ return _results;
237
+ };
238
+
239
+ return Node;
240
+ }
241
+
242
+ var Node = defineNode()
243
+
244
+ /**
245
+ * Callback defining the Tree Class
246
+ */
247
+ var defineTree = function() {
248
+ /**
249
+ * Class modeling trees of nodes
250
+ */
251
+
252
+ function Tree(table, settings) {
253
+ this.table = table;
254
+ this.settings = settings;
255
+ this.tree = {};
256
+
257
+ // Cache the nodes and roots in simple arrays for quick access/iteration
258
+ this.nodes = [];
259
+ this.roots = [];
260
+ }
261
+
262
+ Tree.prototype.collapseAll = function() {
263
+ var node, _i, _len, _ref, _results;
264
+ _ref = this.nodes;
265
+ _results = [];
266
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
267
+ node = _ref[_i];
268
+ _results.push(node.collapse());
269
+ }
270
+ return _results;
271
+ };
272
+
273
+ Tree.prototype.expandAll = function() {
274
+ var node, _i, _len, _ref, _results;
275
+ _ref = this.nodes;
276
+ _results = [];
277
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
278
+ node = _ref[_i];
279
+ _results.push(node.expand());
280
+ }
281
+ return _results;
282
+ };
283
+
284
+ Tree.prototype.findLastNode = function (node) {
285
+ if (node.children.length > 0) {
286
+ return this.findLastNode(node.children[node.children.length - 1]);
287
+ } else {
288
+ return node;
289
+ }
290
+ };
291
+
292
+ Tree.prototype.loadRows = function(rows) {
293
+ var node, row, i;
294
+
295
+ if (rows != null) {
296
+ for (i = 0; i < rows.length; i++) {
297
+ row = jQuery(rows[i]);
298
+
299
+ if (row.data(this.settings.nodeIdAttr) != null) {
300
+ node = new Node(row, this.tree, this.settings);
301
+ this.nodes.push(node);
302
+ this.tree[node.id] = node;
303
+
304
+ if (node.parentId != null && this.tree[node.parentId]) {
305
+ this.tree[node.parentId].addChild(node);
306
+ } else {
307
+ this.roots.push(node);
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ for (i = 0; i < this.nodes.length; i++) {
314
+ node = this.nodes[i].updateBranchLeafClass();
315
+ }
316
+
317
+ return this;
318
+ };
319
+
320
+ Tree.prototype.move = function(node, destination) {
321
+ // Conditions:
322
+ // 1: +node+ should not be inserted as a child of +node+ itself.
323
+ // 2: +destination+ should not be the same as +node+'s current parent (this
324
+ // prevents +node+ from being moved to the same location where it already
325
+ // is).
326
+ // 3: +node+ should not be inserted in a location in a branch if this would
327
+ // result in +node+ being an ancestor of itself.
328
+ var nodeParent = node.parentNode();
329
+ if (node !== destination && destination.id !== node.parentId && jQuery.inArray(node, destination.ancestors()) === -1) {
330
+ node.setParent(destination);
331
+ this._moveRows(node, destination);
332
+
333
+ // Re-render parentNode if this is its first child node, and therefore
334
+ // doesn't have the expander yet.
335
+ if (node.parentNode().children.length === 1) {
336
+ node.parentNode().render();
337
+ }
338
+ }
339
+
340
+ if(nodeParent){
341
+ nodeParent.updateBranchLeafClass();
342
+ }
343
+ if(node.parentNode()){
344
+ node.parentNode().updateBranchLeafClass();
345
+ }
346
+ node.updateBranchLeafClass();
347
+ return this;
348
+ };
349
+
350
+ Tree.prototype.removeNode = function(node) {
351
+ // Recursively remove all descendants of +node+
352
+ this.unloadBranch(node);
353
+
354
+ // Remove node from DOM (<tr>)
355
+ node.row.remove();
356
+
357
+ // Remove node from parent children list
358
+ if (node.parentId != null) {
359
+ node.parentNode().removeChild(node);
360
+ }
361
+
362
+ // Clean up Tree object (so Node objects are GC-ed)
363
+ delete this.tree[node.id];
364
+ this.nodes.splice(jQuery.inArray(node, this.nodes), 1);
365
+
366
+ return this;
367
+ }
368
+
369
+ Tree.prototype.render = function() {
370
+ var root, _i, _len, _ref;
371
+ _ref = this.roots;
372
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
373
+ root = _ref[_i];
374
+
375
+ // Naming is confusing (show/render). I do not call render on node from
376
+ // here.
377
+ root.show();
378
+ }
379
+ return this;
380
+ };
381
+
382
+ Tree.prototype.sortBranch = function(node, sortFun) {
383
+ // First sort internal array of children
384
+ node.children.sort(sortFun);
385
+
386
+ // Next render rows in correct order on page
387
+ this._sortChildRows(node);
388
+
389
+ return this;
390
+ };
391
+
392
+ Tree.prototype.unloadBranch = function(node) {
393
+ // Use a copy of the children array to not have other functions interfere
394
+ // with this function if they manipulate the children array
395
+ // (eg removeNode).
396
+ var children = node.children.slice(0),
397
+ i;
398
+
399
+ for (i = 0; i < children.length; i++) {
400
+ this.removeNode(children[i]);
401
+ }
402
+
403
+ // Reset node's collection of children
404
+ node.children = [];
405
+
406
+ node.updateBranchLeafClass();
407
+
408
+ return this;
409
+ };
410
+
411
+ Tree.prototype._moveRows = function(node, destination) {
412
+ var children = node.children, i;
413
+
414
+ node.row.insertAfter(destination.row);
415
+ node.render();
416
+
417
+ // Loop backwards through children to have them end up on UI in correct
418
+ // order (see #112)
419
+ for (i = children.length - 1; i >= 0; i--) {
420
+ this._moveRows(children[i], node);
421
+ }
422
+ };
423
+
424
+ // Special _moveRows case, move children to itself to force sorting
425
+ Tree.prototype._sortChildRows = function(parentNode) {
426
+ return this._moveRows(parentNode, parentNode);
427
+ };
428
+
429
+ return Tree;
430
+ };
431
+
432
+ var Tree = defineTree()
433
+
434
+ /**
435
+ * Define the methods for the jQuery Plugin
436
+ */
437
+ var methods = {
438
+ /**
439
+ * Constructor
440
+ */
441
+ init: function(options, force) {
442
+ var settings;
443
+
444
+ settings = jQuery.extend({
445
+ branchAttr: "ttBranch",
446
+ clickableNodeNames: false,
447
+ column: 0,
448
+ columnElType: "td", // i.e. 'td', 'th' or 'td,th'
449
+ expandable: false,
450
+ expanderTemplate: "<a href='#'>&nbsp;</a>",
451
+ indent: 19,
452
+ indenterTemplate: "<span class='indenter'></span>",
453
+ initialState: "collapsed",
454
+ nodeIdAttr: "ttId", // maps to data-tt-id
455
+ parentIdAttr: "ttParentId", // maps to data-tt-parent-id
456
+ stringExpand: "Expand",
457
+ stringCollapse: "Collapse",
458
+
459
+ // Events
460
+ onInitialized: null,
461
+ onNodeCollapse: null,
462
+ onNodeExpand: null,
463
+ onNodeInitialized: null
464
+ }, options);
465
+
466
+ return this.each(function() {
467
+ var el = jQuery(this), tree;
468
+
469
+ if (force || el.data("treetable") === undefined) {
470
+ tree = new Tree(this, settings);
471
+ tree.loadRows(this.rows).render();
472
+
473
+ el.addClass("treetable").data("treetable", tree);
474
+
475
+ if (settings.onInitialized != null) {
476
+ settings.onInitialized.apply(tree);
477
+ }
478
+ }
479
+
480
+ return el;
481
+ });
482
+ },
483
+
484
+ /**
485
+ * Destructor
486
+ */
487
+ destroy: function() {
488
+ return this.each(function() {
489
+ return jQuery(this).removeData("treetable").removeClass("treetable");
490
+ });
491
+ },
492
+
493
+ /**
494
+ * Collapsing all tree branches
495
+ */
496
+ collapseAll: function() {
497
+ this.data("treetable").collapseAll();
498
+ return this;
499
+ },
500
+
501
+ /**
502
+ * Collapsing a single tree branch
503
+ */
504
+ collapseNode: function(id) {
505
+ var node = this.data("treetable").tree[id];
506
+
507
+ if (node) {
508
+ node.collapse();
509
+ } else {
510
+ throw new Error("Unknown node '" + id + "'");
511
+ }
512
+
513
+ return this;
514
+ },
515
+
516
+ /**
517
+ * Expanding all tree branches
518
+ */
519
+ expandAll: function() {
520
+ this.data("treetable").expandAll();
521
+ return this;
522
+ },
523
+
524
+ /**
525
+ * Expanding a single tree branch
526
+ */
527
+ expandNode: function(id) {
528
+ var node = this.data("treetable").tree[id];
529
+
530
+ if (node) {
531
+ if (!node.initialized) {
532
+ node._initialize();
533
+ }
534
+
535
+ node.expand();
536
+ } else {
537
+ throw new Error("Unknown node '" + id + "'");
538
+ }
539
+
540
+ return this;
541
+ },
542
+
543
+ /**
544
+ * Load the markup for a single tree branch
545
+ */
546
+ loadBranch: function(node, rows) {
547
+ var settings = this.data("treetable").settings,
548
+ tree = this.data("treetable").tree;
549
+
550
+ // TODO Switch to $.parseHTML
551
+ rows = jQuery(rows);
552
+
553
+ if (node == null) { // Inserting new root nodes
554
+ this.append(rows);
555
+ } else {
556
+ var lastNode = this.data("treetable").findLastNode(node);
557
+ rows.insertAfter(lastNode.row);
558
+ }
559
+
560
+ this.data("treetable").loadRows(rows);
561
+
562
+ // Make sure nodes are properly initialized
563
+ rows.filter("tr").each(function() {
564
+ tree[jQuery(this).data(settings.nodeIdAttr)].show();
565
+ });
566
+
567
+ if (node != null) {
568
+ // Re-render parent to ensure expander icon is shown (#79)
569
+ node.render().expand();
570
+ }
571
+
572
+ return this;
573
+ },
574
+
575
+ /**
576
+ *
577
+ */
578
+ move: function(nodeId, destinationId) {
579
+ var destination, node;
580
+
581
+ node = this.data("treetable").tree[nodeId];
582
+ destination = this.data("treetable").tree[destinationId];
583
+ this.data("treetable").move(node, destination);
584
+
585
+ return this;
586
+ },
587
+
588
+ /**
589
+ *
590
+ */
591
+ node: function(id) {
592
+ return this.data("treetable").tree[id];
593
+ },
594
+
595
+ /**
596
+ *
597
+ */
598
+ removeNode: function(id) {
599
+ var node = this.data("treetable").tree[id];
600
+
601
+ if (node) {
602
+ this.data("treetable").removeNode(node);
603
+ } else {
604
+ throw new Error("Unknown node '" + id + "'");
605
+ }
606
+
607
+ return this;
608
+ },
609
+
610
+ /**
611
+ *
612
+ */
613
+ reveal: function(id) {
614
+ var node = this.data("treetable").tree[id];
615
+
616
+ if (node) {
617
+ node.reveal();
618
+ } else {
619
+ throw new Error("Unknown node '" + id + "'");
620
+ }
621
+
622
+ return this;
623
+ },
624
+
625
+ /**
626
+ *
627
+ */
628
+ sortBranch: function(node, columnOrFunction) {
629
+ var settings = this.data("treetable").settings,
630
+ prepValue,
631
+ sortFun;
632
+
633
+ columnOrFunction = columnOrFunction || settings.column;
634
+ sortFun = columnOrFunction;
635
+
636
+ if (jQuery.isNumeric(columnOrFunction)) {
637
+ sortFun = function(a, b) {
638
+ var extractValue, valA, valB;
639
+
640
+ extractValue = function(node) {
641
+ var val = node.row.find("td:eq(" + columnOrFunction + ")").text();
642
+ // Ignore trailing/leading whitespace and use uppercase values for
643
+ // case insensitive ordering
644
+ return jQuery.trim(val).toUpperCase();
645
+ }
646
+
647
+ valA = extractValue(a);
648
+ valB = extractValue(b);
649
+
650
+ if (valA < valB) return -1;
651
+ if (valA > valB) return 1;
652
+ return 0;
653
+ };
654
+ }
655
+
656
+ this.data("treetable").sortBranch(node, sortFun);
657
+ return this;
658
+ },
659
+
660
+ /**
661
+ *
662
+ */
663
+ unloadBranch: function(node) {
664
+ this.data("treetable").unloadBranch(node);
665
+ return this;
666
+ }
667
+ };
668
+
669
+ /**
670
+ * Define the jQuery Plugin
671
+ *
672
+ */
673
+ jQuery.fn.treetable = function(method) {
674
+ if (methods[method]) {
675
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
676
+ } else if (typeof method === 'object' || !method) {
677
+ return methods.init.apply(this, arguments);
678
+ } else {
679
+ return jQuery.error("Method " + method + " does not exist on jQuery.treetable");
680
+ }
681
+ };
682
+
683
+ // Expose classes to world
684
+ document.TreeTable || (document.TreeTable = {});
685
+ document.TreeTable.Node = Node;
686
+ document.TreeTable.Tree = Tree;
687
+