Ticket #6568: 6568_2.patch

File 6568_2.patch, 11.6 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                }
    211 
    212                 return 0;
    213234        }
    214235
    215236        function insertColumn( selection, insertBefore )
    216237        {
    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 );
     238                var cells = getSelectedCells( selection ),
     239                        firstCell = cells[ 0 ],
     240                        table = firstCell.getAscendant( 'table' ),
     241                        lastCell = cells[ cells.length - 1 ],
     242                        startCol = firstCell.$.cellIndex,
     243                        lastCol = lastCell.$.cellIndex + lastCell.$.colSpan - 1,
     244                        colIndex = insertBefore? startCol : lastCol;
    220245
    221                 if ( !cell )
    222                         return;
    223246
    224                 // Get the cell's table.
    225                 var table = cell.getAscendant( 'table' );
    226                 var cellIndex = cell.$.cellIndex;
     247                var map = CKEDITOR.tools.buildTableMap( table ),
     248                        cloneCol = [],
     249                        nextCol = [],
     250                        height = map.length;
    227251
    228                 // Loop through all rows available in the table.
    229                 for ( var i = 0 ; i < table.$.rows.length ; i++ )
     252                for ( var i = 0; i < height; i++ )
    230253                {
    231                         var $row = table.$.rows[ i ];
     254                        cloneCol.push( map[ i ][ colIndex ] );
     255                        var nextCell = insertBefore ? map[ i ][ colIndex - 1 ] : map[ i ][ colIndex + 1 ];
     256                        nextCell && nextCol.push( nextCell );
     257                }
    232258
    233                         // If the row doesn't have enough cells, ignore it.
    234                         if ( $row.cells.length < ( cellIndex + 1 ) )
    235                                 continue;
     259                for ( i = 0; i < height; i++ )
     260                {
     261                        var cell;
     262                        // Check whether there's a spanning column here, do not break it.
     263                        if ( cloneCol[ i ].colSpan > 1
     264                                && nextCol.length
     265                                && nextCol[ i ] == cloneCol[ i ] )
     266                        {
     267                                cell = cloneCol[ i ];
     268                                cell.colSpan += 1;
     269                        }
     270                        else
     271                        {
     272                                cell = new CKEDITOR.dom.element( cloneCol[ i ] ).clone();
     273                                cell.removeAttribute( 'colSpan' );
     274                                !CKEDITOR.env.ie && cell.appendBogus();
     275                                cell[ insertBefore? 'insertBefore' : 'insertAfter' ].call( cell, new CKEDITOR.dom.element ( cloneCol[ i ] ) );
     276                                cell = cell.$;
     277                        }
    236278
    237                         cell = ( new CKEDITOR.dom.element( $row.cells[ cellIndex ] ) ).clone( 0 );
     279                        i += cell.rowSpan - 1;
     280                }
     281        }
    238282
    239                         if ( !CKEDITOR.env.ie )
    240                                 cell.appendBogus();
     283        function deleteColumns( selectionOrCell )
     284        {
     285                var cells = getSelectedCells( selectionOrCell ),
     286                                firstCell = cells[ 0 ],
     287                                lastCell = cells[ cells.length - 1 ],
     288                                table = firstCell.getAscendant( 'table' ),
     289                                map = CKEDITOR.tools.buildTableMap( table ),
     290                                startColIndex,
     291                                endColIndex,
     292                                rowsToDelete = [];
    241293
    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         }
     294                // Figure out selected cells' column indices.
     295                for ( var i = 0, rows = map.length; i < rows; i++ )
     296                {
     297                        for ( var j = 0, cols = map[ i ].length; j < cols; j++ )
     298                        {
     299                                if ( map[ i ][ j ] == firstCell.$ )
     300                                        startColIndex = j;
     301                                if ( map[ i ][ j ] == lastCell.$ )
     302                                        endColIndex = j;
     303                        }
     304                }
     305
     306                // Delete cell or reduce cell spans by checking through the table map.
     307                for ( i = startColIndex; i <= endColIndex; i++ )
     308                {
     309                        for ( j = 0; j < map.length; j++ )
     310                        {
     311                                var mapRow = map[ j ],
     312                                        row = new CKEDITOR.dom.element( table.$.rows[ j ] ),
     313                                        cell = new CKEDITOR.dom.element( mapRow[ i ] );
     314
     315                                if ( cell.$.colSpan == 1 )
     316                                        cell.remove();
     317                                // Reduce the col spans.
     318                                else
     319                                        cell.$.colSpan -= 1;
     320
     321                                j += cell.$.rowSpan - 1;
     322
     323                                if ( !row.$.cells.length )
     324                                        rowsToDelete.push( row );
     325                        }
     326                }
    250327
     328                var firstRowCells = table.$.rows[ 0 ] && table.$.rows[ 0 ].cells;
     329
     330                // Where to put the cursor after columns been deleted?
     331                // 1. Into next cell of the first row if any;
     332                // 2. Into previous cell of the first row if any;
     333                // 3. Into table's parent element;
     334                var cursorPosition =  new CKEDITOR.dom.element( firstRowCells[ startColIndex ] || ( startColIndex ? firstRowCells[ startColIndex - 1 ] : table.$.parentNode ) );
     335
     336                // Delete table rows only if all columns are gone (do not remove empty row).
     337                if ( rowsToDelete.length == rows )
     338                        table.remove();
     339
     340                return cursorPosition;
     341        }
     342
    251343        function getFocusElementAfterDelCols( cells )
    252344        {
    253345                var cellIndexList = [],
     
    286378                return targetCell ?  new CKEDITOR.dom.element( targetCell ) :  table.getPrevious();
    287379        }
    288380
    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 
    339381        function insertCell( selection, insertBefore )
    340382        {
    341383                var startElement = selection.getStartElement();
© 2003 – 2020 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy