Ticket #4574: 4574_3.patch

File 4574_3.patch, 17.7 KB (added by Garry Yao, 10 years ago)
  • _source/plugins/menu/plugin.js

     
    6767                        {
    6868                                var menu = this._.subMenu,
    6969                                        item = this.items[ index ],
    70                                         subItems = item.getItems && item.getItems();
     70                                        subItemDefs = item.getItems && item.getItems();
    7171
    7272                                // If this item has no subitems, we just hide the submenu, if
    7373                                // available, and return back.
    74                                 if ( !subItems )
     74                                if ( !subItemDefs )
    7575                                {
    7676                                        this._.panel.hideChild();
    7777                                        return;
     
    8989                                }
    9090
    9191                                // Add all submenu items to the menu.
    92                                 for ( var itemName in subItems )
     92                                for ( var subItemName in subItemDefs )
    9393                                {
    94                                         menu.add( this.editor.getMenuItem( itemName ) );
    95                                 }
     94                                        var subItem = this.editor.getMenuItem( subItemName );
     95                                        if ( subItem )
     96                                        {
     97                                                subItem.state = subItemDefs[ subItemName ];
     98                                                menu.add( subItem );
     99                                        }
     100                                }
    96101
    97102                                // Get the element representing the current item.
    98103                                var element = this._.panel.getBlock( this.id ).element.getDocument().getById( this.id + String( index ) );
  • _source/plugins/tabletools/plugin.js

     
    8686                return retval;
    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        {
    24391                // Get the array of row's cells.
     
    416264                }
    417265        }
    418266
     267        function isEmptyCell( cell )
     268        {
     269                var children = cell.getChildren(),
     270                        lastChild;
     271
     272                if( !children.count() )
     273                        return true;
     274                else if( !CKEDITOR.env.ie )
     275                {
     276                        return children.count() == 1
     277                                  && ( lastChild = children.getItem( 0 ) )
     278                                  && lastChild.is && lastChild.is( 'br' );
     279                }
     280        }
     281
     282        function placeCursorInCell( cell )
     283        {
     284                var range = new CKEDITOR.dom.range( cell.getDocument() );
     285                range.selectNodeContents( cell );
     286                range.collapse();
     287                range.select( true );
     288        }
     289
     290        function buildTableMap( table )
     291        {
     292
     293                var aRows = table.$.rows ;
     294
     295                // Row and Column counters.
     296                var r = -1 ;
     297
     298                var aMap = [];
     299
     300                for ( var i = 0 ; i < aRows.length ; i++ )
     301                {
     302                        r++ ;
     303                        !aMap[r] && ( aMap[r] = [] );
     304
     305                        var c = -1 ;
     306
     307                        for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
     308                        {
     309                                var oCell = aRows[i].cells[j] ;
     310
     311                                c++ ;
     312                                while ( aMap[r][c] )
     313                                        c++ ;
     314
     315                                var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
     316                                var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
     317
     318                                for ( var rs = 0 ; rs < iRowSpan ; rs++ )
     319                                {
     320                                        if ( !aMap[r + rs] )
     321                                                aMap[r + rs] = new Array() ;
     322
     323                                        for ( var cs = 0 ; cs < iColSpan ; cs++ )
     324                                        {
     325                                                aMap[r + rs][c + cs] = aRows[i].cells[j] ;
     326                                        }
     327                                }
     328
     329                                c += iColSpan - 1 ;
     330                        }
     331                }
     332                return aMap ;
     333        }
     334
     335        function cellInRow( tableMap, rowIndex, cell )
     336        {
     337                var oRow = tableMap[ rowIndex ];
     338                if( typeof cell == 'undefined' )
     339                        return oRow;
     340
     341                for ( var c = 0 ; oRow && c < oRow.length ; c++ )
     342                {
     343                        if ( cell.is && oRow[c] == cell.$ )
     344                                return c;
     345                        else if( c == cell )
     346                                return new CKEDITOR.dom.element( oRow[ c ] );
     347                }
     348                return cell.is ? -1 : null;
     349        }
     350
     351        function cellInCol( tableMap, colIndex, cell )
     352        {
     353                var oCol = [];
     354                for ( var r = 0; r < tableMap.length; r++ )
     355                {
     356                        var row = tableMap[ r ];
     357                        if( typeof cell == 'undefined' )
     358                                oCol.push( row[ colIndex ] );
     359                        else if( cell.is && row[ colIndex ] == cell.$ )
     360                                return r;
     361                        else if( r == cell )
     362                                return new CKEDITOR.dom.element( row[ colIndex ] );
     363                }
     364               
     365                return ( typeof cell == 'undefined' )? oCol : cell.is ? -1 :  null;
     366        }
     367
     368        function mergeCells( selection, isDetect )
     369        {
     370                var cells = getSelectedCells( selection );
     371
     372                // Disable the merge if:
     373                // 1. Single cell selected.
     374                // 2. Cells distributed in different groups.
     375                if( cells.length < 2 || selection.getCommonAncestor().is( 'table' ) )
     376                        return false;
     377
     378                var     cell,
     379                        firstCell = cells[ 0 ],
     380                        table = firstCell.getAscendant( 'table' ),
     381                        doc = firstCell.getDocument(),
     382                        map = buildTableMap( table ),
     383                        mapHeight = map.length,
     384                        mapWidth = map[ 0 ].length,
     385                        startRow = firstCell.getParent().$.rowIndex,
     386                        startColumn = cellInRow( map, startRow, firstCell ),
     387                        lastRowIndex = startRow,
     388                        totalRowSpan = 0,
     389                        totalColSpan = 0,
     390                        // Use a documentFragment as buffer when appending cell contents.
     391                        frag = !isDetect && new CKEDITOR.dom.documentFragment( doc ),
     392                        dimension = 0;
     393
     394                for ( var i = 0; i < cells.length; i++ )
     395                {
     396                        cell = cells[ i ];
     397
     398                        var tr = cell.getParent(),
     399                                cellFirstChild = cell.getFirst(),
     400                                colSpan = cell.$.colSpan,
     401                                rowSpan = cell.$.rowSpan,
     402                                rowIndex = tr.$.rowIndex,
     403                                colIndex = cellInRow( map, rowIndex, cell );
     404
     405                        // Accumulated the actual places taken by all selected cells.
     406                        dimension += colSpan * rowSpan;
     407                        // Accumulated the maximum virtual spans from column and row.
     408                        totalColSpan = Math.max( totalColSpan, colIndex - startColumn + colSpan ) ;
     409                        totalRowSpan = Math.max( totalRowSpan, rowIndex - startRow + rowSpan );
     410
     411                        if ( !isDetect )
     412                        {
     413                                // Simpily remove empty cells.
     414                                if( cell.trim(), !isEmptyCell( cell ) )
     415                                {
     416                                        // Merge vertically cells as two separated paragraphs.
     417                                        if( rowIndex != lastRowIndex
     418                                                && cellFirstChild
     419                                                && !( cellFirstChild.isBlockBoundary
     420                                                          && cellFirstChild.isBlockBoundary( { br : 1 } ) ) )
     421                                        {
     422                                                var last = frag.getLast( CKEDITOR.dom.walker.whitespaces( true ) );
     423                                                if( last && !( last.is && last.is( 'br' ) ) )
     424                                                        frag.append( new CKEDITOR.dom.element( 'br' ) );
     425                                        }
     426
     427                                        cell.moveChildren( frag );
     428                                }
     429                                i ? cell.remove() : cell.setHtml( '' );
     430                        }
     431                        lastRowIndex = rowIndex;
     432                }
     433
     434                if ( !isDetect )
     435                {
     436                        frag.moveChildren( firstCell );
     437
     438                        if( totalColSpan >= mapWidth )
     439                                firstCell.removeAttribute( 'rowSpan' );
     440                        else
     441                                firstCell.$.rowSpan = totalRowSpan;
     442
     443                        if( totalRowSpan >= mapHeight )
     444                                firstCell.removeAttribute( 'colSpan' );
     445                        else
     446                                firstCell.$.colSpan = totalColSpan;
     447
     448                        // Swip empty <tr> left at the end of table due to the merging.
     449                        var trs = new CKEDITOR.dom.nodeList( table.$.rows ),
     450                                count = trs.count();
     451
     452                        for ( var i = count - 1; i >= 0; i-- )
     453                        {
     454                                var tailTr = trs.getItem( i );
     455                                if( !tailTr.$.cells.length )
     456                                {
     457                                        tailTr.remove();
     458                                        count++;
     459                                        continue;
     460                                }
     461                                else
     462                                        break;
     463                        }
     464
     465                        return firstCell;
     466                }
     467                // Be able to merge cells only if actual dimension of selected
     468                // cells equals to the caculated rectangle.
     469                else
     470                        return ( totalRowSpan * totalColSpan ) == dimension;
     471        }
     472
     473        function verticalSplitCell ( selection, isDetect )
     474        {
     475                var cells = getSelectedCells( selection );
     476                if( cells.length > 1 )
     477                        return false;
     478                else if( isDetect )
     479                        return true;
     480               
     481                var cell = cells[ 0 ],
     482                        tr = cell.getParent(),
     483                        table = tr.getAscendant( 'table' ),
     484                        map = buildTableMap( table ),
     485                        rowIndex = tr.$.rowIndex,
     486                        colIndex = cellInRow( map, rowIndex, cell ),
     487                        rowSpan = cell.$.rowSpan,
     488                        newCell,
     489                        newRowSpan,
     490                        newCellRowSpan,
     491                        newRowIndex;
     492               
     493                if( rowSpan > 1 )
     494                {
     495                        newRowSpan = Math.ceil( rowSpan / 2 );
     496                        newCellRowSpan = Math.floor( rowSpan / 2 );
     497                        newRowIndex = rowIndex + newRowSpan;
     498                        var newCellTr = new CKEDITOR.dom.element( table.$.rows[ newRowIndex ] ),
     499                                newCellRow = cellInRow( map, newRowIndex ),
     500                                candidateCell;
     501                       
     502                        newCell = cell.clone();
     503
     504                        // Figure out where to insert the new cell by checking the vitual row.
     505                        for ( var c = 0; c < newCellRow.length; c++ )
     506                        {
     507                                candidateCell = newCellRow[ c ];
     508                                // Catch first cell actually following the column.
     509                                if( candidateCell.parentNode == newCellTr.$
     510                                        && c > colIndex )
     511                                {
     512                                        newCell.insertBefore( new CKEDITOR.dom.element( candidateCell ) );
     513                                        break;
     514                                }
     515                                else
     516                                        candidateCell = null;
     517                        }
     518
     519                        // The destination row is empty, append at will.
     520                        if( !candidateCell )
     521                                newCellTr.append( newCell, true );
     522                }
     523                else
     524                {
     525                        newCellRowSpan = newRowSpan = 1;
     526                        var newCellTr = tr.clone();
     527                        newCellTr.insertAfter( tr );
     528                        newCellTr.append( newCell = cell.clone() );
     529                        var cellsInSameRow = cellInRow( map, rowIndex );
     530                        for ( var i = 0; i < cellsInSameRow.length; i++ )
     531                                cellsInSameRow[ i ].rowSpan++;
     532                }
     533
     534                if( !CKEDITOR.env.ie )
     535                        newCell.appendBogus();
     536                cell.$.rowSpan = newRowSpan;
     537                newCell.$.rowSpan = newCellRowSpan;
     538                if( newRowSpan == 1 )
     539                        cell.removeAttribute( 'rowSpan' );
     540                if( newCellRowSpan == 1 )
     541                        newCell.removeAttribute( 'rowSpan' );
     542
     543                return newCell;
     544        }
     545
     546        function horizontalSplitCell( selection, isDetect )
     547        {
     548                var cells = getSelectedCells( selection );
     549                if( cells.length > 1 )
     550                        return false;
     551                else if( isDetect )
     552                        return true;
     553
     554                var cell = cells[ 0 ],
     555                        tr = cell.getParent(),
     556                        table = tr.getAscendant( 'table' ),
     557                        map = buildTableMap( table ),
     558                        rowIndex = tr.$.rowIndex,
     559                        colIndex = cellInRow( map, rowIndex, cell ),
     560                        colSpan = cell.$.colSpan,
     561                        newCell,
     562                        newColSpan,
     563                        newCellColSpan;
     564
     565                if( colSpan > 1 )
     566                {
     567                        newColSpan = Math.ceil( colSpan / 2 );
     568                        newCellColSpan = Math.floor( colSpan / 2 );
     569                }
     570                else
     571                {
     572                        newCellColSpan = newColSpan = 1;
     573                        var cellsInSameCol = cellInCol( map, colIndex );
     574                        for ( var i = 0; i < cellsInSameCol.length; i++ )
     575                                cellsInSameCol[ i ].colSpan++;
     576                }
     577                newCell = cell.clone();
     578                newCell.insertAfter( cell );
     579                if( !CKEDITOR.env.ie )
     580                        newCell.appendBogus();
     581
     582                cell.$.colSpan = newColSpan;
     583                newCell.$.colSpan = newCellColSpan;
     584                if( newColSpan == 1 )
     585                        cell.removeAttribute( 'colSpan' );
     586                if( newCellColSpan == 1 )
     587                        newCell.removeAttribute( 'colSpan' );
     588
     589                return newCell;
     590        }
    419591        // Context menu on table caption incorrect (#3834)
    420592        var contextMenuTags = { thead : 1, tbody : 1, tfoot : 1, td : 1, tr : 1, th : 1 };
    421593
     
    516688                                        }
    517689                                } );
    518690
     691                        editor.addCommand( 'cellMerge',
     692                                {
     693                                        exec : function( editor )
     694                                        {
     695                                                placeCursorInCell( mergeCells( editor.getSelection() ) );
     696                                        }
     697                                } );
     698
     699                        editor.addCommand( 'cellVerticalSplit',
     700                                {
     701                                        exec : function( editor )
     702                                        {
     703                                                placeCursorInCell( verticalSplitCell( editor.getSelection() ) );
     704                                        }
     705                                } );
     706                       
     707                        editor.addCommand( 'cellHorizontalSplit',
     708                                {
     709                                        exec : function( editor )
     710                                        {
     711                                                placeCursorInCell( horizontalSplitCell( editor.getSelection() ) );
     712                                        }
     713                                } );
     714                       
    519715                        editor.addCommand( 'cellInsertBefore',
    520716                                {
    521717                                        exec : function( editor )
     
    546742                                                        order : 1,
    547743                                                        getItems : function()
    548744                                                        {
    549                                                                 var cells = getSelectedCells( editor.getSelection() );
     745                                                                var selection = editor.getSelection(),
     746                                                                        cells = getSelectedCells( selection );
    550747                                                                return {
    551748                                                                        tablecell_insertBefore : CKEDITOR.TRISTATE_OFF,
    552749                                                                        tablecell_insertAfter : CKEDITOR.TRISTATE_OFF,
    553750                                                                        tablecell_delete : CKEDITOR.TRISTATE_OFF,
     751                                                                        tablecell_merge : mergeCells( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
     752                                                                        tablecell_split_vertical : verticalSplitCell( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
     753                                                                        tablecell_split_horizontal : horizontalSplitCell( selection, true ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
    554754                                                                        tablecell_properties : cells.length > 0 ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED
    555755                                                                };
    556756                                                        }
     
    580780                                                        order : 15
    581781                                                },
    582782
     783                                                tablecell_merge :
     784                                                {
     785                                                        label : lang.cell.merge,
     786                                                        group : 'tablecell',
     787                                                        command : 'cellMerge',
     788                                                        order : 16
     789                                                },
     790
     791                                                tablecell_split_horizontal :
     792                                                {
     793                                                        label : lang.cell.splitHorizontal,
     794                                                        group : 'tablecell',
     795                                                        command : 'cellHorizontalSplit',
     796                                                        order : 17
     797                                                },
     798
     799                                                tablecell_split_vertical :
     800                                                {
     801                                                        label : lang.cell.splitVertical,
     802                                                        group : 'tablecell',
     803                                                        command : 'cellVerticalSplit',
     804                                                        order : 18
     805                                                },
     806
    583807                                                tablecell_properties :
    584808                                                {
    585809                                                        label : lang.cell.title,
  • _source/plugins/selection/plugin.js

     
    152152                                                // inside a selection. We don't want to capture that.
    153153                                                doc.on( 'mousedown', disableSave );
    154154                                                doc.on( 'mouseup',
    155                                                         function()
     155                                                        function( evt )
    156156                                                        {
     157                                                                // IE contextmenu event in table cells collapse
     158                                                                // whatever selection is, avoding saving the last
     159                                                                // 'wrong' snapshot.(#3001)
     160                                                                var target = evt.data.getTarget();
     161                                                                if ( evt.data.$.button == 2
     162                                                                         && target.is
     163                                                                         && target.getName() in CKEDITOR.dtd.$tableContent )
     164                                                                                return;
     165
    157166                                                                saveEnabled = true;
    158167                                                                setTimeout( function()
    159168                                                                        {
     
    939948                        }
    940949                        this.selectRanges( ranges );
    941950                        return this;
     951                },
     952
     953                getCommonAncestor : function()
     954                {
     955                        var ranges = this.getRanges(),
     956                                startNode = ranges[ 0 ].startContainer,
     957                                endNode = ranges[ ranges.length - 1 ].endContainer;
     958                        return startNode.getCommonAncestor( endNode );
    942959                }
    943960        };
    944961})();
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy