Changeset 6461


Ignore:
Timestamp:
02/18/2011 08:10:24 PM (4 years ago)
Author:
fredck
Message:

#1272 : It's now possible to apply styles to collapsed selections on Safari and Chrome (WebKit).

Location:
CKEditor/trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • CKEditor/trunk/CHANGES.html

    r6459 r6461  
    1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    22<!--
    33Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
     
    4545                        Fixed issues:</p>
    4646        <ul>
     47                <li><a href="http://dev.ckeditor.com/ticket/1272">#1272</a> : It's now possible to apply styles to collapsed selections on Safari and Chrome (WebKit).</li>
    4748                <li><a href="http://dev.ckeditor.com/ticket/7054">#7054</a> : Special characters' tooltips are now lowercased, making them more readable.</li>
    4849                <li><a href="http://dev.ckeditor.com/ticket/7102">#7102</a> : "Replacing Div" sample didn't work when double clicking inside of formatted text.</li>
  • CKEditor/trunk/_source/core/dom/node.js

    r6419 r6461  
    205205                        {
    206206                                var parentNode = node.parentNode;
    207                                 var currentIndex = -1;
    208207
    209208                                if ( parentNode )
    210209                                {
    211                                         for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
    212                                         {
    213                                                 var candidate = parentNode.childNodes[i];
    214 
    215                                                 if ( normalized &&
    216                                                                 candidate.nodeType == 3 &&
    217                                                                 candidate.previousSibling &&
    218                                                                 candidate.previousSibling.nodeType == 3 )
    219                                                 {
    220                                                         continue;
    221                                                 }
    222 
    223                                                 currentIndex++;
    224 
    225                                                 if ( candidate == node )
    226                                                         break;
    227                                         }
    228 
    229                                         address.unshift( currentIndex );
     210                                        // Get the node index. For performance, call getIndex
     211                                        // directly, instead of creating a new node object.
     212                                        address.unshift( this.getIndex.call( { $ : node }, normalized ) );
    230213                                }
    231214
     
    248231                },
    249232
    250                 getIndex : function()
    251                 {
    252                         var $ = this.$;
    253 
    254                         var currentNode = $.parentNode && $.parentNode.firstChild;
    255                         var currentIndex = -1;
    256 
    257                         while ( currentNode )
    258                         {
    259                                 currentIndex++;
    260 
    261                                 if ( currentNode == $ )
    262                                         return currentIndex;
    263 
    264                                 currentNode = currentNode.nextSibling;
    265                         }
    266 
    267                         return -1;
     233                getIndex : function( normalized )
     234                {
     235                        // Attention: getAddress depends on this.$
     236
     237                        var current = this.$,
     238                                index = 0;
     239
     240                        while ( ( current = current.previousSibling ) )
     241                        {
     242                                // When normalizing, do not count it if this is an
     243                                // empty text node or if it's a text node following another one.
     244                                if ( normalized && current.nodeType == 3 &&
     245                                         ( !current.nodeValue.length ||
     246                                           ( current.previousSibling && current.previousSibling.nodeType == 3 ) ) )
     247                                {
     248                                        continue;
     249                                }
     250
     251                                index++;
     252                        }
     253
     254                        return index;
    268255                },
    269256
  • CKEditor/trunk/_source/core/dom/range.js

    r6418 r6461  
    590590                                                startOffset = 0;
    591591                                        }
     592
     593                                        // Get the normalized offset.
     594                                        if ( child && child.type == CKEDITOR.NODE_ELEMENT )
     595                                                startOffset = child.getIndex( 1 );
    592596                                }
    593597
     
    618622                                                        endOffset = 0;
    619623                                                }
     624
     625                                                // Get the normalized offset.
     626                                                if ( child && child.type == CKEDITOR.NODE_ELEMENT )
     627                                                        endOffset = child.getIndex( 1 );
    620628                                        }
    621629
  • CKEditor/trunk/_source/core/dom/text.js

    r6348 r6461  
    6868                },
    6969
     70                setText : function( text )
     71                {
     72                        this.$.nodeValue = text;
     73                },
     74
    7075                /**
    7176                 * Breaks this text node into two nodes at the specified offset,
  • CKEditor/trunk/_source/plugins/editingblock/plugin.js

    r6435 r6461  
    154154        CKEDITOR.editor.prototype.setMode = function( mode )
    155155        {
     156                this.fire( 'beforeSetMode', { newMode : mode } );
     157
    156158                var data,
    157159                        holderElement = this.getThemeSpace( 'contents' ),
     
    243245
    244246/**
    245  * Fired before changing the editing mode
     247 * Fired before changing the editing mode.
    246248 * @name CKEDITOR.editor#beforeModeUnload
    247249 * @event
    248250 */
     251
     252 /**
     253 * Fired before the editor mode is set.
     254 * @name CKEDITOR.editor#beforeSetMode
     255 * @event
     256 * @since 3.5.3
     257 * @param {String} newMode The name of the mode which is about to be set.
     258 */
  • CKEditor/trunk/_source/plugins/selection/plugin.js

    r6459 r6461  
    100100        };
    101101
     102        function createFillingChar( doc )
     103        {
     104                removeFillingChar( doc );
     105
     106                var fillingChar = doc.createText( '\u200B' );
     107                doc.setCustomData( 'cke-fillingChar', fillingChar );
     108
     109                return fillingChar;
     110        }
     111
     112        function getFillingChar( doc )
     113        {
     114                return doc && doc.getCustomData( 'cke-fillingChar' );
     115        }
     116
     117        // Checks if a filling char has been used, eventualy removing it (#1272).
     118        function checkFillingChar( doc )
     119        {
     120                var fillingChar = doc && getFillingChar( doc );
     121                if ( fillingChar )
     122                {
     123                        // Use this flag to avoid removing the filling char right after
     124                        // creating it.
     125                        if ( fillingChar.getCustomData( 'ready' ) )
     126                                removeFillingChar( doc );
     127                        else
     128                                fillingChar.setCustomData( 'ready', 1 );
     129                }
     130        }
     131
     132        function removeFillingChar( doc )
     133        {
     134                var fillingChar = doc && doc.removeCustomData( 'cke-fillingChar' );
     135                if ( fillingChar )
     136                {
     137                        // We can't simply remove the filling node because the user
     138                        // will actually enlarge it when typing, so we just remove the
     139                        // invisible char from it.
     140                        fillingChar.setText( fillingChar.getText().replace( /\u200B/g, '' ) );
     141                        fillingChar = 0;
     142                }
     143        }
     144
    102145        CKEDITOR.plugins.add( 'selection',
    103146        {
    104147                init : function( editor )
    105148                {
     149                        // On WebKit only, we need a special "filling" char on some situations
     150                        // (#1272). Here we set the events that should invalidate that char.
     151                        if ( CKEDITOR.env.webkit )
     152                        {
     153                                editor.on( 'selectionChange', function() { checkFillingChar( editor.document ); } );
     154                                editor.on( 'beforeSetMode', function() { removeFillingChar( editor.document ); } );
     155                                editor.on( 'key', function( e )
     156                                        {
     157                                                // Remove the filling char before some keys get
     158                                                // executed, so they'll not get blocked by it.
     159                                                switch ( e.data.keyCode )
     160                                                {
     161                                                        case 37 :       // LEFT-ARROW
     162                                                        case 39 :       // RIGHT-ARROW
     163                                                        case 8 :        // BACKSPACE
     164                                                                removeFillingChar( editor.document );
     165                                                }
     166                                        });
     167
     168                                var fillingCharBefore;
     169                                function beforeData()
     170                                {
     171                                        var fillingChar = getFillingChar( editor.document );
     172                                        fillingCharBefore = fillingChar && fillingChar.getText();
     173                                        fillingCharBefore && fillingChar.setText( fillingCharBefore.replace( /\u200B/g, '' ) );
     174                                }
     175                                function afterData()
     176                                {
     177                                                var fillingChar = getFillingChar( editor.document );
     178                                                fillingChar && fillingChar.setText( fillingCharBefore );
     179                                }
     180                                editor.on( 'beforeUndoImage', beforeData );
     181                                editor.on( 'afterUndoImage', afterData );
     182                                editor.on( 'beforeGetData', beforeData, null, null, 0 );
     183                                editor.on( 'getData', afterData );
     184                        }
     185
    106186                        editor.on( 'contentDom', function()
    107187                                {
     
    11461226                                var sel = this.getNative();
    11471227
     1228                                // getNative() returns null if iframe is "display:none" in FF. (#6577)
     1229                                if ( !sel )
     1230                                        return;
     1231
    11481232                                if ( ranges.length )
     1233                                {
    11491234                                        sel.removeAllRanges();
     1235                                        // Remove any existing filling char first.
     1236                                        CKEDITOR.env.webkit && removeFillingChar( this.document );
     1237                                }
    11501238
    11511239                                for ( var i = 0 ; i < ranges.length ; i++ )
     
    11971285                                        }
    11981286
    1199                                         nativeRange.setStart( startContainer.$, range.startOffset );
    1200                                         nativeRange.setEnd( range.endContainer.$, range.endOffset );
     1287                                        if ( range.collapsed && CKEDITOR.env.webkit )
     1288                                        {
     1289                                                // Append a zero-width space so WebKit will not try to
     1290                                                // move the selection by itself (#1272).
     1291                                                var fillingChar = createFillingChar( this.document );
     1292                                                range.insertNode( fillingChar ) ;
     1293
     1294                                                var next = fillingChar.getNext();
     1295
     1296                                                // If the filling char is followed by a <br>, whithout
     1297                                                // having something before it, it'll not blink.
     1298                                                // Let's remove it in this case.
     1299                                                if ( next && !fillingChar.getPrevious() && next.type == CKEDITOR.NODE_ELEMENT && next.getName() == 'br' )
     1300                                                {
     1301                                                        removeFillingChar( this.document );
     1302                                                        range.moveToPosition( next, CKEDITOR.POSITION_BEFORE_START );
     1303                                                }
     1304                                                else
     1305                                                        range.moveToPosition( fillingChar, CKEDITOR.POSITION_AFTER_END );
     1306                                        }
     1307
     1308                                        nativeRange.setStart( range.startContainer.$, range.startOffset );
     1309
     1310                                        try
     1311                                        {
     1312                                                nativeRange.setEnd( range.endContainer.$, range.endOffset );
     1313                                        }
     1314                                        catch ( e )
     1315                                        {
     1316                                                // There is a bug in Firefox implementation (it would be too easy
     1317                                                // otherwise). The new start can't be after the end (W3C says it can).
     1318                                                // So, let's create a new range and collapse it to the desired point.
     1319                                                if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 )
     1320                                                {
     1321                                                        range.collapse( 1 );
     1322                                                        nativeRange.setEnd( range.endContainer.$, range.endOffset );
     1323                                                }
     1324                                                else
     1325                                                        throw e;
     1326                                        }
    12011327
    12021328                                        // Select the range.
     
    13851511                        function()
    13861512                        {
    1387                                 var startContainer = this.startContainer;
    1388 
    1389                                 // If we have a collapsed range, inside an empty element, we must add
    1390                                 // something to it, otherwise the caret will not be visible.
    1391                                 if ( this.collapsed && startContainer.type == CKEDITOR.NODE_ELEMENT && !startContainer.getChildCount() )
    1392                                         startContainer.append( new CKEDITOR.dom.text( '' ) );
    1393 
    1394                                 var nativeRange = this.document.$.createRange();
    1395                                 nativeRange.setStart( startContainer.$, this.startOffset );
    1396 
    1397                                 try
    1398                                 {
    1399                                         nativeRange.setEnd( this.endContainer.$, this.endOffset );
    1400                                 }
    1401                                 catch ( e )
    1402                                 {
    1403                                         // There is a bug in Firefox implementation (it would be too easy
    1404                                         // otherwise). The new start can't be after the end (W3C says it can).
    1405                                         // So, let's create a new range and collapse it to the desired point.
    1406                                         if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 )
    1407                                         {
    1408                                                 this.collapse( true );
    1409                                                 nativeRange.setEnd( this.endContainer.$, this.endOffset );
    1410                                         }
    1411                                         else
    1412                                                 throw( e );
    1413                                 }
    1414 
    1415                                 var selection = this.document.getSelection().getNative();
    1416                                 // getSelection() returns null in case when iframe is "display:none" in FF. (#6577)
    1417                                 if ( selection )
    1418                                 {
    1419                                         selection.removeAllRanges();
    1420                                         selection.addRange( nativeRange );
    1421                                 }
     1513                                this.document.getSelection().selectRanges( [ this ] );
    14221514                        };
    14231515} )();
  • CKEditor/trunk/_source/plugins/undo/plugin.js

    r6348 r6461  
    149149        {
    150150                this.editor = editor;
     151
     152                editor.fire( 'beforeUndoImage' );
     153
    151154                var contents = editor.getSnapshot(),
    152155                        selection       = contents && editor.getSelection();
     
    157160                this.contents   = contents;
    158161                this.bookmarks  = selection && selection.createBookmarks2( true );
     162
     163                editor.fire( 'afterUndoImage' );
    159164        };
    160165
     
    553558 * @event
    554559 */
     560
     561/**
     562 * Fired before an undo image is to be taken. An undo image represents the
     563 * editor state at some point. It's saved into an undo store, so the editor is
     564 * able to recover the editor state on undo and redo operations.
     565 * @name CKEDITOR.editor#beforeUndoImage
     566 * @since 3.5.3
     567 * @see CKEDITOR.editor#afterUndoImage
     568 * @event
     569 */
     570
     571/**
     572 * Fired after an undo image is taken. An undo image represents the
     573 * editor state at some point. It's saved into an undo store, so the editor is
     574 * able to recover the editor state on undo and redo operations.
     575 * @name CKEDITOR.editor#afterUndoImage
     576 * @since 3.5.3
     577 * @see CKEDITOR.editor#beforeUndoImage
     578 * @event
     579 */
Note: See TracChangeset for help on using the changeset viewer.
© 2003 – 2012 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy