1 /* 2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 CKEDITOR.dialog.add( 'link', function( editor ) 7 { 8 // Handles the event when the "Target" selection box is changed. 9 var targetChanged = function() 10 { 11 var dialog = this.getDialog(), 12 popupFeatures = dialog.getContentElement( 'target', 'popupFeatures' ), 13 targetName = dialog.getContentElement( 'target', 'linkTargetName' ), 14 value = this.getValue(); 15 16 if ( !popupFeatures || !targetName ) 17 return; 18 19 popupFeatures = popupFeatures.getElement(); 20 21 if ( value == 'popup' ) 22 { 23 popupFeatures.show(); 24 targetName.setLabel( editor.lang.link.targetPopupName ); 25 } 26 else 27 { 28 popupFeatures.hide(); 29 targetName.setLabel( editor.lang.link.targetFrameName ); 30 this.getDialog().setValueOf( 'target', 'linkTargetName', value.charAt( 0 ) == '_' ? value : '' ); 31 } 32 }; 33 34 // Handles the event when the "Type" selection box is changed. 35 var linkTypeChanged = function() 36 { 37 var dialog = this.getDialog(), 38 partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ], 39 typeValue = this.getValue(); 40 if ( typeValue == 'url' ) 41 { 42 if ( editor.config.linkShowTargetTab ) 43 dialog.showPage( 'target' ); 44 if ( editor.config.linkUploadTab ) 45 dialog.showPage( 'upload' ); 46 } 47 else 48 { 49 dialog.hidePage( 'target' ); 50 dialog.hidePage( 'upload' ); 51 } 52 53 for ( var i = 0 ; i < partIds.length ; i++ ) 54 { 55 var element = dialog.getContentElement( 'info', partIds[i] ); 56 if ( !element ) 57 continue; 58 59 element = element.getElement().getParent().getParent(); 60 if ( partIds[i] == typeValue + 'Options' ) 61 element.show(); 62 else 63 element.hide(); 64 } 65 }; 66 67 // Loads the parameters in a selected link to the link dialog fields. 68 var emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/, 69 emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/, 70 emailBodyRegex = /body=([^;?:@&=$,\/]*)/, 71 anchorRegex = /^#(.*)$/, 72 urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/, 73 selectableTargets = /^(_(?:self|top|parent|blank))$/; 74 75 var popupRegex = 76 /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/; 77 var popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/gi; 78 79 var parseLink = function( editor, element ) 80 { 81 var href = element ? ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) : '', 82 emailMatch = '', 83 anchorMatch = '', 84 urlMatch = false, 85 retval = {}; 86 87 if ( href != null ) 88 { 89 emailMatch = href.match( emailRegex ); 90 anchorMatch = href.match( anchorRegex ); 91 urlMatch = href.match( urlRegex ); 92 } 93 94 // Load the link type and URL. 95 if ( emailMatch ) 96 { 97 var subjectMatch = href.match( emailSubjectRegex ), 98 bodyMatch = href.match( emailBodyRegex ); 99 retval.type = 'email'; 100 retval.email = {}; 101 retval.email.address = emailMatch[1]; 102 subjectMatch && ( retval.email.subject = decodeURIComponent( subjectMatch[1] ) ); 103 bodyMatch && ( retval.email.body = decodeURIComponent( bodyMatch[1] ) ); 104 } 105 else if ( anchorMatch ) 106 { 107 retval.type = 'anchor'; 108 retval.anchor = {}; 109 retval.anchor.name = retval.anchor.id = anchorMatch[1]; 110 } 111 else if ( href && urlMatch ) // urlRegex matches empty strings, so need to check for href as well. 112 { 113 retval.type = 'url'; 114 retval.url = {}; 115 retval.url.protocol = urlMatch[1]; 116 retval.url.url = urlMatch[2]; 117 } 118 else 119 retval.type = 'url'; 120 121 // Load target and popup settings. 122 if ( element ) 123 { 124 var target = element.getAttribute( 'target' ); 125 retval.target = {}; 126 retval.adv = {}; 127 128 // IE BUG: target attribute is an empty string instead of null in IE if it's not set. 129 if ( !target ) 130 { 131 var onclick = element.getAttribute( '_cke_pa_onclick' ) || element.getAttribute( 'onclick' ), 132 onclickMatch = onclick && onclick.match( popupRegex ); 133 if ( onclickMatch ) 134 { 135 retval.target.type = 'popup'; 136 retval.target.name = onclickMatch[1]; 137 138 var featureMatch; 139 while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[2] ) ) ) 140 { 141 if ( featureMatch[2] == 'yes' || featureMatch[2] == '1' ) 142 retval.target[ featureMatch[1] ] = true; 143 else if ( isFinite( featureMatch[2] ) ) 144 retval.target[ featureMatch[1] ] = featureMatch[2]; 145 } 146 } 147 } 148 else 149 { 150 var targetMatch = target.match( selectableTargets ); 151 if ( targetMatch ) 152 retval.target.type = retval.target.name = target; 153 else 154 { 155 retval.target.type = 'frame'; 156 retval.target.name = target; 157 } 158 } 159 160 var me = this; 161 var advAttr = function( inputName, attrName ) 162 { 163 var value = element.getAttribute( attrName ); 164 if ( value != null ) 165 retval.adv[ inputName ] = value || ''; 166 }; 167 advAttr( 'advId', 'id' ); 168 advAttr( 'advLangDir', 'dir' ); 169 advAttr( 'advAccessKey', 'accessKey' ); 170 advAttr( 'advName', 'name' ); 171 advAttr( 'advLangCode', 'lang' ); 172 advAttr( 'advTabIndex', 'tabindex' ); 173 advAttr( 'advTitle', 'title' ); 174 advAttr( 'advContentType', 'type' ); 175 advAttr( 'advCSSClasses', 'class' ); 176 advAttr( 'advCharset', 'charset' ); 177 advAttr( 'advStyles', 'style' ); 178 } 179 180 // Find out whether we have any anchors in the editor. 181 // Get all IMG elements in CK document. 182 var elements = editor.document.$.getElementsByTagName( 'img' ), 183 realAnchors = editor.document.$.anchors, 184 anchors = retval.anchors = []; 185 for( var i = 0; i < elements.length ; i++ ) 186 { 187 var item = elements.item( i ); 188 if ( item.getAttribute( '_cke_realelement' ) && item.getAttribute( '_cke_real_element_type' ) == 'anchor' ) 189 { 190 var domElement = new CKEDITOR.dom.element( item ); 191 domElement = editor.restoreRealElement( domElement ); 192 anchors.push( domElement ); 193 } 194 } 195 for ( var i = 0 ; i < realAnchors.length ; i++ ) 196 anchors.push( realAnchors[i] ); 197 for ( var i = 0, item, length = anchors.length ; i < length && ( item = anchors.shift() ) ; i++ ) 198 anchors.push( { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) } ); 199 200 // Record down the selected element in the dialog. 201 this._.selectedElement = element; 202 203 return retval; 204 }; 205 206 var setupParams = function( page, data ) 207 { 208 if ( data[page] ) 209 this.setValue( data[page][this.id] || '' ); 210 }; 211 212 var setupPopupParams = function( data ) 213 { 214 return setupParams.call( this, 'target', data ); 215 }; 216 217 var setupAdvParams = function( data ) 218 { 219 return setupParams.call( this, 'adv', data ); 220 }; 221 222 var commitParams = function( page, data ) 223 { 224 if ( !data[page] ) 225 data[page] = {}; 226 227 data[page][this.id] = this.getValue() || ''; 228 }; 229 230 var commitPopupParams = function( data ) 231 { 232 return commitParams.call( this, 'target', data ); 233 }; 234 235 var commitAdvParams = function( data ) 236 { 237 return commitParams.call( this, 'adv', data ); 238 }; 239 240 return { 241 title : editor.lang.link.title, 242 minWidth : 400, 243 minHeight : 320, 244 contents : [ 245 { 246 id : 'info', 247 label : editor.lang.link.info, 248 title : editor.lang.link.info, 249 elements : 250 [ 251 { 252 id : 'linkType', 253 type : 'select', 254 label : editor.lang.link.type, 255 'default' : 'url', 256 items : 257 [ 258 [ editor.lang.common.url, 'url' ], 259 [ editor.lang.link.toAnchor, 'anchor' ], 260 [ editor.lang.link.toEmail, 'email' ] 261 ], 262 onChange : linkTypeChanged, 263 setup : function( data ) 264 { 265 if ( data.type ) 266 this.setValue( data.type ); 267 }, 268 commit : function( data ) 269 { 270 data.type = this.getValue(); 271 } 272 }, 273 { 274 type : 'vbox', 275 id : 'urlOptions', 276 children : 277 [ 278 { 279 type : 'hbox', 280 widths : [ '25%', '75%' ], 281 children : 282 [ 283 { 284 id : 'protocol', 285 type : 'select', 286 label : editor.lang.common.protocol, 287 'default' : 'http://', 288 style : 'width : 100%;', 289 items : 290 [ 291 [ 'http://' ], 292 [ 'https://' ], 293 [ 'ftp://' ], 294 [ 'news://' ], 295 [ '<other>', '' ] 296 ], 297 setup : function( data ) 298 { 299 if ( data.url ) 300 this.setValue( data.url.protocol ); 301 }, 302 commit : function( data ) 303 { 304 if ( !data.url ) 305 data.url = {}; 306 307 data.url.protocol = this.getValue(); 308 } 309 }, 310 { 311 type : 'text', 312 id : 'url', 313 label : editor.lang.common.url, 314 onLoad : function () 315 { 316 this.allowOnChange = true; 317 }, 318 onKeyUp : function() 319 { 320 this.allowOnChange = false; 321 var protocolCmb = this.getDialog().getContentElement( 'info', 'protocol' ), 322 url = this.getValue(), 323 urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/gi, 324 urlOnChangeTestOther = /^((javascript:)|[#\/\.])/gi; 325 326 var protocol = urlOnChangeProtocol.exec( url ); 327 if ( protocol ) 328 { 329 this.setValue( url.substr( protocol[ 0 ].length ) ); 330 protocolCmb.setValue( protocol[ 0 ].toLowerCase() ); 331 } 332 else if ( urlOnChangeTestOther.test( url ) ) 333 protocolCmb.setValue( '' ); 334 335 this.allowOnChange = true; 336 }, 337 onChange : function() 338 { 339 if ( this.allowOnChange ) // Dont't call on dialog load. 340 this.onKeyUp(); 341 }, 342 validate : function() 343 { 344 var dialog = this.getDialog(); 345 346 if ( dialog.getContentElement( 'info', 'linkType' ) && 347 dialog.getValueOf( 'info', 'linkType' ) != 'url' ) 348 return true; 349 350 if ( this.getDialog().fakeObj != false ) // Edit Anchor. 351 return true; 352 353 var func = CKEDITOR.dialog.validate.notEmpty( editor.lang.link.noUrl ); 354 return func.apply( this ); 355 }, 356 setup : function( data ) 357 { 358 this.allowOnChange = false; 359 if ( data.url ) 360 this.setValue( data.url.url ); 361 this.allowOnChange = true; 362 363 var linkType = this.getDialog().getContentElement( 'info', 'linkType' ); 364 if ( linkType && linkType.getValue() == 'url' ) 365 this.select(); 366 367 }, 368 commit : function( data ) 369 { 370 if ( !data.url ) 371 data.url = {}; 372 373 data.url.url = this.getValue(); 374 this.allowOnChange = false; 375 } 376 } 377 ], 378 setup : function( data ) 379 { 380 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) ) 381 this.getElement().show(); 382 } 383 }, 384 { 385 type : 'button', 386 id : 'browse', 387 label : editor.lang.common.browseServer 388 } 389 ] 390 }, 391 { 392 type : 'vbox', 393 id : 'anchorOptions', 394 width : 260, 395 align : 'center', 396 padding : 0, 397 children : 398 [ 399 { 400 type : 'html', 401 id : 'selectAnchorText', 402 html : CKEDITOR.tools.htmlEncode( editor.lang.link.selectAnchor ), 403 setup : function( data ) 404 { 405 if ( data.anchors.length > 0 ) 406 this.getElement().show(); 407 else 408 this.getElement().hide(); 409 } 410 }, 411 { 412 type : 'html', 413 id : 'noAnchors', 414 style : 'text-align: center;', 415 html : '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.link.noAnchors ) + '</div>', 416 setup : function( data ) 417 { 418 if ( data.anchors.length < 1 ) 419 this.getElement().show(); 420 else 421 this.getElement().hide(); 422 } 423 }, 424 { 425 type : 'hbox', 426 id : 'selectAnchor', 427 children : 428 [ 429 { 430 type : 'select', 431 id : 'anchorName', 432 'default' : '', 433 label : editor.lang.link.anchorName, 434 style : 'width: 100%;', 435 items : 436 [ 437 [ '' ] 438 ], 439 setup : function( data ) 440 { 441 this.clear(); 442 this.add( '' ); 443 for ( var i = 0 ; i < data.anchors.length ; i++ ) 444 { 445 if ( data.anchors[i].name ) 446 this.add( data.anchors[i].name ); 447 } 448 449 if ( data.anchor ) 450 this.setValue( data.anchor.name ); 451 452 var linkType = this.getDialog().getContentElement( 'info', 'linkType' ); 453 if ( linkType && linkType.getValue() == 'email' ) 454 this.focus(); 455 }, 456 commit : function( data ) 457 { 458 if ( !data.anchor ) 459 data.anchor = {}; 460 461 data.anchor.name = this.getValue(); 462 } 463 }, 464 { 465 type : 'select', 466 id : 'anchorId', 467 'default' : '', 468 label : editor.lang.link.anchorId, 469 style : 'width: 100%;', 470 items : 471 [ 472 [ '' ] 473 ], 474 setup : function( data ) 475 { 476 this.clear(); 477 this.add( '' ); 478 for ( var i = 0 ; i < data.anchors.length ; i++ ) 479 { 480 if ( data.anchors[i].id ) 481 this.add( data.anchors[i].id ); 482 } 483 484 if ( data.anchor ) 485 this.setValue( data.anchor.id ); 486 }, 487 commit : function( data ) 488 { 489 if ( !data.anchor ) 490 data.anchor = {}; 491 492 data.anchor.id = this.getValue(); 493 } 494 } 495 ], 496 setup : function( data ) 497 { 498 if ( data.anchors.length > 0 ) 499 this.getElement().show(); 500 else 501 this.getElement().hide(); 502 } 503 } 504 ], 505 setup : function( data ) 506 { 507 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) ) 508 this.getElement().hide(); 509 } 510 }, 511 { 512 type : 'vbox', 513 id : 'emailOptions', 514 padding : 1, 515 children : 516 [ 517 { 518 type : 'text', 519 id : 'emailAddress', 520 label : editor.lang.link.emailAddress, 521 validate : function() 522 { 523 var dialog = this.getDialog(); 524 525 if ( !dialog.getContentElement( 'info', 'linkType' ) || 526 dialog.getValueOf( 'info', 'linkType' ) != 'email' ) 527 return true; 528 529 var func = CKEDITOR.dialog.validate.notEmpty( editor.lang.link.noEmail ); 530 return func.apply( this ); 531 }, 532 setup : function( data ) 533 { 534 if ( data.email ) 535 this.setValue( data.email.address ); 536 537 var linkType = this.getDialog().getContentElement( 'info', 'linkType' ); 538 if ( linkType && linkType.getValue() == 'email' ) 539 this.select(); 540 }, 541 commit : function( data ) 542 { 543 if ( !data.email ) 544 data.email = {}; 545 546 data.email.address = this.getValue(); 547 } 548 }, 549 { 550 type : 'text', 551 id : 'emailSubject', 552 label : editor.lang.link.emailSubject, 553 setup : function( data ) 554 { 555 if ( data.email ) 556 this.setValue( data.email.subject ); 557 }, 558 commit : function( data ) 559 { 560 if ( !data.email ) 561 data.email = {}; 562 563 data.email.subject = this.getValue(); 564 } 565 }, 566 { 567 type : 'textarea', 568 id : 'emailBody', 569 label : editor.lang.link.emailBody, 570 rows : 3, 571 'default' : '', 572 setup : function( data ) 573 { 574 if ( data.email ) 575 this.setValue( data.email.body ); 576 }, 577 commit : function( data ) 578 { 579 if ( !data.email ) 580 data.email = {}; 581 582 data.email.body = this.getValue(); 583 } 584 } 585 ], 586 setup : function( data ) 587 { 588 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) ) 589 this.getElement().hide(); 590 } 591 } 592 ] 593 }, 594 { 595 id : 'target', 596 label : editor.lang.link.target, 597 title : editor.lang.link.target, 598 elements : 599 [ 600 { 601 type : 'hbox', 602 widths : [ '50%', '50%' ], 603 children : 604 [ 605 { 606 type : 'select', 607 id : 'linkTargetType', 608 label : editor.lang.link.target, 609 'default' : 'notSet', 610 style : 'width : 100%;', 611 'items' : 612 [ 613 [ editor.lang.link.targetNotSet, 'notSet' ], 614 [ editor.lang.link.targetFrame, 'frame' ], 615 [ editor.lang.link.targetPopup, 'popup' ], 616 [ editor.lang.link.targetNew, '_blank' ], 617 [ editor.lang.link.targetTop, '_top' ], 618 [ editor.lang.link.targetSelf, '_self' ], 619 [ editor.lang.link.targetParent, '_parent' ] 620 ], 621 onChange : targetChanged, 622 setup : function( data ) 623 { 624 if ( data.target ) 625 this.setValue( data.target.type ); 626 }, 627 commit : function( data ) 628 { 629 if ( !data.target ) 630 data.target = {}; 631 632 data.target.type = this.getValue(); 633 } 634 }, 635 { 636 type : 'text', 637 id : 'linkTargetName', 638 label : editor.lang.link.targetFrameName, 639 'default' : '', 640 setup : function( data ) 641 { 642 if ( data.target ) 643 this.setValue( data.target.name ); 644 }, 645 commit : function( data ) 646 { 647 if ( !data.target ) 648 data.target = {}; 649 650 data.target.name = this.getValue(); 651 } 652 } 653 ] 654 }, 655 { 656 type : 'vbox', 657 width : 260, 658 align : 'center', 659 padding : 2, 660 id : 'popupFeatures', 661 children : 662 [ 663 { 664 type : 'html', 665 html : CKEDITOR.tools.htmlEncode( editor.lang.link.popupFeatures ) 666 }, 667 { 668 type : 'hbox', 669 children : 670 [ 671 { 672 type : 'checkbox', 673 id : 'resizable', 674 label : editor.lang.link.popupResizable, 675 setup : setupPopupParams, 676 commit : commitPopupParams 677 }, 678 { 679 type : 'checkbox', 680 id : 'status', 681 label : editor.lang.link.popupStatusBar, 682 setup : setupPopupParams, 683 commit : commitPopupParams 684 685 } 686 ] 687 }, 688 { 689 type : 'hbox', 690 children : 691 [ 692 { 693 type : 'checkbox', 694 id : 'location', 695 label : editor.lang.link.popupLocationBar, 696 setup : setupPopupParams, 697 commit : commitPopupParams 698 699 }, 700 { 701 type : 'checkbox', 702 id : 'toolbar', 703 label : editor.lang.link.popupToolbar, 704 setup : setupPopupParams, 705 commit : commitPopupParams 706 707 } 708 ] 709 }, 710 { 711 type : 'hbox', 712 children : 713 [ 714 { 715 type : 'checkbox', 716 id : 'menubar', 717 label : editor.lang.link.popupMenuBar, 718 setup : setupPopupParams, 719 commit : commitPopupParams 720 721 }, 722 { 723 type : 'checkbox', 724 id : 'fullscreen', 725 label : editor.lang.link.popupFullScreen, 726 setup : setupPopupParams, 727 commit : commitPopupParams 728 729 } 730 ] 731 }, 732 { 733 type : 'hbox', 734 children : 735 [ 736 { 737 type : 'checkbox', 738 id : 'scrollbars', 739 label : editor.lang.link.popupScrollBars, 740 setup : setupPopupParams, 741 commit : commitPopupParams 742 743 }, 744 { 745 type : 'checkbox', 746 id : 'dependent', 747 label : editor.lang.link.popupDependent, 748 setup : setupPopupParams, 749 commit : commitPopupParams 750 751 } 752 ] 753 }, 754 { 755 type : 'hbox', 756 children : 757 [ 758 { 759 type : 'text', 760 widths : [ '30%', '70%' ], 761 labelLayout : 'horizontal', 762 label : editor.lang.link.popupWidth, 763 id : 'width', 764 setup : setupPopupParams, 765 commit : commitPopupParams 766 767 }, 768 { 769 type : 'text', 770 labelLayout : 'horizontal', 771 widths : [ '55%', '45%' ], 772 label : editor.lang.link.popupLeft, 773 id : 'left', 774 setup : setupPopupParams, 775 commit : commitPopupParams 776 777 } 778 ] 779 }, 780 { 781 type : 'hbox', 782 children : 783 [ 784 { 785 type : 'text', 786 labelLayout : 'horizontal', 787 widths : [ '30%', '70%' ], 788 label : editor.lang.link.popupHeight, 789 id : 'height', 790 setup : setupPopupParams, 791 commit : commitPopupParams 792 793 }, 794 { 795 type : 'text', 796 labelLayout : 'horizontal', 797 label : editor.lang.link.popupTop, 798 widths : [ '55%', '45%' ], 799 id : 'top', 800 setup : setupPopupParams, 801 commit : commitPopupParams 802 803 } 804 ] 805 } 806 ] 807 } 808 ] 809 }, 810 { 811 id : 'upload', 812 label : editor.lang.link.upload, 813 title : editor.lang.link.upload, 814 elements : 815 [ 816 { 817 type : 'file', 818 id : 'upload', 819 label : editor.lang.common.upload, 820 action : editor.config.linkUploadAction, 821 size : 38 822 }, 823 { 824 type : 'fileButton', 825 id : 'uploadButton', 826 label : editor.lang.common.uploadSubmit, 827 'for' : [ 'upload', 'upload' ] 828 } 829 ] 830 }, 831 { 832 id : 'advanced', 833 label : editor.lang.link.advanced, 834 title : editor.lang.link.advanced, 835 elements : 836 [ 837 { 838 type : 'vbox', 839 padding : 1, 840 children : 841 [ 842 { 843 type : 'hbox', 844 widths : [ '45%', '35%', '20%' ], 845 children : 846 [ 847 { 848 type : 'text', 849 id : 'advId', 850 label : editor.lang.link.id, 851 setup : setupAdvParams, 852 commit : commitAdvParams 853 }, 854 { 855 type : 'select', 856 id : 'advLangDir', 857 label : editor.lang.link.langDir, 858 'default' : '', 859 style : 'width: 100%;', 860 items : 861 [ 862 [ editor.lang.link.langDirNotSet, '' ], 863 [ editor.lang.link.langDirLTR, 'ltr' ], 864 [ editor.lang.link.langDirRTL, 'rtl' ] 865 ], 866 setup : setupAdvParams, 867 commit : commitAdvParams 868 }, 869 { 870 type : 'text', 871 id : 'advAccessKey', 872 label : editor.lang.link.acccessKey, 873 maxLength : 1, 874 setup : setupAdvParams, 875 commit : commitAdvParams 876 877 } 878 ] 879 }, 880 { 881 type : 'hbox', 882 widths : [ '45%', '35%', '20%' ], 883 children : 884 [ 885 { 886 type : 'text', 887 label : editor.lang.link.name, 888 id : 'advName', 889 setup : setupAdvParams, 890 commit : commitAdvParams 891 892 }, 893 { 894 type : 'text', 895 label : editor.lang.link.langCode, 896 id : 'advLangCode', 897 'default' : '', 898 setup : setupAdvParams, 899 commit : commitAdvParams 900 901 }, 902 { 903 type : 'text', 904 label : editor.lang.link.tabIndex, 905 id : 'advTabIndex', 906 maxLength : 5, 907 setup : setupAdvParams, 908 commit : commitAdvParams 909 910 } 911 ] 912 } 913 ] 914 }, 915 { 916 type : 'vbox', 917 padding : 1, 918 children : 919 [ 920 { 921 type : 'hbox', 922 widths : [ '45%', '55%' ], 923 children : 924 [ 925 { 926 type : 'text', 927 label : editor.lang.link.advisoryTitle, 928 'default' : '', 929 id : 'advTitle', 930 setup : setupAdvParams, 931 commit : commitAdvParams 932 933 }, 934 { 935 type : 'text', 936 label : editor.lang.link.advisoryContentType, 937 'default' : '', 938 id : 'advContentType', 939 setup : setupAdvParams, 940 commit : commitAdvParams 941 942 } 943 ] 944 }, 945 { 946 type : 'hbox', 947 widths : [ '45%', '55%' ], 948 children : 949 [ 950 { 951 type : 'text', 952 label : editor.lang.link.cssClasses, 953 'default' : '', 954 id : 'advCSSClasses', 955 setup : setupAdvParams, 956 commit : commitAdvParams 957 958 }, 959 { 960 type : 'text', 961 label : editor.lang.link.charset, 962 'default' : '', 963 id : 'advCharset', 964 setup : setupAdvParams, 965 commit : commitAdvParams 966 967 } 968 ] 969 }, 970 { 971 type : 'hbox', 972 children : 973 [ 974 { 975 type : 'text', 976 label : editor.lang.link.styles, 977 'default' : '', 978 id : 'advStyles', 979 setup : setupAdvParams, 980 commit : commitAdvParams 981 982 } 983 ] 984 } 985 ] 986 } 987 ] 988 } 989 ], 990 onShow : function() 991 { 992 this.fakeObj = false; 993 // IE BUG: Selection must be in the editor for getSelection() to work. 994 this.restoreSelection(); 995 var editor = this.getParentEditor(), 996 selection = editor.getSelection(), 997 ranges = selection.getRanges(), 998 element = null, 999 me = this; 1000 1001 // Fill in all the relevant fields if there's already one link selected. 1002 if ( ranges.length == 1 ) 1003 { 1004 ranges[0].enlarge( CKEDITOR.ENLARGE_ELEMENT ); 1005 1006 var rangeRoot = ranges[0].getCommonAncestor( true ); 1007 element = rangeRoot.getAscendant( 'a', true ); 1008 if ( element && element.getAttribute( 'href' ) ) 1009 { 1010 selection.selectElement( element ); 1011 this.saveSelection(); 1012 } 1013 else 1014 { 1015 element = rangeRoot.getAscendant( 'img', true ); 1016 if ( element && element.getAttribute( '_cke_real_element_type' ) && element.getAttribute( '_cke_real_element_type' ) == 'anchor' ) 1017 { 1018 this.fakeObj = element; 1019 element = editor.restoreRealElement( this.fakeObj ); 1020 selection.selectElement( this.fakeObj ); 1021 this.saveSelection(); 1022 } 1023 } 1024 } 1025 1026 this.setupContent( parseLink.apply( this, [ editor, element ] ) ); 1027 }, 1028 onOk : function() 1029 { 1030 var attributes = { href : 'javascript:void(0)/*' + CKEDITOR.tools.getNextNumber() + '*/' }, 1031 removeAttributes = [], 1032 data = { href : attributes.href }, 1033 me = this, editor = this.getParentEditor(); 1034 1035 this.commitContent( data ); 1036 1037 // Compose the URL. 1038 switch ( data.type || 'url' ) 1039 { 1040 case 'url': 1041 var protocol = ( data.url && data.url.protocol != undefined ) ? data.url.protocol : 'http://', 1042 url = ( data.url && data.url.url ) || ''; 1043 attributes._cke_saved_href = protocol + url; 1044 break; 1045 case 'anchor': 1046 var name = ( data.anchor && data.anchor.name ), 1047 id = ( data.anchor && data.anchor.id ); 1048 attributes._cke_saved_href = '#' + ( name || id || '' ); 1049 break; 1050 case 'email': 1051 var address = ( data.email && data.email.address ), 1052 subject = ( data.email && encodeURIComponent( data.email.subject || '' ) ), 1053 body = ( data.email && encodeURIComponent( data.email.body || '' ) ), 1054 linkList = [ 'mailto:', address ]; 1055 if ( subject || body ) 1056 { 1057 var argList = []; 1058 linkList.push( '?' ); 1059 subject && argList.push( 'subject=' + subject ); 1060 body && argList.push( 'body=' + body ); 1061 linkList.push( argList.join( '&' ) ); 1062 } 1063 attributes._cke_saved_href = linkList.join( '' ); 1064 break; 1065 default: 1066 } 1067 1068 // Popups and target. 1069 if ( data.target ) 1070 { 1071 if ( data.target.type == 'popup' ) 1072 { 1073 var onclickList = [ 'window.open(this.href, \'', 1074 data.target.name || '', '\', \'' ]; 1075 var featureList = [ 'resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen', 1076 'scrollbars', 'dependent' ]; 1077 var featureLength = featureList.length; 1078 var addFeature = function( featureName ) 1079 { 1080 if ( data.target[ featureName ] ) 1081 featureList.push( featureName + '=' + data.target[ featureName ] ); 1082 }; 1083 1084 for ( var i = 0 ; i < featureLength ; i++ ) 1085 featureList[i] = featureList[i] + ( data.target[ featureList[i] ] ? '=yes' : '=no' ) ; 1086 addFeature( 'width' ); 1087 addFeature( 'left' ); 1088 addFeature( 'height' ); 1089 addFeature( 'top' ); 1090 1091 onclickList.push( featureList.join( ',' ), '\'); return false;' ); 1092 attributes[ CKEDITOR.env.ie || CKEDITOR.env.webkit ? '_cke_pa_onclick' : 'onclick' ] = onclickList.join( '' ); 1093 } 1094 else 1095 { 1096 if ( data.target.type != 'notSet' && data.target.name ) 1097 attributes.target = data.target.name; 1098 removeAttributes.push( '_cke_pa_onclick', 'onclick' ); 1099 } 1100 } 1101 1102 // Advanced attributes. 1103 if ( data.adv ) 1104 { 1105 var advAttr = function( inputName, attrName ) 1106 { 1107 var value = data.adv[ inputName ]; 1108 if ( value ) 1109 attributes[attrName] = value; 1110 else 1111 removeAttributes.push( attrName ); 1112 }; 1113 1114 if ( this._.selectedElement ) 1115 advAttr( 'advId', 'id' ); 1116 advAttr( 'advLangDir', 'dir' ); 1117 advAttr( 'advAccessKey', 'accessKey' ); 1118 advAttr( 'advName', 'name' ); 1119 advAttr( 'advLangCode', 'lang' ); 1120 advAttr( 'advTabIndex', 'tabindex' ); 1121 advAttr( 'advTitle', 'title' ); 1122 advAttr( 'advContentType', 'type' ); 1123 advAttr( 'advCSSClasses', 'class' ); 1124 advAttr( 'advCharset', 'charset' ); 1125 advAttr( 'advStyles', 'style' ); 1126 } 1127 1128 if ( !this._.selectedElement ) 1129 { 1130 // IE BUG: Selection must be in the editor for getSelection() to work. 1131 this.restoreSelection(); 1132 this.clearSavedSelection(); 1133 1134 // Create element if current selection is collapsed. 1135 var selection = editor.getSelection(), 1136 ranges = selection.getRanges(); 1137 if ( ranges.length == 1 && ranges[0].collapsed ) 1138 { 1139 var text = new CKEDITOR.dom.text( attributes._cke_saved_href, editor.document ); 1140 ranges[0].insertNode( text ); 1141 ranges[0].selectNodeContents( text ); 1142 selection.selectRanges( ranges ); 1143 } 1144 1145 // Apply style. 1146 var style = new CKEDITOR.style( { element : 'a', attributes : attributes } ); 1147 style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why. 1148 style.apply( editor.document ); 1149 1150 // Id. Apply only to the first link. 1151 if ( data.adv && data.adv.advId != '' ) 1152 { 1153 var links = this.getParentEditor().document.$.getElementsByTagName( 'a' ); 1154 for ( var i = 0 ; i < links.length ; i++ ) 1155 { 1156 if ( links[i].href == attributes.href ) 1157 { 1158 links[i].id = data.adv.advId; 1159 break; 1160 } 1161 } 1162 } 1163 } 1164 else 1165 { 1166 // We're only editing an existing link, so just overwrite the attributes. 1167 var element = this._.selectedElement; 1168 1169 // IE BUG: Setting the name attribute to an existing link doesn't work. 1170 // Must re-create the link from weired syntax to workaround. 1171 if ( CKEDITOR.env.ie && attributes.name != element.getAttribute( 'name' ) ) 1172 { 1173 var newElement = new CKEDITOR.dom.element( '<a name="' + CKEDITOR.tools.htmlEncode( attributes.name ) + '">', 1174 editor.document ); 1175 1176 this.restoreSelection(); 1177 var selection = editor.getSelection(); 1178 1179 element.moveChildren( newElement ); 1180 element.copyAttributes( newElement, { name : 1 } ); 1181 newElement.replace( element ); 1182 element = newElement; 1183 1184 this.clearSavedSelection(); 1185 selection.selectElement( element ); 1186 } 1187 1188 element.setAttributes( attributes ); 1189 element.removeAttributes( removeAttributes ); 1190 1191 // Make the element display as an anchor if a name has been set. 1192 if ( element.getAttribute( 'name' ) ) 1193 element.addClass( 'cke_anchor' ); 1194 else 1195 element.removeClass( 'cke_anchor' ); 1196 1197 if ( this.fakeObj ) 1198 editor.createFakeElement( element, 'cke_anchor', 'anchor' ).replace( this.fakeObj ); 1199 1200 delete this._.selectedElement; 1201 } 1202 }, 1203 onLoad : function() 1204 { 1205 if ( editor.config.linkUploadTab == false ) 1206 this.hidePage( 'upload' ); //Hide Upload tab. 1207 1208 if ( editor.config.linkShowAdvancedTab == false ) 1209 this.hidePage( 'advanced' ); //Hide Advanded tab. 1210 1211 if ( editor.config.linkBrowseServer == false ) 1212 this.getContentElement( 'info', 'browse' ).getElement().hide(); 1213 1214 if ( editor.config.linkShowTargetTab == false ) 1215 this.hidePage( 'target' ); //Hide Target tab. 1216 1217 } 1218 }; 1219 } ); 1220