+++ /dev/null
-/*\r
-Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
-For licensing, see LICENSE.html or http://ckeditor.com/license\r
-*/\r
-\r
-/**\r
- * @file Clipboard support\r
- */\r
-\r
-(function()\r
-{\r
- // Tries to execute any of the paste, cut or copy commands in IE. Returns a\r
- // boolean indicating that the operation succeeded.\r
- var execIECommand = function( editor, command )\r
- {\r
- var doc = editor.document,\r
- body = doc.getBody();\r
-\r
- var enabled = 0;\r
- var onExec = function()\r
- {\r
- enabled = 1;\r
- };\r
-\r
- // The following seems to be the only reliable way to detect that\r
- // clipboard commands are enabled in IE. It will fire the\r
- // onpaste/oncut/oncopy events only if the security settings allowed\r
- // the command to execute.\r
- body.on( command, onExec );\r
-\r
- // IE6/7: document.execCommand has problem to paste into positioned element.\r
- ( CKEDITOR.env.version > 7 ? doc.$ : doc.$.selection.createRange() ) [ 'execCommand' ]( command );\r
-\r
- body.removeListener( command, onExec );\r
-\r
- return enabled;\r
- };\r
-\r
- // Attempts to execute the Cut and Copy operations.\r
- var tryToCutCopy =\r
- CKEDITOR.env.ie ?\r
- function( editor, type )\r
- {\r
- return execIECommand( editor, type );\r
- }\r
- : // !IE.\r
- function( editor, type )\r
- {\r
- try\r
- {\r
- // Other browsers throw an error if the command is disabled.\r
- return editor.document.$.execCommand( type, false, null );\r
- }\r
- catch( e )\r
- {\r
- return false;\r
- }\r
- };\r
-\r
- // A class that represents one of the cut or copy commands.\r
- var cutCopyCmd = function( type )\r
- {\r
- this.type = type;\r
- this.canUndo = this.type == 'cut'; // We can't undo copy to clipboard.\r
- this.startDisabled = true;\r
- };\r
-\r
- cutCopyCmd.prototype =\r
- {\r
- exec : function( editor, data )\r
- {\r
- this.type == 'cut' && fixCut( editor );\r
-\r
- var success = tryToCutCopy( editor, this.type );\r
-\r
- if ( !success )\r
- alert( editor.lang.clipboard[ this.type + 'Error' ] ); // Show cutError or copyError.\r
-\r
- return success;\r
- }\r
- };\r
-\r
- // Paste command.\r
- var pasteCmd =\r
- {\r
- canUndo : false,\r
-\r
- exec :\r
- CKEDITOR.env.ie ?\r
- function( editor )\r
- {\r
- // Prevent IE from pasting at the begining of the document.\r
- editor.focus();\r
-\r
- if ( !editor.document.getBody().fire( 'beforepaste' )\r
- && !execIECommand( editor, 'paste' ) )\r
- {\r
- editor.fire( 'pasteDialog' );\r
- return false;\r
- }\r
- }\r
- :\r
- function( editor )\r
- {\r
- try\r
- {\r
- if ( !editor.document.getBody().fire( 'beforepaste' )\r
- && !editor.document.$.execCommand( 'Paste', false, null ) )\r
- {\r
- throw 0;\r
- }\r
- }\r
- catch ( e )\r
- {\r
- setTimeout( function()\r
- {\r
- editor.fire( 'pasteDialog' );\r
- }, 0 );\r
- return false;\r
- }\r
- }\r
- };\r
-\r
- // Listens for some clipboard related keystrokes, so they get customized.\r
- var onKey = function( event )\r
- {\r
- if ( this.mode != 'wysiwyg' )\r
- return;\r
-\r
- switch ( event.data.keyCode )\r
- {\r
- // Paste\r
- case CKEDITOR.CTRL + 86 : // CTRL+V\r
- case CKEDITOR.SHIFT + 45 : // SHIFT+INS\r
-\r
- var body = this.document.getBody();\r
-\r
- // Simulate 'beforepaste' event for all none-IEs.\r
- if ( !CKEDITOR.env.ie && body.fire( 'beforepaste' ) )\r
- event.cancel();\r
- // Simulate 'paste' event for Opera/Firefox2.\r
- else if ( CKEDITOR.env.opera\r
- || CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )\r
- body.fire( 'paste' );\r
- return;\r
-\r
- // Cut\r
- case CKEDITOR.CTRL + 88 : // CTRL+X\r
- case CKEDITOR.SHIFT + 46 : // SHIFT+DEL\r
-\r
- // Save Undo snapshot.\r
- var editor = this;\r
- this.fire( 'saveSnapshot' ); // Save before paste\r
- setTimeout( function()\r
- {\r
- editor.fire( 'saveSnapshot' ); // Save after paste\r
- }, 0 );\r
- }\r
- };\r
-\r
- function cancel( evt ) { evt.cancel(); }\r
-\r
- // Allow to peek clipboard content by redirecting the\r
- // pasting content into a temporary bin and grab the content of it.\r
- function getClipboardData( evt, mode, callback )\r
- {\r
- var doc = this.document;\r
-\r
- // Avoid recursions on 'paste' event or consequent paste too fast. (#5730)\r
- if ( doc.getById( 'cke_pastebin' ) )\r
- return;\r
-\r
- // If the browser supports it, get the data directly\r
- if ( mode == 'text' && evt.data && evt.data.$.clipboardData )\r
- {\r
- // evt.data.$.clipboardData.types contains all the flavours in Mac's Safari, but not on windows.\r
- var plain = evt.data.$.clipboardData.getData( 'text/plain' );\r
- if ( plain )\r
- {\r
- evt.data.preventDefault();\r
- callback( plain );\r
- return;\r
- }\r
- }\r
-\r
- var sel = this.getSelection(),\r
- range = new CKEDITOR.dom.range( doc );\r
-\r
- // Create container to paste into\r
- var pastebin = new CKEDITOR.dom.element( mode == 'text' ? 'textarea' : CKEDITOR.env.webkit ? 'body' : 'div', doc );\r
- pastebin.setAttribute( 'id', 'cke_pastebin' );\r
- // Safari requires a filler node inside the div to have the content pasted into it. (#4882)\r
- CKEDITOR.env.webkit && pastebin.append( doc.createText( '\xa0' ) );\r
- doc.getBody().append( pastebin );\r
-\r
- pastebin.setStyles(\r
- {\r
- position : 'absolute',\r
- // Position the bin exactly at the position of the selected element\r
- // to avoid any subsequent document scroll.\r
- top : sel.getStartElement().getDocumentPosition().y + 'px',\r
- width : '1px',\r
- height : '1px',\r
- overflow : 'hidden'\r
- });\r
-\r
- // It's definitely a better user experience if we make the paste-bin pretty unnoticed\r
- // by pulling it off the screen.\r
- pastebin.setStyle( this.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-1000px' );\r
-\r
- var bms = sel.createBookmarks();\r
-\r
- this.on( 'selectionChange', cancel, null, null, 0 );\r
-\r
- // Turn off design mode temporarily before give focus to the paste bin.\r
- if ( mode == 'text' )\r
- pastebin.$.focus();\r
- else\r
- {\r
- range.setStartAt( pastebin, CKEDITOR.POSITION_AFTER_START );\r
- range.setEndAt( pastebin, CKEDITOR.POSITION_BEFORE_END );\r
- range.select( true );\r
- }\r
-\r
- var editor = this;\r
- // Wait a while and grab the pasted contents\r
- window.setTimeout( function()\r
- {\r
- mode == 'text' && CKEDITOR.env.gecko && editor.focusGrabber.focus();\r
- pastebin.remove();\r
- editor.removeListener( 'selectionChange', cancel );\r
-\r
- // Grab the HTML contents.\r
- // We need to look for a apple style wrapper on webkit it also adds\r
- // a div wrapper if you copy/paste the body of the editor.\r
- // Remove hidden div and restore selection.\r
- var bogusSpan;\r
- pastebin = ( CKEDITOR.env.webkit\r
- && ( bogusSpan = pastebin.getFirst() )\r
- && ( bogusSpan.is && bogusSpan.hasClass( 'Apple-style-span' ) ) ?\r
- bogusSpan : pastebin );\r
-\r
- sel.selectBookmarks( bms );\r
- callback( pastebin[ 'get' + ( mode == 'text' ? 'Value' : 'Html' ) ]() );\r
- }, 0 );\r
- }\r
-\r
- // Cutting off control type element in IE standards breaks the selection entirely. (#4881)\r
- function fixCut( editor )\r
- {\r
- if ( !CKEDITOR.env.ie || CKEDITOR.env.quirks )\r
- return;\r
-\r
- var sel = editor.getSelection();\r
- var control;\r
- if( ( sel.getType() == CKEDITOR.SELECTION_ELEMENT ) && ( control = sel.getSelectedElement() ) )\r
- {\r
- var range = sel.getRanges()[ 0 ];\r
- var dummy = editor.document.createText( '' );\r
- dummy.insertBefore( control );\r
- range.setStartBefore( dummy );\r
- range.setEndAfter( control );\r
- sel.selectRanges( [ range ] );\r
-\r
- // Clear up the fix if the paste wasn't succeeded.\r
- setTimeout( function()\r
- {\r
- // Element still online?\r
- if ( control.getParent() )\r
- {\r
- dummy.remove();\r
- sel.selectElement( control );\r
- }\r
- }, 0 );\r
- }\r
- }\r
-\r
- var depressBeforeEvent;\r
- function stateFromNamedCommand( command, editor )\r
- {\r
- // IE Bug: queryCommandEnabled('paste') fires also 'beforepaste(copy/cut)',\r
- // guard to distinguish from the ordinary sources( either\r
- // keyboard paste or execCommand ) (#4874).\r
- CKEDITOR.env.ie && ( depressBeforeEvent = 1 );\r
-\r
- var retval = CKEDITOR.TRISTATE_OFF;\r
- try { retval = editor.document.$.queryCommandEnabled( command ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED; }catch( er ){}\r
-\r
- depressBeforeEvent = 0;\r
- return retval;\r
- }\r
-\r
- var inReadOnly;\r
- function setToolbarStates()\r
- {\r
- if ( this.mode != 'wysiwyg' )\r
- return;\r
-\r
- this.getCommand( 'cut' ).setState( inReadOnly ? CKEDITOR.TRISTATE_DISABLED : stateFromNamedCommand( 'Cut', this ) );\r
- this.getCommand( 'copy' ).setState( stateFromNamedCommand( 'Copy', this ) );\r
- var pasteState = inReadOnly ? CKEDITOR.TRISTATE_DISABLED :\r
- CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste', this );\r
- this.fire( 'pasteState', pasteState );\r
- }\r
-\r
- // Register the plugin.\r
- CKEDITOR.plugins.add( 'clipboard',\r
- {\r
- requires : [ 'dialog', 'htmldataprocessor' ],\r
- init : function( editor )\r
- {\r
- // Inserts processed data into the editor at the end of the\r
- // events chain.\r
- editor.on( 'paste', function( evt )\r
- {\r
- var data = evt.data;\r
- if ( data[ 'html' ] )\r
- editor.insertHtml( data[ 'html' ] );\r
- else if ( data[ 'text' ] )\r
- editor.insertText( data[ 'text' ] );\r
-\r
- setTimeout( function () { editor.fire( 'afterPaste' ); }, 0 );\r
-\r
- }, null, null, 1000 );\r
-\r
- editor.on( 'pasteDialog', function( evt )\r
- {\r
- setTimeout( function()\r
- {\r
- // Open default paste dialog.\r
- editor.openDialog( 'paste' );\r
- }, 0 );\r
- });\r
-\r
- editor.on( 'pasteState', function( evt )\r
- {\r
- editor.getCommand( 'paste' ).setState( evt.data );\r
- });\r
-\r
- function addButtonCommand( buttonName, commandName, command, ctxMenuOrder )\r
- {\r
- var lang = editor.lang[ commandName ];\r
-\r
- editor.addCommand( commandName, command );\r
- editor.ui.addButton( buttonName,\r
- {\r
- label : lang,\r
- command : commandName\r
- });\r
-\r
- // If the "menu" plugin is loaded, register the menu item.\r
- if ( editor.addMenuItems )\r
- {\r
- editor.addMenuItem( commandName,\r
- {\r
- label : lang,\r
- command : commandName,\r
- group : 'clipboard',\r
- order : ctxMenuOrder\r
- });\r
- }\r
- }\r
-\r
- addButtonCommand( 'Cut', 'cut', new cutCopyCmd( 'cut' ), 1 );\r
- addButtonCommand( 'Copy', 'copy', new cutCopyCmd( 'copy' ), 4 );\r
- addButtonCommand( 'Paste', 'paste', pasteCmd, 8 );\r
-\r
- CKEDITOR.dialog.add( 'paste', CKEDITOR.getUrl( this.path + 'dialogs/paste.js' ) );\r
-\r
- editor.on( 'key', onKey, editor );\r
-\r
- // We'll be catching all pasted content in one line, regardless of whether the\r
- // it's introduced by a document command execution (e.g. toolbar buttons) or\r
- // user paste behaviors. (e.g. Ctrl-V)\r
- editor.on( 'contentDom', function()\r
- {\r
- var body = editor.document.getBody();\r
- body.on( CKEDITOR.env.webkit ? 'paste' : 'beforepaste', function( evt )\r
- {\r
- if ( depressBeforeEvent )\r
- return;\r
-\r
- // Fire 'beforePaste' event so clipboard flavor get customized\r
- // by other plugins.\r
- var eventData = { mode : 'html' };\r
- editor.fire( 'beforePaste', eventData );\r
-\r
- getClipboardData.call( editor, evt, eventData.mode, function ( data )\r
- {\r
- // The very last guard to make sure the\r
- // paste has successfully happened.\r
- if ( !( data = CKEDITOR.tools.trim( data.replace( /<span[^>]+data-cke-bookmark[^<]*?<\/span>/ig,'' ) ) ) )\r
- return;\r
-\r
- var dataTransfer = {};\r
- dataTransfer[ eventData.mode ] = data;\r
- editor.fire( 'paste', dataTransfer );\r
- } );\r
- });\r
-\r
- // Dismiss the (wrong) 'beforepaste' event fired on context menu open. (#7953)\r
- body.on( 'contextmenu', function()\r
- {\r
- depressBeforeEvent = 1;\r
- setTimeout( function() { depressBeforeEvent = 0; }, 10 );\r
- });\r
-\r
- body.on( 'beforecut', function() { !depressBeforeEvent && fixCut( editor ); } );\r
-\r
- body.on( 'mouseup', function(){ setTimeout( function(){ setToolbarStates.call( editor ); }, 0 ); }, editor );\r
- body.on( 'keyup', setToolbarStates, editor );\r
- });\r
-\r
- // For improved performance, we're checking the readOnly state on selectionChange instead of hooking a key event for that.\r
- editor.on( 'selectionChange', function( evt )\r
- {\r
- inReadOnly = evt.data.selection.getRanges()[ 0 ].checkReadOnly();\r
- setToolbarStates.call( editor );\r
- });\r
-\r
- // If the "contextmenu" plugin is loaded, register the listeners.\r
- if ( editor.contextMenu )\r
- {\r
- editor.contextMenu.addListener( function( element, selection )\r
- {\r
- var readOnly = selection.getRanges()[ 0 ].checkReadOnly();\r
- return {\r
- cut : !readOnly && stateFromNamedCommand( 'Cut', editor ),\r
- copy : stateFromNamedCommand( 'Copy', editor ),\r
- paste : !readOnly && ( CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste', editor ) )\r
- };\r
- });\r
- }\r
- }\r
- });\r
-})();\r
-\r
-/**\r
- * Fired when a clipboard operation is about to be taken into the editor.\r
- * Listeners can manipulate the data to be pasted before having it effectively\r
- * inserted into the document.\r
- * @name CKEDITOR.editor#paste\r
- * @since 3.1\r
- * @event\r
- * @param {String} [data.html] The HTML data to be pasted. If not available, e.data.text will be defined.\r
- * @param {String} [data.text] The plain text data to be pasted, available when plain text operations are to used. If not available, e.data.html will be defined.\r
- */\r
-\r
-/**\r
- * Internal event to open the Paste dialog\r
- * @name CKEDITOR.editor#pasteDialog\r
- * @event\r
- */\r