browse-everything 1.0.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+