xref: /openbsd-src/gnu/llvm/clang/www/analyzer/scripts/expandcollapse.js (revision e5dd70708596ae51455a0ffa086a00c5b29f8583)
1*e5dd7070Spatrick// expand/collapse button (expander) is added if height of a cell content
2*e5dd7070Spatrick// exceeds CLIP_HEIGHT px.
3*e5dd7070Spatrickvar CLIP_HEIGHT = 135;
4*e5dd7070Spatrick
5*e5dd7070Spatrick// Height in pixels of an expander image.
6*e5dd7070Spatrickvar EXPANDER_HEIGHT = 13;
7*e5dd7070Spatrick
8*e5dd7070Spatrick// Path to images for an expander.
9*e5dd7070Spatrickvar imgPath = "./images/expandcollapse/";
10*e5dd7070Spatrick
11*e5dd7070Spatrick// array[group][cell] of { 'height', 'expanded' }.
12*e5dd7070Spatrick// group: a number; cells of the same group belong to the same table row.
13*e5dd7070Spatrick// cell: a number; unique index of a cell in a group.
14*e5dd7070Spatrick// height: a number, px; original height of a cell in a table.
15*e5dd7070Spatrick// expanded: boolean; is a cell expanded or collapsed?
16*e5dd7070Spatrickvar CellsInfo = [];
17*e5dd7070Spatrick
18*e5dd7070Spatrick// Extracts group and cell indices from an id of the form identifier_group_cell.
19*e5dd7070Spatrickfunction getCellIdx(id) {
20*e5dd7070Spatrick  var idx = id.substr(id.indexOf("_") + 1).split("_");
21*e5dd7070Spatrick  return { 'group': idx[0], 'cell': idx[1] };
22*e5dd7070Spatrick}
23*e5dd7070Spatrick
24*e5dd7070Spatrick// Returns { 'height', 'expanded' } info for a cell with a given id.
25*e5dd7070Spatrickfunction getCellInfo(id) {
26*e5dd7070Spatrick  var idx = getCellIdx(id);
27*e5dd7070Spatrick  return CellsInfo[idx.group][idx.cell];
28*e5dd7070Spatrick}
29*e5dd7070Spatrick
30*e5dd7070Spatrick// Initialization, add nodes, collect info.
31*e5dd7070Spatrickfunction initExpandCollapse() {
32*e5dd7070Spatrick  if (!document.getElementById)
33*e5dd7070Spatrick    return;
34*e5dd7070Spatrick
35*e5dd7070Spatrick  var groupCount = 0;
36*e5dd7070Spatrick
37*e5dd7070Spatrick  // Examine all table rows in the document.
38*e5dd7070Spatrick  var rows = document.body.getElementsByTagName("tr");
39*e5dd7070Spatrick  for (var i=0; i<rows.length; i+=1) {
40*e5dd7070Spatrick
41*e5dd7070Spatrick    var cellCount=0, newGroupCreated = false;
42*e5dd7070Spatrick
43*e5dd7070Spatrick    // Examine all divs in a table row.
44*e5dd7070Spatrick    var divs = rows[i].getElementsByTagName("div");
45*e5dd7070Spatrick    for (var j=0; j<divs.length; j+=1) {
46*e5dd7070Spatrick
47*e5dd7070Spatrick      var expandableDiv = divs[j];
48*e5dd7070Spatrick
49*e5dd7070Spatrick      if (expandableDiv.className.indexOf("expandable") == -1)
50*e5dd7070Spatrick        continue;
51*e5dd7070Spatrick
52*e5dd7070Spatrick      if (expandableDiv.offsetHeight <= CLIP_HEIGHT)
53*e5dd7070Spatrick        continue;
54*e5dd7070Spatrick
55*e5dd7070Spatrick      // We found a div wrapping a cell content whose height exceeds
56*e5dd7070Spatrick      // CLIP_HEIGHT.
57*e5dd7070Spatrick      var originalHeight = expandableDiv.offsetHeight;
58*e5dd7070Spatrick      // Unique postfix for ids for generated nodes for a given cell.
59*e5dd7070Spatrick      var idxStr = "_" + groupCount + "_" + cellCount;
60*e5dd7070Spatrick      // Create an expander and an additional wrapper for a cell content.
61*e5dd7070Spatrick      //
62*e5dd7070Spatrick      //                                --- expandableDiv ----
63*e5dd7070Spatrick      //  --- expandableDiv ---         | ------ data ------ |
64*e5dd7070Spatrick      //  |    cell content   |   ->    | |  cell content  | |
65*e5dd7070Spatrick      //  ---------------------         | ------------------ |
66*e5dd7070Spatrick      //                                | ---- expander ---- |
67*e5dd7070Spatrick      //                                ----------------------
68*e5dd7070Spatrick      var data = document.createElement("div");
69*e5dd7070Spatrick      data.className = "data";
70*e5dd7070Spatrick      data.id = "data" + idxStr;
71*e5dd7070Spatrick      data.innerHTML = expandableDiv.innerHTML;
72*e5dd7070Spatrick      with (data.style) { height = (CLIP_HEIGHT - EXPANDER_HEIGHT) + "px";
73*e5dd7070Spatrick                          overflow = "hidden" }
74*e5dd7070Spatrick
75*e5dd7070Spatrick      var expander = document.createElement("img");
76*e5dd7070Spatrick      with (expander.style) { display = "block"; paddingTop = "5px"; }
77*e5dd7070Spatrick      expander.src = imgPath + "ellipses_light.gif";
78*e5dd7070Spatrick      expander.id = "expander" + idxStr;
79*e5dd7070Spatrick
80*e5dd7070Spatrick      // Add mouse calbacks to expander.
81*e5dd7070Spatrick      expander.onclick = function() {
82*e5dd7070Spatrick        expandCollapse(this.id);
83*e5dd7070Spatrick        // Hack for Opera - onmouseout callback is not invoked when page
84*e5dd7070Spatrick        // content changes dynamically and mouse pointer goes out of an element.
85*e5dd7070Spatrick        this.src = imgPath +
86*e5dd7070Spatrick                   (getCellInfo(this.id).expanded ? "arrows_light.gif"
87*e5dd7070Spatrick                                                  : "ellipses_light.gif");
88*e5dd7070Spatrick      }
89*e5dd7070Spatrick      expander.onmouseover = function() {
90*e5dd7070Spatrick        this.src = imgPath +
91*e5dd7070Spatrick                   (getCellInfo(this.id).expanded ? "arrows_dark.gif"
92*e5dd7070Spatrick                                                  : "ellipses_dark.gif");
93*e5dd7070Spatrick      }
94*e5dd7070Spatrick      expander.onmouseout = function() {
95*e5dd7070Spatrick        this.src = imgPath +
96*e5dd7070Spatrick                   (getCellInfo(this.id).expanded ? "arrows_light.gif"
97*e5dd7070Spatrick                                                  : "ellipses_light.gif");
98*e5dd7070Spatrick      }
99*e5dd7070Spatrick
100*e5dd7070Spatrick      expandableDiv.innerHTML = "";
101*e5dd7070Spatrick      expandableDiv.appendChild(data);
102*e5dd7070Spatrick      expandableDiv.appendChild(expander);
103*e5dd7070Spatrick      expandableDiv.style.height = CLIP_HEIGHT + "px";
104*e5dd7070Spatrick      expandableDiv.id = "cell"+ idxStr;
105*e5dd7070Spatrick
106*e5dd7070Spatrick      // Keep original cell height and its ecpanded/cpllapsed state.
107*e5dd7070Spatrick      if (!newGroupCreated) {
108*e5dd7070Spatrick        CellsInfo[groupCount] = [];
109*e5dd7070Spatrick        newGroupCreated = true;
110*e5dd7070Spatrick      }
111*e5dd7070Spatrick      CellsInfo[groupCount][cellCount] = { 'height' : originalHeight,
112*e5dd7070Spatrick                                           'expanded' : false };
113*e5dd7070Spatrick      cellCount += 1;
114*e5dd7070Spatrick    }
115*e5dd7070Spatrick    groupCount += newGroupCreated ? 1 : 0;
116*e5dd7070Spatrick  }
117*e5dd7070Spatrick}
118*e5dd7070Spatrick
119*e5dd7070Spatrickfunction isElemTopVisible(elem) {
120*e5dd7070Spatrick  var body = document.body,
121*e5dd7070Spatrick      html = document.documentElement,
122*e5dd7070Spatrick      // Calculate expandableDiv absolute Y coordinate from the top of body.
123*e5dd7070Spatrick      bodyRect = body.getBoundingClientRect(),
124*e5dd7070Spatrick      elemRect = elem.getBoundingClientRect(),
125*e5dd7070Spatrick      elemOffset = Math.floor(elemRect.top - bodyRect.top),
126*e5dd7070Spatrick      // Calculate the absoute Y coordinate of visible area.
127*e5dd7070Spatrick      scrollTop = html.scrollTop || body && body.scrollTop || 0;
128*e5dd7070Spatrick  scrollTop -= html.clientTop; // IE<8
129*e5dd7070Spatrick
130*e5dd7070Spatrick
131*e5dd7070Spatrick  if (elemOffset < scrollTop)
132*e5dd7070Spatrick    return false;
133*e5dd7070Spatrick
134*e5dd7070Spatrick  return true;
135*e5dd7070Spatrick}
136*e5dd7070Spatrick
137*e5dd7070Spatrick// Invoked when an expander is pressed; expand/collapse a cell.
138*e5dd7070Spatrickfunction expandCollapse(id) {
139*e5dd7070Spatrick  var cellInfo = getCellInfo(id);
140*e5dd7070Spatrick  var idx = getCellIdx(id);
141*e5dd7070Spatrick
142*e5dd7070Spatrick  // New height of a row.
143*e5dd7070Spatrick  var newHeight;
144*e5dd7070Spatrick  // Smart page scrolling may be done after collapse.
145*e5dd7070Spatrick  var mayNeedScroll;
146*e5dd7070Spatrick
147*e5dd7070Spatrick  if (cellInfo.expanded) {
148*e5dd7070Spatrick    // Cell is expanded - collapse the row height to CLIP_HEIGHT.
149*e5dd7070Spatrick    newHeight = CLIP_HEIGHT;
150*e5dd7070Spatrick    mayNeedScroll = true;
151*e5dd7070Spatrick  }
152*e5dd7070Spatrick  else {
153*e5dd7070Spatrick    // Cell is collapsed - expand the row height to the cells original height.
154*e5dd7070Spatrick    newHeight = cellInfo.height;
155*e5dd7070Spatrick    mayNeedScroll = false;
156*e5dd7070Spatrick  }
157*e5dd7070Spatrick
158*e5dd7070Spatrick  // Update all cells (height and expanded/collapsed state) in a row according
159*e5dd7070Spatrick  // to the new height of the row.
160*e5dd7070Spatrick  for (var i = 0; i < CellsInfo[idx.group].length; i++) {
161*e5dd7070Spatrick    var idxStr = "_" + idx.group + "_" + i;
162*e5dd7070Spatrick    var expandableDiv = document.getElementById("cell" + idxStr);
163*e5dd7070Spatrick    expandableDiv.style.height = newHeight + "px";
164*e5dd7070Spatrick    var data = document.getElementById("data" + idxStr);
165*e5dd7070Spatrick    var expander = document.getElementById("expander" + idxStr);
166*e5dd7070Spatrick    var state = CellsInfo[idx.group][i];
167*e5dd7070Spatrick
168*e5dd7070Spatrick    if (state.height > newHeight) {
169*e5dd7070Spatrick      // Cell height exceeds row height - collapse a cell.
170*e5dd7070Spatrick      data.style.height = (newHeight - EXPANDER_HEIGHT) + "px";
171*e5dd7070Spatrick      expander.src = imgPath + "ellipses_light.gif";
172*e5dd7070Spatrick      CellsInfo[idx.group][i].expanded = false;
173*e5dd7070Spatrick    } else {
174*e5dd7070Spatrick      // Cell height is less then or equal to row height - expand a cell.
175*e5dd7070Spatrick      data.style.height = "";
176*e5dd7070Spatrick      expander.src = imgPath + "arrows_light.gif";
177*e5dd7070Spatrick      CellsInfo[idx.group][i].expanded = true;
178*e5dd7070Spatrick    }
179*e5dd7070Spatrick  }
180*e5dd7070Spatrick
181*e5dd7070Spatrick  if (mayNeedScroll) {
182*e5dd7070Spatrick    var idxStr = "_" + idx.group + "_" + idx.cell;
183*e5dd7070Spatrick    var clickedExpandableDiv = document.getElementById("cell" + idxStr);
184*e5dd7070Spatrick    // Scroll page up if a row is collapsed and the rows top is above the
185*e5dd7070Spatrick    // viewport. The amount of scroll is the difference between a new and old
186*e5dd7070Spatrick    // row height.
187*e5dd7070Spatrick    if (!isElemTopVisible(clickedExpandableDiv)) {
188*e5dd7070Spatrick      window.scrollBy(0, newHeight - cellInfo.height);
189*e5dd7070Spatrick    }
190*e5dd7070Spatrick  }
191*e5dd7070Spatrick}
192