browse-everything 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +105 -30
  3. data/.gitignore +4 -2
  4. data/.rubocop.yml +54 -34
  5. data/.rubocop_todo.yml +0 -5
  6. data/.tool-versions +2 -0
  7. data/CONTRIBUTING.md +22 -0
  8. data/Gemfile +41 -33
  9. data/README.md +66 -31
  10. data/Rakefile +9 -1
  11. data/app/assets/javascripts/browse_everything/behavior.js +45 -31
  12. data/app/assets/javascripts/browse_everything.js +1 -1
  13. data/app/assets/javascripts/treetable.webpack.js +687 -0
  14. data/app/controllers/browse_everything_controller.rb +60 -60
  15. data/app/helpers/browse_everything_helper.rb +4 -0
  16. data/app/views/browse_everything/_files.html.erb +3 -2
  17. data/bin/rails +14 -0
  18. data/browse-everything.gemspec +13 -12
  19. data/lib/browse_everything/auth/google/credentials.rb +5 -5
  20. data/lib/browse_everything/auth/google/request_parameters.rb +38 -38
  21. data/lib/browse_everything/driver/base.rb +15 -14
  22. data/lib/browse_everything/driver/box.rb +56 -56
  23. data/lib/browse_everything/driver/dropbox.rb +44 -41
  24. data/lib/browse_everything/driver/file_system.rb +31 -18
  25. data/lib/browse_everything/driver/google_drive.rb +38 -38
  26. data/lib/browse_everything/driver/s3.rb +61 -61
  27. data/lib/browse_everything/engine.rb +10 -3
  28. data/lib/browse_everything/file_entry.rb +1 -1
  29. data/lib/browse_everything/retriever.rb +69 -69
  30. data/lib/browse_everything/version.rb +1 -1
  31. data/lib/browse_everything.rb +1 -1
  32. data/spec/dummy_test_app/Rakefile +6 -0
  33. data/spec/dummy_test_app/app/assets/config/manifest.js +3 -0
  34. data/spec/dummy_test_app/app/assets/images/.keep +0 -0
  35. data/spec/dummy_test_app/app/assets/javascripts/application.js +25 -0
  36. data/spec/dummy_test_app/app/assets/javascripts/cable.js +13 -0
  37. data/spec/dummy_test_app/app/assets/javascripts/channels/.keep +0 -0
  38. data/spec/dummy_test_app/app/assets/stylesheets/application.scss +18 -0
  39. data/spec/dummy_test_app/app/channels/application_cable/channel.rb +4 -0
  40. data/spec/dummy_test_app/app/channels/application_cable/connection.rb +4 -0
  41. data/spec/dummy_test_app/app/controllers/application_controller.rb +3 -0
  42. data/spec/dummy_test_app/app/controllers/concerns/.keep +0 -0
  43. data/spec/{support → dummy_test_app}/app/controllers/file_handler_controller.rb +0 -0
  44. data/spec/dummy_test_app/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy_test_app/app/jobs/application_job.rb +2 -0
  46. data/spec/dummy_test_app/app/mailers/application_mailer.rb +4 -0
  47. data/spec/dummy_test_app/app/models/application_record.rb +3 -0
  48. data/spec/dummy_test_app/app/models/concerns/.keep +0 -0
  49. data/spec/dummy_test_app/app/views/file_handler/index.html.erb +10 -0
  50. data/spec/{support → dummy_test_app}/app/views/file_handler/main.html.erb +6 -3
  51. data/spec/dummy_test_app/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy_test_app/app/views/layouts/mailer.html.erb +13 -0
  53. data/spec/dummy_test_app/app/views/layouts/mailer.text.erb +1 -0
  54. data/spec/dummy_test_app/bin/bundle +3 -0
  55. data/spec/dummy_test_app/bin/rails +4 -0
  56. data/spec/dummy_test_app/bin/rake +4 -0
  57. data/spec/dummy_test_app/bin/setup +38 -0
  58. data/spec/dummy_test_app/bin/update +29 -0
  59. data/spec/dummy_test_app/bin/yarn +11 -0
  60. data/spec/dummy_test_app/config/application.rb +27 -0
  61. data/spec/dummy_test_app/config/boot.rb +5 -0
  62. data/spec/dummy_test_app/config/browse_everything_providers.yml +25 -0
  63. data/spec/dummy_test_app/config/cable.yml +10 -0
  64. data/spec/dummy_test_app/config/database.yml +25 -0
  65. data/spec/dummy_test_app/config/environment.rb +5 -0
  66. data/spec/dummy_test_app/config/environments/development.rb +54 -0
  67. data/spec/dummy_test_app/config/environments/production.rb +91 -0
  68. data/spec/dummy_test_app/config/environments/test.rb +42 -0
  69. data/spec/dummy_test_app/config/initializers/application_controller_renderer.rb +8 -0
  70. data/spec/dummy_test_app/config/initializers/assets.rb +14 -0
  71. data/spec/dummy_test_app/config/initializers/backtrace_silencers.rb +7 -0
  72. data/spec/dummy_test_app/config/initializers/cookies_serializer.rb +5 -0
  73. data/spec/dummy_test_app/config/initializers/filter_parameter_logging.rb +4 -0
  74. data/spec/dummy_test_app/config/initializers/inflections.rb +16 -0
  75. data/spec/dummy_test_app/config/initializers/mime_types.rb +4 -0
  76. data/spec/dummy_test_app/config/initializers/wrap_parameters.rb +14 -0
  77. data/spec/dummy_test_app/config/locales/en.yml +33 -0
  78. data/spec/dummy_test_app/config/puma.rb +56 -0
  79. data/spec/dummy_test_app/config/routes.rb +9 -0
  80. data/spec/dummy_test_app/config/secrets.yml +32 -0
  81. data/spec/dummy_test_app/config/spring.rb +6 -0
  82. data/spec/dummy_test_app/config.ru +5 -0
  83. data/spec/dummy_test_app/lib/assets/.keep +0 -0
  84. data/spec/dummy_test_app/log/.keep +0 -0
  85. data/spec/dummy_test_app/package.json +5 -0
  86. data/spec/dummy_test_app/public/404.html +67 -0
  87. data/spec/dummy_test_app/public/422.html +67 -0
  88. data/spec/dummy_test_app/public/500.html +66 -0
  89. data/spec/dummy_test_app/public/apple-touch-icon-precomposed.png +0 -0
  90. data/spec/dummy_test_app/public/apple-touch-icon.png +0 -0
  91. data/spec/dummy_test_app/public/favicon.ico +0 -0
  92. data/spec/dummy_test_app/tmp/.gitkeep +0 -0
  93. data/spec/features/select_files_spec.rb +1 -0
  94. data/spec/features/test_compiling_stylesheets_spec.rb +1 -1
  95. data/spec/lib/browse_everything/driver_spec.rb +43 -3
  96. data/spec/spec_helper.rb +3 -28
  97. data/tasks/ci.rake +1 -1
  98. metadata +180 -94
  99. data/karma.conf.js +0 -71
  100. data/spec/javascripts/behavior_spec.js +0 -7
  101. data/spec/javascripts/helpers/jasmine-jquery.js +0 -838
  102. data/spec/javascripts/helpers/jquery.js +0 -11008
  103. data/spec/javascripts/karma_spec.rb +0 -16
  104. data/spec/support/app/views/file_handler/index.html.erb +0 -6
  105. data/spec/test_app_templates/Gemfile.extra +0 -9
  106. data/spec/test_app_templates/lib/generators/test_app_generator.rb +0 -61
@@ -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
+