jt
2021-06-10 5d0d028456874576560552f5a5c4e8b801786f11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*          Copyright Paul Hanlon (paulhan@eircom.net)
            Licence MIT, BSD, same as jQuery;
Please leave the above copyright notice with this code,
if for no other reason than people wanting to get in touch for help/support.
Not much here in the way of documentation. I'm hoping the demo on the website at
http://www.hanpau.com/jquery/unobtrusivetreetable.php will explain most of it,
particularly how the map is constructed.
The options are mostly the images you need to render the tree properly, with the
last five being:-
collapse:
    Either false or an array of parents to collapse. Just put in the highest
    level nodes, this will recurse down through the children and collapse them,
    without them having to be specified as well. Even if you only set one parent
    to be collapsed, it must be in [] brackets.
column:
    A zero based number of the column you want to render the tree in.
stripe:
    Set to true if you want to have striping on alternate rows. False returns a
    plain treetable. An "even" class needs to be set in CSS for background-color.
highlight:
    Set to true if you want to highlight the row that is being hovered over.
    An "over" class needs to be set in CSS for background-color.
onselect:
    Callback function where you can set what you want to happen when a td is selected
    Forces highlighting on td even if there are other elements within. Links and events
    still work though.
*/
(function(jq){
  var mapa = [], mapb = [], num=0,
  opts = {openImg: "tv-collapsable.gif", shutImg: "tv-expandable.gif", leafImg: "tv-item.gif", lastOpenImg: "tv-collapsable-last.gif", lastShutImg: "tv-expandable-last.gif", lastLeafImg: "tv-item-last.gif", vertLineImg: "vertline.gif", blankImg: "blank.gif", collapse: false, column: 0, striped: false, highlight: false, onselect: false};
  jq.fn.jqTreeTable = function(map, options){
    for (var i in opts){//Sort out the options
      opts[i] = (options[i])? options[i]: opts[i];
    }
    for (var x=0,xl=map.length; x<xl;x++){//From map of parents, get map of kids
      num = map[x];
      if (!mapa[num]){
        mapa[num] = [];
      }
      mapa[num].push(x+1);
    }
    buildText(0, "");
    jq("tr", this).each(function(i){//Inject the images into the column to make it work
      jq(this).children("td").eq(opts.column).prepend(mapb[i]);
    });
    if (opts.collapse instanceof Array){//Set nodes to collapsed
      for (var y=0, yl=opts.collapse.length; y<yl; y++){
        collapseKids(opts.collapse[y]);
      }
    }
    if(opts.striped){jq("#treetable tr:even").addClass("even")};//Stripe all even rows
    jq(".parimg", this).each(function(i){
      var $this = jq(this);
      $this.click(function(){
        var num = $this.attr("id").substr(1);//Number of the row
        if ($this.parents("tr").next().is(".collapsed")){//Then expand immediate children
          expandKids(num);
        }else{//Collapse all and set image to opts.shutImg or opts.lastShutImg on parents
          collapseKids(num);
        }
        if(opts.striped){stripe(num-1)};//Restripe all the rows under this one
      });
    });
    if (opts.highlight){//This is where it highlights the rows
      jq("tr", this).hover(function(){
        jq(this).addClass("over");
      },
      function(){
        jq(this).removeClass("over");
      });
    }
    jq("#treetable").click( function( event ) {//This looks after selecting td's
      var $target = (event.target.tagName == "TD")?jq(event.target):jq(event.target).parents("td");
      if (typeof opts.onselect == "function"){
        jq("td.selected", this).removeClass("selected");
        $target.addClass("selected");
        opts.onselect($target);
      };
    });
  };
  buildText = function(parno, preStr){//Recursively build up the text for the images that make it work
    var mp = mapa[parno], ro=0, pre="", pref, img;
    for (var y=0, yl=mp.length;y<yl;y++){
      ro = mp[y];
      if (mapa[ro]){//It's a parent as well. Build it's string and move on to it's children
        if (y==yl-1){//It's the last child, It's child will have a blank field behind it
          pre = opts.blankImg;
          img = opts.lastOpenImg;
        }else{
          pre = opts.vertLineImg;
          img = opts.openImg;
        }
        mapb[ro-1] = preStr + '<img style="cursor:pointer;"  align="absmiddle" src="'+img+'" class="parimg" id="r'+ro+'">';
        pref = preStr + '<img style="cursor:pointer;" align="absmiddle"  src="' + pre + '" class="preimg">';
        buildText(ro, pref);
      }else{//it's a child
        img = (y==yl-1)? opts.lastLeafImg: opts.leafImg;//It's the last child, It's child will have a blank field behind it
        mapb[ro-1] = preStr + '<img align="absmiddle" src="'+img+'" class="ttimage">';
      }
    }
  };
  expandKids = function(num){//Expands immediate children
    jq("#r"+num).attr("src", function(){
      return (this.src.substr(this.src.lastIndexOf("/")+1)==opts.lastShutImg)? opts.lastOpenImg: opts.openImg;
    });
    for (var x=0, xl=mapa[num].length;x<xl;x++){
      jq("#treetable tr").eq(mapa[num][x]-1).removeClass("collapsed");
    }
  };
  collapseKids = function(num){//Recursively collapses all children and their children and changes
    var mapnumx=0;             //parent images to collapsed state
    jq("#r"+num).attr("src", function(){
      if (this.src.substr(this.src.lastIndexOf("/")+1)!=opts.lastShutImg){
        return (this.src.substr(this.src.lastIndexOf("/")+1)==opts.lastOpenImg)? opts.lastShutImg: opts.shutImg;
      }
    });
    for (var x=0, xl=mapa[num].length;x<xl;x++){
      mapnumx = mapa[num][x];
      jq("#treetable tr").eq(mapnumx-1).addClass("collapsed");
      if (mapa[mapnumx]){
        collapseKids(mapnumx);
      }
    }
  };
  stripe = function(num){//Dynamically stripes rows after expanding/collapsing
    var isStriped = (jq("#treetable tr").eq(num).attr("class")=="even over")? 0:1;
    jq("#treetable tr").gt(num).not(".collapsed").each(function(i){
      if ((i+isStriped) % 2==0){
        jq(this).removeClass("even");
      }else{
        jq(this).addClass("even");
      }
    });
  };
  return this;
})(jQuery);