X-Git-Url: https://jasonwoof.com/gitweb/?p=ckeditor.git;a=blobdiff_plain;f=_source%2Fplugins%2Flink%2Fdialogs%2Flink.js;h=8d4e74b5d1ee029bb49632a0f57cf7086504912b;hp=1e06a6ae554323f31952bceb25c2c1838d8eb630;hb=941b0a9ba4e673e292510d80a5a86806994b8ea6;hpb=7cd80714081a8ffdf4a1a8d2c72f120ed5ef3d6d diff --git a/_source/plugins/link/dialogs/link.js b/_source/plugins/link/dialogs/link.js index 1e06a6a..8d4e74b 100644 --- a/_source/plugins/link/dialogs/link.js +++ b/_source/plugins/link/dialogs/link.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -73,8 +73,10 @@ CKEDITOR.dialog.add( 'link', function( editor ) emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/, emailBodyRegex = /body=([^;?:@&=$,\/]*)/, anchorRegex = /^#(.*)$/, - urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/, - selectableTargets = /^(_(?:self|top|parent|blank))$/; + urlRegex = /^(?!javascript)((?:http|https|ftp|news):\/\/)?(.*)$/, + selectableTargets = /^(_(?:self|top|parent|blank))$/, + encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/, + functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/; var popupRegex = /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/; @@ -83,42 +85,80 @@ CKEDITOR.dialog.add( 'link', function( editor ) var parseLink = function( editor, element ) { var href = element ? ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) : '', - emailMatch = '', - anchorMatch = '', - urlMatch = false, + emailMatch, + anchorMatch, + urlMatch, retval = {}; - if ( href ) - { - emailMatch = href.match( emailRegex ); - anchorMatch = href.match( anchorRegex ); - urlMatch = href.match( urlRegex ); - } - - // Load the link type and URL. - if ( emailMatch ) - { - var subjectMatch = href.match( emailSubjectRegex ), - bodyMatch = href.match( emailBodyRegex ); - retval.type = 'email'; - retval.email = {}; - retval.email.address = emailMatch[1]; - subjectMatch && ( retval.email.subject = decodeURIComponent( subjectMatch[1] ) ); - bodyMatch && ( retval.email.body = decodeURIComponent( bodyMatch[1] ) ); - } - else if ( anchorMatch ) + if ( ( anchorMatch = href.match( anchorRegex ) ) ) { retval.type = 'anchor'; retval.anchor = {}; retval.anchor.name = retval.anchor.id = anchorMatch[1]; } - else if ( href && urlMatch ) // urlRegex matches empty strings, so need to check for href as well. + // urlRegex matches empty strings, so need to check for href as well. + else if ( href && ( urlMatch = href.match( urlRegex ) ) ) { retval.type = 'url'; retval.url = {}; retval.url.protocol = urlMatch[1]; retval.url.url = urlMatch[2]; } + // Protected email link as encoded string. + else if ( !emailProtection || emailProtection == 'encode' ) + { + if( emailProtection == 'encode' ) + { + href = href.replace( encodedEmailLinkRegex, + function ( match, protectedAddress, rest ) + { + return 'mailto:' + + String.fromCharCode.apply( String, protectedAddress.split( ',' ) ) + + ( rest && unescapeSingleQuote( rest ) ); + } ); + } + + emailMatch = href.match( emailRegex ); + + if( emailMatch ) + { + var subjectMatch = href.match( emailSubjectRegex ), + bodyMatch = href.match( emailBodyRegex ); + + retval.type = 'email'; + var email = ( retval.email = {} ); + email.address = emailMatch[ 1 ]; + subjectMatch && ( email.subject = decodeURIComponent( subjectMatch[ 1 ] ) ); + bodyMatch && ( email.body = decodeURIComponent( bodyMatch[ 1 ] ) ); + } + } + // Protected email link as function call. + else if( emailProtection ) + { + href.replace( functionCallProtectedEmailLinkRegex, function( match, funcName, funcArgs ) + { + if( funcName == compiledProtectionFunction.name ) + { + retval.type = 'email'; + var email = retval.email = {}; + + var paramRegex = /[^,\s]+/g, + paramQuoteRegex = /(^')|('$)/g, + paramsMatch = funcArgs.match( paramRegex ), + paramsMatchLength = paramsMatch.length, + paramName, + paramVal; + + for ( var i = 0; i < paramsMatchLength; i++ ) + { + paramVal = decodeURIComponent( unescapeSingleQuote( paramsMatch[ i ].replace( paramQuoteRegex, '' ) ) ); + paramName = compiledProtectionFunction.params[ i ].toLowerCase(); + email[ paramName ] = paramVal; + } + email.address = [ email.name, email.domain ].join( '@' ); + } + } ); + } else retval.type = 'url'; @@ -245,6 +285,72 @@ CKEDITOR.dialog.add( 'link', function( editor ) return commitParams.call( this, 'adv', data ); }; + function unescapeSingleQuote( str ) + { + return str.replace( /\\'/g, '\'' ); + } + + function escapeSingleQuote( str ) + { + return str.replace( /'/g, '\\$&' ); + } + + var emailProtection = editor.config.emailProtection || ''; + + // Compile the protection function pattern. + if( emailProtection && emailProtection != 'encode' ) + { + var compiledProtectionFunction = {}; + + emailProtection.replace( /^([^(]+)\(([^)]+)\)$/, function( match, funcName, params ) + { + compiledProtectionFunction.name = funcName; + compiledProtectionFunction.params = []; + params.replace( /[^,\s]+/g, function( param ) + { + compiledProtectionFunction.params.push( param ); + } ); + } ); + } + + function protectEmailLinkAsFunction( email ) + { + var retval, + name = compiledProtectionFunction.name, + params = compiledProtectionFunction.params, + paramName, + paramValue; + + retval = [ name, '(' ]; + for ( var i = 0; i < params.length; i++ ) + { + paramName = params[ i ].toLowerCase(); + paramValue = email[ paramName ]; + + i > 0 && retval.push( ',' ); + retval.push( '\'', + paramValue ? + escapeSingleQuote( encodeURIComponent( email[ paramName ] ) ) + : '', + '\''); + } + retval.push( ')' ); + return retval.join( '' ); + } + + function protectEmailAddressAsEncodedString( address ) + { + var charCode, + length = address.length, + encodedChars = []; + for ( var i = 0; i < length; i++ ) + { + charCode = address.charCodeAt( i ); + encodedChars.push( charCode ); + } + return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')'; + } + return { title : editor.lang.link.title, minWidth : 350, @@ -1041,7 +1147,8 @@ CKEDITOR.dialog.add( 'link', function( editor ) var attributes = { href : 'javascript:void(0)/*' + CKEDITOR.tools.getNextNumber() + '*/' }, removeAttributes = [], data = { href : attributes.href }, - me = this, editor = this.getParentEditor(); + me = this, + editor = this.getParentEditor(); this.commitContent( data ); @@ -1059,21 +1166,52 @@ CKEDITOR.dialog.add( 'link', function( editor ) attributes._cke_saved_href = '#' + ( name || id || '' ); break; case 'email': - var address = ( data.email && data.email.address ), - subject = ( data.email && encodeURIComponent( data.email.subject || '' ) ), - body = ( data.email && encodeURIComponent( data.email.body || '' ) ), - linkList = [ 'mailto:', address ]; - if ( subject || body ) + + var linkHref, + email = data.email, + address = email.address; + + switch( emailProtection ) { - var argList = []; - linkList.push( '?' ); - subject && argList.push( 'subject=' + subject ); - body && argList.push( 'body=' + body ); - linkList.push( argList.join( '&' ) ); + case '' : + case 'encode' : + { + var subject = encodeURIComponent( email.subject || '' ), + body = encodeURIComponent( email.body || '' ); + + // Build the e-mail parameters first. + var argList = []; + subject && argList.push( 'subject=' + subject ); + body && argList.push( 'body=' + body ); + argList = argList.length ? '?' + argList.join( '&' ) : ''; + + if ( emailProtection == 'encode' ) + { + linkHref = [ 'javascript:void(location.href=\'mailto:\'+', + protectEmailAddressAsEncodedString( address ) ]; + // parameters are optional. + argList && linkHref.push( '+\'', escapeSingleQuote( argList ), '\'' ); + + linkHref.push( ')' ); + } + else + linkHref = [ 'mailto:', address, argList ]; + + break; + } + default : + { + // Separating name and domain. + var nameAndDomain = address.split( '@', 2 ); + email.name = nameAndDomain[ 0 ]; + email.domain = nameAndDomain[ 1 ]; + + linkHref = [ 'javascript:', protectEmailLinkAsFunction( email ) ]; + } } - attributes._cke_saved_href = linkList.join( '' ); + + attributes._cke_saved_href = linkHref.join( '' ); break; - default: } // Popups and target. @@ -1100,7 +1238,7 @@ CKEDITOR.dialog.add( 'link', function( editor ) addFeature( 'top' ); onclickList.push( featureList.join( ',' ), '\'); return false;' ); - attributes[ CKEDITOR.env.ie || CKEDITOR.env.webkit ? '_cke_pa_onclick' : 'onclick' ] = onclickList.join( '' ); + attributes[ '_cke_pa_onclick' ] = onclickList.join( '' ); } else { @@ -1218,4 +1356,24 @@ CKEDITOR.dialog.add( 'link', function( editor ) } }; -} ); +}); + +/** + * The e-mail address anti-spam protection option. + * @name CKEDITOR.config.emailProtection + * @type {String} + * Two forms of protection could be choosed from : + * 1. The whole address parts ( name, domain with any other query string ) are assembled into a + * function call pattern which invoke you own provided function, with the specified arguments. + * 2. Only the e-mail address is obfuscated into unicode code point sequences, replacement are + * done by a String.fromCharCode() call. + * Note: Both approaches require JavaScript to be enabled. + * @default '' + * @example + * config.emailProtection = ''; + * // href="mailto:tester@ckeditor.com?subject=subject&body=body" + * config.emailProtection = 'encode'; + * // href="e-mail" + * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)'; + * // href="javascript:mt('tester','ckeditor.com','subject','body')" + */