X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fcore%2Fdom%2Frange.js;h=fedbfb97e45684a2612f0d548a5921c3e1fe1fe6;hb=48b1db88210b4160dce439c6e3e32e14af8c106b;hp=8f10980e472a859f093ce39bc09249c49e4af736;hpb=614511639979907ceb0da3614122a4d8eb963ad4;p=ckeditor.git diff --git a/_source/core/dom/range.js b/_source/core/dom/range.js index 8f10980..fedbfb9 100644 --- a/_source/core/dom/range.js +++ b/_source/core/dom/range.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -32,7 +32,7 @@ CKEDITOR.dom.range = function( document ) // This is a shared function used to delete, extract and clone the range // contents. // V2 - var execContentsAction = function( range, action, docFrag ) + var execContentsAction = function( range, action, docFrag, mergeThen ) { range.optimizeBookmark(); @@ -247,7 +247,17 @@ CKEDITOR.dom.range = function( document ) if ( removeStartNode && topEnd.$.parentNode == startNode.$.parentNode ) endIndex--; - range.setStart( topEnd.getParent(), endIndex ); + // Merge splitted parents. + if ( mergeThen && topStart.type == CKEDITOR.NODE_ELEMENT ) + { + var span = CKEDITOR.dom.element.createFromHtml( ' ', range.document ); + span.insertAfter( topStart ); + topStart.mergeSiblings( false ); + range.moveToBookmark( { startNode : span } ); + } + else + range.setStart( topEnd.getParent(), endIndex ); } // Collapse it to the start. @@ -280,7 +290,7 @@ CKEDITOR.dom.range = function( document ) // If there's any visible text, then we're not at the start. if ( CKEDITOR.tools.trim( node.getText() ).length ) return false; - } + } else if ( node.type == CKEDITOR.NODE_ELEMENT ) { // If there are non-empty inline elements (e.g. ), then we're not @@ -308,7 +318,7 @@ CKEDITOR.dom.range = function( document ) return node.type != CKEDITOR.NODE_TEXT && node.getName() in CKEDITOR.dtd.$removeEmpty || !CKEDITOR.tools.trim( node.getText() ) - || node.getParent().hasAttribute( '_cke_bookmark' ); + || !!node.getParent().data( 'cke-bookmark' ); } var whitespaceEval = new CKEDITOR.dom.walker.whitespaces(), @@ -367,25 +377,27 @@ CKEDITOR.dom.range = function( document ) /** * Deletes the content nodes of the range permanently from the DOM tree. + * @param {Boolean} [mergeThen] Merge any splitted elements result in DOM true due to partial selection. */ - deleteContents : function() + deleteContents : function( mergeThen ) { if ( this.collapsed ) return; - execContentsAction( this, 0 ); + execContentsAction( this, 0, null, mergeThen ); }, /** * The content nodes of the range are cloned and added to a document fragment, * meanwhile they're removed permanently from the DOM tree. + * @param {Boolean} [mergeThen] Merge any splitted elements result in DOM true due to partial selection. */ - extractContents : function() + extractContents : function( mergeThen ) { var docFrag = new CKEDITOR.dom.documentFragment( this.document ); if ( !this.collapsed ) - execContentsAction( this, 1, docFrag ); + execContentsAction( this, 1, docFrag, mergeThen ); return docFrag; }, @@ -413,7 +425,7 @@ CKEDITOR.dom.range = function( document ) var collapsed = this.collapsed; startNode = this.document.createElement( 'span' ); - startNode.setAttribute( '_cke_bookmark', 1 ); + startNode.data( 'cke-bookmark', 1 ); startNode.setStyle( 'display', 'none' ); // For IE, it must have something inside, otherwise it may be @@ -723,10 +735,10 @@ CKEDITOR.dom.range = function( document ) endNode = this.endContainer; if ( startNode.is && startNode.is( 'span' ) - && startNode.hasAttribute( '_cke_bookmark' ) ) + && startNode.data( 'cke-bookmark' ) ) this.setStartAt( startNode, CKEDITOR.POSITION_BEFORE_START ); if ( endNode && endNode.is && endNode.is( 'span' ) - && endNode.hasAttribute( '_cke_bookmark' ) ) + && endNode.data( 'cke-bookmark' ) ) this.setEndAt( endNode, CKEDITOR.POSITION_AFTER_END ); }, @@ -811,7 +823,12 @@ CKEDITOR.dom.range = function( document ) } }, - enlarge : function( unit ) + /** + * Expands the range so that partial units are completely contained. + * @param unit {Number} The unit type to expand with. + * @param {Boolean} [excludeBrs=false] Whether include line-breaks when expanding. + */ + enlarge : function( unit, excludeBrs ) { switch ( unit ) { @@ -932,7 +949,8 @@ CKEDITOR.dom.range = function( document ) // If this is a visible element. // We need to check for the bookmark attribute because IE insists on // rendering the display:none nodes we use for bookmarks. (#3363) - if ( sibling.$.offsetWidth > 0 && !sibling.getAttribute( '_cke_bookmark' ) ) + // Line-breaks (br) are rendered with zero width, which we don't want to include. (#7041) + if ( ( sibling.$.offsetWidth > 0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) { // We'll accept it only if we need // whitespace, and this is an inline @@ -1091,7 +1109,8 @@ CKEDITOR.dom.range = function( document ) // If this is a visible element. // We need to check for the bookmark attribute because IE insists on // rendering the display:none nodes we use for bookmarks. (#3363) - if ( sibling.$.offsetWidth > 0 && !sibling.getAttribute( '_cke_bookmark' ) ) + // Line-breaks (br) are rendered with zero width, which we don't want to include. (#7041) + if ( ( sibling.$.offsetWidth > 0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) { // We'll accept it only if we need // whitespace, and this is an inline @@ -1755,6 +1774,47 @@ CKEDITOR.dom.range = function( document ) }, /** + * Check if elements at which the range boundaries anchor are read-only, + * with respect to "contenteditable" attribute. + */ + checkReadOnly : ( function() + { + function checkNodesEditable( node, anotherEnd ) + { + while( node ) + { + if ( node.type == CKEDITOR.NODE_ELEMENT ) + { + if ( node.getAttribute( 'contentEditable' ) == 'false' + && !node.data( 'cke-editable' ) ) + { + return 0; + } + // Range enclosed entirely in an editable element. + else if ( node.is( 'body' ) + || node.getAttribute( 'contentEditable' ) == 'true' + && ( node.contains( anotherEnd ) || node.equals( anotherEnd ) ) ) + { + break; + } + } + node = node.getParent(); + } + + return 1; + } + + return function() + { + var startNode = this.startContainer, + endNode = this.endContainer; + + // Check if elements path at both boundaries are editable. + return !( checkNodesEditable( startNode, endNode ) && checkNodesEditable( endNode, startNode ) ); + }; + })(), + + /** * Moves the range boundaries to the first/end editing point inside an * element. For example, in an element tree like * "<p><b><i></i></b> Text</p>", the start editing point is