| 1 |
// |
| 2 |
// Resizable Table Columns. |
| 3 |
// version: 1.0 |
| 4 |
// |
| 5 |
// (c) 2006, bz |
| 6 |
// |
| 7 |
// 25.12.2006: first working prototype |
| 8 |
// 26.12.2006: now works in IE as well but not in Opera (Opera is @#$%!) |
| 9 |
// 27.12.2006: changed initialization, now just make class='resizable' in table and load script |
| 10 |
// |
| 11 |
function preventEvent(e) { |
| 12 |
var ev = e || window.event; |
| 13 |
if (ev.preventDefault) ev.preventDefault(); |
| 14 |
else ev.returnValue = false; |
| 15 |
if (ev.stopPropagation) |
| 16 |
ev.stopPropagation(); |
| 17 |
return false; |
| 18 |
} |
| 19 |
|
| 20 |
function getStyle(x, styleProp) { |
| 21 |
if (x.currentStyle) |
| 22 |
var y = x.currentStyle[styleProp]; |
| 23 |
else if (window.getComputedStyle) |
| 24 |
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp); |
| 25 |
return y; |
| 26 |
} |
| 27 |
|
| 28 |
function getWidth(x) { |
| 29 |
if (x.currentStyle) |
| 30 |
// in IE |
| 31 |
var y = x.clientWidth - parseInt(x.currentStyle["paddingLeft"]) - parseInt(x.currentStyle["paddingRight"]); |
| 32 |
// for IE5: var y = x.offsetWidth; |
| 33 |
else if (window.getComputedStyle) |
| 34 |
// in Gecko |
| 35 |
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue("width"); |
| 36 |
return y || 0; |
| 37 |
} |
| 38 |
|
| 39 |
function setCookie (name, value, expires, path, domain, secure) { |
| 40 |
document.cookie = name + "=" + escape(value) + |
| 41 |
((expires) ? "; expires=" + expires : "") + |
| 42 |
((path) ? "; path=" + path : "") + |
| 43 |
((domain) ? "; domain=" + domain : "") + |
| 44 |
((secure) ? "; secure" : ""); |
| 45 |
} |
| 46 |
|
| 47 |
function getCookie(name) { |
| 48 |
var cookie = " " + document.cookie; |
| 49 |
var search = " " + name + "="; |
| 50 |
var setStr = null; |
| 51 |
var offset = 0; |
| 52 |
var end = 0; |
| 53 |
if (cookie.length > 0) { |
| 54 |
offset = cookie.indexOf(search); |
| 55 |
if (offset != -1) { |
| 56 |
offset += search.length; |
| 57 |
end = cookie.indexOf(";", offset) |
| 58 |
if (end == -1) { |
| 59 |
end = cookie.length; |
| 60 |
} |
| 61 |
setStr = unescape(cookie.substring(offset, end)); |
| 62 |
} |
| 63 |
} |
| 64 |
return(setStr); |
| 65 |
} |
| 66 |
// main class prototype |
| 67 |
function ColumnResize(row) { |
| 68 |
if (row.tagName != 'TR') return; |
| 69 |
|
| 70 |
this.id = row.id; |
| 71 |
|
| 72 |
// ============================================================ |
| 73 |
// private data |
| 74 |
var self = this; |
| 75 |
|
| 76 |
var dragColumns = row.cells; // first row columns, used for changing of width |
| 77 |
if (!dragColumns) return; // return if no table exists or no one row exists |
| 78 |
|
| 79 |
var dragColumnNo; // current dragging column |
| 80 |
var dragX; // last event X mouse coordinate |
| 81 |
|
| 82 |
var saveOnmouseup; // save document onmouseup event handler |
| 83 |
var saveOnmousemove; // save document onmousemove event handler |
| 84 |
var saveBodyCursor; // save body cursor property |
| 85 |
|
| 86 |
var setupFlags = new Array(dragColumns.length); |
| 87 |
|
| 88 |
// ============================================================ |
| 89 |
// methods |
| 90 |
|
| 91 |
// ============================================================ |
| 92 |
// do changes columns widths |
| 93 |
// returns true if success and false otherwise |
| 94 |
this.changeColumnWidth = function(no, w) { |
| 95 |
if (!dragColumns) return false; |
| 96 |
|
| 97 |
if (no < 0) return false; |
| 98 |
if (dragColumns.length < no) return false; |
| 99 |
|
| 100 |
if (parseInt(dragColumns[no].style.width) <= -w) return false; |
| 101 |
if (dragColumns[no+1] && parseInt(dragColumns[no+1].style.width) <= w) return false; |
| 102 |
|
| 103 |
dragColumns[no].style.width = parseInt(dragColumns[no].style.width) + w +'px'; |
| 104 |
// if (dragColumns[no+1]) |
| 105 |
// dragColumns[no+1].style.width = parseInt(dragColumns[no+1].style.width) - w + 'px'; |
| 106 |
|
| 107 |
return true; |
| 108 |
} |
| 109 |
|
| 110 |
// ============================================================ |
| 111 |
// do drag column width |
| 112 |
this.columnDrag = function(e) { |
| 113 |
|
| 114 |
if (!setupFlags[dragColumnNo]) { |
| 115 |
setupFlags[dragColumnNo] = true; |
| 116 |
self.setup(dragColumnNo); |
| 117 |
} |
| 118 |
|
| 119 |
var e = e || window.event; |
| 120 |
var X = e.clientX || e.pageX; |
| 121 |
if (!self.changeColumnWidth(dragColumnNo, X-dragX)) { |
| 122 |
// stop drag! |
| 123 |
self.stopColumnDrag(e); |
| 124 |
} |
| 125 |
|
| 126 |
dragX = X; |
| 127 |
// prevent other event handling |
| 128 |
preventEvent(e); |
| 129 |
return false; |
| 130 |
} |
| 131 |
|
| 132 |
// ============================================================ |
| 133 |
// stops column dragging |
| 134 |
this.stopColumnDrag = function(e) { |
| 135 |
var e = e || window.event; |
| 136 |
if (!dragColumns) return; |
| 137 |
|
| 138 |
// restore handlers & cursor |
| 139 |
document.onmouseup = saveOnmouseup; |
| 140 |
document.onmousemove = saveOnmousemove; |
| 141 |
document.body.style.cursor = saveBodyCursor; |
| 142 |
|
| 143 |
// remember columns widths in cookies for server side |
| 144 |
var colWidth = ''; |
| 145 |
var separator = ''; |
| 146 |
for (var i=0; i<dragColumns.length; i++) { |
| 147 |
colWidth += separator + parseInt( getWidth(dragColumns[i]) ); |
| 148 |
separator = '+'; |
| 149 |
} |
| 150 |
var expire = new Date(); |
| 151 |
expire.setDate(expire.getDate() + 365); // year |
| 152 |
document.cookie = self.id + '-width=' + colWidth + |
| 153 |
'; expires=' + expire.toGMTString(); |
| 154 |
|
| 155 |
preventEvent(e); |
| 156 |
} |
| 157 |
|
| 158 |
this.setup = function(i) { |
| 159 |
// dragColumns[i].width = ""; // for sure |
| 160 |
dragColumns[i].style.width = parseInt( getWidth(dragColumns[i]) ) + "px"; |
| 161 |
|
| 162 |
/* |
| 163 |
// set up current columns widths in their particular attributes |
| 164 |
// do it in two steps to avoid jumps on page! |
| 165 |
var colWidth = new Array(); |
| 166 |
for (var i=0; i<dragColumns.length; i++) |
| 167 |
colWidth[i] = parseInt( getWidth(dragColumns[i]) ); |
| 168 |
for (var i=0; i<dragColumns.length; i++) { |
| 169 |
dragColumns[i].width = ""; // for sure |
| 170 |
dragColumns[i].style.width = colWidth[i] + "px"; |
| 171 |
} |
| 172 |
*/ |
| 173 |
} |
| 174 |
|
| 175 |
// ============================================================ |
| 176 |
// init data and start dragging |
| 177 |
this.startColumnDrag = function(e) { |
| 178 |
var e = e || window.event; |
| 179 |
|
| 180 |
// if not first button was clicked |
| 181 |
//if (e.button != 0) return; |
| 182 |
|
| 183 |
// remember dragging object |
| 184 |
dragColumnNo = (e.target || e.srcElement).parentNode.parentNode.cellIndex; |
| 185 |
dragX = e.clientX || e.pageX; |
| 186 |
|
| 187 |
saveOnmouseup = document.onmouseup; |
| 188 |
document.onmouseup = self.stopColumnDrag; |
| 189 |
|
| 190 |
saveBodyCursor = document.body.style.cursor; |
| 191 |
document.body.style.cursor = 'col-resize'; //'w-resize'; |
| 192 |
|
| 193 |
// fire! |
| 194 |
saveOnmousemove = document.onmousemove; |
| 195 |
document.onmousemove = self.columnDrag; |
| 196 |
|
| 197 |
preventEvent(e); |
| 198 |
} |
| 199 |
|
| 200 |
var wasActive = (document.activeElement != null); |
| 201 |
var activeElemID = wasActive ? document.activeElement.id : ""; |
| 202 |
var activeElemName = wasActive ? document.activeElement.name : ""; |
| 203 |
|
| 204 |
// prepare table header to be draggable |
| 205 |
// it runs during class creation |
| 206 |
for (var i=0; i<dragColumns.length; i++) { |
| 207 |
dragColumns[i].innerHTML = "<div style='position:relative;width:100%;'>"+ |
| 208 |
"<div style='"+ |
| 209 |
"background-color:transparent/*#aaa*/;position:absolute;height:100%;width:5px;margin-right:-5px;"+ |
| 210 |
"left:100%;top:0px;cursor:col-resize/*w-resize*/;z-index:10;'>"+ |
| 211 |
"</div><div>"+ |
| 212 |
dragColumns[i].innerHTML+ |
| 213 |
"</div></div>"; |
| 214 |
// BUGBUG: calculate real border width instead of 5px!!! |
| 215 |
dragColumns[i].firstChild.firstChild.onmousedown = this.startColumnDrag; |
| 216 |
} |
| 217 |
|
| 218 |
if (wasActive && ((activeElemID&&activeElemID.length) || (activeElemName&&activeElemName.length))) { |
| 219 |
var activeEl = activeElemID ? $(activeElemID) : document.getElementsByName(activeElemName)[0]; |
| 220 |
if (activeEl) { |
| 221 |
activeEl.focus(); |
| 222 |
activeEl.select(); |
| 223 |
} |
| 224 |
} |
| 225 |
} |
| 226 |
|
| 227 |
// select all rows and make resizable those that have 'resizable' class |
| 228 |
var resizableRows = new Array(); |
| 229 |
|
| 230 |
function ResizableColumns() { |
| 231 |
resizableRows.clear(); |
| 232 |
var rows = document.getElementsByTagName('tr'); |
| 233 |
for (var i=0; i<rows.length; i++) { |
| 234 |
if (rows[i].className.match(/resizable/)) { |
| 235 |
// generate id |
| 236 |
if (!rows[i].id) rows[i].id = 'tr'+(i+1); |
| 237 |
// make rows resizable |
| 238 |
resizableRows[resizableRows.length] = new ColumnResize(rows[i]); |
| 239 |
} |
| 240 |
} |
| 241 |
} |
| 242 |
|
| 243 |
// execute earlier to avoid overriding other startup modifiers since this replaces HTML and kill previously-attached event listeners. |
| 244 |
document.observe('dom:loaded', ResizableColumns); |
| 245 |
|