1 (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
3 * MUI CSS/JS main module
10 // return if library has been loaded already
11 if (win._muiLoadedJS) return;
12 else win._muiLoadedJS = true;
15 var jqLite = require('src/js/lib/jqLite'),
16 dropdown = require('src/js/dropdown'),
17 overlay = require('src/js/overlay'),
18 ripple = require('src/js/ripple'),
19 select = require('src/js/select'),
20 tabs = require('src/js/tabs'),
21 textfield = require('src/js/textfield');
30 jqLite.ready(function() {
31 textfield.initListeners();
32 select.initListeners();
33 ripple.initListeners();
34 dropdown.initListeners();
39 },{"src/js/dropdown":3,"src/js/lib/jqLite":6,"src/js/overlay":8,"src/js/ripple":9,"src/js/select":10,"src/js/tabs":11,"src/js/textfield":12}],2:[function(require,module,exports){
45 /** Define module API */
51 },{}],3:[function(require,module,exports){
53 * MUI CSS/JS dropdown module
60 var jqLite = require('./lib/jqLite'),
61 util = require('./lib/util'),
62 animationHelpers = require('./lib/animationHelpers'),
63 attrKey = 'data-mui-toggle',
64 attrSelector = '[data-mui-toggle="dropdown"]',
65 openClass = 'mui--is-open',
66 menuClass = 'mui-dropdown__menu',
67 upClass = 'mui-dropdown--up',
68 rightClass = 'mui-dropdown--right',
69 leftClass = 'mui-dropdown--left',
70 bottomClass = 'mui-dropdown__menu--bottom';
74 * Initialize toggle element.
75 * @param {Element} toggleEl - The toggle element.
77 function initialize(toggleEl) {
79 if (toggleEl._muiDropdown === true) return;
80 else toggleEl._muiDropdown = true;
82 // use type "button" to prevent form submission by default
83 var tagName = toggleEl.tagName;
84 if ((tagName === 'INPUT' || tagName === 'BUTTON')
85 && !toggleEl.hasAttribute('type')) {
86 toggleEl.type = 'button';
89 // attach click handler
90 jqLite.on(toggleEl, 'click', clickHandler);
95 * Handle click events on dropdown toggle element.
96 * @param {Event} ev - The DOM event
98 function clickHandler(ev) {
100 if (ev.button !== 0) return;
104 // exit if toggle button is disabled
105 if (toggleEl.getAttribute('disabled') !== null) return;
108 toggleDropdown(toggleEl);
113 * Toggle the dropdown.
114 * @param {Element} toggleEl - The dropdown toggle element.
116 function toggleDropdown(toggleEl) {
117 var wrapperEl = toggleEl.parentNode,
118 menuEl = toggleEl.nextElementSibling,
119 doc = wrapperEl.ownerDocument;
121 // exit if no menu element
122 if (!menuEl || !jqLite.hasClass(menuEl, menuClass)) {
123 return util.raiseError('Dropdown menu element not found');
126 // method to close dropdown
127 function closeDropdownFn() {
128 jqLite.removeClass(menuEl, openClass);
130 // remove event handlers
131 jqLite.off(doc, 'click', closeDropdownFn);
132 jqLite.off(doc, 'keydown', handleKeyDownFn);
135 // close dropdown on escape key press
136 function handleKeyDownFn(ev) {
138 if (key === 'Escape' || key === 'Esc') closeDropdownFn();
141 // method to open dropdown
142 function openDropdownFn() {
143 // position menu element below toggle button
144 var wrapperRect = wrapperEl.getBoundingClientRect(),
145 toggleRect = toggleEl.getBoundingClientRect();
148 if (jqLite.hasClass(wrapperEl, upClass)) {
151 'bottom': toggleRect.height + toggleRect.top - wrapperRect.top + 'px'
153 } else if (jqLite.hasClass(wrapperEl, rightClass)) {
156 'left': toggleRect.width + 'px',
157 'top': toggleRect.top - wrapperRect.top + 'px'
159 } else if (jqLite.hasClass(wrapperEl, leftClass)) {
162 'right': toggleRect.width + 'px',
163 'top': toggleRect.top - wrapperRect.top + 'px'
168 'top': toggleRect.top - wrapperRect.top + toggleRect.height + 'px'
173 if (jqLite.hasClass(menuEl, bottomClass)) {
176 'bottom': toggleRect.top - wrapperRect.top + 'px'
180 // add open class to wrapper
181 jqLite.addClass(menuEl, openClass);
183 setTimeout(function() {
184 // close dropdown when user clicks outside of menu or hits escape key
185 jqLite.on(doc, 'click', closeDropdownFn);
186 jqLite.on(doc, 'keydown', handleKeyDownFn);
191 if (jqLite.hasClass(menuEl, openClass)) closeDropdownFn();
192 else openDropdownFn();
196 /** Define module API */
198 /** Initialize module listeners */
199 initListeners: function() {
200 // markup elements available when method is called
201 var elList = document.querySelectorAll(attrSelector),
203 while (i--) {initialize(elList[i]);}
205 // listen for new elements
206 animationHelpers.onAnimationStart('mui-dropdown-inserted', function(ev) {
207 initialize(ev.target);
212 },{"./lib/animationHelpers":4,"./lib/jqLite":6,"./lib/util":7}],4:[function(require,module,exports){
214 * MUI CSS/JS animation helper module
215 * @module lib/animationHelpers
220 var jqLite = require('./jqLite'),
221 util = require('./util'),
222 animationEvents = 'animationstart mozAnimationStart webkitAnimationStart',
223 animationCallbacks = {};
228 * @param {String} name - The animation name
229 * @param {Function} callbackFn = The callback function
231 function onAnimationStartFn(name, callbackFn) {
232 // get/set callback function
233 var callbacks = animationCallbacks[name];
234 if (!callbacks) callbacks = animationCallbacks[name] = [];
235 callbacks.push(callbackFn);
237 // initialize listeners
243 jqLite.on(document, animationEvents, animationStartHandler, true);
252 * Animation start handler
253 * @param {Event} ev - The DOM event
255 function animationStartHandler(ev) {
256 var callbacks = animationCallbacks[ev.animationName] || [],
257 i = callbacks.length;
259 // exit if a callback hasn't been registered
262 // stop other callbacks from firing
263 ev.stopImmediatePropagation();
265 // iterate through callbacks
266 while (i--) callbacks[i](ev);
276 ['.mui-btn', 'mui-btn-inserted'],
277 ['[data-mui-toggle="dropdown"]', 'mui-dropdown-inserted'],
279 '.mui-btn[data-mui-toggle="dropdown"]',
280 'mui-btn-inserted,mui-dropdown-inserted'
282 ['[data-mui-toggle="tab"]', 'mui-tab-inserted'],
283 ['.mui-textfield > input', 'mui-textfield-inserted'],
284 ['.mui-textfield > textarea', 'mui-textfield-inserted'],
285 ['.mui-select > select', 'mui-select-inserted'],
286 ['.mui-select > select ~ .mui-event-trigger', 'mui-node-inserted'],
287 ['.mui-select > select:disabled ~ .mui-event-trigger', 'mui-node-disabled']
294 for (var i=0, m=rules.length; i < m; i++) {
296 css += '@keyframes ' + rule[1];
297 css += '{from{transform:none;}to{transform:none;}}';
299 css += '{animation-duration:0.0001s;animation-name:' + rule[1] + ';}';
311 animationEvents: animationEvents,
312 onAnimationStart: onAnimationStartFn
315 },{"./jqLite":6,"./util":7}],5:[function(require,module,exports){
317 * MUI CSS/JS form helpers module
318 * @module lib/forms.py
323 var jqLite = require('./jqLite');
327 * Menu position/size/scroll helper
328 * @returns {Object} Object with keys 'height', 'top', 'scrollTop'
330 function getMenuPositionalCSSFn(wrapperEl, menuEl, selectedRow) {
331 var viewHeight = document.documentElement.clientHeight,
332 numRows = menuEl.children.length;
334 // determine menu height
335 var h = parseInt(menuEl.offsetHeight),
336 height = Math.min(h, viewHeight);
338 // determine row height
339 var p = parseInt(jqLite.css(menuEl, 'padding-top')),
340 rowHeight = (h - 2 * p) / numRows;
343 var top, initTop, minTop, maxTop;
345 initTop = -1 * selectedRow * rowHeight;
346 minTop = -1 * wrapperEl.getBoundingClientRect().top;
347 maxTop = (viewHeight - height) + minTop;
349 top = Math.min(Math.max(initTop, minTop), maxTop);
351 // determine 'scrollTop'
356 if (h > viewHeight) {
357 scrollIdeal = top + p + selectedRow * rowHeight;
358 scrollMax = numRows * rowHeight + 2 * p - height;
359 scrollTop = Math.min(scrollIdeal, scrollMax);
363 'height': height + 'px',
365 'scrollTop': scrollTop
370 /** Define module API */
372 getMenuPositionalCSS: getMenuPositionalCSSFn
375 },{"./jqLite":6}],6:[function(require,module,exports){
377 * MUI CSS/JS jqLite module
385 * Add a class to an element.
386 * @param {Element} element - The DOM element.
387 * @param {string} cssClasses - Space separated list of class names.
389 function jqLiteAddClass(element, cssClasses) {
390 if (!cssClasses || !element.setAttribute) return;
392 var existingClasses = _getExistingClasses(element),
393 splitClasses = cssClasses.split(' '),
396 for (var i=0; i < splitClasses.length; i++) {
397 cssClass = splitClasses[i].trim();
398 if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
399 existingClasses += cssClass + ' ';
403 element.setAttribute('class', existingClasses.trim());
408 * Get or set CSS properties.
409 * @param {Element} element - The DOM element.
410 * @param {string} [name] - The property name.
411 * @param {string} [value] - The property value.
413 function jqLiteCss(element, name, value) {
414 // Return full style object
415 if (name === undefined) {
416 return getComputedStyle(element);
419 var nameType = jqLiteType(name);
421 // Set multiple values
422 if (nameType === 'object') {
423 for (var key in name) element.style[_camelCase(key)] = name[key];
427 // Set a single value
428 if (nameType === 'string' && value !== undefined) {
429 element.style[_camelCase(name)] = value;
432 var styleObj = getComputedStyle(element),
433 isArray = (jqLiteType(name) === 'array');
436 if (!isArray) return _getCurrCssProp(element, name, styleObj);
438 // Read multiple values
442 for (var i=0; i < name.length; i++) {
444 outObj[key] = _getCurrCssProp(element, key, styleObj);
452 * Check if element has class.
453 * @param {Element} element - The DOM element.
454 * @param {string} cls - The class name string.
456 function jqLiteHasClass(element, cls) {
457 if (!cls || !element.getAttribute) return false;
458 return (_getExistingClasses(element).indexOf(' ' + cls + ' ') > -1);
463 * Return the type of a variable.
464 * @param {} somevar - The JavaScript variable.
466 function jqLiteType(somevar) {
468 if (somevar === undefined) return 'undefined';
470 // handle others (of type [object <Type>])
471 var typeStr = Object.prototype.toString.call(somevar);
472 if (typeStr.indexOf('[object ') === 0) {
473 return typeStr.slice(8, -1).toLowerCase();
475 throw new Error("MUI: Could not understand type: " + typeStr);
481 * Attach an event handler to a DOM element
482 * @param {Element} element - The DOM element.
483 * @param {string} events - Space separated event names.
484 * @param {Function} callback - The callback function.
485 * @param {Boolean} useCapture - Use capture flag.
487 function jqLiteOn(element, events, callback, useCapture) {
488 useCapture = (useCapture === undefined) ? false : useCapture;
490 var cache = element._muiEventCache = element._muiEventCache || {};
492 events.split(' ').map(function(event) {
494 element.addEventListener(event, callback, useCapture);
497 cache[event] = cache[event] || [];
498 cache[event].push([callback, useCapture]);
504 * Remove an event handler from a DOM element
505 * @param {Element} element - The DOM element.
506 * @param {string} events - Space separated event names.
507 * @param {Function} callback - The callback function.
508 * @param {Boolean} useCapture - Use capture flag.
510 function jqLiteOff(element, events, callback, useCapture) {
511 useCapture = (useCapture === undefined) ? false : useCapture;
514 var cache = element._muiEventCache = element._muiEventCache || {},
519 events.split(' ').map(function(event) {
520 argsList = cache[event] || [];
526 // remove all events if callback is undefined
527 if (callback === undefined ||
528 (args[0] === callback && args[1] === useCapture)) {
531 argsList.splice(i, 1);
534 element.removeEventListener(event, args[0], args[1]);
542 * Attach an event hander which will only execute once per element per event
543 * @param {Element} element - The DOM element.
544 * @param {string} events - Space separated event names.
545 * @param {Function} callback - The callback function.
546 * @param {Boolean} useCapture - Use capture flag.
548 function jqLiteOne(element, events, callback, useCapture) {
549 events.split(' ').map(function(event) {
550 jqLiteOn(element, event, function onFn(ev) {
552 if (callback) callback.apply(this, arguments);
555 jqLiteOff(element, event, onFn, useCapture);
562 * Get or set horizontal scroll position
563 * @param {Element} element - The DOM element
564 * @param {number} [value] - The scroll position
566 function jqLiteScrollLeft(element, value) {
570 if (value === undefined) {
571 if (element === win) {
572 var docEl = document.documentElement;
573 return (win.pageXOffset || docEl.scrollLeft) - (docEl.clientLeft || 0);
575 return element.scrollLeft;
580 if (element === win) win.scrollTo(value, jqLiteScrollTop(win));
581 else element.scrollLeft = value;
586 * Get or set vertical scroll position
587 * @param {Element} element - The DOM element
588 * @param {number} value - The scroll position
590 function jqLiteScrollTop(element, value) {
594 if (value === undefined) {
595 if (element === win) {
596 var docEl = document.documentElement;
597 return (win.pageYOffset || docEl.scrollTop) - (docEl.clientTop || 0);
599 return element.scrollTop;
604 if (element === win) win.scrollTo(jqLiteScrollLeft(win), value);
605 else element.scrollTop = value;
610 * Return object representing top/left offset and element height/width.
611 * @param {Element} element - The DOM element.
613 function jqLiteOffset(element) {
615 rect = element.getBoundingClientRect(),
616 scrollTop = jqLiteScrollTop(win),
617 scrollLeft = jqLiteScrollLeft(win);
620 top: rect.top + scrollTop,
621 left: rect.left + scrollLeft,
629 * Attach a callback to the DOM ready event listener
630 * @param {Function} fn - The callback function.
632 function jqLiteReady(fn) {
636 win = doc.defaultView,
637 root = doc.documentElement,
638 add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
639 rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
640 pre = doc.addEventListener ? '' : 'on';
642 var init = function(e) {
643 if (e.type == 'readystatechange' && doc.readyState != 'complete') {
647 (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
648 if (!done && (done = true)) fn.call(win, e.type || e);
651 var poll = function() {
652 try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
656 if (doc.readyState == 'complete') {
657 fn.call(win, 'lazy');
659 if (doc.createEventObject && root.doScroll) {
660 try { top = !win.frameElement; } catch(e) { }
663 doc[add](pre + 'DOMContentLoaded', init, false);
664 doc[add](pre + 'readystatechange', init, false);
665 win[add](pre + 'load', init, false);
671 * Remove classes from a DOM element
672 * @param {Element} element - The DOM element.
673 * @param {string} cssClasses - Space separated list of class names.
675 function jqLiteRemoveClass(element, cssClasses) {
676 if (!cssClasses || !element.setAttribute) return;
678 var existingClasses = _getExistingClasses(element),
679 splitClasses = cssClasses.split(' '),
682 for (var i=0; i < splitClasses.length; i++) {
683 cssClass = splitClasses[i].trim();
684 while (existingClasses.indexOf(' ' + cssClass + ' ') >= 0) {
685 existingClasses = existingClasses.replace(' ' + cssClass + ' ', ' ');
689 element.setAttribute('class', existingClasses.trim());
693 // ------------------------------
695 // ------------------------------
696 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g,
697 MOZ_HACK_REGEXP = /^moz([A-Z])/,
698 ESCAPE_REGEXP = /([.*+?^=!:${}()|\[\]\/\\])/g;
701 function _getExistingClasses(element) {
702 var classes = (element.getAttribute('class') || '').replace(/[\n\t]/g, '');
703 return ' ' + classes + ' ';
707 function _camelCase(name) {
709 replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
710 return offset ? letter.toUpperCase() : letter;
712 replace(MOZ_HACK_REGEXP, 'Moz$1');
716 function _escapeRegExp(string) {
717 return string.replace(ESCAPE_REGEXP, "\\$1");
721 function _getCurrCssProp(elem, name, computed) {
724 // try computed style
725 ret = computed.getPropertyValue(name);
727 // try style attribute (if element is not attached to document)
728 if (ret === '' && !elem.ownerDocument) ret = elem.style[_camelCase(name)];
739 addClass: jqLiteAddClass,
741 /** Get or set CSS properties */
744 /** Check for class */
745 hasClass: jqLiteHasClass,
747 /** Remove event handlers */
750 /** Return offset values */
751 offset: jqLiteOffset,
753 /** Add event handlers */
756 /** Add an execute-once event handler */
759 /** DOM ready event handler */
762 /** Remove classes */
763 removeClass: jqLiteRemoveClass,
765 /** Check JavaScript variable instance type */
768 /** Get or set horizontal scroll position */
769 scrollLeft: jqLiteScrollLeft,
771 /** Get or set vertical scroll position */
772 scrollTop: jqLiteScrollTop
775 },{}],7:[function(require,module,exports){
777 * MUI CSS/JS utilities module
784 var config = require('../config'),
785 jqLite = require('./jqLite'),
787 scrollLockCls = 'mui-scroll-lock',
792 _supportsPointerEvents;
795 scrollEventHandler = function(ev) {
796 // stop propagation on window scroll events
797 if (!ev.target.tagName) ev.stopImmediatePropagation();
807 if (config.debug && typeof win.console !== "undefined") {
809 win.console.log.apply(win.console, arguments);
811 var e = Array.prototype.slice.call(arguments);
812 win.console.log(e.join("\n"));
819 * Load CSS text in new stylesheet
820 * @param {string} cssText - The css text.
822 function loadStyleFn(cssText) {
826 // copied from jQuery
828 doc.getElementsByTagName('head')[0] ||
831 var e = doc.createElement('style');
834 if (e.styleSheet) e.styleSheet.cssText = cssText;
835 else e.appendChild(doc.createTextNode(cssText));
838 head.insertBefore(e, head.firstChild);
846 * @param {string} msg - The error message.
848 function raiseErrorFn(msg, useConsole) {
850 if (typeof console !== 'undefined') console.warn('MUI Warning: ' + msg);
852 throw new Error('MUI: ' + msg);
858 * Convert Classname object, with class as key and true/false as value, to an
860 * @param {Object} classes The classes
861 * @return {String} class string
863 function classNamesFn(classes) {
865 for (var i in classes) {
866 cs += (classes[i]) ? i + ' ' : '';
873 * Check if client supports pointer events.
875 function supportsPointerEventsFn() {
877 if (_supportsPointerEvents !== undefined) return _supportsPointerEvents;
879 var element = document.createElement('x');
880 element.style.cssText = 'pointer-events:auto';
881 _supportsPointerEvents = (element.style.pointerEvents === 'auto');
882 return _supportsPointerEvents;
887 * Create callback closure.
888 * @param {Object} instance - The object instance.
889 * @param {String} funcName - The name of the callback function.
891 function callbackFn(instance, funcName) {
892 return function() {instance[funcName].apply(instance, arguments);};
898 * @param {Element} element - The DOM element.
899 * @param {String} eventType - The event type.
900 * @param {Boolean} bubbles=true - If true, event bubbles.
901 * @param {Boolean} cancelable=true = If true, event is cancelable
902 * @param {Object} [data] - Data to add to event object
904 function dispatchEventFn(element, eventType, bubbles, cancelable, data) {
905 var ev = document.createEvent('HTMLEvents'),
906 bubbles = (bubbles !== undefined) ? bubbles : true,
907 cancelable = (cancelable !== undefined) ? cancelable : true,
910 ev.initEvent(eventType, bubbles, cancelable);
912 // add data to event object
913 if (data) for (k in data) ev[k] = data[k];
916 if (element) element.dispatchEvent(ev);
923 * Turn on window scroll lock.
925 function enableScrollLockFn() {
930 if (scrollLock === 1) {
933 htmlEl = doc.documentElement,
935 scrollBarWidth = getScrollBarWidth(),
940 // define scroll lock class dynamically
941 cssProps = ['overflow:hidden'];
943 if (scrollBarWidth) {
945 if (htmlEl.scrollHeight > htmlEl.clientHeight) {
946 x = parseInt(jqLite.css(bodyEl, 'padding-right')) + scrollBarWidth;
947 cssProps.push('padding-right:' + x + 'px');
951 if (htmlEl.scrollWidth > htmlEl.clientWidth) {
952 x = parseInt(jqLite.css(bodyEl, 'padding-bottom')) + scrollBarWidth;
953 cssProps.push('padding-bottom:' + x + 'px');
957 // define css class dynamically
958 cssStr = '.' + scrollLockCls + '{';
959 cssStr += cssProps.join(' !important;') + ' !important;}';
960 scrollStyleEl = loadStyleFn(cssStr);
962 // cancel 'scroll' event listener callbacks
963 jqLite.on(win, 'scroll', scrollEventHandler, true);
966 scrollLockPos = {left: jqLite.scrollLeft(win), top: jqLite.scrollTop(win)};
967 jqLite.addClass(bodyEl, scrollLockCls);
973 * Turn off window scroll lock.
974 * @param {Boolean} resetPos - Reset scroll position to original value.
976 function disableScrollLockFn(resetPos) {
978 if (scrollLock === 0) return;
984 if (scrollLock === 0) {
985 // remove scroll lock and delete style element
986 jqLite.removeClass(document.body, scrollLockCls);
988 // restore scroll position
989 if (resetPos) window.scrollTo(scrollLockPos.left, scrollLockPos.top);
991 // restore scroll event listeners
992 jqLite.off(window, 'scroll', scrollEventHandler, true);
994 // delete style element (deferred for Firefox Quantum bugfix)
995 setTimeout(function() {
996 scrollStyleEl.parentNode.removeChild(scrollStyleEl);
1002 * Return scroll bar width.
1004 var getScrollBarWidth = function() {
1006 if (_scrollBarWidth !== undefined) return _scrollBarWidth;
1008 // calculate scroll bar width
1011 el = doc.createElement('div');
1013 el.innerHTML = '<div style="width:50px;height:50px;position:absolute;' +
1014 'left:-50px;top:-50px;overflow:auto;"><div style="width:1px;' +
1015 'height:100px;"></div></div>';
1017 bodyEl.appendChild(el);
1018 _scrollBarWidth = el.offsetWidth - el.clientWidth;
1019 bodyEl.removeChild(el);
1021 return _scrollBarWidth;
1026 * requestAnimationFrame polyfilled
1027 * @param {Function} callback - The callback function
1029 function requestAnimationFrameFn(callback) {
1030 var fn = window.requestAnimationFrame;
1031 if (fn) fn(callback);
1032 else setTimeout(callback, 0);
1037 * Define the module API
1040 /** Create callback closures */
1041 callback: callbackFn,
1043 /** Classnames object to string */
1044 classNames: classNamesFn,
1046 /** Disable scroll lock */
1047 disableScrollLock: disableScrollLockFn,
1049 /** Dispatch event */
1050 dispatchEvent: dispatchEventFn,
1052 /** Enable scroll lock */
1053 enableScrollLock: enableScrollLockFn,
1055 /** Log messages to the console when debug is turned on */
1058 /** Load CSS text as new stylesheet */
1059 loadStyle: loadStyleFn,
1061 /** Raise MUI error */
1062 raiseError: raiseErrorFn,
1064 /** Request animation frame */
1065 requestAnimationFrame: requestAnimationFrameFn,
1067 /** Support Pointer Events check */
1068 supportsPointerEvents: supportsPointerEventsFn
1071 },{"../config":2,"./jqLite":6}],8:[function(require,module,exports){
1073 * MUI CSS/JS overlay module
1080 var util = require('./lib/util'),
1081 jqLite = require('./lib/jqLite'),
1082 overlayId = 'mui-overlay',
1083 bodyClass = 'mui--overflow-hidden',
1084 iosRegex = /(iPad|iPhone|iPod)/g,
1089 * Turn overlay on/off.
1090 * @param {string} action - Turn overlay "on"/"off".
1091 * @param {object} [options]
1092 * @config {boolean} [keyboard] - If true, close when escape key is pressed.
1093 * @config {boolean} [static] - If false, close when backdrop is clicked.
1094 * @config {Function} [onclose] - Callback function to execute on close
1095 * @param {Element} [childElement] - Child element to add to overlay.
1097 function overlayFn(action) {
1100 if (action === 'on') {
1101 // extract arguments
1102 var arg, options, childElement;
1104 // pull options and childElement from arguments
1105 for (var i=arguments.length - 1; i > 0; i--) {
1108 if (jqLite.type(arg) === 'object') options = arg;
1109 if (arg instanceof Element && arg.nodeType === 1) childElement = arg;
1113 options = options || {};
1114 if (options.keyboard === undefined) options.keyboard = true;
1115 if (options.static === undefined) options.static = false;
1118 overlayEl = overlayOn(options, childElement);
1120 } else if (action === 'off') {
1121 overlayEl = overlayOff();
1125 util.raiseError("Expecting 'on' or 'off'");
1135 * @param {object} options - Overlay options.
1136 * @param {Element} childElement - The child element.
1138 function overlayOn(options, childElement) {
1141 overlayEl = doc.getElementById(overlayId);
1143 // cache activeElement
1144 if (doc.activeElement) activeElement = doc.activeElement;
1147 util.enableScrollLock();
1151 overlayEl = doc.createElement('div');
1152 overlayEl.setAttribute('id', overlayId);
1153 overlayEl.setAttribute('tabindex', '-1');
1155 // add child element
1156 if (childElement) overlayEl.appendChild(childElement);
1158 bodyEl.appendChild(overlayEl);
1161 // remove existing children
1162 while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
1164 // add child element
1165 if (childElement) overlayEl.appendChild(childElement);
1169 if (iosRegex.test(navigator.userAgent)) {
1170 jqLite.css(overlayEl, 'cursor', 'pointer');
1174 if (options.keyboard) addKeyupHandler();
1175 else removeKeyupHandler();
1177 if (options.static) removeClickHandler(overlayEl);
1178 else addClickHandler(overlayEl);
1181 overlayEl.muiOptions = options;
1183 // focus overlay element
1193 function overlayOff() {
1194 var overlayEl = document.getElementById(overlayId),
1199 while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
1201 // remove overlay element
1202 overlayEl.parentNode.removeChild(overlayEl);
1204 // callback reference
1205 callbackFn = overlayEl.muiOptions.onclose;
1207 // remove click handler
1208 removeClickHandler(overlayEl);
1211 util.disableScrollLock();
1213 // remove keyup handler
1214 removeKeyupHandler();
1216 // return focus to activeElement
1217 if (activeElement) activeElement.focus();
1220 if (callbackFn) callbackFn();
1227 * Add keyup handler.
1229 function addKeyupHandler() {
1230 jqLite.on(document, 'keyup', onKeyup);
1235 * Remove keyup handler.
1237 function removeKeyupHandler() {
1238 jqLite.off(document, 'keyup', onKeyup);
1243 * Teardown overlay when escape key is pressed.
1245 function onKeyup(ev) {
1246 if (ev.keyCode === 27) overlayOff();
1251 * Add click handler.
1253 function addClickHandler(overlayEl) {
1254 jqLite.on(overlayEl, 'click', onClick);
1259 * Remove click handler.
1261 function removeClickHandler(overlayEl) {
1262 jqLite.off(overlayEl, 'click', onClick);
1267 * Teardown overlay when backdrop is clicked.
1269 function onClick(ev) {
1270 if (ev.target.id === overlayId) overlayOff();
1274 /** Define module API */
1275 module.exports = overlayFn;
1277 },{"./lib/jqLite":6,"./lib/util":7}],9:[function(require,module,exports){
1279 * MUI CSS/JS ripple module
1286 var jqLite = require('./lib/jqLite'),
1287 util = require('./lib/util'),
1288 animationHelpers = require('./lib/animationHelpers'),
1289 supportsTouch = 'ontouchstart' in document.documentElement,
1290 mouseDownEvents = (supportsTouch) ? 'touchstart' : 'mousedown',
1291 mouseUpEvents = (supportsTouch) ? 'touchend' : 'mouseup mouseleave';
1295 * Add ripple effects to button element.
1296 * @param {Element} buttonEl - The button element.
1298 function initialize(buttonEl) {
1300 if (buttonEl._muiRipple === true) return;
1301 else buttonEl._muiRipple = true;
1303 // exit if element is INPUT (doesn't support absolute positioned children)
1304 if (buttonEl.tagName === 'INPUT') return;
1306 // attach event handler
1307 jqLite.on(buttonEl, mouseDownEvents, mouseDownHandler);
1312 * MouseDown Event handler.
1313 * @param {Event} ev - The DOM event
1315 function mouseDownHandler(ev) {
1317 if (ev.type === 'mousedown' && ev.button !== 0) return;
1319 var buttonEl = this,
1320 rippleEl = buttonEl._rippleEl;
1322 // exit if button is disabled
1323 if (buttonEl.disabled) return;
1326 // add ripple container (to avoid https://github.com/muicss/mui/issues/169)
1327 var el = document.createElement('span');
1328 el.className = 'mui-btn__ripple-container';
1329 el.innerHTML = '<span class="mui-ripple"></span>';
1330 buttonEl.appendChild(el);
1332 // cache reference to ripple element
1333 rippleEl = buttonEl._rippleEl = el.children[0];
1335 // add mouseup handler on first-click
1336 jqLite.on(buttonEl, mouseUpEvents, mouseUpHandler);
1339 // get ripple element offset values and (x, y) position of click
1340 var offset = jqLite.offset(buttonEl),
1341 clickEv = (ev.type === 'touchstart') ? ev.touches[0] : ev,
1346 radius = Math.sqrt(offset.height * offset.height +
1347 offset.width * offset.width);
1349 diameter = radius * 2 + 'px';
1351 // set position and dimensions
1352 jqLite.css(rippleEl, {
1355 top: Math.round(clickEv.pageY - offset.top - radius) + 'px',
1356 left: Math.round(clickEv.pageX - offset.left - radius) + 'px'
1359 jqLite.removeClass(rippleEl, 'mui--is-animating');
1360 jqLite.addClass(rippleEl, 'mui--is-visible');
1363 util.requestAnimationFrame(function() {
1364 jqLite.addClass(rippleEl, 'mui--is-animating');
1370 * MouseUp event handler.
1371 * @param {Event} ev - The DOM event
1373 function mouseUpHandler(ev) {
1374 // get ripple element
1375 var rippleEl = this._rippleEl;
1377 // allow a repaint to occur before removing class so animation shows for
1379 util.requestAnimationFrame(function() {
1380 jqLite.removeClass(rippleEl, 'mui--is-visible');
1385 /** Define module API */
1387 /** Initialize module listeners */
1388 initListeners: function() {
1389 // markup elements available when method is called
1390 var elList = document.getElementsByClassName('mui-btn'),
1392 while (i--) initialize(elList[i]);
1394 // listen for new elements
1395 animationHelpers.onAnimationStart('mui-btn-inserted', function(ev) {
1396 initialize(ev.target);
1401 },{"./lib/animationHelpers":4,"./lib/jqLite":6,"./lib/util":7}],10:[function(require,module,exports){
1403 * MUI CSS/JS select module
1404 * @module forms/select
1410 var jqLite = require('./lib/jqLite'),
1411 util = require('./lib/util'),
1412 animationHelpers = require('./lib/animationHelpers'),
1413 formlib = require('./lib/forms'),
1414 wrapperClass = 'mui-select',
1415 cssSelector = '.mui-select > select',
1416 menuClass = 'mui-select__menu',
1417 selectedClass = 'mui--is-selected',
1418 disabledClass = 'mui--is-disabled',
1424 * Initialize select element.
1425 * @param {Element} selectEl - The select element.
1427 function initialize(selectEl) {
1429 if (selectEl._muiSelect === true) return;
1430 else selectEl._muiSelect = true;
1432 // use default behavior on touch devices
1433 if ('ontouchstart' in doc.documentElement) return;
1435 // NOTE: To get around cross-browser issues with <select> behavior we will
1436 // defer focus to the parent element and handle events there
1438 var wrapperEl = selectEl.parentNode;
1440 // exit if use-default
1441 if (jqLite.hasClass(wrapperEl, 'mui-select--use-default')) return;
1443 // initialize variables
1444 wrapperEl._selectEl = selectEl;
1445 wrapperEl._menu = null;
1447 wrapperEl._qTimeout = null;
1449 // make wrapper tab focusable, remove tab focus from <select>
1450 if (!selectEl.disabled) wrapperEl.tabIndex = 0;
1451 selectEl.tabIndex = -1;
1453 // prevent built-in menu from opening on <select>
1454 jqLite.on(selectEl, 'mousedown', onInnerMouseDown);
1456 // attach event listeners for custom menu
1457 jqLite.on(wrapperEl, 'click', onWrapperClick);
1458 jqLite.on(wrapperEl, 'blur focus', onWrapperBlurOrFocus);
1459 jqLite.on(wrapperEl, 'keydown', onWrapperKeyDown);
1460 jqLite.on(wrapperEl, 'keypress', onWrapperKeyPress);
1462 // add element to detect 'disabled' change (using sister element due to
1464 var el = document.createElement('div');
1465 el.className = 'mui-event-trigger';
1466 wrapperEl.appendChild(el);
1468 // handle 'disabled' add/remove
1469 jqLite.on(el, animationHelpers.animationEvents, function(ev) {
1470 var parentEl = ev.target.parentNode;
1472 // no need to propagate
1473 ev.stopPropagation();
1475 if (ev.animationName === 'mui-node-disabled') {
1476 parentEl.removeAttribute('tabIndex');
1478 parentEl.tabIndex = 0;
1485 * Disable default dropdown on mousedown.
1486 * @param {Event} ev - The DOM event
1488 function onInnerMouseDown(ev) {
1490 if (ev.button !== 0) return;
1492 // prevent built-in menu from opening
1493 ev.preventDefault();
1498 * Dispatch focus and blur events on inner <select> element.
1499 * @param {Event} ev - The DOM event
1501 function onWrapperBlurOrFocus(ev) {
1502 util.dispatchEvent(this._selectEl, ev.type, false, false);
1507 * Handle keydown events when wrapper is focused
1509 function onWrapperKeyDown(ev) {
1510 if (ev.defaultPrevented) return;
1512 var keyCode = ev.keyCode,
1516 // spacebar, down, up
1517 if (keyCode === 32 || keyCode === 38 || keyCode === 40) {
1518 ev.preventDefault();
1526 if (keyCode === 9) return menu.destroy();
1528 // escape | up | down | enter
1529 if (keyCode === 27 || keyCode === 40 || keyCode === 38 || keyCode === 13) {
1530 ev.preventDefault();
1533 if (keyCode === 27) {
1536 } else if (keyCode === 40) {
1539 } else if (keyCode === 38) {
1542 } else if (keyCode === 13) {
1544 menu.selectCurrent();
1554 function onWrapperKeyPress(ev) {
1555 var menu = this._menu;
1557 // exit if default prevented or menu is closed
1558 if (ev.defaultPrevented || !menu) return;
1560 // handle query timer
1562 clearTimeout(this._qTimeout);
1564 this._qTimeout = setTimeout(function() {self._q = '';}, 300);
1566 // select first match alphabetically
1567 var prefixRegex = new RegExp('^' + this._q, 'i'),
1568 itemArray = menu.itemArray,
1571 for (pos in itemArray) {
1572 if (prefixRegex.test(itemArray[pos].innerText)) {
1573 menu.selectPos(pos);
1581 * Handle click events on wrapper element.
1582 * @param {Event} ev - The DOM event
1584 function onWrapperClick(ev) {
1585 // only left clicks, check default and disabled flags
1586 if (ev.button !== 0 || this._selectEl.disabled) return;
1597 * Render options menu
1599 function renderMenu(wrapperEl) {
1601 if (wrapperEl._menu) return;
1603 // render custom menu
1604 wrapperEl._menu = new Menu(wrapperEl, wrapperEl._selectEl, function() {
1605 wrapperEl._menu = null; // de-reference instance
1612 * Creates a new Menu
1615 function Menu(wrapperEl, selectEl, wrapperCallbackFn) {
1617 util.enableScrollLock();
1619 // instance variables
1620 this.itemArray = [];
1621 this.origPos = null;
1622 this.currentPos = null;
1623 this.selectEl = selectEl;
1624 this.wrapperEl = wrapperEl;
1626 var res = this._createMenuEl(wrapperEl, selectEl),
1627 menuEl = this.menuEl = res[0];
1629 var cb = util.callback;
1631 this.onClickCB = cb(this, 'onClick');
1632 this.destroyCB = cb(this, 'destroy');
1633 this.wrapperCallbackFn = wrapperCallbackFn;
1636 wrapperEl.appendChild(this.menuEl);
1639 var props = formlib.getMenuPositionalCSS(
1645 jqLite.css(menuEl, props);
1646 jqLite.scrollTop(menuEl, props.scrollTop);
1648 // attach event handlers
1649 var destroyCB = this.destroyCB;
1650 jqLite.on(menuEl, 'click', this.onClickCB);
1651 jqLite.on(win, 'resize', destroyCB);
1653 // attach event handler after current event loop exits
1654 setTimeout(function() {jqLite.on(doc, 'click', destroyCB);}, 0);
1659 * Create menu element
1660 * @param {Element} selectEl - The select element
1662 Menu.prototype._createMenuEl = function(wrapperEl, selectEl) {
1663 var menuEl = doc.createElement('div'),
1664 childEls = selectEl.children,
1665 itemArray = this.itemArray,
1671 docFrag = document.createDocumentFragment(), // for speed
1681 menuEl.className = menuClass;
1683 for (i=0, iMax=childEls.length; i < iMax; i++) {
1684 loopEl = childEls[i];
1686 if (loopEl.tagName === 'OPTGROUP') {
1687 // add row item to menu
1688 rowEl = doc.createElement('div');
1689 rowEl.textContent = loopEl.label;
1690 rowEl.className = 'mui-optgroup__label';
1691 docFrag.appendChild(rowEl);
1694 optionEls = loopEl.children;
1697 optionEls = [loopEl];
1700 // loop through option elements
1701 for (j=0, jMax=optionEls.length; j < jMax; j++) {
1702 loopEl = optionEls[j];
1704 // add row item to menu
1705 rowEl = doc.createElement('div');
1706 rowEl.textContent = loopEl.textContent;
1708 // handle optgroup options
1709 if (inGroup) jqLite.addClass(rowEl, 'mui-optgroup__option');
1711 if (loopEl.hidden) {
1713 } else if (loopEl.disabled) {
1714 // do not attach muiIndex to disable <option> elements to make them
1716 jqLite.addClass(rowEl, disabledClass);
1718 rowEl._muiIndex = loopEl.index;
1719 rowEl._muiPos = itemPos;
1721 // handle selected options
1722 if (loopEl.selected) {
1723 selectedRow = numRows;
1725 selectedPos = itemPos;
1728 // add to item array
1729 itemArray.push(rowEl);
1733 docFrag.appendChild(rowEl);
1739 menuEl.appendChild(docFrag);
1742 this.origPos = origPos;
1743 this.currentPos = selectedPos;
1745 // paint selectedPos
1746 if (itemArray.length) jqLite.addClass(itemArray[selectedPos], selectedClass);
1748 return [menuEl, selectedRow];
1753 * Handle click events on menu element.
1754 * @param {Event} ev - The DOM event
1756 Menu.prototype.onClick = function(ev) {
1757 // don't allow events to bubble
1758 ev.stopPropagation();
1760 var item = ev.target,
1761 index = item._muiIndex;
1763 // ignore clicks on non-items
1764 if (index === undefined) return;
1767 this.currentPos = item._muiPos;
1768 this.selectCurrent();
1776 * Increment selected item
1778 Menu.prototype.increment = function() {
1779 if (this.currentPos === this.itemArray.length - 1) return;
1781 // un-select old row
1782 jqLite.removeClass(this.itemArray[this.currentPos], selectedClass);
1785 this.currentPos += 1;
1786 jqLite.addClass(this.itemArray[this.currentPos], selectedClass);
1791 * Decrement selected item
1793 Menu.prototype.decrement = function() {
1794 if (this.currentPos === 0) return;
1796 // un-select old row
1797 jqLite.removeClass(this.itemArray[this.currentPos], selectedClass);
1800 this.currentPos -= 1;
1801 jqLite.addClass(this.itemArray[this.currentPos], selectedClass);
1806 * Select current item
1808 Menu.prototype.selectCurrent = function() {
1809 if (this.currentPos !== this.origPos) {
1810 this.selectEl.selectedIndex = this.itemArray[this.currentPos]._muiIndex;
1812 // trigger change and input events
1813 util.dispatchEvent(this.selectEl, 'change', true, false);
1814 util.dispatchEvent(this.selectEl, 'input', true, false);
1820 * Select item at position
1822 Menu.prototype.selectPos = function(pos) {
1823 // un-select old row
1824 jqLite.removeClass(this.itemArray[this.currentPos], selectedClass);
1827 this.currentPos = pos;
1828 var itemEl = this.itemArray[pos];
1829 jqLite.addClass(itemEl, selectedClass);
1831 // scroll (if necessary)
1832 var menuEl = this.menuEl,
1833 itemRect = itemEl.getBoundingClientRect();
1835 if (itemRect.top < 0) {
1836 // menu item is hidden above visible window
1837 menuEl.scrollTop = menuEl.scrollTop + itemRect.top - 5;
1838 } else if (itemRect.top > window.innerHeight) {
1839 // menu item is hidden below visible window
1840 menuEl.scrollTop = menuEl.scrollTop +
1841 (itemRect.top + itemRect.height - window.innerHeight) + 5;
1847 * Destroy menu and detach event handlers
1849 Menu.prototype.destroy = function() {
1850 // remove scroll lock
1851 util.disableScrollLock(true);
1853 // remove event handlers
1854 jqLite.off(this.menuEl, 'click', this.clickCallbackFn);
1855 jqLite.off(doc, 'click', this.destroyCB);
1856 jqLite.off(win, 'resize', this.destroyCB);
1858 // remove element and execute wrapper callback
1859 var parentNode = this.menuEl.parentNode;
1861 parentNode.removeChild(this.menuEl);
1862 this.wrapperCallbackFn();
1867 /** Define module API */
1869 /** Initialize module listeners */
1870 initListeners: function() {
1871 // markup elements available when method is called
1872 var elList = doc.querySelectorAll(cssSelector),
1874 while (i--) initialize(elList[i]);
1876 // listen for mui-node-inserted events
1877 animationHelpers.onAnimationStart('mui-select-inserted', function(ev) {
1878 initialize(ev.target);
1883 },{"./lib/animationHelpers":4,"./lib/forms":5,"./lib/jqLite":6,"./lib/util":7}],11:[function(require,module,exports){
1885 * MUI CSS/JS tabs module
1892 var jqLite = require('./lib/jqLite'),
1893 util = require('./lib/util'),
1894 animationHelpers = require('./lib/animationHelpers'),
1895 attrKey = 'data-mui-toggle',
1896 attrSelector = '[' + attrKey + '="tab"]',
1897 controlsAttrKey = 'data-mui-controls',
1898 activeClass = 'mui--is-active',
1899 showstartKey = 'mui.tabs.showstart',
1900 showendKey = 'mui.tabs.showend',
1901 hidestartKey = 'mui.tabs.hidestart',
1902 hideendKey = 'mui.tabs.hideend';
1906 * Initialize the toggle element
1907 * @param {Element} toggleEl - The toggle element.
1909 function initialize(toggleEl) {
1911 if (toggleEl._muiTabs === true) return;
1912 else toggleEl._muiTabs = true;
1914 // attach click handler
1915 jqLite.on(toggleEl, 'click', clickHandler);
1920 * Handle clicks on the toggle element.
1921 * @param {Event} ev - The DOM event.
1923 function clickHandler(ev) {
1925 if (ev.button !== 0) return;
1927 var toggleEl = this;
1929 // exit if toggle element is disabled
1930 if (toggleEl.getAttribute('disabled') !== null) return;
1932 activateTab(toggleEl);
1937 * Activate the tab controlled by the toggle element.
1938 * @param {Element} toggleEl - The toggle element.
1940 function activateTab(currToggleEl) {
1941 var currTabEl = currToggleEl.parentNode,
1942 currPaneId = currToggleEl.getAttribute(controlsAttrKey),
1943 currPaneEl = document.getElementById(currPaneId),
1954 // exit if already active
1955 if (jqLite.hasClass(currTabEl, activeClass)) return;
1957 // raise error if pane doesn't exist
1958 if (!currPaneEl) util.raiseError('Tab pane "' + currPaneId + '" not found');
1960 // get previous pane
1961 prevPaneEl = getActiveSibling(currPaneEl);
1964 prevPaneId = prevPaneEl.id;
1966 // get previous toggle and tab elements
1967 cssSelector = '[' + controlsAttrKey + '="' + prevPaneId + '"]';
1968 prevToggleEl = document.querySelectorAll(cssSelector)[0];
1969 prevTabEl = prevToggleEl.parentNode;
1972 // define event data
1973 currData = {paneId: currPaneId, relatedPaneId: prevPaneId};
1974 prevData = {paneId: prevPaneId, relatedPaneId: currPaneId};
1976 // dispatch 'hidestart', 'showstart' events
1977 ev1 = util.dispatchEvent(prevToggleEl, hidestartKey, true, true, prevData);
1978 ev2 = util.dispatchEvent(currToggleEl, showstartKey, true, true, currData);
1980 // let events bubble
1981 setTimeout(function() {
1982 // exit if either event was canceled
1983 if (ev1.defaultPrevented || ev2.defaultPrevented) return;
1985 // de-activate previous
1986 if (prevTabEl) jqLite.removeClass(prevTabEl, activeClass);
1987 if (prevPaneEl) jqLite.removeClass(prevPaneEl, activeClass);
1990 jqLite.addClass(currTabEl, activeClass);
1991 jqLite.addClass(currPaneEl, activeClass);
1993 // dispatch 'hideend', 'showend' events
1994 util.dispatchEvent(prevToggleEl, hideendKey, true, false, prevData);
1995 util.dispatchEvent(currToggleEl, showendKey, true, false, currData);
2001 * Get previous active sibling.
2002 * @param {Element} el - The anchor element.
2004 function getActiveSibling(el) {
2005 var elList = el.parentNode.children,
2010 while (q-- && !activeEl) {
2012 if (tmpEl !== el && jqLite.hasClass(tmpEl, activeClass)) activeEl = tmpEl
2019 /** Define module API */
2021 /** Initialize module listeners */
2022 initListeners: function() {
2023 // markup elements available when method is called
2024 var elList = document.querySelectorAll(attrSelector),
2026 while (i--) {initialize(elList[i]);}
2028 animationHelpers.onAnimationStart('mui-tab-inserted', function(ev) {
2029 initialize(ev.target);
2035 activate: function(paneId) {
2036 var cssSelector = '[' + controlsAttrKey + '=' + paneId + ']',
2037 toggleEl = document.querySelectorAll(cssSelector);
2039 if (!toggleEl.length) {
2040 util.raiseError('Tab control for pane "' + paneId + '" not found');
2043 activateTab(toggleEl[0]);
2048 },{"./lib/animationHelpers":4,"./lib/jqLite":6,"./lib/util":7}],12:[function(require,module,exports){
2050 * MUI CSS/JS form-control module
2051 * @module forms/form-control
2057 var jqLite = require('./lib/jqLite'),
2058 util = require('./lib/util'),
2059 animlib = require('./lib/animationHelpers'),
2060 cssSelector = '.mui-textfield > input, .mui-textfield > textarea',
2061 floatingLabelClass = 'mui-textfield--float-label';
2064 var touchedClass = 'mui--is-touched', // hasn't lost focus yet
2065 untouchedClass = 'mui--is-untouched',
2066 pristineClass = 'mui--is-pristine', // user hasn't interacted yet
2067 dirtyClass = 'mui--is-dirty',
2068 emptyClass = 'mui--is-empty', // control is empty
2069 notEmptyClass = 'mui--is-not-empty';
2073 * Initialize input element.
2074 * @param {Element} inputEl - The input element.
2076 function initialize(inputEl) {
2078 if (inputEl._muiTextfield === true) return;
2079 else inputEl._muiTextfield = true;
2081 // add initial control state classes
2082 if (inputEl.value.length) jqLite.addClass(inputEl, notEmptyClass);
2083 else jqLite.addClass(inputEl, emptyClass);
2085 jqLite.addClass(inputEl, untouchedClass + ' ' + pristineClass);
2087 // replace `untouched` with `touched` when control loses focus
2088 jqLite.on(inputEl, 'blur', function blurHandler () {
2089 // ignore if event is a window blur
2090 if (document.activeElement === inputEl) return;
2092 // replace class and remove event handler
2093 jqLite.removeClass(inputEl, untouchedClass);
2094 jqLite.addClass(inputEl, touchedClass);
2095 jqLite.off(inputEl, 'blur', blurHandler);
2098 // replace `pristine` with `dirty` when user interacts with control
2099 jqLite.one(inputEl, 'input change', function() {
2100 jqLite.removeClass(inputEl, pristineClass);
2101 jqLite.addClass(inputEl, dirtyClass);
2104 // add change handler
2105 jqLite.on(inputEl, 'input change', inputHandler);
2110 * Handle input events.
2112 function inputHandler() {
2115 if (inputEl.value.length) {
2116 jqLite.removeClass(inputEl, emptyClass);
2117 jqLite.addClass(inputEl, notEmptyClass);
2119 jqLite.removeClass(inputEl, notEmptyClass);
2120 jqLite.addClass(inputEl, emptyClass)
2125 /** Define module API */
2127 /** Initialize input elements */
2128 initialize: initialize,
2130 /** Initialize module listeners */
2131 initListeners: function() {
2134 // markup elements available when method is called
2135 var elList = doc.querySelectorAll(cssSelector),
2137 while (i--) initialize(elList[i]);
2139 // listen for new elements
2140 animlib.onAnimationStart('mui-textfield-inserted', function(ev) {
2141 initialize(ev.target);
2144 // add transition css for floating labels
2145 setTimeout(function() {
2146 var css = '.mui-textfield.mui-textfield--float-label > label {' + [
2147 '-webkit-transition',
2152 ].join(':all .15s ease-out;') + '}';
2154 util.loadStyle(css);
2157 // pointer-events shim for floating labels
2158 if (util.supportsPointerEvents() === false) {
2159 jqLite.on(doc, 'click', function(ev) {
2160 var targetEl = ev.target;
2162 if (targetEl.tagName === 'LABEL' &&
2163 jqLite.hasClass(targetEl.parentNode, floatingLabelClass)) {
2164 var inputEl = targetEl.previousElementSibling;
2165 if (inputEl) inputEl.focus();
2172 },{"./lib/animationHelpers":4,"./lib/jqLite":6,"./lib/util":7}]},{},[1]);