Changeset 435

Show
Ignore:
Timestamp:
2007-07-11 11:48:06 (17 months ago)
Author:
martinkou
Message:

Fixed table operation crashes in Gecko while multiple table cells are selected.
Fix for #109 : Implemented before/after insertion for table cells, rows and columns.

Location:
FCKeditor/trunk/editor
Files:
11 modified

Legend:

Unmodified
Added
Removed
  • FCKeditor/trunk/editor/lang/en-au.js

    r215 r435  
    110110RowCM                           : "Row", 
    111111ColumnCM                        : "Column", 
    112 InsertRow                       : "Insert Row", 
     112InsertRowAfter                  : "Insert Row After", 
     113InsertRowBefore                 : "Insert Row Before", 
    113114DeleteRows                      : "Delete Rows", 
    114 InsertColumn            : "Insert Column", 
     115InsertColumnAfter               : "Insert Column After", 
     116InsertColumnBefore              : "Insert Column Before", 
    115117DeleteColumns           : "Delete Columns", 
    116 InsertCell                      : "Insert Cell", 
     118InsertCellAfter                 : "Insert Cell After", 
     119InsertCellBefore                : "Insert Cell Before", 
    117120DeleteCells                     : "Delete Cells", 
    118121MergeCells                      : "Merge Cells", 
  • FCKeditor/trunk/editor/lang/en-ca.js

    r215 r435  
    110110RowCM                           : "Row", 
    111111ColumnCM                        : "Column", 
    112 InsertRow                       : "Insert Row", 
     112InsertRowAfter                  : "Insert Row After", 
     113InsertRowBefore                 : "Insert Row Before", 
    113114DeleteRows                      : "Delete Rows", 
    114 InsertColumn            : "Insert Column", 
     115InsertColumnAfter               : "Insert Column After", 
     116InsertColumnBefore              : "Insert Column Before", 
    115117DeleteColumns           : "Delete Columns", 
    116 InsertCell                      : "Insert Cell", 
     118InsertCellAfter                 : "Insert Cell After", 
     119InsertCellBefore                : "Insert Cell Before", 
    117120DeleteCells                     : "Delete Cells", 
    118121MergeCells                      : "Merge Cells", 
  • FCKeditor/trunk/editor/lang/en.js

    r174 r435  
    110110RowCM                           : "Row", 
    111111ColumnCM                        : "Column", 
    112 InsertRow                       : "Insert Row", 
     112InsertRowAfter                  : "Insert Row After", 
     113InsertRowBefore                 : "Insert Row Before", 
    113114DeleteRows                      : "Delete Rows", 
    114 InsertColumn            : "Insert Column", 
     115InsertColumnAfter               : "Insert Column After", 
     116InsertColumnBefore              : "Insert Column Before", 
    115117DeleteColumns           : "Delete Columns", 
    116 InsertCell                      : "Insert Cell", 
     118InsertCellAfter                 : "Insert Cell After", 
     119InsertCellBefore                : "Insert Cell Before", 
    117120DeleteCells                     : "Delete Cells", 
    118121MergeCells                      : "Merge Cells", 
  • FCKeditor/trunk/editor/lang/en-uk.js

    r215 r435  
    110110RowCM                           : "Row", 
    111111ColumnCM                        : "Column", 
    112 InsertRow                       : "Insert Row", 
     112InsertRowAfter                  : "Insert Row After", 
     113InsertRowBefore                 : "Insert Row Before", 
    113114DeleteRows                      : "Delete Rows", 
    114 InsertColumn            : "Insert Column", 
     115InsertColumnAfter               : "Insert Column After", 
     116InsertColumnBefore              : "Insert Column Before", 
    115117DeleteColumns           : "Delete Columns", 
    116 InsertCell                      : "Insert Cell", 
     118InsertCellAfter                 : "Insert Cell After", 
     119InsertCellBefore                : "Insert Cell Before", 
    117120DeleteCells                     : "Delete Cells", 
    118121MergeCells                      : "Merge Cells", 
  • FCKeditor/trunk/editor/lang/zh-cn.js

    r174 r435  
    110110RowCM                           : "行", 
    111111ColumnCM                        : "列", 
    112 InsertRow                       : "插入行", 
     112InsertRowBefore                 : "上插入行", 
     113InsertRowAfter                  : "下插入行", 
    113114DeleteRows                      : "删除行", 
    114 InsertColumn            : "插入列", 
    115 DeleteColumns           : "删除列", 
    116 InsertCell                      : "插入单元格", 
     115InsertColumnBefore              : "左插入列", 
     116InsertColumnAfter               : "右插入列", 
     117DeleteColumns                   : "删除列", 
     118InsertCellBefore                : "左插入单元格", 
     119InsertCellAfter                 : "右插入单元格", 
    117120DeleteCells                     : "删除单元格", 
    118121MergeCells                      : "合并单元格", 
  • FCKeditor/trunk/editor/lang/zh.js

    r174 r435  
    110110RowCM                           : "列", 
    111111ColumnCM                        : "欄", 
    112 InsertRow                       : "插入列", 
     112InsertRowBefore                 : "向上插入列", 
     113InsertRowAfter                  : "向下插入列", 
    113114DeleteRows                      : "刪除列", 
    114 InsertColumn            : "插入欄", 
     115InsertColumnBefore              : "向左插入欄", 
     116InsertColumnAfter               : "向右插入欄", 
    115117DeleteColumns           : "刪除欄", 
    116 InsertCell                      : "插入儲存格", 
     118InsertCellBefore                : "向左插入儲存格", 
     119InsertCellAfter                 : "向右插入儲存格", 
    117120DeleteCells                     : "刪除儲存格", 
    118121MergeCells                      : "合併儲存格", 
  • FCKeditor/trunk/editor/_source/classes/fckdomrange_gecko.js

    r132 r435  
    3030        var oSel = this.Window.getSelection() ; 
    3131 
    32         if ( oSel.rangeCount == 1 ) 
     32        if ( oSel.rangeCount > 0 ) 
    3333        { 
    3434                this._Range = FCKW3CRange.CreateFromRange( this.Window.document, oSel.getRangeAt(0) ) ; 
  • FCKeditor/trunk/editor/_source/commandclasses/fcktablecommand.js

    r132 r435  
    3434        switch ( this.Name ) 
    3535        { 
    36                 case 'TableInsertRow' : 
    37                         FCKTableHandler.InsertRow() ; 
     36                case 'TableInsertRowAfter' : 
     37                        FCKTableHandler.InsertRow( false ) ; 
     38                        break ; 
     39                case 'TableInsertRowBefore' : 
     40                        FCKTableHandler.InsertRow( true ) ; 
    3841                        break ; 
    3942                case 'TableDeleteRows' : 
    4043                        FCKTableHandler.DeleteRows() ; 
    4144                        break ; 
    42                 case 'TableInsertColumn' : 
    43                         FCKTableHandler.InsertColumn() ; 
     45                case 'TableInsertColumnAfter' : 
     46                        FCKTableHandler.InsertColumn( false ) ; 
     47                        break ; 
     48                case 'TableInsertColumnBefore' : 
     49                        FCKTableHandler.InsertColumn( true ) ; 
    4450                        break ; 
    4551                case 'TableDeleteColumns' : 
    4652                        FCKTableHandler.DeleteColumns() ; 
    4753                        break ; 
    48                 case 'TableInsertCell' : 
    49                         FCKTableHandler.InsertCell() ; 
     54                case 'TableInsertCellAfter' : 
     55                        FCKTableHandler.InsertCell( null, false ) ; 
     56                        break ; 
     57                case 'TableInsertCellBefore' : 
     58                        FCKTableHandler.InsertCell( null, true ) ; 
    5059                        break ; 
    5160                case 'TableDeleteCells' : 
  • FCKeditor/trunk/editor/_source/internals/fckcommands.js

    r396 r435  
    7979                case 'PasteWord'        : oCommand = new FCKPasteWordCommand() ; break ; 
    8080 
    81                 case 'TableInsertRow'           : oCommand = new FCKTableCommand('TableInsertRow') ; break ; 
     81                case 'TableInsertRowAfter'              : oCommand = new FCKTableCommand('TableInsertRowAfter') ; break ; 
     82                case 'TableInsertRowBefore'             : oCommand = new FCKTableCommand('TableInsertRowBefore') ; break ; 
    8283                case 'TableDeleteRows'          : oCommand = new FCKTableCommand('TableDeleteRows') ; break ; 
    83                 case 'TableInsertColumn'        : oCommand = new FCKTableCommand('TableInsertColumn') ; break ; 
     84                case 'TableInsertColumnAfter'   : oCommand = new FCKTableCommand('TableInsertColumnAfter') ; break ; 
     85                case 'TableInsertColumnBefore'  : oCommand = new FCKTableCommand('TableInsertColumnBefore') ; break ; 
    8486                case 'TableDeleteColumns'       : oCommand = new FCKTableCommand('TableDeleteColumns') ; break ; 
    85                 case 'TableInsertCell'          : oCommand = new FCKTableCommand('TableInsertCell') ; break ; 
     87                case 'TableInsertCellAfter'             : oCommand = new FCKTableCommand('TableInsertCellAfter') ; break ; 
     88                case 'TableInsertCellBefore'            : oCommand = new FCKTableCommand('TableInsertCellBefore') ; break ; 
    8689                case 'TableDeleteCells'         : oCommand = new FCKTableCommand('TableDeleteCells') ; break ; 
    8790                case 'TableMergeCells'          : oCommand = new FCKTableCommand('TableMergeCells') ; break ; 
  • FCKeditor/trunk/editor/_source/internals/fck_contextmenu.js

    r343 r435  
    7171                                        menu.AddSeparator() ; 
    7272                                        var oItem = menu.AddItem( 'Cell'        , FCKLang.CellCM ) ; 
    73                                         oItem.AddItem( 'TableInsertCell'        , FCKLang.InsertCell, 58 ) ; 
     73                                        oItem.AddItem( 'TableInsertCellBefore'  , FCKLang.InsertCellBefore, 58 ) ; 
     74                                        oItem.AddItem( 'TableInsertCellAfter'   , FCKLang.InsertCellAfter, 58 ) ; 
    7475                                        oItem.AddItem( 'TableDeleteCells'       , FCKLang.DeleteCells, 59 ) ; 
    7576                                        oItem.AddItem( 'TableMergeCells'        , FCKLang.MergeCells, 60 ) ; 
     
    8081                                        menu.AddSeparator() ; 
    8182                                        oItem = menu.AddItem( 'Row'                     , FCKLang.RowCM ) ; 
    82                                         oItem.AddItem( 'TableInsertRow'         , FCKLang.InsertRow, 62 ) ; 
     83                                        oItem.AddItem( 'TableInsertRowBefore'           , FCKLang.InsertRowBefore, 62 ) ; 
     84                                        oItem.AddItem( 'TableInsertRowAfter'            , FCKLang.InsertRowAfter, 62 ) ; 
    8385                                        oItem.AddItem( 'TableDeleteRows'        , FCKLang.DeleteRows, 63 ) ; 
    8486 
    8587                                        menu.AddSeparator() ; 
    8688                                        oItem = menu.AddItem( 'Column'          , FCKLang.ColumnCM ) ; 
    87                                         oItem.AddItem( 'TableInsertColumn'      , FCKLang.InsertColumn, 64 ) ; 
     89                                        oItem.AddItem( 'TableInsertColumnBefore', FCKLang.InsertColumnBefore, 64 ) ; 
     90                                        oItem.AddItem( 'TableInsertColumnAfter' , FCKLang.InsertColumnAfter, 64 ) ; 
    8891                                        oItem.AddItem( 'TableDeleteColumns'     , FCKLang.DeleteColumns, 65 ) ; 
    8992                                } 
  • FCKeditor/trunk/editor/_source/internals/fcktablehandler.js

    r132 r435  
    2424var FCKTableHandler = new Object() ; 
    2525 
    26 FCKTableHandler.InsertRow = function() 
     26FCKTableHandler.InsertRow = function( insertBefore ) 
    2727{ 
    2828        // Get the row where the selection is placed in. 
     
    3636        oRow.parentNode.insertBefore( oNewRow, oRow ) ; 
    3737 
    38         // Clean the row (it seems that the new row has been added after it). 
    39         FCKTableHandler.ClearRow( oRow ) ; 
     38        // Clean one of the rows to produce the illusion of inserting an empty row before or after. 
     39        FCKTableHandler.ClearRow( insertBefore ? oNewRow : oRow ) ; 
    4040} 
    4141 
     
    8080} 
    8181 
    82 FCKTableHandler.InsertColumn = function() 
     82FCKTableHandler.InsertColumn = function( insertBefore ) 
    8383{ 
    8484        // Get the cell where the selection is placed in. 
    8585        var oCell = FCKSelection.MoveToAncestorNode('TD') || FCKSelection.MoveToAncestorNode('TH') ; 
    8686 
    87         if ( !oCell ) return ; 
     87        if ( !oCell )  
     88        { 
     89                // oCell not fouund could be due to multiple selection ranges on tables in Gecko. 
     90                // We have another function to find the table cell for this special case. 
     91                if ( ! FCKBrowserInfo.IsIE ) 
     92                { 
     93                        var node = this._GetSelectedCellFromGecko( true ) ; 
     94                        if ( node ) 
     95                                oCell = node ; 
     96                        else 
     97                                return null ; 
     98                } 
     99                else 
     100                        return null ; 
     101        } 
    88102 
    89103        // Get the cell's table. 
    90104        var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ; 
    91105 
    92         // Get the index of the column to be created (based on the cell). 
    93         var iIndex = oCell.cellIndex + 1 ; 
     106        var iIndex = oCell.cellIndex ; 
    94107 
    95108        // Loop throw all rows available in the table. 
     
    100113 
    101114                // If the row doens't have enought cells, ignore it. 
    102                 if ( oRow.cells.length < iIndex ) 
     115                if ( oRow.cells.length < ( iIndex + 1 ) ) 
    103116                        continue ; 
    104117 
    105                 oCell = oRow.cells[iIndex-1].cloneNode(false) ; 
     118                oCell = oRow.cells[iIndex].cloneNode(false) ; 
    106119 
    107120                if ( FCKBrowserInfo.IsGecko ) 
    108121                        oCell.innerHTML = GECKO_BOGUS ; 
    109122 
    110                 // Get the cell that is placed in the new cell place. 
     123                // Get back the currently selected cell. 
    111124                var oBaseCell = oRow.cells[iIndex] ; 
    112125 
    113                 // If the cell is available (we are not in the last cell of the row). 
    114                 if ( oBaseCell ) 
    115                         oRow.insertBefore( oCell, oBaseCell ) ; // Insert the new cell just before of it. 
     126                if ( insertBefore ) 
     127                        oRow.insertBefore( oCell, oBaseCell ) ; 
     128                else if ( oBaseCell.nextSibling ) 
     129                        oRow.insertBefore( oCell, oBaseCell.nextSibling ) ; 
    116130                else 
    117                         oRow.appendChild( oCell ) ;                             // Append the cell at the end of the row. 
     131                        oRow.appendChild( oCell ) ; 
    118132        } 
    119133} 
     
    153167} 
    154168 
    155 FCKTableHandler.InsertCell = function( cell ) 
     169FCKTableHandler.InsertCell = function( cell, insertBefore ) 
    156170{ 
    157171        // Get the cell where the selection is placed in. 
    158172        var oCell = cell ? cell : FCKSelection.MoveToAncestorNode( 'TD' ) ; 
    159         if ( !oCell ) return null ; 
     173        if ( !oCell )  
     174        { 
     175                // oCell not fouund could be due to multiple selection ranges on tables in Gecko. 
     176                // We have another function to find the table cell for this special case. 
     177                if ( ! FCKBrowserInfo.IsIE ) 
     178                { 
     179                        var node = this._GetSelectedCellFromGecko( true ) ; 
     180                        if ( node ) 
     181                                oCell = node ; 
     182                        else 
     183                                return null ; 
     184                } 
     185                else 
     186                        return null ; 
     187        } 
    160188 
    161189        // Create the new cell element to be added. 
     
    165193//      oNewCell.innerHTML = "&nbsp;" ; 
    166194 
    167         // If it is the last cell in the row. 
    168         if ( oCell.cellIndex == oCell.parentNode.cells.length - 1 ) 
    169         { 
    170                 // Add the new cell at the end of the row. 
     195        if ( !insertBefore && oCell.cellIndex == oCell.parentNode.cells.length - 1 ) 
    171196                oCell.parentNode.appendChild( oNewCell ) ; 
    172         } 
    173197        else 
    174         { 
    175                 // Add the new cell before the next cell (after the active one). 
    176                 oCell.parentNode.insertBefore( oNewCell, oCell.nextSibling ) ; 
    177         } 
     198                oCell.parentNode.insertBefore( oNewCell, insertBefore ? oCell : oCell.nextSibling ) ; 
    178199 
    179200        return oNewCell ; 
     
    273294                if ( aCollCells[i] == aCells[0] ) 
    274295                { 
    275                         var oNewCell = this.InsertCell( aCells[0] ) ; 
     296                        var oNewCell = this.InsertCell( aCells[0], false ) ; 
    276297                        if ( !isNaN( aCells[0].rowSpan ) && aCells[0].rowSpan > 1 ) 
    277298                                oNewCell.rowSpan = aCells[0].rowSpan ; 
     
    384405        } 
    385406} 
     407 
     408FCKTableHandler._GetSelectedCellFromGecko = function( getLastCell ) 
     409{ 
     410        var sel = FCK.EditorWindow.getSelection() ; 
     411        if ( sel.rangeCount < 1 ) 
     412                return null ; 
     413        var range = getLastCell ? sel.getRangeAt( sel.rangeCount - 1 ) : sel.getRangeAt( 0 ) ; 
     414        var node = getLastCell ? range.endContainer : range.startContainer ; 
     415 
     416        // Gecko returns a <TR> as startContainer and endContainer when cells are selected. 
     417        // We need to find back the final <TD|TH> that's being selected. 
     418        if ( node.nodeType == 1 && node.tagName.toLowerCase() == 'tr' ) 
     419        { 
     420                for ( var i = range.startOffset ; i <= range.endOffset ; i++ ) 
     421                { 
     422                        var candidate = node.childNodes[i] ; 
     423                        var tag = candidate.tagName.toLowerCase() ; 
     424                        if ( candidate.nodeType == 1 && ( tag == 'td' || tag == 'th' ) ) 
     425                        { 
     426                                node = node.childNodes[i] ; 
     427                                break ; 
     428                        } 
     429                } 
     430        } 
     431        // For safety, we have to be ready for the 'usual' case as well. 
     432        else 
     433        { 
     434                while ( node && node.tagName.toLowerCase() != 'td' && node.tagName.toLowerCase() != 'th' ) 
     435                        node = node.parentNode ; 
     436        } 
     437 
     438        // Have we found the <TD|TH> node we wanted, finally? If yes, return the found node. If not, abort. 
     439        if ( node.tagName.toLowerCase() != 'td' && node.tagName.toLowerCase() != 'th' ) 
     440                return null ; 
     441        else 
     442                return node ; 
     443}