Merge pull request #6733 from edx/gprice/video-upload-progress-bar
Add progress bars for Studio video uploads
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
<h4 class="video-detail-name"><%- fileName %></h4>
|
||||
<progress class="video-detail-progress" value="<%= progress %>"></progress>
|
||||
<p class="video-detail-status"><%- gettext(status) %></p>
|
||||
|
||||
Reference in New Issue
Block a user