From 99692230b17b9d6acfaf497a99cb0cac78f8ed33 Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Wed, 21 Aug 2013 22:00:48 +0100 Subject: [PATCH] Copy-paste data fixes * Assign cut/copy/paste events to the document so that they are triggered when the CE doesn't have real focus e.g. only a FocusableNode is selected * Use clipboardData.setData when available. The key can be stored and retrieved perfectly in text/xcustom but this technique doesn't work in FF or IE * Just use text content for key as this is what is written to the clipboard, so this can be used directly without having to get the content from the pasteTarget. Bug: 48604 Bug: 49396 Change-Id: Ib3702f9441f6ee3fa34ec071f00994dd7e591d99 --- modules/ve/ce/ve.ce.Surface.js | 57 +++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/modules/ve/ce/ve.ce.Surface.js b/modules/ve/ce/ve.ce.Surface.js index cbc5ba1352..25849c46b5 100644 --- a/modules/ve/ce/ve.ce.Surface.js +++ b/modules/ve/ce/ve.ce.Surface.js @@ -63,13 +63,16 @@ ve.ce.Surface = function VeCeSurface( model, surface, options ) { $documentNode.focus(); } ); - this.$.on( { + this.$document.on( { 'cut': ve.bind( this.onCut, this ), 'copy': ve.bind( this.onCopy, this ), - 'paste': ve.bind( this.onPaste, this ), + 'paste': ve.bind( this.onPaste, this ) + } ); + this.$.on( { 'dragover': ve.bind( this.onDocumentDragOver, this ), 'drop': ve.bind( this.onDocumentDrop, this ) } ); + if ( $.browser.msie ) { this.$.on( 'beforepaste', ve.bind( this.onPaste, this ) ); } @@ -590,21 +593,31 @@ ve.ce.Surface.prototype.onCut = function ( e ) { * @method * @param {jQuery.Event} e Copy event */ -ve.ce.Surface.prototype.onCopy = function () { +ve.ce.Surface.prototype.onCopy = function ( e ) { var sel = rangy.getSelection( this.$document[0] ), - $frag = this.$$( sel.getRangeAt(0).cloneContents() ), + $frag = sel.rangeCount ? this.$$( sel.getRangeAt(0).cloneContents() ) : null, slice = this.documentView.model.getSlice( this.model.getSelection() ), - key = ''; + clipboardData = e.originalEvent.clipboardData, + fragText = $frag ? $frag.text() : '', + key = 've-' + fragText.replace( /\s/gm, '' ); // CLone the elements in the slice slice.cloneElements(); - // Create key from text and element names - $frag.contents().each( function () { - key += this.textContent || this.nodeName; - } ); - key = 've-' + key.replace( /\s/gm, '' ); - + // Check we have setData and that it actually works (returns true) + if ( clipboardData && clipboardData.setData && clipboardData.setData( 'text/xcustom', '' ) ) { + // Webkit + e.preventDefault(); + clipboardData.setData( 'text/xcustom', key ); + // As we've disabled the default event we need to set the normal clipboard data + clipboardData.setData( 'text/plain', fragText ); + } else { + if ( window.clipboardData ) { + // IE + e.originalEvent.returnValue = false; + window.clipboardData.setData( 'text/plain', fragText ); + } + } // Set clipboard this.clipboard[key] = slice; }; @@ -615,7 +628,7 @@ ve.ce.Surface.prototype.onCopy = function () { * @method * @param {jQuery.Event} e Paste event */ -ve.ce.Surface.prototype.onPaste = function () { +ve.ce.Surface.prototype.onPaste = function ( e ) { // Prevent pasting until after we are done if ( this.pasting ) { return false; @@ -625,7 +638,10 @@ ve.ce.Surface.prototype.onPaste = function () { var tx, scrollTop, $window = $( ve.Element.getWindow( this.$$.context ) ), view = this, - selection = this.model.getSelection(); + selection = this.model.getSelection(), + clipboardData = e.originalEvent.clipboardData, + eventPasteKey = clipboardData.getData( 'text/xcustom' ) || null, + eventPasteText = clipboardData.getData( 'text/plain' ) || null; this.surfaceObserver.stop( false, true ); @@ -644,11 +660,16 @@ ve.ce.Surface.prototype.onPaste = function () { var pasteData, slice, tx, key = ''; - // Create key from text and element names - view.$pasteTarget.hide().contents().each( function () { - key += this.textContent || this.nodeName; - } ); - key = 've-' + key.replace( /\s/gm, '' ); + if ( eventPasteKey ) { + key = eventPasteKey; + } else { + if ( eventPasteText ) { + key = eventPasteText; + } else { + key = view.$pasteTarget.text(); + } + key = 've-' + key.replace( /\s/gm, '' ); + } // Get linear model from clipboard or create array from unknown pasted content if ( view.clipboard[key] ) {