Skip to content

Commit 52dc0e2

Browse files
Merge pull request magento#2455 from magento-trigger/team3-delivery2
[Team 3] Sprint 6 Delivery Part 2
2 parents fd98e21 + bafc610 commit 52dc0e2

File tree

6 files changed

+169
-26
lines changed

6 files changed

+169
-26
lines changed

app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js

+14-5
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,19 @@ define([
1313
'jquery',
1414
'mage/template',
1515
'Magento_Ui/js/modal/alert',
16+
'Magento_Ui/js/form/element/file-uploader',
1617
'mage/translate',
1718
'jquery/file-uploader'
18-
], function ($, mageTemplate, alert) {
19+
], function ($, mageTemplate, alert, FileUploader) {
1920
'use strict';
2021

22+
var fileUploader = new FileUploader({
23+
dataScope: '',
24+
isMultipleFiles: true
25+
});
26+
27+
fileUploader.initUploader();
28+
2129
$.widget('mage.mediaUploader', {
2230

2331
/**
@@ -79,10 +87,9 @@ define([
7987
if (data.result && !data.result.error) {
8088
self.element.trigger('addItem', data.result);
8189
} else {
82-
alert({
83-
content: $.mage.__('We don\'t recognize or support this file extension type.')
84-
});
90+
fileUploader.aggregateError(data.files[0].name, data.result.error);
8591
}
92+
8693
self.element.find('#' + data.fileId).remove();
8794
},
8895

@@ -108,7 +115,9 @@ define([
108115
.delay(2000)
109116
.hide('highlight')
110117
.remove();
111-
}
118+
},
119+
120+
stop: fileUploader.uploaderConfig.stop
112121
});
113122

114123
this.element.find('input[type=file]').fileupload('option', {

app/code/Magento/Ui/Component/Form/Element/DataType/Media/Image.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public function prepare()
7272
'config' => [
7373
'maxFileSize' => $maxFileSize,
7474
'mediaGallery' => [
75-
'openDialogUrl' => $this->getContext()->getUrl('cms/wysiwyg_images/index'),
75+
'openDialogUrl' => $this->getContext()->getUrl('cms/wysiwyg_images/index', ['_secure' => true]),
7676
'openDialogTitle' => $this->getConfiguration()['openDialogTitle'] ?? __('Insert Images...'),
7777
'initialOpenSubpath' => $this->getConfiguration()['initialMediaGalleryOpenSubpath'],
7878
'storeId' => $this->storeManager->getStore()->getId(),

app/code/Magento/Ui/i18n/en_US.csv

+1
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,4 @@ CSV,CSV
201201
"Please enter at least {0} characters.","Please enter at least {0} characters."
202202
"Please enter a value between {0} and {1} characters long.","Please enter a value between {0} and {1} characters long."
203203
"Please enter a value between {0} and {1}.","Please enter a value between {0} and {1}."
204+
"was not uploaded","was not uploaded"

app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js

+81-9
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ define([
1313
'Magento_Ui/js/modal/alert',
1414
'Magento_Ui/js/lib/validation/validator',
1515
'Magento_Ui/js/form/element/abstract',
16+
'mage/backend/notification',
17+
'mage/translate',
1618
'jquery/file-uploader'
17-
], function ($, _, utils, uiAlert, validator, Element) {
19+
], function ($, _, utils, uiAlert, validator, Element, notification, $t) {
1820
'use strict';
1921

2022
return Element.extend({
2123
defaults: {
2224
value: [],
25+
aggregatedErrors: [],
2326
maxFileSize: false,
2427
isMultipleFiles: false,
2528
placeholderType: 'document', // 'image', 'video'
@@ -278,9 +281,15 @@ define([
278281
* @returns {FileUploader} Chainable.
279282
*/
280283
notifyError: function (msg) {
281-
uiAlert({
284+
var data = {
282285
content: msg
283-
});
286+
};
287+
288+
if (this.isMultipleFiles) {
289+
data.modalClass = '_image-box';
290+
}
291+
292+
uiAlert(data);
284293

285294
return this;
286295
},
@@ -309,13 +318,19 @@ define([
309318
},
310319

311320
/**
312-
* Abstract handler which is invoked when files are choosed for upload.
321+
* Handler which is invoked when files are choosed for upload.
313322
* May be used for implementation of aditional validation rules,
314323
* e.g. total files and a total size rules.
315324
*
316-
* @abstract
325+
* @param {Event} e - Event object.
326+
* @param {Object} data - File data that will be uploaded.
317327
*/
318-
onFilesChoosed: function () {},
328+
onFilesChoosed: function (e, data) {
329+
// no option exists in fileuploader for restricting upload chains to single files; this enforces that policy
330+
if (!this.isMultipleFiles) {
331+
data.files.splice(1);
332+
}
333+
},
319334

320335
/**
321336
* Handler which is invoked prior to the start of a file upload.
@@ -337,22 +352,41 @@ define([
337352
data.submit();
338353
});
339354
} else {
340-
this.notifyError(allowed.message);
355+
this.aggregateError(file.name, allowed.message);
356+
357+
// if all files in upload chain are invalid, stop callback is never called; this resolves promise
358+
if (this.aggregatedErrors.length === data.originalFiles.length) {
359+
this.uploaderConfig.stop();
360+
}
341361
}
342362
},
343363

364+
/**
365+
* Add error message associated with filename for display when upload chain is complete
366+
*
367+
* @param {String} filename
368+
* @param {String} message
369+
*/
370+
aggregateError: function (filename, message) {
371+
this.aggregatedErrors.push({
372+
filename: filename,
373+
message: message
374+
});
375+
},
376+
344377
/**
345378
* Handler of the file upload complete event.
346379
*
347380
* @param {Event} e
348381
* @param {Object} data
349382
*/
350383
onFileUploaded: function (e, data) {
351-
var file = data.result,
384+
var uploadedFilename = data.files[0].name,
385+
file = data.result,
352386
error = file.error;
353387

354388
error ?
355-
this.notifyError(error) :
389+
this.aggregateError(uploadedFilename, error) :
356390
this.addFile(file);
357391
},
358392

@@ -367,7 +401,45 @@ define([
367401
* Load stop event handler.
368402
*/
369403
onLoadingStop: function () {
404+
var aggregatedErrorMessages = [];
405+
370406
this.isLoading = false;
407+
408+
if (!this.aggregatedErrors.length) {
409+
return;
410+
}
411+
412+
if (!this.isMultipleFiles) { // only single file upload occurred; use first file's error message
413+
aggregatedErrorMessages.push(this.aggregatedErrors[0].message);
414+
} else { // construct message from all aggregatedErrors
415+
_.each(this.aggregatedErrors, function (error) {
416+
notification().add({
417+
error: true,
418+
message: '%s' + error.message, // %s to be used as placeholder for html injection
419+
420+
/**
421+
* Adds constructed error notification to aggregatedErrorMessages
422+
*
423+
* @param {String} constructedMessage
424+
*/
425+
insertMethod: function (constructedMessage) {
426+
var errorMsgBodyHtml = '<strong>%s</strong> %s.<br>'
427+
.replace('%s', error.filename)
428+
.replace('%s', $t('was not uploaded'));
429+
430+
// html is escaped in message body for notification widget; prepend unescaped html here
431+
constructedMessage = constructedMessage.replace('%s', errorMsgBodyHtml);
432+
433+
aggregatedErrorMessages.push(constructedMessage);
434+
}
435+
});
436+
});
437+
}
438+
439+
this.notifyError(aggregatedErrorMessages.join(''));
440+
441+
// clear out aggregatedErrors array for this completed upload chain
442+
this.aggregatedErrors = [];
371443
},
372444

373445
/**

app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
&.confirm,
8181
&.prompt {
8282
.modal-inner-wrap {
83-
.message {
83+
.message:not(.message-error) {
8484
background: @modal-popup-colorless__background;
8585
}
8686
}

dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/file-uploader.test.js

+71-10
Original file line numberDiff line numberDiff line change
@@ -235,29 +235,77 @@ define([
235235

236236
describe('onFileUploaded handler', function () {
237237
it('calls addFile method if upload was successful', function () {
238+
spyOn(component, 'aggregateError');
238239
spyOn(component, 'addFile');
239240

240241
component.onFileUploaded({}, {
242+
files: [{
243+
name: 'hello.jpg'
244+
}],
241245
result: {
242246
error: false
243247
}
244248
});
245249

250+
expect(component.aggregateError).not.toHaveBeenCalled();
246251
expect(component.addFile).toHaveBeenCalled();
247252
});
248253

249-
it('calls notifyError method if upload resulted in error', function () {
250-
spyOn(component, 'notifyError');
251-
spyOn(component, 'addFile');
252-
253-
component.onFileUploaded({}, {
254-
result: {
255-
error: true
256-
}
254+
it('should call uploaderConfig.stop when number of errors is equal to number of files', function () {
255+
var fakeEvent = {
256+
target: document.createElement('input')
257+
},
258+
file = {
259+
name: 'hello.jpg'
260+
},
261+
data = {
262+
files: [file],
263+
originalFiles: [file]
264+
};
265+
266+
spyOn(component, 'isFileAllowed').and.callFake(function (fileArg) {
267+
expect(fileArg).toBe(file);
268+
269+
return {
270+
passed: false,
271+
message: 'Not awesome enough'
272+
};
273+
});
274+
component.initUploader();
275+
spyOn(component.uploaderConfig, 'done');
276+
spyOn(component.uploaderConfig, 'stop');
277+
component.onBeforeFileUpload(fakeEvent, data);
278+
expect(component.uploaderConfig.stop).toHaveBeenCalled();
279+
});
280+
it('should not call uploaderConfig.stop when number of errors is unequal to number of files', function () {
281+
var fakeEvent = {
282+
target: document.createElement('input')
283+
},
284+
file = {
285+
name: 'hello.jpg'
286+
},
287+
otherFileInQueue = {
288+
name: 'world.png'
289+
},
290+
data = {
291+
files: [file],
292+
originalFiles: [file, otherFileInQueue]
293+
};
294+
295+
component.initUploader();
296+
spyOn(component.uploaderConfig, 'done');
297+
spyOn(component.uploaderConfig, 'stop');
298+
spyOn(component, 'isFileAllowed').and.callFake(function (fileArg) {
299+
expect(fileArg).toBe(file);
300+
301+
return {
302+
passed: false,
303+
message: 'Not awesome enough'
304+
};
257305
});
258306

259-
expect(component.notifyError).toHaveBeenCalled();
260-
expect(component.addFile).not.toHaveBeenCalled();
307+
component.onBeforeFileUpload(fakeEvent, data);
308+
expect(component.uploaderConfig.stop).not.toHaveBeenCalled();
261309
});
262310
});
263311

@@ -272,5 +320,18 @@ define([
272320
expect(component.initUploader).toHaveBeenCalledWith(input);
273321
});
274322
});
323+
324+
describe('aggregateError method', function () {
325+
it('should append onto aggregatedErrors array when called', function () {
326+
spyOn(component.aggregatedErrors, 'push');
327+
328+
component.aggregateError('blah.jpg', 'File is too awesome');
329+
330+
expect(component.aggregatedErrors.push).toHaveBeenCalledWith({
331+
filename: 'blah.jpg',
332+
message: 'File is too awesome'
333+
});
334+
});
335+
});
275336
});
276337
});

0 commit comments

Comments
 (0)