Ticket #5268: 5268_3.patch

File 5268_3.patch, 12.8 KB (added by Garry Yao, 9 years ago)
  • _source/plugins/tableresize/plugin.js

     
     1/*
     2Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
     3For licensing, see LICENSE.html or http://ckeditor.com/license
     4*/
     5
     6( function()
     7{
     8        var pxUnit = CKEDITOR.tools.cssLength;
     9
     10        function getCellWidth( cell )
     11        {
     12                return CKEDITOR.env.ie ? cell.$.clientWidth : parseInt( cell.getComputedStyle( 'width' ), 10 );
     13        }
     14
     15        function getCellBorderWidth( cell, side )
     16        {
     17                var computed = cell.getComputedStyle( 'border-' + side + '-width' ),
     18                        borderMap =
     19                        {
     20                                thin: '2px',
     21                                medium: '4px',
     22                                thick: '6px'
     23                        };
     24
     25                if ( computed.indexOf( 'px' ) < 0 )
     26                {
     27                        // look up keywords
     28                        if ( computed in borderMap && cell.getComputedStyle( 'border-style' ) != 'none' )
     29                                computed = borderMap[ computed ];
     30                        else
     31                                computed = 0;
     32                }
     33
     34                return computed;
     35        }
     36
     37        function buildTableColumnPillars( tableElement )
     38        {
     39                var table = tableElement.$;
     40
     41                // Elect the table row that contains the most columns.
     42                var maxCells = 0, elected;
     43                for ( var i = 0, rowCount = table.rows.length ; i < rowCount; i++ )
     44                {
     45                        var tr = table.rows[ i ], cellsCount = tr.cells.length;
     46
     47                        if ( cellsCount > maxCells )
     48                        {
     49                                maxCells = cellsCount;
     50                                elected = tr;
     51                        }
     52                }
     53               
     54                tr = elected;
     55                var columnIndex = -1, pillars = [];
     56                var tbody = new CKEDITOR.dom.element( table.tBodies[ 0 ] ),
     57                                tbodyPosition = tbody.getDocumentPosition();
     58                for ( var j = 0, colCount = tr.cells.length ; j < colCount ; j++ )
     59                {
     60                        var td = new CKEDITOR.dom.element( tr.cells[ j ] ),
     61                                        nextTd = tr.cells[ j + 1 ] && new CKEDITOR.dom.element( tr.cells[ j + 1 ] );
     62
     63                        columnIndex += td.$.colSpan || 1;
     64                        var cellPosition =  td.getDocumentPosition(),
     65                                        rangeLeft = cellPosition.x + td.$.offsetWidth - parseInt( getCellBorderWidth ( td, 'right' ), 10 );
     66
     67                        if ( nextTd )
     68                        {
     69                                cellPosition =  nextTd.getDocumentPosition();
     70                                var rangeRight = cellPosition.x + parseInt( getCellBorderWidth( nextTd, 'left' ), 10 );
     71
     72                                // Compsensate for too "slim" line between columns, make the pillar shown easier.
     73                                if ( rangeRight - rangeLeft < 8 )
     74                                {
     75                                        rangeLeft-= 4;
     76                                        rangeRight += 4;
     77                                }
     78
     79                                var columnWidth = rangeRight - rangeLeft;
     80
     81                                // The pillar should reflects exactly the shape of the hovered column border line.
     82                                pillars.push({ table : tableElement, index : columnIndex, x : rangeLeft, y : tbodyPosition.y , width : columnWidth, height: tbody.$.offsetHeight });
     83                        }
     84                }
     85
     86                return pillars;
     87        }
     88
     89        function getPillarAtPosition( pillars, position )
     90        {
     91                for ( var i = 0, length = pillars.length; i < length; i++ )
     92                {
     93                        if ( position.x > pillars[ i ].x && position.x - pillars[ i ].x < pillars[ i ].width )
     94                                return pillars[ i ];
     95                }
     96                return null;
     97        }
     98
     99        function cancel( evt )
     100        {
     101                evt.data.preventDefault();
     102        }
     103       
     104        function columnResizer( editor )
     105        {
     106                var pillar, document, resizer, startOffset, currentShift;
     107               
     108                var leftSideCells, rightSideCells, leftShiftBoundary, rightShiftBoundary;
     109               
     110                function detach()
     111                {
     112                        pillar = null;
     113                        currentShift = null;
     114                        document.removeListener( 'mousemove', onMouseMove );
     115                        document.removeListener( 'mouseup', onMouseUp );
     116                        resizer.removeListener( 'mousedown', onMouseDown );
     117                        resizer.removeListener( 'mouseout', onMouseOut );
     118                        resizer.hide();
     119                }
     120               
     121                function resizeStart()
     122                {
     123                        // Before starting to resize, figure out which cells to change
     124                        // and the boundaries of this resizing shift.
     125                        var columnIndex = pillar.index,
     126                                        map = CKEDITOR.tools.buildTableMap( pillar.table ),
     127                                        leftColumnCells = [],
     128                                        rightColumnCells= [],
     129                                        leftMinSize =  Number.MAX_VALUE,
     130                                        rightMinSize = leftMinSize;
     131
     132                        for ( var i = 0, rowCount = map.length; i < rowCount; i++ )
     133                        {
     134                                var row = map[ i ],
     135                                                leftCell = new CKEDITOR.dom.element( row[ columnIndex ] ),
     136                                                rightCell = new CKEDITOR.dom.element( row[ columnIndex + 1 ] );
     137
     138                                if ( !leftCell.equals( rightCell ) )
     139                                {
     140                                        leftMinSize = Math.min( leftMinSize, getCellWidth( leftCell ) );
     141                                        rightMinSize = Math.min( rightMinSize, getCellWidth( rightCell ) );
     142                                        leftColumnCells.push( leftCell );
     143                                        rightColumnCells.push( rightCell );
     144                                }
     145                        }
     146
     147                        leftSideCells = leftColumnCells;
     148                        rightSideCells = rightColumnCells;
     149                        leftShiftBoundary =  pillar.x - leftMinSize;
     150                        rightShiftBoundary = pillar.x + rightMinSize;
     151                       
     152                        resizer.setOpacity( 0.5 );
     153                        startOffset = parseInt( resizer.getStyle( 'left' ), 10 );
     154                        currentShift = 0;
     155                        document.on( 'mousemove', onMouseMove, this );
     156                        // Prevent the native drag behavior otherwise the above 'mousemove' won't fired.
     157                        document.on( 'dragstart', cancel, this );
     158                }
     159               
     160                function resizeEnd()
     161                {
     162                        resizer.setOpacity( 0 );
     163                        currentShift && resizeColumn();
     164                       
     165                        var table = pillar.table;
     166                        setTimeout( function () { table.removeCustomData( '_cke_table_pillars' ); }, 0 );
     167
     168                        detach();
     169                }
     170               
     171                function resizeColumn()
     172                {
     173                        // Perform the actual resize to table cells, only for those by side of the pillar.
     174                        for ( var i = 0, count = leftSideCells.length; i < count; i++ )
     175                        {
     176                                var leftCell = leftSideCells[ i ],
     177                                                rightCell = rightSideCells[ i ];
     178
     179                                // Defer the resizing to avoid any interference among cells.
     180                                ( function( leftCell, leftOldWidth, rightCell, rightOldWidth, sizeShift )
     181                                {
     182                                        CKEDITOR.tools.setTimeout( function()
     183                                        {
     184                                                leftCell.setStyle( 'width', pxUnit(  leftOldWidth + sizeShift ) );
     185                                                rightCell.setStyle( 'width', pxUnit(  rightOldWidth - sizeShift ) );
     186
     187                                        }, 0, this );
     188
     189                                }).call( this, leftCell, getCellWidth( leftCell ),
     190                                                rightCell, getCellWidth( rightCell ), currentShift );
     191                        }
     192                }
     193               
     194                function onMouseMove( evt )
     195                {
     196                        var mouseOffset = evt.data.$.clientX,
     197                                        resizerNewPosition = mouseOffset - Math.round( parseInt( resizer.getComputedStyle( 'width' ), 10 ) / 2 );
     198
     199                        // Boundaries checking.
     200                        if ( resizerNewPosition > leftShiftBoundary && resizerNewPosition < rightShiftBoundary )
     201                        {
     202                                resizer.setStyle( 'left', pxUnit( resizerNewPosition ) );
     203                                currentShift = resizerNewPosition - startOffset;
     204                        }
     205
     206                        cancel( evt );
     207                }
     208               
     209                function onMouseDown( evt )
     210                {
     211                        cancel( evt );
     212                        resizeStart();
     213                        document.on( 'mouseup', onMouseUp, this );
     214                }
     215               
     216                function onMouseUp()
     217                {
     218                        resizeEnd();
     219                }
     220               
     221                function onMouseOut()
     222                {
     223                        // Don't detach during resizing.
     224                        !currentShift && detach();
     225                }
     226               
     227                document = editor.document;
     228                resizer = CKEDITOR.dom.element.createFromHtml( '<div style="position: absolute; cursor: col-resize; ' +
     229                        'filter:alpha(opacity=0);opacity:0;padding:0;background-color:#004;background-image:none;border: 0px none;"></div>' );
     230
     231                // Place the resizer after body to prevent it from being editable.
     232                document.getDocumentElement().append( resizer );
     233                this.attachTo = function( targetPillar )
     234                {
     235                        // Accept only one pillar at a time.
     236                        if ( currentShift )
     237                                return;
     238
     239                        pillar = targetPillar;
     240                        resizer.setStyles(
     241                        {
     242                                width: pxUnit( targetPillar.width ),
     243                                height : pxUnit( targetPillar.height ),
     244                                left : pxUnit( targetPillar.x ),
     245                                top : pxUnit( targetPillar.y )
     246                        });
     247
     248                        resizer.on( 'mousedown', onMouseDown, this );
     249                        resizer.on( 'mouseout', onMouseOut, this );
     250
     251                        // Display the resizer to receive events but don't show it,
     252                        // only change the cursor to resizable shape.
     253                        resizer.show();
     254                };
     255        }
     256
     257        function clearPillarsCache( evt )
     258        {
     259                var target = evt.data.getTarget();
     260
     261                if ( evt.name == 'mouseout' )
     262                {
     263                        // Bypass interal mouse move.
     264                        if ( !target.is ( 'table' ) )
     265                                return;
     266
     267                        var dest = new CKEDITOR.dom.element( evt.data.$.relatedTarget || evt.data.$.toElement );
     268                        while( dest && !dest.equals( target ) && !dest.is( 'body' ) )
     269                                dest = dest.getParent();
     270                        if ( !dest || dest.equals( target ) )
     271                                return;
     272                }
     273               
     274                target.getAscendant( 'table', true ).removeCustomData( '_cke_table_pillars' );
     275                evt && evt.removeListener();
     276        }
     277
     278        CKEDITOR.plugins.add( 'tableresize',
     279        {
     280                requires : [ 'tabletools' ],
     281                init : function( editor )
     282                {
     283                        editor.on( 'contentDom', function ()
     284                        {
     285                                var resizer;
     286                                editor.document.getBody().on( 'mousemove', function( evt )
     287                                {
     288                                        evt = evt.data;
     289
     290                                        // Considering table, tr, td, tbody but nothing else.
     291                                        var target = evt.getTarget();
     292                                        if ( !( target.is( 'table' ) || target.getAscendant( 'tbody', true ) ) )
     293                                                return;
     294
     295                                        var table = target.getAscendant( 'table', true ),
     296                                                        pillars;
     297
     298                                        if ( !( pillars = table.getCustomData( '_cke_table_pillars' ) ) )
     299                                        {
     300                                                // Cache table pillars caculation result.
     301                                                table.setCustomData( '_cke_table_pillars', ( pillars = buildTableColumnPillars( table ) ) );
     302                                                table.on( 'mouseout', clearPillarsCache );
     303                                                table.on( 'mousedown', clearPillarsCache );
     304                                        }
     305
     306                                        var pillar = getPillarAtPosition( pillars, { x : evt.$.clientX, y : evt.$.clientY } );
     307                                        if ( pillar )
     308                                        {
     309                                                !resizer && ( resizer = new columnResizer( editor ) );
     310                                                resizer.attachTo( pillar );
     311                                        }
     312                                });
     313                        });
     314                }
     315        });
     316
     317} )( );
  • _source/plugins/tabletools/plugin.js

     
    400400                range.select( true );
    401401        }
    402402
    403         function buildTableMap( table )
    404         {
    405 
    406                 var aRows = table.$.rows ;
    407 
    408                 // Row and Column counters.
    409                 var r = -1 ;
    410 
    411                 var aMap = [];
    412 
    413                 for ( var i = 0 ; i < aRows.length ; i++ )
    414                 {
    415                         r++ ;
    416                         !aMap[r] && ( aMap[r] = [] );
    417 
    418                         var c = -1 ;
    419 
    420                         for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
    421                         {
    422                                 var oCell = aRows[i].cells[j] ;
    423 
    424                                 c++ ;
    425                                 while ( aMap[r][c] )
    426                                         c++ ;
    427 
    428                                 var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
    429                                 var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
    430 
    431                                 for ( var rs = 0 ; rs < iRowSpan ; rs++ )
    432                                 {
    433                                         if ( !aMap[r + rs] )
    434                                                 aMap[r + rs] = new Array() ;
    435 
    436                                         for ( var cs = 0 ; cs < iColSpan ; cs++ )
    437                                         {
    438                                                 aMap[r + rs][c + cs] = aRows[i].cells[j] ;
    439                                         }
    440                                 }
    441 
    442                                 c += iColSpan - 1 ;
    443                         }
    444                 }
    445                 return aMap ;
    446         }
    447 
    448403        function cellInRow( tableMap, rowIndex, cell )
    449404        {
    450405                var oRow = tableMap[ rowIndex ];
     
    498453                var     cell,
    499454                        firstCell = cells[ 0 ],
    500455                        table = firstCell.getAscendant( 'table' ),
    501                         map = buildTableMap( table ),
     456                        map = CKEDITOR.tools.buildTableMap( table ),
    502457                        mapHeight = map.length,
    503458                        mapWidth = map[ 0 ].length,
    504459                        startRow = firstCell.getParent().$.rowIndex,
     
    633588                var cell = cells[ 0 ],
    634589                        tr = cell.getParent(),
    635590                        table = tr.getAscendant( 'table' ),
    636                         map = buildTableMap( table ),
     591                        map = CKEDITOR.tools.buildTableMap( table ),
    637592                        rowIndex = tr.$.rowIndex,
    638593                        colIndex = cellInRow( map, rowIndex, cell ),
    639594                        rowSpan = cell.$.rowSpan,
     
    709664                var cell = cells[ 0 ],
    710665                        tr = cell.getParent(),
    711666                        table = tr.getAscendant( 'table' ),
    712                         map = buildTableMap( table ),
     667                        map = CKEDITOR.tools.buildTableMap( table ),
    713668                        rowIndex = tr.$.rowIndex,
    714669                        colIndex = cellInRow( map, rowIndex, cell ),
    715670                        colSpan = cell.$.colSpan,
     
    11141069        };
    11151070        CKEDITOR.plugins.add( 'tabletools', CKEDITOR.plugins.tabletools );
    11161071})();
     1072
     1073/**
     1074 * Create a two-dimension array that reflects the actual layout of table cells,
     1075 * with cell spans, with mappings to the original td elements.
     1076 * @param table {CKEDITOR.dom.element}
     1077 */
     1078CKEDITOR.tools.buildTableMap = function ( table )
     1079{
     1080        var aRows = table.$.rows ;
     1081
     1082        // Row and Column counters.
     1083        var r = -1 ;
     1084
     1085        var aMap = [];
     1086
     1087        for ( var i = 0 ; i < aRows.length ; i++ )
     1088        {
     1089                r++ ;
     1090                !aMap[r] && ( aMap[r] = [] );
     1091
     1092                var c = -1 ;
     1093
     1094                for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
     1095                {
     1096                        var oCell = aRows[i].cells[j] ;
     1097
     1098                        c++ ;
     1099                        while ( aMap[r][c] )
     1100                                c++ ;
     1101
     1102                        var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
     1103                        var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
     1104
     1105                        for ( var rs = 0 ; rs < iRowSpan ; rs++ )
     1106                        {
     1107                                if ( !aMap[r + rs] )
     1108                                        aMap[r + rs] = [];
     1109
     1110                                for ( var cs = 0 ; cs < iColSpan ; cs++ )
     1111                                {
     1112                                        aMap[r + rs][c + cs] = aRows[i].cells[j] ;
     1113                                }
     1114                        }
     1115
     1116                        c += iColSpan - 1 ;
     1117                }
     1118        }
     1119        return aMap ;
     1120};
     1121
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy