You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
6.8 KiB
192 lines
6.8 KiB
// expand/collapse button (expander) is added if height of a cell content
|
|
// exceeds CLIP_HEIGHT px.
|
|
var CLIP_HEIGHT = 135;
|
|
|
|
// Height in pixels of an expander image.
|
|
var EXPANDER_HEIGHT = 13;
|
|
|
|
// Path to images for an expander.
|
|
var imgPath = "./images/expandcollapse/";
|
|
|
|
// array[group][cell] of { 'height', 'expanded' }.
|
|
// group: a number; cells of the same group belong to the same table row.
|
|
// cell: a number; unique index of a cell in a group.
|
|
// height: a number, px; original height of a cell in a table.
|
|
// expanded: boolean; is a cell expanded or collapsed?
|
|
var CellsInfo = [];
|
|
|
|
// Extracts group and cell indices from an id of the form identifier_group_cell.
|
|
function getCellIdx(id) {
|
|
var idx = id.substr(id.indexOf("_") + 1).split("_");
|
|
return { 'group': idx[0], 'cell': idx[1] };
|
|
}
|
|
|
|
// Returns { 'height', 'expanded' } info for a cell with a given id.
|
|
function getCellInfo(id) {
|
|
var idx = getCellIdx(id);
|
|
return CellsInfo[idx.group][idx.cell];
|
|
}
|
|
|
|
// Initialization, add nodes, collect info.
|
|
function initExpandCollapse() {
|
|
if (!document.getElementById)
|
|
return;
|
|
|
|
var groupCount = 0;
|
|
|
|
// Examine all table rows in the document.
|
|
var rows = document.body.getElementsByTagName("tr");
|
|
for (var i=0; i<rows.length; i+=1) {
|
|
|
|
var cellCount=0, newGroupCreated = false;
|
|
|
|
// Examine all divs in a table row.
|
|
var divs = rows[i].getElementsByTagName("div");
|
|
for (var j=0; j<divs.length; j+=1) {
|
|
|
|
var expandableDiv = divs[j];
|
|
|
|
if (expandableDiv.className.indexOf("expandable") == -1)
|
|
continue;
|
|
|
|
if (expandableDiv.offsetHeight <= CLIP_HEIGHT)
|
|
continue;
|
|
|
|
// We found a div wrapping a cell content whose height exceeds
|
|
// CLIP_HEIGHT.
|
|
var originalHeight = expandableDiv.offsetHeight;
|
|
// Unique postfix for ids for generated nodes for a given cell.
|
|
var idxStr = "_" + groupCount + "_" + cellCount;
|
|
// Create an expander and an additional wrapper for a cell content.
|
|
//
|
|
// --- expandableDiv ----
|
|
// --- expandableDiv --- | ------ data ------ |
|
|
// | cell content | -> | | cell content | |
|
|
// --------------------- | ------------------ |
|
|
// | ---- expander ---- |
|
|
// ----------------------
|
|
var data = document.createElement("div");
|
|
data.className = "data";
|
|
data.id = "data" + idxStr;
|
|
data.innerHTML = expandableDiv.innerHTML;
|
|
with (data.style) { height = (CLIP_HEIGHT - EXPANDER_HEIGHT) + "px";
|
|
overflow = "hidden" }
|
|
|
|
var expander = document.createElement("img");
|
|
with (expander.style) { display = "block"; paddingTop = "5px"; }
|
|
expander.src = imgPath + "ellipses_light.gif";
|
|
expander.id = "expander" + idxStr;
|
|
|
|
// Add mouse calbacks to expander.
|
|
expander.onclick = function() {
|
|
expandCollapse(this.id);
|
|
// Hack for Opera - onmouseout callback is not invoked when page
|
|
// content changes dynamically and mouse pointer goes out of an element.
|
|
this.src = imgPath +
|
|
(getCellInfo(this.id).expanded ? "arrows_light.gif"
|
|
: "ellipses_light.gif");
|
|
}
|
|
expander.onmouseover = function() {
|
|
this.src = imgPath +
|
|
(getCellInfo(this.id).expanded ? "arrows_dark.gif"
|
|
: "ellipses_dark.gif");
|
|
}
|
|
expander.onmouseout = function() {
|
|
this.src = imgPath +
|
|
(getCellInfo(this.id).expanded ? "arrows_light.gif"
|
|
: "ellipses_light.gif");
|
|
}
|
|
|
|
expandableDiv.innerHTML = "";
|
|
expandableDiv.appendChild(data);
|
|
expandableDiv.appendChild(expander);
|
|
expandableDiv.style.height = CLIP_HEIGHT + "px";
|
|
expandableDiv.id = "cell"+ idxStr;
|
|
|
|
// Keep original cell height and its ecpanded/cpllapsed state.
|
|
if (!newGroupCreated) {
|
|
CellsInfo[groupCount] = [];
|
|
newGroupCreated = true;
|
|
}
|
|
CellsInfo[groupCount][cellCount] = { 'height' : originalHeight,
|
|
'expanded' : false };
|
|
cellCount += 1;
|
|
}
|
|
groupCount += newGroupCreated ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
function isElemTopVisible(elem) {
|
|
var body = document.body,
|
|
html = document.documentElement,
|
|
// Calculate expandableDiv absolute Y coordinate from the top of body.
|
|
bodyRect = body.getBoundingClientRect(),
|
|
elemRect = elem.getBoundingClientRect(),
|
|
elemOffset = Math.floor(elemRect.top - bodyRect.top),
|
|
// Calculate the absoute Y coordinate of visible area.
|
|
scrollTop = html.scrollTop || body && body.scrollTop || 0;
|
|
scrollTop -= html.clientTop; // IE<8
|
|
|
|
|
|
if (elemOffset < scrollTop)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Invoked when an expander is pressed; expand/collapse a cell.
|
|
function expandCollapse(id) {
|
|
var cellInfo = getCellInfo(id);
|
|
var idx = getCellIdx(id);
|
|
|
|
// New height of a row.
|
|
var newHeight;
|
|
// Smart page scrolling may be done after collapse.
|
|
var mayNeedScroll;
|
|
|
|
if (cellInfo.expanded) {
|
|
// Cell is expanded - collapse the row height to CLIP_HEIGHT.
|
|
newHeight = CLIP_HEIGHT;
|
|
mayNeedScroll = true;
|
|
}
|
|
else {
|
|
// Cell is collapsed - expand the row height to the cells original height.
|
|
newHeight = cellInfo.height;
|
|
mayNeedScroll = false;
|
|
}
|
|
|
|
// Update all cells (height and expanded/collapsed state) in a row according
|
|
// to the new height of the row.
|
|
for (var i = 0; i < CellsInfo[idx.group].length; i++) {
|
|
var idxStr = "_" + idx.group + "_" + i;
|
|
var expandableDiv = document.getElementById("cell" + idxStr);
|
|
expandableDiv.style.height = newHeight + "px";
|
|
var data = document.getElementById("data" + idxStr);
|
|
var expander = document.getElementById("expander" + idxStr);
|
|
var state = CellsInfo[idx.group][i];
|
|
|
|
if (state.height > newHeight) {
|
|
// Cell height exceeds row height - collapse a cell.
|
|
data.style.height = (newHeight - EXPANDER_HEIGHT) + "px";
|
|
expander.src = imgPath + "ellipses_light.gif";
|
|
CellsInfo[idx.group][i].expanded = false;
|
|
} else {
|
|
// Cell height is less then or equal to row height - expand a cell.
|
|
data.style.height = "";
|
|
expander.src = imgPath + "arrows_light.gif";
|
|
CellsInfo[idx.group][i].expanded = true;
|
|
}
|
|
}
|
|
|
|
if (mayNeedScroll) {
|
|
var idxStr = "_" + idx.group + "_" + idx.cell;
|
|
var clickedExpandableDiv = document.getElementById("cell" + idxStr);
|
|
// Scroll page up if a row is collapsed and the rows top is above the
|
|
// viewport. The amount of scroll is the difference between a new and old
|
|
// row height.
|
|
if (!isElemTopVisible(clickedExpandableDiv)) {
|
|
window.scrollBy(0, newHeight - cellInfo.height);
|
|
}
|
|
}
|
|
}
|