Source: Element/FormGroup.js

/**
                * @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
                */

                /**
                * Qfq Namespace
                *
                * @namespace QfqNS
                */
                var QfqNS = QfqNS || {};
                /**
                * Qfq.Element Namespace
                *
                * @namespace QfqNS.Element
                */
                QfqNS.Element = QfqNS.Element || {};

                (function (n) {
                'use strict';

                /**
                * Form Group represents a `<input>/<select>` element including the label and help block.
                *
                * It is not meant to be used directly. Use the specialized objects instead.
                *
                * @param $enclosedElement {jQuery} a jQuery object contained in the Form Group. It used to find the
                enclosing
                * HTML element having the `.form-group` class assigned.
                *
                *
                * @constructor
                * @name QfqNS.Element.FormGroup
                */
                n.FormGroup = function ($enclosedElement) {
                if (!$enclosedElement || $enclosedElement.length === 0) {
                throw new Error("No enclosed element");
                }

                this.$formGroup = this.$findFormGroup($enclosedElement);
                this.$element = this.$formGroup.find('input:not([type="hidden"]), select');
                this.$label = this.$formGroup.find('.control-label');
                this.$helpBlock = this.$formGroup.find(".help-block");
                };

                /**
                * Test if the Form Group is of the given type
                *
                * @param {string} type type name
                * @returns {boolean} true if the Form Group is of the given type. False otherwise
                * @protected
                */
                n.FormGroup.prototype.isType = function (type) {
                var lowerCaseType = type.toLowerCase();
                var isOfType = true;
                this.$element.each(function () {
                if (this.hasAttribute('type')) {
                if (this.getAttribute('type') === lowerCaseType) {
                return true;
                } else {
                isOfType = false;
                return false;
                }
                } else {
                // <select> is not an attribute value, obviously, so check for nodename
                if (this.nodeName.toLowerCase() === lowerCaseType) {
                return true;
                } else if (lowerCaseType === 'text') {
                return true;
                } else {
                isOfType = false;
                return false;
                }
                }
                });

                return isOfType;
                };

                /**
                *
                * @param $enclosedElement
                * @returns {*}
                *
                * @private
                */
                n.FormGroup.prototype.$findFormGroup = function ($enclosedElement) {
                var $formGroup = $enclosedElement.closest("div.form-group");

                if (!$formGroup || $formGroup.length === 0) {
                throw new Error("Unable to find Form Group");
                }

                if ($formGroup.length > 1) {
                throw new Error("enclosed element yields ambiguous form group");
                }

                return $formGroup;
                };

                /**
                * @public
                * @returns {boolean}
                */
                n.FormGroup.prototype.hasLabel = function () {
                return this.$label.length > 0;
                };

                /**
                * @public
                * @returns {boolean}
                */
                n.FormGroup.prototype.hasHelpBlock = function () {
                return this.$helpBlock.length > 0;
                };

                /**
                * @deprecated
                *
                * Read-only is mapped onto setEnabled(). We do not distinguish between those two.
                *
                * @param readonly
                * @public
                */
                n.FormGroup.prototype.setReadOnly = function (readonly) {
                this.setEnabled(!readonly);
                };

                /**
                * @public
                * @param enabled
                */
                n.FormGroup.prototype.setEnabled = function (enabled) {
                this.$element.prop('disabled', !enabled);

                if (enabled) {
                this.$formGroup.removeClass("text-muted");
                this.$label.removeClass("disabled");
                this.$element.parents("div.radio").removeClass("disabled");
                } else {
                this.$formGroup.addClass("text-muted");
                this.$label.addClass("disabled");
                this.$element.parents("div.radio").addClass("disabled");
                }
                };

                /**
                * @public
                * @param hidden
                */
                n.FormGroup.prototype.setHidden = function (hidden) {
                if (hidden) {
                this.$formGroup.addClass("hidden");
                } else {
                this.$formGroup.removeClass("hidden");
                }
                };

                n.FormGroup.prototype.setRequired = function (required) {
                this.$element.prop('required', required);
                };

                })(QfqNS.Element);