diff options
Diffstat (limited to 'apps/files/js/file-upload.js')
-rw-r--r-- | apps/files/js/file-upload.js | 401 |
1 files changed, 165 insertions, 236 deletions
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 9a6e27d30e3..3257ded7b89 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -18,7 +18,7 @@ * - TODO music upload button */ -/* global Files, FileList, jQuery, oc_requesttoken, humanFileSize, getUniqueName */ +/* global jQuery, oc_requesttoken, humanFileSize, FileList */ /** * Function that will allow us to know if Ajax uploads are supported @@ -48,8 +48,28 @@ function supportAjaxUploadWithProgress() { } /** + * Add form data into the given form data + * + * @param {Array|Object} formData form data which can either be an array or an object + * @param {Object} newData key-values to add to the form data + * + * @return updated form data + */ +function addFormData(formData, newData) { + // in IE8, formData is an array instead of object + if (_.isArray(formData)) { + _.each(newData, function(value, key) { + formData.push({name: key, value: value}); + }); + } else { + formData = _.extend(formData, newData); + } + return formData; +} + +/** * keeps track of uploads in progress and implements callbacks for the conflicts dialog - * @type {OC.Upload} + * @namespace */ OC.Upload = { _uploads: [], @@ -75,6 +95,9 @@ OC.Upload = { this._uploads.push(jqXHR); } }, + showUploadCancelMessage: _.debounce(function() { + OC.Notification.showTemporary(t('files', 'Upload cancelled.'), {timeout: 10}); + }, 500), /** * Checks the currently known uploads. * returns true if any hxr has the state 'pending' @@ -139,7 +162,10 @@ OC.Upload = { if (data.data) { data.data.append('resolution', 'replace'); } else { - data.formData.push({name:'resolution', value:'replace'}); //hack for ie8 + if (!data.formData) { + data.formData = {}; + } + addFormData(data.formData, {resolution: 'replace'}); } data.submit(); }, @@ -152,7 +178,10 @@ OC.Upload = { if (data.data) { data.data.append('resolution', 'autorename'); } else { - data.formData.push({name:'resolution', value:'autorename'}); //hack for ie8 + if (!data.formData) { + data.formData = {}; + } + addFormData(data.formData, {resolution: 'autorename'}); } data.submit(); }, @@ -164,8 +193,9 @@ OC.Upload = { } }, /** - * TODO checks the list of existing files prior to uploading and shows a simple dialog to choose + * checks the list of existing files prior to uploading and shows a simple dialog to choose * skip all, replace all or choose which files to keep + * * @param {array} selection of files to upload * @param {object} callbacks - object with several callback methods * @param {function} callbacks.onNoConflicts @@ -175,12 +205,42 @@ OC.Upload = { * @param {function} callbacks.onCancel */ checkExistingFiles: function (selection, callbacks) { - // TODO check filelist before uploading and show dialog on conflicts, use callbacks + var fileList = FileList; + var conflicts = []; + // only keep non-conflicting uploads + selection.uploads = _.filter(selection.uploads, function(upload) { + var fileInfo = fileList.findFile(upload.files[0].name); + if (fileInfo) { + conflicts.push([ + // original + _.extend(fileInfo, { + directory: fileInfo.directory || fileInfo.path || fileList.getCurrentDirectory() + }), + // replacement (File object) + upload + ]); + return false; + } + return true; + }); + if (conflicts.length) { + // wait for template loading + OC.dialogs.fileexists(null, null, null, OC.Upload).done(function() { + _.each(conflicts, function(conflictData) { + OC.dialogs.fileexists(conflictData[1], conflictData[0], conflictData[1].files[0], OC.Upload); + }); + }); + } + + // upload non-conflicting files + // note: when reaching the server they might still meet conflicts + // if the folder was concurrently modified, these will get added + // to the already visible dialog, if applicable callbacks.onNoConflicts(selection); }, _hideProgressBar: function() { - $('#uploadprogresswrapper input.stop').fadeOut(); + $('#uploadprogresswrapper .stop').fadeOut(); $('#uploadprogressbar').fadeOut(function() { $('#file_upload_start').trigger(new $.Event('resized')); }); @@ -191,10 +251,30 @@ OC.Upload = { $('#file_upload_start').trigger(new $.Event('resized')); }, + /** + * Returns whether the given file is known to be a received shared file + * + * @param {Object} file file + * @return {bool} true if the file is a shared file + */ + _isReceivedSharedFile: function(file) { + if (!window.FileList) { + return false; + } + var $tr = window.FileList.findFileEl(file.name); + if (!$tr.length) { + return false; + } + + return ($tr.attr('data-mounttype') === 'shared-root' && $tr.attr('data-mime') !== 'httpd/unix-directory'); + }, + init: function() { + var self = this; if ( $('#file_upload_start').exists() ) { var file_upload_param = { dropZone: $('#content'), // restrict dropZone to content div + pasteZone: null, autoUpload: false, sequentialUploads: true, //singleFileUploads is on by default, so the data.files array will always have length 1 @@ -233,7 +313,8 @@ OC.Upload = { data.originalFiles.selection = { uploads: [], filesToUpload: data.originalFiles.length, - totalBytes: 0 + totalBytes: 0, + biggestFileBytes: 0 }; } var selection = data.originalFiles.selection; @@ -258,11 +339,20 @@ OC.Upload = { // in case folder drag and drop is not supported file will point to a directory // http://stackoverflow.com/a/20448357 if ( ! file.type && file.size%4096 === 0 && file.size <= 102400) { + var dirUploadFailure = false; try { var reader = new FileReader(); reader.readAsBinaryString(file); } catch (NS_ERROR_FILE_ACCESS_DENIED) { //file is a directory + dirUploadFailure = true; + } + if (file.size === 0) { + // file is empty or a directory + dirUploadFailure = true; + } + + if (dirUploadFailure) { data.textStatus = 'dirorzero'; data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes', @@ -271,15 +361,22 @@ OC.Upload = { } } - // add size - selection.totalBytes += file.size; + // only count if we're not overwriting an existing shared file + if (self._isReceivedSharedFile(file)) { + file.isReceivedShare = true; + } else { + // add size + selection.totalBytes += file.size; + // update size of biggest file + selection.biggestFileBytes = Math.max(selection.biggestFileBytes, file.size); + } - // check PHP upload limit - if (selection.totalBytes > $('#upload_limit').val()) { + // check PHP upload limit against biggest file + if (selection.biggestFileBytes > $('#upload_limit').val()) { data.textStatus = 'sizeexceedlimit'; data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', { - 'size1': humanFileSize(selection.totalBytes), + 'size1': humanFileSize(selection.biggestFileBytes), 'size2': humanFileSize($('#upload_limit').val()) }); } @@ -349,27 +446,38 @@ OC.Upload = { }, submit: function(e, data) { OC.Upload.rememberUpload(data); - if ( ! data.formData ) { - var fileDirectory = ''; - if(typeof data.files[0].relativePath !== 'undefined') { - fileDirectory = data.files[0].relativePath; - } - // noone set update parameters, we set the minimum - data.formData = { - requesttoken: oc_requesttoken, - dir: data.targetDir || FileList.getCurrentDirectory(), - file_directory: fileDirectory - }; + if (!data.formData) { + data.formData = {}; + } + + var fileDirectory = ''; + if(typeof data.files[0].relativePath !== 'undefined') { + fileDirectory = data.files[0].relativePath; } + + var params = { + requesttoken: oc_requesttoken, + dir: data.targetDir || FileList.getCurrentDirectory(), + file_directory: fileDirectory, + }; + if (data.files[0].isReceivedShare) { + params.isReceivedShare = true; + } + + addFormData(data.formData, params); }, fail: function(e, data) { OC.Upload.log('fail', e, data); if (typeof data.textStatus !== 'undefined' && data.textStatus !== 'success' ) { if (data.textStatus === 'abort') { - OC.Notification.show(t('files', 'Upload cancelled.')); + OC.Upload.showUploadCancelMessage(); } else { // HTTP connection problem - OC.Notification.show(data.errorThrown); + var message = t('files', 'Error uploading file "{fileName}": {message}', { + fileName: data.files[0].name, + message: data.errorThrown + }); + OC.Notification.show(message, {timeout: 0, type: 'error'}); if (data.result) { var result = JSON.parse(data.result); if (result && result[0] && result[0].data && result[0].data.code === 'targetnotfound') { @@ -378,10 +486,6 @@ OC.Upload = { } } } - //hide notification after 10 sec - setTimeout(function() { - OC.Notification.hide(); - }, 10000); } OC.Upload.deleteUpload(data); }, @@ -400,7 +504,7 @@ OC.Upload = { //fetch response from iframe response = data.result[0].body.innerText; } - var result = $.parseJSON(response); + var result = JSON.parse(response); delete data.jqXHR; @@ -414,16 +518,28 @@ OC.Upload = { data.textStatus = 'servererror'; data.errorThrown = t('files', 'Could not get result from server.'); fu._trigger('fail', e, data); + } else if (result[0].status === 'readonly') { + var original = result[0]; + var replacement = data.files[0]; + OC.dialogs.fileexists(data, original, replacement, OC.Upload); } else if (result[0].status === 'existserror') { //show "file already exists" dialog var original = result[0]; var replacement = data.files[0]; - OC.dialogs.fileexists(data, original, replacement, OC.Upload, fu); + OC.dialogs.fileexists(data, original, replacement, OC.Upload); } else if (result[0].status !== 'success') { //delete data.jqXHR; data.textStatus = 'servererror'; data.errorThrown = result[0].data.message; // error message has been translated on server fu._trigger('fail', e, data); + } else { // Successful upload + // Checking that the uploaded file is the last one and contained in the current directory + if (data.files[0] === data.originalFiles[data.originalFiles.length - 1] && + result[0].directory === FileList.getCurrentDirectory()) { + // Scroll to the last uploaded file and highlight all of them + var fileList = _.pluck(data.originalFiles, 'name'); + FileList.highlightFiles(fileList); + } } }, /** @@ -456,13 +572,13 @@ OC.Upload = { OC.Upload.log('progress handle fileuploadadd', e, data); //show cancel button //if (data.dataType !== 'iframe') { //FIXME when is iframe used? only for ie? - // $('#uploadprogresswrapper input.stop').show(); + // $('#uploadprogresswrapper .stop').show(); //} }); // add progress handlers fileupload.on('fileuploadstart', function(e, data) { OC.Upload.log('progress handle fileuploadstart', e, data); - $('#uploadprogresswrapper input.stop').show(); + $('#uploadprogresswrapper .stop').show(); $('#uploadprogresswrapper .label').show(); $('#uploadprogressbar').progressbar({value: 0}); $('#uploadprogressbar .ui-progressbar-value'). @@ -552,6 +668,21 @@ OC.Upload = { } }); + } else { + // for all browsers that don't support the progress bar + // IE 8 & 9 + + // show a spinner + fileupload.on('fileuploadstart', function() { + $('#upload').addClass('icon-loading'); + $('#upload .icon-upload').hide(); + }); + + // hide a spinner + fileupload.on('fileuploadstop fileuploadfail', function() { + $('#upload').removeClass('icon-loading'); + $('#upload .icon-upload').show(); + }); } } @@ -578,208 +709,6 @@ OC.Upload = { $('#file_upload_start').attr('multiple', 'multiple'); } - $(document).click(function(ev) { - // do not close when clicking in the dropdown - if ($(ev.target).closest('#new').length){ - return; - } - $('#new>ul').hide(); - $('#new').removeClass('active'); - if ($('#new .error').length > 0) { - $('#new .error').tipsy('hide'); - } - $('#new li').each(function(i,element) { - if ($(element).children('p').length === 0) { - $(element).children('form').remove(); - $(element).append('<p>' + $(element).data('text') + '</p>'); - } - }); - }); - $('#new').click(function(event) { - event.stopPropagation(); - }); - $('#new>a').click(function() { - $('#new>ul').toggle(); - $('#new').toggleClass('active'); - }); - $('#new li').click(function() { - if ($(this).children('p').length === 0) { - return; - } - - $('#new .error').tipsy('hide'); - - $('#new li').each(function(i, element) { - if ($(element).children('p').length === 0) { - $(element).children('form').remove(); - $(element).append('<p>' + $(element).data('text') + '</p>'); - } - }); - - var type = $(this).data('type'); - var text = $(this).children('p').text(); - $(this).data('text', text); - $(this).children('p').remove(); - - // add input field - var form = $('<form></form>'); - var input = $('<input type="text">'); - var newName = $(this).attr('data-newname') || ''; - if (newName) { - input.val(newName); - } - form.append(input); - $(this).append(form); - var lastPos; - var checkInput = function () { - var filename = input.val(); - if (type === 'web' && filename.length === 0) { - throw t('files', 'URL cannot be empty'); - } else if (type !== 'web' && ! Files.isFileNameValid(filename)) { - // Files.isFileNameValid(filename) throws an exception itself - } else if (FileList.inList(filename)) { - throw t('files', '{new_name} already exists', {new_name: filename}); - } else { - return true; - } - }; - - // verify filename on typing - input.keyup(function(event) { - try { - checkInput(); - input.tipsy('hide'); - input.removeClass('error'); - } catch (error) { - input.attr('title', error); - input.tipsy({gravity: 'w', trigger: 'manual'}); - input.tipsy('show'); - input.addClass('error'); - } - }); - - input.focus(); - // pre select name up to the extension - lastPos = newName.lastIndexOf('.'); - if (lastPos === -1) { - lastPos = newName.length; - } - input.selectRange(0, lastPos); - form.submit(function(event) { - event.stopPropagation(); - event.preventDefault(); - try { - checkInput(); - var newname = input.val(); - if (FileList.lastAction) { - FileList.lastAction(); - } - var name = FileList.getUniqueName(newname); - if (newname !== name) { - FileList.checkName(name, newname, true); - var hidden = true; - } else { - var hidden = false; - } - switch(type) { - case 'file': - $.post( - OC.filePath('files', 'ajax', 'newfile.php'), - { - dir: FileList.getCurrentDirectory(), - filename: name - }, - function(result) { - if (result.status === 'success') { - FileList.add(result.data, {hidden: hidden, animate: true}); - } else { - OC.dialogs.alert(result.data.message, t('core', 'Could not create file')); - } - } - ); - break; - case 'folder': - $.post( - OC.filePath('files','ajax','newfolder.php'), - { - dir: FileList.getCurrentDirectory(), - foldername: name - }, - function(result) { - if (result.status === 'success') { - FileList.add(result.data, {hidden: hidden, animate: true}); - } else { - OC.dialogs.alert(result.data.message, t('core', 'Could not create folder')); - } - } - ); - break; - case 'web': - if (name.substr(0, 8) !== 'https://' && name.substr(0, 7) !== 'http://') { - name = 'http://' + name; - } - var localName = name; - if (localName.substr(localName.length-1, 1) === '/') {//strip / - localName = localName.substr(0, localName.length-1); - } - if (localName.indexOf('/')) { //use last part of url - localName = localName.split('/').pop(); - } else { //or the domain - localName = (localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.', ''); - } - localName = FileList.getUniqueName(localName); - //IE < 10 does not fire the necessary events for the progress bar. - if ($('html.lte9').length === 0) { - $('#uploadprogressbar').progressbar({value: 0}); - OC.Upload._showProgressBar(); - } - - var eventSource = new OC.EventSource( - OC.filePath('files', 'ajax', 'newfile.php'), - { - dir: FileList.getCurrentDirectory(), - source: name, - filename: localName - } - ); - eventSource.listen('progress', function(progress) { - //IE < 10 does not fire the necessary events for the progress bar. - if ($('html.lte9').length === 0) { - $('#uploadprogressbar').progressbar('value',progress); - } - }); - eventSource.listen('success', function(data) { - var file = data; - OC.Upload._hideProgressBar(); - - FileList.add(file, {hidden: hidden, animate: true}); - }); - eventSource.listen('error', function(error) { - OC.Upload._hideProgressBar(); - var message = (error && error.message) || t('core', 'Error fetching URL'); - OC.Notification.show(message); - //hide notification after 10 sec - setTimeout(function() { - OC.Notification.hide(); - }, 10000); - }); - break; - } - var li = form.parent(); - form.remove(); - /* workaround for IE 9&10 click event trap, 2 lines: */ - $('input').first().focus(); - $('#content').focus(); - li.append('<p>' + li.data('text') + '</p>'); - $('#new>a').click(); - } catch (error) { - input.attr('title', error); - input.tipsy({gravity: 'w', trigger: 'manual'}); - input.tipsy('show'); - input.addClass('error'); - } - }); - }); window.file_upload_param = file_upload_param; return file_upload_param; } |