JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.1
[ckeditor.git] / _source / plugins / link / dialogs / link.js
index 1e06a6a..8d4e74b 100644 (file)
@@ -1,5 +1,5 @@
 /*\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
@@ -73,8 +73,10 @@ CKEDITOR.dialog.add( 'link', function( editor )
                emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,\r
                emailBodyRegex = /body=([^;?:@&=$,\/]*)/,\r
                anchorRegex = /^#(.*)$/,\r
-               urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,\r
-               selectableTargets = /^(_(?:self|top|parent|blank))$/;\r
+               urlRegex = /^(?!javascript)((?:http|https|ftp|news):\/\/)?(.*)$/,\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
@@ -83,42 +85,80 @@ CKEDITOR.dialog.add( 'link', function( editor )
        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
+                       emailMatch,\r
+                       anchorMatch,\r
+                       urlMatch,\r
                        retval = {};\r
 \r
-               if ( href )\r
-               {\r
-                       emailMatch = href.match( emailRegex );\r
-                       anchorMatch = href.match( anchorRegex );\r
-                       urlMatch = href.match( urlRegex );\r
-               }\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
+               if ( ( anchorMatch = href.match( anchorRegex ) ) )\r
                {\r
                        retval.type = 'anchor';\r
                        retval.anchor = {};\r
                        retval.anchor.name = retval.anchor.id = anchorMatch[1];\r
                }\r
-               else if ( href && urlMatch )            // urlRegex matches empty strings, so need to check for href as well.\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
+               // Protected email link as encoded string.\r
+               else if ( !emailProtection || emailProtection == 'encode' )\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
+\r
+                       emailMatch = href.match( emailRegex );\r
+\r
+                       if( emailMatch )\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
+               }\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
+                                       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
                else\r
                        retval.type = 'url';\r
 \r
@@ -245,6 +285,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
@@ -1041,7 +1147,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
@@ -1059,21 +1166,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
@@ -1100,7 +1238,7 @@ 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
@@ -1218,4 +1356,24 @@ CKEDITOR.dialog.add( 'link', function( editor )
 \r
                }\r
        };\r
-} );\r
+});\r
+\r
+/**\r
+ * The e-mail address anti-spam protection option.\r
+ * @name CKEDITOR.config.emailProtection\r
+ * @type {String}\r
+ * Two forms of protection could be choosed from :\r
+ * 1. The whole address parts ( name, domain with any other query string ) are assembled into a\r
+ *   function call pattern which invoke you own provided function, with the specified arguments.\r
+ * 2. Only the e-mail address is obfuscated into unicode code point sequences, replacement are\r
+ *   done by a String.fromCharCode() call.\r
+ * Note: Both approaches require JavaScript to be enabled.\r
+ * @default ''\r
+ * @example\r
+ *  config.emailProtection = '';\r
+ *  // href="mailto:tester@ckeditor.com?subject=subject&body=body"\r
+ *  config.emailProtection = 'encode';\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 = 'mt(NAME,DOMAIN,SUBJECT,BODY)';\r
+ *  // href="javascript:mt('tester','ckeditor.com','subject','body')"\r
+ */\r