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 /**
  7  * @file Clipboard support
  8  */
  9
 10 (function()
 11 {
 12 	// Tries to execute any of the paste, cut or copy commands in IE. Returns a
 13 	// boolean indicating that the operation succeeded.
 14 	var execIECommand = function( editor, command )
 15 	{
 16 		var doc = editor.document,
 17 			body = doc.getBody();
 18
 19 		var	enabled = false;
 20 		var onExec = function()
 21 		{
 22 			enabled = true;
 23 		};
 24
 25 		// The following seems to be the only reliable way to detect that
 26 		// clipboard commands are enabled in IE. It will fire the
 27 		// onpaste/oncut/oncopy events only if the security settings allowed
 28 		// the command to execute.
 29 		body.on( command, onExec );
 30
 31 		doc.$.execCommand( command );
 32
 33 		body.removeListener( command, onExec );
 34
 35 		return enabled;
 36 	};
 37
 38 	// Attempts to execute the Cut and Copy operations.
 39 	var tryToCutCopy =
 40 		CKEDITOR.env.ie ?
 41 			function( editor, type )
 42 			{
 43 				return execIECommand( editor, type );
 44 			}
 45 		:		// !IE.
 46 			function( editor, type )
 47 			{
 48 				try
 49 				{
 50 					// Other browsers throw an error if the command is disabled.
 51 					return editor.document.$.execCommand( type );
 52 				}
 53 				catch( e )
 54 				{
 55 					return false;
 56 				}
 57 			};
 58
 59 	// A class that represents one of the cut or copy commands.
 60 	var cutCopyCmd = function( type )
 61 	{
 62 		this.type = type;
 63 		this.canUndo = ( this.type == 'cut' );		// We can't undo copy to clipboard.
 64 	};
 65
 66 	cutCopyCmd.prototype =
 67 	{
 68 		exec : function( editor, data )
 69 		{
 70 			var success = tryToCutCopy( editor, this.type );
 71
 72 			if ( !success )
 73 				alert( editor.lang.clipboard[ this.type + 'Error' ] );		// Show cutError or copyError.
 74
 75 			return success;
 76 		}
 77 	};
 78
 79 	// Paste command.
 80 	var pasteCmd =
 81 		CKEDITOR.env.ie ?
 82 			{
 83 				exec : function( editor, data )
 84 				{
 85 					// Prevent IE from pasting at the begining of the document.
 86 					editor.focus();
 87
 88 					if ( !editor.fire( 'beforePaste' )
 89 						&& !execIECommand( editor, 'paste' ) )
 90 					{
 91 							editor.openDialog( 'paste' );
 92 					}
 93 				}
 94 			}
 95 		:
 96 			{
 97 				exec : function( editor )
 98 				{
 99 					try
100 					{
101 						if ( !editor.fire( 'beforePaste' )
102 							&& !editor.document.$.execCommand( 'Paste', false, null ) )
103 						{
104 							throw 0;
105 						}
106 					}
107 					catch ( e )
108 					{
109 						// Open the paste dialog.
110 						editor.openDialog( 'paste' );
111 					}
112 				}
113 			};
114
115 	// Listens for some clipboard related keystrokes, so they get customized.
116 	var onKey = function( event )
117 	{
118 		switch ( event.data.keyCode )
119 		{
120 			// Paste
121 			case CKEDITOR.CTRL + 86 :		// CTRL+V
122 			case CKEDITOR.SHIFT + 45 :		// SHIFT+INS
123
124 				var editor = this;
125 				editor.fire( 'saveSnapshot' );		// Save before paste
126
127 				if ( editor.fire( 'beforePaste' ) )
128 					event.cancel();
129
130 				setTimeout( function()
131 					{
132 						editor.fire( 'saveSnapshot' );		// Save after paste
133 					}, 0 );
134 				return;
135
136 			// Cut
137 			case CKEDITOR.CTRL + 88 :		// CTRL+X
138 			case CKEDITOR.SHIFT + 46 :		// SHIFT+DEL
139
140 				// Save Undo snapshot.
141 				editor = this;
142 				editor.fire( 'saveSnapshot' );		// Save before paste
143 				setTimeout( function()
144 					{
145 						editor.fire( 'saveSnapshot' );		// Save after paste
146 					}, 0 );
147 		}
148 	};
149
150 	// Register the plugin.
151 	CKEDITOR.plugins.add( 'clipboard',
152 		{
153 			init : function( editor )
154 			{
155 				function addButtonCommand( buttonName, commandName, command, ctxMenuOrder )
156 				{
157 					var lang = editor.lang[ commandName ];
158
159 					editor.addCommand( commandName, command );
160 					editor.ui.addButton( buttonName,
161 						{
162 							label : lang,
163 							command : commandName
164 						});
165
166 					// If the "menu" plugin is loaded, register the menu item.
167 					if ( editor.addMenuItems )
168 					{
169 						editor.addMenuItem( commandName,
170 							{
171 								label : lang,
172 								command : commandName,
173 								group : 'clipboard',
174 								order : ctxMenuOrder
175 							});
176 					}
177 				}
178
179 				addButtonCommand( 'Cut', 'cut', new cutCopyCmd( 'cut' ), 1 );
180 				addButtonCommand( 'Copy', 'copy', new cutCopyCmd( 'copy' ), 4 );
181 				addButtonCommand( 'Paste', 'paste', pasteCmd, 8 );
182
183 				CKEDITOR.dialog.add( 'paste', CKEDITOR.getUrl( this.path + 'dialogs/paste.js' ) );
184
185 				editor.on( 'key', onKey, editor );
186
187 				// If the "contextmenu" plugin is loaded, register the listeners.
188 				if ( editor.contextMenu )
189 				{
190 					function stateFromNamedCommand( command )
191 					{
192 						return editor.document.$.queryCommandEnabled( command ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
193 					}
194
195 					editor.contextMenu.addListener( function()
196 						{
197 							return {
198 								cut : stateFromNamedCommand( 'Cut' ),
199
200 								// Browser bug: 'Cut' has the correct states for both Copy and Cut.
201 								copy : stateFromNamedCommand( 'Cut' ),
202 								paste : CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste' )
203 							};
204 						});
205 				}
206 			}
207 		});
208 })();
209