Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow built-in image paste handling to be disabled (#4874). #4896

Merged
merged 19 commits into from
Sep 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7bf898b
Allow built-in image paste handling to be disabled (#4874).
FlowIT-JIT Sep 20, 2021
d3f0264
Fix incorrect config parameter type and @since version
FlowIT-JIT Sep 20, 2021
f7d7bcc
Add unit test to cover new clipboard_handleImagePasting option.
FlowIT-JIT Sep 22, 2021
b32582f
Add 'bug' to bender-tags
FlowIT-JIT Sep 22, 2021
d78c4b2
Simplify condition - make it more readable
FlowIT-JIT Sep 22, 2021
d517b5d
Simplify manual test for new clipboard_handleImagePasting option.
FlowIT-JIT Sep 22, 2021
6699017
Update documentation for clipboard_handleImagePasting option
FlowIT-JIT Sep 22, 2021
726375a
Skip test for IE and mobile devices
FlowIT-JIT Sep 22, 2021
886d277
Move assertDropImage function to helpers to allow reuse.
FlowIT-JIT Sep 23, 2021
d3892ad
Add unit test verifying image dropping can be suppressed.
FlowIT-JIT Sep 23, 2021
409ebb3
Rename pasteimagedisabled.js to clipboardimagedisabled.js
FlowIT-JIT Sep 23, 2021
1fbf45a
Rename option clipboard_handleImagePasting to clipboard_handleImages.
FlowIT-JIT Sep 23, 2021
b9347ab
Rename option clipboard_handleImagePasting to clipboard_handleImages.
FlowIT-JIT Sep 23, 2021
83a4b46
Add manual test proving clipboard_handleImages prevents image dropping
FlowIT-JIT Sep 23, 2021
0bce4cb
Unit test now tests that a custom image handler plugin receive files.
FlowIT-JIT Sep 24, 2021
00d29f6
Update tests.
Comandeer Sep 26, 2021
7cbccd6
Rename `assertDropImage()` to `assertImageDrop()` and fix code style …
Comandeer Sep 26, 2021
9639ad1
Adjust test's ACF.
Comandeer Sep 26, 2021
06b2af6
Add changelog entries.
Comandeer Sep 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ New Features:
* [#4750](https://github.com/ckeditor/ckeditor4/issues/4750): Added notification for pasting and dropping unsupported file types into the editor.
* [#3433](https://github.com/ckeditor/ckeditor4/issues/3433): Marked required fields in dialogs with asterisk (`*`) symbol.
* [#4374](https://github.com/ckeditor/ckeditor4/issues/4374): Integrated [Maximize](https://ckeditor.com/cke4/addon/maximize) plugin with browser's History API.
* [#4874](https://github.com/ckeditor/ckeditor4/issues/4874): Added the [`config.clipboard_handleImages`](https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html#cfg-clipboard_handleImages) configuration option for enabling and disabling built-in support for pasting and dropping images in the [Clipboard](https://ckeditor.com/cke4/addon/clipboard) plugin. Thanks to [FlowIT-JIT](https://github.com/FlowIT-JIT)!

Fixed Issues:

Expand All @@ -21,6 +22,7 @@ Fixed Issues:
* [#4604](https://github.com/ckeditor/ckeditor4/issues/4604): Fixed: [`CKEDITOR.plugins.clipboard.dataTransfer#getTypes()`](https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_plugins_clipboard_dataTransfer.html#method-getTypes) returns no types.
* [#4597](https://github.com/ckeditor/ckeditor4/issues/4597): Fixed: Incorrect color conversion for HSL/HSLA values in [`CKEDITOR.tools.color`](https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_tools_color.html).
* [#4596](https://github.com/ckeditor/ckeditor4/issues/4596): Fixed: Incorrect handling of HSL/HSLA values in [`CKEDITOR.tools.color`](https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_tools_color.html).
* [#4874](https://github.com/ckeditor/ckeditor4/issues/4874): Fixed: Built-in support for pasting and dropping images in the [Clipboard](https://ckeditor.com/cke4/addon/clipboard) plugin restricts third party plugins from handling image pasting. Thanks to [FlowIT-JIT](https://github.com/FlowIT-JIT)!

**API Changes:**

Expand Down
13 changes: 12 additions & 1 deletion plugins/clipboard/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@
// Convert image file (if present) to base64 string for modern browsers except IE<10, as it does not support
// custom MIME types in clipboard (#4612).
// Do it as the first step as the conversion is asynchronous and should hold all further paste processing.
if ( CKEDITOR.plugins.clipboard.isCustomDataTypesSupported || CKEDITOR.plugins.clipboard.isFileApiSupported ) {
var isImagePasteSupported = CKEDITOR.plugins.clipboard.isCustomDataTypesSupported || CKEDITOR.plugins.clipboard.isFileApiSupported;
if ( isImagePasteSupported && editor.config.clipboard_handleImages ) {
var supportedImageTypes = [ 'image/png', 'image/jpeg', 'image/gif' ],
unsupportedTypeMsg = createNotificationMessage( supportedImageTypes ),
latestId;
Expand Down Expand Up @@ -3471,3 +3472,13 @@
* @member CKEDITOR.config
*/
CKEDITOR.config.clipboard_notificationDuration = 10000;

/**
* Whether to use clipboard plugin to handle image pasting and dropping,
* turning images into base64 strings on browsers supporting the File API.
*
* @since 4.17.0
* @cfg {Boolean} [clipboard_handleImages=true]
* @member CKEDITOR.config
*/
CKEDITOR.config.clipboard_handleImages = true;
125 changes: 123 additions & 2 deletions tests/plugins/clipboard/_helpers/pasting.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* exported assertPasteEvent, pasteFiles, assertPasteCommand, assertPasteNotification, testResetScenario,
getDefaultNotification, createFixtures, mockFileReader */
/* exported assertPasteEvent, pasteFiles, assertPasteCommand, assertPasteNotification, assertImagePaste,
assertImageDrop, testResetScenario,getDefaultNotification, createFixtures, mockFileReader */

'use strict';

Expand Down Expand Up @@ -235,3 +235,124 @@ function mockFileReader() {

window.FileReader = FileReaderMock;
}

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

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

if ( additionalData ) {
CKEDITOR.tools.array.forEach( additionalData, function( data ) {
nativeData.setData( data.type, data.data );
} );
}

dataTransfer.cacheData();

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

var type = options.type,
expected = options.expected,
additionalData = options.additionalData,
callback = options.callback;

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

if ( callback ) {
callback();
}
} );
}, this, null, 9999 );

mockPasteFile( type, additionalData );

wait();
}

function assertImageDrop( options ) {
function mockDropFile( type ) {
var nativeData = bender.tools.mockNativeDataTransfer(),
dataTransfer = new CKEDITOR.plugins.clipboard.dataTransfer( nativeData );

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

nativeData.types.push( 'Files' );
dataTransfer.cacheData();

return dataTransfer.$;
}

var editor = options.editor,
evt = options.event,
type = options.type,
expectedData = options.expectedData,
callback = options.callback,
dropRangeOptions = options.dropRange,
dropTarget = CKEDITOR.plugins.clipboard.getDropTarget( editor ),
range = new CKEDITOR.dom.range( editor.document );

range.setStart( dropRangeOptions.dropContainer, dropRangeOptions.dropOffset );
evt.testRange = range;

// Push data into clipboard and invoke paste event
evt.$.dataTransfer = mockDropFile( type );

var onDrop,
onPaste,
tearDown;

tearDown = function() {
editor.removeListener( 'drop', onDrop );
editor.removeListener( 'paste', onPaste );
};

onDrop = function( dropEvt ) {
var dropRange = dropEvt.data.dropRange;

dropRange.startContainer = dropRangeOptions.dropContainer;
dropRange.startOffset = dropRangeOptions.dropOffset;
dropRange.endOffset = dropRangeOptions.dropOffset;
};

onPaste = function() {
resume( function() {
assert.beautified.html( expectedData, editor.getData() );

if ( callback ) {
callback();
}

tearDown();
} );
};

editor.on( 'drop', onDrop );
editor.on( 'paste', onPaste );

dropTarget.fire( 'drop', evt );

wait();
}
129 changes: 129 additions & 0 deletions tests/plugins/clipboard/clipboardimagedisabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* bender-tags: editor */
/* bender-ckeditor-plugins: clipboard */
/* bender-include: _helpers/pasting.js */
/* globals mockFileReader, assertImageDrop, assertImagePaste */

( function() {
'use strict';

var pasteCount = 0,
dropCount = 0;

CKEDITOR.plugins.add( 'customImagePasteHandlerPlugin', {
init: function( editor ) {
editor.on( 'paste', function( event ) {
if ( event.data.dataTransfer.$.files.length === 1 ) {
pasteCount++;
}
} );

editor.on( 'drop', function( event ) {
if ( event.data.dataTransfer.$.files.length === 1 ) {
dropCount++;
}
} );
}
} );

var originalFileReader = window.FileReader;

bender.editor = {
config: {
extraAllowedContent: 'img[*];strong',
language: 'en',
clipboard_handleImages: false,
extraPlugins: 'customImagePasteHandlerPlugin'
}
};

bender.test( {
setUp: function() {
mockFileReader();
this.editor.focus();
},

tearDown: function() {
window.FileReader = originalFileReader;
},

'test image paste from clipboard suppressed': function() {
if ( !CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ) {
assert.ignore();
}

FileReader.setFileMockType( 'image/png' );
FileReader.setReadResult( 'load' );

pasteCount = 0;

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

this.assertPaste( {
type: 'image/png',
expected: '<p>Paste image here:^@</p>',
callback: function() {
assert.areSame( pasteCount, 1, 'custom image handler plugin did not receive file' );
}
} );
},

'test image and text paste from clipboard, only image suppressed': function() {
if ( !CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ) {
assert.ignore();
}

FileReader.setFileMockType( 'image/png' );
FileReader.setReadResult( 'load' );

pasteCount = 0;

bender.tools.selection.setWithHtml( this.editor, '<p>{}</p>' );

this.assertPaste( {
type: 'image/png',
expected: '<p><strong>Hello world^</strong>@</p><p></p>',
additionalData: [
{ type: 'text/html', data: '<strong>Hello world</strong>' }
],
callback: function() {
assert.areSame( pasteCount, 1, 'custom image handler plugin did not receive file' );
}
} );
},

'test image drop suppressed': function() {
if ( !CKEDITOR.plugins.clipboard.isFileApiSupported ) {
assert.ignore();
}

var dropEvt = bender.tools.mockDropEvent(),
imageType = 'image/png',
expected = '<p class="p">Paste image here:</p>';

FileReader.setFileMockType( imageType );
FileReader.setReadResult( 'load' );

dropCount = 0;

bender.tools.setHtmlWithSelection( this.editor, '<p class="p">Paste image here:^</p>' );

assertImageDrop( {
editor: this.editor,
event: dropEvt,
type: imageType,
expectedData: expected,
dropRange: {
dropContainer: this.editor.editable().findOne( '.p' ).getChild( 0 ),
dropOffset: 17
},
callback: function() {
assert.areSame( dropCount, 1, 'custom image handler plugin did not receive file' );
}
} );
},

assertPaste: function( options ) {
assertImagePaste( this.editor, options );
}
} );
} )();
Loading