deep-cover 0.1.16 → 0.2.0

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +3 -8
  4. data/.travis.yml +4 -4
  5. data/CHANGELOG.md +10 -0
  6. data/Gemfile +3 -1
  7. data/README.md +9 -4
  8. data/Rakefile +6 -3
  9. data/deep_cover.gemspec +2 -2
  10. data/lib/deep_cover.rb +10 -0
  11. data/lib/deep_cover/analyser.rb +1 -2
  12. data/lib/deep_cover/analyser/base.rb +32 -0
  13. data/lib/deep_cover/analyser/branch.rb +19 -4
  14. data/lib/deep_cover/analyser/node.rb +52 -0
  15. data/lib/deep_cover/analyser/per_char.rb +18 -1
  16. data/lib/deep_cover/analyser/stats.rb +54 -0
  17. data/lib/deep_cover/backports.rb +1 -0
  18. data/lib/deep_cover/base.rb +17 -1
  19. data/lib/deep_cover/builtin_takeover.rb +5 -0
  20. data/lib/deep_cover/cli/deep_cover.rb +2 -1
  21. data/lib/deep_cover/cli/instrumented_clone_reporter.rb +12 -10
  22. data/lib/deep_cover/config.rb +22 -8
  23. data/lib/deep_cover/core_ext/coverage_replacement.rb +22 -18
  24. data/lib/deep_cover/coverage.rb +3 -203
  25. data/lib/deep_cover/coverage/analysis.rb +36 -0
  26. data/lib/deep_cover/coverage/base.rb +91 -0
  27. data/lib/deep_cover/coverage/istanbul.rb +34 -0
  28. data/lib/deep_cover/coverage/persistence.rb +93 -0
  29. data/lib/deep_cover/covered_code.rb +12 -22
  30. data/lib/deep_cover/custom_requirer.rb +6 -2
  31. data/lib/deep_cover/node/base.rb +1 -1
  32. data/lib/deep_cover/node/case.rb +13 -2
  33. data/lib/deep_cover/node/exceptions.rb +2 -2
  34. data/lib/deep_cover/node/if.rb +21 -2
  35. data/lib/deep_cover/node/mixin/flow_accounting.rb +1 -0
  36. data/lib/deep_cover/node/send.rb +9 -2
  37. data/lib/deep_cover/node/short_circuit.rb +10 -0
  38. data/lib/deep_cover/parser_ext/range.rb +4 -4
  39. data/lib/deep_cover/reporter/html.rb +15 -0
  40. data/lib/deep_cover/reporter/html/base.rb +14 -0
  41. data/lib/deep_cover/reporter/html/index.rb +78 -0
  42. data/lib/deep_cover/reporter/html/site.rb +78 -0
  43. data/lib/deep_cover/reporter/html/source.rb +136 -0
  44. data/lib/deep_cover/reporter/html/template/assets/32px.png +0 -0
  45. data/lib/deep_cover/reporter/html/template/assets/40px.png +0 -0
  46. data/lib/deep_cover/reporter/html/template/assets/deep_cover.css.sass +338 -0
  47. data/lib/deep_cover/reporter/html/template/assets/jquery-3.2.1.min.js +4 -0
  48. data/lib/deep_cover/reporter/html/template/assets/jquery-3.2.1.min.map +1 -0
  49. data/lib/deep_cover/reporter/html/template/assets/jstree.css +1108 -0
  50. data/lib/deep_cover/reporter/html/template/assets/jstree.js +8424 -0
  51. data/lib/deep_cover/reporter/html/template/assets/jstreetable.js +1069 -0
  52. data/lib/deep_cover/reporter/html/template/assets/throbber.gif +0 -0
  53. data/lib/deep_cover/reporter/html/template/index.html.erb +75 -0
  54. data/lib/deep_cover/reporter/html/template/source.html.erb +35 -0
  55. data/lib/deep_cover/reporter/html/tree.rb +55 -0
  56. data/lib/deep_cover/tools/content_tag.rb +11 -0
  57. data/lib/deep_cover/tools/covered.rb +9 -0
  58. data/lib/deep_cover/tools/merge.rb +16 -0
  59. data/lib/deep_cover/tools/render_template.rb +13 -0
  60. data/lib/deep_cover/tools/transform_keys.rb +9 -0
  61. data/lib/deep_cover/version.rb +1 -1
  62. metadata +33 -7
  63. data/lib/deep_cover/analyser/ignore_uncovered.rb +0 -21
  64. data/lib/deep_cover/analyser/optionally_covered.rb +0 -19
@@ -0,0 +1,1069 @@
1
+ /*
2
+ * http://github.com/adamjimenez/jstree-table
3
+ *
4
+ * This plugin handles adding columns to a tree to display additional data
5
+ *
6
+ * Licensed under the MIT license:
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ *
9
+ * Works only with jstree version >= 3.0.0
10
+ *
11
+ * $Revision: 3.4.2 $
12
+ */
13
+
14
+ /*jslint nomen:true */
15
+ /*jshint unused:vars */
16
+ /*global navigator, document, jQuery, define, localStorage */
17
+
18
+ (function (factory) {
19
+ if (typeof define === 'function' && define.amd) {
20
+ // AMD. Register as an anonymous module.
21
+ define(['jquery', 'jstree'], factory);
22
+ } else {
23
+ // Browser globals
24
+ factory(jQuery);
25
+ }
26
+ }(function ($) {
27
+ var renderAWidth, renderATitle, getIndent, copyData, htmlstripre, findLastClosedNode, BLANKRE = /^\s*$/g,
28
+ IDREGEX = /[\\:&!^|()\[\]<>@*'+~#";,= \/${}%]/g, escapeId = function (id) {
29
+ return (id||"").replace(IDREGEX,'\\$&');
30
+ }, NODE_DATA_ATTR = "data-jstreetable", COL_DATA_ATTR = "data-jstreetable-column",
31
+ SPECIAL_TITLE = "_DATA_", LEVELINDENT = 24, styled = false, TABLECELLID_PREFIX = "jstable_",TABLECELLID_POSTFIX = "_col",
32
+ MINCOLWIDTH = 10,
33
+ findDataCell = function (from,id) {
34
+ return from.find("div["+NODE_DATA_ATTR+'="'+ escapeId(id) +'"]');
35
+ },
36
+ findDataCellFast = function(colNb,id) {
37
+ return $(document.getElementById("jstable_"+id+"_col"+colNb));
38
+ },
39
+ isClickedSep = false, toResize = null, oldMouseX = 0, newMouseX = 0;
40
+
41
+ /*jslint regexp:true */
42
+ htmlstripre = /<\/?[^>]+>/gi;
43
+ /*jslint regexp:false */
44
+
45
+ getIndent = function(node,tree) {
46
+ var div, i, li, width;
47
+
48
+ // did we already save it for this tree?
49
+ tree._tableSettings = tree._tableSettings || {};
50
+ if (tree._tableSettings.indent > 0) {
51
+ width = tree._tableSettings.indent;
52
+ } else {
53
+ // create a new div on the DOM but not visible on the page
54
+ div = $("<div></div>");
55
+ i = node.prev("i");
56
+ li = i.parent();
57
+ // add to that div all of the classes on the tree root
58
+ div.addClass(tree.get_node("#",true).attr("class"));
59
+
60
+ // move the li to the temporary div root
61
+ li.appendTo(div);
62
+
63
+ // attach to the body quickly
64
+ div.appendTo($("body"));
65
+
66
+ // get the width
67
+ width = i.width() || LEVELINDENT;
68
+
69
+ // detach the li from the new div and destroy the new div
70
+ li.detach();
71
+ div.remove();
72
+
73
+ // save it for the future
74
+ tree._tableSettings.indent = width;
75
+ }
76
+
77
+
78
+ return(width);
79
+
80
+ };
81
+
82
+ copyData = function (fromtree,from,totree,to,recurse) {
83
+ var i, j;
84
+ to.data = $.extend(true, {}, from.data);
85
+ if (from && from.children_d && recurse) {
86
+ for(i = 0, j = from.children_d.length; i < j; i++) {
87
+ copyData(fromtree,fromtree.get_node(from.children_d[i]),totree,totree.get_node(to.children_d[i]),recurse);
88
+ }
89
+ }
90
+ };
91
+
92
+ findLastClosedNode = function (tree,id) {
93
+ // first get our node
94
+ var ret, node = tree.get_node(id), children = node.children;
95
+ // is it closed?
96
+ if (!children || children.length <= 0 || !node.state.opened) {
97
+ ret = id;
98
+ } else {
99
+ ret = findLastClosedNode(tree,children[children.length-1]);
100
+ }
101
+ return(ret);
102
+ };
103
+
104
+ renderAWidth = function(node,tree) {
105
+ var depth, width,
106
+ fullWidth = parseInt(tree.settings.table.columns[0].width,10) + parseInt(tree._tableSettings.treeWidthDiff,10);
107
+ // need to use a selector in jquery 1.4.4+
108
+ depth = tree.get_node(node).parents.length;
109
+ width = fullWidth - depth*getIndent(node,tree);
110
+ // the following line is no longer needed, since we are doing this inside a <td>
111
+ //a.css({"vertical-align": "top", "overflow":"hidden"});
112
+ return(fullWidth);
113
+ };
114
+ renderATitle = function(node,t,tree) {
115
+ var a = node.get(0).tagName.toLowerCase() === "a" ? node : node.children("a"), title, col = tree.settings.table.columns[0];
116
+ // get the title
117
+ title = "";
118
+ if (col.title) {
119
+ if (col.title === SPECIAL_TITLE) {
120
+ title = tree.get_text(t);
121
+ } else if (t.attr(col.title)) {
122
+ title = t.attr(col.title);
123
+ }
124
+ }
125
+ // strip out HTML
126
+ title = title.replace(htmlstripre, '');
127
+ if (title) {
128
+ a.attr("title",title);
129
+ }
130
+ };
131
+
132
+ $.jstree.defaults.table = {
133
+ width: 'auto'
134
+ };
135
+
136
+ $.jstree.plugins.table = function(options,parent) {
137
+ var _this = this;
138
+
139
+ this._initialize = function () {
140
+ if (!this._initialized) {
141
+ var s = this.settings.table || {}, styles, container = this.element, i,
142
+ gs = this._tableSettings = {
143
+ columns : s.columns || [],
144
+ treeClass : "jstree-table-col-0",
145
+ context: s.contextmenu || false,
146
+ columnWidth : s.columnWidth,
147
+ defaultConf : {"*display":"inline","*+display":"inline"},
148
+ isThemeroller : !!this._data.themeroller,
149
+ treeWidthDiff : 0,
150
+ resizable : s.resizable,
151
+ draggable : s.draggable,
152
+ stateful: s.stateful,
153
+ indent: 0,
154
+ sortFn: [],
155
+ sortOrder: 'text',
156
+ sortAsc: true,
157
+ fixedHeader: s.fixedHeader !== false,
158
+ headerContextMenu: s.headerContextMenu !== false,
159
+ checkIcon: 'fa fa-check',
160
+ arrowDownIcon: 'fa fa-chevron-down',
161
+ arrowUpIcon: 'fa fa-chevron-up',
162
+ width: s.width,
163
+ height: s.height
164
+ }, cols = gs.columns, treecol = 0;
165
+ // find which column our tree shuld go in
166
+ for (i=0;i<s.columns.length;i++) {
167
+ //Save sort function
168
+ if (i!==0 && s.columns[i].sort) {
169
+ gs.sortFn[s.columns[i].value] = s.columns[i].sort;
170
+ }
171
+ if (s.columns[i].tree) {
172
+ // save which column it was
173
+ treecol = i;
174
+ // do not check any others
175
+ break;
176
+ }
177
+ }
178
+ // set a unique ID for this table
179
+ this.uniq = Math.ceil(Math.random()*1000);
180
+ this.rootid = container.attr("id");
181
+
182
+ var msie = /msie/.test(navigator.userAgent.toLowerCase());
183
+ if (msie) {
184
+ var version = parseFloat(navigator.appVersion.split("MSIE")[1]);
185
+ if (version < 8) {
186
+ gs.defaultConf.display = "inline";
187
+ gs.defaultConf.zoom = "1";
188
+ }
189
+ }
190
+
191
+ // set up the classes we need
192
+ if (!styled) {
193
+ styled = true;
194
+ styles = [
195
+ '.jstree-table-cell {vertical-align: top; overflow:hidden;margin-left:0;width: 100%;padding-left:7px;white-space: nowrap; cursor: default; text-overflow: ellipsis;}',
196
+ '.jstree-table-cell span {margin-right:0px;margin-right:0px;*display:inline;*+display:inline;white-space: nowrap;}',
197
+ '.jstree-table-separator {position:absolute; top:0; right:0; height:24px; margin-left: -2px; border-width: 0 2px 0 0; *display:inline; *+display:inline; margin-right:0px;width:0px;}',
198
+ '.jstree-table-header-cell {overflow: hidden; white-space: nowrap;padding: 4px 3px 2px 5px; cursor: default;}',
199
+ '.jstree-table-header-themeroller {border: 0; padding: 1px 3px;}',
200
+ '.jstree-table-header-regular {position:relative; background-color: #CBF3FD; z-index: 1;}',
201
+ '.jstree-table-resizable-separator {cursor: col-resize; width: 10px;}',
202
+ '.jstree-table-separator-regular {border-color: #d0d0d0; border-style: solid;}',
203
+ '.jstree-table-cell-themeroller {border: none !important; background: transparent !important;}',
204
+ '.jstree-table-wrapper {table-layout: fixed; width: 100%; overflow: auto; position: relative;}',
205
+ '.jstree-table-midwrapper {display: table-row;}',
206
+ '.jstree-table-width-auto {width:auto;display:block;}',
207
+ '.jstree-table-column {display: table-cell; overflow: hidden;}',
208
+ '.jstree-table-col-0 {width: calc(100% - 18px); overflow: hidden; text-overflow: ellipsis;}',
209
+ '.jstree-table-sort-icon {font-size: 8px; position: absolute; top:0; left: calc(50% - 4px);}',
210
+ '.jstree-table-midwrapper a.jstree-clicked, .jstree-table-midwrapper a.jstree-hovered{background: transparent; border-color: transparent;}',
211
+ '.jstree-table-midwrapper a.jstree-clicked:before, .jstree-table-midwrapper a.jstree-hovered:before {position: absolute; left: 0; content:""; height: inherit; z-index: -1;}',
212
+ '.jstree-table-midwrapper a.jstree-hovered:before {background: #e7f4f9;}',
213
+ '.jstree-table-midwrapper a.jstree-clicked:before {background: #beebff;}',
214
+ '.vakata-context {z-index:2;}'
215
+ ];
216
+
217
+ $('<style type="text/css">'+styles.join("\n")+'</style>').appendTo("head");
218
+ }
219
+ this.tableWrapper = $("<div></div>").addClass("jstree-table-wrapper").insertAfter(container);
220
+ this.midWrapper = $("<div></div>").addClass("jstree-table-midwrapper").appendTo(this.tableWrapper);
221
+ // set the wrapper width
222
+ if (s.width) {
223
+ this.tableWrapper.width(s.width);
224
+ }
225
+ if (s.height) {
226
+ this.tableWrapper.height(s.height);
227
+ }
228
+ // create the data columns
229
+ for (i=0;i<cols.length;i++) {
230
+ // create the column
231
+ $("<div></div>").addClass("jstree-default jstree-table-column jstree-table-column-"+i+" jstree-table-column-root-"+this.rootid).appendTo(this.midWrapper);
232
+
233
+ if (typeof(cols[i].value) === "function") {
234
+ console.warn("[jstree-table] using value as a function is no longer supported, use 'format' option instead.");
235
+ }
236
+ }
237
+ this.midWrapper.children("div:eq("+treecol+")").append(container);
238
+ container.addClass("jstree-table-cell");
239
+
240
+ //move header with scroll
241
+ if (gs.fixedHeader) {
242
+ this.tableWrapper.scroll(function() {
243
+ $(this).find('.jstree-table-header').css('top', $(this).scrollTop());
244
+ });
245
+ }
246
+
247
+ // copy original sort function
248
+ var defaultSort = $.proxy(this.settings.sort, this);
249
+
250
+ // override sort function
251
+ this.settings.sort = function (a, b) {
252
+ var bigger;
253
+
254
+ if (gs.sortOrder==='text') {
255
+ bigger = defaultSort(a, b);
256
+ } else {
257
+ var nodeA = this.get_node(a);
258
+ var nodeB = this.get_node(b);
259
+ var valueA = nodeA.data[gs.sortOrder];
260
+ var valueB = nodeB.data[gs.sortOrder];
261
+ if(valueA && valueB){
262
+ if(gs.sortFn[gs.sortOrder]){
263
+ bigger = gs.sortFn[gs.sortOrder](valueA, valueB, nodeA, nodeB);
264
+ }else{
265
+ // Default sorting
266
+ bigger = (valueA > valueB ? 1 : -1);
267
+ }
268
+ }else{
269
+ // undefined is second
270
+ if(valueA){
271
+ bigger = 1;
272
+ }else if(valueB){
273
+ bigger = -1;
274
+ }else{
275
+ // Compare two nodes without values
276
+ bigger = defaultSort(a, b);
277
+ }
278
+ }
279
+ }
280
+
281
+ if (gs.sortAsc===false){
282
+ bigger = -bigger;
283
+
284
+ }
285
+
286
+ return bigger;
287
+ };
288
+
289
+ // sortable columns when jQuery UI is available
290
+ if (gs.draggable) {
291
+ if (!$.ui || !$.ui.sortable) {
292
+ console.warn('[jstree-table] draggable option requires jQuery UI');
293
+ } else {
294
+ var from, to;
295
+
296
+ $(this.midWrapper).sortable({
297
+ axis: "x",
298
+ handle: ".jstree-table-header",
299
+ cancel: ".jstree-table-separator",
300
+ start: function (event, ui) {
301
+ from = ui.item.index();
302
+ },
303
+ stop: function (event, ui) {
304
+ to = ui.item.index();
305
+ gs.columns.splice(to, 0, gs.columns.splice(from, 1)[0]);
306
+ }
307
+ });
308
+ }
309
+ }
310
+
311
+ this._initialized = true;
312
+ }
313
+ };
314
+ this.init = function (el,options) {
315
+ parent.init.call(this,el,options);
316
+ this._initialize();
317
+ };
318
+ this.bind = function () {
319
+ parent.bind.call(this);
320
+ this._initialize();
321
+ this.element
322
+ .on("move_node.jstree create_node.jstree clean_node.jstree change_node.jstree", $.proxy(function (e, data) {
323
+ var target = this.get_node(data || "#",true);
324
+ this._prepare_table(target);
325
+ }, this))
326
+ .on("delete_node.jstree",$.proxy(function (e,data) {
327
+ if (data.node.id !== undefined) {
328
+ var table = this.tableWrapper, removeNodes = [data.node.id], i;
329
+ // add children to remove list
330
+ if (data.node && data.node.children_d) {
331
+ removeNodes = removeNodes.concat(data.node.children_d);
332
+ }
333
+ for (i=0;i<removeNodes.length;i++) {
334
+ findDataCell(table,removeNodes[i]).remove();
335
+ }
336
+ }
337
+ }, this))
338
+ .on("close_node.jstree",$.proxy(function (e,data) {
339
+ this._hide_table(data.node);
340
+ }, this))
341
+ .on("open_node.jstree",$.proxy(function (e,data) {
342
+ }, this))
343
+ .on("load_node.jstree",$.proxy(function (e,data) {
344
+ }, this))
345
+ .on("loaded.jstree", $.proxy(function (e) {
346
+ this._prepare_headers();
347
+ this.element.trigger("loaded_table.jstree");
348
+ }, this))
349
+ .on("ready.jstree",$.proxy(function (e,data) {
350
+ var cls = this.element.attr("class") || "";
351
+
352
+ // add container classes to the wrapper - EXCEPT those that are added by jstree, i.e. "jstree" and "jstree-*"
353
+ q = cls.split(/\s+/).map(function(i) {
354
+ var match = i.match(/^jstree(-|$)/);
355
+ return (match ? "" : i);
356
+ });
357
+ this.tableWrapper.addClass(q.join(" "));
358
+
359
+ var me = this;
360
+ function resize() {
361
+ // find the line-height of the first known node
362
+ var anchorHeight = me.element.find(".jstree-leaf").outerHeight();
363
+
364
+ if(anchorHeight === null) {
365
+ var result = parent.create_node.call(me, '#', { "id" : "tmp", "text" : "tmp" });
366
+ anchorHeight = me.element.find(".jstree-leaf").outerHeight() || 24;
367
+ parent.delete_node.call(me, "tmp");
368
+ }
369
+
370
+ // resize the hover/ focus highlight
371
+ var tableWidth = $('.jstree-table-midwrapper').width();
372
+
373
+ $('#jsTreeTableExtraCss').remove();
374
+ $('<style type="text/css" id="jsTreeTableExtraCss">\
375
+ div.jstree-table-cell-root-'+me.rootid+' {line-height: '+anchorHeight+'px; min-height: '+anchorHeight+'px;}\
376
+ div.jstree-table-midwrapper a.jstree-clicked:before, .jstree-table-midwrapper a.jstree-hovered:before {width: ' + tableWidth + 'px;}\
377
+ </style>').appendTo("head");
378
+ }
379
+
380
+ resize();
381
+
382
+ // resize rows on zoom
383
+ $(window).on('resize', resize);
384
+
385
+ // resize column expand
386
+ this.element.on("resize_column.jstree-table", resize);
387
+ },this))
388
+ .on("move_node.jstree",$.proxy(function(e,data) {
389
+ var node = data.new_instance.element;
390
+ //renderAWidth(node,this);
391
+ // check all the children, because we could drag a tree over
392
+ node.find("li > a").each($.proxy(function(i,elm) {
393
+ //renderAWidth($(elm),this);
394
+ },this));
395
+ },this))
396
+ .on("search.jstree", $.proxy(function (e, data) {
397
+ // search sometimes filters, so we need to hide all of the appropriate table cells as well, and show only the matches
398
+ var table = this.tableWrapper;
399
+ if(this._data.search.som) {
400
+ if(data.nodes.length) {
401
+ // hide all of the table cells
402
+ table.find('div.jstree-table-cell-regular').hide();
403
+ // show only those that match
404
+ data.nodes.add(data.nodes.parentsUntil(".jstree")).filter(".jstree-node").each(function (i,node) {
405
+ var id = node.id;
406
+ if (id) {
407
+ findDataCell(table,id).show();
408
+ }
409
+ });
410
+ }
411
+ }
412
+ return true;
413
+ }, this))
414
+ .on("clear_search.jstree", $.proxy(function (e, data) {
415
+ // search has been cleared, so we need to show all rows
416
+ this.tableWrapper.find('div.jstree-table-cell').show();
417
+ return true;
418
+ }, this))
419
+ .on("copy_node.jstree", function (e, data) {
420
+ var newtree = data.new_instance, oldtree = data.old_instance, obj = newtree.get_node(data.node,true);
421
+ copyData(oldtree,data.original,newtree,data.node,true);
422
+ newtree._prepare_table(obj);
423
+ return true;
424
+ });
425
+ if (this._tableSettings.isThemeroller) {
426
+ this.element
427
+ .on("select_node.jstree",$.proxy(function(e,data) {
428
+ data.rslt.obj.children("a").nextAll("div").addClass("ui-state-active");
429
+ },this))
430
+ .on("deselect_node.jstree deselect_all.jstree",$.proxy(function(e,data) {
431
+ data.rslt.obj.children("a").nextAll("div").removeClass("ui-state-active");
432
+ },this))
433
+ .on("hover_node.jstree",$.proxy(function(e,data) {
434
+ data.rslt.obj.children("a").nextAll("div").addClass("ui-state-hover");
435
+ },this))
436
+ .on("dehover_node.jstree",$.proxy(function(e,data) {
437
+ data.rslt.obj.children("a").nextAll("div").removeClass("ui-state-hover");
438
+ },this));
439
+ }
440
+
441
+ if (this._tableSettings.stateful) {
442
+ this.element
443
+ .on("resize_column.jstree-table",$.proxy(function(e,col,width) {
444
+ localStorage['jstree-root-'+this.rootid+'-column-'+col] = width;
445
+ },this));
446
+ }
447
+ };
448
+ // tear down the tree entirely
449
+ this.teardown = function() {
450
+ var gw = this.tableWrapper, container = this.element, tableparent = gw.parent();
451
+ container.detach();
452
+ gw.remove();
453
+ tableparent.append(container);
454
+ parent.teardown.call(this);
455
+ };
456
+ // clean the table in case of redraw or refresh entire tree
457
+ this._clean_table = function (target,id) {
458
+ var table = this.tableWrapper;
459
+ if (target) {
460
+ findDataCell(table,id).remove();
461
+ } else {
462
+ // get all of the `div` children in all of the `td` in dataRow except for :first (that is the tree itself) and remove
463
+ table.find("div.jstree-table-cell-regular").remove();
464
+ }
465
+ };
466
+ // prepare the headers
467
+ this._prepare_headers = function() {
468
+ var header, i, col, _this = this, gs = this._tableSettings,cols = gs.columns || [], width, defaultWidth = gs.columnWidth, resizable = gs.resizable || false,
469
+ cl, ccl, val, name, margin, last, tr = gs.isThemeroller, classAdd = (tr?"themeroller":"regular"), puller,
470
+ hasHeaders = false, tableparent = this.tableparent, rootid = this.rootid,
471
+ conf = gs.defaultConf,
472
+ borPadWidth = 0, totalWidth = 0;
473
+ // save the original parent so we can reparent on destroy
474
+ this.parent = tableparent;
475
+
476
+
477
+ // create the headers
478
+ for (i=0;i<cols.length;i++) {
479
+ //col = $("<col/>");
480
+ //col.appendTo(colgroup);
481
+ cl = cols[i].headerClass || "";
482
+ ccl = cols[i].columnClass || "";
483
+ val = cols[i].header || "";
484
+ name = cols[i].value || "text";
485
+
486
+ if (val) {hasHeaders = true;}
487
+ if(gs.stateful && localStorage['jstree-root-'+rootid+'-column-'+i])
488
+ width = localStorage['jstree-root-'+rootid+'-column-'+i];
489
+ else
490
+ width = cols[i].width || defaultWidth;
491
+
492
+ col = this.midWrapper.children("div.jstree-table-column-"+i);
493
+ last = $("<div></div>").css(conf).addClass("jstree-table-div-"+this.uniq+"-"+i+" "+(tr?"ui-widget-header ":"")+" jstree-table-header jstree-table-header-cell jstree-table-header-"+classAdd+" "+cl+" "+ccl).html(val);
494
+ last.addClass((tr?"ui-widget-header ":"")+"jstree-table-header jstree-table-header-"+classAdd);
495
+ last.prependTo(col);
496
+
497
+ if (name) {
498
+ last.attr(COL_DATA_ATTR, name);
499
+ }
500
+ last.hover(function () {
501
+ $(this).addClass("jstree-hovered jstree-table-header-hovered");
502
+ }, function () {
503
+ $(this).removeClass("jstree-hovered jstree-table-header-hovered");
504
+ });
505
+ totalWidth += last.outerWidth();
506
+ puller = $("<div class='jstree-table-separator jstree-table-separator-"+classAdd+(tr ? " ui-widget-header" : "")+(resizable? " jstree-table-resizable-separator":"")+"'>&nbsp;</div>").appendTo(last);
507
+ col.width(width);
508
+ col.css("min-width",width);
509
+ col.css("max-width",width);
510
+ }
511
+
512
+ last.addClass((tr?"ui-widget-header ":"")+"jstree-table-header jstree-table-header-last jstree-table-header-"+classAdd);
513
+ // if there is no width given for the last column, do it via automatic
514
+ if (cols[cols.length-1].width === undefined) {
515
+ totalWidth -= width;
516
+ col.css({width:"auto"});
517
+ last.addClass("jstree-table-width-auto").next(".jstree-table-separator").remove();
518
+ }
519
+ if (hasHeaders) {
520
+ // save the offset of the div from the body
521
+ //gs.divOffset = header.parent().offset().left;
522
+ gs.header = header;
523
+ } else {
524
+ $("div.jstree-table-header").hide();
525
+ }
526
+
527
+ if (!this.bound && resizable) {
528
+ this.bound = true;
529
+ $(document).mouseup(function () {
530
+ var ref, cols, width, headers, currentTree, colNum;
531
+ if (isClickedSep) {
532
+ colNum = toResize.prevAll(".jstree-table-column").length;
533
+ currentTree = toResize.closest(".jstree-table-wrapper").find(".jstree");
534
+ ref = $.jstree.reference(currentTree);
535
+ cols = ref.settings.table.columns;
536
+ headers = toResize.parent().children("div.jstree-table-column");
537
+ if (isNaN(colNum) || colNum < 0) { ref._tableSettings.treeWidthDiff = currentTree.find("ins:eq(0)").width() + currentTree.find("a:eq(0)").width() - ref._tableSettings.columns[0].width; }
538
+ width = ref._tableSettings.columns[colNum].width = parseFloat(toResize.css("width"));
539
+ isClickedSep = false;
540
+ toResize = null;
541
+
542
+ currentTree.trigger("resize_column.jstree-table", [colNum,width]);
543
+ }
544
+ }).mousemove(function (e) {
545
+ if (isClickedSep) {
546
+ newMouseX = e.pageX;
547
+ var diff = newMouseX - oldMouseX,
548
+ oldPrevHeaderInner,
549
+ oldPrevColWidth, newPrevColWidth;
550
+
551
+ if (diff !== 0) {
552
+ oldPrevHeaderInner = toResize.width();
553
+ oldPrevColWidth = parseFloat(toResize.css("width"));
554
+
555
+ // handle a Chrome issue with columns set to auto
556
+ // thanks to Brabus https://github.com/side-by-side
557
+ if (!oldPrevColWidth) {
558
+ oldPrevColWidth = toResize.innerWidth();
559
+ }
560
+
561
+ // make sure that diff cannot be beyond the left/right limits
562
+ diff = diff < 0 ? Math.max(diff,-oldPrevHeaderInner) : diff;
563
+ newPrevColWidth = oldPrevColWidth+diff;
564
+
565
+ // only do this if we are not shrinking past 0 on left - and limit it to that amount
566
+ if ((diff > 0 || oldPrevHeaderInner > 0) && newPrevColWidth > MINCOLWIDTH) {
567
+ toResize.width(newPrevColWidth+"px");
568
+ toResize.css("min-width",newPrevColWidth+"px");
569
+ toResize.css("max-width",newPrevColWidth+"px");
570
+ oldMouseX = newMouseX;
571
+ }
572
+ }
573
+ }
574
+ });
575
+ this.tableWrapper.on("selectstart", ".jstree-table-resizable-separator", function () {
576
+ return false;
577
+ })
578
+ .on("mousedown", ".jstree-table-resizable-separator", function (e) {
579
+ isClickedSep = true;
580
+ oldMouseX = e.pageX;
581
+ toResize = $(this).closest("div.jstree-table-column");
582
+ // the max rightmost position we will allow is the right-most of the wrapper minus a buffer (10)
583
+ return false;
584
+ })
585
+ .on("dblclick", ".jstree-table-resizable-separator", function (e) {
586
+ var col = $(this).closest("div.jstree-table-column");
587
+ _this.autosize_column(col);
588
+ })
589
+ .on("click", ".jstree-table-separator", function (e) {
590
+ // don't sort after resize
591
+ e.stopPropagation();
592
+ });
593
+ }
594
+
595
+ this.tableWrapper.on("click", ".jstree-table-header-cell", function (e) {
596
+ if (!_this.sort) { return; }
597
+
598
+ // get column
599
+ var name = $(this).attr(COL_DATA_ATTR);
600
+ if (!name) { return; }
601
+
602
+ // sort order
603
+ var arrowClass;
604
+ if (gs.sortOrder === name && gs.sortAsc === true) {
605
+ gs.sortAsc = false;
606
+ arrowClass = gs.arrowDownIcon;
607
+ } else {
608
+ gs.sortOrder = name;
609
+ gs.sortAsc = true;
610
+ arrowClass = gs.arrowUpIcon;
611
+ }
612
+
613
+ // add sort arrow
614
+ $(this).closest('.jstree-table-wrapper').find(".jstree-table-sort-icon").remove();
615
+ $("<span></span>").addClass("jstree-table-sort-icon").appendTo($(this)).addClass(arrowClass);
616
+
617
+ // sort by column
618
+ var rootNode = _this.get_node('#');
619
+ _this.sort(rootNode, true);
620
+ _this.redraw_node(rootNode, true);
621
+ });
622
+
623
+ // header context menu
624
+ this.midWrapper.on("contextmenu", ".jstree-table-header-cell", function(e) {
625
+ if (!gs.headerContextMenu) { return; }
626
+ e.preventDefault();
627
+
628
+ var options = {
629
+ "fit":{label:"Size column to fit","action": function (data) {
630
+ var col = $(e.target).closest("div.jstree-table-column");
631
+ _this.autosize_column(col);
632
+ }},
633
+ "fitAll":{"separator_after": true,label:"Size all columns to fit","action": function (data) {
634
+ _this.autosize_all_columns();
635
+ }}
636
+ };
637
+
638
+ // create menu item for every header cell
639
+ var cell, icon, value, label;
640
+ _this.midWrapper.find(".jstree-table-header-cell").each(function() {
641
+ cell = $(this);
642
+ icon = cell.is(":visible") ? gs.checkIcon : false;
643
+ value = cell.attr(COL_DATA_ATTR);
644
+ //get label without sorting arrows
645
+ label = cell.clone().children('.jstree-table-sort-icon').remove().end().text().trim();
646
+
647
+ options[value] = {icon:icon, column:value, label:label, _disabled: (value === 'text'), "action": function (data) {
648
+ var col = _this.midWrapper.find(".jstree-table-header-cell["+COL_DATA_ATTR+"='"+data.item.column+"']").parent();
649
+ col.toggle();
650
+ }};
651
+ });
652
+
653
+ $.vakata.context.show(this,{ 'x' : e.pageX, 'y' : e.pageY },options);
654
+ });
655
+ };
656
+ /*
657
+ * Override redraw_node to correctly insert the table
658
+ */
659
+ this.redraw_node = function(obj, deep, is_callback, force_render) {
660
+ // first allow the parent to redraw the node
661
+ obj = parent.redraw_node.call(this, obj, deep, is_callback, force_render);
662
+ // next prepare the table
663
+ if(obj) {
664
+ this._prepare_table(obj);
665
+ }
666
+ return obj;
667
+ };
668
+ this.refresh = function () {
669
+ this._clean_table();
670
+ return parent.refresh.apply(this,arguments);
671
+ };
672
+ /*
673
+ * Override set_id to update cell attributes
674
+ */
675
+ this.set_id = function (obj, id) {
676
+ var old;
677
+ if(obj) {
678
+ old = obj.id;
679
+ }
680
+ var result = parent.set_id.apply(this,arguments);
681
+ if(result) {
682
+ if (old !== undefined) {
683
+ var table = this.tableWrapper, oldNodes = [old], i;
684
+ // get children
685
+ if (obj && obj.children_d) {
686
+ oldNodes = oldNodes.concat(obj.children_d);
687
+ }
688
+ // update id in children
689
+ for (i=0;i<oldNodes.length;i++) {
690
+ findDataCell(table,oldNodes[i])
691
+ .attr(NODE_DATA_ATTR, obj.id)
692
+ .attr('id', TABLECELLID_PREFIX+obj.id+TABLECELLID_POSTFIX+(i+1))
693
+ .removeClass(TABLECELLID_PREFIX+old+TABLECELLID_POSTFIX)
694
+ .addClass(TABLECELLID_PREFIX+obj.id+TABLECELLID_POSTFIX);
695
+ }
696
+ }
697
+ }
698
+ return result;
699
+ };
700
+ this._hide_table = function (node) {
701
+ var children = node && node.children_d ? node.children_d : [], i;
702
+ // go through each column, remove all children with the correct ID name
703
+ for (i=0;i<children.length;i++) {
704
+ findDataCell(this.tableWrapper,children[i]).remove();
705
+ }
706
+ };
707
+ this.holdingCells = {};
708
+ this.getHoldingCells = function (obj,col,hc) {
709
+ var ret = [];
710
+ this._getHoldingCells(obj,col,hc,ret);
711
+ return($(ret));
712
+ };
713
+ this._getHoldingCells = function (obj,col,hc,ret) {
714
+ var children = obj.children||[], child, i;
715
+ // run through each child, render it, and then render its children recursively
716
+ for (i=0;i<children.length;i++) {
717
+ child = TABLECELLID_PREFIX+escapeId(children[i])+TABLECELLID_POSTFIX+col;
718
+ if (hc[child] && obj.state.opened) {
719
+ ret.push(hc[child][0]);
720
+ this._getHoldingCells(this.get_node(children[i]),col,hc,ret);
721
+ //delete hc[child];
722
+ }
723
+ }
724
+ };
725
+ /**
726
+ * put a table cell in edit mode (input field to edit the data)
727
+ * @name edit(obj, col)
728
+ * @param {mixed} obj
729
+ * @param {obj} col definition
730
+ * @param {element} cell element, either span or wrapping div
731
+ */
732
+ this._edit = function (obj, col, element) {
733
+ if(!obj) { return false; }
734
+ if (element) {
735
+ element = $(element);
736
+ if (element.prop("tagName").toLowerCase() === "div") {
737
+ element = element.children("span:first");
738
+ }
739
+ } else {
740
+ // need to find the element - later
741
+ return false;
742
+ }
743
+ var rtl = this._data.core.rtl,
744
+ w = this.element.width(),
745
+ t = obj.data[col.value],
746
+ h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"),
747
+ h2 = $("<"+"input />", {
748
+ "value" : t,
749
+ "class" : "jstree-rename-input",
750
+ "css" : {
751
+ "padding" : "0",
752
+ "border" : "1px solid silver",
753
+ "box-sizing" : "border-box",
754
+ "display" : "inline-block",
755
+ "height" : (this._data.core.li_height) + "px",
756
+ "lineHeight" : (this._data.core.li_height) + "px",
757
+ "width" : "150px" // will be set a bit further down
758
+ },
759
+ "blur" : $.proxy(function () {
760
+ var v = h2.val();
761
+ // save the value if changed
762
+ if(v === "" || v === t) {
763
+ v = t;
764
+ } else {
765
+ obj.data[col.value] = v;
766
+ this.element.trigger('update_cell.jstree-table',{node:obj, col:col.value, value:v, old:t});
767
+ this._prepare_table(this.get_node(obj,true));
768
+ }
769
+ h2.remove();
770
+ element.show();
771
+ }, this),
772
+ "keydown" : function (event) {
773
+ var key = event.which;
774
+ if(key === 27) {
775
+ this.value = t;
776
+ }
777
+ if(key === 27 || key === 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) {
778
+ event.stopImmediatePropagation();
779
+ }
780
+ if(key === 27 || key === 13) {
781
+ event.preventDefault();
782
+ this.blur();
783
+ }
784
+ },
785
+ "click" : function (e) { e.stopImmediatePropagation(); },
786
+ "mousedown" : function (e) { e.stopImmediatePropagation(); },
787
+ "keyup" : function (event) {
788
+ h2.width(Math.min(h1.text("pW" + this.value).width(),w));
789
+ },
790
+ "keypress" : function(event) {
791
+ if(event.which === 13) { return false; }
792
+ }
793
+ }),
794
+ fn = {
795
+ fontFamily : element.css('fontFamily') || '',
796
+ fontSize : element.css('fontSize') || '',
797
+ fontWeight : element.css('fontWeight') || '',
798
+ fontStyle : element.css('fontStyle') || '',
799
+ fontStretch : element.css('fontStretch') || '',
800
+ fontVariant : element.css('fontVariant') || '',
801
+ letterSpacing : element.css('letterSpacing') || '',
802
+ wordSpacing : element.css('wordSpacing') || ''
803
+ };
804
+ element.hide();
805
+ element.parent().append(h2);
806
+ h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
807
+ };
808
+
809
+ this.autosize_column = function (col) {
810
+ // don't resize hidden columns
811
+ if (col.is(":hidden")) { return; }
812
+
813
+ var oldPrevColWidth = parseFloat(col.css("width")), newWidth = 0, diff,
814
+ colNum = col.prevAll(".jstree-table-column").length,
815
+ oldPrevHeaderInner = col.width(), newPrevColWidth;
816
+
817
+ //find largest width
818
+ col.find(".jstree-table-cell").each(function() {
819
+ var item = $(this), width;
820
+ item.css("position", "absolute");
821
+ item.css("width", "auto");
822
+ width = item.outerWidth();
823
+ item.css("position", "relative");
824
+
825
+ if (width>newWidth) {
826
+ newWidth = width;
827
+ }
828
+ });
829
+
830
+ diff = newWidth-oldPrevColWidth;
831
+
832
+ // make sure that diff cannot be beyond the left limits
833
+ diff = diff < 0 ? Math.max(diff,-oldPrevHeaderInner) : diff;
834
+ newPrevColWidth = (oldPrevColWidth+diff)+"px";
835
+
836
+ col.width(newPrevColWidth);
837
+ col.css("min-width",newPrevColWidth);
838
+ col.css("max-width",newPrevColWidth);
839
+
840
+ $(this).closest(".jstree-table-wrapper").find(".jstree").trigger("resize_column.jstree-table",[colNum,newPrevColWidth]);
841
+ };
842
+
843
+ this.autosize_all_columns = function () {
844
+ this.tableWrapper.find(".jstree-table-column").each(function() {
845
+ _this.autosize_column($(this));
846
+ });
847
+ };
848
+
849
+ this._prepare_table = function (obj) {
850
+ var gs = this._tableSettings, c = gs.treeClass, _this = this, t, cols = gs.columns || [], width, tr = gs.isThemeroller,
851
+ tree = this.element, rootid = this.rootid,
852
+ classAdd = (tr?"themeroller":"regular"), img, objData = this.get_node(obj),
853
+ defaultWidth = gs.columnWidth, conf = gs.defaultConf, cellClickHandler = function (tree,node,val,col,t) {
854
+ return function(e) {
855
+ //node = tree.find("#"+node.attr("id"));
856
+ node.children(".jstree-anchor").trigger("click.jstree",e);
857
+ tree.trigger("select_cell.jstree-table", [{value: val,column: col.header,node: node,table:$(this),sourceName: col.value}]);
858
+ };
859
+ }, cellRightClickHandler = function (tree,node,val,col,t) {
860
+ return function (e) {
861
+ if (gs.context) {
862
+ e.preventDefault();
863
+ $.vakata.context.show(this,{ 'x' : e.pageX, 'y' : e.pageY },{
864
+ "edit":{label:"Edit","action": function (data) {
865
+ var obj = t.get_node(node);
866
+ _this._edit(obj,col,e.target);
867
+ }}
868
+ });
869
+ }
870
+ };
871
+ },
872
+ hoverInHandler = function (node, jsTreeInstance) {
873
+ return function() { jsTreeInstance.hover_node(node); };
874
+ },
875
+ hoverOutHandler = function (node, jsTreeInstance) {
876
+ return function() { jsTreeInstance.dehover_node(node); };
877
+ },
878
+ i, val, cl, wcl, ccl, a, last, valClass, wideValClass, span, paddingleft, title, tableCellName, tableCellParentId, tableCellParent,
879
+ tableCellPrev, tableCellPrevId, tableCellNext, tableCellNextId, tableCellChild, tableCellChildId,
880
+ col, content, tmpWidth, mw = this.midWrapper, dataCell, dataCellNb, lid = objData.id,
881
+ peers = this.get_node(objData.parent).children,
882
+ // find my position in the list of peers. "peers" is the list of everyone at my level under my parent, in order
883
+ pos = $.inArray(lid,peers),
884
+ hc = this.holdingCells, rendered = false, closed;
885
+ // get our column definition
886
+ t = $(obj);
887
+
888
+ // find the a children
889
+ a = t.children("a");
890
+
891
+ if (a.length === 1) {
892
+ closed = !objData.state.opened;
893
+ tableCellName = TABLECELLID_PREFIX+escapeId(lid)+TABLECELLID_POSTFIX;
894
+ tableCellParentId = objData.parent === "#" ? null : objData.parent;
895
+ a.addClass(c);
896
+ //renderAWidth(a,_this);
897
+ renderATitle(a,t,_this);
898
+ last = a;
899
+ // find which column our tree shuld go in
900
+ var s = this.settings.table;
901
+ var treecol = 0;
902
+ for (i=0;i<s.columns.length;i++) {
903
+ if (s.columns[i].tree) {
904
+ // save which column it was
905
+ treecol = i;
906
+ // do not check any others
907
+ break;
908
+ }
909
+ }
910
+ for (i=0;i<cols.length;i++) {
911
+ if (treecol === i) {
912
+ continue;
913
+ }
914
+ col = cols[i];
915
+ dataCell = mw.children("div:eq("+i+")");
916
+ dataCellNb = i;
917
+ // get the cellClass, the wideCellClass, and the columnClass
918
+ cl = col.cellClass || "";
919
+ wcl = col.wideCellClass || "";
920
+ ccl = col.columnClass || "";
921
+
922
+ // add a column class to the dataCell
923
+ dataCell.addClass(ccl);
924
+
925
+ // get the contents of the cell
926
+ val = "";
927
+ if (objData.data && objData.data[col.value] !== undefined) {
928
+ val = objData.data[col.value];
929
+ }
930
+
931
+ if (typeof(col.format) === "function") {
932
+ val = col.format(val);
933
+ }
934
+
935
+ // put images instead of text if needed
936
+ if (col.images) {
937
+ img = col.images[val] || col.images["default"];
938
+ if (img) {content = img[0] === "*" ? '<span class="'+img.substr(1)+'"></span>' : '<img src="'+img+'">';}
939
+ } else { content = val; }
940
+
941
+ // content cannot be blank, or it messes up heights
942
+ if (content === undefined || content === null || BLANKRE.test(content)) {
943
+ content = "&nbsp;";
944
+ }
945
+
946
+ // get the valueClass
947
+ valClass = col.valueClass && objData.data !== null && objData.data !== undefined ? objData.data[col.valueClass] || "" : "";
948
+ if (valClass && col.valueClassPrefix && col.valueClassPrefix !== "") {
949
+ valClass = col.valueClassPrefix + valClass;
950
+ }
951
+ // get the wideValueClass
952
+ wideValClass = col.wideValueClass && objData.data !== null && objData.data !== undefined ? objData.data[col.wideValueClass] || "" : "";
953
+ if (wideValClass && col.wideValueClassPrefix && col.wideValueClassPrefix !== "") {
954
+ wideValClass = col.wideValueClassPrefix + wideValClass;
955
+ }
956
+ // get the title
957
+ title = col.title && objData.data !== null && objData.data !== undefined ? objData.data[col.title] || "" : "";
958
+ // strip out HTML
959
+ if (typeof title === 'string') {
960
+ title = title.replace(htmlstripre, '');
961
+ }
962
+
963
+ // get the width
964
+ paddingleft = 7;
965
+ width = col.width || defaultWidth;
966
+ if (width !== 'auto') {
967
+ width = tmpWidth || (width - paddingleft);
968
+ }
969
+
970
+ last = findDataCellFast(dataCellNb, lid);
971
+ if (!last || last.length < 1) {
972
+ last = $("<div></div>");
973
+ $("<span></span>").appendTo(last);
974
+ last.attr("id",tableCellName+i);
975
+ last.addClass(tableCellName);
976
+ last.attr(NODE_DATA_ATTR,lid);
977
+
978
+ }
979
+ // we need to put it in the dataCell - after the parent, but the position matters
980
+ // if we have no parent, then we are one of the root nodes, but still need to look at peers
981
+
982
+
983
+ // if we are first, i.e. pos === 0, we go right after the parent;
984
+ // if we are not first, and our previous peer (one before us) is closed, we go right after the previous peer cell
985
+ // if we are not first, and our previous peer is opened, then we have to find its youngest & lowest closed child (incl. leaf)
986
+ //
987
+ // probably be much easier to go *before* our next one
988
+ // but that one might not be drawn yet
989
+ // here is the logic for jstree drawing:
990
+ // it draws peers from first to last or from last to first
991
+ // it draws children before a parent
992
+ //
993
+ // so I can rely on my *parent* not being drawn, but I cannot rely on my previous peer or my next peer being drawn
994
+
995
+ // so we do the following:
996
+ // 1- We are the first child: install after the parent
997
+ // 2- Our previous peer is already drawn: install after the previous peer
998
+ // 3- Our previous peer is not drawn, we have a child that is drawn: install right before our first child
999
+ // 4- Our previous peer is not drawn, we have no child that is drawn, our next peer is drawn: install right before our next peer
1000
+ // 5- Our previous peer is not drawn, we have no child that is drawn, our next peer is not drawn: install right after parent
1001
+ tableCellPrevId = pos <=0 ? objData.parent : findLastClosedNode(this,peers[pos-1]);
1002
+ tableCellPrev = findDataCellFast(dataCellNb,tableCellPrevId);
1003
+ tableCellNextId = pos >= peers.length-1 ? "NULL" : peers[pos+1];
1004
+ tableCellNext = findDataCellFast(dataCellNb,tableCellNextId);
1005
+ tableCellChildId = objData.children && objData.children.length > 0 ? objData.children[0] : "NULL";
1006
+ tableCellChild = findDataCellFast(dataCellNb,tableCellChildId);
1007
+ tableCellParent = findDataCellFast(dataCellNb,tableCellParentId);
1008
+
1009
+ // if our parent is already drawn, then we put this in the right order under our parent
1010
+ if (tableCellParentId) {
1011
+ if (tableCellParent && tableCellParent.length > 0) {
1012
+ if (tableCellPrev && tableCellPrev.length > 0) {
1013
+ last.insertAfter(tableCellPrev);
1014
+ } else if (tableCellChild && tableCellChild.length > 0) {
1015
+ last.insertBefore(tableCellChild);
1016
+ } else if (tableCellNext && tableCellNext.length > 0) {
1017
+ last.insertBefore(tableCellNext);
1018
+ } else {
1019
+ last.insertAfter(tableCellParent);
1020
+ }
1021
+ rendered = true;
1022
+ } else {
1023
+ rendered = false;
1024
+ }
1025
+ // always put it in the holding cells, and then sort when the parent comes in, in case parent is (re)drawn later
1026
+ hc[tableCellName+i] = last;
1027
+ } else {
1028
+ if (tableCellPrev && tableCellPrev.length > 0) {
1029
+ last.insertAfter(tableCellPrev);
1030
+ } else if (tableCellChild && tableCellChild.length > 0) {
1031
+ last.insertBefore(tableCellChild);
1032
+ } else if (tableCellNext && tableCellNext.length > 0) {
1033
+ last.insertBefore(tableCellNext);
1034
+ } else {
1035
+ last.appendTo(dataCell);
1036
+ }
1037
+ rendered = true;
1038
+ }
1039
+ // do we have any children waiting for this cell? walk down through the children/grandchildren/etc tree
1040
+ if (rendered) {
1041
+ last.after(this.getHoldingCells(objData,i,hc));
1042
+ }
1043
+ // need to make the height of this match the line height of the tree. How?
1044
+ span = last.children("span");
1045
+
1046
+ // create a span inside the div, so we can control what happens in the whole div versus inside just the text/background
1047
+ span.addClass(cl+" "+valClass).html(content);
1048
+ last = last.css(conf).addClass("jstree-table-cell jstree-table-cell-regular jstree-table-cell-root-"+rootid+" jstree-table-cell-"+classAdd+" "+wcl+ " " + wideValClass + (tr?" ui-state-default":"")).addClass("jstree-table-col-"+i);
1049
+ // add click handler for clicking inside a table cell
1050
+ last.click(cellClickHandler(tree,t,val,col,this));
1051
+ last.on("contextmenu",cellRightClickHandler(tree,t,val,col,this));
1052
+ last.hover(hoverInHandler(t, this), hoverOutHandler(t, this));
1053
+
1054
+ if (title) {
1055
+ span.attr("title",title);
1056
+ }
1057
+ }
1058
+ last.addClass("jstree-table-cell-last"+(tr?" ui-state-default":""));
1059
+ // if there is no width given for the last column, do it via automatic
1060
+ if (cols[cols.length-1].width === undefined) {
1061
+ last.addClass("jstree-table-width-auto").next(".jstree-table-separator").remove();
1062
+ }
1063
+ }
1064
+ this.element.css({'overflow-y':'auto !important'});
1065
+ };
1066
+ // clean up holding cells
1067
+ this.holdingCells = {};
1068
+ };
1069
+ }));