/*\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
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
};\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
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
+ 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
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
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
},\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
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
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
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
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
\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
\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