diff --git a/webroot/rsrc/js/core/FileUpload.js b/webroot/rsrc/js/core/FileUpload.js index e2c3530cbd..ef5089a56e 100644 --- a/webroot/rsrc/js/core/FileUpload.js +++ b/webroot/rsrc/js/core/FileUpload.js @@ -1,211 +1,223 @@ /** * @requires javelin-install * javelin-dom * phabricator-notification * @provides phabricator-file-upload * @javelin */ JX.install('PhabricatorFileUpload', { construct : function() { this._notification = new JX.Notification(); }, properties : { name: null, totalBytes: null, uploadedBytes: null, rawFileObject: null, allocatedPHID: null, ID: null, PHID: null, URI: null, status: null, markup: null, targetNode: null, error: null }, members : { _notification : null, _chunks: null, _isResume: false, addUploadedBytes: function(bytes) { var uploaded = this.getUploadedBytes(); this.setUploadedBytes(uploaded + bytes); return this; }, /** * Get the File Monogram - like 'F123' */ getMonogram: function() { return 'F' + this.getID(); }, /** * Get the File page URI - like '/F123' */ getPageURI: function() { return '/' + this.getMonogram(); }, setChunks: function(chunks) { var chunk; for (var ii = 0; ii < chunks.length; ii++) { chunk = chunks[ii]; if (chunk.complete) { this.addUploadedBytes(chunk.byteEnd - chunk.byteStart); this._isResume = true; } } this._chunks = chunks; return this; }, getChunks: function() { return this._chunks; }, getRemainingChunks: function() { var chunks = this.getChunks(); var result = []; for (var ii = 0; ii < chunks.length; ii++) { if (!chunks[ii].complete) { result.push(chunks[ii]); } } return result; }, didCompleteChunk: function(chunk) { var chunks = this.getRemainingChunks(); for (var ii = 0; ii < chunks.length; ii++) { if (chunks[ii].byteStart == chunk.byteStart) { if (chunks[ii].byteEnd == chunk.byteEnd) { if (!chunks[ii].complete) { chunks[ii].complete = true; } break; } } } return this; }, update : function() { if (!this._notification) { return; } this._notification .setDuration(0) .show(); var content; // TODO: This stuff needs some work for translations. switch (this.getStatus()) { case 'done': - var link = JX.$N('a', {href: this.getPageURI()}, this.getMonogram()); + + // In this case the File upload was successful + + var linkAttr = {}; + linkAttr.href = this.getPageURI(); + + // External links are evil as default. + // Believe it or not, but some Phorge users brainstormed + // for one hour for this specific target="_blank". + // https://we.phorge.it/T15172 + linkAttr.target = '_blank'; + + var link = JX.$N('a', linkAttr, this.getMonogram()); content = [ JX.$N('strong', {}, ['Upload Complete (', link, ')']), JX.$N('br'), this.getName() ]; this._notification .setContent(content) .alterClassName('jx-notification-done', true) .setDuration(12000); this._notification = null; break; case 'error': content = [ JX.$N('strong', {}, 'Upload Failure'), JX.$N('br'), this.getName(), JX.$N('br'), JX.$N('br'), this.getError() ]; this._notification .setContent(content) .alterClassName('jx-notification-error', true); this._notification = null; break; case 'allocate': content = 'Allocating "' + this.getName() + '"...'; this._notification .setContent(content); break; case 'chunks': content = 'Loading chunks for "' + this.getName() + '"...'; this._notification .setContent(content); break; default: var info = ''; if (this.getTotalBytes()) { var p = this._renderPercentComplete(); var f = this._renderFileSize(); info = p + ' of ' + f; } var head; if (this._isResume) { head = 'Resuming:'; } else if (this._chunks) { head = 'Uploading chunks:'; } else { head = 'Uploading:'; } info = [ JX.$N('strong', {}, this.getName()), JX.$N('br'), head + ' ' + info]; this._notification .setContent(info); break; } return this; }, _renderPercentComplete : function() { if (!this.getTotalBytes()) { return null; } var ratio = this.getUploadedBytes() / this.getTotalBytes(); return parseInt(100 * ratio, 10) + '%'; }, _renderFileSize : function() { if (!this.getTotalBytes()) { return null; } var s = 3; var n = this.getTotalBytes(); while (s && n >= 1000) { n = Math.round(n / 100); n = n / 10; s--; } s = ['GB', 'MB', 'KB', 'bytes'][s]; return n + ' ' + s; } } });