Update ckeditor to version 3.2.1
[gopost.git] / ckeditor / _source / plugins / link / dialogs / link.js
blob4ac6766aefebf192ffe005607e54c648a0db3ce1
1 /*
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
4 */
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 )
18 return;
20 popupFeatures = popupFeatures.getElement();
21 popupFeatures.hide();
22 targetName.setValue( '' );
24 switch ( value )
26 case 'frame' :
27 targetName.setLabel( editor.lang.link.targetFrameName );
28 targetName.getElement().show();
29 break;
30 case 'popup' :
31 popupFeatures.show();
32 targetName.setLabel( editor.lang.link.targetPopupName );
33 targetName.getElement().show();
34 break;
35 default :
36 targetName.setValue( value );
37 targetName.getElement().hide();
38 break;
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' );
59 else
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] );
69 if ( !element )
70 continue;
72 element = element.getElement().getParent().getParent();
73 if ( partIds[i] == typeValue + 'Options' )
74 element.show();
75 else
76 element.hide();
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:([^(]+)\(([^)]+)\)$/;
91 var popupRegex =
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' ) ) ) || '',
98 javascriptMatch,
99 emailMatch,
100 anchorMatch,
101 urlMatch,
102 retval = {};
104 if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) )
106 if ( emailProtection == 'encode' )
108 href = href.replace( encodedEmailLinkRegex,
109 function ( match, protectedAddress, rest )
111 return 'mailto:' +
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,
130 paramName,
131 paramVal;
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( '@' );
141 } );
145 if ( !retval.type )
147 if ( ( anchorMatch = href.match( anchorRegex ) ) )
149 retval.type = 'anchor';
150 retval.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 ) ) )
168 retval.type = 'url';
169 retval.url = {};
170 retval.url.protocol = urlMatch[1];
171 retval.url.url = urlMatch[2];
173 else
174 retval.type = 'url';
177 // Load target and popup settings.
178 if ( element )
180 var target = element.getAttribute( 'target' );
181 retval.target = {};
182 retval.adv = {};
184 // IE BUG: target attribute is an empty string instead of null in IE if it's not set.
185 if ( !target )
187 var onclick = element.getAttribute( '_cke_pa_onclick' ) || element.getAttribute( 'onclick' ),
188 onclickMatch = onclick && onclick.match( popupRegex );
189 if ( onclickMatch )
191 retval.target.type = 'popup';
192 retval.target.name = onclickMatch[1];
194 var featureMatch;
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];
204 else
206 var targetMatch = target.match( selectableTargets );
207 if ( targetMatch )
208 retval.target.type = retval.target.name = target;
209 else
211 retval.target.type = 'frame';
212 retval.target.name = target;
216 var me = this;
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++ )
256 item = anchors[ 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;
263 return retval;
266 var setupParams = function( page, data )
268 if ( data[page] )
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 )
284 if ( !data[page] )
285 data[page] = {};
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 );
324 } );
325 } );
328 function protectEmailLinkAsFunction( email )
330 var retval,
331 name = compiledProtectionFunction.name,
332 params = compiledProtectionFunction.params,
333 paramName,
334 paramValue;
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( ',' );
343 retval.push( '\'',
344 paramValue ?
345 escapeSingleQuote( encodeURIComponent( email[ paramName ] ) )
346 : '',
347 '\'');
349 retval.push( ')' );
350 return retval.join( '' );
353 function protectEmailAddressAsEncodedString( address )
355 var charCode,
356 length = address.length,
357 encodedChars = [];
358 for ( var i = 0; i < length; i++ )
360 charCode = address.charCodeAt( i );
361 encodedChars.push( charCode );
363 return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')';
366 return {
367 title : editor.lang.link.title,
368 minWidth : 350,
369 minHeight : 230,
370 contents : [
372 id : 'info',
373 label : editor.lang.link.info,
374 title : editor.lang.link.info,
375 elements :
378 id : 'linkType',
379 type : 'select',
380 label : editor.lang.link.type,
381 'default' : 'url',
382 items :
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 )
391 if ( data.type )
392 this.setValue( data.type );
394 commit : function( data )
396 data.type = this.getValue();
400 type : 'vbox',
401 id : 'urlOptions',
402 children :
405 type : 'hbox',
406 widths : [ '25%', '75%' ],
407 children :
410 id : 'protocol',
411 type : 'select',
412 label : editor.lang.common.protocol,
413 'default' : 'http://',
414 style : 'width : 100%;',
415 items :
417 [ 'http://' ],
418 [ 'https://' ],
419 [ 'ftp://' ],
420 [ 'news://' ],
421 [ editor.lang.link.other , '' ]
423 setup : function( data )
425 if ( data.url )
426 this.setValue( data.url.protocol || '' );
428 commit : function( data )
430 if ( !data.url )
431 data.url = {};
433 data.url.protocol = this.getValue();
437 type : 'text',
438 id : 'url',
439 label : editor.lang.common.url,
440 required: true,
441 onLoad : function ()
443 this.allowOnChange = true;
445 onKeyUp : function()
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 );
454 if ( protocol )
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.
467 this.onKeyUp();
469 validate : function()
471 var dialog = this.getDialog();
473 if ( dialog.getContentElement( 'info', 'linkType' ) &&
474 dialog.getValueOf( 'info', 'linkType' ) != 'url' )
475 return true;
477 if ( this.getDialog().fakeObj ) // Edit Anchor.
478 return true;
480 var func = CKEDITOR.dialog.validate.notEmpty( editor.lang.link.noUrl );
481 return func.apply( this );
483 setup : function( data )
485 this.allowOnChange = false;
486 if ( data.url )
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
495 this.onChange();
497 if ( !data.url )
498 data.url = {};
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();
512 type : 'button',
513 id : 'browse',
514 hidden : 'true',
515 filebrowser : 'info:url',
516 label : editor.lang.common.browseServer
521 type : 'vbox',
522 id : 'anchorOptions',
523 width : 260,
524 align : 'center',
525 padding : 0,
526 children :
529 type : 'fieldset',
530 id : 'selectAnchorText',
531 label : editor.lang.link.selectAnchor,
532 setup : function( data )
534 if ( data.anchors.length > 0 )
535 this.getElement().show();
536 else
537 this.getElement().hide();
539 children :
542 type : 'hbox',
543 id : 'selectAnchor',
544 children :
547 type : 'select',
548 id : 'anchorName',
549 'default' : '',
550 label : editor.lang.link.anchorName,
551 style : 'width: 100%;',
552 items :
554 [ '' ]
556 setup : function( data )
558 this.clear();
559 this.add( '' );
560 for ( var i = 0 ; i < data.anchors.length ; i++ )
562 if ( data.anchors[i].name )
563 this.add( data.anchors[i].name );
566 if ( data.anchor )
567 this.setValue( data.anchor.name );
569 var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
570 if ( linkType && linkType.getValue() == 'email' )
571 this.focus();
573 commit : function( data )
575 if ( !data.anchor )
576 data.anchor = {};
578 data.anchor.name = this.getValue();
582 type : 'select',
583 id : 'anchorId',
584 'default' : '',
585 label : editor.lang.link.anchorId,
586 style : 'width: 100%;',
587 items :
589 [ '' ]
591 setup : function( data )
593 this.clear();
594 this.add( '' );
595 for ( var i = 0 ; i < data.anchors.length ; i++ )
597 if ( data.anchors[i].id )
598 this.add( data.anchors[i].id );
601 if ( data.anchor )
602 this.setValue( data.anchor.id );
604 commit : function( data )
606 if ( !data.anchor )
607 data.anchor = {};
609 data.anchor.id = this.getValue();
613 setup : function( data )
615 if ( data.anchors.length > 0 )
616 this.getElement().show();
617 else
618 this.getElement().hide();
624 type : 'html',
625 id : 'noAnchors',
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.
629 focus : true,
630 setup : function( data )
632 if ( data.anchors.length < 1 )
633 this.getElement().show();
634 else
635 this.getElement().hide();
639 setup : function( data )
641 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
642 this.getElement().hide();
646 type : 'vbox',
647 id : 'emailOptions',
648 padding : 1,
649 children :
652 type : 'text',
653 id : 'emailAddress',
654 label : editor.lang.link.emailAddress,
655 required : true,
656 validate : function()
658 var dialog = this.getDialog();
660 if ( !dialog.getContentElement( 'info', 'linkType' ) ||
661 dialog.getValueOf( 'info', 'linkType' ) != 'email' )
662 return true;
664 var func = CKEDITOR.dialog.validate.notEmpty( editor.lang.link.noEmail );
665 return func.apply( this );
667 setup : function( data )
669 if ( data.email )
670 this.setValue( data.email.address );
672 var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
673 if ( linkType && linkType.getValue() == 'email' )
674 this.select();
676 commit : function( data )
678 if ( !data.email )
679 data.email = {};
681 data.email.address = this.getValue();
685 type : 'text',
686 id : 'emailSubject',
687 label : editor.lang.link.emailSubject,
688 setup : function( data )
690 if ( data.email )
691 this.setValue( data.email.subject );
693 commit : function( data )
695 if ( !data.email )
696 data.email = {};
698 data.email.subject = this.getValue();
702 type : 'textarea',
703 id : 'emailBody',
704 label : editor.lang.link.emailBody,
705 rows : 3,
706 'default' : '',
707 setup : function( data )
709 if ( data.email )
710 this.setValue( data.email.body );
712 commit : function( data )
714 if ( !data.email )
715 data.email = {};
717 data.email.body = this.getValue();
721 setup : function( data )
723 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
724 this.getElement().hide();
730 id : 'target',
731 label : editor.lang.link.target,
732 title : editor.lang.link.target,
733 elements :
736 type : 'hbox',
737 widths : [ '50%', '50%' ],
738 children :
741 type : 'select',
742 id : 'linkTargetType',
743 label : editor.lang.common.target,
744 'default' : 'notSet',
745 style : 'width : 100%;',
746 'items' :
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 )
759 if ( data.target )
760 this.setValue( data.target.type );
762 commit : function( data )
764 if ( !data.target )
765 data.target = {};
767 data.target.type = this.getValue();
771 type : 'text',
772 id : 'linkTargetName',
773 label : editor.lang.link.targetFrameName,
774 'default' : '',
775 setup : function( data )
777 if ( data.target )
778 this.setValue( data.target.name );
780 commit : function( data )
782 if ( !data.target )
783 data.target = {};
785 data.target.name = this.getValue().replace(/\W/gi, '');
791 type : 'vbox',
792 width : 260,
793 align : 'center',
794 padding : 2,
795 id : 'popupFeatures',
796 children :
799 type : 'fieldset',
800 label : editor.lang.link.popupFeatures,
801 children :
804 type : 'hbox',
805 children :
808 type : 'checkbox',
809 id : 'resizable',
810 label : editor.lang.link.popupResizable,
811 setup : setupPopupParams,
812 commit : commitPopupParams
815 type : 'checkbox',
816 id : 'status',
817 label : editor.lang.link.popupStatusBar,
818 setup : setupPopupParams,
819 commit : commitPopupParams
825 type : 'hbox',
826 children :
829 type : 'checkbox',
830 id : 'location',
831 label : editor.lang.link.popupLocationBar,
832 setup : setupPopupParams,
833 commit : commitPopupParams
837 type : 'checkbox',
838 id : 'toolbar',
839 label : editor.lang.link.popupToolbar,
840 setup : setupPopupParams,
841 commit : commitPopupParams
847 type : 'hbox',
848 children :
851 type : 'checkbox',
852 id : 'menubar',
853 label : editor.lang.link.popupMenuBar,
854 setup : setupPopupParams,
855 commit : commitPopupParams
859 type : 'checkbox',
860 id : 'fullscreen',
861 label : editor.lang.link.popupFullScreen,
862 setup : setupPopupParams,
863 commit : commitPopupParams
869 type : 'hbox',
870 children :
873 type : 'checkbox',
874 id : 'scrollbars',
875 label : editor.lang.link.popupScrollBars,
876 setup : setupPopupParams,
877 commit : commitPopupParams
881 type : 'checkbox',
882 id : 'dependent',
883 label : editor.lang.link.popupDependent,
884 setup : setupPopupParams,
885 commit : commitPopupParams
891 type : 'hbox',
892 children :
895 type : 'text',
896 widths : [ '30%', '70%' ],
897 labelLayout : 'horizontal',
898 label : editor.lang.link.popupWidth,
899 id : 'width',
900 setup : setupPopupParams,
901 commit : commitPopupParams
905 type : 'text',
906 labelLayout : 'horizontal',
907 widths : [ '55%', '45%' ],
908 label : editor.lang.link.popupLeft,
909 id : 'left',
910 setup : setupPopupParams,
911 commit : commitPopupParams
917 type : 'hbox',
918 children :
921 type : 'text',
922 labelLayout : 'horizontal',
923 widths : [ '30%', '70%' ],
924 label : editor.lang.link.popupHeight,
925 id : 'height',
926 setup : setupPopupParams,
927 commit : commitPopupParams
931 type : 'text',
932 labelLayout : 'horizontal',
933 label : editor.lang.link.popupTop,
934 widths : [ '55%', '45%' ],
935 id : 'top',
936 setup : setupPopupParams,
937 commit : commitPopupParams
949 id : 'upload',
950 label : editor.lang.link.upload,
951 title : editor.lang.link.upload,
952 hidden : true,
953 filebrowser : 'uploadButton',
954 elements :
957 type : 'file',
958 id : 'upload',
959 label : editor.lang.common.upload,
960 style: 'height:40px',
961 size : 29
964 type : 'fileButton',
965 id : 'uploadButton',
966 label : editor.lang.common.uploadSubmit,
967 filebrowser : 'info:url',
968 'for' : [ 'upload', 'upload' ]
973 id : 'advanced',
974 label : editor.lang.link.advanced,
975 title : editor.lang.link.advanced,
976 elements :
979 type : 'vbox',
980 padding : 1,
981 children :
984 type : 'hbox',
985 widths : [ '45%', '35%', '20%' ],
986 children :
989 type : 'text',
990 id : 'advId',
991 label : editor.lang.link.id,
992 setup : setupAdvParams,
993 commit : commitAdvParams
996 type : 'select',
997 id : 'advLangDir',
998 label : editor.lang.link.langDir,
999 'default' : '',
1000 style : 'width:110px',
1001 items :
1003 [ editor.lang.common.notSet, '' ],
1004 [ editor.lang.link.langDirLTR, 'ltr' ],
1005 [ editor.lang.link.langDirRTL, 'rtl' ]
1007 setup : setupAdvParams,
1008 commit : commitAdvParams
1011 type : 'text',
1012 id : 'advAccessKey',
1013 width : '80px',
1014 label : editor.lang.link.acccessKey,
1015 maxLength : 1,
1016 setup : setupAdvParams,
1017 commit : commitAdvParams
1023 type : 'hbox',
1024 widths : [ '45%', '35%', '20%' ],
1025 children :
1028 type : 'text',
1029 label : editor.lang.link.name,
1030 id : 'advName',
1031 setup : setupAdvParams,
1032 commit : commitAdvParams
1036 type : 'text',
1037 label : editor.lang.link.langCode,
1038 id : 'advLangCode',
1039 width : '110px',
1040 'default' : '',
1041 setup : setupAdvParams,
1042 commit : commitAdvParams
1046 type : 'text',
1047 label : editor.lang.link.tabIndex,
1048 id : 'advTabIndex',
1049 width : '80px',
1050 maxLength : 5,
1051 setup : setupAdvParams,
1052 commit : commitAdvParams
1060 type : 'vbox',
1061 padding : 1,
1062 children :
1065 type : 'hbox',
1066 widths : [ '45%', '55%' ],
1067 children :
1070 type : 'text',
1071 label : editor.lang.link.advisoryTitle,
1072 'default' : '',
1073 id : 'advTitle',
1074 setup : setupAdvParams,
1075 commit : commitAdvParams
1079 type : 'text',
1080 label : editor.lang.link.advisoryContentType,
1081 'default' : '',
1082 id : 'advContentType',
1083 setup : setupAdvParams,
1084 commit : commitAdvParams
1090 type : 'hbox',
1091 widths : [ '45%', '55%' ],
1092 children :
1095 type : 'text',
1096 label : editor.lang.link.cssClasses,
1097 'default' : '',
1098 id : 'advCSSClasses',
1099 setup : setupAdvParams,
1100 commit : commitAdvParams
1104 type : 'text',
1105 label : editor.lang.link.charset,
1106 'default' : '',
1107 id : 'advCharset',
1108 setup : setupAdvParams,
1109 commit : commitAdvParams
1115 type : 'hbox',
1116 children :
1119 type : 'text',
1120 label : editor.lang.link.styles,
1121 'default' : '',
1122 id : 'advStyles',
1123 setup : setupAdvParams,
1124 commit : commitAdvParams
1134 onShow : function()
1136 this.fakeObj = false;
1138 var editor = this.getParentEditor(),
1139 selection = editor.getSelection(),
1140 element = null;
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 );
1153 else
1154 element = null;
1156 this.setupContent( parseLink.apply( this, [ editor, element ] ) );
1158 onOk : function()
1160 var attributes = { href : 'javascript:void(0)/*' + CKEDITOR.tools.getNextNumber() + '*/' },
1161 removeAttributes = [],
1162 data = { href : attributes.href },
1163 me = this,
1164 editor = this.getParentEditor();
1166 this.commitContent( data );
1168 // Compose the URL.
1169 switch ( data.type || 'url' )
1171 case '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;
1175 break;
1176 case 'anchor':
1177 var name = ( data.anchor && data.anchor.name ),
1178 id = ( data.anchor && data.anchor.id );
1179 attributes._cke_saved_href = '#' + ( name || id || '' );
1180 break;
1181 case 'email':
1183 var linkHref,
1184 email = data.email,
1185 address = email.address;
1187 switch( emailProtection )
1189 case '' :
1190 case 'encode' :
1192 var subject = encodeURIComponent( email.subject || '' ),
1193 body = encodeURIComponent( email.body || '' );
1195 // Build the e-mail parameters first.
1196 var argList = [];
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( ')' );
1210 else
1211 linkHref = [ 'mailto:', address, argList ];
1213 break;
1215 default :
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( '' );
1227 break;
1230 // Popups and target.
1231 if ( data.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( '' );
1256 else
1258 if ( data.target.type != 'notSet' && data.target.name )
1259 attributes.target = data.target.name;
1260 else
1261 removeAttributes.push( 'target' );
1263 removeAttributes.push( '_cke_pa_onclick', 'onclick' );
1267 // Advanced attributes.
1268 if ( data.adv )
1270 var advAttr = function( inputName, attrName )
1272 var value = data.adv[ inputName ];
1273 if ( value )
1274 attributes[attrName] = value;
1275 else
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 );
1306 // Apply style.
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;
1320 break;
1325 else
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 ) + '">',
1337 editor.document );
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' );
1357 else
1358 element.removeClass( 'cke_anchor' );
1360 if ( this.fakeObj )
1361 editor.createFakeElement( element, 'cke_anchor', 'anchor' ).replace( this.fakeObj );
1363 delete this._.selectedElement;
1366 onLoad : function()
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' ),
1379 urlField;
1380 if ( linkType && linkType.getValue( ) == 'url' )
1382 urlField = this.getContentElement( 'info', 'url' );
1383 urlField.select();
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
1401 * @since 3.1
1402 * @type String
1403 * @default '' (empty string = disabled)
1404 * @example
1405 * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
1406 * config.emailProtection = '';
1407 * @example
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';
1410 * @example
1411 * // href="javascript:mt('tester','ckeditor.com','subject','body')"
1412 * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';