/** * Mixin class for creation of things like courses and libraries. */ define(['jquery', 'underscore', 'gettext', 'common/js/components/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 }; }; } );