JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.2.2
[ckeditor.git] / _source / plugins / link / dialogs / link.js
index 283c5f7..57c483c 100644 (file)
@@ -1,10 +1,11 @@
 /*\r
-Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.html or http://ckeditor.com/license\r
 */\r
 \r
 CKEDITOR.dialog.add( 'link', function( editor )\r
 {\r
+       var plugin = CKEDITOR.plugins.link;\r
        // Handles the event when the "Target" selection box is changed.\r
        var targetChanged = function()\r
        {\r
@@ -17,18 +18,26 @@ CKEDITOR.dialog.add( 'link', function( editor )
                        return;\r
 \r
                popupFeatures = popupFeatures.getElement();\r
+               popupFeatures.hide();\r
+               targetName.setValue( '' );\r
+\r
+               switch ( value )\r
+               {\r
+                       case 'frame' :\r
+                               targetName.setLabel( editor.lang.link.targetFrameName );\r
+                               targetName.getElement().show();\r
+                               break;\r
+                       case 'popup' :\r
+                               popupFeatures.show();\r
+                               targetName.setLabel( editor.lang.link.targetPopupName );\r
+                               targetName.getElement().show();\r
+                               break;\r
+                       default :\r
+                               targetName.setValue( value );\r
+                               targetName.getElement().hide();\r
+                               break;\r
+               }\r
 \r
-               if ( value == 'popup' )\r
-               {\r
-                       popupFeatures.show();\r
-                       targetName.setLabel( editor.lang.link.targetPopupName );\r
-               }\r
-               else\r
-               {\r
-                       popupFeatures.hide();\r
-                       targetName.setLabel( editor.lang.link.targetFrameName );\r
-                       this.getDialog().setValueOf( 'target', 'linkTargetName', value.charAt( 0 ) == '_' ? value : '' );\r
-               }\r
        };\r
 \r
        // Handles the event when the "Type" selection box is changed.\r
@@ -37,7 +46,8 @@ CKEDITOR.dialog.add( 'link', function( editor )
                var dialog = this.getDialog(),\r
                        partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ],\r
                        typeValue = this.getValue(),\r
-                       uploadInitiallyHidden = dialog.definition.getContents( 'upload' ).hidden;\r
+                       uploadTab = dialog.definition.getContents( 'upload' ),\r
+                       uploadInitiallyHidden = uploadTab && uploadTab.hidden;\r
 \r
                if ( typeValue == 'url' )\r
                {\r
@@ -68,12 +78,15 @@ CKEDITOR.dialog.add( 'link', function( editor )
        };\r
 \r
        // Loads the parameters in a selected link to the link dialog fields.\r
-       var emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,\r
+       var javascriptProtocolRegex = /^javascript:/,\r
+               emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,\r
                emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,\r
                emailBodyRegex = /body=([^;?:@&=$,\/]*)/,\r
                anchorRegex = /^#(.*)$/,\r
                urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,\r
-               selectableTargets = /^(_(?:self|top|parent|blank))$/;\r
+               selectableTargets = /^(_(?:self|top|parent|blank))$/,\r
+               encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/,\r
+               functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/;\r
 \r
        var popupRegex =\r
                /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/;\r
@@ -81,45 +94,85 @@ CKEDITOR.dialog.add( 'link', function( editor )
 \r
        var parseLink = function( editor, element )\r
        {\r
-               var href = element ? ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) : '',\r
-                       emailMatch = '',\r
-                       anchorMatch = '',\r
-                       urlMatch = false,\r
+               var href = ( element  && ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) ) || '',\r
+                       javascriptMatch,\r
+                       emailMatch,\r
+                       anchorMatch,\r
+                       urlMatch,\r
                        retval = {};\r
 \r
-               if ( href )\r
+               if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) )\r
                {\r
-                       emailMatch = href.match( emailRegex );\r
-                       anchorMatch = href.match( anchorRegex );\r
-                       urlMatch = href.match( urlRegex );\r
-               }\r
+                       if ( emailProtection == 'encode' )\r
+                       {\r
+                               href = href.replace( encodedEmailLinkRegex,\r
+                                               function ( match, protectedAddress, rest )\r
+                                               {\r
+                                                       return 'mailto:' +\r
+                                                              String.fromCharCode.apply( String, protectedAddress.split( ',' ) ) +\r
+                                                              ( rest && unescapeSingleQuote( rest ) );\r
+                                               });\r
+                       }\r
+                       // Protected email link as function call.\r
+                       else if ( emailProtection )\r
+                       {\r
+                               href.replace( functionCallProtectedEmailLinkRegex, function( match, funcName, funcArgs )\r
+                               {\r
+                                       if ( funcName == compiledProtectionFunction.name )\r
+                                       {\r
+                                               retval.type = 'email';\r
+                                               var email = retval.email = {};\r
 \r
-               // Load the link type and URL.\r
-               if ( emailMatch )\r
-               {\r
-                       var subjectMatch = href.match( emailSubjectRegex ),\r
-                               bodyMatch = href.match( emailBodyRegex );\r
-                       retval.type = 'email';\r
-                       retval.email = {};\r
-                       retval.email.address = emailMatch[1];\r
-                       subjectMatch && ( retval.email.subject = decodeURIComponent( subjectMatch[1] ) );\r
-                       bodyMatch && ( retval.email.body = decodeURIComponent( bodyMatch[1] ) );\r
-               }\r
-               else if ( anchorMatch )\r
-               {\r
-                       retval.type = 'anchor';\r
-                       retval.anchor = {};\r
-                       retval.anchor.name = retval.anchor.id = anchorMatch[1];\r
+                                               var paramRegex = /[^,\s]+/g,\r
+                                                       paramQuoteRegex = /(^')|('$)/g,\r
+                                                       paramsMatch = funcArgs.match( paramRegex ),\r
+                                                       paramsMatchLength = paramsMatch.length,\r
+                                                       paramName,\r
+                                                       paramVal;\r
+\r
+                                               for ( var i = 0; i < paramsMatchLength; i++ )\r
+                                               {\r
+                                                       paramVal = decodeURIComponent( unescapeSingleQuote( paramsMatch[ i ].replace( paramQuoteRegex, '' ) ) );\r
+                                                       paramName = compiledProtectionFunction.params[ i ].toLowerCase();\r
+                                                       email[ paramName ] = paramVal;\r
+                                               }\r
+                                               email.address = [ email.name, email.domain ].join( '@' );\r
+                                       }\r
+                               } );\r
+                       }\r
                }\r
-               else if ( href && urlMatch )            // urlRegex matches empty strings, so need to check for href as well.\r
+\r
+               if ( !retval.type )\r
                {\r
-                       retval.type = 'url';\r
-                       retval.url = {};\r
-                       retval.url.protocol = urlMatch[1];\r
-                       retval.url.url = urlMatch[2];\r
+                       if ( ( anchorMatch = href.match( anchorRegex ) ) )\r
+                       {\r
+                               retval.type = 'anchor';\r
+                               retval.anchor = {};\r
+                               retval.anchor.name = retval.anchor.id = anchorMatch[1];\r
+                       }\r
+                       // Protected email link as encoded string.\r
+                       else if ( ( emailMatch = href.match( emailRegex ) ) )\r
+                       {\r
+                               var subjectMatch = href.match( emailSubjectRegex ),\r
+                                       bodyMatch = href.match( emailBodyRegex );\r
+\r
+                               retval.type = 'email';\r
+                               var email = ( retval.email = {} );\r
+                               email.address = emailMatch[ 1 ];\r
+                               subjectMatch && ( email.subject = decodeURIComponent( subjectMatch[ 1 ] ) );\r
+                               bodyMatch && ( email.body = decodeURIComponent( bodyMatch[ 1 ] ) );\r
+                       }\r
+                       // urlRegex matches empty strings, so need to check for href as well.\r
+                       else if (  href && ( urlMatch = href.match( urlRegex ) ) )\r
+                       {\r
+                               retval.type = 'url';\r
+                               retval.url = {};\r
+                               retval.url.protocol = urlMatch[1];\r
+                               retval.url.url = urlMatch[2];\r
+                       }\r
+                       else\r
+                               retval.type = 'url';\r
                }\r
-               else\r
-                       retval.type = 'url';\r
 \r
                // Load target and popup settings.\r
                if ( element )\r
@@ -186,7 +239,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                        realAnchors = new CKEDITOR.dom.nodeList( editor.document.$.anchors ),\r
                        anchors = retval.anchors = [];\r
 \r
-               for( var i = 0; i < elements.count() ; i++ )\r
+               for ( var i = 0; i < elements.count() ; i++ )\r
                {\r
                        var item = elements.getItem( i );\r
                        if ( item.getAttribute( '_cke_realelement' ) && item.getAttribute( '_cke_real_element_type' ) == 'anchor' )\r
@@ -244,6 +297,72 @@ CKEDITOR.dialog.add( 'link', function( editor )
                return commitParams.call( this, 'adv', data );\r
        };\r
 \r
+       function unescapeSingleQuote( str )\r
+       {\r
+               return str.replace( /\\'/g, '\'' );\r
+       }\r
+\r
+       function escapeSingleQuote( str )\r
+       {\r
+               return str.replace( /'/g, '\\$&' );\r
+       }\r
+\r
+       var emailProtection = editor.config.emailProtection || '';\r
+\r
+       // Compile the protection function pattern.\r
+       if ( emailProtection && emailProtection != 'encode' )\r
+       {\r
+               var compiledProtectionFunction = {};\r
+\r
+               emailProtection.replace( /^([^(]+)\(([^)]+)\)$/, function( match, funcName, params )\r
+               {\r
+                       compiledProtectionFunction.name = funcName;\r
+                       compiledProtectionFunction.params = [];\r
+                       params.replace( /[^,\s]+/g, function( param )\r
+                       {\r
+                               compiledProtectionFunction.params.push( param );\r
+                       } );\r
+               } );\r
+       }\r
+\r
+       function protectEmailLinkAsFunction( email )\r
+       {\r
+               var retval,\r
+                       name = compiledProtectionFunction.name,\r
+                       params = compiledProtectionFunction.params,\r
+                       paramName,\r
+                       paramValue;\r
+\r
+               retval = [ name, '(' ];\r
+               for ( var i = 0; i < params.length; i++ )\r
+               {\r
+                       paramName = params[ i ].toLowerCase();\r
+                       paramValue = email[ paramName ];\r
+\r
+                       i > 0 && retval.push( ',' );\r
+                       retval.push( '\'',\r
+                                                paramValue ?\r
+                                                escapeSingleQuote( encodeURIComponent( email[ paramName ] ) )\r
+                                                : '',\r
+                                                '\'');\r
+               }\r
+               retval.push( ')' );\r
+               return retval.join( '' );\r
+       }\r
+\r
+       function protectEmailAddressAsEncodedString( address )\r
+       {\r
+               var charCode,\r
+                       length = address.length,\r
+                       encodedChars = [];\r
+               for ( var i = 0; i < length; i++ )\r
+               {\r
+                       charCode = address.charCodeAt( i );\r
+                       encodedChars.push( charCode );\r
+               }\r
+               return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')';\r
+       }\r
+\r
        return {\r
                title : editor.lang.link.title,\r
                minWidth : 350,\r
@@ -262,7 +381,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                'default' : 'url',\r
                                                items :\r
                                                [\r
-                                                       [ editor.lang.common.url, 'url' ],\r
+                                                       [ editor.lang.link.toUrl, 'url' ],\r
                                                        [ editor.lang.link.toAnchor, 'anchor' ],\r
                                                        [ editor.lang.link.toEmail, 'email' ]\r
                                                ],\r
@@ -292,19 +411,19 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                                type : 'select',\r
                                                                                label : editor.lang.common.protocol,\r
                                                                                'default' : 'http://',\r
-                                                                               style : 'width : 100%;',\r
                                                                                items :\r
                                                                                [\r
-                                                                                       [ 'http://' ],\r
-                                                                                       [ 'https://' ],\r
-                                                                                       [ 'ftp://' ],\r
-                                                                                       [ 'news://' ],\r
-                                                                                       [ '<other>', '' ]\r
+                                                                                       // Force 'ltr' for protocol names in BIDI. (#5433)\r
+                                                                                       [ 'http://\u200E', 'http://' ],\r
+                                                                                       [ 'https://\u200E', 'https://' ],\r
+                                                                                       [ 'ftp://\u200E', 'ftp://' ],\r
+                                                                                       [ 'news://\u200E', 'news://' ],\r
+                                                                                       [ editor.lang.link.other , '' ]\r
                                                                                ],\r
                                                                                setup : function( data )\r
                                                                                {\r
                                                                                        if ( data.url )\r
-                                                                                               this.setValue( data.url.protocol );\r
+                                                                                               this.setValue( data.url.protocol || '' );\r
                                                                                },\r
                                                                                commit : function( data )\r
                                                                                {\r
@@ -318,6 +437,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                                type : 'text',\r
                                                                                id : 'url',\r
                                                                                label : editor.lang.common.url,\r
+                                                                               required: true,\r
                                                                                onLoad : function ()\r
                                                                                {\r
                                                                                        this.allowOnChange = true;\r
@@ -328,7 +448,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                                        var     protocolCmb = this.getDialog().getContentElement( 'info', 'protocol' ),\r
                                                                                                url = this.getValue(),\r
                                                                                                urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/gi,\r
-                                                                                               urlOnChangeTestOther = /^((javascript:)|[#\/\.])/gi;\r
+                                                                                               urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/gi;\r
 \r
                                                                                        var protocol = urlOnChangeProtocol.exec( url );\r
                                                                                        if ( protocol )\r
@@ -367,13 +487,13 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                                                this.setValue( data.url.url );\r
                                                                                        this.allowOnChange = true;\r
 \r
-                                                                                       var linkType = this.getDialog().getContentElement( 'info', 'linkType' );\r
-                                                                                       if ( linkType && linkType.getValue() == 'url' )\r
-                                                                                               this.select();\r
-\r
                                                                                },\r
                                                                                commit : function( data )\r
                                                                                {\r
+                                                                                       // IE will not trigger the onChange event if the mouse has been used\r
+                                                                                       // to carry all the operations #4724\r
+                                                                                       this.onChange();\r
+\r
                                                                                        if ( !data.url )\r
                                                                                                data.url = {};\r
 \r
@@ -406,105 +526,110 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                children :\r
                                                [\r
                                                        {\r
-                                                               type : 'html',\r
+                                                               type : 'fieldset',\r
                                                                id : 'selectAnchorText',\r
-                                                               html : CKEDITOR.tools.htmlEncode( editor.lang.link.selectAnchor ),\r
+                                                               label : editor.lang.link.selectAnchor,\r
                                                                setup : function( data )\r
                                                                {\r
                                                                        if ( data.anchors.length > 0 )\r
                                                                                this.getElement().show();\r
                                                                        else\r
                                                                                this.getElement().hide();\r
-                                                               }\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'html',\r
-                                                               id : 'noAnchors',\r
-                                                               style : 'text-align: center;',\r
-                                                               html : '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.link.noAnchors ) + '</div>',\r
-                                                               setup : function( data )\r
-                                                               {\r
-                                                                       if ( data.anchors.length < 1 )\r
-                                                                               this.getElement().show();\r
-                                                                       else\r
-                                                                               this.getElement().hide();\r
-                                                               }\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
-                                                               id : 'selectAnchor',\r
+                                                               },\r
                                                                children :\r
                                                                [\r
                                                                        {\r
-                                                                               type : 'select',\r
-                                                                               id : 'anchorName',\r
-                                                                               'default' : '',\r
-                                                                               label : editor.lang.link.anchorName,\r
-                                                                               style : 'width: 100%;',\r
-                                                                               items :\r
+                                                                               type : 'hbox',\r
+                                                                               id : 'selectAnchor',\r
+                                                                               children :\r
                                                                                [\r
-                                                                                       [ '' ]\r
-                                                                               ],\r
-                                                                               setup : function( data )\r
-                                                                               {\r
-                                                                                       this.clear();\r
-                                                                                       this.add( '' );\r
-                                                                                       for ( var i = 0 ; i < data.anchors.length ; i++ )\r
                                                                                        {\r
-                                                                                               if ( data.anchors[i].name )\r
-                                                                                                       this.add( data.anchors[i].name );\r
+                                                                                               type : 'select',\r
+                                                                                               id : 'anchorName',\r
+                                                                                               'default' : '',\r
+                                                                                               label : editor.lang.link.anchorName,\r
+                                                                                               style : 'width: 100%;',\r
+                                                                                               items :\r
+                                                                                               [\r
+                                                                                                       [ '' ]\r
+                                                                                               ],\r
+                                                                                               setup : function( data )\r
+                                                                                               {\r
+                                                                                                       this.clear();\r
+                                                                                                       this.add( '' );\r
+                                                                                                       for ( var i = 0 ; i < data.anchors.length ; i++ )\r
+                                                                                                       {\r
+                                                                                                               if ( data.anchors[i].name )\r
+                                                                                                                       this.add( data.anchors[i].name );\r
+                                                                                                       }\r
+\r
+                                                                                                       if ( data.anchor )\r
+                                                                                                               this.setValue( data.anchor.name );\r
+\r
+                                                                                                       var linkType = this.getDialog().getContentElement( 'info', 'linkType' );\r
+                                                                                                       if ( linkType && linkType.getValue() == 'email' )\r
+                                                                                                               this.focus();\r
+                                                                                               },\r
+                                                                                               commit : function( data )\r
+                                                                                               {\r
+                                                                                                       if ( !data.anchor )\r
+                                                                                                               data.anchor = {};\r
+\r
+                                                                                                       data.anchor.name = this.getValue();\r
+                                                                                               }\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type : 'select',\r
+                                                                                               id : 'anchorId',\r
+                                                                                               'default' : '',\r
+                                                                                               label : editor.lang.link.anchorId,\r
+                                                                                               style : 'width: 100%;',\r
+                                                                                               items :\r
+                                                                                               [\r
+                                                                                                       [ '' ]\r
+                                                                                               ],\r
+                                                                                               setup : function( data )\r
+                                                                                               {\r
+                                                                                                       this.clear();\r
+                                                                                                       this.add( '' );\r
+                                                                                                       for ( var i = 0 ; i < data.anchors.length ; i++ )\r
+                                                                                                       {\r
+                                                                                                               if ( data.anchors[i].id )\r
+                                                                                                                       this.add( data.anchors[i].id );\r
+                                                                                                       }\r
+\r
+                                                                                                       if ( data.anchor )\r
+                                                                                                               this.setValue( data.anchor.id );\r
+                                                                                               },\r
+                                                                                               commit : function( data )\r
+                                                                                               {\r
+                                                                                                       if ( !data.anchor )\r
+                                                                                                               data.anchor = {};\r
+\r
+                                                                                                       data.anchor.id = this.getValue();\r
+                                                                                               }\r
                                                                                        }\r
-\r
-                                                                                       if ( data.anchor )\r
-                                                                                               this.setValue( data.anchor.name );\r
-\r
-                                                                                       var linkType = this.getDialog().getContentElement( 'info', 'linkType' );\r
-                                                                                       if ( linkType && linkType.getValue() == 'email' )\r
-                                                                                               this.focus();\r
-                                                                               },\r
-                                                                               commit : function( data )\r
-                                                                               {\r
-                                                                                       if ( !data.anchor )\r
-                                                                                               data.anchor = {};\r
-\r
-                                                                                       data.anchor.name = this.getValue();\r
-                                                                               }\r
-                                                                       },\r
-                                                                       {\r
-                                                                               type : 'select',\r
-                                                                               id : 'anchorId',\r
-                                                                               'default' : '',\r
-                                                                               label : editor.lang.link.anchorId,\r
-                                                                               style : 'width: 100%;',\r
-                                                                               items :\r
-                                                                               [\r
-                                                                                       [ '' ]\r
                                                                                ],\r
                                                                                setup : function( data )\r
                                                                                {\r
-                                                                                       this.clear();\r
-                                                                                       this.add( '' );\r
-                                                                                       for ( var i = 0 ; i < data.anchors.length ; i++ )\r
-                                                                                       {\r
-                                                                                               if ( data.anchors[i].id )\r
-                                                                                                       this.add( data.anchors[i].id );\r
-                                                                                       }\r
-\r
-                                                                                       if ( data.anchor )\r
-                                                                                               this.setValue( data.anchor.id );\r
-                                                                               },\r
-                                                                               commit : function( data )\r
-                                                                               {\r
-                                                                                       if ( !data.anchor )\r
-                                                                                               data.anchor = {};\r
-\r
-                                                                                       data.anchor.id = this.getValue();\r
+                                                                                       if ( data.anchors.length > 0 )\r
+                                                                                               this.getElement().show();\r
+                                                                                       else\r
+                                                                                               this.getElement().hide();\r
                                                                                }\r
                                                                        }\r
-                                                               ],\r
+                                                               ]\r
+                                                       },\r
+                                                       {\r
+                                                               type : 'html',\r
+                                                               id : 'noAnchors',\r
+                                                               style : 'text-align: center;',\r
+                                                               html : '<div role="label" tabIndex="-1">' + CKEDITOR.tools.htmlEncode( editor.lang.link.noAnchors ) + '</div>',\r
+                                                               // Focus the first element defined in above html.\r
+                                                               focus : true,\r
                                                                setup : function( data )\r
                                                                {\r
-                                                                       if ( data.anchors.length > 0 )\r
+                                                                       if ( data.anchors.length < 1 )\r
                                                                                this.getElement().show();\r
                                                                        else\r
                                                                                this.getElement().hide();\r
@@ -527,6 +652,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                type : 'text',\r
                                                                id : 'emailAddress',\r
                                                                label : editor.lang.link.emailAddress,\r
+                                                               required : true,\r
                                                                validate : function()\r
                                                                {\r
                                                                        var dialog = this.getDialog();\r
@@ -614,18 +740,18 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                        {\r
                                                                type : 'select',\r
                                                                id : 'linkTargetType',\r
-                                                               label : editor.lang.link.target,\r
+                                                               label : editor.lang.common.target,\r
                                                                'default' : 'notSet',\r
                                                                style : 'width : 100%;',\r
                                                                'items' :\r
                                                                [\r
-                                                                       [ editor.lang.link.targetNotSet, 'notSet' ],\r
+                                                                       [ editor.lang.common.notSet, 'notSet' ],\r
                                                                        [ editor.lang.link.targetFrame, 'frame' ],\r
                                                                        [ editor.lang.link.targetPopup, 'popup' ],\r
-                                                                       [ editor.lang.link.targetNew, '_blank' ],\r
-                                                                       [ editor.lang.link.targetTop, '_top' ],\r
-                                                                       [ editor.lang.link.targetSelf, '_self' ],\r
-                                                                       [ editor.lang.link.targetParent, '_parent' ]\r
+                                                                       [ editor.lang.common.targetNew, '_blank' ],\r
+                                                                       [ editor.lang.common.targetTop, '_top' ],\r
+                                                                       [ editor.lang.common.targetSelf, '_self' ],\r
+                                                                       [ editor.lang.common.targetParent, '_parent' ]\r
                                                                ],\r
                                                                onChange : targetChanged,\r
                                                                setup : function( data )\r
@@ -656,7 +782,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                        if ( !data.target )\r
                                                                                data.target = {};\r
 \r
-                                                                       data.target.name = this.getValue();\r
+                                                                       data.target.name = this.getValue().replace(/\W/gi, '');\r
                                                                }\r
                                                        }\r
                                                ]\r
@@ -670,145 +796,148 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                children :\r
                                                [\r
                                                        {\r
-                                                               type : 'html',\r
-                                                               html : CKEDITOR.tools.htmlEncode( editor.lang.link.popupFeatures )\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
-                                                               children :\r
-                                                               [\r
-                                                                       {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'resizable',\r
-                                                                               label : editor.lang.link.popupResizable,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
-                                                                       },\r
-                                                                       {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'status',\r
-                                                                               label : editor.lang.link.popupStatusBar,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
-\r
-                                                                       }\r
-                                                               ]\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
+                                                               type : 'fieldset',\r
+                                                               label : editor.lang.link.popupFeatures,\r
                                                                children :\r
                                                                [\r
                                                                        {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'location',\r
-                                                                               label : editor.lang.link.popupLocationBar,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                               type : 'hbox',\r
+                                                                               children :\r
+                                                                               [\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'resizable',\r
+                                                                                               label : editor.lang.link.popupResizable,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'status',\r
+                                                                                               label : editor.lang.link.popupStatusBar,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
+                                                                                       }\r
+                                                                               ]\r
                                                                        },\r
                                                                        {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'toolbar',\r
-                                                                               label : editor.lang.link.popupToolbar,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                               type : 'hbox',\r
+                                                                               children :\r
+                                                                               [\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'location',\r
+                                                                                               label : editor.lang.link.popupLocationBar,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
-                                                                       }\r
-                                                               ]\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
-                                                               children :\r
-                                                               [\r
-                                                                       {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'menubar',\r
-                                                                               label : editor.lang.link.popupMenuBar,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'toolbar',\r
+                                                                                               label : editor.lang.link.popupToolbar,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
+                                                                                       }\r
+                                                                               ]\r
                                                                        },\r
                                                                        {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'fullscreen',\r
-                                                                               label : editor.lang.link.popupFullScreen,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                               type : 'hbox',\r
+                                                                               children :\r
+                                                                               [\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'menubar',\r
+                                                                                               label : editor.lang.link.popupMenuBar,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
-                                                                       }\r
-                                                               ]\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
-                                                               children :\r
-                                                               [\r
-                                                                       {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'scrollbars',\r
-                                                                               label : editor.lang.link.popupScrollBars,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'fullscreen',\r
+                                                                                               label : editor.lang.link.popupFullScreen,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
+                                                                                       }\r
+                                                                               ]\r
                                                                        },\r
                                                                        {\r
-                                                                               type : 'checkbox',\r
-                                                                               id : 'dependent',\r
-                                                                               label : editor.lang.link.popupDependent,\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                               type : 'hbox',\r
+                                                                               children :\r
+                                                                               [\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'scrollbars',\r
+                                                                                               label : editor.lang.link.popupScrollBars,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
-                                                                       }\r
-                                                               ]\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
-                                                               children :\r
-                                                               [\r
-                                                                       {\r
-                                                                               type :  'text',\r
-                                                                               widths : [ '30%', '70%' ],\r
-                                                                               labelLayout : 'horizontal',\r
-                                                                               label : editor.lang.link.popupWidth,\r
-                                                                               id : 'width',\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type : 'checkbox',\r
+                                                                                               id : 'dependent',\r
+                                                                                               label : editor.lang.link.popupDependent,\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
+                                                                                       }\r
+                                                                               ]\r
                                                                        },\r
                                                                        {\r
-                                                                               type :  'text',\r
-                                                                               labelLayout : 'horizontal',\r
-                                                                               widths : [ '55%', '45%' ],\r
-                                                                               label : editor.lang.link.popupLeft,\r
-                                                                               id : 'left',\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
-\r
-                                                                       }\r
-                                                               ]\r
-                                                       },\r
-                                                       {\r
-                                                               type : 'hbox',\r
-                                                               children :\r
-                                                               [\r
-                                                                       {\r
-                                                                               type :  'text',\r
-                                                                               labelLayout : 'horizontal',\r
-                                                                               widths : [ '30%', '70%' ],\r
-                                                                               label : editor.lang.link.popupHeight,\r
-                                                                               id : 'height',\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                               type : 'hbox',\r
+                                                                               children :\r
+                                                                               [\r
+                                                                                       {\r
+                                                                                               type :  'text',\r
+                                                                                               widths : [ '30%', '70%' ],\r
+                                                                                               labelLayout : 'horizontal',\r
+                                                                                               label : editor.lang.link.popupWidth,\r
+                                                                                               id : 'width',\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
+\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type :  'text',\r
+                                                                                               labelLayout : 'horizontal',\r
+                                                                                               widths : [ '55%', '45%' ],\r
+                                                                                               label : editor.lang.link.popupLeft,\r
+                                                                                               id : 'left',\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
+                                                                                       }\r
+                                                                               ]\r
                                                                        },\r
                                                                        {\r
-                                                                               type :  'text',\r
-                                                                               labelLayout : 'horizontal',\r
-                                                                               label : editor.lang.link.popupTop,\r
-                                                                               widths : [ '55%', '45%' ],\r
-                                                                               id : 'top',\r
-                                                                               setup : setupPopupParams,\r
-                                                                               commit : commitPopupParams\r
+                                                                               type : 'hbox',\r
+                                                                               children :\r
+                                                                               [\r
+                                                                                       {\r
+                                                                                               type :  'text',\r
+                                                                                               labelLayout : 'horizontal',\r
+                                                                                               widths : [ '30%', '70%' ],\r
+                                                                                               label : editor.lang.link.popupHeight,\r
+                                                                                               id : 'height',\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
+\r
+                                                                                       },\r
+                                                                                       {\r
+                                                                                               type :  'text',\r
+                                                                                               labelLayout : 'horizontal',\r
+                                                                                               label : editor.lang.link.popupTop,\r
+                                                                                               widths : [ '55%', '45%' ],\r
+                                                                                               id : 'top',\r
+                                                                                               setup : setupPopupParams,\r
+                                                                                               commit : commitPopupParams\r
 \r
+                                                                                       }\r
+                                                                               ]\r
                                                                        }\r
                                                                ]\r
                                                        }\r
@@ -871,7 +1000,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                                                                style : 'width:110px',\r
                                                                                items :\r
                                                                                [\r
-                                                                                       [ editor.lang.link.langDirNotSet, '' ],\r
+                                                                                       [ editor.lang.common.notSet, '' ],\r
                                                                                        [ editor.lang.link.langDirLTR, 'ltr' ],\r
                                                                                        [ editor.lang.link.langDirRTL, 'rtl' ]\r
                                                                                ],\r
@@ -1008,30 +1137,21 @@ CKEDITOR.dialog.add( 'link', function( editor )
 \r
                        var editor = this.getParentEditor(),\r
                                selection = editor.getSelection(),\r
-                               ranges = selection.getRanges(),\r
-                               element = null,\r
-                               me = this;\r
+                               element = null;\r
+\r
                        // Fill in all the relevant fields if there's already one link selected.\r
-                       if ( ranges.length == 1 )\r
+                       if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) )\r
+                               selection.selectElement( element );\r
+                       else if ( ( element = selection.getSelectedElement() ) && element.is( 'img' )\r
+                                       && element.getAttribute( '_cke_real_element_type' )\r
+                                       && element.getAttribute( '_cke_real_element_type' ) == 'anchor' )\r
                        {\r
-\r
-                               var rangeRoot = ranges[0].getCommonAncestor( true );\r
-                               element = rangeRoot.getAscendant( 'a', true );\r
-                               if ( element && element.getAttribute( 'href' ) )\r
-                               {\r
-                                       selection.selectElement( element );\r
-                               }\r
-                               else if ( ( element = rangeRoot.getAscendant( 'img', true ) ) &&\r
-                                                element.getAttribute( '_cke_real_element_type' ) &&\r
-                                                element.getAttribute( '_cke_real_element_type' ) == 'anchor' )\r
-                               {\r
-                                       this.fakeObj = element;\r
-                                       element = editor.restoreRealElement( this.fakeObj );\r
-                                       selection.selectElement( this.fakeObj );\r
-                               }\r
-                               else\r
-                                       element = null;\r
+                               this.fakeObj = element;\r
+                               element = editor.restoreRealElement( this.fakeObj );\r
+                               selection.selectElement( this.fakeObj );\r
                        }\r
+                       else\r
+                               element = null;\r
 \r
                        this.setupContent( parseLink.apply( this, [ editor, element ] ) );\r
                },\r
@@ -1040,7 +1160,8 @@ CKEDITOR.dialog.add( 'link', function( editor )
                        var attributes = { href : 'javascript:void(0)/*' + CKEDITOR.tools.getNextNumber() + '*/' },\r
                                removeAttributes = [],\r
                                data = { href : attributes.href },\r
-                               me = this, editor = this.getParentEditor();\r
+                               me = this,\r
+                               editor = this.getParentEditor();\r
 \r
                        this.commitContent( data );\r
 \r
@@ -1058,21 +1179,52 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                        attributes._cke_saved_href = '#' + ( name || id || '' );\r
                                        break;\r
                                case 'email':\r
-                                       var address = ( data.email && data.email.address ),\r
-                                               subject = ( data.email && encodeURIComponent( data.email.subject || '' ) ),\r
-                                               body = ( data.email && encodeURIComponent( data.email.body || '' ) ),\r
-                                               linkList = [ 'mailto:', address ];\r
-                                       if ( subject || body )\r
+\r
+                                       var linkHref,\r
+                                               email = data.email,\r
+                                               address = email.address;\r
+\r
+                                       switch( emailProtection )\r
                                        {\r
-                                               var argList = [];\r
-                                               linkList.push( '?' );\r
-                                               subject && argList.push( 'subject=' + subject );\r
-                                               body && argList.push( 'body=' + body );\r
-                                               linkList.push( argList.join( '&' ) );\r
+                                               case '' :\r
+                                               case 'encode' :\r
+                                               {\r
+                                                       var subject = encodeURIComponent( email.subject || '' ),\r
+                                                               body = encodeURIComponent( email.body || '' );\r
+\r
+                                                       // Build the e-mail parameters first.\r
+                                                       var argList = [];\r
+                                                       subject && argList.push( 'subject=' + subject );\r
+                                                       body && argList.push( 'body=' + body );\r
+                                                       argList = argList.length ? '?' + argList.join( '&' ) : '';\r
+\r
+                                                       if ( emailProtection == 'encode' )\r
+                                                       {\r
+                                                               linkHref = [ 'javascript:void(location.href=\'mailto:\'+',\r
+                                                                                        protectEmailAddressAsEncodedString( address ) ];\r
+                                                               // parameters are optional.\r
+                                                               argList && linkHref.push( '+\'', escapeSingleQuote( argList ), '\'' );\r
+\r
+                                                               linkHref.push( ')' );\r
+                                                       }\r
+                                                       else\r
+                                                               linkHref = [ 'mailto:', address, argList ];\r
+\r
+                                                       break;\r
+                                               }\r
+                                               default :\r
+                                               {\r
+                                                       // Separating name and domain.\r
+                                                       var nameAndDomain = address.split( '@', 2 );\r
+                                                       email.name = nameAndDomain[ 0 ];\r
+                                                       email.domain = nameAndDomain[ 1 ];\r
+\r
+                                                       linkHref = [ 'javascript:', protectEmailLinkAsFunction( email ) ];\r
+                                               }\r
                                        }\r
-                                       attributes._cke_saved_href = linkList.join( '' );\r
+\r
+                                       attributes._cke_saved_href = linkHref.join( '' );\r
                                        break;\r
-                               default:\r
                        }\r
 \r
                        // Popups and target.\r
@@ -1099,12 +1251,15 @@ CKEDITOR.dialog.add( 'link', function( editor )
                                        addFeature( 'top' );\r
 \r
                                        onclickList.push( featureList.join( ',' ), '\'); return false;' );\r
-                                       attributes[ CKEDITOR.env.ie || CKEDITOR.env.webkit ? '_cke_pa_onclick' : 'onclick' ] = onclickList.join( '' );\r
+                                       attributes[ '_cke_pa_onclick' ] = onclickList.join( '' );\r
                                }\r
                                else\r
                                {\r
                                        if ( data.target.type != 'notSet' && data.target.name )\r
                                                attributes.target = data.target.name;\r
+                                       else\r
+                                               removeAttributes.push( 'target' );\r
+\r
                                        removeAttributes.push( '_cke_pa_onclick', 'onclick' );\r
                                }\r
                        }\r
@@ -1170,7 +1325,9 @@ CKEDITOR.dialog.add( 'link', function( editor )
                        else\r
                        {\r
                                // We're only editing an existing link, so just overwrite the attributes.\r
-                               var element = this._.selectedElement;\r
+                               var element = this._.selectedElement,\r
+                                       href = element.getAttribute( '_cke_saved_href' ),\r
+                                       textView = element.getHtml();\r
 \r
                                // IE BUG: Setting the name attribute to an existing link doesn't work.\r
                                // Must re-create the link from weired syntax to workaround.\r
@@ -1191,7 +1348,9 @@ CKEDITOR.dialog.add( 'link', function( editor )
 \r
                                element.setAttributes( attributes );\r
                                element.removeAttributes( removeAttributes );\r
-\r
+                               // Update text view when user changes protocol #4612.\r
+                               if (href == textView)\r
+                                       element.setHtml( attributes._cke_saved_href );\r
                                // Make the element display as an anchor if a name has been set.\r
                                if ( element.getAttribute( 'name' ) )\r
                                        element.addClass( 'cke_anchor' );\r
@@ -1212,6 +1371,43 @@ CKEDITOR.dialog.add( 'link', function( editor )
                        if ( !editor.config.linkShowTargetTab )\r
                                this.hidePage( 'target' );              //Hide Target tab.\r
 \r
+               },\r
+               // Inital focus on 'url' field if link is of type URL.\r
+               onFocus : function()\r
+               {\r
+                       var linkType = this.getContentElement( 'info', 'linkType' ),\r
+                                       urlField;\r
+                       if ( linkType && linkType.getValue( ) == 'url' )\r
+                       {\r
+                               urlField = this.getContentElement( 'info', 'url' );\r
+                               urlField.select();\r
+                       }\r
                }\r
        };\r
-} );\r
+});\r
+\r
+/**\r
+ * The e-mail address anti-spam protection option. The protection will be\r
+ * applied when creating or modifying e-mail links through the editor interface.<br>\r
+ * Two methods of protection can be choosed:\r
+ * <ol>        <li>The e-mail parts (name, domain and any other query string) are\r
+ *                     assembled into a function call pattern. Such function must be\r
+ *                     provided by the developer in the pages that will use the contents.\r
+ *             <li>Only the e-mail address is obfuscated into a special string that\r
+ *                     has no meaning for humans or spam bots, but which is properly\r
+ *                     rendered and accepted by the browser.</li></ol>\r
+ * Both approaches require JavaScript to be enabled.\r
+ * @name CKEDITOR.config.emailProtection\r
+ * @since 3.1\r
+ * @type String\r
+ * @default '' (empty string = disabled)\r
+ * @example\r
+ * // href="mailto:tester@ckeditor.com?subject=subject&body=body"\r
+ * config.emailProtection = '';\r
+ * @example\r
+ * // href="<a href=\"javascript:void(location.href=\'mailto:\'+String.fromCharCode(116,101,115,116,101,114,64,99,107,101,100,105,116,111,114,46,99,111,109)+\'?subject=subject&body=body\')\">e-mail</a>"\r
+ * config.emailProtection = 'encode';\r
+ * @example\r
+ * // href="javascript:mt('tester','ckeditor.com','subject','body')"\r
+ * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';\r
+ */\r