Merge pull request #7655 from Flaburgan/6721-fix-upload-progress-bar
Fix multiple photos upload progress bar
This commit is contained in:
commit
ea15403d57
6 changed files with 84 additions and 84 deletions
|
|
@ -6,6 +6,7 @@
|
|||
* Enable Content-Security-Policy header by default [#7781](https://github.com/diaspora/diaspora/pull/7781)
|
||||
|
||||
## Bug fixes
|
||||
* Fix multiple photos upload progress bar [#7655](https://github.com/diaspora/diaspora/pull/7655)
|
||||
|
||||
## Features
|
||||
* Add client-side cropping of profile image uploads [#7581](https://github.com/diaspora/diaspora/pull/7581)
|
||||
|
|
|
|||
|
|
@ -7,108 +7,92 @@
|
|||
app.views.PublisherUploader = Backbone.View.extend({
|
||||
initialize: function(opts) {
|
||||
this.publisher = opts.publisher;
|
||||
|
||||
this.info = $("<div id=\"fileInfo\" />");
|
||||
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(
|
||||
"<li class=\"publisher_photo loading\" style=\"position:relative;\">" +
|
||||
"<li id=\"upload-" + id + "\"class=\"publisher_photo loading\" style=\"position:relative;\">" +
|
||||
" <div class=\"progress\">" +
|
||||
" <div class=\"progress-bar progress-bar-striped active\" role=\"progressbar\"></div>"+
|
||||
" </div>" +
|
||||
" <img src=\"\"+Handlebars.helpers.imageUrl(\"ajax-loader2.gif\")+\"\" class=\"ajax-loader\" alt=\"\" />"+
|
||||
" <div class=\"spinner\"></div>" +
|
||||
"</li>"
|
||||
);
|
||||
},
|
||||
|
||||
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(
|
||||
"<div id=\"upload_error\">" +
|
||||
Diaspora.I18n.t("photo_uploader.error", {file: fileName}) +
|
||||
Diaspora.I18n.t("photo_uploader.error", {file: fileName}) +
|
||||
"</div>"
|
||||
);
|
||||
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(
|
||||
"<input type=\"hidden\", value=\""+id+"\" name=\"photos[]\" />"
|
||||
"<input type=\"hidden\", value=\"" + photoId + "\" name=\"photos[]\" />"
|
||||
);
|
||||
// replace placeholder
|
||||
var placeholder = publisher.photozoneEl.find("li.loading").first();
|
||||
var placeholder = publisher.photozoneEl.find("li.loading#upload-" + id);
|
||||
placeholder
|
||||
.removeClass("loading")
|
||||
.prepend(
|
||||
"<div class=\"x\"></div>"+
|
||||
"<div class=\"circle\"></div>"
|
||||
)
|
||||
.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();
|
||||
"<div class=\"x\"></div>" +
|
||||
"<div class=\"circle\"></div>" +
|
||||
"<img src=\"" + image.url + "\" data-id=\"" + photoId + "\" alt=\"\" class=\"hidden\" />"
|
||||
).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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -517,13 +517,16 @@ describe("app.views.Publisher", function() {
|
|||
beforeEach(function() {
|
||||
jQuery.fx.off = true;
|
||||
setFixtures(
|
||||
'<div id="publisher">'+
|
||||
' <div class="content_creation"><form>'+
|
||||
' <div id="publisher-textarea-wrapper"></div>'+
|
||||
' <div id="photodropzone"></div>'+
|
||||
' <input type="submit" />'+
|
||||
' </form></div>'+
|
||||
'</div>'
|
||||
"<div id=\"publisher\">" +
|
||||
" <div class=\"content_creation\"><form>" +
|
||||
" <div id=\"publisher-textarea-wrapper\">" +
|
||||
" <div id=\"photodropzone_container\">" +
|
||||
" <ul id=\"photodropzone\"></ul>" +
|
||||
" </div>" +
|
||||
" </div>" +
|
||||
" <input type=\"submit\" />" +
|
||||
" </form></div>" +
|
||||
"</div>"
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -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(
|
||||
"<li id=\"upload-0\" class=\"publisher_photo loading\" style=\"position:relative;\">" +
|
||||
" <div class=\"progress\">" +
|
||||
" <div class=\"progress-bar progress-bar-striped active\" role=\"progressbar\"></div>" +
|
||||
" </div>" +
|
||||
" <div class=\"spinner\"></div>" +
|
||||
"</li>");
|
||||
this.view.photozoneEl.append(
|
||||
"<li id=\"upload-1\" class=\"publisher_photo loading\" style=\"position:relative;\">" +
|
||||
" <div class=\"progress\">" +
|
||||
" <div class=\"progress-bar progress-bar-striped active\" role=\"progressbar\"></div>" +
|
||||
" </div>" +
|
||||
" <div class=\"spinner\"></div>" +
|
||||
"</li>");
|
||||
});
|
||||
|
||||
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('<li class="publisher_photo loading"><img src="" /></li>');
|
||||
$("#photodropzone").html("<li id='upload-0' class='publisher_photo loading'></li>");
|
||||
|
||||
/* 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('<li class="publisher_photo loading"><img src="" /></li>');
|
||||
$("#photodropzone").append("<li id='upload-0' class='publisher_photo loading'></li>");
|
||||
|
||||
/* 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"}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue