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.plugins.add( 'link', 7 { 8 init : function( editor ) 9 { 10 // Add the link and unlink buttons. 11 editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link' ) ); 12 editor.addCommand( 'anchor', new CKEDITOR.dialogCommand( 'anchor' ) ); 13 editor.addCommand( 'unlink', new CKEDITOR.unlinkCommand() ); 14 editor.ui.addButton( 'Link', 15 { 16 label : editor.lang.link.toolbar, 17 command : 'link' 18 } ); 19 editor.ui.addButton( 'Unlink', 20 { 21 label : editor.lang.unlink, 22 command : 'unlink' 23 } ); 24 editor.ui.addButton( 'Anchor', 25 { 26 label : editor.lang.anchor.toolbar, 27 command : 'anchor' 28 } ); 29 CKEDITOR.dialog.add( 'link', this.path + 'dialogs/link.js' ); 30 CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' ); 31 32 // Add the CSS styles for anchor placeholders. 33 editor.addCss( 34 'img.cke_anchor' + 35 '{' + 36 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' + 37 'background-position: center center;' + 38 'background-repeat: no-repeat;' + 39 'border: 1px solid #a9a9a9;' + 40 'width: 18px;' + 41 'height: 18px;' + 42 '}\n' + 43 'a.cke_anchor' + 44 '{' + 45 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' + 46 'background-position: 0 center;' + 47 'background-repeat: no-repeat;' + 48 'border: 1px solid #a9a9a9;' + 49 'padding-left: 18px;' + 50 '}' 51 ); 52 53 // Register selection change handler for the unlink button. 54 editor.on( 'selectionChange', function( evt ) 55 { 56 /* 57 * Despite our initial hope, document.queryCommandEnabled() does not work 58 * for this in Firefox. So we must detect the state by element paths. 59 */ 60 var command = editor.getCommand( 'unlink' ), 61 element = evt.data.path.lastElement.getAscendant( 'a', true ); 62 if ( element && element.getName() == 'a' && element.getAttribute( 'href' ) ) 63 command.setState( CKEDITOR.TRISTATE_OFF ); 64 else 65 command.setState( CKEDITOR.TRISTATE_DISABLED ); 66 } ); 67 68 // If the "menu" plugin is loaded, register the menu items. 69 if ( editor.addMenuItems ) 70 { 71 editor.addMenuItems( 72 { 73 anchor : 74 { 75 label : editor.lang.anchor.menu, 76 command : 'anchor', 77 group : 'anchor' 78 }, 79 80 link : 81 { 82 label : editor.lang.link.menu, 83 command : 'link', 84 group : 'link', 85 order : 1 86 }, 87 88 unlink : 89 { 90 label : editor.lang.unlink, 91 command : 'unlink', 92 group : 'link', 93 order : 5 94 } 95 }); 96 } 97 98 // If the "contextmenu" plugin is loaded, register the listeners. 99 if ( editor.contextMenu ) 100 { 101 editor.contextMenu.addListener( function( element, selection ) 102 { 103 if ( !element ) 104 return; 105 106 var isAnchor = ( element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'anchor' ); 107 108 if ( !isAnchor ) 109 { 110 if ( !( element = element.getAscendant( 'a', true ) ) ) 111 return; 112 113 isAnchor = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ); 114 } 115 116 return isAnchor ? 117 { anchor : CKEDITOR.TRISTATE_OFF } : 118 { link : CKEDITOR.TRISTATE_OFF, unlink : CKEDITOR.TRISTATE_OFF }; 119 }); 120 } 121 }, 122 123 afterInit : function( editor ) 124 { 125 // Register a filter to displaying placeholders after mode change. 126 127 var dataProcessor = editor.dataProcessor, 128 dataFilter = dataProcessor && dataProcessor.dataFilter; 129 130 if ( dataFilter ) 131 { 132 dataFilter.addRules( 133 { 134 elements : 135 { 136 a : function( element ) 137 { 138 var attributes = element.attributes; 139 if ( attributes.name && !attributes.href ) 140 return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' ); 141 } 142 } 143 }); 144 } 145 }, 146 147 requires : [ 'fakeobjects' ] 148 } ); 149 150 CKEDITOR.unlinkCommand = function(){}; 151 CKEDITOR.unlinkCommand.prototype = 152 { 153 /** @ignore */ 154 exec : function( editor ) 155 { 156 /* 157 * execCommand( 'unlink', ... ) in Firefox leaves behind <span> tags at where 158 * the <a> was, so again we have to remove the link ourselves. (See #430) 159 * 160 * TODO: Use the style system when it's complete. Let's use execCommand() 161 * as a stopgap solution for now. 162 */ 163 var selection = editor.getSelection(), 164 bookmarks = selection.createBookmarks(), 165 ranges = selection.getRanges(), 166 rangeRoot, 167 element; 168 169 for ( var i = 0 ; i < ranges.length ; i++ ) 170 { 171 rangeRoot = ranges[i].getCommonAncestor( true ); 172 element = rangeRoot.getAscendant( 'a', true ); 173 if ( !element ) 174 continue; 175 ranges[i].selectNodeContents( element ); 176 } 177 178 selection.selectRanges( ranges ); 179 editor.document.$.execCommand( 'unlink', false, null ); 180 selection.selectBookmarks( bookmarks ); 181 } 182 }; 183 184 CKEDITOR.tools.extend( CKEDITOR.config, 185 { 186 linkUploadTab : true, 187 linkBrowseServer : true, 188 linkUploadAction : 'nowhere.php', 189 linkShowAdvancedTab : true, 190 linkShowTargetTab : true 191 } ); 192