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 null;
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 null;
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 	linkShowAdvancedTab : true,
187 	linkShowTargetTab : true
188 } );
189