Skip to content

Commit

Permalink
Merge branch 't/16705'
Browse files Browse the repository at this point in the history
  • Loading branch information
Comandeer committed Dec 30, 2016
2 parents 4b2c8f8 + 5f1549b commit b941fec
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -14,6 +14,7 @@ Fixed Issues:
* [#10373](http://dev.ckeditor.com/ticket/10373): Fixed: Context menu items can be dragged into the editor.
* [#16728](http://dev.ckeditor.com/ticket/16728): [IE] Fixed: [Copy Formatting](http://ckeditor.com/addon/copyformatting) breaks editor in Quirks Mode.
* [#16753](http://dev.ckeditor.com/ticket/16753): Fixed: `element.setSize` sets wrong editor's dimensions if border's width is in fraction of pixels.
* [#16705](http://dev.ckeditor.com/ticket/16705): [Firefox] Fixed: Unable to paste images as Base64 strings when using [Clipboard](http://ckeditor.com/addon/clipboard).

## CKEditor 4.6.1

Expand Down
44 changes: 44 additions & 0 deletions plugins/clipboard/plugin.js
Expand Up @@ -145,6 +145,50 @@

CKEDITOR.dialog.add( 'paste', CKEDITOR.getUrl( this.path + 'dialogs/paste.js' ) );

// Convert image file (if present) to base64 string for Firefox. Do it as the first
// step as the conversion is asynchronous and should hold all further paste processing.
if ( CKEDITOR.env.gecko ) {
var supportedImageTypes = [ 'image/png', 'image/jpeg', 'image/gif' ],
latestId;

editor.on( 'paste', function( evt ) {
var dataObj = evt.data,
data = dataObj.dataValue,
dataTransfer = dataObj.dataTransfer;

// If data empty check for image content inside data transfer. #16705
if ( !data && dataObj.method == 'paste' && dataTransfer && dataTransfer.getFilesCount() == 1 && latestId != dataTransfer.id ) {
var file = dataTransfer.getFile( 0 );

if ( CKEDITOR.tools.indexOf( supportedImageTypes, file.type ) != -1 ) {
var fileReader = new FileReader();

// Convert image file to img tag with base64 image.
fileReader.addEventListener( 'load', function() {
evt.data.dataValue = '<img src="' + fileReader.result + '" />';
editor.fire( 'paste', evt.data );
}, false );

// Proceed with normal flow if reading file was aborted.
fileReader.addEventListener( 'abort', function() {
editor.fire( 'paste', evt.data );
}, false );

// Proceed with normal flow if reading file failed.
fileReader.addEventListener( 'error', function() {
editor.fire( 'paste', evt.data );
}, false );

fileReader.readAsDataURL( file );

latestId = dataObj.dataTransfer.id;

evt.stop();
}
}
}, null, null, 1 );
}

editor.on( 'paste', function( evt ) {
// Init `dataTransfer` if `paste` event was fired without it, so it will be always available.
if ( !evt.data.dataTransfer ) {
Expand Down
11 changes: 11 additions & 0 deletions tests/plugins/clipboard/manual/pasteimage.html
@@ -0,0 +1,11 @@
<div id="editor">
<p>Paste image from clipboard here:</p>
</div>

<script>
if ( !CKEDITOR.env.gecko ) {
bender.ignore();
}

CKEDITOR.replace( 'editor' );
</script>
10 changes: 10 additions & 0 deletions tests/plugins/clipboard/manual/pasteimage.md
@@ -0,0 +1,10 @@
@bender-ui: collapsed
@bender-tags: 4.6.2, tc, clipboard
@bender-ckeditor-plugins: wysiwygarea, toolbar, undo, basicstyles, image, clipboard, sourcearea

## Scenario:

* Paste image from your clipboard into the editor.

**Expected**: Image is pasted as base64 encoded file.

158 changes: 158 additions & 0 deletions tests/plugins/clipboard/pasteimage.js
@@ -0,0 +1,158 @@
/* bender-tags: editor,unit */
/* bender-ckeditor-plugins: clipboard */

( function() {
'use strict';

// Mock FileReader.
( function() {
var fileMockBase64 = ';base64,fileMockBase64=',
fileMockType,
readResultMock;

function FileReaderMock() {
this.listeners = {};
}

// Any MIME type.
FileReaderMock.setFileMockType = function( type ) {
fileMockType = type;
};

// Result can be: load, abort, error.
FileReaderMock.setReadResult = function( readResult ) {
readResultMock = readResult;
if ( !readResultMock ) {
readResultMock = 'load';
}
};

FileReaderMock.prototype.addEventListener = function( eventName, callback ) {
this.listeners[ eventName ] = callback;
};

FileReaderMock.prototype.readAsDataURL = function() {
CKEDITOR.tools.setTimeout( function() {
this.result = ( readResultMock == 'load' ? 'data:' + fileMockType + fileMockBase64 : null );

if ( this.listeners[ readResultMock ] ) {
this.listeners[ readResultMock ]();
}
}, 15, this );
};

/* jshint ignore:start */
FileReader = FileReaderMock;
/* jshint ignore:end */
} )();

// Mock paste file from clipboard.
function mockPasteFile( editor, type ) {
var nativeData = bender.tools.mockNativeDataTransfer(),
dataTransfer = new CKEDITOR.plugins.clipboard.dataTransfer( nativeData );

nativeData.files.push( {
name: 'mock.file',
type: type
} );

dataTransfer.cacheData();

editor.fire( 'paste', {
dataTransfer: dataTransfer,
dataValue: '',
method: 'paste',
type: 'auto'
} );
}


bender.editor = {
config: {
allowedContent: true
}
};

bender.test( {
setUp: function() {
if ( !CKEDITOR.env.gecko ) {
assert.ignore();
}
FileReader.setFileMockType();
FileReader.setReadResult();
this.editor.focus();
},

'test paste .png from clipboard': function() {
FileReader.setFileMockType( 'image/png' );
FileReader.setReadResult( 'load' );

bender.tools.selection.setWithHtml( this.editor, '<p>Paste image here: {}</p>' );
this.assertPaste( 'image/png',
'<p>Paste image here: <img data-cke-saved-src="data:image/png;base64,fileMockBase64=" src="data:image/png;base64,fileMockBase64=" />^@</p>' );
},

'test paste .jpeg from clipboard': function() {
FileReader.setFileMockType( 'image/jpeg' );
FileReader.setReadResult( 'load' );

bender.tools.selection.setWithHtml( this.editor, '<p>Paste image here: {}</p>' );
this.assertPaste( 'image/jpeg',
'<p>Paste image here: <img data-cke-saved-src="data:image/jpeg;base64,fileMockBase64=" src="data:image/jpeg;base64,fileMockBase64=" />^@</p>' );
},

'test paste .gif from clipboard': function() {
FileReader.setFileMockType( 'image/gif' );
FileReader.setReadResult( 'load' );

bender.tools.selection.setWithHtml( this.editor, '<p>Paste image here: {}</p>' );
this.assertPaste( 'image/gif',
'<p>Paste image here: <img data-cke-saved-src="data:image/gif;base64,fileMockBase64=" src="data:image/gif;base64,fileMockBase64=" />^@</p>' );
},

'test unsupported file type': function() {
FileReader.setFileMockType( 'application/pdf' );
FileReader.setReadResult( 'load' );

bender.tools.selection.setWithHtml( this.editor, '<p>Paste image here: {}</p>' );
this.assertPaste( 'application/pdf',
'<p>Paste image here: ^@</p>' );
},

'test aborted paste': function() {
FileReader.setFileMockType( 'image/png' );
FileReader.setReadResult( 'abort' );

bender.tools.selection.setWithHtml( this.editor, '<p>Paste image here: {}</p>' );
this.assertPaste( 'image/png',
'<p>Paste image here: ^@</p>' );
},

'test failed paste': function() {
FileReader.setFileMockType( 'image/png' );
FileReader.setReadResult( 'error' );

bender.tools.selection.setWithHtml( this.editor, '<p>Paste image here: {}</p>' );
this.assertPaste( 'image/png',
'<p>Paste image here: ^@</p>' );
},

assertPaste: function( type, expected ) {
this.editor.once( 'paste', function() {
resume( function() {
assert.isInnerHtmlMatching( expected, bender.tools.selection.getWithHtml( this.editor ), {
noTempElements: true,
fixStyles: true,
compareSelection: true,
normalizeSelection: true
} );
} );
}, this, null, 9999 );

mockPasteFile( this.editor, type );

wait();
}
} );

} )();

0 comments on commit b941fec

Please sign in to comment.