When you upload a media file to a specific location, if the file is already existed, you will be noticed by a warning:
You can either choose “Skip this File” to ignore the replacement, or hit “Replace File” to replace the old existing file.
The issue
Assuming that you have to replace 2 existing images, but due to wrong naming in one of the images, after you upload them, instead of showing 2 replacements, now it shows that you are trying to add 1 new file and replace 1 existing file.
Now you realized that maybe it was your mistake, you want to cancel the bulk upload, but at this point, there is NO GOING BACK! You have to select 1) Upload both of the files and accept the replacements OR 2) Skip the existing files and continue uploading the remaining new file.
To undo the mistake, you have to delete/revert each of the file you have uploaded to that folder. It’s going to be painful if the folder is already large, or the number of files in your bulk upload is not just 2 but dozens.
The solution
It could be nice if we can have another button to cancel the upload so we can have a second chance to carefully review the changes. This is exactly what we did:
Taking a look at the MultipleFileUploadConfirmation component (the dialog displaying replacement warning), you can see it only have 2 options, skip or replace:
return [ { name: "skipFiles", label: single ? resources.single.buttons.skip : resources.multiple.buttons.skip, title: null, action: function () { when(dialog.hide(), function () { return dialog.onAction(false); }); } }, { name: "replaceFiles", label: single ? resources.single.buttons.replace : resources.multiple.buttons.replace, settings: { "class": "Salt" }, title: null, action: function () { when(dialog.hide(), function () { return dialog.onAction(true); }); } } ];
We are going to extends the dialog, add another cancel button to scrap out the bulk upload.
Implementation steps
Setup a module initializer
First step is adding a module initializer. This will allows you to intercept to the UI events and create your own configures/customizations. Define your module initializer by following the Official Optimizely Developer Documentation
Create your own Upload Confirmation Dialog which extends the original one
We are creating a Custom Upload Confirmation Dialog based on the original dialog. But we will override the _getActions method (to add a cancel button) and the showConfirmation method (to handle when users select an action). Here is the example code:
define("poc/Widget/CustomMultipleFileUploadConfirmation", [ // dojo "dojo/_base/array", "dojo/_base/declare", "dojo/_base/lang", "dojo/dom-class", "dojo/aspect", "dojo/Deferred", "dojo/when", // epi "epi/string", "epi/shell/widget/dialog/Dialog", "epi-cms/widget/ReadOnlyContentList", "epi-cms/widget/MultipleFileUploadConfirmation", // resources "epi/i18n!epi/cms/nls/episerver.cms.widget.uploadmultiplefiles.replaceconfirmdialog" ], function ( // dojo array, declare, lang, domClass, aspect, Deferred, when, // epi epiString, Dialog, ReadOnlyContentList, MultipleFileUploadConfirmation, // resources resources ) { return declare([MultipleFileUploadConfirmation], { // summary: // Confirmation dialog for multiple file upload widget // tags: // internal showConfirmation: function (/*Array*/existingContents, /*Array*/uploadingFiles, /*Array*/newFiles) { // summary: // Show confirmation dialog to replace/skip the existing contents when uploading file(s) by multiple file upload widget. // existingContents: [Array] // Filtered existing content(s) on the server // uploadingFiles: [Array] // The uploading file(s) given from multiple file upload widget // newFiles: [Array] // Filtered new file(s) that are not existing on the server // returns: [dojo.Deferred] // An instance of Array for filtered file list to upload to server. // This list can be the whole original selected file(s) or just the new file(s) that not existed on the server. // tags: // public var deferred = new Deferred(), dialog = this._getDialog(existingContents.length), content = this._getContentList(); dialog.set("content", content); dialog.set("onAction", function (result) { /*deferred.resolve(result ? uploadingFiles : newFiles);*/ switch (result) { case 0: // cancel deferred.resolve([]); break; case 1: // skip existing files deferred.resolve(newFiles); break; case 2: // replace deferred.resolve(uploadingFiles); break; default: deferred.resolve([]); break; } }); when(dialog.show(), function () { content.grid.renderArray(existingContents); }); return deferred; }, // ======================================================================= // Private functions _getActions: function (/*epi/shell/widget/dialog/Dialog*/dialog, /*Boolean*/single) { // summary: // Overridden from Dialog base to assemble the action collection // dialog: [epi/shell/widget/dialog/Dialog] // Confirmation dialog // single: [Boolean] // Indicates that we must show text for single item or multiple items // returns: // A collection of action definitions that can be added to the action pane. // tags: // private return [ { name: "cancel", label: "Cancel", title: null, action: function () { when(dialog.hide(), function () { return dialog.onAction(0); }); } }, { name: "skipFiles", label: single ? resources.single.buttons.skip : resources.multiple.buttons.skip, title: null, action: function () { when(dialog.hide(), function () { return dialog.onAction(1); }); } }, { name: "replaceFiles", label: single ? resources.single.buttons.replace : resources.multiple.buttons.replace, settings: { "class": "Salt" }, title: null, action: function () { when(dialog.hide(), function () { return dialog.onAction(2); }); } } ]; } }); });
Replace the old dialog with your custom dialog above, using moduleInitializer
define([ "dojo", "dojo/_base/declare", "epi/_Module", "epi-cms/widget/MultipleFileUpload", "poc/Widget/CustomMultipleFileUploadConfirmation" ], function (dojo, declare, _Module, MultipleFileUpload, CustomMultipleFileUploadConfirmation ) { return declare("poc.moduleInitializer", [_Module], { initialize: function () { this.inherited(arguments); // Do any custom module initialization here // Extend postCreate method for MultipleFileUpload var originalMultipleFileUpload = MultipleFileUpload.prototype.postCreate; MultipleFileUpload.prototype.postCreate = function () { // call the original function originalMultipleFileUpload.apply(this, arguments); this._confirmationDialog = new CustomMultipleFileUploadConfirmation(); } } }); });
That’s it! Now you have a cancel button for your Bulk Upload Confirmation Dialog. With this methodology you can even extend your custom dialog further to fit a variety of requirements. Happy coding!
very nice! its a good methology.