Index: _source/plugins/link/dialogs/link.js =================================================================== --- _source/plugins/link/dialogs/link.js (revision 4997) +++ _source/plugins/link/dialogs/link.js Mon Feb 01 15:15:22 CST 2010 @@ -5,6 +5,7 @@ CKEDITOR.dialog.add( 'link', function( editor ) { + var plugin = CKEDITOR.plugins.link; // Handles the event when the "Target" selection box is changed. var targetChanged = function() { @@ -92,7 +93,7 @@ var parseLink = function( editor, element ) { - var href = element ? ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) : '', + var href = ( element && ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) ) || '', emailMatch, anchorMatch, urlMatch, @@ -1127,30 +1128,21 @@ var editor = this.getParentEditor(), selection = editor.getSelection(), - ranges = selection.getRanges(), - element = null, - me = this; - // Fill in all the relevant fields if there's already one link selected. - if ( ranges.length == 1 ) - { + element = null; - var rangeRoot = ranges[0].getCommonAncestor( true ); - element = rangeRoot.getAscendant( 'a', true ); - if ( element && element.getAttribute( 'href' ) ) - { + // Fill in all the relevant fields if there's already one link selected. + if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) ) - selection.selectElement( element ); + selection.selectElement( element ); - } - else if ( ( element = rangeRoot.getAscendant( 'img', true ) ) && - element.getAttribute( '_cke_real_element_type' ) && - element.getAttribute( '_cke_real_element_type' ) == 'anchor' ) + else if ( ( element = selection.getSelectedElement() ) && element.is( 'img' ) + && element.getAttribute( '_cke_real_element_type' ) + && element.getAttribute( '_cke_real_element_type' ) == 'anchor' ) - { - this.fakeObj = element; - element = editor.restoreRealElement( this.fakeObj ); - selection.selectElement( this.fakeObj ); - } - else - element = null; + { + this.fakeObj = element; + element = editor.restoreRealElement( this.fakeObj ); + selection.selectElement( this.fakeObj ); + } + else + element = null; - } this.setupContent( parseLink.apply( this, [ editor, element ] ) ); }, Index: _source/plugins/link/plugin.js =================================================================== --- _source/plugins/link/plugin.js (revision 4858) +++ _source/plugins/link/plugin.js Mon Feb 01 15:13:01 CST 2010 @@ -107,7 +107,7 @@ if ( !isAnchor ) { - if ( !( element = element.getAscendant( 'a', true ) ) ) + if ( !( element = CKEDITOR.plugins.link.getSelectedLink( editor ) ) ) return null; isAnchor = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ); @@ -147,6 +147,28 @@ requires : [ 'fakeobjects' ] } ); +CKEDITOR.plugins.link = +{ + /** + * Get the link element under current selection. + * @param editor + */ + getSelectedLink : function( editor ) + { + var selection = editor.getSelection(), + bookmarks = selection.createBookmarks(), + ranges = selection.getRanges(), + range = ranges[0], + link; + + link = range.getSurroundingElement( 'a' ); + selection.selectBookmarks( bookmarks ); + + return link; + } + +}; + CKEDITOR.unlinkCommand = function(){}; CKEDITOR.unlinkCommand.prototype = { Index: _source/core/dom/range.js =================================================================== --- _source/core/dom/range.js (revision 4858) +++ _source/core/dom/range.js Mon Feb 01 15:13:01 CST 2010 @@ -1707,8 +1707,60 @@ return container ; return container.getChild( this.endOffset - 1 ) || container ; + }, + + /** + * Retrieve the element that either surround or touch the boundary of the range. + * Note: This method may result in fragile text nodes. + * @param tagName + * @example + * var link = range.getSurroundingElement( 'a' ); + *
+ * li^nk + * [link] + * text[link] + * li[nk] + * [li]nk] + * [li]nk + *+ */ + getSurroundingElement : function( tagName ) + { + var surround; + + if( this.collapsed ) + surround = this.startContainer.getAscendant( tagName, true ); + else + { + var walker = new CKEDITOR.dom.walker( this ); + + walker.evaluator = function( node ) + { + if ( node.type == CKEDITOR.NODE_TEXT ) + { + var ascendant = node.getAscendant( tagName ); + if ( ascendant && ( !surround || ascendant.equals( surround ) ) ) + { + surround = ascendant; + return true; - } + } + else + return ( surround = false ); + } - }; + }; + + walker.guard = function() + { + return surround !== false; + }; + + // Walk through all enclosed text nodes that are parts of the *same* element. + walker.checkForward(); + + } + return surround || null; + } + }; })(); CKEDITOR.POSITION_AFTER_START = 1; //