diff --git a/cms/static/js/index.js b/cms/static/js/index.js index 74239e3a26..e1c91d03a1 100644 --- a/cms/static/js/index.js +++ b/cms/static/js/index.js @@ -2,7 +2,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie "js/views/utils/create_library_utils", "js/views/utils/view_utils"], function (domReady, $, _, CancelOnEscape, CreateCourseUtilsFactory, CreateLibraryUtilsFactory, ViewUtils) { "use strict"; - var CreateCourseUtils = CreateCourseUtilsFactory({ + var CreateCourseUtils = new CreateCourseUtilsFactory({ name: '.new-course-name', org: '.new-course-org', number: '.new-course-number', @@ -21,7 +21,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie error: 'error' }); - var CreateLibraryUtils = CreateLibraryUtilsFactory({ + var CreateLibraryUtils = new CreateLibraryUtilsFactory({ name: '.new-library-name', org: '.new-library-org', number: '.new-library-number', diff --git a/cms/static/js/spec/views/pages/course_rerun_spec.js b/cms/static/js/spec/views/pages/course_rerun_spec.js index ba6cd799aa..01a5b9c858 100644 --- a/cms/static/js/spec/views/pages/course_rerun_spec.js +++ b/cms/static/js/spec/views/pages/course_rerun_spec.js @@ -26,7 +26,7 @@ define(["jquery", "js/common_helpers/ajax_helpers", "js/spec_helpers/view_helper }, mockCreateCourseRerunHTML = readFixtures('mock/mock-create-course-rerun.underscore'); - var CreateCourseUtils = CreateCourseUtilsFactory(selectors, classes); + var CreateCourseUtils = new CreateCourseUtilsFactory(selectors, classes); var fillInFields = function (org, number, run, name) { $(selectors.org).val(org); diff --git a/cms/static/js/views/course_rerun.js b/cms/static/js/views/course_rerun.js index 9ef7a7f265..cf02733b0f 100644 --- a/cms/static/js/views/course_rerun.js +++ b/cms/static/js/views/course_rerun.js @@ -1,6 +1,6 @@ define(["domReady", "jquery", "underscore", "js/views/utils/create_course_utils", "js/views/utils/view_utils"], function (domReady, $, _, CreateCourseUtilsFactory, ViewUtils) { - var CreateCourseUtils = CreateCourseUtilsFactory({ + var CreateCourseUtils = new CreateCourseUtilsFactory({ name: '.rerun-course-name', org: '.rerun-course-org', number: '.rerun-course-number', diff --git a/cms/static/js/views/utils/create_course_utils.js b/cms/static/js/views/utils/create_course_utils.js index 6f01821547..68ee1c7a70 100644 --- a/cms/static/js/views/utils/create_course_utils.js +++ b/cms/static/js/views/utils/create_course_utils.js @@ -1,66 +1,17 @@ /** * Provides utilities for validating courses during creation, for both new courses and reruns. */ -define(["jquery", "underscore", "gettext", "js/views/utils/view_utils"], - function ($, _, gettext, ViewUtils) { +define(["jquery", "gettext", "js/views/utils/view_utils", "js/views/utils/create_utils_base"], + function ($, gettext, ViewUtils, CreateUtilsFactory) { "use strict"; return function (selectors, classes) { - var toggleSaveButton, validateTotalKeyLength, setFieldInErr, - hasInvalidRequiredFields, create, validateFilledFields, configureHandlers; - - var validateRequiredField = ViewUtils.validateRequiredField; - var validateURLItemEncoding = ViewUtils.validateURLItemEncoding; - var keyLengthViolationMessage = gettext("The combined length of the organization, course number, and course run fields cannot be more than <%=limit%> characters."); - var keyFieldSelectors = [selectors.org, selectors.number, selectors.run]; var nonEmptyCheckFieldSelectors = [selectors.name, selectors.org, selectors.number, selectors.run]; - toggleSaveButton = function (is_enabled) { - var is_disabled = !is_enabled; - $(selectors.save).toggleClass(classes.disabled, is_disabled).attr('aria-disabled', is_disabled); - }; + CreateUtilsFactory.call(this, selectors, classes, keyLengthViolationMessage, keyFieldSelectors, nonEmptyCheckFieldSelectors); - // Ensure that key fields passes checkTotalKeyLengthViolations check - validateTotalKeyLength = function () { - ViewUtils.checkTotalKeyLengthViolations( - selectors, classes, - keyFieldSelectors, - keyLengthViolationMessage - ); - }; - - setFieldInErr = function (element, message) { - if (message) { - element.addClass(classes.error); - element.children(selectors.tipError).addClass(classes.showing).removeClass(classes.hiding).text(message); - toggleSaveButton(false); - } - else { - element.removeClass(classes.error); - element.children(selectors.tipError).addClass(classes.hiding).removeClass(classes.showing); - // One "error" div is always present, but hidden or shown - if ($(selectors.error).length === 1) { - toggleSaveButton(true); - } - } - }; - - // One final check for empty values - hasInvalidRequiredFields = function () { - return _.reduce( - nonEmptyCheckFieldSelectors, - function (acc, element) { - var $element = $(element); - var error = validateRequiredField($element.val()); - setFieldInErr($element.parent(), error); - return error ? true : acc; - }, - false - ); - }; - - create = function (courseInfo, errorHandler) { + this.create = function (courseInfo, errorHandler) { $.postJSON( '/course/', courseInfo, @@ -73,59 +24,5 @@ define(["jquery", "underscore", "gettext", "js/views/utils/view_utils"], } ); }; - - // Ensure that all fields are not empty - validateFilledFields = function () { - return _.reduce( - nonEmptyCheckFieldSelectors, - function (acc, element) { - var $element = $(element); - return $element.val().length !== 0 ? acc : false; - }, - true - ); - }; - - // Handle validation asynchronously - configureHandlers = function () { - _.each( - keyFieldSelectors, - function (element) { - var $element = $(element); - $element.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 === $.ui.keyCode.TAB) { - return; - } - var error = validateURLItemEncoding($element.val(), $(selectors.allowUnicode).val() === 'True'); - setFieldInErr($element.parent(), error); - validateTotalKeyLength(); - if (!validateFilledFields()) { - toggleSaveButton(false); - } - }); - } - ); - var $name = $(selectors.name); - $name.on('keyup', function () { - var error = validateRequiredField($name.val()); - setFieldInErr($name.parent(), error); - validateTotalKeyLength(); - if (!validateFilledFields()) { - toggleSaveButton(false); - } - }); - }; - - return { - validateTotalKeyLength: validateTotalKeyLength, - setFieldInErr: setFieldInErr, - hasInvalidRequiredFields: hasInvalidRequiredFields, - create: create, - validateFilledFields: validateFilledFields, - configureHandlers: configureHandlers - }; }; }); diff --git a/cms/static/js/views/utils/create_library_utils.js b/cms/static/js/views/utils/create_library_utils.js index d417e07d93..9cda9580da 100644 --- a/cms/static/js/views/utils/create_library_utils.js +++ b/cms/static/js/views/utils/create_library_utils.js @@ -1,66 +1,17 @@ /** * Provides utilities for validating libraries during creation. */ -define(["jquery", "underscore", "gettext", "js/views/utils/view_utils"], - function ($, _, gettext, ViewUtils) { +define(["jquery", "gettext", "js/views/utils/view_utils", "js/views/utils/create_utils_base"], + function ($, gettext, ViewUtils, CreateUtilsFactory) { "use strict"; return function (selectors, classes) { - var toggleSaveButton, validateTotalKeyLength, setFieldInErr, - hasInvalidRequiredFields, create, validateFilledFields, configureHandlers; - - var validateRequiredField = ViewUtils.validateRequiredField; - var validateURLItemEncoding = ViewUtils.validateURLItemEncoding; - - var keyLengthViolationMessage = gettext("The combined length of the organization and library code fields cannot be more than <%=limit%> characters."); - + var keyLengthViolationMessage = gettext("The combined length of the organization and library code fields cannot be more than <%=limit%> characters.") var keyFieldSelectors = [selectors.org, selectors.number]; var nonEmptyCheckFieldSelectors = [selectors.name, selectors.org, selectors.number]; - toggleSaveButton = function (is_enabled) { - var is_disabled = !is_enabled; - $(selectors.save).toggleClass(classes.disabled, is_disabled).attr('aria-disabled', is_disabled); - }; + CreateUtilsFactory.call(this, selectors, classes, keyLengthViolationMessage, keyFieldSelectors, nonEmptyCheckFieldSelectors); - // Ensure that key fields passes checkTotalKeyLengthViolations check - validateTotalKeyLength = function () { - ViewUtils.checkTotalKeyLengthViolations( - selectors, classes, - keyFieldSelectors, - keyLengthViolationMessage - ); - }; - - setFieldInErr = function (element, message) { - if (message) { - element.addClass(classes.error); - element.children(selectors.tipError).addClass(classes.showing).removeClass(classes.hiding).text(message); - toggleSaveButton(false); - } - else { - element.removeClass(classes.error); - element.children(selectors.tipError).addClass(classes.hiding).removeClass(classes.showing); - // One "error" div is always present, but hidden or shown - if ($(selectors.error).length === 1) { - toggleSaveButton(true); - } - } - }; - - // One final check for empty values - hasInvalidRequiredFields = function () { - return _.reduce( - nonEmptyCheckFieldSelectors, - function (acc, element) { - var $element = $(element); - var error = validateRequiredField($element.val()); - setFieldInErr($element.parent(), error); - return error ? true : acc; - }, - false - ); - }; - - create = function (libraryInfo, errorHandler) { + this.create = function (libraryInfo, errorHandler) { $.postJSON( '/library/', libraryInfo @@ -78,60 +29,6 @@ define(["jquery", "underscore", "gettext", "js/views/utils/view_utils"], } errorHandler(reason); }); - }; - - // Ensure that all fields are not empty - validateFilledFields = function () { - return _.reduce( - nonEmptyCheckFieldSelectors, - function (acc, element) { - var $element = $(element); - return $element.val().length !== 0 ? acc : false; - }, - true - ); - }; - - // Handle validation asynchronously - configureHandlers = function () { - _.each( - keyFieldSelectors, - function (element) { - var $element = $(element); - $element.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 === $.ui.keyCode.TAB) { - return; - } - var error = validateURLItemEncoding($element.val(), $(selectors.allowUnicode).val() === 'True'); - setFieldInErr($element.parent(), error); - validateTotalKeyLength(); - if (!validateFilledFields()) { - toggleSaveButton(false); - } - }); - } - ); - var $name = $(selectors.name); - $name.on('keyup', function () { - var error = validateRequiredField($name.val()); - setFieldInErr($name.parent(), error); - validateTotalKeyLength(); - if (!validateFilledFields()) { - toggleSaveButton(false); - } - }); - }; - - return { - validateTotalKeyLength: validateTotalKeyLength, - setFieldInErr: setFieldInErr, - hasInvalidRequiredFields: hasInvalidRequiredFields, - create: create, - validateFilledFields: validateFilledFields, - configureHandlers: configureHandlers - }; + } }; }); diff --git a/cms/static/js/views/utils/create_utils_base.js b/cms/static/js/views/utils/create_utils_base.js new file mode 100644 index 0000000000..480587223b --- /dev/null +++ b/cms/static/js/views/utils/create_utils_base.js @@ -0,0 +1,123 @@ +/** + * Mixin class for creation of things like courses and libraries. + */ +define(["jquery", "underscore", "gettext", "js/views/utils/view_utils"], + function ($, _, gettext, ViewUtils) { + return function (selectors, classes, keyLengthViolationMessage, keyFieldSelectors, nonEmptyCheckFieldSelectors) { + var self = this; + + this.selectors = selectors; + this.classes = classes; + this.validateRequiredField = ViewUtils.validateRequiredField; + this.validateURLItemEncoding = ViewUtils.validateURLItemEncoding; + this.keyLengthViolationMessage = keyLengthViolationMessage; + // Key fields for your model, like [selectors.org, selectors.number] + this.keyFieldSelectors = keyFieldSelectors; + // Fields that must not be empty on your model. + this.nonEmptyCheckFieldSelectors = nonEmptyCheckFieldSelectors; + + this.create = function (courseInfo, errorHandler) { + // Replace this with a function that will make a request to create the object. + }; + + // Ensure that key fields passes checkTotalKeyLengthViolations check + this.validateTotalKeyLength = function () { + ViewUtils.checkTotalKeyLengthViolations( + self.selectors, self.classes, + self.keyFieldSelectors, + self.keyLengthViolationMessage + ); + }; + + this.toggleSaveButton = function (is_enabled) { + var is_disabled = !is_enabled; + $(self.selectors.save).toggleClass(self.classes.disabled, is_disabled).attr('aria-disabled', is_disabled); + }; + + this.setFieldInErr = function (element, message) { + if (message) { + element.addClass(self.classes.error); + element.children(self.selectors.tipError).addClass(self.classes.showing).removeClass(self.classes.hiding).text(message); + self.toggleSaveButton(false); + } + else { + element.removeClass(self.classes.error); + element.children(self.selectors.tipError).addClass(self.classes.hiding).removeClass(self.classes.showing); + // One "error" div is always present, but hidden or shown + if ($(self.selectors.error).length === 1) { + self.toggleSaveButton(true); + } + } + }; + + // One final check for empty values + this.hasInvalidRequiredFields = function () { + return _.reduce( + self.nonEmptyCheckFieldSelectors, + function (acc, element) { + var $element = $(element); + var error = self.validateRequiredField($element.val()); + self.setFieldInErr($element.parent(), error); + return error ? true : acc; + }, + false + ); + }; + + // Ensure that all fields are not empty + this.validateFilledFields = function () { + return _.reduce( + self.nonEmptyCheckFieldSelectors, + function (acc, element) { + var $element = $(element); + return $element.val().length !== 0 ? acc : false; + }, + true + ); + }; + + // Handle validation asynchronously + this.configureHandlers = function () { + _.each( + self.keyFieldSelectors, + function (element) { + var $element = $(element); + $element.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 === $.ui.keyCode.TAB) { + return; + } + var error = self.validateURLItemEncoding($element.val(), $(self.selectors.allowUnicode).val() === 'True'); + self.setFieldInErr($element.parent(), error); + self.validateTotalKeyLength(); + if (!self.validateFilledFields()) { + self.toggleSaveButton(false); + } + }); + } + ); + + var $name = $(self.selectors.name); + $name.on('keyup', function () { + var error = self.validateRequiredField($name.val()); + self.setFieldInErr($name.parent(), error); + self.validateTotalKeyLength(); + if (!self.validateFilledFields()) { + self.toggleSaveButton(false); + } + }); + }; + + return { + validateTotalKeyLength: self.validateTotalKeyLength, + setFieldInErr: self.setFieldInErr, + hasInvalidRequiredFields: self.hasInvalidRequiredFields, + create: self.create, + validateFilledFields: self.validateFilledFields, + configureHandlers: self.configureHandlers + }; + } + } +);