From af02d01d4120203d78f6490cca21379d59428023 Mon Sep 17 00:00:00 2001 From: flaburgan Date: Thu, 17 May 2018 15:10:21 +0200 Subject: [PATCH] Fix progress when uploading multiple photo at the same time --- .../app/views/publisher/uploader_view.js | 76 +++++++---------- .../javascripts/app/views/publisher_view.js | 4 +- .../helpers/post_photo_uploader.es6 | 2 +- app/controllers/photos_controller.rb | 2 +- .../app/views/publisher_view_spec.js | 83 +++++++++++-------- 5 files changed, 83 insertions(+), 84 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher/uploader_view.js b/app/assets/javascripts/app/views/publisher/uploader_view.js index e046a00ea..bd5c8ed3b 100644 --- a/app/assets/javascripts/app/views/publisher/uploader_view.js +++ b/app/assets/javascripts/app/views/publisher/uploader_view.js @@ -7,108 +7,92 @@ app.views.PublisherUploader = Backbone.View.extend({ initialize: function(opts) { this.publisher = opts.publisher; - - this.info = $("
"); - this.publisher.wrapperEl.before(this.info); this.publisher.photozoneEl.on("click", ".x", _.bind(this._removePhoto, this)); // Initialize the PostPhotoUploader and subscribe its events this.uploader = new Diaspora.PostPhotoUploader(this.el); - this.uploader.onUploadStarted = _.bind(this.uploadStartedHandler, this); this.uploader.onProgress = _.bind(this.progressHandler, this); this.uploader.onUploadCompleted = _.bind(this.uploadCompleteHandler, this); }, // add photo placeholders to the publisher to indicate an upload in progress - _addPhotoPlaceholder: function() { + _addPhotoPlaceholder: function(id) { var publisher = this.publisher; publisher.setButtonsEnabled(false); publisher.wrapperEl.addClass("with_attachments"); publisher.photozoneEl.append( - "
  • " + + "
  • " + "
    " + "
    "+ "
    " + - " \"\""+ + "
    " + "
  • " ); }, - uploadStartedHandler: function() { + uploadStartedHandler: function(id) { this.$el.addClass("loading"); - this._addPhotoPlaceholder(); + this._addPhotoPlaceholder(id); }, - progressHandler: function(fileName, progress) { - this.info.text(fileName + " " + progress + "%").fadeTo(200, 1); + progressHandler: function(id, fileName, progress) { this.publisher.photozoneEl - .find("li.loading").first().find(".progress-bar") + .find("li.loading#upload-" + id + " .progress-bar") .width(progress + "%"); }, - uploadCompleteHandler: function(_id, fileName, response) { + uploadCompleteHandler: function(id, fileName, response) { if (response.success){ - this.info.text(Diaspora.I18n.t("photo_uploader.completed", {file: fileName})).fadeTo(2000, 0); - - var id = response.data.photo.id, + var photoId = response.data.photo.id, image = response.data.photo.unprocessed_image; - this._addFinishedPhoto(id, image); + this._addFinishedPhoto(id, photoId, image); this.trigger("change"); } else { - this._cancelPhotoUpload(); - this.trigger("change"); - this.info.text(Diaspora.I18n.t("photo_uploader.error", {file: fileName})); + this._cancelPhotoUpload(id); this.publisher.wrapperEl.find("#photodropzone_container").first().after( "
    " + - Diaspora.I18n.t("photo_uploader.error", {file: fileName}) + + Diaspora.I18n.t("photo_uploader.error", {file: fileName}) + "
    " ); + this.trigger("change"); } }, // replace the first photo placeholder with the finished uploaded image and // add the id to the publishers form - _addFinishedPhoto: function(id, image) { + _addFinishedPhoto: function(id, photoId, image) { var publisher = this.publisher; // add form input element publisher.$(".content_creation form").append( - "" + "" ); // replace placeholder - var placeholder = publisher.photozoneEl.find("li.loading").first(); + var placeholder = publisher.photozoneEl.find("li.loading#upload-" + id); placeholder - .removeClass("loading") .prepend( - "
    "+ - "
    " - ) - .find("img").attr( - { - "src": image.thumb_medium.url, - "data-small": image.thumb_small.url, - "data-scaled": image.scaled_full.url, - "data-id": id - }).removeClass("ajax-loader"); - placeholder - .find("div.progress").remove(); + "
    " + + "
    " + + "\"\"" + ).removeClass("loading"); + placeholder.find("div.progress").remove(); + placeholder.find("img").on("load", function(ev) { + $(ev.target).removeClass("hidden"); + placeholder.find(".spinner").remove(); + }); // no more placeholders? enable buttons - if( publisher.photozoneEl.find("li.loading").length === 0 ) { + if (publisher.photozoneEl.find("li.loading").length === 0) { this.$el.removeClass("loading"); publisher.setButtonsEnabled(true); } }, - _cancelPhotoUpload: function() { - var publisher = this.publisher; - var placeholder = publisher.photozoneEl.find("li.loading").first(); - placeholder - .removeClass("loading") - .find("img").remove(); + _cancelPhotoUpload: function(id) { + this.publisher.photozoneEl.find("li.loading#upload-" + id).remove(); }, // remove an already uploaded photo @@ -126,7 +110,7 @@ app.views.PublisherUploader = Backbone.View.extend({ photo.fadeOut(400, function() { photo.remove(); - if( self.publisher.$(".publisher_photo").length === 0 ) { + if (self.publisher.$(".publisher_photo").length === 0) { // no more photos left... self.publisher.wrapperEl.removeClass("with_attachments"); } @@ -135,9 +119,7 @@ app.views.PublisherUploader = Backbone.View.extend({ }); } }); - return false; } - }); // @license-end diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 5db247145..2549692ab 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -445,7 +445,7 @@ app.views.Publisher = Backbone.View.extend({ }, checkSubmitAvailability: function() { - if( this._submittable() ) { + if (this._submittable()) { this.setButtonsEnabled(true); } else { this.setButtonsEnabled(false); @@ -484,7 +484,7 @@ app.views.Publisher = Backbone.View.extend({ }, _beforeUnload: function(e) { - if(this._submittable() && this.inputEl.val() !== this.prefillText){ + if (this._submittable() && this.inputEl.val() !== this.prefillText) { var confirmationMessage = Diaspora.I18n.t("confirm_unload"); (e || window.event).returnValue = confirmationMessage; //Gecko + IE return confirmationMessage; //Webkit, Safari, Chrome, etc. diff --git a/app/assets/javascripts/helpers/post_photo_uploader.es6 b/app/assets/javascripts/helpers/post_photo_uploader.es6 index 5a786f64b..10a6f6b24 100644 --- a/app/assets/javascripts/helpers/post_photo_uploader.es6 +++ b/app/assets/javascripts/helpers/post_photo_uploader.es6 @@ -66,7 +66,7 @@ Diaspora.PostPhotoUploader = class { onSubmit: (id, name) => this.onPictureSelected(id, name), onUpload: (id, name) => (this.func(this.onUploadStarted) && this.onUploadStarted(id, name)), onProgress: (id, fileName, loaded, total) => - (this.func(this.onProgress) && this.onProgress(fileName, Math.round(loaded / total * 100))), + (this.func(this.onProgress) && this.onProgress(id, fileName, Math.round(loaded / total * 100))), onComplete: (id, name, json) => (this.func(this.onUploadCompleted) && this.onUploadCompleted(id, name, json)), onError: (id, name, errorReason) => this.showMessage("error", errorReason) } diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 4bcbb90d2..0b01d6e49 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -119,7 +119,7 @@ class PhotosController < ApplicationController file_name = params[:qqfile] # get file content type att_content_type = request.content_type.to_s == "" ? "application/octet-stream" : request.content_type.to_s - # create tempora##l file + # create temporal file file = Tempfile.new(file_name, encoding: "BINARY") # put data into this file from raw post request file.print request.raw_post.force_encoding("BINARY") diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index 33f3edcb0..85ebea854 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -517,13 +517,16 @@ describe("app.views.Publisher", function() { beforeEach(function() { jQuery.fx.off = true; setFixtures( - '
    '+ - '
    '+ - '
    '+ - '
    '+ - ' '+ - '
    '+ - '
    ' + "
    " + + "
    " + + "
    " + + "
    " + + "
      " + + "
      " + + "
      " + + " " + + "
      " + + "
      " ); }); @@ -542,25 +545,43 @@ describe("app.views.Publisher", function() { var uploadView = this.view.viewUploader; this.uploader = { onProgress: _.bind(uploadView.progressHandler, uploadView), - onUpload: _.bind(uploadView.uploadStartedHandler, uploadView), - onComplete: _.bind(uploadView.uploadCompleteHandler, uploadView) + onUploadStarted: _.bind(uploadView.uploadStartedHandler, uploadView), + onUploadCompleted: _.bind(uploadView.uploadCompleteHandler, uploadView) }; uploadView.uploader = this.uploader; }); context("progress", function() { - it("shows progress in percent", function() { - this.uploader.onProgress("test.jpg", 20); + beforeEach(function() { + this.view.photozoneEl.append( + "
    • " + + "
      " + + "
      " + + "
      " + + "
      " + + "
    • "); + this.view.photozoneEl.append( + "
    • " + + "
      " + + "
      " + + "
      " + + "
      " + + "
    • "); + }); - var info = this.view.viewUploader.info; - expect(info.text()).toContain("test.jpg"); - expect(info.text()).toContain("20%"); + it("shows progress in percent", function() { + this.uploader.onProgress(0, "test.jpg", 20); + this.uploader.onProgress(1, "test2.jpg", 25); + + var dropzone = $("#photodropzone"); + expect(dropzone.find("li.loading#upload-0 .progress-bar").attr("style")).toBe("width: 20%;"); + expect(dropzone.find("li.loading#upload-1 .progress-bar").attr("style")).toBe("width: 25%;"); }); }); context("submitting", function() { beforeEach(function() { - this.uploader.onUpload(null, "test.jpg"); + this.uploader.onUploadStarted(null, "test.jpg"); }); it("adds a placeholder", function() { @@ -575,28 +596,24 @@ describe("app.views.Publisher", function() { context('successful completion', function() { beforeEach(function() { - $('#photodropzone').html('
    • '); + $("#photodropzone").html("
    • "); /* eslint-disable camelcase */ - this.uploader.onComplete(null, 'test.jpg', { + this.uploader.onUploadCompleted(0, "test.jpg", { data: { photo: { id: '987', unprocessed_image: { - thumb_small: {url: "test.jpg"}, - thumb_medium: {url: "test.jpg"}, - thumb_large: {url: "test.jpg"}, - scaled_full: {url: "test.jpg"} + scaled_full: {url: "/uploads/images/scaled_full_test.jpg"}, + thumb_large: {url: "/uploads/images/thumb_large_test.jpg"}, + thumb_medium: {url: "/uploads/images/thumb_medium_test.jpg"}, + thumb_small: {url: "/uploads/images/thumb_small_test.jpg"}, + url: "/uploads/images/test.jpg" } }}, success: true }); }); /* eslint-enable camelcase */ - it('shows it in text form', function() { - var info = this.view.viewUploader.info; - expect(info.text()).toBe(Diaspora.I18n.t('photo_uploader.completed', {file: 'test.jpg'})); - }); - it('adds a hidden input to the publisher', function() { var input = this.view.$('input[type="hidden"][value="987"][name="photos[]"]'); expect(input.length).toBe(1); @@ -606,9 +623,9 @@ describe("app.views.Publisher", function() { var li = this.view.photozoneEl.find("li"); var img = li.find('img'); - expect(li.attr('class')).not.toContain('loading'); - expect(img.attr('src')).toBe('test.jpg'); - expect(img.attr('data-id')).toBe('987'); + expect(li).not.toHaveClass("loading"); + expect(img.attr("src")).toBe("/uploads/images/test.jpg"); + expect(img.attr("data-id")).toBe("987"); }); it('re-enables the buttons', function() { @@ -618,10 +635,10 @@ describe("app.views.Publisher", function() { context('unsuccessful completion', function() { beforeEach(function() { - $('#photodropzone').html('
    • '); + $("#photodropzone").append("
    • "); /* eslint-disable camelcase */ - this.uploader.onComplete(null, 'test.jpg', { + this.uploader.onUploadCompleted(0, "test.jpg", { data: { photo: { id: '987', unprocessed_image: { @@ -635,8 +652,8 @@ describe("app.views.Publisher", function() { }); /* eslint-enable camelcase */ it('shows error message', function() { - var info = this.view.viewUploader.info; - expect(info.text()).toBe(Diaspora.I18n.t('photo_uploader.error', {file: 'test.jpg'})); + expect($("#photodropzone li").length).toEqual(0); + expect($("#upload_error").text()).toBe(Diaspora.I18n.t("photo_uploader.error", {file: "test.jpg"})); }); }); });