scinote-web/app/assets/javascripts/sitewide/drag_n_drop.js.erb
aignatov-bio 894e201e1b
Fix big file issue in step attachments [SCI-3682] (#1919)
* Fix big file issue in step atachments

* Fix markup
2019-07-15 11:00:01 +02:00

585 lines
19 KiB
Text

(function(global) {
'use strict';
// Copy from clipboard
global.copyFromClipboard = (function() {
var UPLOADED_IMAGE = {};
var LOCATION = '';
function init(location) {
LOCATION = location;
global.addEventListener('paste', _listener, false);
$.initTooltips();
};
function destroy() {
global.removeEventListener('paste', _listener, false);
}
function _listener(pasteEvent) {
_retrieveImageFromClipboardAsBlob(pasteEvent, function(imageBlob) {
if(imageBlob){
_clipboardPasteModal().promise().done(function() {
var canvas = document.getElementById('clipboardPreview');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
canvas.width = this.width;
canvas.height = this.height;
ctx.drawImage(img, 0, 0);
};
var URLObj = window.URL || window.webkitURL;
img.src = URLObj.createObjectURL(imageBlob);
var extension = imageBlob.name.slice(
(Math.max(0, imageBlob.name.lastIndexOf(".")) || Infinity) + 1
);
$('#image-name').html('.' + extension); // add extension near file name
// temporary store image blob
UPLOADED_IMAGE = imageBlob
});
}
});
}
function _retrieveImageFromClipboardAsBlob(pasteEvent, callback){
if(pasteEvent.clipboardData == false) {
if(typeof(callback) == "function"){
callback(undefined);
}
};
var items = pasteEvent.clipboardData.items;
if(items == undefined){
if(typeof(callback) == "function"){
callback(undefined);
}
};
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") == -1) continue;
var blob = items[i].getAsFile();
if(typeof(callback) == "function") {
callback(blob);
}
}
};
// removes modal from dom
function _destroyModalCallback() {
var modal = $('#clipboardPreviewModal');
modal.on('hidden.bs.modal', function() {
modal.modal('hide').promise().done(function() {
modal.remove();
});
UPLOADED_IMAGE = {};
});
}
function _closeModal() {
_hideModalForGood();
$("#clipboardPreviewModal").remove();
}
// $(..).modal('hide') don't work properly so here we manually remove the
// displayed modal
function _hideModalForGood(){
$("#clipboardPreviewModal").removeClass("in");
$(".modal-backdrop").remove();
$('body').removeClass('modal-open');
$('body').css('padding-right', '');
$("#clipboardPreviewModal").hide();
}
function _addImageCallback() {
$('[data-action="addImageFormClipboard"]').on('click', function() {
var inputArray = [];
var newName = $('#clipboardImageName').val();
// check if the name is set
if( newName && newName.length > 0 ) {
var extension = UPLOADED_IMAGE.name.slice(
(Math.max(0, UPLOADED_IMAGE.name.lastIndexOf(".")) || Infinity) + 1
);
// hack to inject custom name in File object
var name = newName + '.' + extension;
var blob = UPLOADED_IMAGE.slice(0, UPLOADED_IMAGE.size, UPLOADED_IMAGE.type);
// make new blob with the correct name;
var newFile = new File([blob], name, { type: UPLOADED_IMAGE.type });
inputArray.push(newFile);
} else { // return the default name
inputArray.push(UPLOADED_IMAGE);
}
// close modal
_closeModal();
// reuse file upload from drag'n drop :)
if(LOCATION === 'steps') {
DragNDropSteps.init(inputArray);
} else {
DragNDropResults.init(inputArray);
}
// clear all uploaded images
UPLOADED_IMAGE = {};
});
}
// Generate modal html and hook callbacks
function _clipboardPasteModal() {
var html = '<div id="clipboardPreviewModal" class="modal fade" ';
html += 'tabindex="-1" role="dialog" aria-hidden="true">';
html += '<div class="modal-dialog" role="document">';
html += '<div class="modal-content"><div class="modal-header">';
html += '<button type="button" class="close" data-dismiss="modal"';
html += ' aria-label="Close"><span aria-hidden="true">&times;</span>';
html += '</button><h4 class="modal-title"><%= I18n.t('assets.from_clipboard.modal_title') %></h4>';
html += '</div><div class="modal-body"><p><strong><%= I18n.t('assets.from_clipboard.image_preview') %></strong></p>';
html += '<canvas style="border:1px solid grey;max-width:400px;max-height:300px" id="clipboardPreview" />';
html += '<p><strong><%= I18n.t('assets.from_clipboard.file_name') %></strong></p>';
html += '<div class="input-group">';
html += '<input id="clipboardImageName" type="text" class="form-control" ';
html += 'placeholder="<%= I18n.t('assets.from_clipboard.file_name_placeholder') %>" aria-describedby="image-name">';
html += '<span class="input-group-addon" id="image-name"></span></div>';
html += '</div><div class="modal-footer">';
html += '<button type="button" class="btn btn-default" data-dismiss="modal"><%= I18n.t('general.cancel') %></button>';
html += '<button type="button" class="btn btn-success" data-action="addImageFormClipboard"><%= I18n.t('assets.from_clipboard.add_image') %></button>';
html += '</div></div></div></div><!-- /.modal -->';
return $(html).appendTo($('body')).promise().done(function() {
// display modal
$('#clipboardPreviewModal').modal('show');
// add callback to remove modal from DOM
_destroyModalCallback();
// add callback on image submit
_addImageCallback();
});
}
return Object.freeze({
init: init,
destroy: destroy
});
})();
// Module to handle file uploading in Steps
global.DragNDropSteps = (function() {
var droppedFiles = [];
var filesValid = true;
var totalSize = 0;
var fileMaxSizeMb;
var fileMaxSize;
function checkErrors() {
// Check for error
var errors = $('.attachments.edit').find('.dnd-error').length;
if (errors > 0){
$('#new-step-assets-tab').addClass('has-error');
} else {
$('#new-step-assets-tab').removeClass('has-error');
filesValid = true;
}
}
function init(files) {
fileMaxSizeMb = $(document.body).data('file-max-size-mb');
fileMaxSize = fileMaxSizeMb * 1024 * 1024;
for(var i = 0; i < files.length; i++) {
droppedFiles.push(files[i]);
}
listItems();
checkErrors();
$('.attachments.edit').find('.remove-icon .fa-trash').click(() => {
setTimeout(() => {checkErrors()}, 0);
})
}
// return the status of files if they are ready to submit
function filesStatus() {
return filesValid;
}
function clearFiles() {
droppedFiles = [];
}
// loops through a list of files and display each file in a separate panel
function listItems() {
totalSize = 0;
_enableSubmitButton();
$('.attachment-placeholder.new').remove();
_dragNdropAssetsOff();
for(var i = 0; i < droppedFiles.length; i++) {
$('.attachments.edit')
.append(_uploadedAssetPreview(droppedFiles[i], i))
.promise()
.done(function() {
_removeItemHandler(i);
});
}
_validateTotalSize();
dragNdropAssetsInit('steps');
}
// append the files to the form before submit
function appendFilesToForm(ev) {
var regex = /step\[assets_attributes\]\[[0-9]*\]\[id\]/;
var prevEls = $('input').filter(function() {
return this.name.match(regex);
});
var fd = new FormData($(ev.target).closest('form').get(0));
for(var i = 0; i < droppedFiles.length; i++) {
var index = i + prevEls.length;
var name = 'step[assets_attributes][' + index + '][file]';
fd.append(name, droppedFiles[i]);
}
filesValid = true;
totalSize = 0;
_dragNdropAssetsOff();
return fd;
}
function _disableSubmitButton() {
$('.step-save').prop('disabled', true);
}
function _enableSubmitButton() {
$('.step-save').prop('disabled', false);
}
function _filerAndCheckFiles() {
for(var i = 0; i < droppedFiles.length; i++) {
if(droppedFiles[i].isValid == false) {
return false;
}
}
return (droppedFiles.length > 0);
}
function _validateFilesSize(file) {
var fileSize = file.size;
totalSize += parseInt(fileSize);
if(fileSize > fileMaxSize) {
file.isValid = false;
_disableSubmitButton();
return "<p class='dnd-error'>" + I18n.t('general.file.size_exceeded', { file_size: fileMaxSizeMb }) + '</p>';
}
return '';
}
function _validateTotalSize() {
if(totalSize > fileMaxSize) {
filesValid = false;
_disableSubmitButton();
$.each($('.panel-step-attachment-new'), function() {
if(!$(this).find('p').hasClass('dnd-total-error')) {
$(this)
.find('.panel-body')
.append("<p class='dnd-total-error'>" + I18n.t('general.file.total_size', { size: fileMaxSizeMb }) + '</p>');
}
});
} else {
$('.dnd-total-error').remove();
if(_filerAndCheckFiles()) {
filesValid = true;
_enableSubmitButton();
}
}
}
function _uploadedAssetPreview(asset, i) {
var html = '<div class="attachment-placeholder pull-left new">';
html +='<div class="attachment-thumbnail no-shadow %>">';
html +='<i class="fas fa-image"></i>';
html +='</div>';
html +='<div class="attachment-label">' + truncateLongString(asset.name, <%= Constants::FILENAME_TRUNCATION_LENGTH %>);
html += '</div>';
html +='<div class="spencer-bonnet-modif">';
html +='</div>';
html +='<div class="remove-icon pull-right">';
html +='<a data-item-id="' + i + '" href="#">';
html +='<span class="fas fa-trash"></span>';
html +='</a> </div>';
html += _validateFilesSize(asset);
html +='</div>';
return html;
}
function _removeItemHandler(id) {
$('[data-item-id="' + id +'"]').off('click').on('click', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
var $el = $(this);
var index = $el.data('item-id');
totalSize -= parseInt(droppedFiles[index].size);
droppedFiles.splice(index, 1);
listItems();
});
}
function _dragNdropAssetsOff() {
$('body').off('drag dragstart dragend dragover dragenter dragleave drop');
$('.is-dragover').hide();
// remove listeners for clipboard images
copyFromClipboard.destroy();
}
return Object.freeze({
init: init,
appendFilesToForm: appendFilesToForm,
listItems: listItems,
filesStatus: filesStatus,
clearFiles: clearFiles,
checkErrors: checkErrors
});
})();
// Module to handle file uploading in Results
global.DragNDropResults = (function() {
var droppedFiles = [];
var isValid = true;
var totalSize = 0;
var fileMaxSizeMb;
var fileMaxSize;
function init(files) {
fileMaxSizeMb = $(document.body).data('file-max-size-mb');
fileMaxSize = fileMaxSizeMb * 1024 * 1024;
for(var i = 0; i < files.length; i++) {
droppedFiles.push(files[i]);
}
listItems();
}
// return the status of files if they are ready to submit
function filesStatus() {
return isValid;
}
// loops through a list of files and display each file in a separate panel
function listItems() {
totalSize = 0;
$('.panel-result-attachment-new').remove();
if(droppedFiles.length < 1) {
_disableSubmitButton();
} else {
_dragNdropAssetsOff();
for(var i = 0; i < droppedFiles.length; i++) {
$('#new-result-assets-select')
.after(_uploadedAssetPreview(droppedFiles[i], i))
.promise()
.done(function() {
_removeItemHandler(i);
});
}
_validateTotalSize();
dragNdropAssetsInit('results');
}
}
// appent the files to the form before submit
function _appendFilesToForm() {
var regex = /result\[assets_attributes\]\[[0-9]*\]\[id\]/;
var prevEls = $('input').filter(function() {
return this.name.match(regex);
});
var fd = new FormData();
var result_names = [];
$.each($('input[rel="results[name]"]'), function() {
result_names.push($(this).val());
});
result_names.reverse();
for(var i = 0; i < droppedFiles.length; i++) {
var index = i + prevEls.length;
var file_name = 'results_files[' + index + ']';
fd.append(file_name, droppedFiles[i]);
fd.append('results_names[' + i + ']', result_names[i]);
}
destroyAll();
return fd;
}
function _disableSubmitButton() {
$('.save-result').prop('disabled', true);
}
function _enableSubmitButton() {
$('.save-result').prop('disabled', false);
}
function _filerAndCheckFiles() {
for(var i = 0; i < droppedFiles.length; i++) {
if(droppedFiles[i].isValid == false) {
return false;
}
}
return (droppedFiles.length > 0);
}
function _validateFilesSize(file) {
var fileSize = file.size;
totalSize += parseInt(fileSize);
if(fileSize > fileMaxSize) {
file.isValid = false;
_disableSubmitButton();
return "<p class='dnd-error'>" + I18n.t('general.file.size_exceeded', { file_size: fileMaxSizeMb }) + '</p>';
}
return '';
}
function _validateTotalSize() {
if(totalSize > fileMaxSize) {
isValid = false;
_disableSubmitButton();
$.each($('.panel-result-attachment-new'), function() {
if(!$(this).find('p').hasClass('dnd-total-error')) {
$(this)
.find('.panel-body')
.append("<p class='dnd-total-error'>" + I18n.t('general.file.total_size', { size: fileMaxSizeMb }) + '</p>');
}
});
} else {
$('.dnd-total-error').remove();
if(_filerAndCheckFiles()) {
isValid = true;
_enableSubmitButton();
}
}
}
function validateTextSize(input) {
if(input.value.length > <%= Constants::NAME_MAX_LENGTH %>) {
$(input).parent().find('.dnd-error').remove();
$(input).after("<p class='dnd-error'><%= I18n.t('general.text.length_too_long', max_length: Constants::NAME_MAX_LENGTH) %></p>");
isValid = false;
} else {
$(input).parent().find('.dnd-error').remove();
isValid = true;
}
}
function _uploadedAssetPreview(asset, i) {
var html = '<div class="panel panel-default panel-result-attachment-new">';
html += '<div class="panel-heading">';
html += '<span class="fas fa-paperclip"></span>';
html += '<%= I18n.t 'assets.drag_n_drop.file_label' %>';
html += '<div class="pull-right">';
html += '<a data-item-id="' + i + '" href="#">';
html += '<span class="fas fa-times"></span></a></div></div>';
html += '<div class="panel-body"><div class="form-group">';
html += '<label class="control-label">Name</label>';
html += '<input type="text" class="form-control" ';
html += 'onChange="DragNDropResults.validateTextSize(this)"';
html += ' rel="results[name]" name="results[name][' + i + ']">';
html += '</div><div class="form-group"><label class="control-label">';
html += '<%= I18n.t 'assets.drag_n_drop.file_label' %>:</label> ';
html += truncateLongString(asset.name,
<%= Constants::FILENAME_TRUNCATION_LENGTH %>);
html += _validateFilesSize(asset);
html += '</div></div>';
return html;
}
function _removeItemHandler(id) {
$('[data-item-id="' + id +'"]').off('click').on('click', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
var $el = $(this);
var index = $el.data('item-id');
totalSize -= parseInt(droppedFiles[index].size);
droppedFiles.splice(index, 1);
listItems();
});
}
function processResult(button) {
if(isValid && _filerAndCheckFiles()) {
animateSpinner();
$.ajax({
url: $(button).attr('data-href'),
method: 'POST',
data: _appendFilesToForm(),
contentType: false,
processData: false,
success: function(data) {
animateSpinner(null, false);
$('#new-result-assets-select').parent().remove();
$(data.html).prependTo('#results').promise().done(function() {
$.each($('[data-container="new-reports"]').find('.result'),
function() {
initFormSubmitLinks($(this));
ResutlAssets.applyEditResultAssetCallback();
Results.applyCollapseLinkCallBack();
Results.toggleResultEditButtons(true);
FilePreviewModal.init();
Comments.init();
ResutlAssets.initNewResultAsset();
Results.expandResult($(this));
});
});
$('#results-toolbar').show();
},
error: function() {
animateSpinner();
location.reload();
}
})
}
}
function destroyAll() {
_dragNdropAssetsOff();
droppedFiles = [];
isValid = true;
totalSize = 0;
}
function _dragNdropAssetsOff() {
$('body').off('drag dragstart dragend dragover dragenter dragleave drop');
$('.is-dragover').hide();
}
return Object.freeze({
init: init,
listItems: listItems,
destroyAll: destroyAll,
filesStatus: filesStatus,
validateTextSize: validateTextSize,
processResult: processResult
});
})();
global.dragNdropAssetsInit = function(location) {
var in_window = true;
$('body').on('drag dragstart dragend dragover dragenter dragleave drop',
function(e) {
e.preventDefault();
e.stopPropagation();
}).on('dragover', function() {
in_window = true;
$('.is-dragover').show();
}).on('dragleave', function() {
in_window = false;
setTimeout(function() {
if(!in_window) {
$('.is-dragover').hide();
}
}, 5000);
}).on('drop', function(e) {
$('.is-dragover').hide();
var files = e.originalEvent.dataTransfer.files;
if(location === 'steps') {
DragNDropSteps.init(files);
} else {
DragNDropResults.init(files);
}
});
copyFromClipboard.init(location);
}
})(window);