Commit 5f341423 by Greg Price

Add progress bars for Studio video uploads

The CSS is also restructured a bit to style both the progress bar and
the status text based on the state of the upload using a single class
on the parent element.
parent 15030438
...@@ -19,7 +19,8 @@ define( ...@@ -19,7 +19,8 @@ define(
var ActiveVideoUpload = Backbone.Model.extend( var ActiveVideoUpload = Backbone.Model.extend(
{ {
defaults: { defaults: {
status: statusStrings.STATUS_QUEUED status: statusStrings.STATUS_QUEUED,
progress: 0
} }
}, },
statusStrings statusStrings
......
...@@ -131,39 +131,49 @@ define( ...@@ -131,39 +131,49 @@ define(
); );
}); });
it("should display status", function() { it("should display upload status and progress", function() {
var spec = this; var spec = this;
expect(this.$uploadElems.length).toEqual(caseInfo.numFiles); expect(this.$uploadElems.length).toEqual(caseInfo.numFiles);
this.$uploadElems.each(function(i, uploadElem) { this.$uploadElems.each(function(i, uploadElem) {
var $uploadElem = $(uploadElem); var $uploadElem = $(uploadElem);
var queued = i >= concurrentUploadLimit;
expect($.trim($uploadElem.find(".video-detail-name").text())).toEqual( expect($.trim($uploadElem.find(".video-detail-name").text())).toEqual(
fileNames[i] fileNames[i]
); );
expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual( expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual(
i >= concurrentUploadLimit ? queued ?
ActiveVideoUpload.STATUS_QUEUED : ActiveVideoUpload.STATUS_QUEUED :
ActiveVideoUpload.STATUS_UPLOADING ActiveVideoUpload.STATUS_UPLOADING
); );
expect($uploadElem.find(".success").length).toEqual(0); expect($uploadElem.find(".video-detail-progress").attr("value")).toEqual(0);
expect($uploadElem.find(".error").length).toEqual(0); expect($uploadElem).not.toHaveClass("success");
expect($uploadElem).not.toHaveClass("error");
expect($uploadElem.hasClass("queued")).toEqual(queued);
}); });
}); });
// TODO: test progress update; the libraries we are using to mock ajax
// do not currently support progress events. If we upgrade to Jasmine
// 2.0, the latest version of jasmine-ajax (mock-ajax.js) does have the
// necessary support.
_.each( _.each(
[ [
{ {
desc: "completion", desc: "completion",
responseStatus: 204, responseStatus: 204,
statusText: ActiveVideoUpload.STATUS_COMPLETED, statusText: ActiveVideoUpload.STATUS_COMPLETED,
presentSelector: ".success", progressValue: 1,
absentSelector: ".error" presentClass: "success",
absentClass: "error"
}, },
{ {
desc: "failure", desc: "failure",
responseStatus: 500, responseStatus: 500,
statusText: ActiveVideoUpload.STATUS_FAILED, statusText: ActiveVideoUpload.STATUS_FAILED,
presentSelector: ".error", progressValue: 0,
absentSelector: ".success" presentClass: "error",
absentClass: "success"
}, },
], ],
function(subCaseInfo) { function(subCaseInfo) {
...@@ -172,14 +182,17 @@ define( ...@@ -172,14 +182,17 @@ define(
getSentRequests()[0].response({status: subCaseInfo.responseStatus}); getSentRequests()[0].response({status: subCaseInfo.responseStatus});
}); });
it("should update status", function() { it("should update status and progress", function() {
var $uploadElem = this.view.$(".active-video-upload:first"); var $uploadElem = this.view.$(".active-video-upload:first");
expect($uploadElem.length).toEqual(1); expect($uploadElem.length).toEqual(1);
expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual( expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual(
subCaseInfo.statusText subCaseInfo.statusText
); );
expect($uploadElem.find(subCaseInfo.presentSelector).length).toEqual(1); expect(
expect($uploadElem.find(subCaseInfo.absentSelector).length).toEqual(0); $uploadElem.find(".video-detail-progress").attr("value")
).toEqual(subCaseInfo.progressValue);
expect($uploadElem).toHaveClass(subCaseInfo.presentClass);
expect($uploadElem).not.toHaveClass(subCaseInfo.absentClass);
}); });
it("should not trigger the global AJAX error handler", function() { it("should not trigger the global AJAX error handler", function() {
...@@ -195,6 +208,7 @@ define( ...@@ -195,6 +208,7 @@ define(
expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual( expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual(
ActiveVideoUpload.STATUS_UPLOADING ActiveVideoUpload.STATUS_UPLOADING
); );
expect($uploadElem).not.toHaveClass("queued");
}); });
} }
}); });
......
...@@ -2,6 +2,13 @@ define( ...@@ -2,6 +2,13 @@ define(
["js/models/active_video_upload", "js/views/baseview"], ["js/models/active_video_upload", "js/views/baseview"],
function(ActiveVideoUpload, BaseView) { function(ActiveVideoUpload, BaseView) {
"use strict"; "use strict";
var STATUS_CLASSES = [
{status: ActiveVideoUpload.STATUS_QUEUED, cls: "queued"},
{status: ActiveVideoUpload.STATUS_COMPLETED, cls: "success"},
{status: ActiveVideoUpload.STATUS_FAILED, cls: "error"}
];
var ActiveVideoUploadView = BaseView.extend({ var ActiveVideoUploadView = BaseView.extend({
tagName: "li", tagName: "li",
className: "active-video-upload", className: "active-video-upload",
...@@ -12,11 +19,15 @@ define( ...@@ -12,11 +19,15 @@ define(
}, },
render: function() { render: function() {
this.$el.html(this.template(this.model.attributes)); var $el = this.$el;
var $statusEl = this.$el.find(".video-detail-status"); $el.html(this.template(this.model.attributes));
var status = this.model.get("status"); var status = this.model.get("status");
$statusEl.toggleClass("success", status == ActiveVideoUpload.STATUS_COMPLETED); _.each(
$statusEl.toggleClass("error", status == ActiveVideoUpload.STATUS_FAILED); STATUS_CLASSES,
function(statusClass) {
$el.toggleClass(statusClass.cls, status == statusClass.status);
}
);
return this; return this;
}, },
}); });
......
...@@ -36,6 +36,7 @@ define( ...@@ -36,6 +36,7 @@ define(
dragover: this.dragover.bind(this), dragover: this.dragover.bind(this),
add: this.fileUploadAdd.bind(this), add: this.fileUploadAdd.bind(this),
send: this.fileUploadSend.bind(this), send: this.fileUploadSend.bind(this),
progress: this.fileUploadProgress.bind(this),
done: this.fileUploadDone.bind(this), done: this.fileUploadDone.bind(this),
fail: this.fileUploadFail.bind(this) fail: this.fileUploadFail.bind(this)
}); });
...@@ -124,12 +125,22 @@ define( ...@@ -124,12 +125,22 @@ define(
this.collection.get(cid).set("status", status); this.collection.get(cid).set("status", status);
}, },
// progress should be a number between 0 and 1 (inclusive)
setProgress: function(cid, progress) {
this.collection.get(cid).set("progress", progress);
},
fileUploadSend: function(event, data) { fileUploadSend: function(event, data) {
this.setStatus(data.cid, ActiveVideoUpload.STATUS_UPLOADING); this.setStatus(data.cid, ActiveVideoUpload.STATUS_UPLOADING);
}, },
fileUploadProgress: function(event, data) {
this.setProgress(data.cid, data.loaded / data.total);
},
fileUploadDone: function(event, data) { fileUploadDone: function(event, data) {
this.setStatus(data.cid, ActiveVideoUpload.STATUS_COMPLETED); this.setStatus(data.cid, ActiveVideoUpload.STATUS_COMPLETED);
this.setProgress(data.cid, 1);
}, },
fileUploadFail: function(event, data) { fileUploadFail: function(event, data) {
......
...@@ -68,20 +68,62 @@ ...@@ -68,20 +68,62 @@
.video-detail-status { .video-detail-status {
@include font-size(12); @include font-size(12);
@include line-height(12); @include line-height(12);
}
&.error { .video-detail-progress {
color: $color-error; -webkit-appearance: none;
} -moz-appearance: none;
appearance: none;
margin-bottom: ($baseline/2);
border: none;
width: 100%;
height: ($baseline/4);
}
&.success { .video-detail-progress::-webkit-progress-bar {
color: $color-ready; background-color: $white;
} }
// Sadly, these rules must be separate or both Chrome and Firefox break
.video-detail-progress::-webkit-progress-value {
background-color: $color-ready;
}
.video-detail-progress::-moz-progress-bar {
background-color: $color-ready;
} }
&:hover { &:hover {
@include transition(all $tmg-f3); @include transition(all $tmg-f3);
background: $white; background: $white;
} }
&.queued {
.video-detail-progress {
visibility: hidden;
}
}
&.error {
.video-detail-status {
color: $color-error;
}
// Sadly, these rules must be separate or both Chrome and Firefox break
.video-detail-progress::-webkit-progress-value {
background-color: $color-error;
}
.video-detail-progress::-moz-progress-bar {
background-color: $color-error;
}
}
&.success {
.video-detail-status {
color: $color-ready;
}
}
} }
} }
} }
......
<h4 class="video-detail-name"><%- fileName %></h4> <h4 class="video-detail-name"><%- fileName %></h4>
<progress class="video-detail-progress" value="<%= progress %>"></progress>
<p class="video-detail-status"><%- gettext(status) %></p> <p class="video-detail-status"><%- gettext(status) %></p>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment