X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=_source%2Fplugins%2Fselection%2Fplugin.js;h=39c6db7d76f77510f4ffd627ce136cde2f049f8e;hb=e73319a12b56100b29ef456fd74114fe5519e01c;hp=a42ef66f3617031c1cc52514d8cd1132407dc52c;hpb=4e70ea24db840898be8cc21c950363a52a2a6aba;p=ckeditor.git diff --git a/_source/plugins/selection/plugin.js b/_source/plugins/selection/plugin.js index a42ef66..39c6db7 100644 --- a/_source/plugins/selection/plugin.js +++ b/_source/plugins/selection/plugin.js @@ -78,6 +78,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license && node.getName() in CKEDITOR.dtd.$removeEmpty; } + function singletonBlock( node ) + { + var body = range.document.getBody(); + return !node.is( 'body' ) && body.getChildCount() == 1; + } + var start = range.startContainer, offset = range.startOffset; @@ -86,7 +92,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // 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 ) ); + // 3. The only empty block in document.^
(#7222) + return !CKEDITOR.tools.trim( start.getHtml() ) ? isInlineCt( start ) || singletonBlock( start ) + : isInlineCt( start.getChild( offset - 1 ) ) || isInlineCt( start.getChild( offset ) ); } var selectAllCmd = @@ -455,6 +463,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license doc.on( 'mouseup', checkSelectionChangeTimeout, editor ); doc.on( 'keyup', checkSelectionChangeTimeout, editor ); + doc.on( 'selectionchange', checkSelectionChangeTimeout, editor ); } }); @@ -469,15 +478,22 @@ For licensing, see LICENSE.html or http://ckeditor.com/license }); editor.selectionChange = checkSelectionChangeTimeout; + + // IE9 might cease to work if there's an object selection inside the iframe (#7639). + CKEDITOR.env.ie9Compat && editor.on( 'destroy', function() + { + var sel = editor.getSelection(); + sel && sel.getNative().clear(); + }, null, null, 9 ); } }); /** * Gets the current selection from the editing area when in WYSIWYG mode. - * @returns {CKEDITOR.dom.selection} A selection object or null if not on + * @returns {CKEDITOR.dom.selection} A selection object or null if not in * WYSIWYG mode or no selection is available. * @example - * var selection = CKEDITOR.instances.editor1.getSelection(); + * var selection = CKEDITOR.instances.editor1.getSelection(); * alert( selection.getType() ); */ CKEDITOR.editor.prototype.getSelection = function() @@ -494,7 +510,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * Gets the current selection from the document. * @returns {CKEDITOR.dom.selection} A selection object. * @example - * var selection = CKEDITOR.instances.editor1.document.getSelection(); + * var selection = CKEDITOR.instances.editor1.document.getSelection(); * alert( selection.getType() ); */ CKEDITOR.dom.document.prototype.getSelection = function() @@ -513,11 +529,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license CKEDITOR.SELECTION_NONE = 1; /** - * Text or collapsed selection. + * A text or a collapsed selection. * @constant * @example * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT ) - * alert( 'Text is selected' ); + * alert( 'A text is selected' ); */ CKEDITOR.SELECTION_TEXT = 2; @@ -533,7 +549,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license /** * Manipulates the selection in a DOM document. * @constructor + * @param {CKEDITOR.dom.document} document The DOM document that contains the selection. * @example + * var sel = new CKEDITOR.dom.selection( CKEDITOR.document ); */ CKEDITOR.dom.selection = function( document ) { @@ -551,7 +569,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license /** * IE BUG: The selection's document may be a different document than the - * editor document. Return null if that's the case. + * editor document. Return null if that is the case. */ if ( CKEDITOR.env.ie ) { @@ -578,9 +596,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license /** * Gets the native selection object from the browser. * @function - * @returns {Object} The native selection object. + * @returns {Object} The native browser selection object. * @example - * var selection = editor.getSelection().getNative(); + * var selection = editor.getSelection().getNative(); */ getNative : CKEDITOR.env.ie ? @@ -598,19 +616,19 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * Gets the type of the current selection. The following values are * available: *{@link CKEDITOR.SELECTION_NONE}
(1): No selection.{@link CKEDITOR.SELECTION_TEXT}
(2): A text or a collapsed
+ * selection is selected.{@link CKEDITOR.SELECTION_ELEMENT}
(3): An element is
+ * selected.{@link CKEDITOR.SELECTION_NONE}
, {@link CKEDITOR.SELECTION_TEXT}
, or
+ * {@link CKEDITOR.SELECTION_ELEMENT}
.
* @example
- * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
- * alert( 'Text is selected' );
+ * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
+ * alert( 'A text is selected' );
*/
getType :
CKEDITOR.env.ie ?
@@ -678,13 +696,15 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * 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}
+ * Retrieves the {@link CKEDITOR.dom.range}
instances that represent the current selection.
+ * Note: Some browsers return multiple ranges even for a continuous selection. Firefox, for example, returns
+ * one range for each table cell when one or more table rows are selected.
+ * @function
+ * @param {Boolean} [onlyEditables] If set to true
, this function retrives editable ranges only.
+ * @return {Array} Range instances that represent the current selection.
* @example
- * var ranges = selection.getRanges();
- * alert(ranges.length);
+ * var ranges = selection.getRanges();
+ * alert( ranges.length );
*/
getRanges : (function()
{
@@ -942,18 +962,30 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( range.collapsed )
continue;
+ // Range may start inside a non-editable element,
+ // replace the range start after it.
+ if ( range.startContainer.isReadOnly() )
+ {
+ var current = range.startContainer;
+ while( current )
+ {
+ if ( current.is( 'body' ) || !current.isReadOnly() )
+ break;
+
+ if ( current.type == CKEDITOR.NODE_ELEMENT
+ && current.getAttribute( 'contentEditable' ) == 'false' )
+ range.setStartAfter( current );
+
+ current = current.getParent();
+ }
+ }
+
var startContainer = range.startContainer,
endContainer = range.endContainer,
startOffset = range.startOffset,
endOffset = range.endOffset,
walkerRange = range.clone();
- // Range may start inside a non-editable element, restart range
- // by the end of it.
- var readOnly;
- if ( ( readOnly = startContainer.isReadOnly() ) )
- range.setStartAfter( readOnly );
-
// Enlarge range start/end with text node to avoid walker
// being DOM destructive, it doesn't interfere our checking
// of elements below as well.
@@ -1016,7 +1048,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
* @returns {CKEDITOR.dom.element} The element at the beginning of the
* selection.
* @example
- * var element = editor.getSelection().getStartElement();
+ * var element = editor.getSelection().getStartElement();
* alert( element.getName() );
*/
getStartElement : function()
@@ -1092,12 +1124,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * Gets the current selected element.
+ * Gets the currently selected element.
* @returns {CKEDITOR.dom.element} The selected element. Null if no
* selection is available or the selection type is not
- * {@link CKEDITOR.SELECTION_ELEMENT}.
+ * {@link CKEDITOR.SELECTION_ELEMENT}
.
* @example
- * var element = editor.getSelection().getSelectedElement();
+ * var element = editor.getSelection().getSelectedElement();
* alert( element.getName() );
*/
getSelectedElement : function()
@@ -1114,6 +1146,74 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
{
return self.getNative().createRange().item( 0 );
},
+ // If a table or list is fully selected.
+ function()
+ {
+ var root,
+ retval,
+ range = self.getRanges()[ 0 ],
+ ancestor = range.getCommonAncestor( 1, 1 ),
+ tags = { table:1,ul:1,ol:1,dl:1 };
+
+ for ( var t in tags )
+ {
+ if ( root = ancestor.getAscendant( t, 1 ) )
+ break;
+ }
+
+ if ( root )
+ {
+ // Enlarging the start boundary.
+ var testRange = new CKEDITOR.dom.range( this.document );
+ testRange.setStartAt( root, CKEDITOR.POSITION_AFTER_START );
+ testRange.setEnd( range.startContainer, range.startOffset );
+
+ var enlargeables = CKEDITOR.tools.extend( tags, CKEDITOR.dtd.$listItem, CKEDITOR.dtd.$tableContent ),
+ walker = new CKEDITOR.dom.walker( testRange ),
+ // Check the range is at the inner boundary of the structural element.
+ guard = function( walker, isEnd )
+ {
+ return function( node, isWalkOut )
+ {
+ if ( node.type == CKEDITOR.NODE_TEXT && ( !CKEDITOR.tools.trim( node.getText() ) || node.getParent().data( 'cke-bookmark' ) ) )
+ return true;
+
+ var tag;
+ if ( node.type == CKEDITOR.NODE_ELEMENT )
+ {
+ tag = node.getName();
+
+ // Bypass bogus br at the end of block.
+ if ( tag == 'br' && isEnd && node.equals( node.getParent().getBogus() ) )
+ return true;
+
+ if ( isWalkOut && tag in enlargeables || tag in CKEDITOR.dtd.$removeEmpty )
+ return true;
+ }
+
+ walker.halted = 1;
+ return false;
+ };
+ };
+
+ walker.guard = guard( walker );
+
+ if ( walker.checkBackward() && !walker.halted )
+ {
+ walker = new CKEDITOR.dom.walker( testRange );
+ testRange.setStart( range.endContainer, range.endOffset );
+ testRange.setEndAt( root, CKEDITOR.POSITION_BEFORE_END );
+ walker.guard = guard( walker, 1 );
+ if ( walker.checkForward() && !walker.halted )
+ retval = root.$;
+ }
+ }
+
+ if ( !retval )
+ throw 0;
+
+ return retval;
+ },
// Figure it out by checking if there's a single enclosed
// node of the range.
function()
@@ -1138,12 +1238,43 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
return cache.selectedElement = ( node ? new CKEDITOR.dom.element( node ) : null );
},
+ /**
+ * Retrieves the text contained within the range. An empty string is returned for non-text selection.
+ * @returns {String} A string of text within the current selection.
+ * @since 3.6.1
+ * @example
+ * var text = editor.getSelection().getSelectedText();
+ * alert( text );
+ */
+ getSelectedText : function()
+ {
+ var cache = this._.cache;
+ if ( cache.selectedText !== undefined )
+ return cache.selectedText;
+
+ var text = '',
+ nativeSel = this.getNative();
+ if ( this.getType() == CKEDITOR.SELECTION_TEXT )
+ text = CKEDITOR.env.ie ? nativeSel.createRange().text : nativeSel.toString();
+
+ return ( cache.selectedText = text );
+ },
+
+ /**
+ * Locks the selection made in the editor in order to make it possible to
+ * manipulate it without browser interference. A locked selection is
+ * cached and remains unchanged until it is released with the #unlock
+ * method.
+ * @example
+ * editor.getSelection().lock();
+ */
lock : function()
{
// Call all cacheable function.
this.getRanges();
this.getStartElement();
this.getSelectedElement();
+ this.getSelectedText();
// The native selection is not available when locked.
this._.cache.nativeSel = {};
@@ -1154,6 +1285,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
this.document.setCustomData( 'cke_locked_selection', this );
},
+ /**
+ * Unlocks the selection made in the editor and locked with the #lock
method.
+ * An unlocked selection is no longer cached and can be changed.
+ * @param {Boolean} [restore] If set to true
, the selection is restored back to the selection saved earlier by using the #lock
method.
+ * @example
+ * editor.getSelection().unlock();
+ */
unlock : function( restore )
{
var doc = this.document,
@@ -1187,14 +1325,22 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
}
},
+ /**
+ * Clears the selection cache.
+ * @example
+ * editor.getSelection().reset();
+ */
reset : function()
{
this._.cache = {};
},
/**
- * Make the current selection of type {@link CKEDITOR.SELECTION_ELEMENT} by enclosing the specified element.
- * @param element
+ * Makes the current selection of type {@link CKEDITOR.SELECTION_ELEMENT}
by enclosing the specified element.
+ * @param {CKEDITOR.dom.element} element The element to enclose in the selection.
+ * @example
+ * var element = editor.document.getById( 'sampleElement' );
+ * editor.getSelection.selectElement( element );
*/
selectElement : function( element )
{
@@ -1223,9 +1369,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * Adding the specified ranges to document selection preceding
- * by clearing up the original selection.
- * @param {CKEDITOR.dom.range} ranges
+ * Clears the original selection and adds the specified ranges
+ * to the document selection.
+ * @param {Array} ranges An array of {@link CKEDITOR.dom.range}
instances representing ranges to be added to the document.
+ * @example
+ * var ranges = new CKEDITOR.dom.range( editor.document );
+ * editor.getSelection().selectRanges( [ ranges ] );
*/
selectRanges : function( ranges )
{
@@ -1364,15 +1513,20 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
sel.addRange( nativeRange );
}
+ // Don't miss selection change event for non-IEs.
+ this.document.fire( 'selectionchange' );
this.reset();
}
},
/**
- * Create bookmark for every single of this selection range (from #getRanges)
- * by calling the {@link CKEDITOR.dom.range.prototype.createBookmark} method,
- * with extra cares to avoid interferon among those ranges. Same arguments are
- * received as with the underlay range method.
+ * Creates a bookmark for each range of this selection (from #getRanges
)
+ * by calling the {@link CKEDITOR.dom.range.prototype.createBookmark}
method,
+ * with extra care taken to avoid interference among those ranges. The arguments
+ * received are the same as with the underlying range method.
+ * @returns {Array} Array of bookmarks for each range.
+ * @example
+ * var bookmarks = editor.getSelection().createBookmarks();
*/
createBookmarks : function( serializable )
{
@@ -1380,10 +1534,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * Create bookmark for every single of this selection range (from #getRanges)
- * by calling the {@link CKEDITOR.dom.range.prototype.createBookmark2} method,
- * with extra cares to avoid interferon among those ranges. Same arguments are
- * received as with the underlay range method.
+ * Creates a bookmark for each range of this selection (from #getRanges
)
+ * by calling the {@link CKEDITOR.dom.range.prototype.createBookmark2}
method,
+ * with extra care taken to avoid interference among those ranges. The arguments
+ * received are the same as with the underlying range method.
+ * @returns {Array} Array of bookmarks for each range.
+ * @example
+ * var bookmarks = editor.getSelection().createBookmarks2();
*/
createBookmarks2 : function( normalized )
{
@@ -1391,8 +1548,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * Select the virtual ranges denote by the bookmarks by calling #selectRanges.
- * @param bookmarks
+ * Selects the virtual ranges denoted by the bookmarks by calling #selectRanges
.
+ * @param {Array} bookmarks The bookmarks representing ranges to be selected.
+ * @returns {CKEDITOR.dom.selection} This selection object, after the ranges were selected.
+ * @example
+ * var bookmarks = editor.getSelection().createBookmarks();
+ * editor.getSelection().selectBookmarks( bookmarks );
*/
selectBookmarks : function( bookmarks )
{
@@ -1408,7 +1569,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * Retrieve the common ancestor node of the first range and the last range.
+ * Retrieves the common ancestor node of the first range and the last range.
+ * @returns {CKEDITOR.dom.element} The common ancestor of the selection.
+ * @example
+ * var ancestor = editor.getSelection().getCommonAncestor();
*/
getCommonAncestor : function()
{
@@ -1419,7 +1583,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
},
/**
- * Moving scroll bar to the current selection's start position.
+ * Moves the scrollbar to the starting position of the current selection.
+ * @example
+ * editor.getSelection().scrollIntoView();
*/
scrollIntoView : function()
{