]> source.dussan.org Git - nextcloud-server.git/commitdiff
Added unit tests for "add()" method for file upload
authorVincent Petry <pvince81@owncloud.com>
Thu, 6 Mar 2014 12:49:57 +0000 (13:49 +0100)
committerVincent Petry <pvince81@owncloud.com>
Thu, 6 Mar 2014 12:53:34 +0000 (13:53 +0100)
- Added OC.Upload.init() to make the code testable
- Added unit tests for the add() method of the uploader with some error
  cases

apps/files/js/file-upload.js
apps/files/tests/js/fileUploadSpec.js [new file with mode: 0644]

index aa85644cefb0048feac57085c0a74487802aac0a..b9c4dc941f7c589b00617270df12496e2ac88062 100644 (file)
@@ -177,549 +177,554 @@ OC.Upload = {
        checkExistingFiles: function (selection, callbacks) {
                // TODO check filelist before uploading and show dialog on conflicts, use callbacks
                callbacks.onNoConflicts(selection);
-       }
-};
-
-$(document).ready(function() {
-
-       if ( $('#file_upload_start').exists() ) {
-
-               var file_upload_param = {
-                       dropZone: $('#content'), // restrict dropZone to content div
-                       autoUpload: false,
-                       sequentialUploads: true,
-                       //singleFileUploads is on by default, so the data.files array will always have length 1
-                       /**
-                        * on first add of every selection
-                        * - check all files of originalFiles array with files in dir
-                        * - on conflict show dialog
-                        *   - skip all -> remember as single skip action for all conflicting files
-                        *   - replace all -> remember as single replace action for all conflicting files
-                        *   - choose -> show choose dialog
-                        *     - mark files to keep
-                        *       - when only existing -> remember as single skip action
-                        *       - when only new -> remember as single replace action
-                        *       - when both -> remember as single autorename action
-                        * - start uploading selection
-                        * @param {object} e
-                        * @param {object} data
-                        * @returns {boolean}
-                        */
-                       add: function(e, data) {
-                               OC.Upload.log('add', e, data);
-                               var that = $(this);
-
-                               // we need to collect all data upload objects before starting the upload so we can check their existence
-                               // and set individual conflict actions. unfortunately there is only one variable that we can use to identify
-                               // the selection a data upload is part of, so we have to collect them in data.originalFiles
-                               // turning singleFileUploads off is not an option because we want to gracefully handle server errors like
-                               // already exists
-
-                               // create a container where we can store the data objects
-                               if ( ! data.originalFiles.selection ) {
-                                       // initialize selection and remember number of files to upload
-                                       data.originalFiles.selection = {
-                                               uploads: [],
-                                               filesToUpload: data.originalFiles.length,
-                                               totalBytes: 0
-                                       };
-                               }
-                               var selection = data.originalFiles.selection;
-
-                               // add uploads
-                               if ( selection.uploads.length < selection.filesToUpload ) {
-                                       // remember upload
-                                       selection.uploads.push(data);
-                               }
-
-                               //examine file
-                               var file = data.files[0];
-                               try {
-                                       // FIXME: not so elegant... need to refactor that method to return a value
-                                       Files.isFileNameValid(file.name, FileList.getCurrentDirectory());
-                               }
-                               catch (errorMessage) {
-                                       data.textStatus = 'invalidcharacters';
-                                       data.errorThrown = errorMessage;
-                               }
+       },
 
-                               if (file.type === '' && file.size === 4096) {
-                                       data.textStatus = 'dirorzero';
-                                       data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes',
-                                               {filename: file.name}
-                                       );
-                               }
+       init: function() {
+               if ( $('#file_upload_start').exists() ) {
+
+                       var file_upload_param = {
+                               dropZone: $('#content'), // restrict dropZone to content div
+                               autoUpload: false,
+                               sequentialUploads: true,
+                               //singleFileUploads is on by default, so the data.files array will always have length 1
+                               /**
+                                * on first add of every selection
+                                * - check all files of originalFiles array with files in dir
+                                * - on conflict show dialog
+                                *   - skip all -> remember as single skip action for all conflicting files
+                                *   - replace all -> remember as single replace action for all conflicting files
+                                *   - choose -> show choose dialog
+                                *     - mark files to keep
+                                *       - when only existing -> remember as single skip action
+                                *       - when only new -> remember as single replace action
+                                *       - when both -> remember as single autorename action
+                                * - start uploading selection
+                                * @param {object} e
+                                * @param {object} data
+                                * @returns {boolean}
+                                */
+                               add: function(e, data) {
+                                       OC.Upload.log('add', e, data);
+                                       var that = $(this);
+
+                                       // we need to collect all data upload objects before starting the upload so we can check their existence
+                                       // and set individual conflict actions. unfortunately there is only one variable that we can use to identify
+                                       // the selection a data upload is part of, so we have to collect them in data.originalFiles
+                                       // turning singleFileUploads off is not an option because we want to gracefully handle server errors like
+                                       // already exists
+
+                                       // create a container where we can store the data objects
+                                       if ( ! data.originalFiles.selection ) {
+                                               // initialize selection and remember number of files to upload
+                                               data.originalFiles.selection = {
+                                                       uploads: [],
+                                                       filesToUpload: data.originalFiles.length,
+                                                       totalBytes: 0
+                                               };
+                                       }
+                                       var selection = data.originalFiles.selection;
 
-                               // add size
-                               selection.totalBytes += file.size;
+                                       // add uploads
+                                       if ( selection.uploads.length < selection.filesToUpload ) {
+                                               // remember upload
+                                               selection.uploads.push(data);
+                                       }
 
-                               // check PHP upload limit
-                               if (selection.totalBytes > $('#upload_limit').val()) {
-                                       data.textStatus = 'sizeexceedlimit';
-                                       data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', {
-                                               'size1': humanFileSize(selection.totalBytes),
-                                               'size2': humanFileSize($('#upload_limit').val())
-                                       });
-                               }
+                                       //examine file
+                                       var file = data.files[0];
+                                       try {
+                                               // FIXME: not so elegant... need to refactor that method to return a value
+                                               Files.isFileNameValid(file.name, FileList.getCurrentDirectory());
+                                       }
+                                       catch (errorMessage) {
+                                               data.textStatus = 'invalidcharacters';
+                                               data.errorThrown = errorMessage;
+                                       }
 
-                               // check free space
-                               if (selection.totalBytes > $('#free_space').val()) {
-                                       data.textStatus = 'notenoughspace';
-                                       data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', {
-                                               'size1': humanFileSize(selection.totalBytes),
-                                               'size2': humanFileSize($('#free_space').val())
-                                       });
-                               }
+                                       if (file.type === '' && file.size === 4096) {
+                                               data.textStatus = 'dirorzero';
+                                               data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes',
+                                                       {filename: file.name}
+                                               );
+                                       }
 
-                               // end upload for whole selection on error
-                               if (data.errorThrown) {
-                                       // trigger fileupload fail
-                                       var fu = that.data('blueimp-fileupload') || that.data('fileupload');
-                                       fu._trigger('fail', e, data);
-                                       return false; //don't upload anything
-                               }
+                                       // add size
+                                       selection.totalBytes += file.size;
 
-                               // check existing files when all is collected
-                               if ( selection.uploads.length >= selection.filesToUpload ) {
+                                       // check PHP upload limit
+                                       if (selection.totalBytes > $('#upload_limit').val()) {
+                                               data.textStatus = 'sizeexceedlimit';
+                                               data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', {
+                                                       'size1': humanFileSize(selection.totalBytes),
+                                                       'size2': humanFileSize($('#upload_limit').val())
+                                               });
+                                       }
 
-                                       //remove our selection hack:
-                                       delete data.originalFiles.selection;
+                                       // check free space
+                                       if (selection.totalBytes > $('#free_space').val()) {
+                                               data.textStatus = 'notenoughspace';
+                                               data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', {
+                                                       'size1': humanFileSize(selection.totalBytes),
+                                                       'size2': humanFileSize($('#free_space').val())
+                                               });
+                                       }
 
-                                       var callbacks = {
+                                       // end upload for whole selection on error
+                                       if (data.errorThrown) {
+                                               // trigger fileupload fail
+                                               var fu = that.data('blueimp-fileupload') || that.data('fileupload');
+                                               fu._trigger('fail', e, data);
+                                               return false; //don't upload anything
+                                       }
 
-                                               onNoConflicts: function (selection) {
-                                                       $.each(selection.uploads, function(i, upload) {
-                                                               upload.submit();
-                                                       });
-                                               },
-                                               onSkipConflicts: function (selection) {
-                                                       //TODO mark conflicting files as toskip
-                                               },
-                                               onReplaceConflicts: function (selection) {
-                                                       //TODO mark conflicting files as toreplace
-                                               },
-                                               onChooseConflicts: function (selection) {
-                                                       //TODO mark conflicting files as chosen
-                                               },
-                                               onCancel: function (selection) {
-                                                       $.each(selection.uploads, function(i, upload) {
-                                                               upload.abort();
-                                                       });
-                                               }
-                                       };
+                                       // check existing files when all is collected
+                                       if ( selection.uploads.length >= selection.filesToUpload ) {
+
+                                               //remove our selection hack:
+                                               delete data.originalFiles.selection;
+
+                                               var callbacks = {
+
+                                                       onNoConflicts: function (selection) {
+                                                               $.each(selection.uploads, function(i, upload) {
+                                                                       upload.submit();
+                                                               });
+                                                       },
+                                                       onSkipConflicts: function (selection) {
+                                                               //TODO mark conflicting files as toskip
+                                                       },
+                                                       onReplaceConflicts: function (selection) {
+                                                               //TODO mark conflicting files as toreplace
+                                                       },
+                                                       onChooseConflicts: function (selection) {
+                                                               //TODO mark conflicting files as chosen
+                                                       },
+                                                       onCancel: function (selection) {
+                                                               $.each(selection.uploads, function(i, upload) {
+                                                                       upload.abort();
+                                                               });
+                                                       }
+                                               };
 
-                                       OC.Upload.checkExistingFiles(selection, callbacks);
+                                               OC.Upload.checkExistingFiles(selection, callbacks);
 
-                               }
+                                       }
 
-                               return true; // continue adding files
-                       },
-                       /**
-                        * called after the first add, does NOT have the data param
-                        * @param {object} e
-                        */
-                       start: function(e) {
-                               OC.Upload.log('start', e, null);
-                       },
-                       submit: function(e, data) {
-                               OC.Upload.rememberUpload(data);
-                               if ( ! data.formData ) {
-                                       // noone set update parameters, we set the minimum
-                                       data.formData = {
-                                               requesttoken: oc_requesttoken,
-                                                                dir: $('#dir').val()
-                                       };
-                               }
-                       },
-                       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.'));
-                                       } else {
-                                               // HTTP connection problem
-                                               OC.Notification.show(data.errorThrown);
-                                               if (data.result) {
-                                                       var result = JSON.parse(data.result);
-                                                       if (result && result[0] && result[0].data && result[0].data.code === 'targetnotfound') {
-                                                               // abort upload of next files if any
-                                                               OC.Upload.cancelUploads();
+                                       return true; // continue adding files
+                               },
+                               /**
+                                * called after the first add, does NOT have the data param
+                                * @param {object} e
+                                */
+                               start: function(e) {
+                                       OC.Upload.log('start', e, null);
+                               },
+                               submit: function(e, data) {
+                                       OC.Upload.rememberUpload(data);
+                                       if ( ! data.formData ) {
+                                               // noone set update parameters, we set the minimum
+                                               data.formData = {
+                                                       requesttoken: oc_requesttoken,
+                                                                        dir: $('#dir').val()
+                                               };
+                                       }
+                               },
+                               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.'));
+                                               } else {
+                                                       // HTTP connection problem
+                                                       OC.Notification.show(data.errorThrown);
+                                                       if (data.result) {
+                                                               var result = JSON.parse(data.result);
+                                                               if (result && result[0] && result[0].data && result[0].data.code === 'targetnotfound') {
+                                                                       // abort upload of next files if any
+                                                                       OC.Upload.cancelUploads();
+                                                               }
                                                        }
                                                }
+                                               //hide notification after 10 sec
+                                               setTimeout(function() {
+                                                       OC.Notification.hide();
+                                               }, 10000);
                                        }
-                                       //hide notification after 10 sec
-                                       setTimeout(function() {
-                                               OC.Notification.hide();
-                                       }, 10000);
-                               }
-                               OC.Upload.deleteUpload(data);
-                       },
-                       /**
-                        * called for every successful upload
-                        * @param {object} e
-                        * @param {object} data
-                        */
-                       done:function(e, data) {
-                               OC.Upload.log('done', e, data);
-                               // handle different responses (json or body from iframe for ie)
-                               var response;
-                               if (typeof data.result === 'string') {
-                                       response = data.result;
-                               } else {
-                                       //fetch response from iframe
-                                       response = data.result[0].body.innerText;
-                               }
-                               var result=$.parseJSON(response);
-
-                               delete data.jqXHR;
-
-                               if (result.status === 'error' && result.data && result.data.message){
-                                       data.textStatus = 'servererror';
-                                       data.errorThrown = result.data.message;
-                                       var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
-                                       fu._trigger('fail', e, data);
-                               } else if (typeof result[0] === 'undefined') {
-                                       data.textStatus = 'servererror';
-                                       data.errorThrown = t('files', 'Could not get result from server.');
-                                       var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
-                                       fu._trigger('fail', e, data);
-                               } else if (result[0].status === 'existserror') {
-                                       //show "file already exists" dialog
-                                       var original = result[0];
-                                       var replacement = data.files[0];
-                                       var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
-                                       OC.dialogs.fileexists(data, original, replacement, OC.Upload, fu);
-                               } 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
-                                       var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
-                                       fu._trigger('fail', e, data);
+                                       OC.Upload.deleteUpload(data);
+                               },
+                               /**
+                                * called for every successful upload
+                                * @param {object} e
+                                * @param {object} data
+                                */
+                               done:function(e, data) {
+                                       OC.Upload.log('done', e, data);
+                                       // handle different responses (json or body from iframe for ie)
+                                       var response;
+                                       if (typeof data.result === 'string') {
+                                               response = data.result;
+                                       } else {
+                                               //fetch response from iframe
+                                               response = data.result[0].body.innerText;
+                                       }
+                                       var result=$.parseJSON(response);
+
+                                       delete data.jqXHR;
+
+                                       if (result.status === 'error' && result.data && result.data.message){
+                                               data.textStatus = 'servererror';
+                                               data.errorThrown = result.data.message;
+                                               var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
+                                               fu._trigger('fail', e, data);
+                                       } else if (typeof result[0] === 'undefined') {
+                                               data.textStatus = 'servererror';
+                                               data.errorThrown = t('files', 'Could not get result from server.');
+                                               var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
+                                               fu._trigger('fail', e, data);
+                                       } else if (result[0].status === 'existserror') {
+                                               //show "file already exists" dialog
+                                               var original = result[0];
+                                               var replacement = data.files[0];
+                                               var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
+                                               OC.dialogs.fileexists(data, original, replacement, OC.Upload, fu);
+                                       } 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
+                                               var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
+                                               fu._trigger('fail', e, data);
+                                       }
+                               },
+                               /**
+                                * called after last upload
+                                * @param {object} e
+                                * @param {object} data
+                                */
+                               stop: function(e, data) {
+                                       OC.Upload.log('stop', e, data);
                                }
-                       },
-                       /**
-                        * called after last upload
-                        * @param {object} e
-                        * @param {object} data
-                        */
-                       stop: function(e, data) {
-                               OC.Upload.log('stop', e, data);
-                       }
-               };
+                       };
+
+                       // initialize jquery fileupload (blueimp)
+                       var fileupload = $('#file_upload_start').fileupload(file_upload_param);
+                       window.file_upload_param = fileupload;
+
+                       if (supportAjaxUploadWithProgress()) {
+
+                               // add progress handlers
+                               fileupload.on('fileuploadadd', function(e, data) {
+                                       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();
+                                       //}
+                               });
+                               // add progress handlers
+                               fileupload.on('fileuploadstart', function(e, data) {
+                                       OC.Upload.log('progress handle fileuploadstart', e, data);
+                                       $('#uploadprogresswrapper input.stop').show();
+                                       $('#uploadprogressbar').progressbar({value:0});
+                                       $('#uploadprogressbar').fadeIn();
+                               });
+                               fileupload.on('fileuploadprogress', function(e, data) {
+                                       OC.Upload.log('progress handle fileuploadprogress', e, data);
+                                       //TODO progressbar in row
+                               });
+                               fileupload.on('fileuploadprogressall', function(e, data) {
+                                       OC.Upload.log('progress handle fileuploadprogressall', e, data);
+                                       var progress = (data.loaded / data.total) * 100;
+                                       $('#uploadprogressbar').progressbar('value', progress);
+                               });
+                               fileupload.on('fileuploadstop', function(e, data) {
+                                       OC.Upload.log('progress handle fileuploadstop', e, data);
 
-               // initialize jquery fileupload (blueimp)
-               var fileupload = $('#file_upload_start').fileupload(file_upload_param);
-               window.file_upload_param = fileupload;
-
-               if (supportAjaxUploadWithProgress()) {
-
-                       // add progress handlers
-                       fileupload.on('fileuploadadd', function(e, data) {
-                               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();
-                               //}
-                       });
-                       // add progress handlers
-                       fileupload.on('fileuploadstart', function(e, data) {
-                               OC.Upload.log('progress handle fileuploadstart', e, data);
-                               $('#uploadprogresswrapper input.stop').show();
-                               $('#uploadprogressbar').progressbar({value:0});
-                               $('#uploadprogressbar').fadeIn();
-                       });
-                       fileupload.on('fileuploadprogress', function(e, data) {
-                               OC.Upload.log('progress handle fileuploadprogress', e, data);
-                               //TODO progressbar in row
-                       });
-                       fileupload.on('fileuploadprogressall', function(e, data) {
-                               OC.Upload.log('progress handle fileuploadprogressall', e, data);
-                               var progress = (data.loaded / data.total) * 100;
-                               $('#uploadprogressbar').progressbar('value', progress);
-                       });
-                       fileupload.on('fileuploadstop', function(e, data) {
-                               OC.Upload.log('progress handle fileuploadstop', e, data);
-
-                               $('#uploadprogresswrapper input.stop').fadeOut();
-                               $('#uploadprogressbar').fadeOut();
-                           Files.updateStorageStatistics();
-                       });
-                       fileupload.on('fileuploadfail', function(e, data) {
-                               OC.Upload.log('progress handle fileuploadfail', e, data);
-                               //if user pressed cancel hide upload progress bar and cancel button
-                               if (data.errorThrown === 'abort') {
                                        $('#uploadprogresswrapper input.stop').fadeOut();
                                        $('#uploadprogressbar').fadeOut();
-                               }
-                       });
-
-               } else {
-                       console.log('skipping file progress because your browser is broken');
-               }
-       }
+                                       Files.updateStorageStatistics();
+                               });
+                               fileupload.on('fileuploadfail', function(e, data) {
+                                       OC.Upload.log('progress handle fileuploadfail', e, data);
+                                       //if user pressed cancel hide upload progress bar and cancel button
+                                       if (data.errorThrown === 'abort') {
+                                               $('#uploadprogresswrapper input.stop').fadeOut();
+                                               $('#uploadprogressbar').fadeOut();
+                                       }
+                               });
 
-       $.assocArraySize = function(obj) {
-               // http://stackoverflow.com/a/6700/11236
-               var size = 0, key;
-               for (key in obj) {
-                       if (obj.hasOwnProperty(key)) {
-                               size++;
+                       } else {
+                               console.log('skipping file progress because your browser is broken');
                        }
                }
-               return size;
-       };
 
-       // warn user not to leave the page while upload is in progress
-       $(window).on('beforeunload', function(e) {
-               if (OC.Upload.isProcessing()) {
-                       return t('files', 'File upload is in progress. Leaving the page now will cancel the upload.');
-               }
-       });
+               $.assocArraySize = function(obj) {
+                       // http://stackoverflow.com/a/6700/11236
+                       var size = 0, key;
+                       for (key in obj) {
+                               if (obj.hasOwnProperty(key)) {
+                                       size++;
+                               }
+                       }
+                       return size;
+               };
 
-       //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
-       if (navigator.userAgent.search(/konqueror/i) === -1) {
-               $('#file_upload_start').attr('multiple', 'multiple');
-       }
+               // warn user not to leave the page while upload is in progress
+               $(window).on('beforeunload', function(e) {
+                       if (OC.Upload.isProcessing()) {
+                               return t('files', 'File upload is in progress. Leaving the page now will cancel the upload.');
+                       }
+               });
 
-       //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder
-       var crumb=$('div.crumb').first();
-       while($('div.controls').height() > 40 && crumb.next('div.crumb').length > 0) {
-               crumb.children('a').text('...');
-               crumb = crumb.next('div.crumb');
-       }
-       //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent
-       var crumb = $('div.crumb').first();
-       var next = crumb.next('div.crumb');
-       while($('div.controls').height()>40 && next.next('div.crumb').length > 0) {
-               crumb.remove();
-               crumb = next;
-               next = crumb.next('div.crumb');
-       }
-       //still not enough, start shorting down the current folder name
-       var crumb=$('div.crumb>a').last();
-       while($('div.controls').height() > 40 && crumb.text().length > 6) {
-               var text=crumb.text();
-               text = text.substr(0,text.length-6)+'...';
-               crumb.text(text);
-       }
+               //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
+               if (navigator.userAgent.search(/konqueror/i) === -1) {
+                       $('#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;
+               //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder
+               var crumb=$('div.crumb').first();
+               while($('div.controls').height() > 40 && crumb.next('div.crumb').length > 0) {
+                       crumb.children('a').text('...');
+                       crumb = crumb.next('div.crumb');
                }
-               $('#new>ul').hide();
-               $('#new').removeClass('active');
-               if ($('#new .error').length > 0) {
-                       $('#new .error').tipsy('hide');
+               //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent
+               var crumb = $('div.crumb').first();
+               var next = crumb.next('div.crumb');
+               while($('div.controls').height()>40 && next.next('div.crumb').length > 0) {
+                       crumb.remove();
+                       crumb = next;
+                       next = crumb.next('div.crumb');
                }
-               $('#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;
+               //still not enough, start shorting down the current folder name
+               var crumb=$('div.crumb>a').last();
+               while($('div.controls').height() > 40 && crumb.text().length > 6) {
+                       var text=crumb.text();
+                       text = text.substr(0,text.length-6)+'...';
+                       crumb.text(text);
                }
 
-               $('#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>');
+               $(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>');
+                               }
+                       });
                });
-
-               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.getCurrentDirectory() === '/' && filename.toLowerCase() === 'shared') {
-                               throw t('files', 'In the home folder \'Shared\' is a reserved filename');
-                       } else if (FileList.inList(filename)) {
-                               throw t('files', '{new_name} already exists', {new_name: filename});
-                       } else {
-                               return true;
+               $('#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;
                        }
-               };
 
-               // 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');
-                       }
-               });
+                       $('#new .error').tipsy('hide');
 
-               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();
+                       $('#new li').each(function(i,element) {
+                               if ($(element).children('p').length === 0) {
+                                       $(element).children('form').remove();
+                                       $(element).append('<p>'+$(element).data('text')+'</p>');
                                }
-                               var name = getUniqueName(newname);
-                               if (newname !== name) {
-                                       FileList.checkName(name, newname, true);
-                                       var hidden = true;
+                       });
+
+                       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.getCurrentDirectory() === '/' && filename.toLowerCase() === 'shared') {
+                                       throw t('files', 'In the home folder \'Shared\' is a reserved filename');
+                               } else if (FileList.inList(filename)) {
+                                       throw t('files', '{new_name} already exists', {new_name: filename});
                                } else {
-                                       var hidden = false;
+                                       return true;
                                }
-                               switch(type) {
-                                       case 'file':
-                                               $.post(
-                                                       OC.filePath('files', 'ajax', 'newfile.php'),
-                                                       {dir:$('#dir').val(), filename:name},
-                                                       function(result) {
-                                                               if (result.status === 'success') {
-                                                                       var date = new Date();
-                                                                       // TODO: ideally addFile should be able to receive
-                                                                       // all attributes and set them automatically,
-                                                                       // and also auto-load the preview
-                                                                       var tr = FileList.addFile(name, 0, date, false, hidden);
-                                                                       tr.attr('data-size', result.data.size);
-                                                                       tr.attr('data-mime', result.data.mime);
-                                                                       tr.attr('data-id', result.data.id);
-                                                                       tr.attr('data-etag', result.data.etag);
-                                                                       tr.find('.filesize').text(humanFileSize(result.data.size));
-                                                                       var path = getPathForPreview(name);
-                                                                       Files.lazyLoadPreview(path, result.data.mime, function(previewpath) {
-                                                                               tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
-                                                                       }, null, null, result.data.etag);
-                                                                       FileActions.display(tr.find('td.filename'), true);
-                                                               } else {
-                                                                       OC.dialogs.alert(result.data.message, t('core', 'Could not create file'));
+                       };
+
+                       // 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 = 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:$('#dir').val(), filename:name},
+                                                               function(result) {
+                                                                       if (result.status === 'success') {
+                                                                               var date = new Date();
+                                                                               // TODO: ideally addFile should be able to receive
+                                                                               // all attributes and set them automatically,
+                                                                               // and also auto-load the preview
+                                                                               var tr = FileList.addFile(name, 0, date, false, hidden);
+                                                                               tr.attr('data-size', result.data.size);
+                                                                               tr.attr('data-mime', result.data.mime);
+                                                                               tr.attr('data-id', result.data.id);
+                                                                               tr.attr('data-etag', result.data.etag);
+                                                                               tr.find('.filesize').text(humanFileSize(result.data.size));
+                                                                               var path = getPathForPreview(name);
+                                                                               Files.lazyLoadPreview(path, result.data.mime, function(previewpath) {
+                                                                                       tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
+                                                                               }, null, null, result.data.etag);
+                                                                               FileActions.display(tr.find('td.filename'), 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:$('#dir').val(), foldername:name},
-                                                       function(result) {
-                                                               if (result.status === 'success') {
-                                                                       var date=new Date();
-                                                                       FileList.addDir(name, 0, date, hidden);
-                                                                       var tr = FileList.findFileEl(name);
-                                                                       tr.attr('data-id', result.data.id);
-                                                               } else {
-                                                                       OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
+                                                       );
+                                                       break;
+                                               case 'folder':
+                                                       $.post(
+                                                               OC.filePath('files','ajax','newfolder.php'),
+                                                               {dir:$('#dir').val(), foldername:name},
+                                                               function(result) {
+                                                                       if (result.status === 'success') {
+                                                                               var date=new Date();
+                                                                               FileList.addDir(name, 0, date, hidden);
+                                                                               var tr = FileList.findFileEl(name);
+                                                                               tr.attr('data-id', result.data.id);
+                                                                       } 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;
                                                        }
-                                               );
-                                               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 = getUniqueName(localName);
-                                               //IE < 10 does not fire the necessary events for the progress bar.
-                                               if ($('html.lte9').length === 0) {
-                                                       $('#uploadprogressbar').progressbar({value:0});
-                                                       $('#uploadprogressbar').fadeIn();
-                                               }
-
-                                               var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
-                                               eventSource.listen('progress',function(progress) {
+                                                       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 = getUniqueName(localName);
                                                        //IE < 10 does not fire the necessary events for the progress bar.
                                                        if ($('html.lte9').length === 0) {
-                                                               $('#uploadprogressbar').progressbar('value',progress);
+                                                               $('#uploadprogressbar').progressbar({value:0});
+                                                               $('#uploadprogressbar').fadeIn();
                                                        }
-                                               });
-                                               eventSource.listen('success',function(data) {
-                                                       var mime = data.mime;
-                                                       var size = data.size;
-                                                       var id = data.id;
-                                                       $('#uploadprogressbar').fadeOut();
-                                                       var date = new Date();
-                                                       FileList.addFile(localName, size, date, false, hidden);
-                                                       var tr = FileList.findFileEl(localName);
-                                                       tr.data('mime', mime).data('id', id);
-                                                       tr.attr('data-id', id);
-                                                       var path = $('#dir').val()+'/'+localName;
-                                                       Files.lazyLoadPreview(path, mime, function(previewpath) {
-                                                               tr.find('td.filename').attr('style', 'background-image:url('+previewpath+')');
-                                                       }, null, null, data.etag);
-                                                       FileActions.display(tr.find('td.filename'), true);
-                                               });
-                                               eventSource.listen('error',function(error) {
-                                                       $('#uploadprogressbar').fadeOut();
-                                                       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 eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),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 mime = data.mime;
+                                                               var size = data.size;
+                                                               var id = data.id;
+                                                               $('#uploadprogressbar').fadeOut();
+                                                               var date = new Date();
+                                                               FileList.addFile(localName, size, date, false, hidden);
+                                                               var tr = FileList.findFileEl(localName);
+                                                               tr.data('mime', mime).data('id', id);
+                                                               tr.attr('data-id', id);
+                                                               var path = $('#dir').val()+'/'+localName;
+                                                               Files.lazyLoadPreview(path, mime, function(previewpath) {
+                                                                       tr.find('td.filename').attr('style', 'background-image:url('+previewpath+')');
+                                                               }, null, null, data.etag);
+                                                               FileActions.display(tr.find('td.filename'), true);
+                                                       });
+                                                       eventSource.listen('error',function(error) {
+                                                               $('#uploadprogressbar').fadeOut();
+                                                               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');
                                }
-                               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;
+               window.file_upload_param = file_upload_param;
+               return file_upload_param;
+       }
+};
+
+$(document).ready(function() {
+       OC.Upload.init();
 });
+
diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js
new file mode 100644 (file)
index 0000000..2b4341e
--- /dev/null
@@ -0,0 +1,127 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/* global OC */
+describe('OC.Upload tests', function() {
+       var $dummyUploader;
+       var testFile;
+
+       beforeEach(function() {
+               testFile = {
+                       name: 'test.txt',
+                       size: 5000, // 5 KB
+                       type: 'text/plain',
+                       lastModifiedDate: new Date()
+               };
+               // need a dummy button because file-upload checks on it
+               $('#testArea').append(
+                       '<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' +
+                       '<input type="hidden" id="upload_limit" name="upload_limit" value="10000000">' + // 10 MB
+                       '<input type="hidden" id="free_space" name="free_space" value="50000000">' // 50 MB
+               );
+               $dummyUploader = $('#file_upload_start');
+       });
+       afterEach(function() {
+               delete window.file_upload_param;
+               $dummyUploader = undefined;
+       });
+       describe('Adding files for upload', function() {
+               var params;
+               var failStub;
+
+               beforeEach(function() {
+                       params = OC.Upload.init();
+                       failStub = sinon.stub();
+                       $dummyUploader.on('fileuploadfail', failStub);
+               });
+               afterEach(function() {
+                       params = undefined;
+                       failStub = undefined;
+               });
+
+               /**
+                * Add file for upload
+                * @param file file data
+                */
+               function addFile(file) {
+                       return params.add.call(
+                                       $dummyUploader[0],
+                                       {},
+                                       {
+                                       originalFiles: {},
+                                       files: [file]
+                               });
+               }
+
+               it('adds file when size is below limits', function() {
+                       var result = addFile(testFile);
+                       expect(result).toEqual(true);
+               });
+               it('adds file when free space is unknown', function() {
+                       var result;
+                       $('#free_space').val(-2);
+
+                       result = addFile(testFile);
+
+                       expect(result).toEqual(true);
+                       expect(failStub.notCalled).toEqual(true);
+               });
+               it('does not add file if it exceeds upload limit', function() {
+                       var result;
+                       $('#upload_limit').val(1000);
+
+                       result = addFile(testFile);
+
+                       expect(result).toEqual(false);
+                       expect(failStub.calledOnce).toEqual(true);
+                       expect(failStub.getCall(0).args[1].textStatus).toEqual('sizeexceedlimit');
+                       expect(failStub.getCall(0).args[1].errorThrown).toEqual(
+                               'Total file size 5 kB exceeds upload limit 1000 B'
+                       );
+               });
+               it('does not add file if it exceeds free space', function() {
+                       var result;
+                       $('#free_space').val(1000);
+
+                       result = addFile(testFile);
+
+                       expect(result).toEqual(false);
+                       expect(failStub.calledOnce).toEqual(true);
+                       expect(failStub.getCall(0).args[1].textStatus).toEqual('notenoughspace');
+                       expect(failStub.getCall(0).args[1].errorThrown).toEqual(
+                               'Not enough free space, you are uploading 5 kB but only 1000 B is left'
+                       );
+               });
+               it('does not add file if it has invalid characters', function() {
+                       var result;
+                       testFile.name = 'stars*stars.txt';
+
+                       result = addFile(testFile);
+
+                       expect(result).toEqual(false);
+                       expect(failStub.calledOnce).toEqual(true);
+                       expect(failStub.getCall(0).args[1].textStatus).toEqual('invalidcharacters');
+                       expect(failStub.getCall(0).args[1].errorThrown.substr(0, 12)).toEqual(
+                               'Invalid name'
+                       );
+               });
+       });
+});