Skip to content

Commit b01cee9

Browse files
author
Piotr Jasiun
committed
Merge branch 't/13518' into major
2 parents 336a28c + 8749b3f commit b01cee9

File tree

6 files changed

+355
-37
lines changed

6 files changed

+355
-37
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ New Features:
77

88
* [#12077](https://dev.ckeditor.com/ticket/12077): Add support for HTML5 "download" attribute in link (a) elements. Thanks to [sbusse](https://github.com/sbusse)!
99
* [#13519](http://dev.ckeditor.com/ticket/13519): (http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools) response is now more flexible.
10+
* [#13518](http://dev.ckeditor.com/ticket/13518): (http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools) request is now more flexible and [additionalRequestParameters](http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools.uploadWidgetDefinition-property-additionalRequestParameters) property was introduced.
1011
* [#13828](http://dev.ckeditor.com/ticket/13828): Adding a class to widget element will also add a prefixed class to it's wrapper.
1112

1213
## CKEditor 4.5.5

plugins/filetools/plugin.js

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,35 @@
3434
* @member CKEDITOR.editor
3535
* @param data
3636
* @param {CKEDITOR.fileTools.fileLoader} data.fileLoader File loader instance.
37+
* @param {Object} data.requestData Object containing all data to be sent to the server.
3738
*/
3839
editor.on( 'fileUploadRequest', function( evt ) {
3940
var fileLoader = evt.data.fileLoader;
4041

4142
fileLoader.xhr.open( 'POST', fileLoader.uploadUrl, true );
43+
44+
// Adding file to event's data by default - allows overwriting it by user's event listeners. (#13518)
45+
evt.data.requestData.upload = { file: fileLoader.file, name: fileLoader.fileName };
4246
}, null, null, 5 );
4347

4448
editor.on( 'fileUploadRequest', function( evt ) {
4549
var fileLoader = evt.data.fileLoader,
46-
formData = new FormData();
50+
$formData = new FormData(),
51+
requestData = evt.data.requestData;
52+
53+
for ( var name in requestData ) {
54+
var value = requestData[ name ];
4755

48-
formData.append( 'upload', fileLoader.file, fileLoader.fileName );
49-
fileLoader.xhr.send( formData );
56+
// Treating files in special way
57+
if ( typeof value === 'object' && value.file ) {
58+
$formData.append( name, value.file, value.name );
59+
}
60+
else {
61+
$formData.append( name, value );
62+
}
63+
}
64+
65+
fileLoader.xhr.send( $formData );
5066
}, null, null, 999 );
5167

5268
/**
@@ -443,8 +459,10 @@
443459
* * `uploaded`.
444460
*
445461
* @param {String} url The upload URL.
462+
* @param {Object} [additionalRequestParameters] Additional parameters that would be passed into
463+
* {@link CKEDITOR.editor#fileUploadRequest} event.
446464
*/
447-
loadAndUpload: function( url ) {
465+
loadAndUpload: function( url, additionalRequestParameters ) {
448466
var loader = this;
449467

450468
this.once( 'loaded', function( evt ) {
@@ -457,7 +475,7 @@
457475
}, null, null, 0 );
458476

459477
// Start uploading.
460-
loader.upload( url );
478+
loader.upload( url, additionalRequestParameters );
461479
}, null, null, 0 );
462480

463481
this.load();
@@ -518,8 +536,12 @@
518536
* * `uploaded`.
519537
*
520538
* @param {String} url The upload URL.
539+
* @param {Object} [additionalRequestParameters] Additional data that would be passed into
540+
* {@link CKEDITOR.editor#fileUploadRequest} event.
521541
*/
522-
upload: function( url ) {
542+
upload: function( url, additionalRequestParameters ) {
543+
var requestData = additionalRequestParameters || {};
544+
523545
if ( !url ) {
524546
this.message = this.lang.filetools.noUrlError;
525547
this.changeStatus( 'error' );
@@ -529,7 +551,7 @@
529551
this.xhr = new XMLHttpRequest();
530552
this.attachRequestListeners();
531553

532-
if ( this.editor.fire( 'fileUploadRequest', { fileLoader: this } ) ) {
554+
if ( this.editor.fire( 'fileUploadRequest', { fileLoader: this, requestData: requestData } ) ) {
533555
this.changeStatus( 'uploading' );
534556
}
535557
}

plugins/uploadwidget/plugin.js

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/**
22
* @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
33
* For licensing, see LICENSE.md or http://ckeditor.com/license
44
*/
@@ -84,6 +84,28 @@
8484
* }
8585
* } );
8686
*
87+
* If you need to pass additional data to the request, you can do this using
88+
* {@link CKEDITOR.fileTools.uploadWidgetDefinition#additionalRequestParameters additionalRequestParameters} property.
89+
* That data is then passed to the upload method, defined by {@link CKEDITOR.fileTools.uploadWidgetDefinition#loadMethod},
90+
* and to {@link CKEDITOR.editor#fileUploadRequest} event (as part of `requestData` property).
91+
* Syntax of that parameter is compatible with {@link CKEDITOR.editor#fileUploadRequest} `requestData` property.
92+
*
93+
* CKEDITOR.fileTools.addUploadWidget( editor, 'uploadFile', {
94+
* additionalRequestParameters: {
95+
* foo: 'bar'
96+
* },
97+
*
98+
* fileToElement: function( file ) {
99+
* var el = new CKEDITOR.dom.element( 'span' );
100+
* el.setText( '...' );
101+
* return el;
102+
* },
103+
*
104+
* onUploaded: function( upload ) {
105+
* this.replaceWith( '<a href="' + upload.url + '" target="_blank">' + upload.fileName + '</a>' );
106+
* }
107+
* } );
108+
*
87109
* If you need custom `paste` handling you need to mark the pasted element to be changed into an upload widget
88110
* using {@link CKEDITOR.fileTools#markElement markElement}. For example, instead of the `fileToElement` helper from the
89111
* example above, a `paste` listener can be created manually:
@@ -169,7 +191,7 @@
169191
loader = uploads.create( file );
170192

171193
if ( el ) {
172-
loader[ loadMethod ]( def.uploadUrl );
194+
loader[ loadMethod ]( def.uploadUrl, def.additionalRequestParameters );
173195

174196
CKEDITOR.fileTools.markElement( el, name, loader.id );
175197

@@ -195,9 +217,9 @@
195217
* should not be overwritten.
196218
*
197219
* Also, the upload widget definition defines a few properties ({@link #fileToElement}, {@link #supportedTypes},
198-
* {@link #loadMethod loadMethod} and {@link #uploadUrl}) used in the {@link CKEDITOR.editor#paste} listener
199-
* which is registered by {@link CKEDITOR.fileTools#addUploadWidget} if the upload widget definition contains
200-
* the {@link #fileToElement} callback.
220+
* {@link #loadMethod loadMethod}, {@link #uploadUrl} and {@link #additionalRequestParameters}) used in the
221+
* {@link CKEDITOR.editor#paste} listener which is registered by {@link CKEDITOR.fileTools#addUploadWidget}
222+
* if the upload widget definition contains the {@link #fileToElement} callback.
201223
*
202224
* @abstract
203225
* @class CKEDITOR.fileTools.uploadWidgetDefinition
@@ -341,6 +363,12 @@
341363
* @property {String} [uploadUrl]
342364
*/
343365

366+
/**
367+
* Object containing additional data that should be based into function defined by {@link #loadMethod}.
368+
*
369+
* @property {Object} [additionalRequestParameters]
370+
*/
371+
344372
/**
345373
* The type of loading operation that should be executed as a result of pasting a file. Possible options are:
346374
*

tests/plugins/filetools/fileloader.js

Lines changed: 127 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
'use strict';
55

66
( function() {
7-
var FileReaderBackup = window.FileReader,
7+
var File = window.File,
8+
Blob = window.Blob,
9+
FormData = window.FormData,
10+
FileReaderBackup = window.FileReader,
811
XMLHttpRequestBackup = window.XMLHttpRequest,
912
FileLoader, resumeAfter,
1013
pngBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAxJREFUCNdjYGBgAAAABAABJzQnCgAAAABJRU5ErkJggg==',
@@ -19,6 +22,42 @@
1922
}
2023
};
2124

25+
function createFileMock() {
26+
window.File = File = function( data, name ) {
27+
var file = new Blob( data , {} );
28+
file.name = name;
29+
30+
return file;
31+
};
32+
}
33+
34+
function createFormDataMock() {
35+
window.FormData = function() {
36+
var entries = {},
37+
mock = {
38+
get: function( name ) {
39+
return entries[ name ] || null;
40+
},
41+
append: function( name, value, fileName ) {
42+
if ( value instanceof File && ( value.name === fileName || !fileName ) )
43+
entries[ name ] = value;
44+
else if ( value instanceof Blob ) {
45+
fileName = fileName || value.name || 'blob';
46+
47+
entries [ name ] = new File( [ value ], fileName );
48+
}
49+
else
50+
entries[ name ] = value + '';
51+
},
52+
has: function( name ) {
53+
return Object.prototype.hasOwnProperty.call( entries, name );
54+
}
55+
};
56+
57+
return mock;
58+
};
59+
}
60+
2261
function createFileReaderMock( scenario ) {
2362
var isAborted = false;
2463

@@ -197,6 +236,15 @@
197236
assert.ignore();
198237
}
199238

239+
// IE doesn't support File constructor, so there is a need to mimic it.
240+
if ( typeof MSBlobBuilder === 'function' )
241+
createFileMock();
242+
243+
// FormData in IE & Chrome 47- supports only adding data, not getting it, so mocking (polyfilling?) is required.
244+
// Note that mocking is needed only for tests, as CKEditor.fileTools uses only append method
245+
if ( !FormData.prototype.get || !FormData.prototype.has )
246+
createFormDataMock();
247+
200248
FileLoader = CKEDITOR.fileTools.fileLoader;
201249
resumeAfter = bender.tools.resumeAfter;
202250
testFile = bender.tools.getTestPngFile();
@@ -348,6 +396,61 @@
348396
wait();
349397
},
350398

399+
'test upload with custom field name (#13518)': function() {
400+
var loader = new FileLoader( editorMock, pngBase64, 'name.png' );
401+
402+
attachListener( editorMock, 'fileUploadRequest', function( evt ) {
403+
var requestData = evt.data.requestData;
404+
405+
requestData.myFile = requestData.upload;
406+
407+
delete requestData.upload;
408+
} );
409+
410+
createXMLHttpRequestMock( [ 'load' ] );
411+
412+
resumeAfter( loader, 'uploaded', function() {
413+
assert.isTrue( lastFormData.has( 'myFile' ) );
414+
assert.isFalse( lastFormData.has( 'upload' ) );
415+
416+
// FormData converts all Blob objects into File ones, so we must "revert" it
417+
objectAssert.areEqual( new Blob( [ lastFormData.get( 'myFile' ) ], {} ), loader.file );
418+
}, 3 );
419+
420+
loader.upload( 'http:\/\/url\/' );
421+
422+
wait();
423+
},
424+
425+
'test upload with additional request parameters provided (#13518)': function() {
426+
var loader = new FileLoader( editorMock, pngBase64, 'name.png' );
427+
428+
createXMLHttpRequestMock( [ 'load' ] );
429+
430+
resumeAfter( loader, 'uploaded', function() {
431+
assert.areSame( 'test', lastFormData.get( 'test' ) );
432+
}, 3 );
433+
434+
loader.upload( 'http:\/\/url\/', { test: 'test' } );
435+
436+
wait();
437+
},
438+
439+
'test if name of file is correctly attached (#13518)': function() {
440+
var name = 'customName.png',
441+
loader = new FileLoader( editorMock, pngBase64, name );
442+
443+
createXMLHttpRequestMock( [ 'load' ] );
444+
445+
resumeAfter( loader, 'uploaded', function() {
446+
assert.areSame( name, lastFormData.get( 'upload' ).name );
447+
}, 3 );
448+
449+
loader.upload( 'http:\/\/url\/' );
450+
451+
wait();
452+
},
453+
351454
'test upload response not encoded (#13030)': function() {
352455
var loader = new FileLoader( editorMock, pngBase64, 'na me.png' ),
353456
observer = observeEvents( loader );
@@ -768,27 +871,6 @@
768871
wait();
769872
},
770873

771-
'test response with custom fields (#13519)': function() {
772-
var loader = new FileLoader( editorMock, testFile ),
773-
response = {
774-
fileName: 'name2.png',
775-
uploaded: 1,
776-
url: 'http:\/\/url\/name2.png',
777-
foo: 'bar'
778-
};
779-
780-
createXMLHttpRequestMock( [ 'progress', 'load' ],
781-
{ responseText: JSON.stringify( response ) } );
782-
783-
resumeAfter( loader, 'uploaded', function() {
784-
objectAssert.areEqual( response, loader.responseData );
785-
} );
786-
787-
loader.upload( 'http:\/\/url\/' );
788-
789-
wait();
790-
},
791-
792874
'test error 404 with message': function() {
793875
editorMock.lang = { filetools: { httpError404: 'httpError404' } };
794876

@@ -887,6 +969,29 @@
887969
wait();
888970
},
889971

972+
'test additional data passed to xhr via fileUploadRequest listener (#13518)': function() {
973+
var loader = new FileLoader( editorMock, testFile ),
974+
file = new File( [], 'a' );
975+
976+
attachListener( editorMock, 'fileUploadRequest', function( evt ) {
977+
var requestData = evt.data.requestData;
978+
979+
requestData.customField = 'test';
980+
requestData.customFile = file;
981+
} );
982+
983+
createXMLHttpRequestMock( [ 'load' ] );
984+
985+
resumeAfter( loader, 'uploaded', function() {
986+
assert.areSame( 'test', lastFormData.get( 'customField' ) );
987+
objectAssert.areEqual( file, lastFormData.get( 'customFile' ) );
988+
} );
989+
990+
loader.upload( 'http:\/\/url\/' );
991+
992+
wait();
993+
},
994+
890995
'test additional data in fileUploadResponse (#13519)': function() {
891996
var data,
892997
loader = new FileLoader( editorMock, testFile );

0 commit comments

Comments
 (0)