]> git.immae.eu Git - perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git/blobdiff - sources/core/selection.js
Upgrade to 4.5.7 and add some plugin
[perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git] / sources / core / selection.js
index fec3b7fc166bba1e57c5c764c1a683feb334df70..573b890e18d89bd42f58550f4ccd7e99f456bfe4 100644 (file)
@@ -1,5 +1,5 @@
-/**
- * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md or http://ckeditor.com/license
  */
 
                return false;
        }
 
-       function createFillingChar( element ) {
-               removeFillingChar( element, false );
+       function createFillingCharSequenceNode( editable ) {
+               removeFillingCharSequenceNode( editable, false );
 
-               var fillingChar = element.getDocument().createText( '\u200B' );
-               element.setCustomData( 'cke-fillingChar', fillingChar );
+               var fillingChar = editable.getDocument().createText( fillingCharSequence );
+               editable.setCustomData( 'cke-fillingChar', fillingChar );
 
                return fillingChar;
        }
 
-       function getFillingChar( element ) {
-               return element.getCustomData( 'cke-fillingChar' );
-       }
-
        // Checks if a filling char has been used, eventualy removing it (#1272).
-       function checkFillingChar( element ) {
-               var fillingChar = getFillingChar( element );
+       function checkFillingCharSequenceNodeReady( editable ) {
+               var fillingChar = editable.getCustomData( 'cke-fillingChar' );
+
                if ( fillingChar ) {
                        // Use this flag to avoid removing the filling char right after
                        // creating it.
-                       if ( fillingChar.getCustomData( 'ready' ) )
-                               removeFillingChar( element );
-                       else
+                       if ( fillingChar.getCustomData( 'ready' ) ) {
+                               removeFillingCharSequenceNode( editable );
+                       } else {
                                fillingChar.setCustomData( 'ready', 1 );
+                       }
                }
        }
 
-       function removeFillingChar( element, keepSelection ) {
-               var fillingChar = element && element.removeCustomData( 'cke-fillingChar' );
-               if ( fillingChar ) {
+       function removeFillingCharSequenceNode( editable, keepSelection ) {
+               var fillingChar = editable && editable.removeCustomData( 'cke-fillingChar' );
 
+               if ( fillingChar ) {
                        // Text selection position might get mangled by
                        // subsequent dom modification, save it now for restoring. (#8617)
                        if ( keepSelection !== false ) {
-                               var bm,
-                                       sel = element.getDocument().getSelection().getNative(),
+                               var sel = editable.getDocument().getSelection().getNative(),
                                        // Be error proof.
-                                       range = sel && sel.type != 'None' && sel.getRangeAt( 0 );
+                                       range = sel && sel.type != 'None' && sel.getRangeAt( 0 ),
+                                       fillingCharSeqLength = fillingCharSequence.length;
 
-                               if ( fillingChar.getLength() > 1 && range && range.intersectsNode( fillingChar.$ ) ) {
-                                       bm = createNativeSelectionBookmark( sel );
+                               // If there's some text other than the sequence in the FC text node and the range
+                               // intersects with that node...
+                               if ( fillingChar.getLength() > fillingCharSeqLength && range && range.intersectsNode( fillingChar.$ ) ) {
+                                       var bm = createNativeSelectionBookmark( sel );
+
+                                       // Correct start offset anticipating the removal of FC.
+                                       if ( sel.anchorNode == fillingChar.$ && sel.anchorOffset > fillingCharSeqLength ) {
+                                               bm[ 0 ].offset -= fillingCharSeqLength;
+                                       }
 
-                                       // Anticipate the offset change brought by the removed char.
-                                       var startAffected = sel.anchorNode == fillingChar.$ && sel.anchorOffset > 0,
-                                               endAffected = sel.focusNode == fillingChar.$ && sel.focusOffset > 0;
-                                       startAffected && bm[ 0 ].offset--;
-                                       endAffected && bm[ 1 ].offset--;
+                                       // Correct end offset anticipating the removal of FC.
+                                       if ( sel.focusNode == fillingChar.$ && sel.focusOffset > fillingCharSeqLength ) {
+                                               bm[ 1 ].offset -= fillingCharSeqLength;
+                                       }
                                }
                        }
 
                        // We can't simply remove the filling node because the user
                        // will actually enlarge it when typing, so we just remove the
                        // invisible char from it.
-                       fillingChar.setText( replaceFillingChar( fillingChar.getText() ) );
+                       fillingChar.setText( removeFillingCharSequenceString( fillingChar.getText(), 1 ) );
 
                        // Restore the bookmark preserving selection's direction.
                        if ( bm ) {
-                               moveNativeSelectionToBookmark( element.getDocument().$, bm );
+                               moveNativeSelectionToBookmark( editable.getDocument().$, bm );
                        }
                }
        }
 
-       function replaceFillingChar( html ) {
-               return html.replace( /\u200B( )?/g, function( match ) {
-                       // #10291 if filling char is followed by a space replace it with nbsp.
-                       return match[ 1 ] ? '\xa0' : '';
-               } );
+       // #13816
+       function removeFillingCharSequenceString( str, nbspAware ) {
+               if ( nbspAware ) {
+                       return str.replace( fillingCharSequenceRegExp, function( m, p ) {
+                               // #10291 if filling char is followed by a space replace it with NBSP.
+                               return p ? '\xa0' : '';
+                       } );
+               } else {
+                       return str.replace( fillingCharSequence, '' );
+               }
        }
 
        function createNativeSelectionBookmark( sel ) {
                                                case 8: // BACKSPACE
                                                case 45: // INS
                                                case 46: // DEl
-                                                       removeFillingChar( editable );
+                                                       removeFillingCharSequenceNode( editable );
                                        }
 
                                }, null, null, -1 );
                }
        } );
 
-       CKEDITOR.on( 'instanceReady', function( evt ) {
-               var editor = evt.editor,
-                       fillingCharBefore,
-                       selectionBookmark;
+       // On WebKit only, we need a special "filling" char on some situations
+       // (#1272). Here we set the events that should invalidate that char.
+       if ( CKEDITOR.env.webkit ) {
+               CKEDITOR.on( 'instanceReady', function( evt ) {
+                       var editor = evt.editor;
 
-               // On WebKit only, we need a special "filling" char on some situations
-               // (#1272). Here we set the events that should invalidate that char.
-               if ( CKEDITOR.env.webkit ) {
                        editor.on( 'selectionChange', function() {
-                               checkFillingChar( editor.editable() );
+                               checkFillingCharSequenceNodeReady( editor.editable() );
                        }, null, null, -1 );
+
                        editor.on( 'beforeSetMode', function() {
-                               removeFillingChar( editor.editable() );
+                               removeFillingCharSequenceNode( editor.editable() );
                        }, null, null, -1 );
 
-                       editor.on( 'beforeUndoImage', beforeData );
-                       editor.on( 'afterUndoImage', afterData );
-                       editor.on( 'beforeGetData', beforeData, null, null, 0 );
-                       editor.on( 'getData', afterData );
-               }
-
-               function beforeData() {
-                       var editable = editor.editable();
-                       if ( !editable )
-                               return;
-
-                       var fillingChar = getFillingChar( editable );
-
-                       if ( fillingChar ) {
-                               // If the selection's focus or anchor is located in the filling char's text node,
-                               // we need to restore the selection in afterData, because it will be lost
-                               // when setting text. Selection's direction must be preserved.
-                               // (#7437, #12489, #12491 comment:3)
-                               var sel = editor.document.$.getSelection();
-                               if ( sel.type != 'None' && ( sel.anchorNode == fillingChar.$ || sel.focusNode == fillingChar.$ ) )
-                                       selectionBookmark = createNativeSelectionBookmark( sel );
-
-                               fillingCharBefore = fillingChar.getText();
-                               fillingChar.setText( replaceFillingChar( fillingCharBefore ) );
-                       }
-               }
-
-               function afterData() {
-                       var editable = editor.editable();
-                       if ( !editable )
-                               return;
-
-                       var fillingChar = getFillingChar( editable );
-
-                       if ( fillingChar ) {
-                               fillingChar.setText( fillingCharBefore );
-
-                               if ( selectionBookmark ) {
-                                       moveNativeSelectionToBookmark( editor.document.$, selectionBookmark );
-                                       selectionBookmark = null;
+                       // Filter Undo snapshot's HTML to get rid of Filling Char Sequence.
+                       // Note: CKEDITOR.dom.range.createBookmark2() normalizes snapshot's
+                       // bookmarks to anticipate the removal of FCSeq from the snapshot's HTML (#13816).
+                       editor.on( 'getSnapshot', function( evt ) {
+                               if ( evt.data ) {
+                                       evt.data = removeFillingCharSequenceString( evt.data );
                                }
-                       }
-               }
-       } );
+                       }, editor, null, 20 );
+
+                       // Filter data to get rid of Filling Char Sequence. Filter on #toDataFormat
+                       // instead of #getData because once removed, FCSeq may leave an empty element,
+                       // which should be pruned by the dataProcessor (#13816).
+                       // Note: Used low priority to filter when dataProcessor works on strings,
+                       // not pseudo–DOM.
+                       editor.on( 'toDataFormat', function( evt ) {
+                               evt.data.dataValue = removeFillingCharSequenceString( evt.data.dataValue );
+                       }, null, null, 0 );
+               } );
+       }
 
        /**
         * Check the selection change in editor and potentially fires
        var styleObjectElements = { img: 1, hr: 1, li: 1, table: 1, tr: 1, td: 1, th: 1, embed: 1, object: 1, ol: 1, ul: 1,
                        a: 1, input: 1, form: 1, select: 1, textarea: 1, button: 1, fieldset: 1, thead: 1, tfoot: 1 };
 
+       // #13816
+       var fillingCharSequence = CKEDITOR.tools.repeat( '\u200b', 7 ),
+               fillingCharSequenceRegExp = new RegExp( fillingCharSequence + '( )?', 'g' );
+
+       CKEDITOR.tools.extend( CKEDITOR.dom.selection, {
+               _removeFillingCharSequenceString: removeFillingCharSequenceString,
+               _createFillingCharSequenceNode: createFillingCharSequenceNode,
+
+               /**
+                * The sequence used in a WebKit-based browser to create a Filling Character. By default it is
+                * a string of 7 zero-width space characters (U+200B).
+                *
+                * @since 4.5.7
+                * @readonly
+                * @property {String}
+                */
+               FILLING_CHAR_SEQUENCE: fillingCharSequence
+       } );
+
        CKEDITOR.dom.selection.prototype = {
                /**
                 * Gets the native selection object from the browser.
                                        if ( range.collapsed && CKEDITOR.env.webkit && rangeRequiresFix( range ) ) {
                                                // Append a zero-width space so WebKit will not try to
                                                // move the selection by itself (#1272).
-                                               var fillingChar = createFillingChar( this.root );
+                                               var fillingChar = createFillingCharSequenceNode( this.root );
                                                range.insertNode( fillingChar );
 
                                                next = fillingChar.getNext();
                                                // having something before it, it'll not blink.
                                                // Let's remove it in this case.
                                                if ( next && !fillingChar.getPrevious() && next.type == CKEDITOR.NODE_ELEMENT && next.getName() == 'br' ) {
-                                                       removeFillingChar( this.root );
+                                                       removeFillingCharSequenceNode( this.root );
                                                        range.moveToPosition( next, CKEDITOR.POSITION_BEFORE_START );
                                                } else {
                                                        range.moveToPosition( fillingChar, CKEDITOR.POSITION_AFTER_END );