1 xq.RichTable = Class.create({ 2 initialize: function(rdom, table) { 3 this.rdom = rdom; 4 this.table = table; 5 }, 6 insertNewRowAt: function(tr, where) { 7 var row = this.rdom.createElement("TR"); 8 var cells = tr.cells; 9 for(var i = 0; i < cells.length; i++) { 10 var cell = this.rdom.createElement(cells[i].nodeName); 11 this.rdom.correctEmptyElement(cell); 12 row.appendChild(cell); 13 } 14 return this.rdom.insertNodeAt(row, tr, where); 15 }, 16 insertNewCellAt: function(cell, where) { 17 // collect cells; 18 var cells = []; 19 var x = this.getXIndexOf(cell); 20 var y = 0; 21 while(true) { 22 var cur = this.getCellAt(x, y); 23 if(!cur) break; 24 cells.push(cur); 25 y++; 26 } 27 28 // insert new cells 29 for(var i = 0; i < cells.length; i++) { 30 var cell = this.rdom.createElement(cells[i].nodeName); 31 this.rdom.correctEmptyElement(cell); 32 this.rdom.insertNodeAt(cell, cells[i], where); 33 } 34 }, 35 deleteRow: function(tr) { 36 return this.rdom.removeBlock(tr); 37 }, 38 deleteCell: function(cell) { 39 if(!cell.previousSibling && !cell.nextSibling) { 40 this.rdom.deleteNode(this.table); 41 return; 42 } 43 44 // collect cells; 45 var cells = []; 46 var x = this.getXIndexOf(cell); 47 var y = 0; 48 while(true) { 49 var cur = this.getCellAt(x, y); 50 if(!cur) break; 51 cells.push(cur); 52 y++; 53 } 54 55 for(var i = 0; i < cells.length; i++) { 56 this.rdom.deleteNode(cells[i]); 57 } 58 }, 59 getPreviousCellOf: function(cell) { 60 if(cell.previousSibling) return cell.previousSibling; 61 var adjRow = this.getPreviousRowOf(cell.parentNode); 62 if(adjRow) return adjRow.lastChild; 63 return null; 64 }, 65 getNextCellOf: function(cell) { 66 if(cell.nextSibling) return cell.nextSibling; 67 var adjRow = this.getNextRowOf(cell.parentNode); 68 if(adjRow) return adjRow.firstChild; 69 return null; 70 }, 71 getPreviousRowOf: function(row) { 72 if(row.previousSibling) return row.previousSibling; 73 var rowContainer = row.parentNode; 74 if(rowContainer.previousSibling && rowContainer.previousSibling.lastChild) return rowContainer.previousSibling.lastChild; 75 return null; 76 }, 77 getNextRowOf: function(row) { 78 if(row.nextSibling) return row.nextSibling; 79 var rowContainer = row.parentNode; 80 if(rowContainer.nextSibling && rowContainer.nextSibling.firstChild) return rowContainer.nextSibling.firstChild; 81 return null; 82 }, 83 getAboveCellOf: function(cell) { 84 var row = this.getPreviousRowOf(cell.parentNode); 85 if(!row) return null; 86 87 var x = this.getXIndexOf(cell); 88 return row.cells[x]; 89 }, 90 getBelowCellOf: function(cell) { 91 var row = this.getNextRowOf(cell.parentNode); 92 if(!row) return null; 93 94 var x = this.getXIndexOf(cell); 95 return row.cells[x]; 96 }, 97 getXIndexOf: function(cell) { 98 var row = cell.parentNode; 99 for(var i = 0; i < row.cells.length; i++) { 100 if(row.cells[i] == cell) return i; 101 } 102 103 return -1; 104 }, 105 getYIndexOf: function(cell) { 106 var y = -1; 107 108 // find y 109 var group = row.parentNode; 110 for(var i = 0; i <group.rows.length; i++) { 111 if(group.rows[i] == row) { 112 y = i; 113 break; 114 } 115 } 116 if(this.hasHeadingAtTop() && group.nodeName == "TBODY") y = y + 1; 117 118 return y; 119 }, 120 /** 121 * TODO: Not used. Delete or not? 122 */ 123 getLocationOf: function(cell) { 124 var x = this.getXIndexOf(cell); 125 var y = this.getYIndexOf(cell); 126 return {x:x, y:y}; 127 }, 128 getCellAt: function(col, row) { 129 var row = this.getRowAt(row); 130 return (row && row.cells.length > col) ? row.cells[col] : null; 131 }, 132 getRowAt: function(index) { 133 if(this.hasHeadingAtTop()) { 134 return index == 0 ? this.table.tHead.rows[0] : this.table.tBodies[0].rows[index - 1]; 135 } else { 136 var rows = this.table.tBodies[0].rows; 137 return (rows.length > index) ? rows[index] : null; 138 } 139 }, 140 getDom: function() { 141 return this.table; 142 }, 143 hasHeadingAtTop: function() { 144 return !!(this.table.tHead && this.table.tHead.rows[0]); 145 }, 146 hasHeadingAtLeft: function() { 147 return this.table.tBodies[0].rows[0].cells[0].nodeName == "TH"; 148 }, 149 correctEmptyCells: function() { 150 var cells = $A(this.table.getElementsByTagName("TH")); 151 cells.push($A(this.table.getElementsByTagName("TD"))); 152 cells = cells.flatten(); 153 154 for(var i = 0; i < cells.length; i++) { 155 if(this.rdom.isEmptyBlock(cells[i])) this.rdom.correctEmptyElement(cells[i]) 156 } 157 } 158 }); 159 160 xq.RichTable.create = function(rdom, cols, rows, headerPositions) { 161 if(["t", "tl", "lt"].include(headerPositions)) var headingAtTop = true 162 if(["l", "tl", "lt"].include(headerPositions)) var headingAtLeft = true 163 164 var sb = [] 165 sb.push('<table class="datatable">') 166 167 // thead 168 if(headingAtTop) { 169 sb.push('<thead><tr>') 170 for(var i = 0; i < cols; i++) sb.push('<th></th>') 171 sb.push('</tr></thead>') 172 rows -= 1 173 } 174 175 // tbody 176 sb.push('<tbody>') 177 for(var i = 0; i < rows; i++) { 178 sb.push('<tr>') 179 180 for(var j = 0; j < cols; j++) { 181 if(headingAtLeft && j == 0) { 182 sb.push('<th></th>') 183 } else { 184 sb.push('<td></td>') 185 } 186 } 187 188 sb.push('</tr>') 189 } 190 sb.push('</tbody>') 191 192 sb.push('</table>') 193 194 // create DOM element 195 var container = rdom.createElement("div"); 196 container.innerHTML = sb.join(""); 197 198 // correct empty cells and return 199 var rtable = new xq.RichTable(rdom, container.firstChild); 200 rtable.correctEmptyCells(); 201 return rtable; 202 }