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