Ticket #3190: 3190_7.patch

File 3190_7.patch, 9.2 KB (added by Garry Yao, 10 years ago)
  • _source/plugins/wysiwygarea/plugin.js

     
    1010
    1111(function()
    1212{
     13        /**
     14         * List of elements in which has no way to move editing focus outside.
     15         */
     16        var nonExitableElementNames = { table:1,pre:1 };
     17
    1318        function onInsertHtml( evt )
    1419        {
    1520                if ( this.mode == 'wysiwyg' )
     
    7176
    7277                                clone = !i && element || element.clone( true );
    7378
    74                                 var toSplit;
    75 
    76                                 // If the new node is a block element, split the current block (if any).
     79                                // If we're inserting a block at dtd-violated positoin, split
     80                                // the parent blocks until we reach blockLimit.
     81                                var parent, dtd;
    7782                                if ( this.config.enterMode != CKEDITOR.ENTER_BR && isBlock )
    78                                 {
    79                                         var startPath = new CKEDITOR.dom.elementPath( range.startContainer ),
    80                                                 j = 0,
    81                                                 parent;
     83                                        while( ( parent = range.getCommonAncestor( false, true ) )
     84                                                        && ( dtd = CKEDITOR.dtd[ parent.getName() ] )
     85                                                        && !( dtd && dtd [ elementName ] ) )
     86                                                range.splitBlock();
    8287
    83                                         while( ( parent = startPath.elements[ j++ ] ) && parent != startPath.blockLimit )
    84                                         {
    85                                                 var parentName = parent.getName(),
    86                                                         parentDtd = CKEDITOR.dtd[ parentName ];
    87 
    88                                                 if ( parentDtd && !parentDtd[ elementName ] )
    89                                                         toSplit = parent;
    90                                         }
    91                                 }
    92 
    9388                                // Insert the new node.
    9489                                range.insertNode( clone );
    9590
    96                                 if ( toSplit )
    97                                         clone.breakParent( toSplit );
    98 
    9991                                // Save the last element reference so we can make the
    10092                                // selection later.
    10193                                if ( !lastElement )
     
    114106                                this.getSelection().lock();
    115107                }
    116108        }
    117 
     109       
     110        /**
     111         *  Auto-fixing block-less content by wrapping paragraph, prevent
     112         *  non-exitable-block by padding extra br.
     113         */
     114        function onSelectionChangeFixBody( evt )
     115        {
     116                var editor = evt.editor,
     117                        path = evt.data.path,
     118                        blockLimit = path.blockLimit,
     119                        body = editor.document.getBody(),
     120                        enterMode = editor.config.enterMode;
     121
     122                // When enterMode set to block, we'll establing new paragraph if the
     123                // current range is block-less within body.
     124                if ( enterMode != CKEDITOR.ENTER_BR
     125                         && blockLimit.getName() == 'body'
     126                         && !path.block )
     127                {
     128                        var selection = evt.data.selection,
     129                                range = evt.data.selection.getRanges()[0],
     130                                bms = selection.createBookmarks(),
     131                                fixedBlock = range.fixBlock( true,
     132                                        editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p'  );
     133
     134                        // For IE, we'll be removing any bogus br ( introduce by fixing body )
     135                        // right now to prevent it introducing visual line break.
     136                        if ( CKEDITOR.env.ie )
     137                        {
     138                                var brNodeList = fixedBlock.getElementsByTag( 'br' ), brNode;
     139                                for ( var i = 0 ; i < brNodeList.count() ; i++ )
     140                                        if( ( brNode = brNodeList.getItem( i ) ) && brNode.hasAttribute( '_fck_bookmark' ) )
     141                                                brNode.remove();
     142                        }
     143
     144                        selection.selectBookmarks( bms );
     145                }
     146
     147                // Inserting the padding-br before body if it's preceded by an
     148                // unexitable block.
     149                var lastNode = body.getLast( true );
     150                if ( lastNode.getName && ( lastNode.getName() in nonExitableElementNames ) )
     151                {
     152                        var paddingBlock = editor.document.createElement(
     153                                        ( CKEDITOR.env.ie && enterMode != CKEDITOR.ENTER_BR ) ?
     154                                                '<br _cke_bogus="true" />' : 'br' );
     155                        body.append( paddingBlock );
     156                }
     157        }
     158
    118159        CKEDITOR.plugins.add( 'wysiwygarea',
    119160        {
    120161                requires : [ 'editingblock' ],
     
    449490
    450491                                        editor.on( 'insertHtml', onInsertHtml, null, null, 20 );
    451492                                        editor.on( 'insertElement', onInsertElement, null, null, 20 );
     493                                        // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)
     494                                        editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 );
    452495                                });
    453496                }
    454497        });
  • _source/core/dom/element.js

     
    643643                        return $ ? new CKEDITOR.dom.node( $ ) : null;
    644644                },
    645645
    646                 getLast : function()
     646                /**
     647                 * @param ignoreEmpty Skip empty text nodes.
     648                 */
     649                getLast : function( ignoreEmpty )
    647650                {
    648651                        var $ = this.$.lastChild;
    649                         return $ ? new CKEDITOR.dom.node( $ ) : null;
     652                        if ( ignoreEmpty && $ && ( $.nodeType == CKEDITOR.NODE_TEXT )
     653                                        && !CKEDITOR.tools.trim( $.nodeValue ) )
     654                                return new CKEDITOR.dom.node( $ ).getPrevious( true );
     655                        else
     656                                return $ ? new CKEDITOR.dom.node( $ ) : null;
    650657                },
    651658
    652659                getStyle : function( name )
  • _source/core/dom/node.js

     
    259259                        return -1;
    260260                },
    261261
    262                 /**
    263                  * Gets the node following this node (next sibling).
    264                  * @returns {CKEDITOR.dom.node} The next node.
    265                  */
    266                 getNext : function()
    267                 {
    268                         var next = this.$.nextSibling;
    269                         return next ? new CKEDITOR.dom.node( next ) : null;
    270                 },
    271 
    272262                getNextSourceNode : function( startFromSibling, nodeType, guard )
    273263                {
    274264                        // If "guard" is a node, transform it in a function.
     
    360350                        return node;
    361351                },
    362352
    363                 getPrevious : function()
     353                getPrevious : function( ignoreSpaces )
    364354                {
    365355                        var previous = this.$.previousSibling;
     356                        while ( ignoreSpaces && previous && ( previous.nodeType == CKEDITOR.NODE_TEXT )
     357                                        && !CKEDITOR.tools.trim( previous.nodeValue ) )
     358                                previous = previous.previousSibling;
     359
    366360                        return previous ? new CKEDITOR.dom.node( previous ) : null;
    367361                },
    368362
    369363                /**
    370364                 * Gets the node that follows this element in its parent's child list.
     365                 * @param {Boolean} ignoreSpaces Whether should ignore empty text nodes.
    371366                 * @returns {CKEDITOR.dom.node} The next node or null if not
    372367                 *              available.
    373368                 * @example
     
    375370                 * var first = <b>element.getFirst().getNext()</b>;
    376371                 * alert( first.getName() );  // "i"
    377372                 */
    378                 getNext : function()
     373                getNext : function( ignoreSpaces )
    379374                {
    380                         var $ = this.$.nextSibling;
    381                         return $ ? new CKEDITOR.dom.node( $ ) : null;
     375                        var next = this.$.nextSibling;
     376                        while ( ignoreSpaces && next && ( next.nodeType == CKEDITOR.NODE_TEXT )
     377                                  && !CKEDITOR.tools.trim( next.nodeValue ) )
     378                                next = next.nextSibling;
     379                       
     380                        return next ? new CKEDITOR.dom.node( next ) : null;
    382381                },
    383382
    384383                /**
  • _source/core/dom/range.js

     
    3131        // V2
    3232        var execContentsAction = function( range, action, docFrag )
    3333        {
     34                range.optimizeBookmark();
     35               
    3436                var startNode   = range.startContainer;
    3537                var endNode             = range.endContainer;
    3638
     
    607609                        return { startNode : startNode, endNode : endNode };
    608610                },
    609611
    610                 getCommonAncestor : function( includeSelf )
     612                /**
     613                 * Find the node which fully contains the range.
     614                 * @param includeSelf
     615                 * @param {Boolean} ignoreTextNode Whether ignore CKEDITOR.NODE_TEXT type.
     616                 */
     617                getCommonAncestor : function( includeSelf , ignoreTextNode )
    611618                {
    612                         var start = this.startContainer;
    613                         var end = this.endContainer;
     619                        var start = this.startContainer,
     620                                end = this.endContainer,
     621                                ancestor;
    614622
    615623                        if ( start.equals( end ) )
    616624                        {
    617                                 if ( includeSelf && start.type == CKEDITOR.NODE_ELEMENT && this.startOffset == this.endOffset - 1 )
    618                                         return start.getChild( this.startOffset );
    619                                 return start;
     625                                if ( includeSelf
     626                                                && start.type == CKEDITOR.NODE_ELEMENT
     627                                                && this.startOffset == this.endOffset - 1 )
     628                                        ancestor = start.getChild( this.startOffset );
     629                                else
     630                                        ancestor = start;
    620631                        }
     632                        else
     633                                ancestor = start.getCommonAncestor( end );
    621634
    622                         return start.getCommonAncestor( end );
     635                        return ignoreTextNode && !ancestor.is ? ancestor.getParent() : ancestor;
    623636                },
    624637
    625638                /**
     
    653666                        }
    654667                },
    655668
     669                /**
     670                 * Move the range out of bookmark nodes if they're been the container.
     671                 */
     672                optimizeBookmark: function()
     673                {
     674                        var startNode = this.startContainer,
     675                                endNode = this.endContainer;
     676
     677                        if ( startNode.is && startNode.is( 'span' )
     678                                && startNode.hasAttribute( '_fck_bookmark' ) )
     679                                this.setStartAt( startNode, CKEDITOR.POSITION_BEFORE_START );
     680                        if ( endNode && endNode.is && endNode.is( 'span' )
     681                                && endNode.hasAttribute( '_fck_bookmark' ) )
     682                                this.setEndAt( endNode,  CKEDITOR.POSITION_AFTER_END );
     683                },
     684
    656685                trim : function( ignoreStart, ignoreEnd )
    657686                {
    658687                        var startContainer = this.startContainer;
     
    11361165                 */
    11371166                insertNode : function( node )
    11381167                {
     1168                        this.optimizeBookmark();
    11391169                        this.trim( false, true );
    11401170
    11411171                        var startContainer = this.startContainer;
     
    13261356                                endBlock        = endPath.block;
    13271357
    13281358                        var elementPath = null;
    1329 
    13301359                        // Do nothing if the boundaries are in different block limits.
    13311360                        if ( !startBlockLimit.equals( endBlockLimit ) )
    13321361                                return null;
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy