X-Git-Url: https://jasonwoof.com/gitweb/?p=ckeditor.git;a=blobdiff_plain;f=_source%2Fplugins%2Fselection%2Fplugin.js;h=66161f3b745726941e3e79db294c3f6a71c55c09;hp=fd8332e0a04a2925d00e9a4dba166a1168210942;hb=4e90e78dc97789709ee7404359a5517540c27553;hpb=8f6c203fdaa543c3bca40baea6ae4ddcdf1a77f5 diff --git a/_source/plugins/selection/plugin.js b/_source/plugins/selection/plugin.js index fd8332e..66161f3 100644 --- a/_source/plugins/selection/plugin.js +++ b/_source/plugins/selection/plugin.js @@ -70,6 +70,25 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // #### checkSelectionChange : END + function rangeRequiresFix( range ) + { + function isInlineCt( node ) + { + return node && node.type == CKEDITOR.NODE_ELEMENT + && node.getName() in CKEDITOR.dtd.$removeEmpty; + } + + var start = range.startContainer, + offset = range.startOffset; + + if ( start.type == CKEDITOR.NODE_TEXT ) + return false; + + // 1. Empty inline element. ^ + // 2. Adjoin to inline element.

text^

+ return !CKEDITOR.tools.trim( start.getHtml() ) ? isInlineCt( start ) : isInlineCt( start.getChild( offset - 1 ) ) || isInlineCt( start.getChild( offset ) ); + } + var selectAllCmd = { modes : { wysiwyg : 1, source : 1 }, @@ -99,10 +118,116 @@ For licensing, see LICENSE.html or http://ckeditor.com/license canUndo : false }; + function createFillingChar( doc ) + { + removeFillingChar( doc ); + + var fillingChar = doc.createText( '\u200B' ); + doc.setCustomData( 'cke-fillingChar', fillingChar ); + + return fillingChar; + } + + function getFillingChar( doc ) + { + return doc && doc.getCustomData( 'cke-fillingChar' ); + } + + // Checks if a filling char has been used, eventualy removing it (#1272). + function checkFillingChar( doc ) + { + var fillingChar = doc && getFillingChar( doc ); + if ( fillingChar ) + { + // Use this flag to avoid removing the filling char right after + // creating it. + if ( fillingChar.getCustomData( 'ready' ) ) + removeFillingChar( doc ); + else + fillingChar.setCustomData( 'ready', 1 ); + } + } + + function removeFillingChar( doc ) + { + var fillingChar = doc && doc.removeCustomData( 'cke-fillingChar' ); + if ( fillingChar ) + { + // 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( fillingChar.getText().replace( /\u200B/g, '' ) ); + fillingChar = 0; + } + } + CKEDITOR.plugins.add( 'selection', { init : function( 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.document ); } ); + editor.on( 'beforeSetMode', function() { removeFillingChar( editor.document ); } ); + editor.on( 'key', function( e ) + { + // Remove the filling char before some keys get + // executed, so they'll not get blocked by it. + switch ( e.data.keyCode ) + { + case 13 : // ENTER + case CKEDITOR.SHIFT + 13 : // SHIFT-ENTER + case 37 : // LEFT-ARROW + case 39 : // RIGHT-ARROW + case 8 : // BACKSPACE + removeFillingChar( editor.document ); + } + }, null, null, 10 ); + + var fillingCharBefore, + resetSelection; + + function beforeData() + { + var doc = editor.document, + fillingChar = getFillingChar( doc ); + + if ( fillingChar ) + { + // If cursor is right blinking by side of the filler node, save it for restoring, + // as the following text substitution will blind it. (#7437) + var sel = doc.$.defaultView.getSelection(); + if ( sel.type == 'Caret' && sel.anchorNode == fillingChar.$ ) + resetSelection = 1; + + fillingCharBefore = fillingChar.getText(); + fillingChar.setText( fillingCharBefore.replace( /\u200B/g, '' ) ); + } + } + function afterData() + { + var doc = editor.document, + fillingChar = getFillingChar( doc ); + + if ( fillingChar ) + { + fillingChar.setText( fillingCharBefore ); + + if ( resetSelection ) + { + doc.$.defaultView.getSelection().setPosition( fillingChar.$,fillingChar.getLength() ); + resetSelection = 0; + } + } + } + editor.on( 'beforeUndoImage', beforeData ); + editor.on( 'afterUndoImage', afterData ); + editor.on( 'beforeGetData', beforeData, null, null, 0 ); + editor.on( 'getData', afterData ); + } + editor.on( 'contentDom', function() { var doc = editor.document, @@ -134,10 +259,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // point. if ( savedRange ) { - // Range restored here might invalidate the DOM structure thus break up - // the locked selection, give it up. (#6083) - var lockedSelection = doc.getCustomData( 'cke_locked_selection' ); - if ( restoreEnabled && !lockedSelection ) + if ( restoreEnabled ) { // Well not break because of this. try @@ -146,6 +268,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } catch (e) {} + + // Update locked selection because of the normalized text nodes. (#6083, #6987) + var lockedSelection = doc.getCustomData( 'cke_locked_selection' ); + if ( lockedSelection ) + { + lockedSelection.unlock(); + lockedSelection.lock(); + } } savedRange = null; @@ -571,7 +701,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license range.collapse( start ); // Gets the element that encloses the range entirely. - var parent = range.parentElement(); + var parent = range.parentElement(), + doc = parent.ownerDocument; // Empty parent element, e.g. ^ if ( !parent.hasChildNodes() ) @@ -579,6 +710,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license var siblings = parent.children, child, + sibling, testRange = range.duplicate(), startIndex = 0, endIndex = siblings.length - 1, @@ -600,7 +732,21 @@ For licensing, see LICENSE.html or http://ckeditor.com/license else if ( position < 0 ) startIndex = index + 1; else - return { container : parent, offset : getNodeIndex( child ) }; + { + // IE9 report wrong measurement with compareEndPoints when range anchors between two BRs. + // e.g.

text
^

(#7433) + if ( CKEDITOR.env.ie9Compat && child.tagName == 'BR' ) + { + var bmId = 'cke_range_marker'; + range.execCommand( 'CreateBookmark', false, bmId ); + child = doc.getElementsByName( bmId )[ 0 ]; + var offset = getNodeIndex( child ); + parent.removeChild( child ); + return { container : parent, offset : offset }; + } + else + return { container : parent, offset : getNodeIndex( child ) }; + } } // All childs are text nodes, @@ -656,10 +802,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Start the measuring until distance overflows, meanwhile count the text nodes. while ( distance > 0 ) { - child = child[ position > 0 ? 'previousSibling' : 'nextSibling' ]; try { - distance -= child.nodeValue.length; + sibling = child[ position > 0 ? 'previousSibling' : 'nextSibling' ]; + distance -= sibling.nodeValue.length; + child = sibling; } // Measurement in IE could be somtimes wrong because of