Commit 8fa4b4db by Peter Fogg

Change course create form to synchronous validation.

parent d1e0005f
...@@ -8,6 +8,6 @@ Feature: Create Course ...@@ -8,6 +8,6 @@ Feature: Create Course
And I am logged into Studio And I am logged into Studio
When I click the New Course button When I click the New Course button
And I fill in the new course information And I fill in the new course information
And I press the "Save" button And I press the "Create" button
Then the Courseware page has loaded in Studio Then the Courseware page has loaded in Studio
And I see a link for adding a new section And I see a link for adding a new section
...@@ -605,80 +605,118 @@ function cancelNewSection(e) { ...@@ -605,80 +605,118 @@ function cancelNewSection(e) {
function addNewCourse(e) { function addNewCourse(e) {
e.preventDefault(); e.preventDefault();
$('.new-course-button').addClass('is-disabled'); $('.new-course-button').addClass('is-disabled');
$('.new-course-save').addClass('is-disabled');
var $newCourse = $('.wrapper-create-course').addClass('is-shown'); var $newCourse = $('.wrapper-create-course').addClass('is-shown');
var $cancelButton = $newCourse.find('.new-course-cancel'); var $cancelButton = $newCourse.find('.new-course-cancel');
$newCourse.find('.new-course-name').focus().select(); var $courseName = $('.new-course-name');
$newCourse.find('form').bind('submit', saveNewCourse); $courseName.focus().select();
$('.new-course-save').on('click', saveNewCourse);
$cancelButton.bind('click', cancelNewCourse); $cancelButton.bind('click', cancelNewCourse);
$body.bind('keyup', { $body.bind('keyup', {
$cancelButton: $cancelButton $cancelButton: $cancelButton
}, checkForCancel); }, checkForCancel);
// Handle validation asynchronously
_.each(
['.new-course-org', '.new-course-number', '.new-course-run'],
function(ele) {
var $ele = $(ele);
$ele.on('keyup', function(event) {
// Don't bother showing "required field" error when
// the user tabs into a new field; this is distracting
// and unnecessary
if(event.keyCode === 9) {
return;
}
var error = validateCourseItemEncoding($ele.val());
setNewCourseFieldInErr($ele.parent('li'), error);
validateTotalCourseItemsLength();
});
}
);
var $name = $('.new-course-name');
$name.on('keyup', function() {
var error = validateCourseName($name.val());
setNewCourseFieldInErr($name.parent('li'), error);
validateTotalCourseItemsLength();
});
} }
function saveNewCourse(e) { function setNewCourseFieldInErr(el, msg) {
e.preventDefault(); el.children('.tip-error').remove();
if(msg) {
var $newCourseForm = $(this).closest('#create-course-form'); el.addClass('error');
var display_name = $newCourseForm.find('.new-course-name').val(); el.append('<span class="tip tip-error">' + msg + '</span>');
var org = $newCourseForm.find('.new-course-org').val(); $('.new-course-save').addClass('is-disabled');
var number = $newCourseForm.find('.new-course-number').val(); }
var run = $newCourseForm.find('.new-course-run').val(); else {
el.removeClass('error');
var required_field_text = gettext('Required field'); // One "error" div is always present, but hidden or shown
if($('.error').length === 1) {
var display_name_errMsg = (display_name === '') ? required_field_text : null; $('.new-course-save').removeClass('is-disabled');
var org_errMsg = (org === '') ? required_field_text : null; }
var number_errMsg = (number === '') ? required_field_text : null; }
var run_errMsg = (run === '') ? required_field_text : null; };
var bInErr = (display_name_errMsg || org_errMsg || number_errMsg || run_errMsg);
// check for suitable encoding
if (!bInErr) {
var encoding_errMsg = gettext('Please do not use any spaces or special characters in this field.');
if (encodeURIComponent(org) != org)
org_errMsg = encoding_errMsg;
if (encodeURIComponent(number) != number)
number_errMsg = encoding_errMsg;
if (encodeURIComponent(run) != run)
run_errMsg = encoding_errMsg;
bInErr = (org_errMsg || number_errMsg || run_errMsg); function validateCourseName(name) {
if(name.length === 0) {
return gettext('Required field.');
} }
return '';
}
var header_err_msg = (bInErr) ? gettext('Please correct the fields below.') : null; // Check that a course (org, number, run) doesn't use any special characters
function validateCourseItemEncoding(item) {
if(item === '') {
return gettext('Required field.');
}
if(item !== encodeURIComponent(item)) {
return gettext('Please do not use any spaces or special characters in this field.');
}
return '';
}
var setNewCourseErrMsgs = function(header_err_msg, display_name_errMsg, org_errMsg, number_errMsg, run_errMsg) { // Ensure that all items are less than 80 characters.
if (header_err_msg) { function validateTotalCourseItemsLength() {
$('.wrapper-create-course').addClass('has-errors'); var totalLength = _.reduce(
['.new-course-name', '.new-course-org', '.new-course-number', '.new-course-run'],
function(sum, ele) {
return sum + $(ele).val().length;
}, 0
);
if(totalLength > 80) {
$('.wrap-error').addClass('is-shown'); $('.wrap-error').addClass('is-shown');
$('#course_creation_error').html('<p>' + header_err_msg + '</p>'); $('#course_creation_error').html('<p>' + gettext('Course fields must have a combined length of no more than 80 characters.') + '</p>');
} else { $('.new-course-save').addClass('is-disabled');
}
else {
$('.wrap-error').removeClass('is-shown'); $('.wrap-error').removeClass('is-shown');
$('#course_creation_error').html('');
} }
}
var setNewCourseFieldInErr = function(el, msg) { function saveNewCourse(e) {
el.children('.tip-error').remove(); e.preventDefault();
if (msg !== null && msg !== '') {
el.addClass('error');
el.append('<span class="tip tip-error">' + msg + '</span>');
} else {
el.removeClass('error');
}
};
setNewCourseFieldInErr($('#field-course-name'), display_name_errMsg); // One final check for empty values
setNewCourseFieldInErr($('#field-organization'), org_errMsg); var errors = _.reduce(
setNewCourseFieldInErr($('#field-course-number'), number_errMsg); ['.new-course-name', '.new-course-org', '.new-course-number', '.new-course-run'],
setNewCourseFieldInErr($('#field-course-run'), run_errMsg); function(acc, ele) {
}; var $ele = $(ele);
var error = $ele.val().length === 0 ? gettext('Required field.') : '';
setNewCourseFieldInErr($ele.parent('li'), error);
return error ? true : acc;
},
false
);
setNewCourseErrMsgs(header_err_msg, display_name_errMsg, org_errMsg, number_errMsg, run_errMsg); var $newCourseForm = $(this).closest('#create-course-form');
var display_name = $newCourseForm.find('.new-course-name').val();
var org = $newCourseForm.find('.new-course-org').val();
var number = $newCourseForm.find('.new-course-number').val();
var run = $newCourseForm.find('.new-course-run').val();
if (bInErr) if(errors) {
return; return;
}
analytics.track('Created a Course', { analytics.track('Created a Course', {
'org': org, 'org': org,
...@@ -698,8 +736,13 @@ function saveNewCourse(e) { ...@@ -698,8 +736,13 @@ function saveNewCourse(e) {
window.location = '/' + data.id.replace(/.*:\/\//, ''); window.location = '/' + data.id.replace(/.*:\/\//, '');
} else if (data.ErrMsg !== undefined) { } else if (data.ErrMsg !== undefined) {
var orgErrMsg = (data.OrgErrMsg !== undefined) ? data.OrgErrMsg : null; var orgErrMsg = (data.OrgErrMsg !== undefined) ? data.OrgErrMsg : null;
if(orgErrMsg) {
setNewCourseFieldInErr($('.new-course-org').parent('li'), orgErrMsg);
}
var courseErrMsg = (data.CourseErrMsg !== undefined) ? data.CourseErrMsg : null; var courseErrMsg = (data.CourseErrMsg !== undefined) ? data.CourseErrMsg : null;
setNewCourseErrMsgs(data.ErrMsg, null, orgErrMsg, courseErrMsg, null); if(courseErrMsg) {
setNewCourseFieldInErr($('.new-course-number').parent('li'), orgErrMsg);
}
} }
} }
); );
......
...@@ -226,7 +226,6 @@ form[class^="create-"] { ...@@ -226,7 +226,6 @@ form[class^="create-"] {
} }
.tip-error { .tip-error {
@extend .anim-fadeIn;
display: block; display: block;
color: $red; color: $red;
} }
......
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
</div> </div>
<div class="actions"> <div class="actions">
<input type="submit" value="${_('Save')}" class="action action-primary new-course-save" /> <input type="submit" value="${_('Create')}" class="action action-primary new-course-save" />
<input type="button" value="${_('Cancel')}" class="action action-secondary action-cancel new-course-cancel" /> <input type="button" value="${_('Cancel')}" class="action action-secondary action-cancel new-course-cancel" />
</div> </div>
</form> </form>
......
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