Commit 8dd4f6ef by Alessandro Verdura

PR feedback

TNL-925

* Fix semicolons
* Use stage constants
* Group var declarations
* Add errorStage function
* Use constant for cookie name
* Use promises instead of callbacks
* Use fn.bind
* Improve error handling on upload stage
parent a299af9e
......@@ -5,14 +5,6 @@ define([
'use strict';
return function (feedbackUrl, library) {
var dbError;
if (library) {
dbError = gettext('There was an error while importing the new library to our database.');
} else {
dbError = gettext('There was an error while importing the new course to our database.');
}
var bar = $('.progress-bar'),
fill = $('.progress-fill'),
submitBtn = $('.submit-button'),
......@@ -24,14 +16,21 @@ define([
dbError + '\n'
],
previousImport = Import.storedImport(),
dbError,
file;
Import.callbacks.complete = function () {
var onComplete = function () {
bar.hide();
chooseBtn
.find('.copy').html(gettext("Choose new file")).end()
.show();
};
}
if (library) {
dbError = gettext('There was an error while importing the new library to our database.');
} else {
dbError = gettext('There was an error while importing the new course to our database.');
}
// Display the status of last file upload on page load
if (previousImport) {
......@@ -43,7 +42,7 @@ define([
chooseBtn.hide();
}
Import.resume();
Import.resume().then(onComplete);
}
$('#fileupload').fileupload({
......@@ -64,7 +63,7 @@ define([
Import.start(
file.name,
feedbackUrl.replace('fillerName', file.name)
);
).then(onComplete);
submitBtn.hide();
data.submit().complete(function (result, textStatus, xhr) {
......@@ -72,20 +71,15 @@ define([
var serverMsg, errMsg, stage;
try{
serverMsg = $.parseJSON(result.responseText);
serverMsg = $.parseJSON(result.responseText) || {};
} catch (e) {
return;
}
errMsg = serverMsg.hasOwnProperty('ErrMsg') ? serverMsg.ErrMsg : '' ;
errMsg = serverMsg.hasOwnProperty('ErrMsg') ? serverMsg.ErrMsg : '';
stage = Math.abs(serverMsg.Stage || 0);
if (serverMsg.hasOwnProperty('Stage')) {
stage = Math.abs(serverMsg.Stage);
Import.error(defaults[stage] + errMsg, stage);
}
else {
alert(gettext('Your import has failed.') + '\n\n' + errMsg);
}
Import.error(defaults[stage] + errMsg, stage);
}
});
});
......
......@@ -9,14 +9,25 @@ define(
/********** Private properties ****************************************/
var COOKIE_NAME = 'lastfileupload';
var STAGE = {
'UPLOADING': 0,
'UNPACKING': 1,
'VERIFYING': 2,
'UPDATING' : 3,
'SUCCESS' : 4
};
var STATE = {
'READY' : 1,
'IN_PROGRESS': 2,
'SUCCESS' : 3,
'ERROR' : 4
}
};
var current = { stage: 0, state: STATE.READY };
var deferred = null;
var file = { name: null, url: null };
var timeout = { id: null, delay: 1000 };
var $dom = {
......@@ -34,7 +45,7 @@ define(
*/
var destroyEventListeners = function () {
window.onbeforeunload = null;
}
};
/**
* Makes Import feedback status list visible
......@@ -50,15 +61,27 @@ define(
*/
var initEventListeners = function () {
window.onbeforeunload = function () {
if (current.stage <= 1 ) {
if (current.stage <= STAGE.UNPACKING) {
return gettext('Your import is in progress; navigating away will abort it.');
}
}
}
};
/**
* Stores in a cookie the current import data
*
* @param {boolean} [completed=false] If the import has been completed or not
*/
var storeImport = function (completed) {
$.cookie(COOKIE_NAME, JSON.stringify({
file: file,
date: moment().valueOf(),
completed: completed || false
}));
};
/**
* Sets the Import on the "success" status
* (callbacks: complete)
*
* If it wasn't already, marks the stored import as "completed",
* and updates its date timestamp
......@@ -73,9 +96,7 @@ define(
destroyEventListeners();
updateFeedbackList();
if (typeof CourseImport.callbacks.complete === 'function') {
CourseImport.callbacks.complete();
}
deferred.resolve();
};
/**
......@@ -85,7 +106,10 @@ define(
* current stage (for now only in case of error)
*/
var updateFeedbackList = function (currStageMsg) {
var $checkmark = $dom.successStage.find('.icon');
var $checkmark, $curr, $prev, $next;
var date, successUnix, time;
$checkmark = $dom.successStage.find('.icon');
currStageMsg = currStageMsg || '';
function completeStage(stage) {
......@@ -94,6 +118,20 @@ define(
.addClass("is-complete");
}
function errorStage(stage) {
var $stage = $(stage);
var error = currStageMsg;
if (!$stage.hasClass('has-error')) {
$stage
.removeClass('is-started')
.addClass('has-error')
.find('p.copy')
.hide()
.after("<p class='copy error'>" + error + "</p>");
}
}
function resetStage(stage) {
$(stage)
.removeClass("is-complete is-started has-error")
......@@ -109,8 +147,8 @@ define(
break;
case STATE.IN_PROGRESS:
var $prev = $dom.stages.slice(0, current.stage);
var $curr = $dom.stages.eq(current.stage);
$prev = $dom.stages.slice(0, current.stage);
$curr = $dom.stages.eq(current.stage);
_.map($prev, completeStage);
$curr.removeClass("is-not-started").addClass("is-started");
......@@ -118,9 +156,9 @@ define(
break;
case STATE.SUCCESS:
var successUnix = CourseImport.storedImport().date;
var date = moment(successUnix).utc().format('MM/DD/YYYY');
var time = moment(successUnix).utc().format('HH:mm');
successUnix = CourseImport.storedImport().date;
date = moment(successUnix).utc().format('MM/DD/YYYY');
time = moment(successUnix).utc().format('HH:mm');
_.map($dom.stages, completeStage);
......@@ -132,22 +170,13 @@ define(
case STATE.ERROR:
// Make all stages up to, and including, the error stage 'complete'.
var $prev = $dom.stages.slice(0, current.stage + 1);
var $curr = $dom.stages.eq(current.stage);
var $next = $dom.stages.slice(current.stage + 1);
var error = currStageMsg || gettext("There was an error with the upload");
$prev = $dom.stages.slice(0, current.stage + 1);
$curr = $dom.stages.eq(current.stage);
$next = $dom.stages.slice(current.stage + 1);
_.map($prev, completeStage);
_.map($next, resetStage);
if (!$curr.hasClass('has-error')) {
$curr
.removeClass('is-started')
.addClass('has-error')
.find('p.copy')
.hide()
.after("<p class='copy error'>" + error + "</p>");
}
errorStage($curr);
break;
}
......@@ -159,34 +188,12 @@ define(
}
};
/**
* Stores in a cookie the current import data
*
* @param {boolean} [completed=false] If the import has been completed or not
*/
var storeImport = function (completed) {
$.cookie('lastfileupload', JSON.stringify({
file: file,
date: moment().valueOf(),
completed: completed || false
}));
}
/********** Public functions ******************************************/
var CourseImport = {
/**
* A collection of callbacks.
* For now the only supported is 'complete', called on success/error
*
*/
callbacks: {},
/**
* Sets the Import in the "error" status.
* (callbacks: complete)
*
* Immediately stops any further polling from the server.
* Displays the error message at the list element that corresponds
......@@ -203,9 +210,7 @@ define(
clearTimeout(timeout.id);
updateFeedbackList(msg);
if (typeof this.callbacks.complete === 'function') {
this.callbacks.complete();
}
deferred.resolve();
},
/**
......@@ -217,26 +222,24 @@ define(
* @param {int} [stage=0] Starting stage.
*/
pollStatus: function (stage) {
var self = this;
if (current.state !== STATE.IN_PROGRESS) {
return;
}
current.stage = stage || 0;
current.stage = stage || STAGE.UPLOADING;
if (current.stage === 4) { // Succeeded
if (current.stage === STAGE.SUCCESS) {
success();
} else if (current.stage < 0) { // Failed
} else if (current.stage < STAGE.UPLOADING) { // Failed
this.error(gettext("Error importing course"));
} else { // In progress
updateFeedbackList();
$.getJSON(file.url, function (data) {
timeout.id = setTimeout(function () {
self.pollStatus(data.ImportStatus);
}, timeout.delay);
});
this.pollStatus(data.ImportStatus);
}.bind(this), timeout.delay);
}.bind(this));
}
},
......@@ -245,7 +248,7 @@ define(
*
*/
reset: function () {
current.stage = 0;
current.stage = STAGE.UPLOADING;
current.state = STATE.READY;
updateFeedbackList();
......@@ -255,22 +258,28 @@ define(
* Show last import status from server and start sending requests
* to the server for status updates
*
* @return {jQuery promise}
*/
resume: function () {
var self = this;
file = self.storedImport().file;
deferred = $.Deferred();
file = this.storedImport().file;
$.getJSON(file.url, function (data) {
current.stage = data.ImportStatus;
if (current.stage !== 0) {
displayFeedbackList();
if (current.stage !== STAGE.UPLOADING) {
current.state = STATE.IN_PROGRESS;
displayFeedbackList();
self.pollStatus(current.stage);
this.pollStatus(current.stage);
} else {
// An import in the upload stage cannot be resumed
this.error(gettext("There was an error with the upload"));
}
});
}.bind(this));
return deferred.promise();
},
/**
......@@ -280,9 +289,11 @@ define(
* @param {string} fileName The name of the file to import
* @param {string} fileUrl The full URL to use to query the server
* about the import status
* @return {jQuery promise}
*/
start: function (fileName, fileUrl) {
current.state = STATE.IN_PROGRESS;
deferred = $.Deferred();
file.name = fileName;
file.url = fileUrl;
......@@ -291,6 +302,8 @@ define(
storeImport();
displayFeedbackList();
updateFeedbackList();
return deferred.promise();
},
/**
......@@ -299,7 +312,7 @@ define(
* @return {JSON} the data of the previous import
*/
storedImport: function () {
return JSON.parse($.cookie('lastfileupload'));
return JSON.parse($.cookie(COOKIE_NAME));
}
};
......
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