      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