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