1 |
2 |
- |
/****************************************************************
|
2 |
|
|
* jquery.tableHelper.js *
|
3 |
|
|
* *
|
4 |
|
|
* by: Dan VerWeire *
|
5 |
|
|
|
6 |
|
|
* *
|
7 |
|
|
* sponsored by: Pavilion Gift Company *
|
8 |
|
|
* www.paviliongift.com *
|
9 |
|
|
* *
|
10 |
|
|
* This library is free software; you can redistribute *
|
11 |
|
|
* it and/or modify it under the terms of the GNU *
|
12 |
|
|
* Lesser General Public License as published by the *
|
13 |
|
|
* Free Software Foundation; either version 2.1 of the *
|
14 |
|
|
* License, or (at your option) any later version. *
|
15 |
|
|
* *
|
16 |
|
|
* This library is distributed in the hope that it will *
|
17 |
|
|
* be useful, but WITHOUT ANY WARRANTY; without even the *
|
18 |
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A *
|
19 |
|
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public *
|
20 |
|
|
* License for more details. *
|
21 |
|
|
* *
|
22 |
|
|
* You should have received a copy of the GNU Lesser *
|
23 |
|
|
* General Public License along with this library; *
|
24 |
|
|
* Inc., 59 Temple Place, Suite 330, Boston, *
|
25 |
|
|
* MA 02111-1307 USA *
|
26 |
|
|
****************************************************************/
|
27 |
|
|
|
28 |
|
|
(function () {
|
29 |
|
|
var alphaColLookup = {}
|
30 |
|
|
var colIndex = 0;
|
31 |
|
|
|
32 |
|
|
for (var x = 97; x <= 122; x++) {
|
33 |
|
|
alphaColLookup[String.fromCharCode(x)] = colIndex++;
|
34 |
|
|
}
|
35 |
|
|
|
36 |
|
|
for (var x = 97; x <= 122; x++) {
|
37 |
|
|
for (var y = 97; y <= 122; y++) {
|
38 |
|
|
alphaColLookup[String.fromCharCode(x) + String.fromCharCode(y)] = colIndex++;
|
39 |
|
|
}
|
40 |
|
|
}
|
41 |
|
|
|
42 |
|
|
//helper function to quickly determine if an element is a table
|
43 |
|
|
isTable = function (el) {
|
44 |
|
|
return (el.nodeName == 'TABLE') ? true : false;
|
45 |
|
|
}
|
46 |
|
|
|
47 |
|
|
//helper function to quickly determine if an element is a tbody
|
48 |
|
|
isTbody = function (el) {
|
49 |
|
|
return (el.nodeName == 'TBODY') ? true : false;
|
50 |
|
|
}
|
51 |
|
|
|
52 |
|
|
//helper function to quickly determine if an element is a tfoot
|
53 |
|
|
isTfoot = function (el) {
|
54 |
|
|
return (el.nodeName == 'TFOOT') ? true : false;
|
55 |
|
|
}
|
56 |
|
|
|
57 |
|
|
//helper function to quickly determine if an element is a thead
|
58 |
|
|
isThead = function (el) {
|
59 |
|
|
return (el.nodeName == 'THEAD') ? true : false;
|
60 |
|
|
}
|
61 |
|
|
|
62 |
|
|
//helper function to quickly determine if an element is a table cell
|
63 |
|
|
isCell = function (el) {
|
64 |
|
|
return (el.nodeName == 'TD') ? true : false;
|
65 |
|
|
}
|
66 |
|
|
|
67 |
|
|
//helper function to quickly determine if an element is a table row
|
68 |
|
|
isRow = function (el) {
|
69 |
|
|
return (el.nodeName == 'TR') ? true : false;
|
70 |
|
|
}
|
71 |
|
|
|
72 |
|
|
getTable = function (el,jq) {
|
73 |
|
|
var tbl;
|
74 |
|
|
|
75 |
|
|
if (isTable(el) || isThead(el) || isTbody(el) || isTfoot(el)) {
|
76 |
|
|
jq = jq.not(el);
|
77 |
|
|
tbl = el;
|
78 |
|
|
}
|
79 |
|
|
else if (isCell(el)) {
|
80 |
|
|
tbl = el.parentNode.parentNode;
|
81 |
|
|
}
|
82 |
|
|
else if (isRow(el)) {
|
83 |
|
|
tbl = el.parentNode;
|
84 |
|
|
}
|
85 |
|
|
|
86 |
|
|
return { table : tbl, jq : jq }
|
87 |
|
|
}
|
88 |
|
|
|
89 |
|
|
getVirtTable = function (tbl) {
|
90 |
|
|
//tables which contain cells that have a rowSpan or cellSpan make the indices not friendly for
|
91 |
|
|
//any type of coordinate system. What this section does is loop through the actual table, building
|
92 |
|
|
//a map of that table where a 'merged cell' has a reference at every coordinate which it takes up.
|
93 |
|
|
//i tried other methods, but this is the one that ended up working. not sure if this is the most efficient.
|
94 |
|
|
//
|
95 |
|
|
//this method helps with including merged cells in an overlapping range
|
96 |
|
|
|
97 |
|
|
var virtTable = {};
|
98 |
|
|
|
99 |
|
|
if (tbl.rowLength) {
|
100 |
|
|
rowLength = tbl.rowLength+1;
|
101 |
|
|
}
|
102 |
|
|
else {
|
103 |
|
|
rowLength = tbl.rows.length
|
104 |
|
|
}
|
105 |
|
|
|
106 |
|
|
if (tbl.cellLength) {
|
107 |
|
|
colLength = tbl.cellLength+1;
|
108 |
|
|
}
|
109 |
|
|
else {
|
110 |
|
|
colLength = tbl.rows[0].cells.length;
|
111 |
|
|
}
|
112 |
|
|
|
113 |
|
|
for (var y = 0; y < rowLength; y++) {
|
114 |
|
|
var row = tbl.rows[y];
|
115 |
|
|
for (var x = 0; x < colLength; x++) {
|
116 |
|
|
var cell = row.cells[x];
|
117 |
|
|
|
118 |
|
|
if (cell) {
|
119 |
|
|
//this loop is for setting the references of a cell that might have a rowSpan or cellSpan
|
120 |
|
|
for (var a = 0; a < cell.rowSpan; a++) {
|
121 |
|
|
for (var b = 0; b < cell.colSpan; b++) {
|
122 |
|
|
if (!virtTable[y + a]) virtTable[y + a] = {};
|
123 |
|
|
|
124 |
|
|
if (!virtTable[y + a][x + b]) {
|
125 |
|
|
virtTable[y + a][x + b] = cell;
|
126 |
|
|
cell.x = x + b;
|
127 |
|
|
cell.y = y + a;
|
128 |
|
|
}
|
129 |
|
|
else {
|
130 |
|
|
var c = 0;
|
131 |
|
|
while (virtTable[y + a][x + b + c]) {
|
132 |
|
|
c++;
|
133 |
|
|
}
|
134 |
|
|
virtTable[y + a][x + b + c] = cell;
|
135 |
|
|
cell.x = x + b + c;
|
136 |
|
|
cell.y = y + a;
|
137 |
|
|
}
|
138 |
|
|
}
|
139 |
|
|
}
|
140 |
|
|
}
|
141 |
|
|
}
|
142 |
|
|
}
|
143 |
|
|
|
144 |
|
|
return virtTable;
|
145 |
|
|
}
|
146 |
|
|
|
147 |
|
|
//add the cell method to the jQuery object
|
148 |
|
|
//this method adds the cell at row,col in any tables in the current
|
149 |
|
|
//selection to the selection
|
150 |
|
|
//
|
151 |
|
|
//it will remove the table from the selection
|
152 |
|
|
jQuery.fn.cell = function (col,row) {
|
153 |
|
|
var jq = this;
|
154 |
|
|
|
155 |
|
|
this.each(function(i,el) {
|
156 |
|
|
var obj = getTable(this,jq);
|
157 |
|
|
jq = obj.jq;
|
158 |
|
|
tbl = obj.table;
|
159 |
|
|
|
160 |
|
|
var virtTable = getVirtTable(tbl);
|
161 |
|
|
|
162 |
|
|
if (virtTable && virtTable[row] && virtTable[row][col]) {
|
163 |
|
|
var cell = virtTable[row][col];
|
164 |
|
|
jq = jq.add(cell);
|
165 |
|
|
}
|
166 |
|
|
});
|
167 |
|
|
|
168 |
|
|
return jq;
|
169 |
|
|
};
|
170 |
|
|
|
171 |
|
|
jQuery.fn.row = function (row) {
|
172 |
|
|
var jq = this;
|
173 |
|
|
|
174 |
|
|
jq.each(function (i,el) {
|
175 |
|
|
var obj = getTable(this,jq);
|
176 |
|
|
jq = obj.jq;
|
177 |
|
|
tbl = obj.table;
|
178 |
|
|
|
179 |
|
|
var tmp = Array();
|
180 |
|
|
var rw = tbl.rows.item(row);
|
181 |
|
|
|
182 |
|
|
if (rw) {
|
183 |
|
|
for (var x = 0; x < rw.cells.length; x++) {
|
184 |
|
|
var cell = rw.cells.item(x);
|
185 |
|
|
tmp.push(cell);
|
186 |
|
|
}
|
187 |
|
|
|
188 |
|
|
jq = jq.add(tmp);
|
189 |
|
|
}
|
190 |
|
|
});
|
191 |
|
|
|
192 |
|
|
return jq;
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
jQuery.fn.alternate = function(start, interval) {
|
196 |
|
|
var jq = this;
|
197 |
|
|
|
198 |
|
|
jq.each(function (i,el) {
|
199 |
|
|
var obj = getTable(this,jq);
|
200 |
|
|
jq = obj.jq;
|
201 |
|
|
tbl = obj.table;
|
202 |
|
|
|
203 |
|
|
var tmp = Array();
|
204 |
|
|
|
205 |
|
|
for (var x = start; x < tbl.rows.length; x += interval) {
|
206 |
|
|
var rw = tbl.rows.item(x);
|
207 |
|
|
|
208 |
|
|
for (var y = 0; y < rw.cells.length; y++) {
|
209 |
|
|
var cell = rw.cells.item(y);
|
210 |
|
|
tmp.push(cell);
|
211 |
|
|
}
|
212 |
|
|
}
|
213 |
|
|
|
214 |
|
|
jq = jq.add(tmp);
|
215 |
|
|
});
|
216 |
|
|
|
217 |
|
|
return jq;
|
218 |
|
|
}
|
219 |
|
|
|
220 |
|
|
jQuery.fn.even = function () {
|
221 |
|
|
return this.alternate(0,2);
|
222 |
|
|
}
|
223 |
|
|
|
224 |
|
|
jQuery.fn.odd = function () {
|
225 |
|
|
return this.alternate(1,2);
|
226 |
|
|
}
|
227 |
|
|
|
228 |
|
|
jQuery.fn.all = function () {
|
229 |
|
|
return this.alternate(0,1);
|
230 |
|
|
}
|
231 |
|
|
|
232 |
|
|
|
233 |
|
|
jQuery.fn.col = function (col) {
|
234 |
|
|
var jq = this;
|
235 |
|
|
|
236 |
|
|
jq.each(function (i,el) {
|
237 |
|
|
var obj = getTable(this,jq);
|
238 |
|
|
jq = obj.jq;
|
239 |
|
|
tbl = obj.table;
|
240 |
|
|
|
241 |
|
|
var tmp = Array();
|
242 |
|
|
|
243 |
|
|
for (var y = 0; y < tbl.rows.length; y++) {
|
244 |
|
|
var cell = tbl.rows.item(y).cells.item(col)
|
245 |
|
|
tmp.push(cell);
|
246 |
|
|
}
|
247 |
|
|
|
248 |
|
|
jq = jq.add(tmp);
|
249 |
|
|
});
|
250 |
|
|
|
251 |
|
|
return jq;
|
252 |
|
|
}
|
253 |
|
|
|
254 |
|
|
jQuery.fn.tableEnd = function () {
|
255 |
|
|
var jq = this;
|
256 |
|
|
|
257 |
|
|
while (jq.length > 0 ) {
|
258 |
|
|
// jq.each(function (i, el) {
|
259 |
|
|
jq = jq.end();
|
260 |
|
|
// });
|
261 |
|
|
}
|
262 |
|
|
jq = jq.end();
|
263 |
|
|
|
264 |
|
|
return jq;
|
265 |
|
|
}
|
266 |
|
|
|
267 |
|
|
//resize the table, only grows the table at the moment
|
268 |
|
|
jQuery.fn.resize = function (cols,rows) {
|
269 |
|
|
var jq = this;
|
270 |
|
|
//fix off by one issue
|
271 |
|
|
cols--;
|
272 |
|
|
rows--;
|
273 |
|
|
result = this.each(function(i,el) {
|
274 |
|
|
this.cellLength = cols;
|
275 |
|
|
this.rowLength = rows;
|
276 |
|
|
|
277 |
|
|
for (var y = this.rows.length; y < rows + 1; y++) {
|
278 |
|
|
var rw = this.insertRow(-1);
|
279 |
|
|
}
|
280 |
|
|
|
281 |
|
|
//now for each row, check all the cells
|
282 |
|
|
for (var y = 0; y < this.rows.length; y++) {
|
283 |
|
|
var rw = this.rows.item(y);
|
284 |
|
|
|
285 |
|
|
for (var x = rw.cells.length; x < cols + 1; x ++) {
|
286 |
|
|
var td = rw.insertCell(-1);
|
287 |
|
|
}
|
288 |
|
|
}
|
289 |
|
|
});
|
290 |
|
|
|
291 |
|
|
return jq;
|
292 |
|
|
}
|
293 |
|
|
|
294 |
|
|
jQuery.fn.range = function (stRange) { //yes i called this stRange for fun reasons.
|
295 |
|
|
var jq = this;
|
296 |
|
|
|
297 |
|
|
if (stRange.indexOf(':') >= 0) {
|
298 |
|
|
var tokens = stRange.split(':');
|
299 |
|
|
var range = []
|
300 |
|
|
|
301 |
|
|
for (var x = 0; x < tokens.length; x++) {
|
302 |
|
|
var token = tokens[x];
|
303 |
|
|
var col = alphaColLookup[/[a-zA-Z]{1,2}/.exec(token)];
|
304 |
|
|
var row = (/[0-9]{1,}/.exec(token)) - 1;
|
305 |
|
|
|
306 |
|
|
range.push({row : row, col : col});
|
307 |
|
|
}
|
308 |
|
|
|
309 |
|
|
if (range.length == 2) {
|
310 |
|
|
//we have a start coord and a stop coord
|
311 |
|
|
jq.each(function(i,el) {
|
312 |
|
|
var cells = [];
|
313 |
|
|
var obj = getTable(this,jq);
|
314 |
|
|
|
315 |
|
|
jq = obj.jq;
|
316 |
|
|
tbl = obj.table;
|
317 |
|
|
|
318 |
|
|
var virtTable = getVirtTable(tbl);
|
319 |
|
|
|
320 |
|
|
//now grab the cells in the range from the virtual table.
|
321 |
|
|
for (var y = range[0].row ; y <= range[1].row ; y ++) {
|
322 |
|
|
for (var x = range[0].col; x <= range[1].col; x++) {
|
323 |
|
|
try {
|
324 |
|
|
if (virtTable[y][x]) {
|
325 |
|
|
cells.push(virtTable[y][x]);
|
326 |
|
|
}
|
327 |
|
|
}
|
328 |
|
|
catch (e) { alert('.range error: ' + e + ': ' + y + ', ' + x) };
|
329 |
|
|
}
|
330 |
|
|
}
|
331 |
|
|
|
332 |
|
|
//add the cells we collected to the jquery object
|
333 |
|
|
jq = jq.add(cells);
|
334 |
|
|
});
|
335 |
|
|
}
|
336 |
|
|
}
|
337 |
|
|
return jq;
|
338 |
|
|
}
|
339 |
|
|
|
340 |
|
|
jQuery.fn.merge = function (copyContents) {
|
341 |
|
|
var jq = this;
|
342 |
|
|
var contents = '';
|
343 |
|
|
var tl = {}, br = {};
|
344 |
|
|
|
345 |
|
|
var cells = [];
|
346 |
|
|
|
347 |
|
|
jq.each(function (i, el) {
|
348 |
|
|
if (isCell(this)) cells.push(this);
|
349 |
|
|
})
|
350 |
|
|
|
351 |
|
|
//find the top left most cell
|
352 |
|
|
if (cells.length > 0) {
|
353 |
|
|
|
354 |
|
|
var tl = {row : cells[0].y, col : cells[0].x, cell : cells[0]};
|
355 |
|
|
var br = {row : cells[0].y, col : cells[0].x, cell : cells[0]};
|
356 |
|
|
|
357 |
|
|
for (var x = 0; x < cells.length; x ++){
|
358 |
|
|
var cell = cells[x];
|
359 |
|
|
|
360 |
|
|
var row = cell.y;
|
361 |
|
|
var col = cell.x;
|
362 |
|
|
|
363 |
|
|
if (row < tl.row || col < tl.col ) tl = {row : row, col : col, cell : cell};
|
364 |
|
|
if (row > br.row || col > br.col ) br = {row : row, col : col, cell : cell};
|
365 |
|
|
}
|
366 |
|
|
|
367 |
|
|
for (var x = 0; x < cells.length; x ++){
|
368 |
|
|
var cell = cells[x];
|
369 |
|
|
|
370 |
|
|
if (cell != tl.cell) {
|
371 |
|
|
if (copyContents) contents += cell.innerHTML;
|
372 |
|
|
cell.parentNode.removeChild(cell);
|
373 |
|
|
}
|
374 |
|
|
}
|
375 |
|
|
|
376 |
|
|
tl.cell.colSpan = br.col - tl.col + 1;
|
377 |
|
|
tl.cell.rowSpan = br.row - tl.row + 1;
|
378 |
|
|
|
379 |
|
|
if (copyContents) tl.cell.innerHTML += contents;
|
380 |
|
|
}
|
381 |
|
|
|
382 |
|
|
//remove all the td's and then just add back in the topleft cell
|
383 |
|
|
jq = jq.not('td').add(tl.cell);
|
384 |
|
|
|
385 |
|
|
return jq;
|
386 |
|
|
}
|
387 |
|
|
|
388 |
|
|
jQuery.fn.unMerge = function () {
|
389 |
|
|
var jq = this;
|
390 |
|
|
var contents = '';
|
391 |
|
|
|
392 |
|
|
var cells = [];
|
393 |
|
|
|
394 |
|
|
jq.each(function (i, el) {
|
395 |
|
|
var done = false;
|
396 |
|
|
|
397 |
|
|
if (isCell(this)) {
|
398 |
|
|
var tbl = getTable(this).table;
|
399 |
|
|
var virtTable = getVirtTable(tbl);
|
400 |
|
|
|
401 |
|
|
//loop through the virtual table to find the top leftest reference to this merged cell.
|
402 |
|
|
for ( var y in virtTable ) {
|
403 |
|
|
var row = virtTable[y];
|
404 |
|
|
|
405 |
|
|
for (var x in row) {
|
406 |
|
|
var cell = row[x];
|
407 |
|
|
|
408 |
|
|
if (cell == this) {
|
409 |
|
|
rowSpan = this.rowSpan;
|
410 |
|
|
colSpan = this.colSpan;
|
411 |
|
|
//
|
412 |
|
|
//loop through the size of this cell and insert new cells
|
413 |
|
|
for ( var a = 0; a < rowSpan; a++ ) {
|
414 |
|
|
for ( var b = 0 ; b < colSpan; b++ ) {
|
415 |
|
|
//alert(parseInt(x) + colSpan);
|
416 |
|
|
//alert((parseInt(y) + a) + ' ' + y + ' ' + a)// + virtTable[String(y + a)][x])
|
417 |
|
|
var cell = jQuery('<td />').insertBefore(virtTable[(parseInt(y) + a)][parseInt(x) + colSpan]).get(0)
|
418 |
|
|
cells.push(cell);
|
419 |
|
|
}
|
420 |
|
|
}
|
421 |
|
|
$(this).remove();
|
422 |
|
|
done = true;
|
423 |
|
|
break;
|
424 |
|
|
}
|
425 |
|
|
}
|
426 |
|
|
if (done) break;
|
427 |
|
|
}
|
428 |
|
|
}
|
429 |
|
|
})
|
430 |
|
|
return jq.add(cells);
|
431 |
|
|
}
|
432 |
|
|
|
433 |
|
|
})();
|