/*! * bootstrap-material-design v4.0.2 (https://github.com/FezVrasta/bootstrap-material-design) * Copyright 2016 Federico Zivolo and contributors * Licensed under MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('babel-polyfill'), require('bootstrap/dist/js/bootstrap')) : typeof define === 'function' && define.amd ? define(['babel-polyfill', 'bootstrap/dist/js/bootstrap'], factory) : (factory(global.babelPolyfill,global.bootstrap_dist_js_bootstrap)); }(this, function (babelPolyfill,bootstrap_dist_js_bootstrap) { 'use strict'; var Util = function () { /** * ------------------------------------------------------------------------ * Private TransitionEnd Helpers * ------------------------------------------------------------------------ */ var transitionEnd = false; var _transitionEndSelector = ''; var TransitionEndEvent = { WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', OTransition: 'oTransitionEnd otransitionend', transition: 'transitionend' }; function transitionEndTest() { if (window.QUnit) { return false; } var el = document.createElement('bmd'); for (var name in TransitionEndEvent) { if (el.style[name] !== undefined) { return TransitionEndEvent[name]; // { end: TransitionEndEvent[name] } } } return false; } function setTransitionEndSupport() { transitionEnd = transitionEndTest(); // generate a concatenated transition end event selector for (var name in TransitionEndEvent) { _transitionEndSelector += ' ' + TransitionEndEvent[name]; } } /** * -------------------------------------------------------------------------- * Public Util Api * -------------------------------------------------------------------------- */ var Util = { transitionEndSupported: function transitionEndSupported() { return transitionEnd; }, transitionEndSelector: function transitionEndSelector() { return _transitionEndSelector; }, isChar: function isChar(event) { if (typeof event.which === 'undefined') { return true; } else if (typeof event.which === 'number' && event.which > 0) { return !event.ctrlKey && !event.metaKey && !event.altKey && event.which !== 8 // backspace && event.which !== 9 // tab && event.which !== 13 // enter && event.which !== 16 // shift && event.which !== 17 // ctrl && event.which !== 20 // caps lock && event.which !== 27 // escape ; } return false; }, assert: function assert($element, invalidTest, message) { if (invalidTest) { if (!$element === undefined) { $element.css('border', '1px solid red'); } console.error(message, $element); // eslint-disable-line no-console throw message; } }, describe: function describe($element) { if ($element === undefined) { return 'undefined'; } else if ($element.length === 0) { return '(no matching elements)'; } return $element[0].outerHTML.split('>')[0] + '>'; } }; setTransitionEndSupport(); return Util; }(jQuery); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var Base = function ($) { var ClassName = { BMD_FORM_GROUP: 'bmd-form-group', IS_FILLED: 'is-filled', IS_FOCUSED: 'is-focused' }; var Selector = { BMD_FORM_GROUP: '.' + ClassName.BMD_FORM_GROUP }; var Default = {}; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ var Base = function () { /** * * @param element * @param config * @param properties - anything that needs to be set as this[key] = value. Works around the need to call `super` before using `this` */ function Base($element, config) { var properties = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; classCallCheck(this, Base); this.$element = $element; this.config = $.extend(true, {}, Default, config); // set properties for use in the constructor initialization for (var key in properties) { this[key] = properties[key]; } } createClass(Base, [{ key: 'dispose', value: function dispose(dataKey) { this.$element.data(dataKey, null); this.$element = null; this.config = null; } // ------------------------------------------------------------------------ // protected }, { key: 'addFormGroupFocus', value: function addFormGroupFocus() { if (!this.$element.prop('disabled')) { this.$bmdFormGroup.addClass(ClassName.IS_FOCUSED); } } }, { key: 'removeFormGroupFocus', value: function removeFormGroupFocus() { this.$bmdFormGroup.removeClass(ClassName.IS_FOCUSED); } }, { key: 'removeIsFilled', value: function removeIsFilled() { this.$bmdFormGroup.removeClass(ClassName.IS_FILLED); } }, { key: 'addIsFilled', value: function addIsFilled() { this.$bmdFormGroup.addClass(ClassName.IS_FILLED); } // Find bmd-form-group }, { key: 'findMdbFormGroup', value: function findMdbFormGroup() { var raiseError = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; var mfg = this.$element.closest(Selector.BMD_FORM_GROUP); if (mfg.length === 0 && raiseError) { $.error('Failed to find ' + Selector.BMD_FORM_GROUP + ' for ' + Util.describe(this.$element)); } return mfg; } // ------------------------------------------------------------------------ // private // ------------------------------------------------------------------------ // static }]); return Base; }(); return Base; }(jQuery); var BaseInput = function ($) { var ClassName = { FORM_GROUP: 'form-group', BMD_FORM_GROUP: 'bmd-form-group', BMD_LABEL: 'bmd-label', BMD_LABEL_STATIC: 'bmd-label-static', BMD_LABEL_PLACEHOLDER: 'bmd-label-placeholder', BMD_LABEL_FLOATING: 'bmd-label-floating', HAS_DANGER: 'has-danger', IS_FILLED: 'is-filled', IS_FOCUSED: 'is-focused', INPUT_GROUP: 'input-group' }; var Selector = { FORM_GROUP: '.' + ClassName.FORM_GROUP, BMD_FORM_GROUP: '.' + ClassName.BMD_FORM_GROUP, BMD_LABEL_WILDCARD: 'label[class^=\'' + ClassName.BMD_LABEL + '\'], label[class*=\' ' + ClassName.BMD_LABEL + '\']' // match any label variant if specified }; var Default = { validate: false, formGroup: { required: false }, bmdFormGroup: { template: '', create: true, // create a wrapper if form-group not found required: true // not recommended to turn this off, only used for inline components }, label: { required: false, // Prioritized find order for resolving the label to be used as an bmd-label if not specified in the markup // - a function(thisComponent); or // - a string selector used like $bmdFormGroup.find(selector) // // Note this only runs if $bmdFormGroup.find(Selector.BMD_LABEL_WILDCARD) fails to find a label (as authored in the markup) // selectors: ['.form-control-label', // in the case of horizontal or inline forms, this will be marked '> label' // usual case for text inputs, first child. Deeper would find toggle labels so don't do that. ], className: ClassName.BMD_LABEL_STATIC }, requiredClasses: [], invalidComponentMatches: [], convertInputSizeVariations: true }; var FormControlSizeMarkers = { 'form-control-lg': 'bmd-form-group-lg', 'form-control-sm': 'bmd-form-group-sm' }; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ var BaseInput = function (_Base) { inherits(BaseInput, _Base); /** * * @param element * @param config * @param properties - anything that needs to be set as this[key] = value. Works around the need to call `super` before using `this` */ function BaseInput($element, config) { var properties = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; classCallCheck(this, BaseInput); // Enforce no overlap between components to prevent side effects var _this = possibleConstructorReturn(this, Object.getPrototypeOf(BaseInput).call(this, $element, $.extend(true, {}, Default, config), properties)); _this._rejectInvalidComponentMatches(); // Enforce expected structure (if any) _this.rejectWithoutRequiredStructure(); // Enforce required classes for a consistent rendering _this._rejectWithoutRequiredClasses(); // Resolve the form-group first, it will be used for bmd-form-group if possible // note: different components have different rules _this.$formGroup = _this.findFormGroup(_this.config.formGroup.required); // Will add bmd-form-group to form-group or create an bmd-form-group // Performance Note: for those forms that are really performance driven, create the markup with the .bmd-form-group to avoid // rendering changes once added. _this.$bmdFormGroup = _this.resolveMdbFormGroup(); // Resolve and mark the bmdLabel if necessary as defined by the config _this.$bmdLabel = _this.resolveMdbLabel(); // Signal to the bmd-form-group that a form-control-* variation is being used _this.resolveMdbFormGroupSizing(); _this.addFocusListener(); _this.addChangeListener(); if (_this.$element.val() != '') { _this.addIsFilled(); } return _this; } createClass(BaseInput, [{ key: 'dispose', value: function dispose(dataKey) { get(Object.getPrototypeOf(BaseInput.prototype), 'dispose', this).call(this, dataKey); this.$bmdFormGroup = null; this.$formGroup = null; } // ------------------------------------------------------------------------ // protected }, { key: 'rejectWithoutRequiredStructure', value: function rejectWithoutRequiredStructure() { // implement } }, { key: 'addFocusListener', value: function addFocusListener() { var _this2 = this; this.$element.on('focus', function () { _this2.addFormGroupFocus(); }).on('blur', function () { _this2.removeFormGroupFocus(); }); } }, { key: 'addChangeListener', value: function addChangeListener() { var _this3 = this; this.$element.on('keydown paste', function (event) { if (Util.isChar(event)) { _this3.addIsFilled(); } }).on('keyup change', function () { // make sure empty is added back when there is a programmatic value change. // NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change') if (_this3.isEmpty()) { _this3.removeIsFilled(); } else { _this3.addIsFilled(); } if (_this3.config.validate) { // Validation events do not bubble, so they must be attached directly to the text: http://jsfiddle.net/PEpRM/1/ // Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter // the form-group on change. // // NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code. // BUT, I've left it here for backwards compatibility. var isValid = typeof _this3.$element[0].checkValidity === 'undefined' || _this3.$element[0].checkValidity(); if (isValid) { _this3.removeHasDanger(); } else { _this3.addHasDanger(); } } }); } }, { key: 'addHasDanger', value: function addHasDanger() { this.$bmdFormGroup.addClass(ClassName.HAS_DANGER); } }, { key: 'removeHasDanger', value: function removeHasDanger() { this.$bmdFormGroup.removeClass(ClassName.HAS_DANGER); } }, { key: 'isEmpty', value: function isEmpty() { return this.$element.val() === null || this.$element.val() === undefined || this.$element.val() === ''; } // Will add bmd-form-group to form-group or create a bmd-form-group if necessary }, { key: 'resolveMdbFormGroup', value: function resolveMdbFormGroup() { var mfg = this.findMdbFormGroup(false); if (mfg === undefined || mfg.length === 0) { if (this.config.bmdFormGroup.create && (this.$formGroup === undefined || this.$formGroup.length === 0)) { // If a form-group doesn't exist (not recommended), take a guess and wrap the element (assuming no label). // note: it's possible to make this smarter, but I need to see valid cases before adding any complexity. // this may be an input-group, wrap that instead if (this.outerElement().parent().hasClass(ClassName.INPUT_GROUP)) { this.outerElement().parent().wrap(this.config.bmdFormGroup.template); } else { this.outerElement().wrap(this.config.bmdFormGroup.template); } } else { // a form-group does exist, add our marker class to it this.$formGroup.addClass(ClassName.BMD_FORM_GROUP); // OLD: may want to implement this after all, see how the styling turns out, but using an existing form-group is less manipulation of the dom and therefore preferable // A form-group does exist, so add an bmd-form-group wrapping it's internal contents //fg.wrapInner(this.config.bmdFormGroup.template) } mfg = this.findMdbFormGroup(this.config.bmdFormGroup.required); } return mfg; } // Demarcation element (e.g. first child of a form-group) // Subclasses such as file inputs may have different structures }, { key: 'outerElement', value: function outerElement() { return this.$element; } // Will add bmd-label to bmd-form-group if not already specified }, { key: 'resolveMdbLabel', value: function resolveMdbLabel() { var label = this.$bmdFormGroup.find(Selector.BMD_LABEL_WILDCARD); if (label === undefined || label.length === 0) { // we need to find it based on the configured selectors label = this.findMdbLabel(this.config.label.required); if (label === undefined || label.length === 0) { // no label found, and finder did not require one } else { // a candidate label was found, add the configured default class name label.addClass(this.config.label.className); } } return label; } // Find bmd-label variant based on the config selectors }, { key: 'findMdbLabel', value: function findMdbLabel() { var raiseError = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; var label = null; // use the specified selector order var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this.config.label.selectors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var selector = _step.value; if ($.isFunction(selector)) { label = selector(this); } else { label = this.$bmdFormGroup.find(selector); } if (label !== undefined && label.length > 0) { break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } if (label.length === 0 && raiseError) { $.error('Failed to find ' + Selector.BMD_LABEL_WILDCARD + ' within form-group for ' + Util.describe(this.$element)); } return label; } // Find bmd-form-group }, { key: 'findFormGroup', value: function findFormGroup() { var raiseError = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; var fg = this.$element.closest(Selector.FORM_GROUP); if (fg.length === 0 && raiseError) { $.error('Failed to find ' + Selector.FORM_GROUP + ' for ' + Util.describe(this.$element)); } return fg; } // Due to the interconnected nature of labels/inputs/help-blocks, signal the bmd-form-group-* size variation based on // a found form-control-* size }, { key: 'resolveMdbFormGroupSizing', value: function resolveMdbFormGroupSizing() { if (!this.config.convertInputSizeVariations) { return; } // Modification - Change text-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants) for (var inputSize in FormControlSizeMarkers) { if (this.$element.hasClass(inputSize)) { //this.$element.removeClass(inputSize) this.$bmdFormGroup.addClass(FormControlSizeMarkers[inputSize]); } } } // ------------------------------------------------------------------------ // private }, { key: '_rejectInvalidComponentMatches', value: function _rejectInvalidComponentMatches() { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this.config.invalidComponentMatches[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var otherComponent = _step2.value; otherComponent.rejectMatch(this.constructor.name, this.$element); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } }, { key: '_rejectWithoutRequiredClasses', value: function _rejectWithoutRequiredClasses() { var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = this.config.requiredClasses[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var requiredClass = _step3.value; var found = false; // allow one of several classes to be passed in x||y if (requiredClass.indexOf('||') !== -1) { var oneOf = requiredClass.split('||'); var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = oneOf[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _requiredClass = _step4.value; if (this.$element.hasClass(_requiredClass)) { found = true; break; } } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } } else if (this.$element.hasClass(requiredClass)) { found = true; } // error if not found if (!found) { $.error(this.constructor.name + ' element: ' + Util.describe(this.$element) + ' requires class: ' + requiredClass); } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } // ------------------------------------------------------------------------ // static }]); return BaseInput; }(Base); return BaseInput; }(jQuery); var BaseSelection = function ($) { /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ var Default = { label: { required: false // Prioritized find order for resolving the label to be used as an bmd-label if not specified in the markup // - a function(thisComponent); or // - a string selector used like $bmdFormGroup.find(selector) // // Note this only runs if $bmdFormGroup.find(Selector.BMD_LABEL_WILDCARD) fails to find a label (as authored in the markup) // //selectors: [ // `.form-control-label`, // in the case of horizontal or inline forms, this will be marked // `> label` // usual case for text inputs //] } }; var Selector = { LABEL: 'label' }; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ var BaseSelection = function (_BaseInput) { inherits(BaseSelection, _BaseInput); function BaseSelection($element, config, properties) { classCallCheck(this, BaseSelection); var _this = possibleConstructorReturn(this, Object.getPrototypeOf(BaseSelection).call(this, $element, $.extend(true, {}, Default, config), properties)); // properties = {inputType: checkbox, outerClass: checkbox-inline} // '.checkbox|switch|radio > label > input[type=checkbox|radio]' // '.${this.outerClass} > label > input[type=${this.inputType}]' _this.decorateMarkup(); return _this; } // ------------------------------------------------------------------------ // protected createClass(BaseSelection, [{ key: 'decorateMarkup', value: function decorateMarkup() { this.$element.after(this.config.template); } // Demarcation element (e.g. first child of a form-group) }, { key: 'outerElement', value: function outerElement() { // .checkbox|switch|radio > label > input[type=checkbox|radio] // label.checkbox-inline > input[type=checkbox|radio] // .${this.outerClass} > label > input[type=${this.inputType}] return this.$element.parent().closest('.' + this.outerClass); } }, { key: 'rejectWithoutRequiredStructure', value: function rejectWithoutRequiredStructure() { // '.checkbox|switch|radio > label > input[type=checkbox|radio]' // '.${this.outerClass} > label > input[type=${this.inputType}]' Util.assert(this.$element, !this.$element.parent().prop('tagName') === 'label', this.constructor.name + '\'s ' + Util.describe(this.$element) + ' parent element should be