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(
var ActiveVideoUpload = Backbone.Model.extend(
{
defaults: {
status: statusStrings.STATUS_QUEUED
status: statusStrings.STATUS_QUEUED,
progress: 0
}
},
statusStrings
......
......@@ -131,39 +131,49 @@ define(
);
});
it("should display status", function() {
it("should display upload status and progress", function() {
var spec = this;
expect(this.$uploadElems.length).toEqual(caseInfo.numFiles);
this.$uploadElems.each(function(i, uploadElem) {
var $uploadElem = $(uploadElem);
var queued = i >= concurrentUploadLimit;
expect($.trim($uploadElem.find(".video-detail-name").text())).toEqual(
fileNames[i]
);
expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual(
i >= concurrentUploadLimit ?
queued ?
ActiveVideoUpload.STATUS_QUEUED :
ActiveVideoUpload.STATUS_UPLOADING
);
expect($uploadElem.find(".success").length).toEqual(0);
expect($uploadElem.find(".error").length).toEqual(0);
expect($uploadElem.find(".video-detail-progress").attr("value")).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(
[
{
desc: "completion",
responseStatus: 204,
statusText: ActiveVideoUpload.STATUS_COMPLETED,
presentSelector: ".success",
absentSelector: ".error"
progressValue: 1,
presentClass: "success",
absentClass: "error"
},
{
desc: "failure",
responseStatus: 500,
statusText: ActiveVideoUpload.STATUS_FAILED,
presentSelector: ".error",
absentSelector: ".success"
progressValue: 0,
presentClass: "error",
absentClass: "success"
},
],
function(subCaseInfo) {
......@@ -172,14 +182,17 @@ define(
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");
expect($uploadElem.length).toEqual(1);
expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual(
subCaseInfo.statusText
);
expect($uploadElem.find(subCaseInfo.presentSelector).length).toEqual(1);
expect($uploadElem.find(subCaseInfo.absentSelector).length).toEqual(0);
expect(
$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() {
......@@ -195,6 +208,7 @@ define(
expect($.trim($uploadElem.find(".video-detail-status").text())).toEqual(
ActiveVideoUpload.STATUS_UPLOADING
);
expect($uploadElem).not.toHaveClass("queued");
});
}
});
......
......@@ -2,6 +2,13 @@ define(
["js/models/active_video_upload", "js/views/baseview"],
function(ActiveVideoUpload, BaseView) {
"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({
tagName: "li",
className: "active-video-upload",
......@@ -12,11 +19,15 @@ define(
},
render: function() {
this.$el.html(this.template(this.model.attributes));
var $statusEl = this.$el.find(".video-detail-status");
var $el = this.$el;
$el.html(this.template(this.model.attributes));
var status = this.model.get("status");
$statusEl.toggleClass("success", status == ActiveVideoUpload.STATUS_COMPLETED);
$statusEl.toggleClass("error", status == ActiveVideoUpload.STATUS_FAILED);
_.each(
STATUS_CLASSES,
function(statusClass) {
$el.toggleClass(statusClass.cls, status == statusClass.status);
}
);
return this;
},
});
......
......@@ -36,6 +36,7 @@ define(
dragover: this.dragover.bind(this),
add: this.fileUploadAdd.bind(this),
send: this.fileUploadSend.bind(this),
progress: this.fileUploadProgress.bind(this),
done: this.fileUploadDone.bind(this),
fail: this.fileUploadFail.bind(this)
});
......@@ -124,12 +125,22 @@ define(
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) {
this.setStatus(data.cid, ActiveVideoUpload.STATUS_UPLOADING);
},
fileUploadProgress: function(event, data) {
this.setProgress(data.cid, data.loaded / data.total);
},
fileUploadDone: function(event, data) {
this.setStatus(data.cid, ActiveVideoUpload.STATUS_COMPLETED);
this.setProgress(data.cid, 1);
},
fileUploadFail: function(event, data) {
......
......@@ -68,20 +68,62 @@
.video-detail-status {
@include font-size(12);
@include line-height(12);
}
&.error {
color: $color-error;
}
.video-detail-progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin-bottom: ($baseline/2);
border: none;
width: 100%;
height: ($baseline/4);
}
&.success {
color: $color-ready;
}
.video-detail-progress::-webkit-progress-bar {
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 {
@include transition(all $tmg-f3);
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>
<progress class="video-detail-progress" value="<%= progress %>"></progress>
<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