2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
6 CKEDITOR
.dialog
.add( 'link', function( editor
)
8 var plugin
= CKEDITOR
.plugins
.link
;
9 // Handles the event when the "Target" selection box is changed.
10 var targetChanged = function()
12 var dialog
= this.getDialog(),
13 popupFeatures
= dialog
.getContentElement( 'target', 'popupFeatures' ),
14 targetName
= dialog
.getContentElement( 'target', 'linkTargetName' ),
15 value
= this.getValue();
17 if ( !popupFeatures
|| !targetName
)
20 popupFeatures
= popupFeatures
.getElement();
22 targetName
.setValue( '' );
27 targetName
.setLabel( editor
.lang
.link
.targetFrameName
);
28 targetName
.getElement().show();
32 targetName
.setLabel( editor
.lang
.link
.targetPopupName
);
33 targetName
.getElement().show();
36 targetName
.setValue( value
);
37 targetName
.getElement().hide();
43 // Handles the event when the "Type" selection box is changed.
44 var linkTypeChanged = function()
46 var dialog
= this.getDialog(),
47 partIds
= [ 'urlOptions', 'anchorOptions', 'emailOptions' ],
48 typeValue
= this.getValue(),
49 uploadTab
= dialog
.definition
.getContents( 'upload' ),
50 uploadInitiallyHidden
= uploadTab
&& uploadTab
.hidden
;
52 if ( typeValue
== 'url' )
54 if ( editor
.config
.linkShowTargetTab
)
55 dialog
.showPage( 'target' );
56 if ( !uploadInitiallyHidden
)
57 dialog
.showPage( 'upload' );
61 dialog
.hidePage( 'target' );
62 if ( !uploadInitiallyHidden
)
63 dialog
.hidePage( 'upload' );
66 for ( var i
= 0 ; i
< partIds
.length
; i
++ )
68 var element
= dialog
.getContentElement( 'info', partIds
[i
] );
72 element
= element
.getElement().getParent().getParent();
73 if ( partIds
[i
] == typeValue
+ 'Options' )
80 // Loads the parameters in a selected link to the link dialog fields.
81 var javascriptProtocolRegex
= /^javascript:/,
82 emailRegex
= /^mailto:([^?]+)(?:\?(.+))?$/,
83 emailSubjectRegex
= /subject=([^;?:@&=$,\/]*)/,
84 emailBodyRegex
= /body=([^;?:@&=$,\/]*)/,
85 anchorRegex
= /^#(.*)$/,
86 urlRegex
= /^((?:http|https|ftp|news):\/\/)?(.*)$/,
87 selectableTargets
= /^(_(?:self|top|parent|blank))$/,
88 encodedEmailLinkRegex
= /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/,
89 functionCallProtectedEmailLinkRegex
= /^javascript:([^(]+)\(([^)]+)\)$/;
92 /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/;
93 var popupFeaturesRegex
= /(?:^|,)([^=]+)=(\d+|yes|no)/gi;
95 var parseLink = function( editor
, element
)
97 var href
= ( element
&& ( element
.getAttribute( '_cke_saved_href' ) || element
.getAttribute( 'href' ) ) ) || '',
104 if ( ( javascriptMatch
= href
.match( javascriptProtocolRegex
) ) )
106 if ( emailProtection
== 'encode' )
108 href
= href
.replace( encodedEmailLinkRegex
,
109 function ( match
, protectedAddress
, rest
)
112 String
.fromCharCode
.apply( String
, protectedAddress
.split( ',' ) ) +
113 ( rest
&& unescapeSingleQuote( rest
) );
116 // Protected email link as function call.
117 else if ( emailProtection
)
119 href
.replace( functionCallProtectedEmailLinkRegex
, function( match
, funcName
, funcArgs
)
121 if ( funcName
== compiledProtectionFunction
.name
)
123 retval
.type
= 'email';
124 var email
= retval
.email
= {};
126 var paramRegex
= /[^,\s]+/g,
127 paramQuoteRegex
= /(^')|('$)/g,
128 paramsMatch
= funcArgs
.match( paramRegex
),
129 paramsMatchLength
= paramsMatch
.length
,
133 for ( var i
= 0; i
< paramsMatchLength
; i
++ )
135 paramVal
= decodeURIComponent( unescapeSingleQuote( paramsMatch
[ i
].replace( paramQuoteRegex
, '' ) ) );
136 paramName
= compiledProtectionFunction
.params
[ i
].toLowerCase();
137 email
[ paramName
] = paramVal
;
139 email
.address
= [ email
.name
, email
.domain
].join( '@' );
147 if ( ( anchorMatch
= href
.match( anchorRegex
) ) )
149 retval
.type
= 'anchor';
151 retval
.anchor
.name
= retval
.anchor
.id
= anchorMatch
[1];
153 // Protected email link as encoded string.
154 else if ( ( emailMatch
= href
.match( emailRegex
) ) )
156 var subjectMatch
= href
.match( emailSubjectRegex
),
157 bodyMatch
= href
.match( emailBodyRegex
);
159 retval
.type
= 'email';
160 var email
= ( retval
.email
= {} );
161 email
.address
= emailMatch
[ 1 ];
162 subjectMatch
&& ( email
.subject
= decodeURIComponent( subjectMatch
[ 1 ] ) );
163 bodyMatch
&& ( email
.body
= decodeURIComponent( bodyMatch
[ 1 ] ) );
165 // urlRegex matches empty strings, so need to check for href as well.
166 else if ( href
&& ( urlMatch
= href
.match( urlRegex
) ) )
170 retval
.url
.protocol
= urlMatch
[1];
171 retval
.url
.url
= urlMatch
[2];
177 // Load target and popup settings.
180 var target
= element
.getAttribute( 'target' );
184 // IE BUG: target attribute is an empty string instead of null in IE if it's not set.
187 var onclick
= element
.getAttribute( '_cke_pa_onclick' ) || element
.getAttribute( 'onclick' ),
188 onclickMatch
= onclick
&& onclick
.match( popupRegex
);
191 retval
.target
.type
= 'popup';
192 retval
.target
.name
= onclickMatch
[1];
195 while ( ( featureMatch
= popupFeaturesRegex
.exec( onclickMatch
[2] ) ) )
197 if ( featureMatch
[2] == 'yes' || featureMatch
[2] == '1' )
198 retval
.target
[ featureMatch
[1] ] = true;
199 else if ( isFinite( featureMatch
[2] ) )
200 retval
.target
[ featureMatch
[1] ] = featureMatch
[2];
206 var targetMatch
= target
.match( selectableTargets
);
208 retval
.target
.type
= retval
.target
.name
= target
;
211 retval
.target
.type
= 'frame';
212 retval
.target
.name
= target
;
217 var advAttr = function( inputName
, attrName
)
219 var value
= element
.getAttribute( attrName
);
220 if ( value
!== null )
221 retval
.adv
[ inputName
] = value
|| '';
223 advAttr( 'advId', 'id' );
224 advAttr( 'advLangDir', 'dir' );
225 advAttr( 'advAccessKey', 'accessKey' );
226 advAttr( 'advName', 'name' );
227 advAttr( 'advLangCode', 'lang' );
228 advAttr( 'advTabIndex', 'tabindex' );
229 advAttr( 'advTitle', 'title' );
230 advAttr( 'advContentType', 'type' );
231 advAttr( 'advCSSClasses', 'class' );
232 advAttr( 'advCharset', 'charset' );
233 advAttr( 'advStyles', 'style' );
236 // Find out whether we have any anchors in the editor.
237 // Get all IMG elements in CK document.
238 var elements
= editor
.document
.getElementsByTag( 'img' ),
239 realAnchors
= new CKEDITOR
.dom
.nodeList( editor
.document
.$.anchors
),
240 anchors
= retval
.anchors
= [];
242 for ( var i
= 0; i
< elements
.count() ; i
++ )
244 var item
= elements
.getItem( i
);
245 if ( item
.getAttribute( '_cke_realelement' ) && item
.getAttribute( '_cke_real_element_type' ) == 'anchor' )
247 anchors
.push( editor
.restoreRealElement( item
) );
251 for ( i
= 0 ; i
< realAnchors
.count() ; i
++ )
252 anchors
.push( realAnchors
.getItem( i
) );
254 for ( i
= 0 ; i
< anchors
.length
; i
++ )
257 anchors
[ i
] = { name
: item
.getAttribute( 'name' ), id
: item
.getAttribute( 'id' ) };
260 // Record down the selected element in the dialog.
261 this._
.selectedElement
= element
;
266 var setupParams = function( page
, data
)
269 this.setValue( data
[page
][this.id
] || '' );
272 var setupPopupParams = function( data
)
274 return setupParams
.call( this, 'target', data
);
277 var setupAdvParams = function( data
)
279 return setupParams
.call( this, 'adv', data
);
282 var commitParams = function( page
, data
)
287 data
[page
][this.id
] = this.getValue() || '';
290 var commitPopupParams = function( data
)
292 return commitParams
.call( this, 'target', data
);
295 var commitAdvParams = function( data
)
297 return commitParams
.call( this, 'adv', data
);
300 function unescapeSingleQuote( str
)
302 return str
.replace( /\\'/g, '\'' );
305 function escapeSingleQuote( str
)
307 return str
.replace( /'/g, '\\$&' );
310 var emailProtection = editor.config.emailProtection || '';
312 // Compile the protection function pattern.
313 if ( emailProtection && emailProtection != 'encode
' )
315 var compiledProtectionFunction = {};
317 emailProtection.replace( /^([^(]+)\(([^)]+)\)$/, function( match, funcName, params )
319 compiledProtectionFunction.name = funcName;
320 compiledProtectionFunction.params = [];
321 params.replace( /[^,\s]+/g, function( param )
323 compiledProtectionFunction.params.push( param );
328 function protectEmailLinkAsFunction( email )
331 name = compiledProtectionFunction.name,
332 params = compiledProtectionFunction.params,
336 retval = [ name, '(' ];
337 for ( var i = 0; i < params.length; i++ )
339 paramName = params[ i ].toLowerCase();
340 paramValue = email[ paramName ];
342 i > 0 && retval.push( ',' );
345 escapeSingleQuote( encodeURIComponent( email[ paramName ] ) )
350 return retval.join( '' );
353 function protectEmailAddressAsEncodedString( address )
356 length = address.length,
358 for ( var i = 0; i < length; i++ )
360 charCode = address.charCodeAt( i );
361 encodedChars.push( charCode );
363 return 'String
.fromCharCode(' + encodedChars.join( ',' ) + ')';
367 title : editor.lang.link.title,
373 label : editor.lang.link.info,
374 title : editor.lang.link.info,
380 label : editor.lang.link.type,
384 [ editor.lang.link.toUrl, 'url
' ],
385 [ editor.lang.link.toAnchor, 'anchor
' ],
386 [ editor.lang.link.toEmail, 'email
' ]
388 onChange : linkTypeChanged,
389 setup : function( data )
392 this.setValue( data.type );
394 commit : function( data )
396 data.type = this.getValue();
406 widths : [ '25%', '75%' ],
412 label : editor.lang.common.protocol,
413 'default' : 'http
://',
414 style
: 'width : 100%;',
421 [ editor
.lang
.link
.other
, '' ]
423 setup : function( data
)
426 this.setValue( data
.url
.protocol
|| '' );
428 commit : function( data
)
433 data
.url
.protocol
= this.getValue();
439 label
: editor
.lang
.common
.url
,
443 this.allowOnChange
= true;
447 this.allowOnChange
= false;
448 var protocolCmb
= this.getDialog().getContentElement( 'info', 'protocol' ),
449 url
= this.getValue(),
450 urlOnChangeProtocol
= /^(http|https|ftp|news):\/\/(?=.)/gi,
451 urlOnChangeTestOther
= /^((javascript:)|[#\/\.\?])/gi;
453 var protocol
= urlOnChangeProtocol
.exec( url
);
456 this.setValue( url
.substr( protocol
[ 0 ].length
) );
457 protocolCmb
.setValue( protocol
[ 0 ].toLowerCase() );
459 else if ( urlOnChangeTestOther
.test( url
) )
460 protocolCmb
.setValue( '' );
462 this.allowOnChange
= true;
464 onChange : function()
466 if ( this.allowOnChange
) // Dont't call on dialog load.
469 validate : function()
471 var dialog
= this.getDialog();
473 if ( dialog
.getContentElement( 'info', 'linkType' ) &&
474 dialog
.getValueOf( 'info', 'linkType' ) != 'url' )
477 if ( this.getDialog().fakeObj
) // Edit Anchor.
480 var func
= CKEDITOR
.dialog
.validate
.notEmpty( editor
.lang
.link
.noUrl
);
481 return func
.apply( this );
483 setup : function( data
)
485 this.allowOnChange
= false;
487 this.setValue( data
.url
.url
);
488 this.allowOnChange
= true;
491 commit : function( data
)
493 // IE will not trigger the onChange event if the mouse has been used
494 // to carry all the operations #4724
500 data
.url
.url
= this.getValue();
501 this.allowOnChange
= false;
505 setup : function( data
)
507 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
508 this.getElement().show();
515 filebrowser
: 'info:url',
516 label
: editor
.lang
.common
.browseServer
522 id
: 'anchorOptions',
530 id
: 'selectAnchorText',
531 label
: editor
.lang
.link
.selectAnchor
,
532 setup : function( data
)
534 if ( data
.anchors
.length
> 0 )
535 this.getElement().show();
537 this.getElement().hide();
550 label
: editor
.lang
.link
.anchorName
,
551 style
: 'width: 100%;',
556 setup : function( data
)
560 for ( var i
= 0 ; i
< data
.anchors
.length
; i
++ )
562 if ( data
.anchors
[i
].name
)
563 this.add( data
.anchors
[i
].name
);
567 this.setValue( data
.anchor
.name
);
569 var linkType
= this.getDialog().getContentElement( 'info', 'linkType' );
570 if ( linkType
&& linkType
.getValue() == 'email' )
573 commit : function( data
)
578 data
.anchor
.name
= this.getValue();
585 label
: editor
.lang
.link
.anchorId
,
586 style
: 'width: 100%;',
591 setup : function( data
)
595 for ( var i
= 0 ; i
< data
.anchors
.length
; i
++ )
597 if ( data
.anchors
[i
].id
)
598 this.add( data
.anchors
[i
].id
);
602 this.setValue( data
.anchor
.id
);
604 commit : function( data
)
609 data
.anchor
.id
= this.getValue();
613 setup : function( data
)
615 if ( data
.anchors
.length
> 0 )
616 this.getElement().show();
618 this.getElement().hide();
626 style
: 'text-align: center;',
627 html
: '<div role="label" tabIndex="-1">' + CKEDITOR
.tools
.htmlEncode( editor
.lang
.link
.noAnchors
) + '</div>',
628 // Focus the first element defined in above html.
630 setup : function( data
)
632 if ( data
.anchors
.length
< 1 )
633 this.getElement().show();
635 this.getElement().hide();
639 setup : function( data
)
641 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
642 this.getElement().hide();
654 label
: editor
.lang
.link
.emailAddress
,
656 validate : function()
658 var dialog
= this.getDialog();
660 if ( !dialog
.getContentElement( 'info', 'linkType' ) ||
661 dialog
.getValueOf( 'info', 'linkType' ) != 'email' )
664 var func
= CKEDITOR
.dialog
.validate
.notEmpty( editor
.lang
.link
.noEmail
);
665 return func
.apply( this );
667 setup : function( data
)
670 this.setValue( data
.email
.address
);
672 var linkType
= this.getDialog().getContentElement( 'info', 'linkType' );
673 if ( linkType
&& linkType
.getValue() == 'email' )
676 commit : function( data
)
681 data
.email
.address
= this.getValue();
687 label
: editor
.lang
.link
.emailSubject
,
688 setup : function( data
)
691 this.setValue( data
.email
.subject
);
693 commit : function( data
)
698 data
.email
.subject
= this.getValue();
704 label
: editor
.lang
.link
.emailBody
,
707 setup : function( data
)
710 this.setValue( data
.email
.body
);
712 commit : function( data
)
717 data
.email
.body
= this.getValue();
721 setup : function( data
)
723 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
724 this.getElement().hide();
731 label
: editor
.lang
.link
.target
,
732 title
: editor
.lang
.link
.target
,
737 widths
: [ '50%', '50%' ],
742 id
: 'linkTargetType',
743 label
: editor
.lang
.common
.target
,
744 'default' : 'notSet',
745 style
: 'width : 100%;',
748 [ editor
.lang
.common
.notSet
, 'notSet' ],
749 [ editor
.lang
.link
.targetFrame
, 'frame' ],
750 [ editor
.lang
.link
.targetPopup
, 'popup' ],
751 [ editor
.lang
.common
.targetNew
, '_blank' ],
752 [ editor
.lang
.common
.targetTop
, '_top' ],
753 [ editor
.lang
.common
.targetSelf
, '_self' ],
754 [ editor
.lang
.common
.targetParent
, '_parent' ]
756 onChange
: targetChanged
,
757 setup : function( data
)
760 this.setValue( data
.target
.type
);
762 commit : function( data
)
767 data
.target
.type
= this.getValue();
772 id
: 'linkTargetName',
773 label
: editor
.lang
.link
.targetFrameName
,
775 setup : function( data
)
778 this.setValue( data
.target
.name
);
780 commit : function( data
)
785 data
.target
.name
= this.getValue().replace(/\W/gi, '');
795 id
: 'popupFeatures',
800 label
: editor
.lang
.link
.popupFeatures
,
810 label
: editor
.lang
.link
.popupResizable
,
811 setup
: setupPopupParams
,
812 commit
: commitPopupParams
817 label
: editor
.lang
.link
.popupStatusBar
,
818 setup
: setupPopupParams
,
819 commit
: commitPopupParams
831 label
: editor
.lang
.link
.popupLocationBar
,
832 setup
: setupPopupParams
,
833 commit
: commitPopupParams
839 label
: editor
.lang
.link
.popupToolbar
,
840 setup
: setupPopupParams
,
841 commit
: commitPopupParams
853 label
: editor
.lang
.link
.popupMenuBar
,
854 setup
: setupPopupParams
,
855 commit
: commitPopupParams
861 label
: editor
.lang
.link
.popupFullScreen
,
862 setup
: setupPopupParams
,
863 commit
: commitPopupParams
875 label
: editor
.lang
.link
.popupScrollBars
,
876 setup
: setupPopupParams
,
877 commit
: commitPopupParams
883 label
: editor
.lang
.link
.popupDependent
,
884 setup
: setupPopupParams
,
885 commit
: commitPopupParams
896 widths
: [ '30%', '70%' ],
897 labelLayout
: 'horizontal',
898 label
: editor
.lang
.link
.popupWidth
,
900 setup
: setupPopupParams
,
901 commit
: commitPopupParams
906 labelLayout
: 'horizontal',
907 widths
: [ '55%', '45%' ],
908 label
: editor
.lang
.link
.popupLeft
,
910 setup
: setupPopupParams
,
911 commit
: commitPopupParams
922 labelLayout
: 'horizontal',
923 widths
: [ '30%', '70%' ],
924 label
: editor
.lang
.link
.popupHeight
,
926 setup
: setupPopupParams
,
927 commit
: commitPopupParams
932 labelLayout
: 'horizontal',
933 label
: editor
.lang
.link
.popupTop
,
934 widths
: [ '55%', '45%' ],
936 setup
: setupPopupParams
,
937 commit
: commitPopupParams
950 label
: editor
.lang
.link
.upload
,
951 title
: editor
.lang
.link
.upload
,
953 filebrowser
: 'uploadButton',
959 label
: editor
.lang
.common
.upload
,
960 style
: 'height:40px',
966 label
: editor
.lang
.common
.uploadSubmit
,
967 filebrowser
: 'info:url',
968 'for' : [ 'upload', 'upload' ]
974 label
: editor
.lang
.link
.advanced
,
975 title
: editor
.lang
.link
.advanced
,
985 widths
: [ '45%', '35%', '20%' ],
991 label
: editor
.lang
.link
.id
,
992 setup
: setupAdvParams
,
993 commit
: commitAdvParams
998 label
: editor
.lang
.link
.langDir
,
1000 style
: 'width:110px',
1003 [ editor
.lang
.common
.notSet
, '' ],
1004 [ editor
.lang
.link
.langDirLTR
, 'ltr' ],
1005 [ editor
.lang
.link
.langDirRTL
, 'rtl' ]
1007 setup
: setupAdvParams
,
1008 commit
: commitAdvParams
1012 id
: 'advAccessKey',
1014 label
: editor
.lang
.link
.acccessKey
,
1016 setup
: setupAdvParams
,
1017 commit
: commitAdvParams
1024 widths
: [ '45%', '35%', '20%' ],
1029 label
: editor
.lang
.link
.name
,
1031 setup
: setupAdvParams
,
1032 commit
: commitAdvParams
1037 label
: editor
.lang
.link
.langCode
,
1041 setup
: setupAdvParams
,
1042 commit
: commitAdvParams
1047 label
: editor
.lang
.link
.tabIndex
,
1051 setup
: setupAdvParams
,
1052 commit
: commitAdvParams
1066 widths
: [ '45%', '55%' ],
1071 label
: editor
.lang
.link
.advisoryTitle
,
1074 setup
: setupAdvParams
,
1075 commit
: commitAdvParams
1080 label
: editor
.lang
.link
.advisoryContentType
,
1082 id
: 'advContentType',
1083 setup
: setupAdvParams
,
1084 commit
: commitAdvParams
1091 widths
: [ '45%', '55%' ],
1096 label
: editor
.lang
.link
.cssClasses
,
1098 id
: 'advCSSClasses',
1099 setup
: setupAdvParams
,
1100 commit
: commitAdvParams
1105 label
: editor
.lang
.link
.charset
,
1108 setup
: setupAdvParams
,
1109 commit
: commitAdvParams
1120 label
: editor
.lang
.link
.styles
,
1123 setup
: setupAdvParams
,
1124 commit
: commitAdvParams
1136 this.fakeObj
= false;
1138 var editor
= this.getParentEditor(),
1139 selection
= editor
.getSelection(),
1142 // Fill in all the relevant fields if there's already one link selected.
1143 if ( ( element
= plugin
.getSelectedLink( editor
) ) && element
.hasAttribute( 'href' ) )
1144 selection
.selectElement( element
);
1145 else if ( ( element
= selection
.getSelectedElement() ) && element
.is( 'img' )
1146 && element
.getAttribute( '_cke_real_element_type' )
1147 && element
.getAttribute( '_cke_real_element_type' ) == 'anchor' )
1149 this.fakeObj
= element
;
1150 element
= editor
.restoreRealElement( this.fakeObj
);
1151 selection
.selectElement( this.fakeObj
);
1156 this.setupContent( parseLink
.apply( this, [ editor
, element
] ) );
1160 var attributes
= { href
: 'javascript:void(0)/*' + CKEDITOR
.tools
.getNextNumber() + '*/' },
1161 removeAttributes
= [],
1162 data
= { href
: attributes
.href
},
1164 editor
= this.getParentEditor();
1166 this.commitContent( data
);
1169 switch ( data
.type
|| 'url' )
1172 var protocol
= ( data
.url
&& data
.url
.protocol
!= undefined ) ? data
.url
.protocol
: 'http://',
1173 url
= ( data
.url
&& data
.url
.url
) || '';
1174 attributes
._cke_saved_href
= ( url
.indexOf( '/' ) === 0 ) ? url
: protocol
+ url
;
1177 var name
= ( data
.anchor
&& data
.anchor
.name
),
1178 id
= ( data
.anchor
&& data
.anchor
.id
);
1179 attributes
._cke_saved_href
= '#' + ( name
|| id
|| '' );
1185 address
= email
.address
;
1187 switch( emailProtection
)
1192 var subject
= encodeURIComponent( email
.subject
|| '' ),
1193 body
= encodeURIComponent( email
.body
|| '' );
1195 // Build the e-mail parameters first.
1197 subject
&& argList
.push( 'subject=' + subject
);
1198 body
&& argList
.push( 'body=' + body
);
1199 argList
= argList
.length
? '?' + argList
.join( '&' ) : '';
1201 if ( emailProtection
== 'encode' )
1203 linkHref
= [ 'javascript:void(location.href=\'mailto:\'+',
1204 protectEmailAddressAsEncodedString( address
) ];
1205 // parameters are optional.
1206 argList
&& linkHref
.push( '+\'', escapeSingleQuote( argList
), '\'' );
1208 linkHref
.push( ')' );
1211 linkHref
= [ 'mailto:', address
, argList
];
1217 // Separating name and domain.
1218 var nameAndDomain
= address
.split( '@', 2 );
1219 email
.name
= nameAndDomain
[ 0 ];
1220 email
.domain
= nameAndDomain
[ 1 ];
1222 linkHref
= [ 'javascript:', protectEmailLinkAsFunction( email
) ];
1226 attributes
._cke_saved_href
= linkHref
.join( '' );
1230 // Popups and target.
1233 if ( data
.target
.type
== 'popup' )
1235 var onclickList
= [ 'window.open(this.href, \'',
1236 data
.target
.name
|| '', '\', \'' ];
1237 var featureList
= [ 'resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen',
1238 'scrollbars', 'dependent' ];
1239 var featureLength
= featureList
.length
;
1240 var addFeature = function( featureName
)
1242 if ( data
.target
[ featureName
] )
1243 featureList
.push( featureName
+ '=' + data
.target
[ featureName
] );
1246 for ( var i
= 0 ; i
< featureLength
; i
++ )
1247 featureList
[i
] = featureList
[i
] + ( data
.target
[ featureList
[i
] ] ? '=yes' : '=no' ) ;
1248 addFeature( 'width' );
1249 addFeature( 'left' );
1250 addFeature( 'height' );
1251 addFeature( 'top' );
1253 onclickList
.push( featureList
.join( ',' ), '\'); return false;' );
1254 attributes
[ '_cke_pa_onclick' ] = onclickList
.join( '' );
1258 if ( data
.target
.type
!= 'notSet' && data
.target
.name
)
1259 attributes
.target
= data
.target
.name
;
1261 removeAttributes
.push( 'target' );
1263 removeAttributes
.push( '_cke_pa_onclick', 'onclick' );
1267 // Advanced attributes.
1270 var advAttr = function( inputName
, attrName
)
1272 var value
= data
.adv
[ inputName
];
1274 attributes
[attrName
] = value
;
1276 removeAttributes
.push( attrName
);
1279 if ( this._
.selectedElement
)
1280 advAttr( 'advId', 'id' );
1281 advAttr( 'advLangDir', 'dir' );
1282 advAttr( 'advAccessKey', 'accessKey' );
1283 advAttr( 'advName', 'name' );
1284 advAttr( 'advLangCode', 'lang' );
1285 advAttr( 'advTabIndex', 'tabindex' );
1286 advAttr( 'advTitle', 'title' );
1287 advAttr( 'advContentType', 'type' );
1288 advAttr( 'advCSSClasses', 'class' );
1289 advAttr( 'advCharset', 'charset' );
1290 advAttr( 'advStyles', 'style' );
1293 if ( !this._
.selectedElement
)
1295 // Create element if current selection is collapsed.
1296 var selection
= editor
.getSelection(),
1297 ranges
= selection
.getRanges();
1298 if ( ranges
.length
== 1 && ranges
[0].collapsed
)
1300 var text
= new CKEDITOR
.dom
.text( attributes
._cke_saved_href
, editor
.document
);
1301 ranges
[0].insertNode( text
);
1302 ranges
[0].selectNodeContents( text
);
1303 selection
.selectRanges( ranges
);
1307 var style
= new CKEDITOR
.style( { element
: 'a', attributes
: attributes
} );
1308 style
.type
= CKEDITOR
.STYLE_INLINE
; // need to override... dunno why.
1309 style
.apply( editor
.document
);
1311 // Id. Apply only to the first link.
1312 if ( data
.adv
&& data
.adv
.advId
)
1314 var links
= this.getParentEditor().document
.$.getElementsByTagName( 'a' );
1315 for ( i
= 0 ; i
< links
.length
; i
++ )
1317 if ( links
[i
].href
== attributes
.href
)
1319 links
[i
].id
= data
.adv
.advId
;
1327 // We're only editing an existing link, so just overwrite the attributes.
1328 var element
= this._
.selectedElement
,
1329 href
= element
.getAttribute( '_cke_saved_href' ),
1330 textView
= element
.getHtml();
1332 // IE BUG: Setting the name attribute to an existing link doesn't work.
1333 // Must re-create the link from weired syntax to workaround.
1334 if ( CKEDITOR
.env
.ie
&& attributes
.name
!= element
.getAttribute( 'name' ) )
1336 var newElement
= new CKEDITOR
.dom
.element( '<a name="' + CKEDITOR
.tools
.htmlEncode( attributes
.name
) + '">',
1339 selection
= editor
.getSelection();
1341 element
.moveChildren( newElement
);
1342 element
.copyAttributes( newElement
, { name
: 1 } );
1343 newElement
.replace( element
);
1344 element
= newElement
;
1346 selection
.selectElement( element
);
1349 element
.setAttributes( attributes
);
1350 element
.removeAttributes( removeAttributes
);
1351 // Update text view when user changes protocol #4612.
1352 if (href
== textView
)
1353 element
.setHtml( attributes
._cke_saved_href
);
1354 // Make the element display as an anchor if a name has been set.
1355 if ( element
.getAttribute( 'name' ) )
1356 element
.addClass( 'cke_anchor' );
1358 element
.removeClass( 'cke_anchor' );
1361 editor
.createFakeElement( element
, 'cke_anchor', 'anchor' ).replace( this.fakeObj
);
1363 delete this._
.selectedElement
;
1368 if ( !editor
.config
.linkShowAdvancedTab
)
1369 this.hidePage( 'advanced' ); //Hide Advanded tab.
1371 if ( !editor
.config
.linkShowTargetTab
)
1372 this.hidePage( 'target' ); //Hide Target tab.
1375 // Inital focus on 'url' field if link is of type URL.
1376 onFocus : function()
1378 var linkType
= this.getContentElement( 'info', 'linkType' ),
1380 if ( linkType
&& linkType
.getValue( ) == 'url' )
1382 urlField
= this.getContentElement( 'info', 'url' );
1390 * The e-mail address anti-spam protection option. The protection will be
1391 * applied when creating or modifying e-mail links through the editor interface.<br>
1392 * Two methods of protection can be choosed:
1393 * <ol> <li>The e-mail parts (name, domain and any other query string) are
1394 * assembled into a function call pattern. Such function must be
1395 * provided by the developer in the pages that will use the contents.
1396 * <li>Only the e-mail address is obfuscated into a special string that
1397 * has no meaning for humans or spam bots, but which is properly
1398 * rendered and accepted by the browser.</li></ol>
1399 * Both approaches require JavaScript to be enabled.
1400 * @name CKEDITOR.config.emailProtection
1403 * @default '' (empty string = disabled)
1405 * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
1406 * config.emailProtection = '';
1408 * // 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>"
1409 * config.emailProtection = 'encode';
1411 * // href="javascript:mt('tester','ckeditor.com','subject','body')"
1412 * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';