CKEDITOR.plugins.add( 'link', {\r
requires: 'dialog,fakeobjects',\r
// jscs:disable maximumLineLength\r
- lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r
+ lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r
// jscs:enable maximumLineLength\r
icons: 'anchor,anchor-rtl,link,unlink', // %REMOVE_LINE_CORE%\r
hidpi: true, // %REMOVE_LINE_CORE%\r
CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' );\r
\r
editor.on( 'doubleclick', function( evt ) {\r
- var element = CKEDITOR.plugins.link.getSelectedLink( editor ) || evt.data.element;\r
+ // If the link has descendants and the last part of it is also a part of a word partially\r
+ // unlinked, clicked element may be a descendant of the link, not the link itself (http://dev.ckeditor.com/ticket/11956).\r
+ // The evt.data.element.getAscendant( 'img', 1 ) condition allows opening anchor dialog if the anchor is empty (#501).\r
+ var element = evt.data.element.getAscendant( { a: 1, img: 1 }, true );\r
\r
- if ( !element.isReadOnly() ) {\r
+ if ( element && !element.isReadOnly() ) {\r
if ( element.is( 'a' ) ) {\r
evt.data.dialog = ( element.getAttribute( 'name' ) && ( !element.getAttribute( 'href' ) || !element.getChildCount() ) ) ? 'anchor' : 'link';\r
\r
\r
// If event was cancelled, link passed in event data will not be selected.\r
editor.on( 'doubleclick', function( evt ) {\r
- // Make sure both links and anchors are selected (#11822).\r
+ // Make sure both links and anchors are selected (http://dev.ckeditor.com/ticket/11822).\r
if ( evt.data.dialog in { link: 1, anchor: 1 } && evt.data.link )\r
editor.getSelection().selectElement( evt.data.link );\r
}, null, null, 20 );\r
*\r
* @since 3.2.1\r
* @param {CKEDITOR.editor} editor\r
+ * @param {Boolean} [returnMultiple=false] Indicates whether the function should return only the first selected link or all of them.\r
+ * @returns {CKEDITOR.dom.element/CKEDITOR.dom.element[]/null} A single link element or an array of link\r
+ * elements relevant to the current selection.\r
*/\r
- getSelectedLink: function( editor ) {\r
- var selection = editor.getSelection();\r
- var selectedElement = selection.getSelectedElement();\r
- if ( selectedElement && selectedElement.is( 'a' ) )\r
+ getSelectedLink: function( editor, returnMultiple ) {\r
+ var selection = editor.getSelection(),\r
+ selectedElement = selection.getSelectedElement(),\r
+ ranges = selection.getRanges(),\r
+ links = [],\r
+ link,\r
+ range,\r
+ i;\r
+\r
+ if ( !returnMultiple && selectedElement && selectedElement.is( 'a' ) ) {\r
return selectedElement;\r
+ }\r
+\r
+ for ( i = 0; i < ranges.length; i++ ) {\r
+ range = selection.getRanges()[ i ];\r
\r
- var range = selection.getRanges()[ 0 ];\r
+ // Skip bogus to cover cases of multiple selection inside tables (#tp2245).\r
+ range.shrink( CKEDITOR.SHRINK_TEXT, false, { skipBogus: true } );\r
+ link = editor.elementPath( range.getCommonAncestor() ).contains( 'a', 1 );\r
\r
- if ( range ) {\r
- range.shrink( CKEDITOR.SHRINK_TEXT );\r
- return editor.elementPath( range.getCommonAncestor() ).contains( 'a', 1 );\r
+ if ( link && returnMultiple ) {\r
+ links.push( link );\r
+ } else if ( link ) {\r
+ return link;\r
+ }\r
}\r
- return null;\r
+\r
+ return returnMultiple ? links : null;\r
},\r
\r
/**\r
var editable = editor.editable(),\r
\r
// The scope of search for anchors is the entire document for inline editors\r
- // and editor's editable for classic editor/divarea (#11359).\r
+ // and editor's editable for classic editor/divarea (http://dev.ckeditor.com/ticket/11359).\r
scope = ( editable.isInline() && !editor.plugins.divarea ) ? editor.document : editable,\r
\r
links = scope.getElementsByTag( 'a' ),\r
fakeAnchor: true,\r
\r
/**\r
- * For browsers that do not support CSS3 `a[name]:empty()`. Note that IE9 is included because of #7783.\r
+ * For browsers that do not support CSS3 `a[name]:empty()`. Note that IE9 is included because of http://dev.ckeditor.com/ticket/7783.\r
*\r
* @readonly\r
* @deprecated 4.3.3 It is set to `false` in every browser.\r
if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) ) {\r
if ( emailProtection == 'encode' ) {\r
href = href.replace( encodedEmailLinkRegex, function( match, protectedAddress, rest ) {\r
- // Without it 'undefined' is appended to e-mails without subject and body (#9192).\r
+ // Without it 'undefined' is appended to e-mails without subject and body (http://dev.ckeditor.com/ticket/9192).\r
rest = rest || '';\r
\r
return 'mailto:' +\r
\r
var featureMatch;\r
while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[ 2 ] ) ) ) {\r
- // Some values should remain numbers (#7300)\r
+ // Some values should remain numbers (http://dev.ckeditor.com/ticket/7300)\r
if ( ( featureMatch[ 2 ] == 'yes' || featureMatch[ 2 ] == '1' ) && !( featureMatch[ 1 ] in { height: 1, width: 1, top: 1, left: 1 } ) )\r
retval.target[ featureMatch[ 1 ] ] = true;\r
else if ( isFinite( featureMatch[ 2 ] ) )\r
set[ 'data-cke-saved-name' ] = set.name;\r
}\r
\r
- // Browser need the "href" fro copy/paste link to work. (#6641)\r
+ // Browser need the "href" fro copy/paste link to work. (http://dev.ckeditor.com/ticket/6641)\r
if ( set[ 'data-cke-saved-href' ] )\r
set.href = set[ 'data-cke-saved-href' ];\r
\r
*/\r
showDisplayTextForElement: function( element, editor ) {\r
var undesiredElements = {\r
- img: 1,\r
- table: 1,\r
- tbody: 1,\r
- thead: 1,\r
- tfoot: 1,\r
- input: 1,\r
- select: 1,\r
- textarea: 1\r
- };\r
+ img: 1,\r
+ table: 1,\r
+ tbody: 1,\r
+ thead: 1,\r
+ tfoot: 1,\r
+ input: 1,\r
+ select: 1,\r
+ textarea: 1\r
+ },\r
+ selection = editor.getSelection();\r
\r
// Widget duck typing, we don't want to show display text for widgets.\r
if ( editor.widgets && editor.widgets.focused ) {\r
return false;\r
}\r
\r
+ if ( selection && selection.getRanges().length > 1 ) {\r
+ return false;\r
+ }\r
+\r
return !element || !element.getName || !element.is( undesiredElements );\r
}\r
};\r
CKEDITOR.unlinkCommand = function() {};\r
CKEDITOR.unlinkCommand.prototype = {\r
exec: function( editor ) {\r
+ // IE/Edge removes link from selection while executing "unlink" command when cursor\r
+ // is right before/after link's text. Therefore whole link must be selected and the\r
+ // position of cursor must be restored to its initial state after unlinking. (http://dev.ckeditor.com/ticket/13062)\r
+ if ( CKEDITOR.env.ie ) {\r
+ var range = editor.getSelection().getRanges()[ 0 ],\r
+ link = ( range.getPreviousEditableNode() && range.getPreviousEditableNode().getAscendant( 'a', true ) ) ||\r
+ ( range.getNextEditableNode() && range.getNextEditableNode().getAscendant( 'a', true ) ),\r
+ bookmark;\r
+\r
+ if ( range.collapsed && link ) {\r
+ bookmark = range.createBookmark();\r
+ range.selectNodeContents( link );\r
+ range.select();\r
+ }\r
+ }\r
+\r
var style = new CKEDITOR.style( { element: 'a', type: CKEDITOR.STYLE_INLINE, alwaysRemoveElement: 1 } );\r
editor.removeStyle( style );\r
+\r
+ if ( bookmark ) {\r
+ range.moveToBookmark( bookmark );\r
+ range.select();\r
+ }\r
},\r
\r
refresh: function( editor, path ) {\r
\r
contextSensitive: 1,\r
startDisabled: 1,\r
- requiredContent: 'a[href]'\r
+ requiredContent: 'a[href]',\r
+ editorFocus: 1\r
};\r
\r
CKEDITOR.removeAnchorCommand = function() {};\r