Ticket #6568: 6568_3.patch

File 6568_3.patch, 12.2 KB (added by Garry Yao, 10 years ago)
  • _source/plugins/tabletools/plugin.js

     
    1 /*
     1/*
    22Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
    55
    66(function()
    77{
    8         function removeRawAttribute( $node, attr )
    9         {
    10                 if ( CKEDITOR.env.ie )
    11                         $node.removeAttribute( attr );
    12                 else
    13                         delete $node[ attr ];
    14         }
    15 
    168        var cellNodeRegex = /^(?:td|th)$/;
    179
    1810        function getSelectedCells( selection )
     
    123115                return null;
    124116        }
    125117
    126         function clearRow( $tr )
     118        function insertRow( selection, insertBefore )
    127119        {
    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;
    130131
    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;
    135136
    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                        }
    140155
    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                }
    147158
    148                 // Create a clone of the row.
    149                 var newRow = row.clone( 1 );
    150 
    151159                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 );
    157162        }
    158163
    159164        function deleteRows( selectionOrRow )
     
    161166                if ( selectionOrRow instanceof CKEDITOR.dom.selection )
    162167                {
    163168                        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 = [];
    169177
    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++ )
    172180                        {
    173                                 var row = cells[ i ].getParent(),
    174                                                 rowIndex = row.$.rowIndex;
     181                                var mapRow = map[ i ],
     182                                                row = new CKEDITOR.dom.element( table.$.rows[ i ] );
    175183
    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                                        }
    180205
    181                         var table = row.getAscendant( 'table' ),
    182                                         rows =  table.$.rows,
    183                                         rowCount = rows.length;
     206                                        j += cell.$.colSpan - 1;
     207                                }
    184208
     209                                rowsToDelete.push( row );
     210                        }
     211
     212                        var rows = table.$.rows;
     213
    185214                        // Where to put the cursor after rows been deleted?
    186215                        // 1. Into next sibling row if any;
    187216                        // 2. Into previous sibling row if any;
    188217                        // 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 );
    193219
    194220                        for ( i = rowsToDelete.length ; i >= 0 ; i-- )
    195                         {
    196                                 if ( rowsToDelete[ i ] )
    197                                         deleteRows( rowsToDelete[ i ] );
    198                         }
     221                                deleteRows( rowsToDelete[ i ] );
    199222
    200223                        return cursorPosition;
    201224                }
     
    208231                        else
    209232                                selectionOrRow.remove();
    210233                }
     234        }
    211235
    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                }
    214249
     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
    215265        function insertColumn( selection, insertBefore )
    216266        {
    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;
    220273
    221                 if ( !cell )
    222                         return;
     274                var map = CKEDITOR.tools.buildTableMap( table ),
     275                        cloneCol = [],
     276                        nextCol = [],
     277                        height = map.length;
    223278
    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                }
    227285
    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++ )
    230287                {
    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                        }
    232305
    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        }
    236309
    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 = [];
    238320
    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                }
    241332
    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                }
    250354
     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
    251370        function getFocusElementAfterDelCols( cells )
    252371        {
    253372                var cellIndexList = [],
     
    286405                return targetCell ?  new CKEDITOR.dom.element( targetCell ) :  table.getPrevious();
    287406        }
    288407
    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 rows
    316                          * 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 
    339408        function insertCell( selection, insertBefore )
    340409        {
    341410                var startElement = selection.getStartElement();
© 2003 – 2020 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy