Ticket #5479: 5479_14.patch

File 5479_14.patch, 12.7 KB (added by Garry Yao, 10 years ago)
  • _source/core/dom/element.js

     
    234234                                this.append( new CKEDITOR.dom.text( text ) );
    235235                },
    236236
    237                 appendBogus : function()
    238                 {
    239                         var lastChild = this.getLast() ;
    240 
    241                         // Ignore empty/spaces text.
    242                         while ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.rtrim( lastChild.getText() ) )
    243                                 lastChild = lastChild.getPrevious();
    244                         if ( !lastChild || !lastChild.is || !lastChild.is( 'br' ) )
    245                         {
    246                                 var bogus = CKEDITOR.env.opera ?
    247                                                 this.getDocument().createText('') :
    248                                                 this.getDocument().createElement( 'br' );
    249 
    250                                 CKEDITOR.env.gecko && bogus.setAttribute( 'type', '_moz' );
    251 
    252                                 this.append( bogus );
    253                         }
    254                 },
    255 
    256237                /**
    257238                * Retrieve block element's filler node if existed.
    258239                */
  • _source/core/dom/walker.js

     
    449449                return false;
    450450        };
    451451
     452        // Append a filler node at the end of an element if not exists.
     453        CKEDITOR.dom.element.prototype.appendBogus = function()
     454        {
     455                var lastChild = this.getLast( fillerEvaluator ) ;
     456                if ( !lastChild || !lastChild.is || !lastChild.is( 'br' ) )
     457                {
     458                        var bogus = CKEDITOR.env.opera ?
     459                                        this.getDocument().createText('') :
     460                                        this.getDocument().createElement( 'br' );
     461
     462                        CKEDITOR.env.gecko && bogus.setAttribute( 'type', '_moz' );
     463
     464                        this.append( bogus );
     465                }
     466        };
     467
     468
    452469})();
  • _source/plugins/wysiwygarea/plugin.js

     
    2121        // Elements that could have empty new line around, including table, pre-formatted block, hr, page-break. (#6554)
    2222        function nonExitable( element )
    2323        {
    24                 return ( element.getName() in nonExitableElementNames )
    25                                 || element.isBlockBoundary() && CKEDITOR.dtd.$empty[ element.getName() ];
     24                return !!( element.getName() in nonExitableElementNames
     25                                || element.isBlockBoundary() && CKEDITOR.dtd.$empty[ element.getName() ] );
    2626        }
    2727
    2828
     
    3838
    3939                                insertFunc.call( this, evt.data );
    4040
     41                                paddingBody( this );
     42
    4143                                // Save snaps after the whole execution completed.
    4244                                // This's a workaround for make DOM modification's happened after
    4345                                // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents'
     
    197199                if ( selIsLocked )
    198200                        selection.unlock();
    199201
    200                 var range, clone, lastElement, bookmark;
     202                var range, clone, lastElement,
     203                                path;
    201204
    202205                for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
    203206                {
    204207                        range = ranges[ i ];
     208                        path = new CKEDITOR.dom.elementPath( range.startContainer );
    205209
    206                                 if ( !range.checkReadOnly() )
    207                                 {
    208                                         // Remove the original contents.
    209                                         range.deleteContents();
     210                        if ( !range.checkReadOnly() )
     211                        {
     212                                // Remove the original contents.
     213                                range.deleteContents();
    210214
    211                                         clone = !i && element || element.clone( 1 );
     215                                clone = !i && element || element.clone( 1 );
    212216
    213                                         // If we're inserting a block at dtd-violated position, split
    214                                         // the parent blocks until we reach blockLimit.
    215                                         var current, dtd;
    216                                         if ( isBlock )
    217                                         {
    218                                                 while ( ( current = range.getCommonAncestor( 0, 1 ) )
    219                                                                 && ( dtd = CKEDITOR.dtd[ current.getName() ] )
    220                                                                 && !( dtd && dtd [ elementName ] ) )
    221                                                 {
    222                                                         // Split up inline elements.
    223                                                         if ( current.getName() in CKEDITOR.dtd.span )
    224                                                                 range.splitElement( current );
    225                                                         // If we're in an empty block which indicate a new paragraph,
    226                                                         // simply replace it with the inserting block.(#3664)
    227                                                         else if ( range.checkStartOfBlock()
    228                                                                         && range.checkEndOfBlock() )
    229                                                         {
    230                                                                 range.setStartBefore( current );
    231                                                                 range.collapse( true );
    232                                                                 current.remove();
    233                                                         }
    234                                                         else
    235                                                                 range.splitBlock();
    236                                                 }
    237                                         }
     217                                // If we're inserting a block at dtd-violated position, split
     218                                // the parent blocks until we reach blockLimit.
     219                                var current, dtd;
     220                                if ( isBlock )
     221                                {
     222                                        while ( ( current = range.getCommonAncestor( 0, 1 ) )
     223                                                        && ( dtd = CKEDITOR.dtd[
     224                                                                // Is the div used as paragraph?
     225                                                                this.config.enterMode == CKEDITOR.ENTER_DIV
     226                                                                && path.block
     227                                                                && path.block.equals( current )
     228                                                                && current.is( 'div' ) ? 'p' : current.getName() ] )
     229                                                        && !( dtd && dtd [ elementName ] ) )
     230                                        {
     231                                                // Split up inline elements.
     232                                                if ( current.getName() in CKEDITOR.dtd.span )
     233                                                        range.splitElement( current );
     234                                                // If we're in an empty block which indicate a new paragraph,
     235                                                // simply replace it with the inserting block.(#3664)
     236                                                else if ( range.checkStartOfBlock()
     237                                                                && range.checkEndOfBlock() )
     238                                                {
     239                                                        range.setStartBefore( current );
     240                                                        range.collapse( true );
     241                                                        current.remove();
     242                                                }
     243                                                else
     244                                                        range.splitBlock();
     245                                        }
     246                                }
    238247
    239                                         // Insert the new node.
    240                                         range.insertNode( clone );
     248                                // Insert the new node.
     249                                range.insertNode( clone );
    241250
    242                                         // Save the last element reference so we can make the
    243                                         // selection later.
    244                                         if ( !lastElement )
    245                                                 lastElement = clone;
    246                                 }
    247                         }
     251                                // Save the last element reference so we can make the
     252                                // selection later.
     253                                if ( !lastElement )
     254                                        lastElement = clone;
     255                        }
     256                }
    248257
    249                         if ( lastElement )
    250                         {
    251                                 range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
     258                if ( lastElement )
     259                {
     260                        range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
    252261
    253                                 // If we're inserting a block element immediatelly followed by
    254                                 // another block element, the selection must move there. (#3100,#5436)
    255                                 if ( isBlock )
    256                                 {
    257                                         var next = lastElement.getNext( notWhitespaceEval ),
    258                                                 nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName();
     262                        // If we're inserting a block element immediatelly followed by
     263                        // another block element, the selection must move there. (#3100,#5436)
     264                        if ( isBlock )
     265                        {
     266                                var next = lastElement.getNext( notWhitespaceEval ),
     267                                        nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName();
    259268
    260                                         // Check if it's a block element that accepts text.
    261                                         if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )
    262                                                 range.moveToElementEditStart( next );
    263                                 }
    264                         }
     269                                // Check if it's a block element that accepts text.
     270                                if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )
     271                                        range.moveToElementEditStart( next );
     272                        }
     273                }
    265274
     275                // Defer it a bit to allow other adjustment to happen.
     276                setTimeout( function()
     277                {
    266278                        selection.selectRanges( [ range ] );
     279                }, 0 );
    267280
    268281                if ( selIsLocked )
    269282                        this.getSelection().lock();
     
    304317                return block.getOuterHtml().match( emptyParagraphRegexp );
    305318        }
    306319
    307         isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true );
    308 
    309320        // Gecko need a key event to 'wake up' the editing
    310321        // ability when document is empty.(#3864, #5781)
    311322        function activateEditing( editor )
     
    343354                }
    344355        }
    345356
     357        function paddingBody( editor )
     358        {
     359                // IE below version 8 doesn't require this fix.
     360                if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat )
     361                        return;
     362
     363                // All browsers are incapable to moving cursor out of certain non-exitable
     364                // blocks (e.g. table, list, pre) at the end of document, make this happen by
     365                // place a bogus node there, which would be later removed by dataprocessor.
     366                var body = editor.document.getBody(),
     367                        enterMode = editor.config.enterMode,
     368                        selection = editor.getSelection(),
     369                        walkerRange = new CKEDITOR.dom.range( editor.document ),
     370                        walker = new CKEDITOR.dom.walker( walkerRange );
     371
     372                walkerRange.selectNodeContents( body );
     373                walker.evaluator = function( node )
     374                {
     375                        return node.type == CKEDITOR.NODE_ELEMENT && nonExitable( node );
     376                };
     377                walker.guard = function( node, isMoveout )
     378                {
     379                        return !( ( node.type == CKEDITOR.NODE_TEXT && isNotWhitespace( node ) ) || isMoveout );
     380                };
     381
     382                if ( walker.previous() )
     383                {
     384                        editor.fire( 'updateSnapshot' );
     385                        restoreDirty( editor );
     386                        CKEDITOR.env.ie && selection && restoreSelection( selection );
     387
     388                        var paddingBlock;
     389                        if ( enterMode != CKEDITOR.ENTER_BR )
     390                                paddingBlock = body.append( new CKEDITOR.dom.element( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) );
     391                        else
     392                                paddingBlock = body;
     393
     394                        if ( !CKEDITOR.env.ie )
     395                                paddingBlock.appendBogus();
     396                        else if ( paddingBlock.is( 'body' ) )
     397                        {
     398                                // IE need at least a node to show the cursor, use a zero height br
     399                                // to fly under the radar, additionally wrap the br element with an extra span ,
     400                                // so selection change event could be easily captured when cursor move inside of it.
     401                                var paddingNode = CKEDITOR.dom.element.createFromHtml( '<span data-cke-bogus=1>' +
     402                                                                                                                                                           '<br data-cke-temp=1 style="line-height:0"/></span>', editor.document );
     403                                paddingBlock.append( paddingNode );
     404                        }
     405                }
     406        }
     407
    346408        /**
    347409         *  Auto-fixing block-less content by wrapping paragraph (#3190), prevent
    348410         *  non-exitable-block by padding extra br.(#3189)
     
    359421
    360422                CKEDITOR.env.gecko && activateEditing( editor );
    361423
     424                // Remove the padding body node used in IE.
     425                if ( CKEDITOR.env.ie )
     426                {
     427                        var start = range.collapsed && range.startContainer;
     428                        if ( start.type == CKEDITOR.NODE_ELEMENT && start.is( 'span') && start.data( 'cke-bogus') )
     429                        {
     430                                range.moveToPosition( start, CKEDITOR.POSITION_BEFORE_START );
     431                                start.remove();
     432                                range.select();
     433                                return;
     434                        }
     435                }
     436
    362437                // When enterMode set to block, we'll establing new paragraph only if we're
    363438                // selecting inline contents right under body. (#3657)
    364439                if ( enterMode != CKEDITOR.ENTER_BR
     
    396471                                {
    397472                                        element = fixedBlock.getPrevious( isNotWhitespace );
    398473                                        if ( element &&
    399                                                  element.type == CKEDITOR.NODE_ELEMENT &&
    400                                                  !nonExitable( element ) )
     474                                                 element.type == CKEDITOR.NODE_ELEMENT )
    401475                                        {
    402                                                 range.moveToElementEditEnd( element );
    403                                                 fixedBlock.remove();
    404                                         }
    405                                 }
    406                         }
     476                                                if ( !nonExitable( element ) )
     477                                                {
     478                                                        range.moveToElementEditEnd( element );
     479                                                        fixedBlock.remove();
     480                                                }
     481                                                else if ( element.getDirection() )
     482                                                        fixedBlock.setAttribute( 'dir', element.getDirection() );
     483                                        }
     484                                }
     485                        }
    407486
    408487                        range.select();
    409488                        // Notify non-IE that selection has changed.
     
    415494                        }
    416495                }
    417496
    418                 // All browsers are incapable to moving cursor out of certain non-exitable
    419                 // blocks (e.g. table, list, pre) at the end of document, make this happen by
    420                 // place a bogus node there, which would be later removed by dataprocessor.
    421                 var walkerRange = new CKEDITOR.dom.range( editor.document ),
    422                         walker = new CKEDITOR.dom.walker( walkerRange );
    423                 walkerRange.selectNodeContents( body );
    424                 walker.evaluator = function( node )
    425                 {
    426                         return node.type == CKEDITOR.NODE_ELEMENT && ( node.getName() in nonExitableElementNames );
    427                 };
    428                 walker.guard = function( node, isMoveout )
    429                 {
    430                         return !( ( node.type == CKEDITOR.NODE_TEXT && isNotWhitespace( node ) ) || isMoveout );
    431                 };
    432 
    433                 if ( walker.previous() )
    434                 {
    435                         editor.fire( 'updateSnapshot' );
    436                         restoreDirty( editor );
    437                         CKEDITOR.env.ie && restoreSelection( selection );
    438 
    439                         var paddingBlock;
    440                         if ( enterMode != CKEDITOR.ENTER_BR )
    441                                 paddingBlock = body.append( new CKEDITOR.dom.element( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) );
    442                         else
    443                                 paddingBlock = body;
    444 
    445                         if ( !CKEDITOR.env.ie )
    446                                 paddingBlock.appendBogus();
    447                 }
    448         }
     497                paddingBody( editor );
     498        }
    449499
    450500        CKEDITOR.plugins.add( 'wysiwygarea',
    451501        {
     
    10821132                                        var title = editor.document.getElementsByTag( 'title' ).getItem( 0 );
    10831133                                        title.data( 'cke-title', editor.document.$.title );
    10841134                                        editor.document.$.title = frameLabel;
     1135
     1136                                        paddingBody( editor );
     1137
    10851138                                });
    10861139
    10871140                        // IE8 stricts mode doesn't have 'contentEditable' in effect
     
    11651218                                                element.data( 'cke-editable', element.hasAttribute( 'contenteditable' ) ? 'true' : '1' );
    11661219                                        element.setAttribute( 'contentEditable', false );
    11671220                                }
     1221
     1222                                paddingBody( editor );
    11681223                        });
    11691224
    1170                 }
    1171         });
     1225                                        }
     1226                        });
    11721227
    11731228        // Fixing Firefox 'Back-Forward Cache' break design mode. (#4514)
    11741229        if ( CKEDITOR.env.gecko )
© 2003 – 2021 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy