Ticket #6568: 6568_3.patch
File 6568_3.patch, 12.2 KB (added by , 13 years ago) |
---|
-
_source/plugins/tabletools/plugin.js
1 /* 1 /* 2 2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. 3 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 4 */ 5 5 6 6 (function() 7 7 { 8 function removeRawAttribute( $node, attr )9 {10 if ( CKEDITOR.env.ie )11 $node.removeAttribute( attr );12 else13 delete $node[ attr ];14 }15 16 8 var cellNodeRegex = /^(?:td|th)$/; 17 9 18 10 function getSelectedCells( selection ) … … 123 115 return null; 124 116 } 125 117 126 function clearRow( $tr)118 function insertRow( selection, insertBefore ) 127 119 { 128 // Get the array of row's cells. 129 var $cells = $tr.cells; 120 var cells = getSelectedCells( selection ), 121 firstCell = cells[ 0 ], 122 table = firstCell.getAscendant( 'table' ), 123 doc = firstCell.getDocument(), 124 startRow = cells[ 0 ].getParent(), 125 startRowIndex = startRow.$.rowIndex, 126 lastCell = cells[ cells.length - 1 ], 127 endRowIndex = lastCell.getParent().$.rowIndex + lastCell.$.rowSpan - 1, 128 endRow = new CKEDITOR.dom.element( table.$.rows[ endRowIndex ] ), 129 rowIndex = insertBefore ? startRowIndex : endRowIndex, 130 row = insertBefore ? startRow : endRow; 130 131 131 // Empty all cells.132 for ( var i = 0 ; i < $cells.length ; i++ )133 {134 $cells[ i ].innerHTML = '';132 var map = CKEDITOR.tools.buildTableMap( table ), 133 cloneRow = map[ rowIndex ], 134 nextRow = insertBefore ? map[ rowIndex - 1 ] : map[ rowIndex + 1 ], 135 width = map[0].length; 135 136 136 if ( !CKEDITOR.env.ie ) 137 ( new CKEDITOR.dom.element( $cells[ i ] ) ).appendBogus(); 138 } 139 } 137 var newRow = doc.createElement( 'tr' ); 138 for ( var i = 0; i < width; i++ ) 139 { 140 var cell; 141 // Check whether there's a spanning row here, do not break it. 142 if ( cloneRow[ i ].rowSpan > 1 && nextRow && cloneRow[ i ] == nextRow[ i ] ) 143 { 144 cell = cloneRow[ i ]; 145 cell.rowSpan += 1; 146 } 147 else 148 { 149 cell = new CKEDITOR.dom.element( cloneRow[ i ] ).clone(); 150 cell.removeAttribute( 'rowSpan' ); 151 !CKEDITOR.env.ie && cell.appendBogus(); 152 newRow.append( cell ); 153 cell = cell.$; 154 } 140 155 141 function insertRow( selection, insertBefore ) 142 { 143 // Get the row where the selection is placed in. 144 var row = selection.getStartElement().getAscendant( 'tr' ); 145 if ( !row ) 146 return; 156 i += cell.colSpan - 1; 157 } 147 158 148 // Create a clone of the row.149 var newRow = row.clone( 1 );150 151 159 insertBefore ? 152 newRow.insertBefore( row ) : 153 newRow.insertAfter( row ); 154 155 // Clean the new row. 156 clearRow( newRow.$ ); 160 newRow.insertBefore( row ) : 161 newRow.insertAfter( row ); 157 162 } 158 163 159 164 function deleteRows( selectionOrRow ) … … 161 166 if ( selectionOrRow instanceof CKEDITOR.dom.selection ) 162 167 { 163 168 var cells = getSelectedCells( selectionOrRow ), 164 cellsCount = cells.length, 165 rowsToDelete = [], 166 cursorPosition, 167 previousRowIndex, 168 nextRowIndex; 169 firstCell = cells[ 0 ], 170 table = firstCell.getAscendant( 'table' ), 171 map = CKEDITOR.tools.buildTableMap( table ), 172 startRow = cells[ 0 ].getParent(), 173 startRowIndex = startRow.$.rowIndex, 174 lastCell = cells[ cells.length - 1 ], 175 endRowIndex = lastCell.getParent().$.rowIndex + lastCell.$.rowSpan - 1, 176 rowsToDelete = []; 169 177 170 // Queue up the rows - it's possible and likely that we have duplicates.171 for ( var i = 0 ; i < cellsCount; i++ )178 // Delete cell or reduce cell spans by checking through the table map. 179 for ( var i = startRowIndex; i <= endRowIndex; i++ ) 172 180 { 173 var row = cells[ i ].getParent(),174 row Index = row.$.rowIndex;181 var mapRow = map[ i ], 182 row = new CKEDITOR.dom.element( table.$.rows[ i ] ); 175 183 176 !i && ( previousRowIndex = rowIndex - 1 ); 177 rowsToDelete[ rowIndex ] = row; 178 i == cellsCount - 1 && ( nextRowIndex = rowIndex + 1 ); 179 } 184 for ( var j = 0; j < mapRow.length; j++ ) 185 { 186 var cell = new CKEDITOR.dom.element( mapRow[ j ] ), 187 cellRowIndex = cell.getParent().$.rowIndex; 188 189 if ( cell.$.rowSpan == 1 ) 190 cell.remove(); 191 // Row spanned cell. 192 else 193 { 194 // Span row of the cell, reduce spanning. 195 cell.$.rowSpan -= 1; 196 // Root row of the cell, root cell to next row. 197 if ( cellRowIndex == i ) 198 { 199 var nextMapRow = map[ i + 1 ]; 200 nextMapRow[ j - 1 ] ? 201 cell.insertAfter( new CKEDITOR.dom.element( nextMapRow[ j - 1 ] ) ) 202 : new CKEDITOR.dom.element( table.$.rows[ i + 1 ] ).append( cell, 1 ); 203 } 204 } 180 205 181 var table = row.getAscendant( 'table' ), 182 rows = table.$.rows, 183 rowCount = rows.length; 206 j += cell.$.colSpan - 1; 207 } 184 208 209 rowsToDelete.push( row ); 210 } 211 212 var rows = table.$.rows; 213 185 214 // Where to put the cursor after rows been deleted? 186 215 // 1. Into next sibling row if any; 187 216 // 2. Into previous sibling row if any; 188 217 // 3. Into table's parent element if it's the very last row. 189 cursorPosition = new CKEDITOR.dom.element( 190 nextRowIndex < rowCount && table.$.rows[ nextRowIndex ] || 191 previousRowIndex > 0 && table.$.rows[ previousRowIndex ] || 192 table.$.parentNode ); 218 var cursorPosition = new CKEDITOR.dom.element( rows[ startRowIndex ] || rows[ startRowIndex - 1 ] || table.$.parentNode ); 193 219 194 220 for ( i = rowsToDelete.length ; i >= 0 ; i-- ) 195 { 196 if ( rowsToDelete[ i ] ) 197 deleteRows( rowsToDelete[ i ] ); 198 } 221 deleteRows( rowsToDelete[ i ] ); 199 222 200 223 return cursorPosition; 201 224 } … … 208 231 else 209 232 selectionOrRow.remove(); 210 233 } 234 } 211 235 212 return 0; 213 } 236 function getCellColIndex( cell, isStart ) 237 { 238 var row = cell.getParent(), 239 rowCells = row.$.cells; 240 241 var colIndex = 0; 242 for ( var i = 0; i < rowCells.length; i++ ) 243 { 244 var mapCell = rowCells[ i ]; 245 colIndex += isStart ? 1 : mapCell.colSpan; 246 if ( mapCell == cell.$ ) 247 break; 248 } 214 249 250 return colIndex -1; 251 } 252 253 function getColumnsIndices( cells, isStart ) 254 { 255 var retval = isStart ? Infinity : 0; 256 for ( var i = 0; i < cells.length; i++ ) 257 { 258 var colIndex = getCellColIndex( cells[ i ], isStart ); 259 if ( isStart ? colIndex < retval : colIndex > retval ) 260 retval = colIndex; 261 } 262 return retval; 263 } 264 215 265 function insertColumn( selection, insertBefore ) 216 266 { 217 // Get the cell where the selection is placed in. 218 var startElement = selection.getStartElement(); 219 var cell = startElement.getAscendant( 'td', 1 ) || startElement.getAscendant( 'th', 1 ); 267 var cells = getSelectedCells( selection ), 268 firstCell = cells[ 0 ], 269 table = firstCell.getAscendant( 'table' ), 270 startCol = getColumnsIndices( cells, 1 ), 271 lastCol = getColumnsIndices( cells ), 272 colIndex = insertBefore? startCol : lastCol; 220 273 221 if ( !cell ) 222 return; 274 var map = CKEDITOR.tools.buildTableMap( table ), 275 cloneCol = [], 276 nextCol = [], 277 height = map.length; 223 278 224 // Get the cell's table. 225 var table = cell.getAscendant( 'table' ); 226 var cellIndex = cell.$.cellIndex; 279 for ( var i = 0; i < height; i++ ) 280 { 281 cloneCol.push( map[ i ][ colIndex ] ); 282 var nextCell = insertBefore ? map[ i ][ colIndex - 1 ] : map[ i ][ colIndex + 1 ]; 283 nextCell && nextCol.push( nextCell ); 284 } 227 285 228 // Loop through all rows available in the table. 229 for ( var i = 0 ; i < table.$.rows.length ; i++ ) 286 for ( i = 0; i < height; i++ ) 230 287 { 231 var $row = table.$.rows[ i ]; 288 var cell; 289 // Check whether there's a spanning column here, do not break it. 290 if ( cloneCol[ i ].colSpan > 1 291 && nextCol.length 292 && nextCol[ i ] == cloneCol[ i ] ) 293 { 294 cell = cloneCol[ i ]; 295 cell.colSpan += 1; 296 } 297 else 298 { 299 cell = new CKEDITOR.dom.element( cloneCol[ i ] ).clone(); 300 cell.removeAttribute( 'colSpan' ); 301 !CKEDITOR.env.ie && cell.appendBogus(); 302 cell[ insertBefore? 'insertBefore' : 'insertAfter' ].call( cell, new CKEDITOR.dom.element ( cloneCol[ i ] ) ); 303 cell = cell.$; 304 } 232 305 233 // If the row doesn't have enough cells, ignore it.234 if ( $row.cells.length < ( cellIndex + 1 ) )235 continue;306 i += cell.rowSpan - 1; 307 } 308 } 236 309 237 cell = ( new CKEDITOR.dom.element( $row.cells[ cellIndex ] ) ).clone( 0 ); 310 function deleteColumns( selectionOrCell ) 311 { 312 var cells = getSelectedCells( selectionOrCell ), 313 firstCell = cells[ 0 ], 314 lastCell = cells[ cells.length - 1 ], 315 table = firstCell.getAscendant( 'table' ), 316 map = CKEDITOR.tools.buildTableMap( table ), 317 startColIndex, 318 endColIndex, 319 rowsToDelete = []; 238 320 239 if ( !CKEDITOR.env.ie ) 240 cell.appendBogus(); 321 // Figure out selected cells' column indices. 322 for ( var i = 0, rows = map.length; i < rows; i++ ) 323 { 324 for ( var j = 0, cols = map[ i ].length; j < cols; j++ ) 325 { 326 if ( map[ i ][ j ] == firstCell.$ ) 327 startColIndex = j; 328 if ( map[ i ][ j ] == lastCell.$ ) 329 endColIndex = j; 330 } 331 } 241 332 242 // Get back the currently selected cell. 243 var baseCell = new CKEDITOR.dom.element( $row.cells[ cellIndex ] ); 244 if ( insertBefore ) 245 cell.insertBefore( baseCell ); 246 else 247 cell.insertAfter( baseCell ); 248 } 249 } 333 // Delete cell or reduce cell spans by checking through the table map. 334 for ( i = startColIndex; i <= endColIndex; i++ ) 335 { 336 for ( j = 0; j < map.length; j++ ) 337 { 338 var mapRow = map[ j ], 339 row = new CKEDITOR.dom.element( table.$.rows[ j ] ), 340 cell = new CKEDITOR.dom.element( mapRow[ i ] ); 341 342 if ( cell.$.colSpan == 1 ) 343 cell.remove(); 344 // Reduce the col spans. 345 else 346 cell.$.colSpan -= 1; 347 348 j += cell.$.rowSpan - 1; 349 350 if ( !row.$.cells.length ) 351 rowsToDelete.push( row ); 352 } 353 } 250 354 355 var firstRowCells = table.$.rows[ 0 ] && table.$.rows[ 0 ].cells; 356 357 // Where to put the cursor after columns been deleted? 358 // 1. Into next cell of the first row if any; 359 // 2. Into previous cell of the first row if any; 360 // 3. Into table's parent element; 361 var cursorPosition = new CKEDITOR.dom.element( firstRowCells[ startColIndex ] || ( startColIndex ? firstRowCells[ startColIndex - 1 ] : table.$.parentNode ) ); 362 363 // Delete table rows only if all columns are gone (do not remove empty row). 364 if ( rowsToDelete.length == rows ) 365 table.remove(); 366 367 return cursorPosition; 368 } 369 251 370 function getFocusElementAfterDelCols( cells ) 252 371 { 253 372 var cellIndexList = [], … … 286 405 return targetCell ? new CKEDITOR.dom.element( targetCell ) : table.getPrevious(); 287 406 } 288 407 289 function deleteColumns( selectionOrCell )290 {291 if ( selectionOrCell instanceof CKEDITOR.dom.selection )292 {293 var colsToDelete = getSelectedCells( selectionOrCell ),294 elementToFocus = getFocusElementAfterDelCols( colsToDelete );295 296 for ( var i = colsToDelete.length - 1 ; i >= 0 ; i-- )297 {298 if ( colsToDelete[ i ] )299 deleteColumns( colsToDelete[ i ] );300 }301 302 return elementToFocus;303 }304 else if ( selectionOrCell instanceof CKEDITOR.dom.element )305 {306 // Get the cell's table.307 var table = selectionOrCell.getAscendant( 'table' );308 if ( !table )309 return null;310 311 // Get the cell index.312 var cellIndex = selectionOrCell.$.cellIndex;313 314 /*315 * Loop through all rows from down to up, coz it's possible that some rows316 * will be deleted.317 */318 for ( i = table.$.rows.length - 1 ; i >= 0 ; i-- )319 {320 // Get the row.321 var row = new CKEDITOR.dom.element( table.$.rows[ i ] );322 323 // If the cell to be removed is the first one and the row has just one cell.324 if ( !cellIndex && row.$.cells.length == 1 )325 {326 deleteRows( row );327 continue;328 }329 330 // Else, just delete the cell.331 if ( row.$.cells[ cellIndex ] )332 row.$.removeChild( row.$.cells[ cellIndex ] );333 }334 }335 336 return null;337 }338 339 408 function insertCell( selection, insertBefore ) 340 409 { 341 410 var startElement = selection.getStartElement();