X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fselection%2Fplugin.js;h=17e2c52eeff55d92fa90f8a731ed0ce859c4c712;hb=039a051ccf3901311661022a30afd60fc38130c9;hp=cf699ce83c89ef64137525a3c601d88301235702;hpb=7cd80714081a8ffdf4a1a8d2c72f120ed5ef3d6d;p=ckeditor.git diff --git a/_source/plugins/selection/plugin.js b/_source/plugins/selection/plugin.js index cf699ce..17e2c52 100644 --- a/_source/plugins/selection/plugin.js +++ b/_source/plugins/selection/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -17,7 +17,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // In IE, the "selectionchange" event may still get thrown when // releasing the WYSIWYG mode, so we need to check it first. var sel = this.getSelection(); - if ( !sel ) + if ( !sel || !sel.document.getWindow().$ ) return; var firstElement = sel.getStartElement(); @@ -72,6 +72,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license var selectAllCmd = { + modes : { wysiwyg : 1, source : 1 }, exec : function( editor ) { switch ( editor.mode ) @@ -80,7 +81,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license editor.document.$.execCommand( 'SelectAll', false, null ); break; case 'source' : - // TODO + // Select the contents of the textarea + var textarea = editor.textarea.$ ; + if ( CKEDITOR.env.ie ) + { + textarea.createTextRange().execCommand( 'SelectAll' ) ; + } + else + { + textarea.selectionStart = 0 ; + textarea.selectionEnd = textarea.value.length ; + } + textarea.focus() ; } }, canUndo : false @@ -93,7 +105,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license editor.on( 'contentDom', function() { var doc = editor.document, - body = doc.getBody(); + body = doc.getBody(), + html = doc.getDocumentElement(); if ( CKEDITOR.env.ie ) { @@ -103,57 +116,134 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // than firing the selection change event. var savedRange, - saveEnabled; + saveEnabled, + restoreEnabled = 1; // "onfocusin" is fired before "onfocus". It makes it // possible to restore the selection before click // events get executed. - body.on( 'focusin', function() + body.on( 'focusin', function( evt ) { + // If there are elements with layout they fire this event but + // it must be ignored to allow edit its contents #4682 + if ( evt.data.$.srcElement.nodeName != 'BODY' ) + return; + // If we have saved a range, restore it at this // point. if ( savedRange ) { - // Well not break because of this. - try + // 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 ) { - savedRange.select(); + // Well not break because of this. + try + { + savedRange.select(); + } + catch (e) + {} } - catch (e) - {} savedRange = null; } }); - editor.window.on( 'focus', function() + body.on( 'focus', function() { // Enable selections to be saved. - saveEnabled = true; + saveEnabled = 1; saveSelection(); }); - body.on( 'beforedeactivate', function() + body.on( 'beforedeactivate', function( evt ) { + // Ignore this event if it's caused by focus switch between + // internal editable control type elements, e.g. layouted paragraph. (#4682) + if ( evt.data.$.toElement ) + return; + // Disable selections from being saved. - saveEnabled = false; + saveEnabled = 0; + restoreEnabled = 1; + }); + + // IE before version 8 will leave cursor blinking inside the document after + // editor blurred unless we clean up the selection. (#4716) + if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) + { + editor.on( 'blur', function( evt ) + { + // Try/Catch to avoid errors if the editor is hidden. (#6375) + try + { + editor.document && editor.document.$.selection.empty(); + } + catch (e) {} + }); + } + + // Listening on document element ensures that + // scrollbar is included. (#5280) + html.on( 'mousedown', function() + { + // Lock restore selection now, as we have + // a followed 'click' event which introduce + // new selection. (#5735) + restoreEnabled = 0; + }); + + html.on( 'mouseup', function() + { + restoreEnabled = 1; + }); + + // In IE6/7 the blinking cursor appears, but contents are + // not editable. (#5634) + if ( CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.version < 8 || CKEDITOR.env.quirks ) ) + { + // The 'click' event is not fired when clicking the + // scrollbars, so we can use it to check whether + // the empty space following has been clicked. + html.on( 'click', function( evt ) + { + if ( evt.data.getTarget().getName() == 'html' ) + editor.getSelection().getRanges()[ 0 ].select(); }); + } + var scroll; // IE fires the "selectionchange" event when clicking // inside a selection. We don't want to capture that. - body.on( 'mousedown', disableSave ); + body.on( 'mousedown', function( evt ) + { + // IE scrolls document to top on right mousedown + // when editor has no focus, remember this scroll + // position and revert it before context menu opens. (#5778) + if ( evt.data.$.button == 2 ) + { + var sel = editor.document.$.selection; + if ( sel.type == 'None' ) + scroll = editor.window.getScrollPosition(); + } + disableSave(); + }); + body.on( 'mouseup', function( evt ) { - // IE context-menu event in table cells collapse - // whatever selection is, avoiding saving this - // 'wrong' snapshot.(#3001) - evt = evt.data; - if ( evt.$.button == 2 && evt.getTarget().hasAscendant( 'table' ) ) - return; + // Restore recorded scroll position when needed on right mouseup. + if ( evt.data.$.button == 2 && scroll ) + { + editor.document.$.documentElement.scrollLeft = scroll.x; + editor.document.$.documentElement.scrollTop = scroll.y; + } + scroll = null; - saveEnabled = true; + saveEnabled = 1; setTimeout( function() { saveSelection( true ); @@ -165,7 +255,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license body.on( 'keyup', function() { - saveEnabled = true; + saveEnabled = 1; saveSelection(); }); @@ -176,7 +266,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license function disableSave() { - saveEnabled = false; + saveEnabled = 0; } function saveSelection( testIt ) @@ -184,7 +274,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( saveEnabled ) { var doc = editor.document, - sel = doc && doc.$.selection; + sel = editor.getSelection(), + nativeSel = sel && sel.getNative(); // There is a very specific case, when clicking // inside a text selection. In that case, the @@ -194,7 +285,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // range at the very start of the document. In // such situation we have to test the range, to // be sure it's valid. - if ( testIt && sel && sel.type == 'None' ) + if ( testIt && nativeSel && nativeSel.type == 'None' ) { // The "InsertImage" command can be used to // test whether the selection is good or not. @@ -207,7 +298,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } } - savedRange = sel && sel.createRange(); + // Avoid saving selection from within text input. (#5747) + var parentTag; + if ( nativeSel && nativeSel.type && nativeSel.type != 'Control' + && ( parentTag = nativeSel.createRange() ) + && ( parentTag = parentTag.parentElement() ) + && ( parentTag = parentTag.nodeName ) + && parentTag.toLowerCase() in { input: 1, textarea : 1 } ) + { + return; + } + + savedRange = nativeSel && sel.getRanges()[ 0 ]; checkSelectionChangeTimeout.call( editor ); } @@ -306,7 +408,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return lockedSelection; this.document = document; - this.isLocked = false; + this.isLocked = 0; this._ = { cache : {} @@ -440,8 +542,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return ( cache.type = type ); }, - getRanges : - CKEDITOR.env.ie ? + /** + * Retrieve the {@link CKEDITOR.dom.range} instances that represent the current selection. + * Note: Some browsers returns multiple ranges even on a sequent selection, e.g. Firefox returns + * one range for each table cell when one or more table row is selected. + * @return {Array} + * @example + * var ranges = selection.getRanges(); + * alert(ranges.length); + */ + getRanges : (function() + { + var func = CKEDITOR.env.ie ? ( function() { // Finds the container and offset for a specific boundary @@ -466,17 +578,21 @@ For licensing, see LICENSE.html or http://ckeditor.com/license testRange = range.duplicate(); testRange.moveToElementText( child ); - testRange.collapse(); - var comparison = testRange.compareEndPoints( 'StartToStart', range ); + var comparisonStart = testRange.compareEndPoints( 'StartToStart', range ), + comparisonEnd = testRange.compareEndPoints( 'EndToStart', range ); + + testRange.collapse(); - if ( comparison > 0 ) + if ( comparisonStart > 0 ) break; - else if ( comparison === 0 ) - return { - container : parent, - offset : i - }; + // When selection stay at the side of certain self-closing elements, e.g. BR, + // our comparison will never shows an equality. (#4824) + else if ( !comparisonStart + || comparisonEnd == 1 && comparisonStart == -1 ) + return { container : parent, offset : i }; + else if ( !comparisonEnd ) + return { container : parent, offset : i + 1 }; testRange = null; } @@ -495,8 +611,17 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // breaking character counting logic below. (#3949) var distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length; - while ( distance > 0 ) - distance -= siblings[ --i ].nodeValue.length; + try + { + while ( distance > 0 ) + distance -= siblings[ --i ].nodeValue.length; + } + // Measurement in IE could be somtimes wrong because of