Changeset 4609


Ignore:
Timestamp:
12/07/09 11:46:05 (4 years ago)
Author:
garry.yao
Message:

#4574: Adding table merging tools.

Location:
CKEditor/branches/versions/3.1.x
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • CKEditor/branches/versions/3.1.x/CHANGES.html

    r4586 r4609  
    4747                <li><a href="http://dev.fckeditor.net/ticket/4549">#4549</a> : Make the anti-cache query string configurable.</li> 
    4848                <li><a href="http://dev.fckeditor.net/ticket/4708">#4708</a> : Added the 'htmlEncodeOutput' config option.</li> 
     49                <li><a href="http://dev.fckeditor.net/ticket/4574">#4574</a> : Added the table merging tools and corresponding context menu options.</li> 
    4950        </ul> 
    5051        <p> 
  • CKEditor/branches/versions/3.1.x/_source/core/dom/range.js

    r4480 r4609  
    15791579                        return walker.checkForward(); 
    15801580                }, 
    1581  
    15821581                /** 
    1583                  * Moves the range boundaries to the first editing point inside an 
     1582                 * Moves the range boundaries to the first/end editing point inside an 
    15841583                 * element. For example, in an element tree like 
    15851584                 * "&lt;p&gt;&lt;b&gt;&lt;i&gt;&lt;/i&gt;&lt;/b&gt; Text&lt;/p&gt;", the start editing point is 
    15861585                 * "&lt;p&gt;&lt;b&gt;&lt;i&gt;^&lt;/i&gt;&lt;/b&gt; Text&lt;/p&gt;" (inside &lt;i&gt;). 
    15871586                 * @param {CKEDITOR.dom.element} targetElement The element into which 
    1588                  *              look for the editing spot. 
     1587                 *              look for the editing spot, it should be guaranteed to contains at least one editable position. 
     1588                        @param {Boolean} isMoveToEnd Whether move to the end editable position. 
    15891589                 */ 
    1590                 moveToElementEditStart : function( targetElement ) 
     1590                moveToElementEditablePosition: function( targetElement, isMoveToEnd ) 
    15911591                { 
    15921592                        var editableElement; 
     
    15991599                                        break ;         // If we already found an editable element, stop the loop. 
    16001600 
    1601                                 targetElement = targetElement.getFirst(); 
     1601                                targetElement = targetElement[ isMoveToEnd? 'getLast' : 'getFirst' ].call( targetElement ); 
    16021602                        } 
    16031603 
    16041604                        if ( editableElement ) 
    16051605                        { 
    1606                                 this.moveToPosition(editableElement, CKEDITOR.POSITION_AFTER_START); 
     1606                                // Make sure carot anchor before filler when moving to editable end. 
     1607                                var filler = editableElement.isBlockBoundary() && editableElement.getBogus(); 
     1608                                this.moveToPosition( isMoveToEnd && filler ? filler : editableElement, 
     1609                                                isMoveToEnd && filler ? CKEDITOR.POSITION_BEFORE_START : 
     1610                                                        isMoveToEnd ? CKEDITOR.POSITION_BEFORE_END : 
     1611                                                        CKEDITOR.POSITION_AFTER_START ); 
    16071612                                return true; 
    16081613                        } 
     
    16121617 
    16131618                /** 
    1614                  * Get the single node enclosed within the range if there's one. 
     1619                 *@see {CKEDITOR.dom.range.moveToElementEditablePosition} 
    16151620                 */ 
    1616                 getEnclosedNode : function() 
    1617                 { 
    1618                         var walkerRange = this.clone(), 
    1619                                 walker = new CKEDITOR.dom.walker( walkerRange ), 
    1620                                 isNotBookmarks = CKEDITOR.dom.walker.bookmark( true ), 
    1621                                 isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ), 
    1622                                 evaluator = function( node ) 
    1623                                 { 
    1624                                         return isNotWhitespaces( node ) && isNotBookmarks( node ); 
    1625                                 }; 
    1626                         walkerRange.evaluator = evaluator; 
    1627                         var node = walker.next(); 
    1628                         walker.reset(); 
    1629                         return node && node.equals( walker.previous() ) ? node : null; 
     1621                moveToElementEditStart : function( target ) 
     1622                { 
     1623                        return this.moveToElementEditablePosition( target ); 
     1624                }, 
     1625 
     1626                /** 
     1627                 *@see {CKEDITOR.dom.range.moveToElementEditablePosition} 
     1628                 */ 
     1629                moveToElementEditEnd : function( target ) 
     1630                { 
     1631                        return this.moveToElementEditablePosition( target, true ); 
    16301632                }, 
    16311633 
  • CKEditor/branches/versions/3.1.x/_source/core/dom/walker.js

    r4555 r4609  
    429429        }; 
    430430 
     431        var tailNbspRegex = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/, 
     432                isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ), 
     433                isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ), 
     434                fillerEvaluator = function( element ) 
     435                { 
     436                        return isNotBookmark( element ) && isNotWhitespaces( element ); 
     437                }; 
     438 
     439        // Check if there's a filler node at the end of an element, and return it. 
     440        CKEDITOR.dom.element.prototype.getBogus = function () 
     441        { 
     442                var tail = this.getLast( fillerEvaluator ); 
     443                if ( tail && ( !CKEDITOR.env.ie ? tail.is && tail.is( 'br' ) 
     444                                : tail.getText && tailNbspRegex.test( tail.getText() ) ) ) 
     445                { 
     446                        return tail; 
     447                } 
     448                return false; 
     449        }; 
     450 
    431451})(); 
  • CKEditor/branches/versions/3.1.x/_source/plugins/contextmenu/plugin.js

    r4555 r4609  
    8383                        var selection = this.editor.getSelection(), 
    8484                                element = selection && selection.getStartElement(); 
    85  
    86                         // Lock the selection in IE, so it can be restored when closing the 
    87                         // menu. 
    88                         if ( CKEDITOR.env.ie ) 
    89                                 selection.lock(); 
    9085 
    9186                        menu.onHide = CKEDITOR.tools.bind( function() 
     
    178173                                        } 
    179174                                } ); 
     175                        } 
     176 
     177                        // Certain forms of IE selection changes on 'contextmenu' event, 
     178                        // lock the selection before that.(#4041) 
     179                        if ( CKEDITOR.env.ie ) 
     180                        { 
     181                                element.on( 'mousedown', function( event ) 
     182                                { 
     183                                        if ( event.data.$.button == 2 ) 
     184                                                this.editor.getSelection().lock(); 
     185                                }, this ); 
    180186                        } 
    181187 
  • CKEditor/branches/versions/3.1.x/_source/plugins/selection/plugin.js

    r4555 r4609  
    950950                        this.selectRanges( ranges ); 
    951951                        return this; 
    952                 } 
     952                }, 
     953                 
     954                getCommonAncestor : function() 
     955                { 
     956                        var ranges = this.getRanges(), 
     957                                startNode = ranges[ 0 ].startContainer, 
     958                                endNode = ranges[ ranges.length - 1 ].endContainer; 
     959                        return startNode.getCommonAncestor( endNode ); 
     960                 } 
    953961        }; 
    954962})(); 
  • CKEditor/branches/versions/3.1.x/_source/plugins/tabletools/plugin.js

    r3826 r4609  
    8787        } 
    8888 
    89         function createTableMap( $refCell ) 
    90         { 
    91                 var refCell = new CKEDITOR.dom.element( $refCell ); 
    92                 var $table = ( refCell.getName() == 'table' ? $refCell : refCell.getAscendant( 'table' ) ).$; 
    93                 var $rows = $table.rows; 
    94  
    95                 // Row and column counters. 
    96                 var r = -1; 
    97                 var map = []; 
    98                 for ( var i = 0 ; i < $rows.length ; i++ ) 
    99                 { 
    100                         r++; 
    101                         if ( !map[ r ] ) 
    102                                 map[ r ] = []; 
    103  
    104                         var c = -1; 
    105  
    106                         for ( var j = 0 ; j < $rows[ i ].cells.length ; j++ ) 
    107                         { 
    108                                 var $cell = $rows[ i ].cells[ j ]; 
    109  
    110                                 c++; 
    111                                 while ( map[ r ][ c ] ) 
    112                                         c++; 
    113  
    114                                 var colSpan = isNaN( $cell.colSpan ) ? 1 : $cell.colSpan; 
    115                                 var rowSpan = isNaN( $cell.rowSpan ) ? 1 : $cell.rowSpan; 
    116  
    117                                 for ( var rs = 0 ; rs < rowSpan ; rs++ ) 
    118                                 { 
    119                                         if ( !map[ r + rs ] ) 
    120                                                 map[ r + rs ] = []; 
    121  
    122                                         for ( var cs = 0 ; cs < colSpan ; cs++ ) 
    123                                                 map [ r + rs ][ c + cs ] = $rows[ i ].cells[ j ]; 
    124                                 } 
    125  
    126                                 c += colSpan - 1; 
    127                         } 
    128                 } 
    129  
    130                 return map; 
    131         } 
    132  
    133         function installTableMap( tableMap, $table ) 
    134         { 
    135                 /* 
    136                  * IE BUG: rowSpan is always 1 in IE if the cell isn't attached to a row. So 
    137                  * store is separately in another attribute. (#1917) 
    138                  */ 
    139                 var rowSpanAttr = CKEDITOR.env.ie ? '_cke_rowspan' : 'rowSpan'; 
    140  
    141                 /* 
    142                  * Disconnect all the cells in tableMap from their parents, set all colSpan 
    143                  * and rowSpan attributes to 1. 
    144                  */ 
    145                 for ( var i = 0 ; i < tableMap.length ; i++ ) 
    146                 { 
    147                         for ( var j = 0 ; j < tableMap[ i ].length ; j++ ) 
    148                         { 
    149                                 var $cell = tableMap[ i ][ j ]; 
    150                                 if ( $cell.parentNode ) 
    151                                         $cell.parentNode.removeChild( $cell ); 
    152                                 $cell.colSpan = $cell[ rowSpanAttr ] = 1; 
    153                         } 
    154                 } 
    155  
    156                 // Scan by rows and set colSpan. 
    157                 var maxCol = 0; 
    158                 for ( i = 0 ; i < tableMap.length ; i++ ) 
    159                 { 
    160                         for ( j = 0 ; j < tableMap[ i ].length ; j++ ) 
    161                         { 
    162                                 $cell = tableMap[ i ][ j ]; 
    163                                 if ( !$cell ) 
    164                                         continue; 
    165                                 if ( j > maxCol ) 
    166                                         maxCol = j; 
    167                                 if ( $cell[ '_cke_colScanned' ] ) 
    168                                         continue; 
    169                                 if ( tableMap[ i ][ j - 1 ] == $cell ) 
    170                                         $cell.colSpan++; 
    171                                 if ( tableMap[ i ][ j + 1 ] != $cell ) 
    172                                         $cell[ '_cke_colScanned' ] = 1; 
    173                         } 
    174                 } 
    175  
    176                 // Scan by columns and set rowSpan. 
    177                 for ( i = 0 ; i <= maxCol ; i++ ) 
    178                 { 
    179                         for ( j = 0 ; j < tableMap.length ; j++ ) 
    180                         { 
    181                                 if ( !tableMap[ j ] ) 
    182                                         continue; 
    183                                 $cell = tableMap[ j ][ i ]; 
    184                                 if ( !$cell || $cell[ '_cke_rowScanned' ] ) 
    185                                         continue; 
    186                                 if ( tableMap[ j - 1 ] && tableMap[ j - 1 ][ i ] == $cell ) 
    187                                         $cell[ rowSpanAttr ]++; 
    188                                 if ( !tableMap[ j + 1 ] || tableMap[ j + 1 ][ i ] != $cell  ) 
    189                                         $cell[ '_cke_rowScanned' ] = 1; 
    190                         } 
    191                 } 
    192  
    193                 // Clear all temporary flags. 
    194                 for ( i = 0 ; i < tableMap.length ; i++ ) 
    195                 { 
    196                         for ( j = 0 ; j < tableMap[ i ].length ; j++ ) 
    197                         { 
    198                                 $cell = tableMap[ i ][ j ]; 
    199                                 removeRawAttribute( $cell, '_cke_colScanned' ); 
    200                                 removeRawAttribute( $cell, '_cke_rowScanned' ); 
    201                         } 
    202                 } 
    203  
    204                 // Insert physical rows and columns to table. 
    205                 for ( i = 0 ; i < tableMap.length ; i++ ) 
    206                 { 
    207                         var $row = $table.ownerDocument.createElement( 'tr' ); 
    208                         for ( j = 0 ; j < tableMap[ i ].length ; ) 
    209                         { 
    210                                 $cell = tableMap[ i ][ j ]; 
    211                                 if ( tableMap[ i - 1 ] && tableMap[ i - 1 ][ j ] == $cell ) 
    212                                 { 
    213                                         j += $cell.colSpan; 
    214                                         continue; 
    215                                 } 
    216                                 $row.appendChild( $cell ); 
    217                                 if ( rowSpanAttr != 'rowSpan' ) 
    218                                 { 
    219                                         $cell.rowSpan = $cell[ rowSpanAttr ]; 
    220                                         $cell.removeAttribute( rowSpanAttr ); 
    221                                 } 
    222                                 j += $cell.colSpan; 
    223                                 if ( $cell.colSpan == 1 ) 
    224                                         $cell.removeAttribute( 'colSpan' ); 
    225                                 if ( $cell.rowSpan == 1 ) 
    226                                         $cell.removeAttribute( 'rowSpan' ); 
    227                         } 
    228  
    229                         if ( CKEDITOR.env.ie ) 
    230                                 $table.rows[ i ].replaceNode( $row ); 
    231                         else 
    232                         { 
    233                                 var dest = new CKEDITOR.dom.element( $table.rows[ i ] ); 
    234                                 var src = new CKEDITOR.dom.element( $row ); 
    235                                 dest.setHtml( '' ); 
    236                                 src.moveChildren( dest ); 
    237                         } 
    238                 } 
    239         } 
    240  
    24189        function clearRow( $tr ) 
    24290        { 
     
    417265        } 
    418266 
     267        // Remove filler at end and empty spaces around the cell content. 
     268        function trimCell( cell ) 
     269        { 
     270                var bogus = cell.getBogus(); 
     271                bogus && bogus.remove(); 
     272                cell.trim(); 
     273        } 
     274 
     275        function placeCursorInCell( cell, placeAtEnd ) 
     276        { 
     277                var range = new CKEDITOR.dom.range( cell.getDocument() ); 
     278                if ( !range[ 'moveToElementEdit' + ( placeAtEnd ? 'End' : 'Start' ) ]( cell ) ) 
     279                { 
     280                        range.selectNodeContents( cell ); 
     281                        range.collapse( placeAtEnd ? false : true ); 
     282                } 
     283                range.select( true ); 
     284        } 
     285 
     286        function buildTableMap( table ) 
     287        { 
     288 
     289                var aRows = table.$.rows ; 
     290 
     291                // Row and Column counters. 
     292                var r = -1 ; 
     293 
     294                var aMap = []; 
     295 
     296                for ( var i = 0 ; i < aRows.length ; i++ ) 
     297                { 
     298                        r++ ; 
     299                        !aMap[r] && ( aMap[r] = [] ); 
     300 
     301                        var c = -1 ; 
     302 
     303                        for ( var j = 0 ; j < aRows[i].cells.length ; j++ ) 
     304                        { 
     305                                var oCell = aRows[i].cells[j] ; 
     306 
     307                                c++ ; 
     308                                while ( aMap[r][c] ) 
     309                                        c++ ; 
     310 
     311                                var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ; 
     312                                var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ; 
     313 
     314                                for ( var rs = 0 ; rs < iRowSpan ; rs++ ) 
     315                                { 
     316                                        if ( !aMap[r + rs] ) 
     317                                                aMap[r + rs] = new Array() ; 
     318 
     319                                        for ( var cs = 0 ; cs < iColSpan ; cs++ ) 
     320                                        { 
     321                                                aMap[r + rs][c + cs] = aRows[i].cells[j] ; 
     322                                        } 
     323                                } 
     324 
     325                                c += iColSpan - 1 ; 
     326                        } 
     327                } 
     328                return aMap ; 
     329        } 
     330 
     331        function cellInRow( tableMap, rowIndex, cell ) 
     332        { 
     333                var oRow = tableMap[ rowIndex ]; 
     334                if( typeof cell == 'undefined' ) 
     335                        return oRow; 
     336 
     337                for ( var c = 0 ; oRow && c < oRow.length ; c++ ) 
     338                { 
     339                        if ( cell.is && oRow[c] == cell.$ ) 
     340                                return c; 
     341                        else if( c == cell ) 
     342                                return new CKEDITOR.dom.element( oRow[ c ] ); 
     343                } 
     344                return cell.is ? -1 : null; 
     345        } 
     346 
     347        function cellInCol( tableMap, colIndex, cell ) 
     348        { 
     349                var oCol = []; 
     350                for ( var r = 0; r < tableMap.length; r++ ) 
     351                { 
     352                        var row = tableMap[ r ]; 
     353                        if( typeof cell == 'undefined' ) 
     354                                oCol.push( row[ colIndex ] ); 
     355                        else if( cell.is && row[ colIndex ] == cell.$ ) 
     356                                return r; 
     357                        else if( r == cell ) 
     358                                return new CKEDITOR.dom.element( row[ colIndex ] ); 
     359                } 
     360                 
     361                return ( typeof cell == 'undefined' )? oCol : cell.is ? -1 :  null; 
     362        } 
     363 
     364        function mergeCells( selection, mergeDirection, isDetect ) 
     365        { 
     366                var cells = getSelectedCells( selection ); 
     367 
     368                // Invalid merge request if: 
     369                // 1. In batch mode despite that less than two selected. 
     370                // 2. In solo mode while not exactly only one selected.     
     371                // 3. Cells distributed in different table groups (e.g. from both thead and tbody). 
     372                if( ( mergeDirection ? cells.length != 1 : cells.length < 2 )  
     373                         || selection.getCommonAncestor().is( 'table' ) ) 
     374                        return false; 
     375 
     376                var     cell, 
     377                        firstCell = cells[ 0 ], 
     378                        table = firstCell.getAscendant( 'table' ), 
     379                        map = buildTableMap( table ), 
     380                        mapHeight = map.length, 
     381                        mapWidth = map[ 0 ].length, 
     382                        startRow = firstCell.getParent().$.rowIndex, 
     383                        startColumn = cellInRow( map, startRow, firstCell ); 
     384 
     385                if( mergeDirection ) 
     386                { 
     387                        var targetCell; 
     388                        try 
     389                        { 
     390                                targetCell = 
     391                                        map[ mergeDirection == 'up' ? 
     392                                                        ( startRow - 1 ): 
     393                                                        mergeDirection == 'down' ? ( startRow + 1 ) : startRow  ] [ 
     394                                                 mergeDirection == 'left' ? 
     395                                                        ( startColumn - 1 ): 
     396                                                 mergeDirection == 'right' ?  ( startColumn + 1 ) : startColumn ]; 
     397 
     398                        } 
     399                        catch( er ) 
     400                        { 
     401                                return false; 
     402                        } 
     403 
     404                        // 1. No cell could be merged. 
     405                        // 2. Same cell actually. 
     406                        if( !targetCell || firstCell.$ == targetCell  ) 
     407                                return false; 
     408 
     409                        // Sort in map order regardless of the DOM sequence. 
     410                        cells[ ( mergeDirection == 'up' || mergeDirection == 'left' ) ? 
     411                                 'unshift' : 'push' ]( new CKEDITOR.dom.element( targetCell ) ); 
     412                } 
     413 
     414                // Start from here are merging way ignorance (merge up/right, batch merge). 
     415                var     doc = firstCell.getDocument(), 
     416                        lastRowIndex = startRow, 
     417                        totalRowSpan = 0, 
     418                        totalColSpan = 0, 
     419                        // Use a documentFragment as buffer when appending cell contents. 
     420                        frag = !isDetect && new CKEDITOR.dom.documentFragment( doc ), 
     421                        dimension = 0; 
     422 
     423                for ( var i = 0; i < cells.length; i++ ) 
     424                { 
     425                        cell = cells[ i ]; 
     426 
     427                        var tr = cell.getParent(), 
     428                                cellFirstChild = cell.getFirst(), 
     429                                colSpan = cell.$.colSpan, 
     430                                rowSpan = cell.$.rowSpan, 
     431                                rowIndex = tr.$.rowIndex, 
     432                                colIndex = cellInRow( map, rowIndex, cell ); 
     433 
     434                        // Accumulated the actual places taken by all selected cells. 
     435                        dimension += colSpan * rowSpan; 
     436                        // Accumulated the maximum virtual spans from column and row. 
     437                        totalColSpan = Math.max( totalColSpan, colIndex - startColumn + colSpan ) ; 
     438                        totalRowSpan = Math.max( totalRowSpan, rowIndex - startRow + rowSpan ); 
     439 
     440                        if ( !isDetect ) 
     441                        { 
     442                                // Trim all cell fillers and check to remove empty cells. 
     443                                if( trimCell( cell ), cell.getChildren().count() ) 
     444                                { 
     445                                        // Merge vertically cells as two separated paragraphs. 
     446                                        if( rowIndex != lastRowIndex 
     447                                                && cellFirstChild 
     448                                                && !( cellFirstChild.isBlockBoundary 
     449                                                          && cellFirstChild.isBlockBoundary( { br : 1 } ) ) ) 
     450                                        { 
     451                                                var last = frag.getLast( CKEDITOR.dom.walker.whitespaces( true ) ); 
     452                                                if( last && !( last.is && last.is( 'br' ) ) ) 
     453                                                        frag.append( new CKEDITOR.dom.element( 'br' ) ); 
     454                                        } 
     455 
     456                                        cell.moveChildren( frag ); 
     457                                } 
     458                                i ? cell.remove() : cell.setHtml( '' ); 
     459                        } 
     460                        lastRowIndex = rowIndex; 
     461                } 
     462 
     463                if ( !isDetect ) 
     464                { 
     465                        frag.moveChildren( firstCell ); 
     466 
     467                        if( !CKEDITOR.env.ie ) 
     468                                firstCell.appendBogus(); 
     469 
     470                        if( totalColSpan >= mapWidth ) 
     471                                firstCell.removeAttribute( 'rowSpan' ); 
     472                        else 
     473                                firstCell.$.rowSpan = totalRowSpan; 
     474 
     475                        if( totalRowSpan >= mapHeight ) 
     476                                firstCell.removeAttribute( 'colSpan' ); 
     477                        else 
     478                                firstCell.$.colSpan = totalColSpan; 
     479 
     480                        // Swip empty <tr> left at the end of table due to the merging. 
     481                        var trs = new CKEDITOR.dom.nodeList( table.$.rows ), 
     482                                count = trs.count(); 
     483 
     484                        for ( var i = count - 1; i >= 0; i-- ) 
     485                        { 
     486                                var tailTr = trs.getItem( i ); 
     487                                if( !tailTr.$.cells.length ) 
     488                                { 
     489                                        tailTr.remove(); 
     490                                        count++; 
     491                                        continue; 
     492                                } 
     493                        } 
     494 
     495                        return firstCell; 
     496                } 
     497                // Be able to merge cells only if actual dimension of selected 
     498                // cells equals to the caculated rectangle. 
     499                else 
     500                        return ( totalRowSpan * totalColSpan ) == dimension; 
     501        } 
     502 
     503        function verticalSplitCell ( selection, isDetect ) 
     504        { 
     505                var cells = getSelectedCells( selection ); 
     506                if( cells.length > 1 ) 
     507                        return false; 
     508                else if( isDetect ) 
     509                        return true; 
     510                 
     511                var cell = cells[ 0 ], 
     512                        tr = cell.getParent(), 
     513                        table = tr.getAscendant( 'table' ), 
     514                        map = buildTableMap( table ), 
     515                        rowIndex = tr.$.rowIndex, 
     516                        colIndex = cellInRow( map, rowIndex, cell ), 
     517                        rowSpan = cell.$.rowSpan, 
     518                        newCell, 
     519                        newRowSpan, 
     520                        newCellRowSpan, 
     521                        newRowIndex; 
     522                 
     523                if( rowSpan > 1 ) 
     524                { 
     525                        newRowSpan = Math.ceil( rowSpan / 2 ); 
     526                        newCellRowSpan = Math.floor( rowSpan / 2 ); 
     527                        newRowIndex = rowIndex + newRowSpan; 
     528                        var newCellTr = new CKEDITOR.dom.element( table.$.rows[ newRowIndex ] ), 
     529                                newCellRow = cellInRow( map, newRowIndex ), 
     530                                candidateCell; 
     531                         
     532                        newCell = cell.clone(); 
     533 
     534                        // Figure out where to insert the new cell by checking the vitual row. 
     535                        for ( var c = 0; c < newCellRow.length; c++ ) 
     536                        { 
     537                                candidateCell = newCellRow[ c ]; 
     538                                // Catch first cell actually following the column. 
     539                                if( candidateCell.parentNode == newCellTr.$ 
     540                                        && c > colIndex ) 
     541                                { 
     542                                        newCell.insertBefore( new CKEDITOR.dom.element( candidateCell ) ); 
     543                                        break; 
     544                                } 
     545                                else 
     546                                        candidateCell = null; 
     547                        } 
     548 
     549                        // The destination row is empty, append at will. 
     550                        if( !candidateCell ) 
     551                                newCellTr.append( newCell, true ); 
     552                } 
     553                else 
     554                { 
     555                        newCellRowSpan = newRowSpan = 1; 
     556                        var newCellTr = tr.clone(); 
     557                        newCellTr.insertAfter( tr ); 
     558                        newCellTr.append( newCell = cell.clone() ); 
     559                        var cellsInSameRow = cellInRow( map, rowIndex ); 
     560                        for ( var i = 0; i < cellsInSameRow.length; i++ ) 
     561                                cellsInSameRow[ i ].rowSpan++; 
     562                } 
     563 
     564                if( !CKEDITOR.env.ie ) 
     565                        newCell.appendBogus(); 
     566 
     567                cell.$.rowSpan = newRowSpan; 
     568                newCell.$.rowSpan = newCellRowSpan; 
     569                if( newRowSpan == 1 ) 
     570                        cell.removeAttribute( 'rowSpan' ); 
     571                if( newCellRowSpan == 1 ) 
     572                        newCell.removeAttribute( 'rowSpan' ); 
     573 
     574                return newCell; 
     575        } 
     576 
     577        function horizontalSplitCell( selection, isDetect ) 
     578        { 
     579                var cells = getSelectedCells( selection ); 
     580                if( cells.length > 1 ) 
     581                        return false; 
     582                else if( isDetect ) 
     583                        return true; 
     584 
     585                var cell = cells[ 0 ], 
     586                        tr = cell.getParent(), 
     587                        table = tr.getAscendant( 'table' ), 
     588                        map = buildTableMap( table ), 
     589                        rowIndex = tr.$.rowIndex, 
     590                        colIndex = cellInRow( map, rowIndex, cell ), 
     591                        colSpan = cell.$.colSpan, 
     592                        newCell, 
     593                        newColSpan, 
     594                        newCellColSpan; 
     595 
     596                if( colSpan > 1 ) 
     597                { 
     598                        newColSpan = Math.ceil( colSpan / 2 ); 
     599                        newCellColSpan = Math.floor( colSpan / 2 ); 
     600                } 
     601                else 
     602                { 
     603                        newCellColSpan = newColSpan = 1; 
     604                        var cellsInSameCol = cellInCol( map, colIndex ); 
     605                        for ( var i = 0; i < cellsInSameCol.length; i++ ) 
     606                                cellsInSameCol[ i ].colSpan++; 
     607                } 
     608                newCell = cell.clone(); 
     609                newCell.insertAfter( cell ); 
     610                if( !CKEDITOR.env.ie ) 
     611                        newCell.appendBogus(); 
     612 
     613                cell.$.colSpan = newColSpan; 
     614                newCell.$.colSpan = newCellColSpan; 
     615                if( newColSpan == 1 ) 
     616                        cell.removeAttribute( 'colSpan' ); 
     617                if( newCellColSpan == 1 ) 
     618                        newCell.removeAttribute( 'colSpan' ); 
     619 
     620                return newCell; 
     621        } 
    419622        // Context menu on table caption incorrect (#3834) 
    420623        var contextMenuTags = { thead : 1, tbody : 1, tfoot : 1, td : 1, tr : 1, th : 1 }; 
     
    517720                                } ); 
    518721 
     722                        editor.addCommand( 'cellMerge', 
     723                                { 
     724                                        exec : function( editor ) 
     725                                        { 
     726                                                placeCursorInCell( mergeCells( editor.getSelection() ), true ); 
     727                                        } 
     728                                } ); 
     729 
     730                        editor.addCommand( 'cellMergeRight', 
     731                                { 
     732                                        exec : function( editor ) 
     733                                        { 
     734                                                placeCursorInCell( mergeCells( editor.getSelection(), 'right' ), true ); 
     735                                        } 
     736                                } ); 
     737 
     738                        editor.addCommand( 'cellMergeDown', 
     739                                { 
     740                                        exec : function( editor ) 
     741                                        { 
     742                                                placeCursorInCell( mergeCells( editor.getSelection(), 'down' ), true ); 
     743                                        } 
     744                                } ); 
     745 
     746                        editor.addCommand( 'cellVerticalSplit', 
     747                                { 
     748                                        exec : function( editor ) 
     749                                        { 
     750                                                placeCursorInCell( verticalSplitCell( editor.getSelection() ) ); 
     751                                        } 
     752                                } ); 
     753                         
     754                        editor.addCommand( 'cellHorizontalSplit', 
     755                                { 
     756                                        exec : function( editor ) 
     757                                        { 
     758                                                placeCursorInCell( horizontalSplitCell( editor.getSelection() ) ); 
     759                                        } 
     760                                } ); 
     761                         
    519762                        editor.addCommand( 'cellInsertBefore', 
    520763                                { 
     
    547790                                                        getItems : function() 
    548791                                                        { 
    549                                                                 var cells = getSelectedCells( editor.getSelection() ); 
     792                                                                var selection = editor.getSelection(), 
     793                                                                        cells = getSelectedCells( selection ); 
    550794                                                                return { 
    551795                                                                        tablecell_insertBefore : CKEDITOR.TRISTATE_OFF, 
    552796                                                                        tablecell_insertAfter : CKEDITOR.TRISTATE_OFF, 
    553797                                                                        tablecell_delete : CKEDITOR.TRISTATE_OFF, 
     798                                                                        tablecell_merge : mergeCells( selection, null, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 
     799                                                                        tablecell_merge_right : mergeCells( selection, 'right', true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 
     800                                                                        tablecell_merge_down : mergeCells( selection, 'down', true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 
     801                                                                        tablecell_split_vertical : verticalSplitCell( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 
     802                                                                        tablecell_split_horizontal : horizontalSplitCell( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 
    554803                                                                        tablecell_properties : cells.length > 0 ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED 
    555804                                                                }; 
     
    581830                                                }, 
    582831 
     832                                                tablecell_merge : 
     833                                                { 
     834                                                        label : lang.cell.merge, 
     835                                                        group : 'tablecell', 
     836                                                        command : 'cellMerge', 
     837                                                        order : 16 
     838                                                }, 
     839 
     840                                                tablecell_merge_right : 
     841                                                { 
     842                                                        label : lang.cell.mergeRight, 
     843                                                        group : 'tablecell', 
     844                                                        command : 'cellMergeRight', 
     845                                                        order : 17 
     846                                                }, 
     847 
     848                                                tablecell_merge_down : 
     849                                                { 
     850                                                        label : lang.cell.mergeDown, 
     851                                                        group : 'tablecell', 
     852                                                        command : 'cellMergeDown', 
     853                                                        order : 18 
     854                                                }, 
     855 
     856                                                tablecell_split_horizontal : 
     857                                                { 
     858                                                        label : lang.cell.splitHorizontal, 
     859                                                        group : 'tablecell', 
     860                                                        command : 'cellHorizontalSplit', 
     861                                                        order : 19 
     862                                                }, 
     863 
     864                                                tablecell_split_vertical : 
     865                                                { 
     866                                                        label : lang.cell.splitVertical, 
     867                                                        group : 'tablecell', 
     868                                                        command : 'cellVerticalSplit', 
     869                                                        order : 20 
     870                                                }, 
     871 
    583872                                                tablecell_properties : 
    584873                                                { 
     
    586875                                                        group : 'tablecellproperties', 
    587876                                                        command : 'cellProperties', 
    588                                                         order : 20 
     877                                                        order : 21 
    589878                                                }, 
    590879 
Note: See TracChangeset for help on using the changeset viewer.
© 2003 – 2012 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy