aboutsummaryrefslogblamecommitdiff
path: root/sources/plugins/clipboard/dialogs/paste.js
blob: 80ce29f39b732251830cea94799d170952208fde (plain) (tree)





























































































































































































































































                                                                                                                                                                                               
/**
 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

CKEDITOR.dialog.add( 'paste', function( editor ) {
	var lang = editor.lang.clipboard,
		clipboard = CKEDITOR.plugins.clipboard,
		lastDataTransfer;

	function onPasteFrameLoad( win ) {
		var doc = new CKEDITOR.dom.document( win.document ),
			body = doc.getBody(),
			script = doc.getById( 'cke_actscrpt' );

		script && script.remove();

		body.setAttribute( 'contenteditable', true );

		// Forward dataTransfer (#13883).
		body.on( clipboard.mainPasteEvent, function( evt ) {
			var dataTransfer = clipboard.initPasteDataTransfer( evt );

			if ( !lastDataTransfer ) {
				lastDataTransfer = dataTransfer;
			} else
			// For two paste with the same dataTransfer we can use that dataTransfer (two internal pastes are
			// considered as an internal paste).
			if ( dataTransfer != lastDataTransfer ) {
				// If there were two paste with different DataTransfer objects create a new, empty, data transfer
				// and use it (one internal and one external paste are considered as external paste).
				lastDataTransfer = clipboard.initPasteDataTransfer();
			}
		} );

		// IE before version 8 will leave cursor blinking inside the document after
		// editor blurred unless we clean up the selection. (#4716)
		if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) {
			doc.getWindow().on( 'blur', function() {
				doc.$.selection.empty();
			} );
		}

		doc.on( 'keydown', function( e ) {
			var domEvent = e.data,
				key = domEvent.getKeystroke(),
				processed;

			switch ( key ) {
				case 27:
					this.hide();
					processed = 1;
					break;

				case 9:
				case CKEDITOR.SHIFT + 9:
					this.changeFocus( 1 );
					processed = 1;
			}

			processed && domEvent.preventDefault();
		}, this );

		editor.fire( 'ariaWidget', new CKEDITOR.dom.element( win.frameElement ) );

		// Handle pending focus.
		if ( doc.getWindow().getFrame().removeCustomData( 'pendingFocus' ) )
			body.focus();
	}

	// If pasteDialogCommit wasn't canceled by e.g. editor.getClipboardData
	// then fire paste event.
	// Do not use editor#paste, because it would start from beforePaste event.
	editor.on( 'pasteDialogCommit', function( evt ) {
		if ( evt.data )
			editor.fire( 'paste', {
				type: 'auto',
				dataValue: evt.data.dataValue,
				method: 'paste',
				dataTransfer: evt.data.dataTransfer || clipboard.initPasteDataTransfer()
			} );
	}, null, null, 1000 );

	return {
		title: lang.title,

		minWidth: CKEDITOR.env.ie && CKEDITOR.env.quirks ? 370 : 350,
		minHeight: CKEDITOR.env.quirks ? 250 : 245,
		onShow: function() {
			// FIREFOX BUG: Force the browser to render the dialog to make the to-be-
			// inserted iframe editable. (#3366)
			this.parts.dialog.$.offsetHeight;

			this.setupContent();

			// Set dialog title to the custom value (set e.g. in editor.openDialog callback) and reset this value.
			// If custom title not set, use default one.
			this.parts.title.setHtml( this.customTitle || lang.title );
			this.customTitle = null;
		},

		onLoad: function() {
			if ( ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) && editor.lang.dir == 'rtl' )
				this.parts.contents.setStyle( 'overflow', 'hidden' );
		},

		onOk: function() {
			this.commitContent();
		},

		contents: [ {
			id: 'general',
			label: editor.lang.common.generalTab,
			elements: [
				{
					type: 'html',
					id: 'securityMsg',
					html: '<div style="white-space:normal;width:340px">' + lang.securityMsg + '</div>'
				},
				{
					type: 'html',
					id: 'pasteMsg',
					html: '<div style="white-space:normal;width:340px">' + lang.pasteMsg + '</div>'
				},
				{
					type: 'html',
					id: 'editing_area',
					style: 'width:100%;height:100%',
					html: '',
					focus: function() {
						var iframe = this.getInputElement(),
							doc = iframe.getFrameDocument(),
							body = doc.getBody();

						// Frame content may not loaded at the moment.
						if ( !body || body.isReadOnly() )
							iframe.setCustomData( 'pendingFocus', 1 );
						else
							body.focus();
					},
					setup: function() {
						var dialog = this.getDialog();
						var htmlToLoad = '<html dir="' + editor.config.contentsLangDirection + '"' +
							' lang="' + ( editor.config.contentsLanguage || editor.langCode ) + '">' +
							'<head><style>body{margin:3px;height:95%;word-break:break-all;}</style></head><body>' +
							'<script id="cke_actscrpt" type="text/javascript">' +
							'window.parent.CKEDITOR.tools.callFunction(' + CKEDITOR.tools.addFunction( onPasteFrameLoad, dialog ) + ',this);' +
							'</script></body>' +
							'</html>';

						var src =
							CKEDITOR.env.air ?
								'javascript:void(0)' : // jshint ignore:line
							( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ?
								'javascript:void((function(){' + encodeURIComponent( // jshint ignore:line
									'document.open();' +
									'(' + CKEDITOR.tools.fixDomain + ')();' +
									'document.close();'
								) + '})())"'
							: '';

						var iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' +
							' class="cke_pasteframe"' +
							' frameborder="0" ' +
							' allowTransparency="true"' +
							' src="' + src + '"' +
							' aria-label="' + lang.pasteArea + '"' +
							' aria-describedby="' + dialog.getContentElement( 'general', 'pasteMsg' ).domId + '"' +
							'></iframe>' );

						// Reset last data transfer.
						lastDataTransfer = null;

						iframe.on( 'load', function( e ) {
							e.removeListener();

							var doc = iframe.getFrameDocument();
							doc.write( htmlToLoad );

							editor.focusManager.add( doc.getBody() );

							if ( CKEDITOR.env.air )
								onPasteFrameLoad.call( this, doc.getWindow().$ );
						}, dialog );

						iframe.setCustomData( 'dialog', dialog );

						var container = this.getElement();
						container.setHtml( '' );
						container.append( iframe );

						// IE need a redirect on focus to make
						// the cursor blinking inside iframe. (#5461)
						if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
							var focusGrabber = CKEDITOR.dom.element.createFromHtml( '<span tabindex="-1" style="position:absolute" role="presentation"></span>' );
							focusGrabber.on( 'focus', function() {
								// Since fixDomain is called in src attribute,
								// IE needs some slight delay to correctly move focus.
								setTimeout( function() {
									iframe.$.contentWindow.focus();
								} );
							} );
							container.append( focusGrabber );

							// Override focus handler on field.
							this.focus = function() {
								focusGrabber.focus();
								this.fire( 'focus' );
							};
						}

						this.getInputElement = function() {
							return iframe;
						};

						// Force container to scale in IE.
						if ( CKEDITOR.env.ie ) {
							container.setStyle( 'display', 'block' );
							container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
						}
					},
					commit: function() {
						var editor = this.getDialog().getParentEditor(),
							body = this.getInputElement().getFrameDocument().getBody(),
							bogus = body.getBogus(),
							html;
						bogus && bogus.remove();

						// Saving the contents so changes until paste is complete will not take place (#7500)
						html = body.getHtml();

						// Opera needs some time to think about what has happened and what it should do now.
						setTimeout( function() {
							editor.fire( 'pasteDialogCommit', {
								dataValue: html,
								// Avoid error if there was no paste so lastDataTransfer is null.
								dataTransfer: lastDataTransfer || clipboard.initPasteDataTransfer()
							} );
						}, 0 );
					}
				}
			]
		} ]
	};
} );

/**
 * Internal event to pass paste dialog's data to the listeners.
 *
 * @private
 * @event pasteDialogCommit
 * @member CKEDITOR.editor
 * @param {CKEDITOR.editor} editor This editor instance.
 */