9426: suppress new lines in the tag content editable field
[arvados.git] / apps / workbench / app / assets / javascripts / upload_to_collection.js
index 9e205423f33911a24c4ee6f2e83765e48cb4ae0b..55f562d9364f4f7f5b787eda7366eee2d13343e9 100644 (file)
@@ -65,6 +65,7 @@ function UploadToCollection($scope, $filter, $q, $timeout,
     ////////////////////////////////
 
     var keepProxy;
+    var defaultErrorMessage = 'A network error occurred: either the server was unreachable, or there is a server configuration problem. Please check your browser debug console for a more specific error message (browser security features prevent us from showing the details here).';
 
     function SliceReader(_slice) {
         var that = this;
@@ -117,7 +118,20 @@ function UploadToCollection($scope, $filter, $q, $timeout,
             // resolve(locator) when the block is accepted by the
             // proxy.
             _deferred = $.Deferred();
-            goSend();
+            if (proxyUriBase().match(/^http:/) &&
+                window.location.origin.match(/^https:/)) {
+                // In this case, requests will fail, and no ajax
+                // success/fail handlers will be called (!), which
+                // will leave our status saying "uploading" and the
+                // user waiting for something to happen. Better to
+                // give up now.
+                _deferred.reject({
+                    textStatus: 'error',
+                    err: 'There is a server configuration problem. Proxy ' + proxyUriBase() + ' cannot be used from origin ' + window.location.origin + ' due to the browser\'s mixed-content (https/http) policy.'
+                });
+            } else {
+                goSend();
+            }
             return _deferred.promise();
         }
         function stop() {
@@ -262,7 +276,8 @@ function UploadToCollection($scope, $filter, $q, $timeout,
             that.state = 'Paused';
             setProgress(_readPos);
             _currentUploader = null;
-            _deferred.reject(reason);
+            if (_deferred)
+                _deferred.reject(reason);
         }
         function onUploaderProgress(sliceDone, sliceSize) {
             setProgress(_readPos + sliceDone);
@@ -282,7 +297,10 @@ function UploadToCollection($scope, $filter, $q, $timeout,
         }
         function setProgress(bytesDone) {
             var kBps;
-            that.progress = Math.min(100, 100 * bytesDone / that.file.size)
+            if (that.file.size == 0)
+                that.progress = 100;
+            else
+                that.progress = Math.min(100, 100 * bytesDone / that.file.size);
             if (bytesDone > _startByte) {
                 kBps = (bytesDone - _startByte) /
                     (Date.now() - _startTime);
@@ -301,7 +319,7 @@ function UploadToCollection($scope, $filter, $q, $timeout,
             } else {
                 that.statistics = that.state;
             }
-            if (that.state === 'Uploading' || that.state === 'Uploaded') {
+            if (that.state === 'Uploaded') {
                 // 'Uploaded' gets reported as 'finished', which is a
                 // little misleading because the collection hasn't
                 // been updated yet. But FileUploader's portion of the
@@ -311,13 +329,14 @@ function UploadToCollection($scope, $filter, $q, $timeout,
                     $filter('date')(Date.now(), 'shortTime');
                 _finishTime = Date.now();
             }
-            _deferred.notify();
+            if (_deferred)
+                _deferred.notify();
         }
     }
 
     function QueueUploader() {
         $.extend(this, {
-            state: 'Idle',
+            state: 'Idle',      // Idle, Running, Stopped, Failed
             stateReason: null,
             statusSuccess: null,
             go: go,
@@ -344,9 +363,6 @@ function UploadToCollection($scope, $filter, $q, $timeout,
             if (_deferred) {
                 _deferred.reject({});
             }
-            if (_deferredAppend) {
-                _deferredAppend.reject({});
-            }
             for (var i=0; i<$scope.uploadQueue.length; i++)
                 $scope.uploadQueue[i].stop();
             onQueueProgress();
@@ -363,20 +379,28 @@ function UploadToCollection($scope, $filter, $q, $timeout,
             return doQueueWork();
         }
         function doQueueWork() {
-            if (!_deferred) {
-                // Queue work has been stopped.
-                return;
-            }
-            that.stateReason = null;
             // If anything is not Done, do it.
             if ($scope.uploadQueue.length > 0 &&
                 $scope.uploadQueue[0].state !== 'Done') {
-                return $scope.uploadQueue[0].go().
-                    then(appendToCollection, null, onQueueProgress).
-                    then(doQueueWork, onQueueReject);
+                if (_deferred) {
+                    that.stateReason = null;
+                    return $scope.uploadQueue[0].go().
+                        then(appendToCollection, null, onQueueProgress).
+                        then(doQueueWork, onQueueReject);
+                } else {
+                    // Queue work has been stopped. Just update the
+                    // view.
+                    onQueueProgress();
+                    return;
+                }
             }
-            // If everything is Done, resolve the promise and clean up.
-            return onQueueResolve();
+            // If everything is Done, resolve the promise and clean
+            // up. Note this can happen even after the _deferred
+            // promise has been rejected: specifically, when stop() is
+            // called too late to prevent completion of the last
+            // upload. In that case we want to update state to "Idle",
+            // rather than leave it at "Stopped".
+            onQueueResolve();
         }
         function onQueueReject(reason) {
             if (!_deferred) {
@@ -384,13 +408,14 @@ function UploadToCollection($scope, $filter, $q, $timeout,
                 return;
             }
 
+            that.state = 'Failed';
             that.stateReason = (
                 (reason.textStatus || 'Error') +
                     (reason.xhr && reason.xhr.options
                      ? (' (from ' + reason.xhr.options.url + ')')
                      : '') +
                     ': ' +
-                    (reason.err || ''));
+                    (reason.err || defaultErrorMessage));
             if (reason.xhr && reason.xhr.responseText)
                 that.stateReason += ' -- ' + reason.xhr.responseText;
             _deferred.reject(reason);
@@ -399,7 +424,8 @@ function UploadToCollection($scope, $filter, $q, $timeout,
         function onQueueResolve() {
             that.state = 'Idle';
             that.stateReason = 'Done!';
-            _deferred.resolve();
+            if (_deferred)
+                _deferred.resolve();
             onQueueProgress();
         }
         function onQueueProgress() {
@@ -414,11 +440,18 @@ function UploadToCollection($scope, $filter, $q, $timeout,
                 then(function(collection) {
                     var manifestText = '';
                     $.each(uploads, function(_, upload) {
+                        var locators = upload.locators;
+                        if (locators.length === 0) {
+                            // Every stream must have at least one
+                            // data locator, even if it is zero bytes
+                            // long:
+                            locators = ['d41d8cd98f00b204e9800998ecf8427e+0'];
+                        }
                         filename = ArvadosClient.uniqueNameForManifest(
                             collection.manifest_text,
                             '.', upload.file.name);
                         collection.manifest_text += '. ' +
-                            upload.locators.join(' ') +
+                            locators.join(' ') +
                             ' 0:' + upload.file.size.toString() + ':' +
                             filename +
                             '\n';
@@ -447,11 +480,11 @@ function UploadToCollection($scope, $filter, $q, $timeout,
                     }
                 }).
                 then(_deferredAppend.resolve,
-                     _deferredAppend.reject).
+                     _deferredAppend.reject);
+            return _deferredAppend.promise().
                 always(function() {
                     _deferredAppend = null;
                 });
-            return _deferredAppend.promise();
         }
     }
 }