Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / third_party / mdl / repo / material.js
1 ;(function() {
2 "use strict";
3
4 /**
5  * @license
6  * Copyright 2015 Google Inc. All Rights Reserved.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 /**
22  * A component handler interface using the revealing module design pattern.
23  * More details on this design pattern here:
24  * https://github.com/jasonmayes/mdl-component-design-pattern
25  *
26  * @author Jason Mayes.
27  */
28 /* exported componentHandler */
29
30 // Pre-defining the componentHandler interface, for closure documentation and
31 // static verification.
32 var componentHandler = {
33   /**
34    * Searches existing DOM for elements of our component type and upgrades them
35    * if they have not already been upgraded.
36    *
37    * @param {string=} optJsClass the programatic name of the element class we
38    * need to create a new instance of.
39    * @param {string=} optCssClass the name of the CSS class elements of this
40    * type will have.
41    */
42   upgradeDom: function(optJsClass, optCssClass) {},
43   /**
44    * Upgrades a specific element rather than all in the DOM.
45    *
46    * @param {!Element} element The element we wish to upgrade.
47    * @param {string=} optJsClass Optional name of the class we want to upgrade
48    * the element to.
49    */
50   upgradeElement: function(element, optJsClass) {},
51   /**
52    * Upgrades a specific list of elements rather than all in the DOM.
53    *
54    * @param {!Element|!Array<!Element>|!NodeList|!HTMLCollection} elements
55    * The elements we wish to upgrade.
56    */
57   upgradeElements: function(elements) {},
58   /**
59    * Upgrades all registered components found in the current DOM. This is
60    * automatically called on window load.
61    */
62   upgradeAllRegistered: function() {},
63   /**
64    * Allows user to be alerted to any upgrades that are performed for a given
65    * component type
66    *
67    * @param {string} jsClass The class name of the MDL component we wish
68    * to hook into for any upgrades performed.
69    * @param {function(!HTMLElement)} callback The function to call upon an
70    * upgrade. This function should expect 1 parameter - the HTMLElement which
71    * got upgraded.
72    */
73   registerUpgradedCallback: function(jsClass, callback) {},
74   /**
75    * Registers a class for future use and attempts to upgrade existing DOM.
76    *
77    * @param {componentHandler.ComponentConfigPublic} config the registration configuration
78    */
79   register: function(config) {},
80   /**
81    * Downgrade either a given node, an array of nodes, or a NodeList.
82    *
83    * @param {!Node|!Array<!Node>|!NodeList} nodes
84    */
85   downgradeElements: function(nodes) {}
86 };
87
88 componentHandler = (function() {
89   'use strict';
90
91   /** @type {!Array<componentHandler.ComponentConfig>} */
92   var registeredComponents_ = [];
93
94   /** @type {!Array<componentHandler.Component>} */
95   var createdComponents_ = [];
96
97   var componentConfigProperty_ = 'mdlComponentConfigInternal_';
98
99   /**
100    * Searches registered components for a class we are interested in using.
101    * Optionally replaces a match with passed object if specified.
102    *
103    * @param {string} name The name of a class we want to use.
104    * @param {componentHandler.ComponentConfig=} optReplace Optional object to replace match with.
105    * @return {!Object|boolean}
106    * @private
107    */
108   function findRegisteredClass_(name, optReplace) {
109     for (var i = 0; i < registeredComponents_.length; i++) {
110       if (registeredComponents_[i].className === name) {
111         if (typeof optReplace !== 'undefined') {
112           registeredComponents_[i] = optReplace;
113         }
114         return registeredComponents_[i];
115       }
116     }
117     return false;
118   }
119
120   /**
121    * Returns an array of the classNames of the upgraded classes on the element.
122    *
123    * @param {!Element} element The element to fetch data from.
124    * @return {!Array<string>}
125    * @private
126    */
127   function getUpgradedListOfElement_(element) {
128     var dataUpgraded = element.getAttribute('data-upgraded');
129     // Use `['']` as default value to conform the `,name,name...` style.
130     return dataUpgraded === null ? [''] : dataUpgraded.split(',');
131   }
132
133   /**
134    * Returns true if the given element has already been upgraded for the given
135    * class.
136    *
137    * @param {!Element} element The element we want to check.
138    * @param {string} jsClass The class to check for.
139    * @returns {boolean}
140    * @private
141    */
142   function isElementUpgraded_(element, jsClass) {
143     var upgradedList = getUpgradedListOfElement_(element);
144     return upgradedList.indexOf(jsClass) !== -1;
145   }
146
147   /**
148    * Create an event object.
149    *
150    * @param {string} eventType The type name of the event.
151    * @param {boolean} bubbles Whether the event should bubble up the DOM.
152    * @param {boolean} cancelable Whether the event can be canceled.
153    * @returns {!Event}
154    */
155   function createEvent_(eventType, bubbles, cancelable) {
156     if ('CustomEvent' in window && typeof window.CustomEvent === 'function') {
157       return new CustomEvent(eventType, {
158         bubbles: bubbles,
159         cancelable: cancelable
160       });
161     } else {
162       var ev = document.createEvent('Events');
163       ev.initEvent(eventType, bubbles, cancelable);
164       return ev;
165     }
166   }
167
168   /**
169    * Searches existing DOM for elements of our component type and upgrades them
170    * if they have not already been upgraded.
171    *
172    * @param {string=} optJsClass the programatic name of the element class we
173    * need to create a new instance of.
174    * @param {string=} optCssClass the name of the CSS class elements of this
175    * type will have.
176    */
177   function upgradeDomInternal(optJsClass, optCssClass) {
178     if (typeof optJsClass === 'undefined' &&
179         typeof optCssClass === 'undefined') {
180       for (var i = 0; i < registeredComponents_.length; i++) {
181         upgradeDomInternal(registeredComponents_[i].className,
182             registeredComponents_[i].cssClass);
183       }
184     } else {
185       var jsClass = /** @type {string} */ (optJsClass);
186       if (typeof optCssClass === 'undefined') {
187         var registeredClass = findRegisteredClass_(jsClass);
188         if (registeredClass) {
189           optCssClass = registeredClass.cssClass;
190         }
191       }
192
193       var elements = document.querySelectorAll('.' + optCssClass);
194       for (var n = 0; n < elements.length; n++) {
195         upgradeElementInternal(elements[n], jsClass);
196       }
197     }
198   }
199
200   /**
201    * Upgrades a specific element rather than all in the DOM.
202    *
203    * @param {!Element} element The element we wish to upgrade.
204    * @param {string=} optJsClass Optional name of the class we want to upgrade
205    * the element to.
206    */
207   function upgradeElementInternal(element, optJsClass) {
208     // Verify argument type.
209     if (!(typeof element === 'object' && element instanceof Element)) {
210       throw new Error('Invalid argument provided to upgrade MDL element.');
211     }
212     // Allow upgrade to be canceled by canceling emitted event.
213     var upgradingEv = createEvent_('mdl-componentupgrading', true, true);
214     element.dispatchEvent(upgradingEv);
215     if (upgradingEv.defaultPrevented) {
216       return;
217     }
218
219     var upgradedList = getUpgradedListOfElement_(element);
220     var classesToUpgrade = [];
221     // If jsClass is not provided scan the registered components to find the
222     // ones matching the element's CSS classList.
223     if (!optJsClass) {
224       var classList = element.classList;
225       registeredComponents_.forEach(function(component) {
226         // Match CSS & Not to be upgraded & Not upgraded.
227         if (classList.contains(component.cssClass) &&
228             classesToUpgrade.indexOf(component) === -1 &&
229             !isElementUpgraded_(element, component.className)) {
230           classesToUpgrade.push(component);
231         }
232       });
233     } else if (!isElementUpgraded_(element, optJsClass)) {
234       classesToUpgrade.push(findRegisteredClass_(optJsClass));
235     }
236
237     // Upgrade the element for each classes.
238     for (var i = 0, n = classesToUpgrade.length, registeredClass; i < n; i++) {
239       registeredClass = classesToUpgrade[i];
240       if (registeredClass) {
241         // Mark element as upgraded.
242         upgradedList.push(registeredClass.className);
243         element.setAttribute('data-upgraded', upgradedList.join(','));
244         var instance = new registeredClass.classConstructor(element);
245         instance[componentConfigProperty_] = registeredClass;
246         createdComponents_.push(instance);
247         // Call any callbacks the user has registered with this component type.
248         for (var j = 0, m = registeredClass.callbacks.length; j < m; j++) {
249           registeredClass.callbacks[j](element);
250         }
251
252         if (registeredClass.widget) {
253           // Assign per element instance for control over API
254           element[registeredClass.className] = instance;
255         }
256       } else {
257         throw new Error(
258           'Unable to find a registered component for the given class.');
259       }
260
261       var upgradedEv = createEvent_('mdl-componentupgraded', true, false);
262       element.dispatchEvent(upgradedEv);
263     }
264   }
265
266   /**
267    * Upgrades a specific list of elements rather than all in the DOM.
268    *
269    * @param {!Element|!Array<!Element>|!NodeList|!HTMLCollection} elements
270    * The elements we wish to upgrade.
271    */
272   function upgradeElementsInternal(elements) {
273     if (!Array.isArray(elements)) {
274       if (elements instanceof Element) {
275         elements = [elements];
276       } else {
277         elements = Array.prototype.slice.call(elements);
278       }
279     }
280     for (var i = 0, n = elements.length, element; i < n; i++) {
281       element = elements[i];
282       if (element instanceof HTMLElement) {
283         upgradeElementInternal(element);
284         if (element.children.length > 0) {
285           upgradeElementsInternal(element.children);
286         }
287       }
288     }
289   }
290
291   /**
292    * Registers a class for future use and attempts to upgrade existing DOM.
293    *
294    * @param {componentHandler.ComponentConfigPublic} config
295    */
296   function registerInternal(config) {
297     // In order to support both Closure-compiled and uncompiled code accessing
298     // this method, we need to allow for both the dot and array syntax for
299     // property access. You'll therefore see the `foo.bar || foo['bar']`
300     // pattern repeated across this method.
301     var widgetMissing = (typeof config.widget === 'undefined' &&
302         typeof config['widget'] === 'undefined');
303     var widget = true;
304
305     if (!widgetMissing) {
306       widget = config.widget || config['widget'];
307     }
308
309     var newConfig = /** @type {componentHandler.ComponentConfig} */ ({
310       classConstructor: config.constructor || config['constructor'],
311       className: config.classAsString || config['classAsString'],
312       cssClass: config.cssClass || config['cssClass'],
313       widget: widget,
314       callbacks: []
315     });
316
317     registeredComponents_.forEach(function(item) {
318       if (item.cssClass === newConfig.cssClass) {
319         throw new Error('The provided cssClass has already been registered: ' + item.cssClass);
320       }
321       if (item.className === newConfig.className) {
322         throw new Error('The provided className has already been registered');
323       }
324     });
325
326     if (config.constructor.prototype
327         .hasOwnProperty(componentConfigProperty_)) {
328       throw new Error(
329           'MDL component classes must not have ' + componentConfigProperty_ +
330           ' defined as a property.');
331     }
332
333     var found = findRegisteredClass_(config.classAsString, newConfig);
334
335     if (!found) {
336       registeredComponents_.push(newConfig);
337     }
338   }
339
340   /**
341    * Allows user to be alerted to any upgrades that are performed for a given
342    * component type
343    *
344    * @param {string} jsClass The class name of the MDL component we wish
345    * to hook into for any upgrades performed.
346    * @param {function(!HTMLElement)} callback The function to call upon an
347    * upgrade. This function should expect 1 parameter - the HTMLElement which
348    * got upgraded.
349    */
350   function registerUpgradedCallbackInternal(jsClass, callback) {
351     var regClass = findRegisteredClass_(jsClass);
352     if (regClass) {
353       regClass.callbacks.push(callback);
354     }
355   }
356
357   /**
358    * Upgrades all registered components found in the current DOM. This is
359    * automatically called on window load.
360    */
361   function upgradeAllRegisteredInternal() {
362     for (var n = 0; n < registeredComponents_.length; n++) {
363       upgradeDomInternal(registeredComponents_[n].className);
364     }
365   }
366
367   /**
368    * Check the component for the downgrade method.
369    * Execute if found.
370    * Remove component from createdComponents list.
371    *
372    * @param {?componentHandler.Component} component
373    */
374   function deconstructComponentInternal(component) {
375     if (component) {
376       var componentIndex = createdComponents_.indexOf(component);
377       createdComponents_.splice(componentIndex, 1);
378
379       var upgrades = component.element_.getAttribute('data-upgraded').split(',');
380       var componentPlace = upgrades.indexOf(component[componentConfigProperty_].classAsString);
381       upgrades.splice(componentPlace, 1);
382       component.element_.setAttribute('data-upgraded', upgrades.join(','));
383
384       var ev = createEvent_('mdl-componentdowngraded', true, false);
385       component.element_.dispatchEvent(ev);
386     }
387   }
388
389   /**
390    * Downgrade either a given node, an array of nodes, or a NodeList.
391    *
392    * @param {!Node|!Array<!Node>|!NodeList} nodes
393    */
394   function downgradeNodesInternal(nodes) {
395     /**
396      * Auxiliary function to downgrade a single node.
397      * @param  {!Node} node the node to be downgraded
398      */
399     var downgradeNode = function(node) {
400       createdComponents_.filter(function(item) {
401         return item.element_ === node;
402       }).forEach(deconstructComponentInternal);
403     };
404     if (nodes instanceof Array || nodes instanceof NodeList) {
405       for (var n = 0; n < nodes.length; n++) {
406         downgradeNode(nodes[n]);
407       }
408     } else if (nodes instanceof Node) {
409       downgradeNode(nodes);
410     } else {
411       throw new Error('Invalid argument provided to downgrade MDL nodes.');
412     }
413   }
414
415   // Now return the functions that should be made public with their publicly
416   // facing names...
417   return {
418     upgradeDom: upgradeDomInternal,
419     upgradeElement: upgradeElementInternal,
420     upgradeElements: upgradeElementsInternal,
421     upgradeAllRegistered: upgradeAllRegisteredInternal,
422     registerUpgradedCallback: registerUpgradedCallbackInternal,
423     register: registerInternal,
424     downgradeElements: downgradeNodesInternal
425   };
426 })();
427
428 /**
429  * Describes the type of a registered component type managed by
430  * componentHandler. Provided for benefit of the Closure compiler.
431  *
432  * @typedef {{
433  *   constructor: Function,
434  *   classAsString: string,
435  *   cssClass: string,
436  *   widget: (string|boolean|undefined)
437  * }}
438  */
439 componentHandler.ComponentConfigPublic;  // jshint ignore:line
440
441 /**
442  * Describes the type of a registered component type managed by
443  * componentHandler. Provided for benefit of the Closure compiler.
444  *
445  * @typedef {{
446  *   constructor: !Function,
447  *   className: string,
448  *   cssClass: string,
449  *   widget: (string|boolean),
450  *   callbacks: !Array<function(!HTMLElement)>
451  * }}
452  */
453 componentHandler.ComponentConfig;  // jshint ignore:line
454
455 /**
456  * Created component (i.e., upgraded element) type as managed by
457  * componentHandler. Provided for benefit of the Closure compiler.
458  *
459  * @typedef {{
460  *   element_: !HTMLElement,
461  *   className: string,
462  *   classAsString: string,
463  *   cssClass: string,
464  *   widget: string
465  * }}
466  */
467 componentHandler.Component;  // jshint ignore:line
468
469 // Export all symbols, for the benefit of Closure compiler.
470 // No effect on uncompiled code.
471 componentHandler['upgradeDom'] = componentHandler.upgradeDom;
472 componentHandler['upgradeElement'] = componentHandler.upgradeElement;
473 componentHandler['upgradeElements'] = componentHandler.upgradeElements;
474 componentHandler['upgradeAllRegistered'] =
475     componentHandler.upgradeAllRegistered;
476 componentHandler['registerUpgradedCallback'] =
477     componentHandler.registerUpgradedCallback;
478 componentHandler['register'] = componentHandler.register;
479 componentHandler['downgradeElements'] = componentHandler.downgradeElements;
480 window.componentHandler = componentHandler;
481 window['componentHandler'] = componentHandler;
482
483 window.addEventListener('load', function() {
484   'use strict';
485
486   /**
487    * Performs a "Cutting the mustard" test. If the browser supports the features
488    * tested, adds a mdl-js class to the <html> element. It then upgrades all MDL
489    * components requiring JavaScript.
490    */
491   if ('classList' in document.createElement('div') &&
492       'querySelector' in document &&
493       'addEventListener' in window && Array.prototype.forEach) {
494     document.documentElement.classList.add('mdl-js');
495     componentHandler.upgradeAllRegistered();
496   } else {
497     /**
498      * Dummy function to avoid JS errors.
499      */
500     componentHandler.upgradeElement = function() {};
501     /**
502      * Dummy function to avoid JS errors.
503      */
504     componentHandler.register = function() {};
505   }
506 });
507
508 // Source: https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js
509 // Adapted from https://gist.github.com/paulirish/1579671 which derived from
510 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
511 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
512 // requestAnimationFrame polyfill by Erik Möller.
513 // Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
514 // MIT license
515 if (!Date.now) {
516     /**
517      * Date.now polyfill.
518      * @return {number} the current Date
519      */
520     Date.now = function () {
521         return new Date().getTime();
522     };
523     Date['now'] = Date.now;
524 }
525 var vendors = [
526     'webkit',
527     'moz'
528 ];
529 for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
530     var vp = vendors[i];
531     window.requestAnimationFrame = window[vp + 'RequestAnimationFrame'];
532     window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame'];
533     window['requestAnimationFrame'] = window.requestAnimationFrame;
534     window['cancelAnimationFrame'] = window.cancelAnimationFrame;
535 }
536 if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
537     var lastTime = 0;
538     /**
539      * requestAnimationFrame polyfill.
540      * @param  {!Function} callback the callback function.
541      */
542     window.requestAnimationFrame = function (callback) {
543         var now = Date.now();
544         var nextTime = Math.max(lastTime + 16, now);
545         return setTimeout(function () {
546             callback(lastTime = nextTime);
547         }, nextTime - now);
548     };
549     window.cancelAnimationFrame = clearTimeout;
550     window['requestAnimationFrame'] = window.requestAnimationFrame;
551     window['cancelAnimationFrame'] = window.cancelAnimationFrame;
552 }
553 /**
554  * @license
555  * Copyright 2015 Google Inc. All Rights Reserved.
556  *
557  * Licensed under the Apache License, Version 2.0 (the "License");
558  * you may not use this file except in compliance with the License.
559  * You may obtain a copy of the License at
560  *
561  *      http://www.apache.org/licenses/LICENSE-2.0
562  *
563  * Unless required by applicable law or agreed to in writing, software
564  * distributed under the License is distributed on an "AS IS" BASIS,
565  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
566  * See the License for the specific language governing permissions and
567  * limitations under the License.
568  */
569 /**
570    * Class constructor for Button MDL component.
571    * Implements MDL component design pattern defined at:
572    * https://github.com/jasonmayes/mdl-component-design-pattern
573    *
574    * @param {HTMLElement} element The element that will be upgraded.
575    */
576 var MaterialButton = function MaterialButton(element) {
577     this.element_ = element;
578     // Initialize instance.
579     this.init();
580 };
581 window['MaterialButton'] = MaterialButton;
582 /**
583    * Store constants in one place so they can be updated easily.
584    *
585    * @enum {string | number}
586    * @private
587    */
588 MaterialButton.prototype.Constant_ = {};
589 /**
590    * Store strings for class names defined by this component that are used in
591    * JavaScript. This allows us to simply change it in one place should we
592    * decide to modify at a later date.
593    *
594    * @enum {string}
595    * @private
596    */
597 MaterialButton.prototype.CssClasses_ = {
598     RIPPLE_EFFECT: 'mdl-js-ripple-effect',
599     RIPPLE_CONTAINER: 'mdl-button__ripple-container',
600     RIPPLE: 'mdl-ripple'
601 };
602 /**
603    * Handle blur of element.
604    *
605    * @param {Event} event The event that fired.
606    * @private
607    */
608 MaterialButton.prototype.blurHandler_ = function (event) {
609     if (event) {
610         this.element_.blur();
611     }
612 };
613 // Public methods.
614 /**
615    * Disable button.
616    *
617    * @public
618    */
619 MaterialButton.prototype.disable = function () {
620     this.element_.disabled = true;
621 };
622 MaterialButton.prototype['disable'] = MaterialButton.prototype.disable;
623 /**
624    * Enable button.
625    *
626    * @public
627    */
628 MaterialButton.prototype.enable = function () {
629     this.element_.disabled = false;
630 };
631 MaterialButton.prototype['enable'] = MaterialButton.prototype.enable;
632 /**
633    * Initialize element.
634    */
635 MaterialButton.prototype.init = function () {
636     if (this.element_) {
637         if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) {
638             var rippleContainer = document.createElement('span');
639             rippleContainer.classList.add(this.CssClasses_.RIPPLE_CONTAINER);
640             this.rippleElement_ = document.createElement('span');
641             this.rippleElement_.classList.add(this.CssClasses_.RIPPLE);
642             rippleContainer.appendChild(this.rippleElement_);
643             this.boundRippleBlurHandler = this.blurHandler_.bind(this);
644             this.rippleElement_.addEventListener('mouseup', this.boundRippleBlurHandler);
645             this.element_.appendChild(rippleContainer);
646         }
647         this.boundButtonBlurHandler = this.blurHandler_.bind(this);
648         this.element_.addEventListener('mouseup', this.boundButtonBlurHandler);
649         this.element_.addEventListener('mouseleave', this.boundButtonBlurHandler);
650     }
651 };
652 // The component registers itself. It can assume componentHandler is available
653 // in the global scope.
654 componentHandler.register({
655     constructor: MaterialButton,
656     classAsString: 'MaterialButton',
657     cssClass: 'mdl-js-button',
658     widget: true
659 });
660 /**
661  * @license
662  * Copyright 2015 Google Inc. All Rights Reserved.
663  *
664  * Licensed under the Apache License, Version 2.0 (the "License");
665  * you may not use this file except in compliance with the License.
666  * You may obtain a copy of the License at
667  *
668  *      http://www.apache.org/licenses/LICENSE-2.0
669  *
670  * Unless required by applicable law or agreed to in writing, software
671  * distributed under the License is distributed on an "AS IS" BASIS,
672  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
673  * See the License for the specific language governing permissions and
674  * limitations under the License.
675  */
676 /**
677    * Class constructor for Checkbox MDL component.
678    * Implements MDL component design pattern defined at:
679    * https://github.com/jasonmayes/mdl-component-design-pattern
680    *
681    * @constructor
682    * @param {HTMLElement} element The element that will be upgraded.
683    */
684 var MaterialCheckbox = function MaterialCheckbox(element) {
685     this.element_ = element;
686     // Initialize instance.
687     this.init();
688 };
689 window['MaterialCheckbox'] = MaterialCheckbox;
690 /**
691    * Store constants in one place so they can be updated easily.
692    *
693    * @enum {string | number}
694    * @private
695    */
696 MaterialCheckbox.prototype.Constant_ = { TINY_TIMEOUT: 0.001 };
697 /**
698    * Store strings for class names defined by this component that are used in
699    * JavaScript. This allows us to simply change it in one place should we
700    * decide to modify at a later date.
701    *
702    * @enum {string}
703    * @private
704    */
705 MaterialCheckbox.prototype.CssClasses_ = {
706     INPUT: 'mdl-checkbox__input',
707     BOX_OUTLINE: 'mdl-checkbox__box-outline',
708     FOCUS_HELPER: 'mdl-checkbox__focus-helper',
709     TICK_OUTLINE: 'mdl-checkbox__tick-outline',
710     RIPPLE_EFFECT: 'mdl-js-ripple-effect',
711     RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
712     RIPPLE_CONTAINER: 'mdl-checkbox__ripple-container',
713     RIPPLE_CENTER: 'mdl-ripple--center',
714     RIPPLE: 'mdl-ripple',
715     IS_FOCUSED: 'is-focused',
716     IS_DISABLED: 'is-disabled',
717     IS_CHECKED: 'is-checked',
718     IS_UPGRADED: 'is-upgraded'
719 };
720 /**
721    * Handle change of state.
722    *
723    * @param {Event} event The event that fired.
724    * @private
725    */
726 MaterialCheckbox.prototype.onChange_ = function (event) {
727     this.updateClasses_();
728 };
729 /**
730    * Handle focus of element.
731    *
732    * @param {Event} event The event that fired.
733    * @private
734    */
735 MaterialCheckbox.prototype.onFocus_ = function (event) {
736     this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
737 };
738 /**
739    * Handle lost focus of element.
740    *
741    * @param {Event} event The event that fired.
742    * @private
743    */
744 MaterialCheckbox.prototype.onBlur_ = function (event) {
745     this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
746 };
747 /**
748    * Handle mouseup.
749    *
750    * @param {Event} event The event that fired.
751    * @private
752    */
753 MaterialCheckbox.prototype.onMouseUp_ = function (event) {
754     this.blur_();
755 };
756 /**
757    * Handle class updates.
758    *
759    * @private
760    */
761 MaterialCheckbox.prototype.updateClasses_ = function () {
762     this.checkDisabled();
763     this.checkToggleState();
764 };
765 /**
766    * Add blur.
767    *
768    * @private
769    */
770 MaterialCheckbox.prototype.blur_ = function () {
771     // TODO: figure out why there's a focus event being fired after our blur,
772     // so that we can avoid this hack.
773     window.setTimeout(function () {
774         this.inputElement_.blur();
775     }.bind(this), this.Constant_.TINY_TIMEOUT);
776 };
777 // Public methods.
778 /**
779    * Check the inputs toggle state and update display.
780    *
781    * @public
782    */
783 MaterialCheckbox.prototype.checkToggleState = function () {
784     if (this.inputElement_.checked) {
785         this.element_.classList.add(this.CssClasses_.IS_CHECKED);
786     } else {
787         this.element_.classList.remove(this.CssClasses_.IS_CHECKED);
788     }
789 };
790 MaterialCheckbox.prototype['checkToggleState'] = MaterialCheckbox.prototype.checkToggleState;
791 /**
792    * Check the inputs disabled state and update display.
793    *
794    * @public
795    */
796 MaterialCheckbox.prototype.checkDisabled = function () {
797     if (this.inputElement_.disabled) {
798         this.element_.classList.add(this.CssClasses_.IS_DISABLED);
799     } else {
800         this.element_.classList.remove(this.CssClasses_.IS_DISABLED);
801     }
802 };
803 MaterialCheckbox.prototype['checkDisabled'] = MaterialCheckbox.prototype.checkDisabled;
804 /**
805    * Disable checkbox.
806    *
807    * @public
808    */
809 MaterialCheckbox.prototype.disable = function () {
810     this.inputElement_.disabled = true;
811     this.updateClasses_();
812 };
813 MaterialCheckbox.prototype['disable'] = MaterialCheckbox.prototype.disable;
814 /**
815    * Enable checkbox.
816    *
817    * @public
818    */
819 MaterialCheckbox.prototype.enable = function () {
820     this.inputElement_.disabled = false;
821     this.updateClasses_();
822 };
823 MaterialCheckbox.prototype['enable'] = MaterialCheckbox.prototype.enable;
824 /**
825    * Check checkbox.
826    *
827    * @public
828    */
829 MaterialCheckbox.prototype.check = function () {
830     this.inputElement_.checked = true;
831     this.updateClasses_();
832 };
833 MaterialCheckbox.prototype['check'] = MaterialCheckbox.prototype.check;
834 /**
835    * Uncheck checkbox.
836    *
837    * @public
838    */
839 MaterialCheckbox.prototype.uncheck = function () {
840     this.inputElement_.checked = false;
841     this.updateClasses_();
842 };
843 MaterialCheckbox.prototype['uncheck'] = MaterialCheckbox.prototype.uncheck;
844 /**
845    * Initialize element.
846    */
847 MaterialCheckbox.prototype.init = function () {
848     if (this.element_) {
849         this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT);
850         var boxOutline = document.createElement('span');
851         boxOutline.classList.add(this.CssClasses_.BOX_OUTLINE);
852         var tickContainer = document.createElement('span');
853         tickContainer.classList.add(this.CssClasses_.FOCUS_HELPER);
854         var tickOutline = document.createElement('span');
855         tickOutline.classList.add(this.CssClasses_.TICK_OUTLINE);
856         boxOutline.appendChild(tickOutline);
857         this.element_.appendChild(tickContainer);
858         this.element_.appendChild(boxOutline);
859         if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) {
860             this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS);
861             this.rippleContainerElement_ = document.createElement('span');
862             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER);
863             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_EFFECT);
864             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER);
865             this.boundRippleMouseUp = this.onMouseUp_.bind(this);
866             this.rippleContainerElement_.addEventListener('mouseup', this.boundRippleMouseUp);
867             var ripple = document.createElement('span');
868             ripple.classList.add(this.CssClasses_.RIPPLE);
869             this.rippleContainerElement_.appendChild(ripple);
870             this.element_.appendChild(this.rippleContainerElement_);
871         }
872         this.boundInputOnChange = this.onChange_.bind(this);
873         this.boundInputOnFocus = this.onFocus_.bind(this);
874         this.boundInputOnBlur = this.onBlur_.bind(this);
875         this.boundElementMouseUp = this.onMouseUp_.bind(this);
876         this.inputElement_.addEventListener('change', this.boundInputOnChange);
877         this.inputElement_.addEventListener('focus', this.boundInputOnFocus);
878         this.inputElement_.addEventListener('blur', this.boundInputOnBlur);
879         this.element_.addEventListener('mouseup', this.boundElementMouseUp);
880         this.updateClasses_();
881         this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
882     }
883 };
884 // The component registers itself. It can assume componentHandler is available
885 // in the global scope.
886 componentHandler.register({
887     constructor: MaterialCheckbox,
888     classAsString: 'MaterialCheckbox',
889     cssClass: 'mdl-js-checkbox',
890     widget: true
891 });
892 /**
893  * @license
894  * Copyright 2015 Google Inc. All Rights Reserved.
895  *
896  * Licensed under the Apache License, Version 2.0 (the "License");
897  * you may not use this file except in compliance with the License.
898  * You may obtain a copy of the License at
899  *
900  *      http://www.apache.org/licenses/LICENSE-2.0
901  *
902  * Unless required by applicable law or agreed to in writing, software
903  * distributed under the License is distributed on an "AS IS" BASIS,
904  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
905  * See the License for the specific language governing permissions and
906  * limitations under the License.
907  */
908 /**
909    * Class constructor for icon toggle MDL component.
910    * Implements MDL component design pattern defined at:
911    * https://github.com/jasonmayes/mdl-component-design-pattern
912    *
913    * @constructor
914    * @param {HTMLElement} element The element that will be upgraded.
915    */
916 var MaterialIconToggle = function MaterialIconToggle(element) {
917     this.element_ = element;
918     // Initialize instance.
919     this.init();
920 };
921 window['MaterialIconToggle'] = MaterialIconToggle;
922 /**
923    * Store constants in one place so they can be updated easily.
924    *
925    * @enum {string | number}
926    * @private
927    */
928 MaterialIconToggle.prototype.Constant_ = { TINY_TIMEOUT: 0.001 };
929 /**
930    * Store strings for class names defined by this component that are used in
931    * JavaScript. This allows us to simply change it in one place should we
932    * decide to modify at a later date.
933    *
934    * @enum {string}
935    * @private
936    */
937 MaterialIconToggle.prototype.CssClasses_ = {
938     INPUT: 'mdl-icon-toggle__input',
939     JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect',
940     RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
941     RIPPLE_CONTAINER: 'mdl-icon-toggle__ripple-container',
942     RIPPLE_CENTER: 'mdl-ripple--center',
943     RIPPLE: 'mdl-ripple',
944     IS_FOCUSED: 'is-focused',
945     IS_DISABLED: 'is-disabled',
946     IS_CHECKED: 'is-checked'
947 };
948 /**
949    * Handle change of state.
950    *
951    * @param {Event} event The event that fired.
952    * @private
953    */
954 MaterialIconToggle.prototype.onChange_ = function (event) {
955     this.updateClasses_();
956 };
957 /**
958    * Handle focus of element.
959    *
960    * @param {Event} event The event that fired.
961    * @private
962    */
963 MaterialIconToggle.prototype.onFocus_ = function (event) {
964     this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
965 };
966 /**
967    * Handle lost focus of element.
968    *
969    * @param {Event} event The event that fired.
970    * @private
971    */
972 MaterialIconToggle.prototype.onBlur_ = function (event) {
973     this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
974 };
975 /**
976    * Handle mouseup.
977    *
978    * @param {Event} event The event that fired.
979    * @private
980    */
981 MaterialIconToggle.prototype.onMouseUp_ = function (event) {
982     this.blur_();
983 };
984 /**
985    * Handle class updates.
986    *
987    * @private
988    */
989 MaterialIconToggle.prototype.updateClasses_ = function () {
990     this.checkDisabled();
991     this.checkToggleState();
992 };
993 /**
994    * Add blur.
995    *
996    * @private
997    */
998 MaterialIconToggle.prototype.blur_ = function () {
999     // TODO: figure out why there's a focus event being fired after our blur,
1000     // so that we can avoid this hack.
1001     window.setTimeout(function () {
1002         this.inputElement_.blur();
1003     }.bind(this), this.Constant_.TINY_TIMEOUT);
1004 };
1005 // Public methods.
1006 /**
1007    * Check the inputs toggle state and update display.
1008    *
1009    * @public
1010    */
1011 MaterialIconToggle.prototype.checkToggleState = function () {
1012     if (this.inputElement_.checked) {
1013         this.element_.classList.add(this.CssClasses_.IS_CHECKED);
1014     } else {
1015         this.element_.classList.remove(this.CssClasses_.IS_CHECKED);
1016     }
1017 };
1018 MaterialIconToggle.prototype['checkToggleState'] = MaterialIconToggle.prototype.checkToggleState;
1019 /**
1020    * Check the inputs disabled state and update display.
1021    *
1022    * @public
1023    */
1024 MaterialIconToggle.prototype.checkDisabled = function () {
1025     if (this.inputElement_.disabled) {
1026         this.element_.classList.add(this.CssClasses_.IS_DISABLED);
1027     } else {
1028         this.element_.classList.remove(this.CssClasses_.IS_DISABLED);
1029     }
1030 };
1031 MaterialIconToggle.prototype['checkDisabled'] = MaterialIconToggle.prototype.checkDisabled;
1032 /**
1033    * Disable icon toggle.
1034    *
1035    * @public
1036    */
1037 MaterialIconToggle.prototype.disable = function () {
1038     this.inputElement_.disabled = true;
1039     this.updateClasses_();
1040 };
1041 MaterialIconToggle.prototype['disable'] = MaterialIconToggle.prototype.disable;
1042 /**
1043    * Enable icon toggle.
1044    *
1045    * @public
1046    */
1047 MaterialIconToggle.prototype.enable = function () {
1048     this.inputElement_.disabled = false;
1049     this.updateClasses_();
1050 };
1051 MaterialIconToggle.prototype['enable'] = MaterialIconToggle.prototype.enable;
1052 /**
1053    * Check icon toggle.
1054    *
1055    * @public
1056    */
1057 MaterialIconToggle.prototype.check = function () {
1058     this.inputElement_.checked = true;
1059     this.updateClasses_();
1060 };
1061 MaterialIconToggle.prototype['check'] = MaterialIconToggle.prototype.check;
1062 /**
1063    * Uncheck icon toggle.
1064    *
1065    * @public
1066    */
1067 MaterialIconToggle.prototype.uncheck = function () {
1068     this.inputElement_.checked = false;
1069     this.updateClasses_();
1070 };
1071 MaterialIconToggle.prototype['uncheck'] = MaterialIconToggle.prototype.uncheck;
1072 /**
1073    * Initialize element.
1074    */
1075 MaterialIconToggle.prototype.init = function () {
1076     if (this.element_) {
1077         this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT);
1078         if (this.element_.classList.contains(this.CssClasses_.JS_RIPPLE_EFFECT)) {
1079             this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS);
1080             this.rippleContainerElement_ = document.createElement('span');
1081             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER);
1082             this.rippleContainerElement_.classList.add(this.CssClasses_.JS_RIPPLE_EFFECT);
1083             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER);
1084             this.boundRippleMouseUp = this.onMouseUp_.bind(this);
1085             this.rippleContainerElement_.addEventListener('mouseup', this.boundRippleMouseUp);
1086             var ripple = document.createElement('span');
1087             ripple.classList.add(this.CssClasses_.RIPPLE);
1088             this.rippleContainerElement_.appendChild(ripple);
1089             this.element_.appendChild(this.rippleContainerElement_);
1090         }
1091         this.boundInputOnChange = this.onChange_.bind(this);
1092         this.boundInputOnFocus = this.onFocus_.bind(this);
1093         this.boundInputOnBlur = this.onBlur_.bind(this);
1094         this.boundElementOnMouseUp = this.onMouseUp_.bind(this);
1095         this.inputElement_.addEventListener('change', this.boundInputOnChange);
1096         this.inputElement_.addEventListener('focus', this.boundInputOnFocus);
1097         this.inputElement_.addEventListener('blur', this.boundInputOnBlur);
1098         this.element_.addEventListener('mouseup', this.boundElementOnMouseUp);
1099         this.updateClasses_();
1100         this.element_.classList.add('is-upgraded');
1101     }
1102 };
1103 // The component registers itself. It can assume componentHandler is available
1104 // in the global scope.
1105 componentHandler.register({
1106     constructor: MaterialIconToggle,
1107     classAsString: 'MaterialIconToggle',
1108     cssClass: 'mdl-js-icon-toggle',
1109     widget: true
1110 });
1111 /**
1112  * @license
1113  * Copyright 2015 Google Inc. All Rights Reserved.
1114  *
1115  * Licensed under the Apache License, Version 2.0 (the "License");
1116  * you may not use this file except in compliance with the License.
1117  * You may obtain a copy of the License at
1118  *
1119  *      http://www.apache.org/licenses/LICENSE-2.0
1120  *
1121  * Unless required by applicable law or agreed to in writing, software
1122  * distributed under the License is distributed on an "AS IS" BASIS,
1123  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1124  * See the License for the specific language governing permissions and
1125  * limitations under the License.
1126  */
1127 /**
1128    * Class constructor for dropdown MDL component.
1129    * Implements MDL component design pattern defined at:
1130    * https://github.com/jasonmayes/mdl-component-design-pattern
1131    *
1132    * @constructor
1133    * @param {HTMLElement} element The element that will be upgraded.
1134    */
1135 var MaterialMenu = function MaterialMenu(element) {
1136     this.element_ = element;
1137     // Initialize instance.
1138     this.init();
1139 };
1140 window['MaterialMenu'] = MaterialMenu;
1141 /**
1142    * Store constants in one place so they can be updated easily.
1143    *
1144    * @enum {string | number}
1145    * @private
1146    */
1147 MaterialMenu.prototype.Constant_ = {
1148     // Total duration of the menu animation.
1149     TRANSITION_DURATION_SECONDS: 0.3,
1150     // The fraction of the total duration we want to use for menu item animations.
1151     TRANSITION_DURATION_FRACTION: 0.8,
1152     // How long the menu stays open after choosing an option (so the user can see
1153     // the ripple).
1154     CLOSE_TIMEOUT: 150
1155 };
1156 /**
1157    * Keycodes, for code readability.
1158    *
1159    * @enum {number}
1160    * @private
1161    */
1162 MaterialMenu.prototype.Keycodes_ = {
1163     ENTER: 13,
1164     ESCAPE: 27,
1165     SPACE: 32,
1166     UP_ARROW: 38,
1167     DOWN_ARROW: 40
1168 };
1169 /**
1170    * Store strings for class names defined by this component that are used in
1171    * JavaScript. This allows us to simply change it in one place should we
1172    * decide to modify at a later date.
1173    *
1174    * @enum {string}
1175    * @private
1176    */
1177 MaterialMenu.prototype.CssClasses_ = {
1178     CONTAINER: 'mdl-menu__container',
1179     OUTLINE: 'mdl-menu__outline',
1180     ITEM: 'mdl-menu__item',
1181     ITEM_RIPPLE_CONTAINER: 'mdl-menu__item-ripple-container',
1182     RIPPLE_EFFECT: 'mdl-js-ripple-effect',
1183     RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
1184     RIPPLE: 'mdl-ripple',
1185     // Statuses
1186     IS_UPGRADED: 'is-upgraded',
1187     IS_VISIBLE: 'is-visible',
1188     IS_ANIMATING: 'is-animating',
1189     // Alignment options
1190     BOTTOM_LEFT: 'mdl-menu--bottom-left',
1191     // This is the default.
1192     BOTTOM_RIGHT: 'mdl-menu--bottom-right',
1193     TOP_LEFT: 'mdl-menu--top-left',
1194     TOP_RIGHT: 'mdl-menu--top-right',
1195     UNALIGNED: 'mdl-menu--unaligned'
1196 };
1197 /**
1198    * Initialize element.
1199    */
1200 MaterialMenu.prototype.init = function () {
1201     if (this.element_) {
1202         // Create container for the menu.
1203         var container = document.createElement('div');
1204         container.classList.add(this.CssClasses_.CONTAINER);
1205         this.element_.parentElement.insertBefore(container, this.element_);
1206         this.element_.parentElement.removeChild(this.element_);
1207         container.appendChild(this.element_);
1208         this.container_ = container;
1209         // Create outline for the menu (shadow and background).
1210         var outline = document.createElement('div');
1211         outline.classList.add(this.CssClasses_.OUTLINE);
1212         this.outline_ = outline;
1213         container.insertBefore(outline, this.element_);
1214         // Find the "for" element and bind events to it.
1215         var forElId = this.element_.getAttribute('for') || this.element_.getAttribute('data-mdl-for');
1216         var forEl = null;
1217         if (forElId) {
1218             forEl = document.getElementById(forElId);
1219             if (forEl) {
1220                 this.forElement_ = forEl;
1221                 forEl.addEventListener('click', this.handleForClick_.bind(this));
1222                 forEl.addEventListener('keydown', this.handleForKeyboardEvent_.bind(this));
1223             }
1224         }
1225         var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM);
1226         this.boundItemKeydown_ = this.handleItemKeyboardEvent_.bind(this);
1227         this.boundItemClick_ = this.handleItemClick_.bind(this);
1228         for (var i = 0; i < items.length; i++) {
1229             // Add a listener to each menu item.
1230             items[i].addEventListener('click', this.boundItemClick_);
1231             // Add a tab index to each menu item.
1232             items[i].tabIndex = '-1';
1233             // Add a keyboard listener to each menu item.
1234             items[i].addEventListener('keydown', this.boundItemKeydown_);
1235         }
1236         // Add ripple classes to each item, if the user has enabled ripples.
1237         if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) {
1238             this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS);
1239             for (i = 0; i < items.length; i++) {
1240                 var item = items[i];
1241                 var rippleContainer = document.createElement('span');
1242                 rippleContainer.classList.add(this.CssClasses_.ITEM_RIPPLE_CONTAINER);
1243                 var ripple = document.createElement('span');
1244                 ripple.classList.add(this.CssClasses_.RIPPLE);
1245                 rippleContainer.appendChild(ripple);
1246                 item.appendChild(rippleContainer);
1247                 item.classList.add(this.CssClasses_.RIPPLE_EFFECT);
1248             }
1249         }
1250         // Copy alignment classes to the container, so the outline can use them.
1251         if (this.element_.classList.contains(this.CssClasses_.BOTTOM_LEFT)) {
1252             this.outline_.classList.add(this.CssClasses_.BOTTOM_LEFT);
1253         }
1254         if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) {
1255             this.outline_.classList.add(this.CssClasses_.BOTTOM_RIGHT);
1256         }
1257         if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) {
1258             this.outline_.classList.add(this.CssClasses_.TOP_LEFT);
1259         }
1260         if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) {
1261             this.outline_.classList.add(this.CssClasses_.TOP_RIGHT);
1262         }
1263         if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) {
1264             this.outline_.classList.add(this.CssClasses_.UNALIGNED);
1265         }
1266         container.classList.add(this.CssClasses_.IS_UPGRADED);
1267     }
1268 };
1269 /**
1270    * Handles a click on the "for" element, by positioning the menu and then
1271    * toggling it.
1272    *
1273    * @param {Event} evt The event that fired.
1274    * @private
1275    */
1276 MaterialMenu.prototype.handleForClick_ = function (evt) {
1277     if (this.element_ && this.forElement_) {
1278         var rect = this.forElement_.getBoundingClientRect();
1279         var forRect = this.forElement_.parentElement.getBoundingClientRect();
1280         if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) {
1281         } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) {
1282             // Position below the "for" element, aligned to its right.
1283             this.container_.style.right = forRect.right - rect.right + 'px';
1284             this.container_.style.top = this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px';
1285         } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) {
1286             // Position above the "for" element, aligned to its left.
1287             this.container_.style.left = this.forElement_.offsetLeft + 'px';
1288             this.container_.style.bottom = forRect.bottom - rect.top + 'px';
1289         } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) {
1290             // Position above the "for" element, aligned to its right.
1291             this.container_.style.right = forRect.right - rect.right + 'px';
1292             this.container_.style.bottom = forRect.bottom - rect.top + 'px';
1293         } else {
1294             // Default: position below the "for" element, aligned to its left.
1295             this.container_.style.left = this.forElement_.offsetLeft + 'px';
1296             this.container_.style.top = this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px';
1297         }
1298     }
1299     this.toggle(evt);
1300 };
1301 /**
1302    * Handles a keyboard event on the "for" element.
1303    *
1304    * @param {Event} evt The event that fired.
1305    * @private
1306    */
1307 MaterialMenu.prototype.handleForKeyboardEvent_ = function (evt) {
1308     if (this.element_ && this.container_ && this.forElement_) {
1309         var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM + ':not([disabled])');
1310         if (items && items.length > 0 && this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) {
1311             if (evt.keyCode === this.Keycodes_.UP_ARROW) {
1312                 evt.preventDefault();
1313                 items[items.length - 1].focus();
1314             } else if (evt.keyCode === this.Keycodes_.DOWN_ARROW) {
1315                 evt.preventDefault();
1316                 items[0].focus();
1317             }
1318         }
1319     }
1320 };
1321 /**
1322    * Handles a keyboard event on an item.
1323    *
1324    * @param {Event} evt The event that fired.
1325    * @private
1326    */
1327 MaterialMenu.prototype.handleItemKeyboardEvent_ = function (evt) {
1328     if (this.element_ && this.container_) {
1329         var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM + ':not([disabled])');
1330         if (items && items.length > 0 && this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) {
1331             var currentIndex = Array.prototype.slice.call(items).indexOf(evt.target);
1332             if (evt.keyCode === this.Keycodes_.UP_ARROW) {
1333                 evt.preventDefault();
1334                 if (currentIndex > 0) {
1335                     items[currentIndex - 1].focus();
1336                 } else {
1337                     items[items.length - 1].focus();
1338                 }
1339             } else if (evt.keyCode === this.Keycodes_.DOWN_ARROW) {
1340                 evt.preventDefault();
1341                 if (items.length > currentIndex + 1) {
1342                     items[currentIndex + 1].focus();
1343                 } else {
1344                     items[0].focus();
1345                 }
1346             } else if (evt.keyCode === this.Keycodes_.SPACE || evt.keyCode === this.Keycodes_.ENTER) {
1347                 evt.preventDefault();
1348                 // Send mousedown and mouseup to trigger ripple.
1349                 var e = new MouseEvent('mousedown');
1350                 evt.target.dispatchEvent(e);
1351                 e = new MouseEvent('mouseup');
1352                 evt.target.dispatchEvent(e);
1353                 // Send click.
1354                 evt.target.click();
1355             } else if (evt.keyCode === this.Keycodes_.ESCAPE) {
1356                 evt.preventDefault();
1357                 this.hide();
1358             }
1359         }
1360     }
1361 };
1362 /**
1363    * Handles a click event on an item.
1364    *
1365    * @param {Event} evt The event that fired.
1366    * @private
1367    */
1368 MaterialMenu.prototype.handleItemClick_ = function (evt) {
1369     if (evt.target.hasAttribute('disabled')) {
1370         evt.stopPropagation();
1371     } else {
1372         // Wait some time before closing menu, so the user can see the ripple.
1373         this.closing_ = true;
1374         window.setTimeout(function (evt) {
1375             this.hide();
1376             this.closing_ = false;
1377         }.bind(this), this.Constant_.CLOSE_TIMEOUT);
1378     }
1379 };
1380 /**
1381    * Calculates the initial clip (for opening the menu) or final clip (for closing
1382    * it), and applies it. This allows us to animate from or to the correct point,
1383    * that is, the point it's aligned to in the "for" element.
1384    *
1385    * @param {number} height Height of the clip rectangle
1386    * @param {number} width Width of the clip rectangle
1387    * @private
1388    */
1389 MaterialMenu.prototype.applyClip_ = function (height, width) {
1390     if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) {
1391         // Do not clip.
1392         this.element_.style.clip = '';
1393     } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) {
1394         // Clip to the top right corner of the menu.
1395         this.element_.style.clip = 'rect(0 ' + width + 'px ' + '0 ' + width + 'px)';
1396     } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) {
1397         // Clip to the bottom left corner of the menu.
1398         this.element_.style.clip = 'rect(' + height + 'px 0 ' + height + 'px 0)';
1399     } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) {
1400         // Clip to the bottom right corner of the menu.
1401         this.element_.style.clip = 'rect(' + height + 'px ' + width + 'px ' + height + 'px ' + width + 'px)';
1402     } else {
1403         // Default: do not clip (same as clipping to the top left corner).
1404         this.element_.style.clip = '';
1405     }
1406 };
1407 /**
1408    * Cleanup function to remove animation listeners.
1409    *
1410    * @param {Event} evt
1411    * @private
1412    */
1413 MaterialMenu.prototype.removeAnimationEndListener_ = function (evt) {
1414     evt.target.classList.remove(MaterialMenu.prototype.CssClasses_.IS_ANIMATING);
1415 };
1416 /**
1417    * Adds an event listener to clean up after the animation ends.
1418    *
1419    * @private
1420    */
1421 MaterialMenu.prototype.addAnimationEndListener_ = function () {
1422     this.element_.addEventListener('transitionend', this.removeAnimationEndListener_);
1423     this.element_.addEventListener('webkitTransitionEnd', this.removeAnimationEndListener_);
1424 };
1425 /**
1426    * Displays the menu.
1427    *
1428    * @public
1429    */
1430 MaterialMenu.prototype.show = function (evt) {
1431     if (this.element_ && this.container_ && this.outline_) {
1432         // Measure the inner element.
1433         var height = this.element_.getBoundingClientRect().height;
1434         var width = this.element_.getBoundingClientRect().width;
1435         // Apply the inner element's size to the container and outline.
1436         this.container_.style.width = width + 'px';
1437         this.container_.style.height = height + 'px';
1438         this.outline_.style.width = width + 'px';
1439         this.outline_.style.height = height + 'px';
1440         var transitionDuration = this.Constant_.TRANSITION_DURATION_SECONDS * this.Constant_.TRANSITION_DURATION_FRACTION;
1441         // Calculate transition delays for individual menu items, so that they fade
1442         // in one at a time.
1443         var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM);
1444         for (var i = 0; i < items.length; i++) {
1445             var itemDelay = null;
1446             if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT) || this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) {
1447                 itemDelay = (height - items[i].offsetTop - items[i].offsetHeight) / height * transitionDuration + 's';
1448             } else {
1449                 itemDelay = items[i].offsetTop / height * transitionDuration + 's';
1450             }
1451             items[i].style.transitionDelay = itemDelay;
1452         }
1453         // Apply the initial clip to the text before we start animating.
1454         this.applyClip_(height, width);
1455         // Wait for the next frame, turn on animation, and apply the final clip.
1456         // Also make it visible. This triggers the transitions.
1457         window.requestAnimationFrame(function () {
1458             this.element_.classList.add(this.CssClasses_.IS_ANIMATING);
1459             this.element_.style.clip = 'rect(0 ' + width + 'px ' + height + 'px 0)';
1460             this.container_.classList.add(this.CssClasses_.IS_VISIBLE);
1461         }.bind(this));
1462         // Clean up after the animation is complete.
1463         this.addAnimationEndListener_();
1464         // Add a click listener to the document, to close the menu.
1465         var callback = function (e) {
1466             // Check to see if the document is processing the same event that
1467             // displayed the menu in the first place. If so, do nothing.
1468             // Also check to see if the menu is in the process of closing itself, and
1469             // do nothing in that case.
1470             // Also check if the clicked element is a menu item
1471             // if so, do nothing.
1472             if (e !== evt && !this.closing_ && e.target.parentNode !== this.element_) {
1473                 document.removeEventListener('click', callback);
1474                 this.hide();
1475             }
1476         }.bind(this);
1477         document.addEventListener('click', callback);
1478     }
1479 };
1480 MaterialMenu.prototype['show'] = MaterialMenu.prototype.show;
1481 /**
1482    * Hides the menu.
1483    *
1484    * @public
1485    */
1486 MaterialMenu.prototype.hide = function () {
1487     if (this.element_ && this.container_ && this.outline_) {
1488         var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM);
1489         // Remove all transition delays; menu items fade out concurrently.
1490         for (var i = 0; i < items.length; i++) {
1491             items[i].style.removeProperty('transition-delay');
1492         }
1493         // Measure the inner element.
1494         var rect = this.element_.getBoundingClientRect();
1495         var height = rect.height;
1496         var width = rect.width;
1497         // Turn on animation, and apply the final clip. Also make invisible.
1498         // This triggers the transitions.
1499         this.element_.classList.add(this.CssClasses_.IS_ANIMATING);
1500         this.applyClip_(height, width);
1501         this.container_.classList.remove(this.CssClasses_.IS_VISIBLE);
1502         // Clean up after the animation is complete.
1503         this.addAnimationEndListener_();
1504     }
1505 };
1506 MaterialMenu.prototype['hide'] = MaterialMenu.prototype.hide;
1507 /**
1508    * Displays or hides the menu, depending on current state.
1509    *
1510    * @public
1511    */
1512 MaterialMenu.prototype.toggle = function (evt) {
1513     if (this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) {
1514         this.hide();
1515     } else {
1516         this.show(evt);
1517     }
1518 };
1519 MaterialMenu.prototype['toggle'] = MaterialMenu.prototype.toggle;
1520 // The component registers itself. It can assume componentHandler is available
1521 // in the global scope.
1522 componentHandler.register({
1523     constructor: MaterialMenu,
1524     classAsString: 'MaterialMenu',
1525     cssClass: 'mdl-js-menu',
1526     widget: true
1527 });
1528 /**
1529  * @license
1530  * Copyright 2015 Google Inc. All Rights Reserved.
1531  *
1532  * Licensed under the Apache License, Version 2.0 (the "License");
1533  * you may not use this file except in compliance with the License.
1534  * You may obtain a copy of the License at
1535  *
1536  *      http://www.apache.org/licenses/LICENSE-2.0
1537  *
1538  * Unless required by applicable law or agreed to in writing, software
1539  * distributed under the License is distributed on an "AS IS" BASIS,
1540  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1541  * See the License for the specific language governing permissions and
1542  * limitations under the License.
1543  */
1544 /**
1545    * Class constructor for Progress MDL component.
1546    * Implements MDL component design pattern defined at:
1547    * https://github.com/jasonmayes/mdl-component-design-pattern
1548    *
1549    * @constructor
1550    * @param {HTMLElement} element The element that will be upgraded.
1551    */
1552 var MaterialProgress = function MaterialProgress(element) {
1553     this.element_ = element;
1554     // Initialize instance.
1555     this.init();
1556 };
1557 window['MaterialProgress'] = MaterialProgress;
1558 /**
1559    * Store constants in one place so they can be updated easily.
1560    *
1561    * @enum {string | number}
1562    * @private
1563    */
1564 MaterialProgress.prototype.Constant_ = {};
1565 /**
1566    * Store strings for class names defined by this component that are used in
1567    * JavaScript. This allows us to simply change it in one place should we
1568    * decide to modify at a later date.
1569    *
1570    * @enum {string}
1571    * @private
1572    */
1573 MaterialProgress.prototype.CssClasses_ = { INDETERMINATE_CLASS: 'mdl-progress__indeterminate' };
1574 /**
1575    * Set the current progress of the progressbar.
1576    *
1577    * @param {number} p Percentage of the progress (0-100)
1578    * @public
1579    */
1580 MaterialProgress.prototype.setProgress = function (p) {
1581     if (this.element_.classList.contains(this.CssClasses_.INDETERMINATE_CLASS)) {
1582         return;
1583     }
1584     this.progressbar_.style.width = p + '%';
1585 };
1586 MaterialProgress.prototype['setProgress'] = MaterialProgress.prototype.setProgress;
1587 /**
1588    * Set the current progress of the buffer.
1589    *
1590    * @param {number} p Percentage of the buffer (0-100)
1591    * @public
1592    */
1593 MaterialProgress.prototype.setBuffer = function (p) {
1594     this.bufferbar_.style.width = p + '%';
1595     this.auxbar_.style.width = 100 - p + '%';
1596 };
1597 MaterialProgress.prototype['setBuffer'] = MaterialProgress.prototype.setBuffer;
1598 /**
1599    * Initialize element.
1600    */
1601 MaterialProgress.prototype.init = function () {
1602     if (this.element_) {
1603         var el = document.createElement('div');
1604         el.className = 'progressbar bar bar1';
1605         this.element_.appendChild(el);
1606         this.progressbar_ = el;
1607         el = document.createElement('div');
1608         el.className = 'bufferbar bar bar2';
1609         this.element_.appendChild(el);
1610         this.bufferbar_ = el;
1611         el = document.createElement('div');
1612         el.className = 'auxbar bar bar3';
1613         this.element_.appendChild(el);
1614         this.auxbar_ = el;
1615         this.progressbar_.style.width = '0%';
1616         this.bufferbar_.style.width = '100%';
1617         this.auxbar_.style.width = '0%';
1618         this.element_.classList.add('is-upgraded');
1619     }
1620 };
1621 // The component registers itself. It can assume componentHandler is available
1622 // in the global scope.
1623 componentHandler.register({
1624     constructor: MaterialProgress,
1625     classAsString: 'MaterialProgress',
1626     cssClass: 'mdl-js-progress',
1627     widget: true
1628 });
1629 /**
1630  * @license
1631  * Copyright 2015 Google Inc. All Rights Reserved.
1632  *
1633  * Licensed under the Apache License, Version 2.0 (the "License");
1634  * you may not use this file except in compliance with the License.
1635  * You may obtain a copy of the License at
1636  *
1637  *      http://www.apache.org/licenses/LICENSE-2.0
1638  *
1639  * Unless required by applicable law or agreed to in writing, software
1640  * distributed under the License is distributed on an "AS IS" BASIS,
1641  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1642  * See the License for the specific language governing permissions and
1643  * limitations under the License.
1644  */
1645 /**
1646    * Class constructor for Radio MDL component.
1647    * Implements MDL component design pattern defined at:
1648    * https://github.com/jasonmayes/mdl-component-design-pattern
1649    *
1650    * @constructor
1651    * @param {HTMLElement} element The element that will be upgraded.
1652    */
1653 var MaterialRadio = function MaterialRadio(element) {
1654     this.element_ = element;
1655     // Initialize instance.
1656     this.init();
1657 };
1658 window['MaterialRadio'] = MaterialRadio;
1659 /**
1660    * Store constants in one place so they can be updated easily.
1661    *
1662    * @enum {string | number}
1663    * @private
1664    */
1665 MaterialRadio.prototype.Constant_ = { TINY_TIMEOUT: 0.001 };
1666 /**
1667    * Store strings for class names defined by this component that are used in
1668    * JavaScript. This allows us to simply change it in one place should we
1669    * decide to modify at a later date.
1670    *
1671    * @enum {string}
1672    * @private
1673    */
1674 MaterialRadio.prototype.CssClasses_ = {
1675     IS_FOCUSED: 'is-focused',
1676     IS_DISABLED: 'is-disabled',
1677     IS_CHECKED: 'is-checked',
1678     IS_UPGRADED: 'is-upgraded',
1679     JS_RADIO: 'mdl-js-radio',
1680     RADIO_BTN: 'mdl-radio__button',
1681     RADIO_OUTER_CIRCLE: 'mdl-radio__outer-circle',
1682     RADIO_INNER_CIRCLE: 'mdl-radio__inner-circle',
1683     RIPPLE_EFFECT: 'mdl-js-ripple-effect',
1684     RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
1685     RIPPLE_CONTAINER: 'mdl-radio__ripple-container',
1686     RIPPLE_CENTER: 'mdl-ripple--center',
1687     RIPPLE: 'mdl-ripple'
1688 };
1689 /**
1690    * Handle change of state.
1691    *
1692    * @param {Event} event The event that fired.
1693    * @private
1694    */
1695 MaterialRadio.prototype.onChange_ = function (event) {
1696     // Since other radio buttons don't get change events, we need to look for
1697     // them to update their classes.
1698     var radios = document.getElementsByClassName(this.CssClasses_.JS_RADIO);
1699     for (var i = 0; i < radios.length; i++) {
1700         var button = radios[i].querySelector('.' + this.CssClasses_.RADIO_BTN);
1701         // Different name == different group, so no point updating those.
1702         if (button.getAttribute('name') === this.btnElement_.getAttribute('name')) {
1703             if (typeof radios[i]['MaterialRadio'] !== 'undefined') {
1704                 radios[i]['MaterialRadio'].updateClasses_();
1705             }
1706         }
1707     }
1708 };
1709 /**
1710    * Handle focus.
1711    *
1712    * @param {Event} event The event that fired.
1713    * @private
1714    */
1715 MaterialRadio.prototype.onFocus_ = function (event) {
1716     this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
1717 };
1718 /**
1719    * Handle lost focus.
1720    *
1721    * @param {Event} event The event that fired.
1722    * @private
1723    */
1724 MaterialRadio.prototype.onBlur_ = function (event) {
1725     this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
1726 };
1727 /**
1728    * Handle mouseup.
1729    *
1730    * @param {Event} event The event that fired.
1731    * @private
1732    */
1733 MaterialRadio.prototype.onMouseup_ = function (event) {
1734     this.blur_();
1735 };
1736 /**
1737    * Update classes.
1738    *
1739    * @private
1740    */
1741 MaterialRadio.prototype.updateClasses_ = function () {
1742     this.checkDisabled();
1743     this.checkToggleState();
1744 };
1745 /**
1746    * Add blur.
1747    *
1748    * @private
1749    */
1750 MaterialRadio.prototype.blur_ = function () {
1751     // TODO: figure out why there's a focus event being fired after our blur,
1752     // so that we can avoid this hack.
1753     window.setTimeout(function () {
1754         this.btnElement_.blur();
1755     }.bind(this), this.Constant_.TINY_TIMEOUT);
1756 };
1757 // Public methods.
1758 /**
1759    * Check the components disabled state.
1760    *
1761    * @public
1762    */
1763 MaterialRadio.prototype.checkDisabled = function () {
1764     if (this.btnElement_.disabled) {
1765         this.element_.classList.add(this.CssClasses_.IS_DISABLED);
1766     } else {
1767         this.element_.classList.remove(this.CssClasses_.IS_DISABLED);
1768     }
1769 };
1770 MaterialRadio.prototype['checkDisabled'] = MaterialRadio.prototype.checkDisabled;
1771 /**
1772    * Check the components toggled state.
1773    *
1774    * @public
1775    */
1776 MaterialRadio.prototype.checkToggleState = function () {
1777     if (this.btnElement_.checked) {
1778         this.element_.classList.add(this.CssClasses_.IS_CHECKED);
1779     } else {
1780         this.element_.classList.remove(this.CssClasses_.IS_CHECKED);
1781     }
1782 };
1783 MaterialRadio.prototype['checkToggleState'] = MaterialRadio.prototype.checkToggleState;
1784 /**
1785    * Disable radio.
1786    *
1787    * @public
1788    */
1789 MaterialRadio.prototype.disable = function () {
1790     this.btnElement_.disabled = true;
1791     this.updateClasses_();
1792 };
1793 MaterialRadio.prototype['disable'] = MaterialRadio.prototype.disable;
1794 /**
1795    * Enable radio.
1796    *
1797    * @public
1798    */
1799 MaterialRadio.prototype.enable = function () {
1800     this.btnElement_.disabled = false;
1801     this.updateClasses_();
1802 };
1803 MaterialRadio.prototype['enable'] = MaterialRadio.prototype.enable;
1804 /**
1805    * Check radio.
1806    *
1807    * @public
1808    */
1809 MaterialRadio.prototype.check = function () {
1810     this.btnElement_.checked = true;
1811     this.onChange_(null);
1812 };
1813 MaterialRadio.prototype['check'] = MaterialRadio.prototype.check;
1814 /**
1815    * Uncheck radio.
1816    *
1817    * @public
1818    */
1819 MaterialRadio.prototype.uncheck = function () {
1820     this.btnElement_.checked = false;
1821     this.onChange_(null);
1822 };
1823 MaterialRadio.prototype['uncheck'] = MaterialRadio.prototype.uncheck;
1824 /**
1825    * Initialize element.
1826    */
1827 MaterialRadio.prototype.init = function () {
1828     if (this.element_) {
1829         this.btnElement_ = this.element_.querySelector('.' + this.CssClasses_.RADIO_BTN);
1830         this.boundChangeHandler_ = this.onChange_.bind(this);
1831         this.boundFocusHandler_ = this.onChange_.bind(this);
1832         this.boundBlurHandler_ = this.onBlur_.bind(this);
1833         this.boundMouseUpHandler_ = this.onMouseup_.bind(this);
1834         var outerCircle = document.createElement('span');
1835         outerCircle.classList.add(this.CssClasses_.RADIO_OUTER_CIRCLE);
1836         var innerCircle = document.createElement('span');
1837         innerCircle.classList.add(this.CssClasses_.RADIO_INNER_CIRCLE);
1838         this.element_.appendChild(outerCircle);
1839         this.element_.appendChild(innerCircle);
1840         var rippleContainer;
1841         if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) {
1842             this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS);
1843             rippleContainer = document.createElement('span');
1844             rippleContainer.classList.add(this.CssClasses_.RIPPLE_CONTAINER);
1845             rippleContainer.classList.add(this.CssClasses_.RIPPLE_EFFECT);
1846             rippleContainer.classList.add(this.CssClasses_.RIPPLE_CENTER);
1847             rippleContainer.addEventListener('mouseup', this.boundMouseUpHandler_);
1848             var ripple = document.createElement('span');
1849             ripple.classList.add(this.CssClasses_.RIPPLE);
1850             rippleContainer.appendChild(ripple);
1851             this.element_.appendChild(rippleContainer);
1852         }
1853         this.btnElement_.addEventListener('change', this.boundChangeHandler_);
1854         this.btnElement_.addEventListener('focus', this.boundFocusHandler_);
1855         this.btnElement_.addEventListener('blur', this.boundBlurHandler_);
1856         this.element_.addEventListener('mouseup', this.boundMouseUpHandler_);
1857         this.updateClasses_();
1858         this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
1859     }
1860 };
1861 // The component registers itself. It can assume componentHandler is available
1862 // in the global scope.
1863 componentHandler.register({
1864     constructor: MaterialRadio,
1865     classAsString: 'MaterialRadio',
1866     cssClass: 'mdl-js-radio',
1867     widget: true
1868 });
1869 /**
1870  * @license
1871  * Copyright 2015 Google Inc. All Rights Reserved.
1872  *
1873  * Licensed under the Apache License, Version 2.0 (the "License");
1874  * you may not use this file except in compliance with the License.
1875  * You may obtain a copy of the License at
1876  *
1877  *      http://www.apache.org/licenses/LICENSE-2.0
1878  *
1879  * Unless required by applicable law or agreed to in writing, software
1880  * distributed under the License is distributed on an "AS IS" BASIS,
1881  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1882  * See the License for the specific language governing permissions and
1883  * limitations under the License.
1884  */
1885 /**
1886    * Class constructor for Slider MDL component.
1887    * Implements MDL component design pattern defined at:
1888    * https://github.com/jasonmayes/mdl-component-design-pattern
1889    *
1890    * @constructor
1891    * @param {HTMLElement} element The element that will be upgraded.
1892    */
1893 var MaterialSlider = function MaterialSlider(element) {
1894     this.element_ = element;
1895     // Browser feature detection.
1896     this.isIE_ = window.navigator.msPointerEnabled;
1897     // Initialize instance.
1898     this.init();
1899 };
1900 window['MaterialSlider'] = MaterialSlider;
1901 /**
1902    * Store constants in one place so they can be updated easily.
1903    *
1904    * @enum {string | number}
1905    * @private
1906    */
1907 MaterialSlider.prototype.Constant_ = {};
1908 /**
1909    * Store strings for class names defined by this component that are used in
1910    * JavaScript. This allows us to simply change it in one place should we
1911    * decide to modify at a later date.
1912    *
1913    * @enum {string}
1914    * @private
1915    */
1916 MaterialSlider.prototype.CssClasses_ = {
1917     IE_CONTAINER: 'mdl-slider__ie-container',
1918     SLIDER_CONTAINER: 'mdl-slider__container',
1919     BACKGROUND_FLEX: 'mdl-slider__background-flex',
1920     BACKGROUND_LOWER: 'mdl-slider__background-lower',
1921     BACKGROUND_UPPER: 'mdl-slider__background-upper',
1922     IS_LOWEST_VALUE: 'is-lowest-value',
1923     IS_UPGRADED: 'is-upgraded'
1924 };
1925 /**
1926    * Handle input on element.
1927    *
1928    * @param {Event} event The event that fired.
1929    * @private
1930    */
1931 MaterialSlider.prototype.onInput_ = function (event) {
1932     this.updateValueStyles_();
1933 };
1934 /**
1935    * Handle change on element.
1936    *
1937    * @param {Event} event The event that fired.
1938    * @private
1939    */
1940 MaterialSlider.prototype.onChange_ = function (event) {
1941     this.updateValueStyles_();
1942 };
1943 /**
1944    * Handle mouseup on element.
1945    *
1946    * @param {Event} event The event that fired.
1947    * @private
1948    */
1949 MaterialSlider.prototype.onMouseUp_ = function (event) {
1950     event.target.blur();
1951 };
1952 /**
1953    * Handle mousedown on container element.
1954    * This handler is purpose is to not require the use to click
1955    * exactly on the 2px slider element, as FireFox seems to be very
1956    * strict about this.
1957    *
1958    * @param {Event} event The event that fired.
1959    * @private
1960    * @suppress {missingProperties}
1961    */
1962 MaterialSlider.prototype.onContainerMouseDown_ = function (event) {
1963     // If this click is not on the parent element (but rather some child)
1964     // ignore. It may still bubble up.
1965     if (event.target !== this.element_.parentElement) {
1966         return;
1967     }
1968     // Discard the original event and create a new event that
1969     // is on the slider element.
1970     event.preventDefault();
1971     var newEvent = new MouseEvent('mousedown', {
1972         target: event.target,
1973         buttons: event.buttons,
1974         clientX: event.clientX,
1975         clientY: this.element_.getBoundingClientRect().y
1976     });
1977     this.element_.dispatchEvent(newEvent);
1978 };
1979 /**
1980    * Handle updating of values.
1981    *
1982    * @private
1983    */
1984 MaterialSlider.prototype.updateValueStyles_ = function () {
1985     // Calculate and apply percentages to div structure behind slider.
1986     var fraction = (this.element_.value - this.element_.min) / (this.element_.max - this.element_.min);
1987     if (fraction === 0) {
1988         this.element_.classList.add(this.CssClasses_.IS_LOWEST_VALUE);
1989     } else {
1990         this.element_.classList.remove(this.CssClasses_.IS_LOWEST_VALUE);
1991     }
1992     if (!this.isIE_) {
1993         this.backgroundLower_.style.flex = fraction;
1994         this.backgroundLower_.style.webkitFlex = fraction;
1995         this.backgroundUpper_.style.flex = 1 - fraction;
1996         this.backgroundUpper_.style.webkitFlex = 1 - fraction;
1997     }
1998 };
1999 // Public methods.
2000 /**
2001    * Disable slider.
2002    *
2003    * @public
2004    */
2005 MaterialSlider.prototype.disable = function () {
2006     this.element_.disabled = true;
2007 };
2008 MaterialSlider.prototype['disable'] = MaterialSlider.prototype.disable;
2009 /**
2010    * Enable slider.
2011    *
2012    * @public
2013    */
2014 MaterialSlider.prototype.enable = function () {
2015     this.element_.disabled = false;
2016 };
2017 MaterialSlider.prototype['enable'] = MaterialSlider.prototype.enable;
2018 /**
2019    * Update slider value.
2020    *
2021    * @param {number} value The value to which to set the control (optional).
2022    * @public
2023    */
2024 MaterialSlider.prototype.change = function (value) {
2025     if (typeof value !== 'undefined') {
2026         this.element_.value = value;
2027     }
2028     this.updateValueStyles_();
2029 };
2030 MaterialSlider.prototype['change'] = MaterialSlider.prototype.change;
2031 /**
2032    * Initialize element.
2033    */
2034 MaterialSlider.prototype.init = function () {
2035     if (this.element_) {
2036         if (this.isIE_) {
2037             // Since we need to specify a very large height in IE due to
2038             // implementation limitations, we add a parent here that trims it down to
2039             // a reasonable size.
2040             var containerIE = document.createElement('div');
2041             containerIE.classList.add(this.CssClasses_.IE_CONTAINER);
2042             this.element_.parentElement.insertBefore(containerIE, this.element_);
2043             this.element_.parentElement.removeChild(this.element_);
2044             containerIE.appendChild(this.element_);
2045         } else {
2046             // For non-IE browsers, we need a div structure that sits behind the
2047             // slider and allows us to style the left and right sides of it with
2048             // different colors.
2049             var container = document.createElement('div');
2050             container.classList.add(this.CssClasses_.SLIDER_CONTAINER);
2051             this.element_.parentElement.insertBefore(container, this.element_);
2052             this.element_.parentElement.removeChild(this.element_);
2053             container.appendChild(this.element_);
2054             var backgroundFlex = document.createElement('div');
2055             backgroundFlex.classList.add(this.CssClasses_.BACKGROUND_FLEX);
2056             container.appendChild(backgroundFlex);
2057             this.backgroundLower_ = document.createElement('div');
2058             this.backgroundLower_.classList.add(this.CssClasses_.BACKGROUND_LOWER);
2059             backgroundFlex.appendChild(this.backgroundLower_);
2060             this.backgroundUpper_ = document.createElement('div');
2061             this.backgroundUpper_.classList.add(this.CssClasses_.BACKGROUND_UPPER);
2062             backgroundFlex.appendChild(this.backgroundUpper_);
2063         }
2064         this.boundInputHandler = this.onInput_.bind(this);
2065         this.boundChangeHandler = this.onChange_.bind(this);
2066         this.boundMouseUpHandler = this.onMouseUp_.bind(this);
2067         this.boundContainerMouseDownHandler = this.onContainerMouseDown_.bind(this);
2068         this.element_.addEventListener('input', this.boundInputHandler);
2069         this.element_.addEventListener('change', this.boundChangeHandler);
2070         this.element_.addEventListener('mouseup', this.boundMouseUpHandler);
2071         this.element_.parentElement.addEventListener('mousedown', this.boundContainerMouseDownHandler);
2072         this.updateValueStyles_();
2073         this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
2074     }
2075 };
2076 // The component registers itself. It can assume componentHandler is available
2077 // in the global scope.
2078 componentHandler.register({
2079     constructor: MaterialSlider,
2080     classAsString: 'MaterialSlider',
2081     cssClass: 'mdl-js-slider',
2082     widget: true
2083 });
2084 /**
2085  * Copyright 2015 Google Inc. All Rights Reserved.
2086  *
2087  * Licensed under the Apache License, Version 2.0 (the "License");
2088  * you may not use this file except in compliance with the License.
2089  * You may obtain a copy of the License at
2090  *
2091  *      http://www.apache.org/licenses/LICENSE-2.0
2092  *
2093  * Unless required by applicable law or agreed to in writing, software
2094  * distributed under the License is distributed on an "AS IS" BASIS,
2095  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2096  * See the License for the specific language governing permissions and
2097  * limitations under the License.
2098  */
2099 /**
2100    * Class constructor for Snackbar MDL component.
2101    * Implements MDL component design pattern defined at:
2102    * https://github.com/jasonmayes/mdl-component-design-pattern
2103    *
2104    * @constructor
2105    * @param {HTMLElement} element The element that will be upgraded.
2106    */
2107 var MaterialSnackbar = function MaterialSnackbar(element) {
2108     this.element_ = element;
2109     this.textElement_ = this.element_.querySelector('.' + this.cssClasses_.MESSAGE);
2110     this.actionElement_ = this.element_.querySelector('.' + this.cssClasses_.ACTION);
2111     if (!this.textElement_) {
2112         throw new Error('There must be a message element for a snackbar.');
2113     }
2114     if (!this.actionElement_) {
2115         throw new Error('There must be an action element for a snackbar.');
2116     }
2117     this.active = false;
2118     this.actionHandler_ = undefined;
2119     this.message_ = undefined;
2120     this.actionText_ = undefined;
2121     this.queuedNotifications_ = [];
2122     this.setActionHidden_(true);
2123 };
2124 window['MaterialSnackbar'] = MaterialSnackbar;
2125 /**
2126    * Store constants in one place so they can be updated easily.
2127    *
2128    * @enum {string | number}
2129    * @private
2130    */
2131 MaterialSnackbar.prototype.Constant_ = {
2132     // The duration of the snackbar show/hide animation, in ms.
2133     ANIMATION_LENGTH: 250
2134 };
2135 /**
2136    * Store strings for class names defined by this component that are used in
2137    * JavaScript. This allows us to simply change it in one place should we
2138    * decide to modify at a later date.
2139    *
2140    * @enum {string}
2141    * @private
2142    */
2143 MaterialSnackbar.prototype.cssClasses_ = {
2144     SNACKBAR: 'mdl-snackbar',
2145     MESSAGE: 'mdl-snackbar__text',
2146     ACTION: 'mdl-snackbar__action',
2147     ACTIVE: 'mdl-snackbar--active'
2148 };
2149 /**
2150    * Display the snackbar.
2151    *
2152    * @private
2153    */
2154 MaterialSnackbar.prototype.displaySnackbar_ = function () {
2155     this.element_.setAttribute('aria-hidden', 'true');
2156     if (this.actionHandler_) {
2157         this.actionElement_.textContent = this.actionText_;
2158         this.actionElement_.addEventListener('click', this.actionHandler_);
2159         this.setActionHidden_(false);
2160     }
2161     this.textElement_.textContent = this.message_;
2162     this.element_.classList.add(this.cssClasses_.ACTIVE);
2163     this.element_.setAttribute('aria-hidden', 'false');
2164     setTimeout(this.cleanup_.bind(this), this.timeout_);
2165 };
2166 /**
2167    * Show the snackbar.
2168    *
2169    * @param {Object} data The data for the notification.
2170    * @public
2171    */
2172 MaterialSnackbar.prototype.showSnackbar = function (data) {
2173     if (data === undefined) {
2174         throw new Error('Please provide a data object with at least a message to display.');
2175     }
2176     if (data['message'] === undefined) {
2177         throw new Error('Please provide a message to be displayed.');
2178     }
2179     if (data['actionHandler'] && !data['actionText']) {
2180         throw new Error('Please provide action text with the handler.');
2181     }
2182     if (this.active) {
2183         this.queuedNotifications_.push(data);
2184     } else {
2185         this.active = true;
2186         this.message_ = data['message'];
2187         if (data['timeout']) {
2188             this.timeout_ = data['timeout'];
2189         } else {
2190             this.timeout_ = 2750;
2191         }
2192         if (data['actionHandler']) {
2193             this.actionHandler_ = data['actionHandler'];
2194         }
2195         if (data['actionText']) {
2196             this.actionText_ = data['actionText'];
2197         }
2198         this.displaySnackbar_();
2199     }
2200 };
2201 MaterialSnackbar.prototype['showSnackbar'] = MaterialSnackbar.prototype.showSnackbar;
2202 /**
2203    * Check if the queue has items within it.
2204    * If it does, display the next entry.
2205    *
2206    * @private
2207    */
2208 MaterialSnackbar.prototype.checkQueue_ = function () {
2209     if (this.queuedNotifications_.length > 0) {
2210         this.showSnackbar(this.queuedNotifications_.shift());
2211     }
2212 };
2213 /**
2214    * Cleanup the snackbar event listeners and accessiblity attributes.
2215    *
2216    * @private
2217    */
2218 MaterialSnackbar.prototype.cleanup_ = function () {
2219     this.element_.classList.remove(this.cssClasses_.ACTIVE);
2220     setTimeout(function () {
2221         this.element_.setAttribute('aria-hidden', 'true');
2222         this.textElement_.textContent = '';
2223         if (!Boolean(this.actionElement_.getAttribute('aria-hidden'))) {
2224             this.setActionHidden_(true);
2225             this.actionElement_.textContent = '';
2226             this.actionElement_.removeEventListener('click', this.actionHandler_);
2227         }
2228         this.actionHandler_ = undefined;
2229         this.message_ = undefined;
2230         this.actionText_ = undefined;
2231         this.active = false;
2232         this.checkQueue_();
2233     }.bind(this), this.Constant_.ANIMATION_LENGTH);
2234 };
2235 /**
2236    * Set the action handler hidden state.
2237    *
2238    * @param {boolean} value
2239    * @private
2240    */
2241 MaterialSnackbar.prototype.setActionHidden_ = function (value) {
2242     if (value) {
2243         this.actionElement_.setAttribute('aria-hidden', 'true');
2244     } else {
2245         this.actionElement_.removeAttribute('aria-hidden');
2246     }
2247 };
2248 // The component registers itself. It can assume componentHandler is available
2249 // in the global scope.
2250 componentHandler.register({
2251     constructor: MaterialSnackbar,
2252     classAsString: 'MaterialSnackbar',
2253     cssClass: 'mdl-js-snackbar',
2254     widget: true
2255 });
2256 /**
2257  * @license
2258  * Copyright 2015 Google Inc. All Rights Reserved.
2259  *
2260  * Licensed under the Apache License, Version 2.0 (the "License");
2261  * you may not use this file except in compliance with the License.
2262  * You may obtain a copy of the License at
2263  *
2264  *      http://www.apache.org/licenses/LICENSE-2.0
2265  *
2266  * Unless required by applicable law or agreed to in writing, software
2267  * distributed under the License is distributed on an "AS IS" BASIS,
2268  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2269  * See the License for the specific language governing permissions and
2270  * limitations under the License.
2271  */
2272 /**
2273    * Class constructor for Spinner MDL component.
2274    * Implements MDL component design pattern defined at:
2275    * https://github.com/jasonmayes/mdl-component-design-pattern
2276    *
2277    * @param {HTMLElement} element The element that will be upgraded.
2278    * @constructor
2279    */
2280 var MaterialSpinner = function MaterialSpinner(element) {
2281     this.element_ = element;
2282     // Initialize instance.
2283     this.init();
2284 };
2285 window['MaterialSpinner'] = MaterialSpinner;
2286 /**
2287    * Store constants in one place so they can be updated easily.
2288    *
2289    * @enum {string | number}
2290    * @private
2291    */
2292 MaterialSpinner.prototype.Constant_ = { MDL_SPINNER_LAYER_COUNT: 4 };
2293 /**
2294    * Store strings for class names defined by this component that are used in
2295    * JavaScript. This allows us to simply change it in one place should we
2296    * decide to modify at a later date.
2297    *
2298    * @enum {string}
2299    * @private
2300    */
2301 MaterialSpinner.prototype.CssClasses_ = {
2302     MDL_SPINNER_LAYER: 'mdl-spinner__layer',
2303     MDL_SPINNER_CIRCLE_CLIPPER: 'mdl-spinner__circle-clipper',
2304     MDL_SPINNER_CIRCLE: 'mdl-spinner__circle',
2305     MDL_SPINNER_GAP_PATCH: 'mdl-spinner__gap-patch',
2306     MDL_SPINNER_LEFT: 'mdl-spinner__left',
2307     MDL_SPINNER_RIGHT: 'mdl-spinner__right'
2308 };
2309 /**
2310    * Auxiliary method to create a spinner layer.
2311    *
2312    * @param {number} index Index of the layer to be created.
2313    * @public
2314    */
2315 MaterialSpinner.prototype.createLayer = function (index) {
2316     var layer = document.createElement('div');
2317     layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER);
2318     layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER + '-' + index);
2319     var leftClipper = document.createElement('div');
2320     leftClipper.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE_CLIPPER);
2321     leftClipper.classList.add(this.CssClasses_.MDL_SPINNER_LEFT);
2322     var gapPatch = document.createElement('div');
2323     gapPatch.classList.add(this.CssClasses_.MDL_SPINNER_GAP_PATCH);
2324     var rightClipper = document.createElement('div');
2325     rightClipper.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE_CLIPPER);
2326     rightClipper.classList.add(this.CssClasses_.MDL_SPINNER_RIGHT);
2327     var circleOwners = [
2328         leftClipper,
2329         gapPatch,
2330         rightClipper
2331     ];
2332     for (var i = 0; i < circleOwners.length; i++) {
2333         var circle = document.createElement('div');
2334         circle.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE);
2335         circleOwners[i].appendChild(circle);
2336     }
2337     layer.appendChild(leftClipper);
2338     layer.appendChild(gapPatch);
2339     layer.appendChild(rightClipper);
2340     this.element_.appendChild(layer);
2341 };
2342 MaterialSpinner.prototype['createLayer'] = MaterialSpinner.prototype.createLayer;
2343 /**
2344    * Stops the spinner animation.
2345    * Public method for users who need to stop the spinner for any reason.
2346    *
2347    * @public
2348    */
2349 MaterialSpinner.prototype.stop = function () {
2350     this.element_.classList.remove('is-active');
2351 };
2352 MaterialSpinner.prototype['stop'] = MaterialSpinner.prototype.stop;
2353 /**
2354    * Starts the spinner animation.
2355    * Public method for users who need to manually start the spinner for any reason
2356    * (instead of just adding the 'is-active' class to their markup).
2357    *
2358    * @public
2359    */
2360 MaterialSpinner.prototype.start = function () {
2361     this.element_.classList.add('is-active');
2362 };
2363 MaterialSpinner.prototype['start'] = MaterialSpinner.prototype.start;
2364 /**
2365    * Initialize element.
2366    */
2367 MaterialSpinner.prototype.init = function () {
2368     if (this.element_) {
2369         for (var i = 1; i <= this.Constant_.MDL_SPINNER_LAYER_COUNT; i++) {
2370             this.createLayer(i);
2371         }
2372         this.element_.classList.add('is-upgraded');
2373     }
2374 };
2375 // The component registers itself. It can assume componentHandler is available
2376 // in the global scope.
2377 componentHandler.register({
2378     constructor: MaterialSpinner,
2379     classAsString: 'MaterialSpinner',
2380     cssClass: 'mdl-js-spinner',
2381     widget: true
2382 });
2383 /**
2384  * @license
2385  * Copyright 2015 Google Inc. All Rights Reserved.
2386  *
2387  * Licensed under the Apache License, Version 2.0 (the "License");
2388  * you may not use this file except in compliance with the License.
2389  * You may obtain a copy of the License at
2390  *
2391  *      http://www.apache.org/licenses/LICENSE-2.0
2392  *
2393  * Unless required by applicable law or agreed to in writing, software
2394  * distributed under the License is distributed on an "AS IS" BASIS,
2395  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2396  * See the License for the specific language governing permissions and
2397  * limitations under the License.
2398  */
2399 /**
2400    * Class constructor for Checkbox MDL component.
2401    * Implements MDL component design pattern defined at:
2402    * https://github.com/jasonmayes/mdl-component-design-pattern
2403    *
2404    * @constructor
2405    * @param {HTMLElement} element The element that will be upgraded.
2406    */
2407 var MaterialSwitch = function MaterialSwitch(element) {
2408     this.element_ = element;
2409     // Initialize instance.
2410     this.init();
2411 };
2412 window['MaterialSwitch'] = MaterialSwitch;
2413 /**
2414    * Store constants in one place so they can be updated easily.
2415    *
2416    * @enum {string | number}
2417    * @private
2418    */
2419 MaterialSwitch.prototype.Constant_ = { TINY_TIMEOUT: 0.001 };
2420 /**
2421    * Store strings for class names defined by this component that are used in
2422    * JavaScript. This allows us to simply change it in one place should we
2423    * decide to modify at a later date.
2424    *
2425    * @enum {string}
2426    * @private
2427    */
2428 MaterialSwitch.prototype.CssClasses_ = {
2429     INPUT: 'mdl-switch__input',
2430     TRACK: 'mdl-switch__track',
2431     THUMB: 'mdl-switch__thumb',
2432     FOCUS_HELPER: 'mdl-switch__focus-helper',
2433     RIPPLE_EFFECT: 'mdl-js-ripple-effect',
2434     RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
2435     RIPPLE_CONTAINER: 'mdl-switch__ripple-container',
2436     RIPPLE_CENTER: 'mdl-ripple--center',
2437     RIPPLE: 'mdl-ripple',
2438     IS_FOCUSED: 'is-focused',
2439     IS_DISABLED: 'is-disabled',
2440     IS_CHECKED: 'is-checked'
2441 };
2442 /**
2443    * Handle change of state.
2444    *
2445    * @param {Event} event The event that fired.
2446    * @private
2447    */
2448 MaterialSwitch.prototype.onChange_ = function (event) {
2449     this.updateClasses_();
2450 };
2451 /**
2452    * Handle focus of element.
2453    *
2454    * @param {Event} event The event that fired.
2455    * @private
2456    */
2457 MaterialSwitch.prototype.onFocus_ = function (event) {
2458     this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
2459 };
2460 /**
2461    * Handle lost focus of element.
2462    *
2463    * @param {Event} event The event that fired.
2464    * @private
2465    */
2466 MaterialSwitch.prototype.onBlur_ = function (event) {
2467     this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
2468 };
2469 /**
2470    * Handle mouseup.
2471    *
2472    * @param {Event} event The event that fired.
2473    * @private
2474    */
2475 MaterialSwitch.prototype.onMouseUp_ = function (event) {
2476     this.blur_();
2477 };
2478 /**
2479    * Handle class updates.
2480    *
2481    * @private
2482    */
2483 MaterialSwitch.prototype.updateClasses_ = function () {
2484     this.checkDisabled();
2485     this.checkToggleState();
2486 };
2487 /**
2488    * Add blur.
2489    *
2490    * @private
2491    */
2492 MaterialSwitch.prototype.blur_ = function () {
2493     // TODO: figure out why there's a focus event being fired after our blur,
2494     // so that we can avoid this hack.
2495     window.setTimeout(function () {
2496         this.inputElement_.blur();
2497     }.bind(this), this.Constant_.TINY_TIMEOUT);
2498 };
2499 // Public methods.
2500 /**
2501    * Check the components disabled state.
2502    *
2503    * @public
2504    */
2505 MaterialSwitch.prototype.checkDisabled = function () {
2506     if (this.inputElement_.disabled) {
2507         this.element_.classList.add(this.CssClasses_.IS_DISABLED);
2508     } else {
2509         this.element_.classList.remove(this.CssClasses_.IS_DISABLED);
2510     }
2511 };
2512 MaterialSwitch.prototype['checkDisabled'] = MaterialSwitch.prototype.checkDisabled;
2513 /**
2514    * Check the components toggled state.
2515    *
2516    * @public
2517    */
2518 MaterialSwitch.prototype.checkToggleState = function () {
2519     if (this.inputElement_.checked) {
2520         this.element_.classList.add(this.CssClasses_.IS_CHECKED);
2521     } else {
2522         this.element_.classList.remove(this.CssClasses_.IS_CHECKED);
2523     }
2524 };
2525 MaterialSwitch.prototype['checkToggleState'] = MaterialSwitch.prototype.checkToggleState;
2526 /**
2527    * Disable switch.
2528    *
2529    * @public
2530    */
2531 MaterialSwitch.prototype.disable = function () {
2532     this.inputElement_.disabled = true;
2533     this.updateClasses_();
2534 };
2535 MaterialSwitch.prototype['disable'] = MaterialSwitch.prototype.disable;
2536 /**
2537    * Enable switch.
2538    *
2539    * @public
2540    */
2541 MaterialSwitch.prototype.enable = function () {
2542     this.inputElement_.disabled = false;
2543     this.updateClasses_();
2544 };
2545 MaterialSwitch.prototype['enable'] = MaterialSwitch.prototype.enable;
2546 /**
2547    * Activate switch.
2548    *
2549    * @public
2550    */
2551 MaterialSwitch.prototype.on = function () {
2552     this.inputElement_.checked = true;
2553     this.updateClasses_();
2554 };
2555 MaterialSwitch.prototype['on'] = MaterialSwitch.prototype.on;
2556 /**
2557    * Deactivate switch.
2558    *
2559    * @public
2560    */
2561 MaterialSwitch.prototype.off = function () {
2562     this.inputElement_.checked = false;
2563     this.updateClasses_();
2564 };
2565 MaterialSwitch.prototype['off'] = MaterialSwitch.prototype.off;
2566 /**
2567    * Initialize element.
2568    */
2569 MaterialSwitch.prototype.init = function () {
2570     if (this.element_) {
2571         this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT);
2572         var track = document.createElement('div');
2573         track.classList.add(this.CssClasses_.TRACK);
2574         var thumb = document.createElement('div');
2575         thumb.classList.add(this.CssClasses_.THUMB);
2576         var focusHelper = document.createElement('span');
2577         focusHelper.classList.add(this.CssClasses_.FOCUS_HELPER);
2578         thumb.appendChild(focusHelper);
2579         this.element_.appendChild(track);
2580         this.element_.appendChild(thumb);
2581         this.boundMouseUpHandler = this.onMouseUp_.bind(this);
2582         if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) {
2583             this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS);
2584             this.rippleContainerElement_ = document.createElement('span');
2585             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER);
2586             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_EFFECT);
2587             this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER);
2588             this.rippleContainerElement_.addEventListener('mouseup', this.boundMouseUpHandler);
2589             var ripple = document.createElement('span');
2590             ripple.classList.add(this.CssClasses_.RIPPLE);
2591             this.rippleContainerElement_.appendChild(ripple);
2592             this.element_.appendChild(this.rippleContainerElement_);
2593         }
2594         this.boundChangeHandler = this.onChange_.bind(this);
2595         this.boundFocusHandler = this.onFocus_.bind(this);
2596         this.boundBlurHandler = this.onBlur_.bind(this);
2597         this.inputElement_.addEventListener('change', this.boundChangeHandler);
2598         this.inputElement_.addEventListener('focus', this.boundFocusHandler);
2599         this.inputElement_.addEventListener('blur', this.boundBlurHandler);
2600         this.element_.addEventListener('mouseup', this.boundMouseUpHandler);
2601         this.updateClasses_();
2602         this.element_.classList.add('is-upgraded');
2603     }
2604 };
2605 // The component registers itself. It can assume componentHandler is available
2606 // in the global scope.
2607 componentHandler.register({
2608     constructor: MaterialSwitch,
2609     classAsString: 'MaterialSwitch',
2610     cssClass: 'mdl-js-switch',
2611     widget: true
2612 });
2613 /**
2614  * @license
2615  * Copyright 2015 Google Inc. All Rights Reserved.
2616  *
2617  * Licensed under the Apache License, Version 2.0 (the "License");
2618  * you may not use this file except in compliance with the License.
2619  * You may obtain a copy of the License at
2620  *
2621  *      http://www.apache.org/licenses/LICENSE-2.0
2622  *
2623  * Unless required by applicable law or agreed to in writing, software
2624  * distributed under the License is distributed on an "AS IS" BASIS,
2625  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2626  * See the License for the specific language governing permissions and
2627  * limitations under the License.
2628  */
2629 /**
2630    * Class constructor for Tabs MDL component.
2631    * Implements MDL component design pattern defined at:
2632    * https://github.com/jasonmayes/mdl-component-design-pattern
2633    *
2634    * @constructor
2635    * @param {Element} element The element that will be upgraded.
2636    */
2637 var MaterialTabs = function MaterialTabs(element) {
2638     // Stores the HTML element.
2639     this.element_ = element;
2640     // Initialize instance.
2641     this.init();
2642 };
2643 window['MaterialTabs'] = MaterialTabs;
2644 /**
2645    * Store constants in one place so they can be updated easily.
2646    *
2647    * @enum {string}
2648    * @private
2649    */
2650 MaterialTabs.prototype.Constant_ = {};
2651 /**
2652    * Store strings for class names defined by this component that are used in
2653    * JavaScript. This allows us to simply change it in one place should we
2654    * decide to modify at a later date.
2655    *
2656    * @enum {string}
2657    * @private
2658    */
2659 MaterialTabs.prototype.CssClasses_ = {
2660     TAB_CLASS: 'mdl-tabs__tab',
2661     PANEL_CLASS: 'mdl-tabs__panel',
2662     ACTIVE_CLASS: 'is-active',
2663     UPGRADED_CLASS: 'is-upgraded',
2664     MDL_JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect',
2665     MDL_RIPPLE_CONTAINER: 'mdl-tabs__ripple-container',
2666     MDL_RIPPLE: 'mdl-ripple',
2667     MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events'
2668 };
2669 /**
2670    * Handle clicks to a tabs component
2671    *
2672    * @private
2673    */
2674 MaterialTabs.prototype.initTabs_ = function () {
2675     if (this.element_.classList.contains(this.CssClasses_.MDL_JS_RIPPLE_EFFECT)) {
2676         this.element_.classList.add(this.CssClasses_.MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS);
2677     }
2678     // Select element tabs, document panels
2679     this.tabs_ = this.element_.querySelectorAll('.' + this.CssClasses_.TAB_CLASS);
2680     this.panels_ = this.element_.querySelectorAll('.' + this.CssClasses_.PANEL_CLASS);
2681     // Create new tabs for each tab element
2682     for (var i = 0; i < this.tabs_.length; i++) {
2683         new MaterialTab(this.tabs_[i], this);
2684     }
2685     this.element_.classList.add(this.CssClasses_.UPGRADED_CLASS);
2686 };
2687 /**
2688    * Reset tab state, dropping active classes
2689    *
2690    * @private
2691    */
2692 MaterialTabs.prototype.resetTabState_ = function () {
2693     for (var k = 0; k < this.tabs_.length; k++) {
2694         this.tabs_[k].classList.remove(this.CssClasses_.ACTIVE_CLASS);
2695     }
2696 };
2697 /**
2698    * Reset panel state, droping active classes
2699    *
2700    * @private
2701    */
2702 MaterialTabs.prototype.resetPanelState_ = function () {
2703     for (var j = 0; j < this.panels_.length; j++) {
2704         this.panels_[j].classList.remove(this.CssClasses_.ACTIVE_CLASS);
2705     }
2706 };
2707 /**
2708    * Initialize element.
2709    */
2710 MaterialTabs.prototype.init = function () {
2711     if (this.element_) {
2712         this.initTabs_();
2713     }
2714 };
2715 /**
2716    * Constructor for an individual tab.
2717    *
2718    * @constructor
2719    * @param {Element} tab The HTML element for the tab.
2720    * @param {MaterialTabs} ctx The MaterialTabs object that owns the tab.
2721    */
2722 function MaterialTab(tab, ctx) {
2723     if (tab) {
2724         if (ctx.element_.classList.contains(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT)) {
2725             var rippleContainer = document.createElement('span');
2726             rippleContainer.classList.add(ctx.CssClasses_.MDL_RIPPLE_CONTAINER);
2727             rippleContainer.classList.add(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT);
2728             var ripple = document.createElement('span');
2729             ripple.classList.add(ctx.CssClasses_.MDL_RIPPLE);
2730             rippleContainer.appendChild(ripple);
2731             tab.appendChild(rippleContainer);
2732         }
2733         tab.addEventListener('click', function (e) {
2734             if (tab.getAttribute('href').charAt(0) === '#') {
2735                 e.preventDefault();
2736                 var href = tab.href.split('#')[1];
2737                 var panel = ctx.element_.querySelector('#' + href);
2738                 ctx.resetTabState_();
2739                 ctx.resetPanelState_();
2740                 tab.classList.add(ctx.CssClasses_.ACTIVE_CLASS);
2741                 panel.classList.add(ctx.CssClasses_.ACTIVE_CLASS);
2742             }
2743         });
2744     }
2745 }
2746 // The component registers itself. It can assume componentHandler is available
2747 // in the global scope.
2748 componentHandler.register({
2749     constructor: MaterialTabs,
2750     classAsString: 'MaterialTabs',
2751     cssClass: 'mdl-js-tabs'
2752 });
2753 /**
2754  * @license
2755  * Copyright 2015 Google Inc. All Rights Reserved.
2756  *
2757  * Licensed under the Apache License, Version 2.0 (the "License");
2758  * you may not use this file except in compliance with the License.
2759  * You may obtain a copy of the License at
2760  *
2761  *      http://www.apache.org/licenses/LICENSE-2.0
2762  *
2763  * Unless required by applicable law or agreed to in writing, software
2764  * distributed under the License is distributed on an "AS IS" BASIS,
2765  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2766  * See the License for the specific language governing permissions and
2767  * limitations under the License.
2768  */
2769 /**
2770    * Class constructor for Textfield MDL component.
2771    * Implements MDL component design pattern defined at:
2772    * https://github.com/jasonmayes/mdl-component-design-pattern
2773    *
2774    * @constructor
2775    * @param {HTMLElement} element The element that will be upgraded.
2776    */
2777 var MaterialTextfield = function MaterialTextfield(element) {
2778     this.element_ = element;
2779     this.maxRows = this.Constant_.NO_MAX_ROWS;
2780     // Initialize instance.
2781     this.init();
2782 };
2783 window['MaterialTextfield'] = MaterialTextfield;
2784 /**
2785    * Store constants in one place so they can be updated easily.
2786    *
2787    * @enum {string | number}
2788    * @private
2789    */
2790 MaterialTextfield.prototype.Constant_ = {
2791     NO_MAX_ROWS: -1,
2792     MAX_ROWS_ATTRIBUTE: 'maxrows'
2793 };
2794 /**
2795    * Store strings for class names defined by this component that are used in
2796    * JavaScript. This allows us to simply change it in one place should we
2797    * decide to modify at a later date.
2798    *
2799    * @enum {string}
2800    * @private
2801    */
2802 MaterialTextfield.prototype.CssClasses_ = {
2803     LABEL: 'mdl-textfield__label',
2804     INPUT: 'mdl-textfield__input',
2805     IS_DIRTY: 'is-dirty',
2806     IS_FOCUSED: 'is-focused',
2807     IS_DISABLED: 'is-disabled',
2808     IS_INVALID: 'is-invalid',
2809     IS_UPGRADED: 'is-upgraded',
2810     HAS_PLACEHOLDER: 'has-placeholder'
2811 };
2812 /**
2813    * Handle input being entered.
2814    *
2815    * @param {Event} event The event that fired.
2816    * @private
2817    */
2818 MaterialTextfield.prototype.onKeyDown_ = function (event) {
2819     var currentRowCount = event.target.value.split('\n').length;
2820     if (event.keyCode === 13) {
2821         if (currentRowCount >= this.maxRows) {
2822             event.preventDefault();
2823         }
2824     }
2825 };
2826 /**
2827    * Handle focus.
2828    *
2829    * @param {Event} event The event that fired.
2830    * @private
2831    */
2832 MaterialTextfield.prototype.onFocus_ = function (event) {
2833     this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
2834 };
2835 /**
2836    * Handle lost focus.
2837    *
2838    * @param {Event} event The event that fired.
2839    * @private
2840    */
2841 MaterialTextfield.prototype.onBlur_ = function (event) {
2842     this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
2843 };
2844 /**
2845    * Handle reset event from out side.
2846    *
2847    * @param {Event} event The event that fired.
2848    * @private
2849    */
2850 MaterialTextfield.prototype.onReset_ = function (event) {
2851     this.updateClasses_();
2852 };
2853 /**
2854    * Handle class updates.
2855    *
2856    * @private
2857    */
2858 MaterialTextfield.prototype.updateClasses_ = function () {
2859     this.checkDisabled();
2860     this.checkValidity();
2861     this.checkDirty();
2862     this.checkFocus();
2863 };
2864 // Public methods.
2865 /**
2866    * Check the disabled state and update field accordingly.
2867    *
2868    * @public
2869    */
2870 MaterialTextfield.prototype.checkDisabled = function () {
2871     if (this.input_.disabled) {
2872         this.element_.classList.add(this.CssClasses_.IS_DISABLED);
2873     } else {
2874         this.element_.classList.remove(this.CssClasses_.IS_DISABLED);
2875     }
2876 };
2877 MaterialTextfield.prototype['checkDisabled'] = MaterialTextfield.prototype.checkDisabled;
2878 /**
2879   * Check the focus state and update field accordingly.
2880   *
2881   * @public
2882   */
2883 MaterialTextfield.prototype.checkFocus = function () {
2884     if (Boolean(this.element_.querySelector(':focus'))) {
2885         this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
2886     } else {
2887         this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
2888     }
2889 };
2890 MaterialTextfield.prototype['checkFocus'] = MaterialTextfield.prototype.checkFocus;
2891 /**
2892    * Check the validity state and update field accordingly.
2893    *
2894    * @public
2895    */
2896 MaterialTextfield.prototype.checkValidity = function () {
2897     if (this.input_.validity) {
2898         if (this.input_.validity.valid) {
2899             this.element_.classList.remove(this.CssClasses_.IS_INVALID);
2900         } else {
2901             this.element_.classList.add(this.CssClasses_.IS_INVALID);
2902         }
2903     }
2904 };
2905 MaterialTextfield.prototype['checkValidity'] = MaterialTextfield.prototype.checkValidity;
2906 /**
2907    * Check the dirty state and update field accordingly.
2908    *
2909    * @public
2910    */
2911 MaterialTextfield.prototype.checkDirty = function () {
2912     if (this.input_.value && this.input_.value.length > 0) {
2913         this.element_.classList.add(this.CssClasses_.IS_DIRTY);
2914     } else {
2915         this.element_.classList.remove(this.CssClasses_.IS_DIRTY);
2916     }
2917 };
2918 MaterialTextfield.prototype['checkDirty'] = MaterialTextfield.prototype.checkDirty;
2919 /**
2920    * Disable text field.
2921    *
2922    * @public
2923    */
2924 MaterialTextfield.prototype.disable = function () {
2925     this.input_.disabled = true;
2926     this.updateClasses_();
2927 };
2928 MaterialTextfield.prototype['disable'] = MaterialTextfield.prototype.disable;
2929 /**
2930    * Enable text field.
2931    *
2932    * @public
2933    */
2934 MaterialTextfield.prototype.enable = function () {
2935     this.input_.disabled = false;
2936     this.updateClasses_();
2937 };
2938 MaterialTextfield.prototype['enable'] = MaterialTextfield.prototype.enable;
2939 /**
2940    * Update text field value.
2941    *
2942    * @param {string} value The value to which to set the control (optional).
2943    * @public
2944    */
2945 MaterialTextfield.prototype.change = function (value) {
2946     this.input_.value = value || '';
2947     this.updateClasses_();
2948 };
2949 MaterialTextfield.prototype['change'] = MaterialTextfield.prototype.change;
2950 /**
2951    * Initialize element.
2952    */
2953 MaterialTextfield.prototype.init = function () {
2954     if (this.element_) {
2955         this.label_ = this.element_.querySelector('.' + this.CssClasses_.LABEL);
2956         this.input_ = this.element_.querySelector('.' + this.CssClasses_.INPUT);
2957         if (this.input_) {
2958             if (this.input_.hasAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE)) {
2959                 this.maxRows = parseInt(this.input_.getAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE), 10);
2960                 if (isNaN(this.maxRows)) {
2961                     this.maxRows = this.Constant_.NO_MAX_ROWS;
2962                 }
2963             }
2964             if (this.input_.hasAttribute('placeholder')) {
2965                 this.element_.classList.add(this.CssClasses_.HAS_PLACEHOLDER);
2966             }
2967             this.boundUpdateClassesHandler = this.updateClasses_.bind(this);
2968             this.boundFocusHandler = this.onFocus_.bind(this);
2969             this.boundBlurHandler = this.onBlur_.bind(this);
2970             this.boundResetHandler = this.onReset_.bind(this);
2971             this.input_.addEventListener('input', this.boundUpdateClassesHandler);
2972             this.input_.addEventListener('focus', this.boundFocusHandler);
2973             this.input_.addEventListener('blur', this.boundBlurHandler);
2974             this.input_.addEventListener('reset', this.boundResetHandler);
2975             if (this.maxRows !== this.Constant_.NO_MAX_ROWS) {
2976                 // TODO: This should handle pasting multi line text.
2977                 // Currently doesn't.
2978                 this.boundKeyDownHandler = this.onKeyDown_.bind(this);
2979                 this.input_.addEventListener('keydown', this.boundKeyDownHandler);
2980             }
2981             var invalid = this.element_.classList.contains(this.CssClasses_.IS_INVALID);
2982             this.updateClasses_();
2983             this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
2984             if (invalid) {
2985                 this.element_.classList.add(this.CssClasses_.IS_INVALID);
2986             }
2987             if (this.input_.hasAttribute('autofocus')) {
2988                 this.element_.focus();
2989                 this.checkFocus();
2990             }
2991         }
2992     }
2993 };
2994 // The component registers itself. It can assume componentHandler is available
2995 // in the global scope.
2996 componentHandler.register({
2997     constructor: MaterialTextfield,
2998     classAsString: 'MaterialTextfield',
2999     cssClass: 'mdl-js-textfield',
3000     widget: true
3001 });
3002 /**
3003  * @license
3004  * Copyright 2015 Google Inc. All Rights Reserved.
3005  *
3006  * Licensed under the Apache License, Version 2.0 (the "License");
3007  * you may not use this file except in compliance with the License.
3008  * You may obtain a copy of the License at
3009  *
3010  *      http://www.apache.org/licenses/LICENSE-2.0
3011  *
3012  * Unless required by applicable law or agreed to in writing, software
3013  * distributed under the License is distributed on an "AS IS" BASIS,
3014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3015  * See the License for the specific language governing permissions and
3016  * limitations under the License.
3017  */
3018 /**
3019    * Class constructor for Tooltip MDL component.
3020    * Implements MDL component design pattern defined at:
3021    * https://github.com/jasonmayes/mdl-component-design-pattern
3022    *
3023    * @constructor
3024    * @param {HTMLElement} element The element that will be upgraded.
3025    */
3026 var MaterialTooltip = function MaterialTooltip(element) {
3027     this.element_ = element;
3028     // Initialize instance.
3029     this.init();
3030 };
3031 window['MaterialTooltip'] = MaterialTooltip;
3032 /**
3033    * Store constants in one place so they can be updated easily.
3034    *
3035    * @enum {string | number}
3036    * @private
3037    */
3038 MaterialTooltip.prototype.Constant_ = {};
3039 /**
3040    * Store strings for class names defined by this component that are used in
3041    * JavaScript. This allows us to simply change it in one place should we
3042    * decide to modify at a later date.
3043    *
3044    * @enum {string}
3045    * @private
3046    */
3047 MaterialTooltip.prototype.CssClasses_ = {
3048     IS_ACTIVE: 'is-active',
3049     BOTTOM: 'mdl-tooltip--bottom',
3050     LEFT: 'mdl-tooltip--left',
3051     RIGHT: 'mdl-tooltip--right',
3052     TOP: 'mdl-tooltip--top'
3053 };
3054 /**
3055    * Handle mouseenter for tooltip.
3056    *
3057    * @param {Event} event The event that fired.
3058    * @private
3059    */
3060 MaterialTooltip.prototype.handleMouseEnter_ = function (event) {
3061     var props = event.target.getBoundingClientRect();
3062     var left = props.left + props.width / 2;
3063     var top = props.top + props.height / 2;
3064     var marginLeft = -1 * (this.element_.offsetWidth / 2);
3065     var marginTop = -1 * (this.element_.offsetHeight / 2);
3066     if (this.element_.classList.contains(this.CssClasses_.LEFT) || this.element_.classList.contains(this.CssClasses_.RIGHT)) {
3067         left = props.width / 2;
3068         if (top + marginTop < 0) {
3069             this.element_.style.top = '0';
3070             this.element_.style.marginTop = '0';
3071         } else {
3072             this.element_.style.top = top + 'px';
3073             this.element_.style.marginTop = marginTop + 'px';
3074         }
3075     } else {
3076         if (left + marginLeft < 0) {
3077             this.element_.style.left = '0';
3078             this.element_.style.marginLeft = '0';
3079         } else {
3080             this.element_.style.left = left + 'px';
3081             this.element_.style.marginLeft = marginLeft + 'px';
3082         }
3083     }
3084     if (this.element_.classList.contains(this.CssClasses_.TOP)) {
3085         this.element_.style.top = props.top - this.element_.offsetHeight - 10 + 'px';
3086     } else if (this.element_.classList.contains(this.CssClasses_.RIGHT)) {
3087         this.element_.style.left = props.left + props.width + 10 + 'px';
3088     } else if (this.element_.classList.contains(this.CssClasses_.LEFT)) {
3089         this.element_.style.left = props.left - this.element_.offsetWidth - 10 + 'px';
3090     } else {
3091         this.element_.style.top = props.top + props.height + 10 + 'px';
3092     }
3093     this.element_.classList.add(this.CssClasses_.IS_ACTIVE);
3094 };
3095 /**
3096    * Hide tooltip on mouseleave or scroll
3097    *
3098    * @private
3099    */
3100 MaterialTooltip.prototype.hideTooltip_ = function () {
3101     this.element_.classList.remove(this.CssClasses_.IS_ACTIVE);
3102 };
3103 /**
3104    * Initialize element.
3105    */
3106 MaterialTooltip.prototype.init = function () {
3107     if (this.element_) {
3108         var forElId = this.element_.getAttribute('for') || this.element_.getAttribute('data-mdl-for');
3109         if (forElId) {
3110             this.forElement_ = document.getElementById(forElId);
3111         }
3112         if (this.forElement_) {
3113             // It's left here because it prevents accidental text selection on Android
3114             if (!this.forElement_.hasAttribute('tabindex')) {
3115                 this.forElement_.setAttribute('tabindex', '0');
3116             }
3117             this.boundMouseEnterHandler = this.handleMouseEnter_.bind(this);
3118             this.boundMouseLeaveAndScrollHandler = this.hideTooltip_.bind(this);
3119             this.forElement_.addEventListener('mouseenter', this.boundMouseEnterHandler, false);
3120             this.forElement_.addEventListener('touchend', this.boundMouseEnterHandler, false);
3121             this.forElement_.addEventListener('mouseleave', this.boundMouseLeaveAndScrollHandler, false);
3122             window.addEventListener('scroll', this.boundMouseLeaveAndScrollHandler, true);
3123             window.addEventListener('touchstart', this.boundMouseLeaveAndScrollHandler);
3124         }
3125     }
3126 };
3127 // The component registers itself. It can assume componentHandler is available
3128 // in the global scope.
3129 componentHandler.register({
3130     constructor: MaterialTooltip,
3131     classAsString: 'MaterialTooltip',
3132     cssClass: 'mdl-tooltip'
3133 });
3134 /**
3135  * @license
3136  * Copyright 2015 Google Inc. All Rights Reserved.
3137  *
3138  * Licensed under the Apache License, Version 2.0 (the "License");
3139  * you may not use this file except in compliance with the License.
3140  * You may obtain a copy of the License at
3141  *
3142  *      http://www.apache.org/licenses/LICENSE-2.0
3143  *
3144  * Unless required by applicable law or agreed to in writing, software
3145  * distributed under the License is distributed on an "AS IS" BASIS,
3146  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3147  * See the License for the specific language governing permissions and
3148  * limitations under the License.
3149  */
3150 /**
3151    * Class constructor for Layout MDL component.
3152    * Implements MDL component design pattern defined at:
3153    * https://github.com/jasonmayes/mdl-component-design-pattern
3154    *
3155    * @constructor
3156    * @param {HTMLElement} element The element that will be upgraded.
3157    */
3158 var MaterialLayout = function MaterialLayout(element) {
3159     this.element_ = element;
3160     // Initialize instance.
3161     this.init();
3162 };
3163 window['MaterialLayout'] = MaterialLayout;
3164 /**
3165    * Store constants in one place so they can be updated easily.
3166    *
3167    * @enum {string | number}
3168    * @private
3169    */
3170 MaterialLayout.prototype.Constant_ = {
3171     MAX_WIDTH: '(max-width: 1024px)',
3172     TAB_SCROLL_PIXELS: 100,
3173     RESIZE_TIMEOUT: 100,
3174     MENU_ICON: '&#xE5D2;',
3175     CHEVRON_LEFT: 'chevron_left',
3176     CHEVRON_RIGHT: 'chevron_right'
3177 };
3178 /**
3179    * Keycodes, for code readability.
3180    *
3181    * @enum {number}
3182    * @private
3183    */
3184 MaterialLayout.prototype.Keycodes_ = {
3185     ENTER: 13,
3186     ESCAPE: 27,
3187     SPACE: 32
3188 };
3189 /**
3190    * Modes.
3191    *
3192    * @enum {number}
3193    * @private
3194    */
3195 MaterialLayout.prototype.Mode_ = {
3196     STANDARD: 0,
3197     SEAMED: 1,
3198     WATERFALL: 2,
3199     SCROLL: 3
3200 };
3201 /**
3202    * Store strings for class names defined by this component that are used in
3203    * JavaScript. This allows us to simply change it in one place should we
3204    * decide to modify at a later date.
3205    *
3206    * @enum {string}
3207    * @private
3208    */
3209 MaterialLayout.prototype.CssClasses_ = {
3210     CONTAINER: 'mdl-layout__container',
3211     HEADER: 'mdl-layout__header',
3212     DRAWER: 'mdl-layout__drawer',
3213     CONTENT: 'mdl-layout__content',
3214     DRAWER_BTN: 'mdl-layout__drawer-button',
3215     ICON: 'material-icons',
3216     JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect',
3217     RIPPLE_CONTAINER: 'mdl-layout__tab-ripple-container',
3218     RIPPLE: 'mdl-ripple',
3219     RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
3220     HEADER_SEAMED: 'mdl-layout__header--seamed',
3221     HEADER_WATERFALL: 'mdl-layout__header--waterfall',
3222     HEADER_SCROLL: 'mdl-layout__header--scroll',
3223     FIXED_HEADER: 'mdl-layout--fixed-header',
3224     OBFUSCATOR: 'mdl-layout__obfuscator',
3225     TAB_BAR: 'mdl-layout__tab-bar',
3226     TAB_CONTAINER: 'mdl-layout__tab-bar-container',
3227     TAB: 'mdl-layout__tab',
3228     TAB_BAR_BUTTON: 'mdl-layout__tab-bar-button',
3229     TAB_BAR_LEFT_BUTTON: 'mdl-layout__tab-bar-left-button',
3230     TAB_BAR_RIGHT_BUTTON: 'mdl-layout__tab-bar-right-button',
3231     TAB_MANUAL_SWITCH: 'mdl-layout__tab-manual-switch',
3232     PANEL: 'mdl-layout__tab-panel',
3233     HAS_DRAWER: 'has-drawer',
3234     HAS_TABS: 'has-tabs',
3235     HAS_SCROLLING_HEADER: 'has-scrolling-header',
3236     CASTING_SHADOW: 'is-casting-shadow',
3237     IS_COMPACT: 'is-compact',
3238     IS_SMALL_SCREEN: 'is-small-screen',
3239     IS_DRAWER_OPEN: 'is-visible',
3240     IS_ACTIVE: 'is-active',
3241     IS_UPGRADED: 'is-upgraded',
3242     IS_ANIMATING: 'is-animating',
3243     ON_LARGE_SCREEN: 'mdl-layout--large-screen-only',
3244     ON_SMALL_SCREEN: 'mdl-layout--small-screen-only'
3245 };
3246 /**
3247    * Handles scrolling on the content.
3248    *
3249    * @private
3250    */
3251 MaterialLayout.prototype.contentScrollHandler_ = function () {
3252     if (this.header_.classList.contains(this.CssClasses_.IS_ANIMATING)) {
3253         return;
3254     }
3255     var headerVisible = !this.element_.classList.contains(this.CssClasses_.IS_SMALL_SCREEN) || this.element_.classList.contains(this.CssClasses_.FIXED_HEADER);
3256     if (this.content_.scrollTop > 0 && !this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) {
3257         this.header_.classList.add(this.CssClasses_.CASTING_SHADOW);
3258         this.header_.classList.add(this.CssClasses_.IS_COMPACT);
3259         if (headerVisible) {
3260             this.header_.classList.add(this.CssClasses_.IS_ANIMATING);
3261         }
3262     } else if (this.content_.scrollTop <= 0 && this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) {
3263         this.header_.classList.remove(this.CssClasses_.CASTING_SHADOW);
3264         this.header_.classList.remove(this.CssClasses_.IS_COMPACT);
3265         if (headerVisible) {
3266             this.header_.classList.add(this.CssClasses_.IS_ANIMATING);
3267         }
3268     }
3269 };
3270 /**
3271    * Handles a keyboard event on the drawer.
3272    *
3273    * @param {Event} evt The event that fired.
3274    * @private
3275    */
3276 MaterialLayout.prototype.keyboardEventHandler_ = function (evt) {
3277     // Only react when the drawer is open.
3278     if (evt.keyCode === this.Keycodes_.ESCAPE && this.drawer_.classList.contains(this.CssClasses_.IS_DRAWER_OPEN)) {
3279         this.toggleDrawer();
3280     }
3281 };
3282 /**
3283    * Handles changes in screen size.
3284    *
3285    * @private
3286    */
3287 MaterialLayout.prototype.screenSizeHandler_ = function () {
3288     if (this.screenSizeMediaQuery_.matches) {
3289         this.element_.classList.add(this.CssClasses_.IS_SMALL_SCREEN);
3290     } else {
3291         this.element_.classList.remove(this.CssClasses_.IS_SMALL_SCREEN);
3292         // Collapse drawer (if any) when moving to a large screen size.
3293         if (this.drawer_) {
3294             this.drawer_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN);
3295             this.obfuscator_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN);
3296         }
3297     }
3298 };
3299 /**
3300    * Handles events of drawer button.
3301    *
3302    * @param {Event} evt The event that fired.
3303    * @private
3304    */
3305 MaterialLayout.prototype.drawerToggleHandler_ = function (evt) {
3306     if (evt && evt.type === 'keydown') {
3307         if (evt.keyCode === this.Keycodes_.SPACE || evt.keyCode === this.Keycodes_.ENTER) {
3308             // prevent scrolling in drawer nav
3309             evt.preventDefault();
3310         } else {
3311             // prevent other keys
3312             return;
3313         }
3314     }
3315     this.toggleDrawer();
3316 };
3317 /**
3318    * Handles (un)setting the `is-animating` class
3319    *
3320    * @private
3321    */
3322 MaterialLayout.prototype.headerTransitionEndHandler_ = function () {
3323     this.header_.classList.remove(this.CssClasses_.IS_ANIMATING);
3324 };
3325 /**
3326    * Handles expanding the header on click
3327    *
3328    * @private
3329    */
3330 MaterialLayout.prototype.headerClickHandler_ = function () {
3331     if (this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) {
3332         this.header_.classList.remove(this.CssClasses_.IS_COMPACT);
3333         this.header_.classList.add(this.CssClasses_.IS_ANIMATING);
3334     }
3335 };
3336 /**
3337    * Reset tab state, dropping active classes
3338    *
3339    * @private
3340    */
3341 MaterialLayout.prototype.resetTabState_ = function (tabBar) {
3342     for (var k = 0; k < tabBar.length; k++) {
3343         tabBar[k].classList.remove(this.CssClasses_.IS_ACTIVE);
3344     }
3345 };
3346 /**
3347    * Reset panel state, droping active classes
3348    *
3349    * @private
3350    */
3351 MaterialLayout.prototype.resetPanelState_ = function (panels) {
3352     for (var j = 0; j < panels.length; j++) {
3353         panels[j].classList.remove(this.CssClasses_.IS_ACTIVE);
3354     }
3355 };
3356 /**
3357   * Toggle drawer state
3358   *
3359   * @public
3360   */
3361 MaterialLayout.prototype.toggleDrawer = function () {
3362     var drawerButton = this.element_.querySelector('.' + this.CssClasses_.DRAWER_BTN);
3363     this.drawer_.classList.toggle(this.CssClasses_.IS_DRAWER_OPEN);
3364     this.obfuscator_.classList.toggle(this.CssClasses_.IS_DRAWER_OPEN);
3365     // Set accessibility properties.
3366     if (this.drawer_.classList.contains(this.CssClasses_.IS_DRAWER_OPEN)) {
3367         this.drawer_.setAttribute('aria-hidden', 'false');
3368         drawerButton.setAttribute('aria-expanded', 'true');
3369     } else {
3370         this.drawer_.setAttribute('aria-hidden', 'true');
3371         drawerButton.setAttribute('aria-expanded', 'false');
3372     }
3373 };
3374 MaterialLayout.prototype['toggleDrawer'] = MaterialLayout.prototype.toggleDrawer;
3375 /**
3376    * Initialize element.
3377    */
3378 MaterialLayout.prototype.init = function () {
3379     if (this.element_) {
3380         var container = document.createElement('div');
3381         container.classList.add(this.CssClasses_.CONTAINER);
3382         var focusedElement = this.element_.querySelector(':focus');
3383         this.element_.parentElement.insertBefore(container, this.element_);
3384         this.element_.parentElement.removeChild(this.element_);
3385         container.appendChild(this.element_);
3386         if (focusedElement) {
3387             focusedElement.focus();
3388         }
3389         var directChildren = this.element_.childNodes;
3390         var numChildren = directChildren.length;
3391         for (var c = 0; c < numChildren; c++) {
3392             var child = directChildren[c];
3393             if (child.classList && child.classList.contains(this.CssClasses_.HEADER)) {
3394                 this.header_ = child;
3395             }
3396             if (child.classList && child.classList.contains(this.CssClasses_.DRAWER)) {
3397                 this.drawer_ = child;
3398             }
3399             if (child.classList && child.classList.contains(this.CssClasses_.CONTENT)) {
3400                 this.content_ = child;
3401             }
3402         }
3403         window.addEventListener('pageshow', function (e) {
3404             if (e.persisted) {
3405                 // when page is loaded from back/forward cache
3406                 // trigger repaint to let layout scroll in safari
3407                 this.element_.style.overflowY = 'hidden';
3408                 requestAnimationFrame(function () {
3409                     this.element_.style.overflowY = '';
3410                 }.bind(this));
3411             }
3412         }.bind(this), false);
3413         if (this.header_) {
3414             this.tabBar_ = this.header_.querySelector('.' + this.CssClasses_.TAB_BAR);
3415         }
3416         var mode = this.Mode_.STANDARD;
3417         if (this.header_) {
3418             if (this.header_.classList.contains(this.CssClasses_.HEADER_SEAMED)) {
3419                 mode = this.Mode_.SEAMED;
3420             } else if (this.header_.classList.contains(this.CssClasses_.HEADER_WATERFALL)) {
3421                 mode = this.Mode_.WATERFALL;
3422                 this.header_.addEventListener('transitionend', this.headerTransitionEndHandler_.bind(this));
3423                 this.header_.addEventListener('click', this.headerClickHandler_.bind(this));
3424             } else if (this.header_.classList.contains(this.CssClasses_.HEADER_SCROLL)) {
3425                 mode = this.Mode_.SCROLL;
3426                 container.classList.add(this.CssClasses_.HAS_SCROLLING_HEADER);
3427             }
3428             if (mode === this.Mode_.STANDARD) {
3429                 this.header_.classList.add(this.CssClasses_.CASTING_SHADOW);
3430                 if (this.tabBar_) {
3431                     this.tabBar_.classList.add(this.CssClasses_.CASTING_SHADOW);
3432                 }
3433             } else if (mode === this.Mode_.SEAMED || mode === this.Mode_.SCROLL) {
3434                 this.header_.classList.remove(this.CssClasses_.CASTING_SHADOW);
3435                 if (this.tabBar_) {
3436                     this.tabBar_.classList.remove(this.CssClasses_.CASTING_SHADOW);
3437                 }
3438             } else if (mode === this.Mode_.WATERFALL) {
3439                 // Add and remove shadows depending on scroll position.
3440                 // Also add/remove auxiliary class for styling of the compact version of
3441                 // the header.
3442                 this.content_.addEventListener('scroll', this.contentScrollHandler_.bind(this));
3443                 this.contentScrollHandler_();
3444             }
3445         }
3446         // Add drawer toggling button to our layout, if we have an openable drawer.
3447         if (this.drawer_) {
3448             var drawerButton = this.element_.querySelector('.' + this.CssClasses_.DRAWER_BTN);
3449             if (!drawerButton) {
3450                 drawerButton = document.createElement('div');
3451                 drawerButton.setAttribute('aria-expanded', 'false');
3452                 drawerButton.setAttribute('role', 'button');
3453                 drawerButton.setAttribute('tabindex', '0');
3454                 drawerButton.classList.add(this.CssClasses_.DRAWER_BTN);
3455                 var drawerButtonIcon = document.createElement('i');
3456                 drawerButtonIcon.classList.add(this.CssClasses_.ICON);
3457                 drawerButtonIcon.innerHTML = this.Constant_.MENU_ICON;
3458                 drawerButton.appendChild(drawerButtonIcon);
3459             }
3460             if (this.drawer_.classList.contains(this.CssClasses_.ON_LARGE_SCREEN)) {
3461                 //If drawer has ON_LARGE_SCREEN class then add it to the drawer toggle button as well.
3462                 drawerButton.classList.add(this.CssClasses_.ON_LARGE_SCREEN);
3463             } else if (this.drawer_.classList.contains(this.CssClasses_.ON_SMALL_SCREEN)) {
3464                 //If drawer has ON_SMALL_SCREEN class then add it to the drawer toggle button as well.
3465                 drawerButton.classList.add(this.CssClasses_.ON_SMALL_SCREEN);
3466             }
3467             drawerButton.addEventListener('click', this.drawerToggleHandler_.bind(this));
3468             drawerButton.addEventListener('keydown', this.drawerToggleHandler_.bind(this));
3469             // Add a class if the layout has a drawer, for altering the left padding.
3470             // Adds the HAS_DRAWER to the elements since this.header_ may or may
3471             // not be present.
3472             this.element_.classList.add(this.CssClasses_.HAS_DRAWER);
3473             // If we have a fixed header, add the button to the header rather than
3474             // the layout.
3475             if (this.element_.classList.contains(this.CssClasses_.FIXED_HEADER)) {
3476                 this.header_.insertBefore(drawerButton, this.header_.firstChild);
3477             } else {
3478                 this.element_.insertBefore(drawerButton, this.content_);
3479             }
3480             var obfuscator = document.createElement('div');
3481             obfuscator.classList.add(this.CssClasses_.OBFUSCATOR);
3482             this.element_.appendChild(obfuscator);
3483             obfuscator.addEventListener('click', this.drawerToggleHandler_.bind(this));
3484             this.obfuscator_ = obfuscator;
3485             this.drawer_.addEventListener('keydown', this.keyboardEventHandler_.bind(this));
3486             this.drawer_.setAttribute('aria-hidden', 'true');
3487         }
3488         // Keep an eye on screen size, and add/remove auxiliary class for styling
3489         // of small screens.
3490         this.screenSizeMediaQuery_ = window.matchMedia(this.Constant_.MAX_WIDTH);
3491         this.screenSizeMediaQuery_.addListener(this.screenSizeHandler_.bind(this));
3492         this.screenSizeHandler_();
3493         // Initialize tabs, if any.
3494         if (this.header_ && this.tabBar_) {
3495             this.element_.classList.add(this.CssClasses_.HAS_TABS);
3496             var tabContainer = document.createElement('div');
3497             tabContainer.classList.add(this.CssClasses_.TAB_CONTAINER);
3498             this.header_.insertBefore(tabContainer, this.tabBar_);
3499             this.header_.removeChild(this.tabBar_);
3500             var leftButton = document.createElement('div');
3501             leftButton.classList.add(this.CssClasses_.TAB_BAR_BUTTON);
3502             leftButton.classList.add(this.CssClasses_.TAB_BAR_LEFT_BUTTON);
3503             var leftButtonIcon = document.createElement('i');
3504             leftButtonIcon.classList.add(this.CssClasses_.ICON);
3505             leftButtonIcon.textContent = this.Constant_.CHEVRON_LEFT;
3506             leftButton.appendChild(leftButtonIcon);
3507             leftButton.addEventListener('click', function () {
3508                 this.tabBar_.scrollLeft -= this.Constant_.TAB_SCROLL_PIXELS;
3509             }.bind(this));
3510             var rightButton = document.createElement('div');
3511             rightButton.classList.add(this.CssClasses_.TAB_BAR_BUTTON);
3512             rightButton.classList.add(this.CssClasses_.TAB_BAR_RIGHT_BUTTON);
3513             var rightButtonIcon = document.createElement('i');
3514             rightButtonIcon.classList.add(this.CssClasses_.ICON);
3515             rightButtonIcon.textContent = this.Constant_.CHEVRON_RIGHT;
3516             rightButton.appendChild(rightButtonIcon);
3517             rightButton.addEventListener('click', function () {
3518                 this.tabBar_.scrollLeft += this.Constant_.TAB_SCROLL_PIXELS;
3519             }.bind(this));
3520             tabContainer.appendChild(leftButton);
3521             tabContainer.appendChild(this.tabBar_);
3522             tabContainer.appendChild(rightButton);
3523             // Add and remove tab buttons depending on scroll position and total
3524             // window size.
3525             var tabUpdateHandler = function () {
3526                 if (this.tabBar_.scrollLeft > 0) {
3527                     leftButton.classList.add(this.CssClasses_.IS_ACTIVE);
3528                 } else {
3529                     leftButton.classList.remove(this.CssClasses_.IS_ACTIVE);
3530                 }
3531                 if (this.tabBar_.scrollLeft < this.tabBar_.scrollWidth - this.tabBar_.offsetWidth) {
3532                     rightButton.classList.add(this.CssClasses_.IS_ACTIVE);
3533                 } else {
3534                     rightButton.classList.remove(this.CssClasses_.IS_ACTIVE);
3535                 }
3536             }.bind(this);
3537             this.tabBar_.addEventListener('scroll', tabUpdateHandler);
3538             tabUpdateHandler();
3539             // Update tabs when the window resizes.
3540             var windowResizeHandler = function () {
3541                 // Use timeouts to make sure it doesn't happen too often.
3542                 if (this.resizeTimeoutId_) {
3543                     clearTimeout(this.resizeTimeoutId_);
3544                 }
3545                 this.resizeTimeoutId_ = setTimeout(function () {
3546                     tabUpdateHandler();
3547                     this.resizeTimeoutId_ = null;
3548                 }.bind(this), this.Constant_.RESIZE_TIMEOUT);
3549             }.bind(this);
3550             window.addEventListener('resize', windowResizeHandler);
3551             if (this.tabBar_.classList.contains(this.CssClasses_.JS_RIPPLE_EFFECT)) {
3552                 this.tabBar_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS);
3553             }
3554             // Select element tabs, document panels
3555             var tabs = this.tabBar_.querySelectorAll('.' + this.CssClasses_.TAB);
3556             var panels = this.content_.querySelectorAll('.' + this.CssClasses_.PANEL);
3557             // Create new tabs for each tab element
3558             for (var i = 0; i < tabs.length; i++) {
3559                 new MaterialLayoutTab(tabs[i], tabs, panels, this);
3560             }
3561         }
3562         this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
3563     }
3564 };
3565 /**
3566    * Constructor for an individual tab.
3567    *
3568    * @constructor
3569    * @param {HTMLElement} tab The HTML element for the tab.
3570    * @param {!Array<HTMLElement>} tabs Array with HTML elements for all tabs.
3571    * @param {!Array<HTMLElement>} panels Array with HTML elements for all panels.
3572    * @param {MaterialLayout} layout The MaterialLayout object that owns the tab.
3573    */
3574 function MaterialLayoutTab(tab, tabs, panels, layout) {
3575     /**
3576      * Auxiliary method to programmatically select a tab in the UI.
3577      */
3578     function selectTab() {
3579         var href = tab.href.split('#')[1];
3580         var panel = layout.content_.querySelector('#' + href);
3581         layout.resetTabState_(tabs);
3582         layout.resetPanelState_(panels);
3583         tab.classList.add(layout.CssClasses_.IS_ACTIVE);
3584         panel.classList.add(layout.CssClasses_.IS_ACTIVE);
3585     }
3586     if (layout.tabBar_.classList.contains(layout.CssClasses_.JS_RIPPLE_EFFECT)) {
3587         var rippleContainer = document.createElement('span');
3588         rippleContainer.classList.add(layout.CssClasses_.RIPPLE_CONTAINER);
3589         rippleContainer.classList.add(layout.CssClasses_.JS_RIPPLE_EFFECT);
3590         var ripple = document.createElement('span');
3591         ripple.classList.add(layout.CssClasses_.RIPPLE);
3592         rippleContainer.appendChild(ripple);
3593         tab.appendChild(rippleContainer);
3594     }
3595     if (!layout.tabBar_.classList.contains(layout.CssClasses_.TAB_MANUAL_SWITCH)) {
3596         tab.addEventListener('click', function (e) {
3597             if (tab.getAttribute('href').charAt(0) === '#') {
3598                 e.preventDefault();
3599                 selectTab();
3600             }
3601         });
3602     }
3603     tab.show = selectTab;
3604 }
3605 window['MaterialLayoutTab'] = MaterialLayoutTab;
3606 // The component registers itself. It can assume componentHandler is available
3607 // in the global scope.
3608 componentHandler.register({
3609     constructor: MaterialLayout,
3610     classAsString: 'MaterialLayout',
3611     cssClass: 'mdl-js-layout'
3612 });
3613 /**
3614  * @license
3615  * Copyright 2015 Google Inc. All Rights Reserved.
3616  *
3617  * Licensed under the Apache License, Version 2.0 (the "License");
3618  * you may not use this file except in compliance with the License.
3619  * You may obtain a copy of the License at
3620  *
3621  *      http://www.apache.org/licenses/LICENSE-2.0
3622  *
3623  * Unless required by applicable law or agreed to in writing, software
3624  * distributed under the License is distributed on an "AS IS" BASIS,
3625  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3626  * See the License for the specific language governing permissions and
3627  * limitations under the License.
3628  */
3629 /**
3630    * Class constructor for Data Table Card MDL component.
3631    * Implements MDL component design pattern defined at:
3632    * https://github.com/jasonmayes/mdl-component-design-pattern
3633    *
3634    * @constructor
3635    * @param {Element} element The element that will be upgraded.
3636    */
3637 var MaterialDataTable = function MaterialDataTable(element) {
3638     this.element_ = element;
3639     // Initialize instance.
3640     this.init();
3641 };
3642 window['MaterialDataTable'] = MaterialDataTable;
3643 /**
3644    * Store constants in one place so they can be updated easily.
3645    *
3646    * @enum {string | number}
3647    * @private
3648    */
3649 MaterialDataTable.prototype.Constant_ = {};
3650 /**
3651    * Store strings for class names defined by this component that are used in
3652    * JavaScript. This allows us to simply change it in one place should we
3653    * decide to modify at a later date.
3654    *
3655    * @enum {string}
3656    * @private
3657    */
3658 MaterialDataTable.prototype.CssClasses_ = {
3659     DATA_TABLE: 'mdl-data-table',
3660     SELECTABLE: 'mdl-data-table--selectable',
3661     SELECT_ELEMENT: 'mdl-data-table__select',
3662     IS_SELECTED: 'is-selected',
3663     IS_UPGRADED: 'is-upgraded'
3664 };
3665 /**
3666    * Generates and returns a function that toggles the selection state of a
3667    * single row (or multiple rows).
3668    *
3669    * @param {Element} checkbox Checkbox that toggles the selection state.
3670    * @param {Element} row Row to toggle when checkbox changes.
3671    * @param {(Array<Object>|NodeList)=} opt_rows Rows to toggle when checkbox changes.
3672    * @private
3673    */
3674 MaterialDataTable.prototype.selectRow_ = function (checkbox, row, opt_rows) {
3675     if (row) {
3676         return function () {
3677             if (checkbox.checked) {
3678                 row.classList.add(this.CssClasses_.IS_SELECTED);
3679             } else {
3680                 row.classList.remove(this.CssClasses_.IS_SELECTED);
3681             }
3682         }.bind(this);
3683     }
3684     if (opt_rows) {
3685         return function () {
3686             var i;
3687             var el;
3688             if (checkbox.checked) {
3689                 for (i = 0; i < opt_rows.length; i++) {
3690                     el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox');
3691                     el['MaterialCheckbox'].check();
3692                     opt_rows[i].classList.add(this.CssClasses_.IS_SELECTED);
3693                 }
3694             } else {
3695                 for (i = 0; i < opt_rows.length; i++) {
3696                     el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox');
3697                     el['MaterialCheckbox'].uncheck();
3698                     opt_rows[i].classList.remove(this.CssClasses_.IS_SELECTED);
3699                 }
3700             }
3701         }.bind(this);
3702     }
3703 };
3704 /**
3705    * Creates a checkbox for a single or or multiple rows and hooks up the
3706    * event handling.
3707    *
3708    * @param {Element} row Row to toggle when checkbox changes.
3709    * @param {(Array<Object>|NodeList)=} opt_rows Rows to toggle when checkbox changes.
3710    * @private
3711    */
3712 MaterialDataTable.prototype.createCheckbox_ = function (row, opt_rows) {
3713     var label = document.createElement('label');
3714     var labelClasses = [
3715         'mdl-checkbox',
3716         'mdl-js-checkbox',
3717         'mdl-js-ripple-effect',
3718         this.CssClasses_.SELECT_ELEMENT
3719     ];
3720     label.className = labelClasses.join(' ');
3721     var checkbox = document.createElement('input');
3722     checkbox.type = 'checkbox';
3723     checkbox.classList.add('mdl-checkbox__input');
3724     if (row) {
3725         checkbox.checked = row.classList.contains(this.CssClasses_.IS_SELECTED);
3726         checkbox.addEventListener('change', this.selectRow_(checkbox, row));
3727     } else if (opt_rows) {
3728         checkbox.addEventListener('change', this.selectRow_(checkbox, null, opt_rows));
3729     }
3730     label.appendChild(checkbox);
3731     componentHandler.upgradeElement(label, 'MaterialCheckbox');
3732     return label;
3733 };
3734 /**
3735    * Initialize element.
3736    */
3737 MaterialDataTable.prototype.init = function () {
3738     if (this.element_) {
3739         var firstHeader = this.element_.querySelector('th');
3740         var bodyRows = Array.prototype.slice.call(this.element_.querySelectorAll('tbody tr'));
3741         var footRows = Array.prototype.slice.call(this.element_.querySelectorAll('tfoot tr'));
3742         var rows = bodyRows.concat(footRows);
3743         if (this.element_.classList.contains(this.CssClasses_.SELECTABLE)) {
3744             var th = document.createElement('th');
3745             var headerCheckbox = this.createCheckbox_(null, rows);
3746             th.appendChild(headerCheckbox);
3747             firstHeader.parentElement.insertBefore(th, firstHeader);
3748             for (var i = 0; i < rows.length; i++) {
3749                 var firstCell = rows[i].querySelector('td');
3750                 if (firstCell) {
3751                     var td = document.createElement('td');
3752                     if (rows[i].parentNode.nodeName.toUpperCase() === 'TBODY') {
3753                         var rowCheckbox = this.createCheckbox_(rows[i]);
3754                         td.appendChild(rowCheckbox);
3755                     }
3756                     rows[i].insertBefore(td, firstCell);
3757                 }
3758             }
3759             this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
3760         }
3761     }
3762 };
3763 // The component registers itself. It can assume componentHandler is available
3764 // in the global scope.
3765 componentHandler.register({
3766     constructor: MaterialDataTable,
3767     classAsString: 'MaterialDataTable',
3768     cssClass: 'mdl-js-data-table'
3769 });
3770 /**
3771  * @license
3772  * Copyright 2015 Google Inc. All Rights Reserved.
3773  *
3774  * Licensed under the Apache License, Version 2.0 (the "License");
3775  * you may not use this file except in compliance with the License.
3776  * You may obtain a copy of the License at
3777  *
3778  *      http://www.apache.org/licenses/LICENSE-2.0
3779  *
3780  * Unless required by applicable law or agreed to in writing, software
3781  * distributed under the License is distributed on an "AS IS" BASIS,
3782  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3783  * See the License for the specific language governing permissions and
3784  * limitations under the License.
3785  */
3786 /**
3787    * Class constructor for Ripple MDL component.
3788    * Implements MDL component design pattern defined at:
3789    * https://github.com/jasonmayes/mdl-component-design-pattern
3790    *
3791    * @constructor
3792    * @param {HTMLElement} element The element that will be upgraded.
3793    */
3794 var MaterialRipple = function MaterialRipple(element) {
3795     this.element_ = element;
3796     // Initialize instance.
3797     this.init();
3798 };
3799 window['MaterialRipple'] = MaterialRipple;
3800 /**
3801    * Store constants in one place so they can be updated easily.
3802    *
3803    * @enum {string | number}
3804    * @private
3805    */
3806 MaterialRipple.prototype.Constant_ = {
3807     INITIAL_SCALE: 'scale(0.0001, 0.0001)',
3808     INITIAL_SIZE: '1px',
3809     INITIAL_OPACITY: '0.4',
3810     FINAL_OPACITY: '0',
3811     FINAL_SCALE: ''
3812 };
3813 /**
3814    * Store strings for class names defined by this component that are used in
3815    * JavaScript. This allows us to simply change it in one place should we
3816    * decide to modify at a later date.
3817    *
3818    * @enum {string}
3819    * @private
3820    */
3821 MaterialRipple.prototype.CssClasses_ = {
3822     RIPPLE_CENTER: 'mdl-ripple--center',
3823     RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
3824     RIPPLE: 'mdl-ripple',
3825     IS_ANIMATING: 'is-animating',
3826     IS_VISIBLE: 'is-visible'
3827 };
3828 /**
3829    * Handle mouse / finger down on element.
3830    *
3831    * @param {Event} event The event that fired.
3832    * @private
3833    */
3834 MaterialRipple.prototype.downHandler_ = function (event) {
3835     if (!this.rippleElement_.style.width && !this.rippleElement_.style.height) {
3836         var rect = this.element_.getBoundingClientRect();
3837         this.boundHeight = rect.height;
3838         this.boundWidth = rect.width;
3839         this.rippleSize_ = Math.sqrt(rect.width * rect.width + rect.height * rect.height) * 2 + 2;
3840         this.rippleElement_.style.width = this.rippleSize_ + 'px';
3841         this.rippleElement_.style.height = this.rippleSize_ + 'px';
3842     }
3843     this.rippleElement_.classList.add(this.CssClasses_.IS_VISIBLE);
3844     if (event.type === 'mousedown' && this.ignoringMouseDown_) {
3845         this.ignoringMouseDown_ = false;
3846     } else {
3847         if (event.type === 'touchstart') {
3848             this.ignoringMouseDown_ = true;
3849         }
3850         var frameCount = this.getFrameCount();
3851         if (frameCount > 0) {
3852             return;
3853         }
3854         this.setFrameCount(1);
3855         var bound = event.currentTarget.getBoundingClientRect();
3856         var x;
3857         var y;
3858         // Check if we are handling a keyboard click.
3859         if (event.clientX === 0 && event.clientY === 0) {
3860             x = Math.round(bound.width / 2);
3861             y = Math.round(bound.height / 2);
3862         } else {
3863             var clientX = event.clientX !== undefined ? event.clientX : event.touches[0].clientX;
3864             var clientY = event.clientY !== undefined ? event.clientY : event.touches[0].clientY;
3865             x = Math.round(clientX - bound.left);
3866             y = Math.round(clientY - bound.top);
3867         }
3868         this.setRippleXY(x, y);
3869         this.setRippleStyles(true);
3870         window.requestAnimationFrame(this.animFrameHandler.bind(this));
3871     }
3872 };
3873 /**
3874    * Handle mouse / finger up on element.
3875    *
3876    * @param {Event} event The event that fired.
3877    * @private
3878    */
3879 MaterialRipple.prototype.upHandler_ = function (event) {
3880     // Don't fire for the artificial "mouseup" generated by a double-click.
3881     if (event && event.detail !== 2) {
3882         // Allow a repaint to occur before removing this class, so the animation
3883         // shows for tap events, which seem to trigger a mouseup too soon after
3884         // mousedown.
3885         window.setTimeout(function () {
3886             this.rippleElement_.classList.remove(this.CssClasses_.IS_VISIBLE);
3887         }.bind(this), 0);
3888     }
3889 };
3890 /**
3891    * Initialize element.
3892    */
3893 MaterialRipple.prototype.init = function () {
3894     if (this.element_) {
3895         var recentering = this.element_.classList.contains(this.CssClasses_.RIPPLE_CENTER);
3896         if (!this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT_IGNORE_EVENTS)) {
3897             this.rippleElement_ = this.element_.querySelector('.' + this.CssClasses_.RIPPLE);
3898             this.frameCount_ = 0;
3899             this.rippleSize_ = 0;
3900             this.x_ = 0;
3901             this.y_ = 0;
3902             // Touch start produces a compat mouse down event, which would cause a
3903             // second ripples. To avoid that, we use this property to ignore the first
3904             // mouse down after a touch start.
3905             this.ignoringMouseDown_ = false;
3906             this.boundDownHandler = this.downHandler_.bind(this);
3907             this.element_.addEventListener('mousedown', this.boundDownHandler);
3908             this.element_.addEventListener('touchstart', this.boundDownHandler);
3909             this.boundUpHandler = this.upHandler_.bind(this);
3910             this.element_.addEventListener('mouseup', this.boundUpHandler);
3911             this.element_.addEventListener('mouseleave', this.boundUpHandler);
3912             this.element_.addEventListener('touchend', this.boundUpHandler);
3913             this.element_.addEventListener('blur', this.boundUpHandler);
3914             /**
3915          * Getter for frameCount_.
3916          * @return {number} the frame count.
3917          */
3918             this.getFrameCount = function () {
3919                 return this.frameCount_;
3920             };
3921             /**
3922          * Setter for frameCount_.
3923          * @param {number} fC the frame count.
3924          */
3925             this.setFrameCount = function (fC) {
3926                 this.frameCount_ = fC;
3927             };
3928             /**
3929          * Getter for rippleElement_.
3930          * @return {Element} the ripple element.
3931          */
3932             this.getRippleElement = function () {
3933                 return this.rippleElement_;
3934             };
3935             /**
3936          * Sets the ripple X and Y coordinates.
3937          * @param  {number} newX the new X coordinate
3938          * @param  {number} newY the new Y coordinate
3939          */
3940             this.setRippleXY = function (newX, newY) {
3941                 this.x_ = newX;
3942                 this.y_ = newY;
3943             };
3944             /**
3945          * Sets the ripple styles.
3946          * @param  {boolean} start whether or not this is the start frame.
3947          */
3948             this.setRippleStyles = function (start) {
3949                 if (this.rippleElement_ !== null) {
3950                     var transformString;
3951                     var scale;
3952                     var size;
3953                     var offset = 'translate(' + this.x_ + 'px, ' + this.y_ + 'px)';
3954                     if (start) {
3955                         scale = this.Constant_.INITIAL_SCALE;
3956                         size = this.Constant_.INITIAL_SIZE;
3957                     } else {
3958                         scale = this.Constant_.FINAL_SCALE;
3959                         size = this.rippleSize_ + 'px';
3960                         if (recentering) {
3961                             offset = 'translate(' + this.boundWidth / 2 + 'px, ' + this.boundHeight / 2 + 'px)';
3962                         }
3963                     }
3964                     transformString = 'translate(-50%, -50%) ' + offset + scale;
3965                     this.rippleElement_.style.webkitTransform = transformString;
3966                     this.rippleElement_.style.msTransform = transformString;
3967                     this.rippleElement_.style.transform = transformString;
3968                     if (start) {
3969                         this.rippleElement_.classList.remove(this.CssClasses_.IS_ANIMATING);
3970                     } else {
3971                         this.rippleElement_.classList.add(this.CssClasses_.IS_ANIMATING);
3972                     }
3973                 }
3974             };
3975             /**
3976          * Handles an animation frame.
3977          */
3978             this.animFrameHandler = function () {
3979                 if (this.frameCount_-- > 0) {
3980                     window.requestAnimationFrame(this.animFrameHandler.bind(this));
3981                 } else {
3982                     this.setRippleStyles(false);
3983                 }
3984             };
3985         }
3986     }
3987 };
3988 // The component registers itself. It can assume componentHandler is available
3989 // in the global scope.
3990 componentHandler.register({
3991     constructor: MaterialRipple,
3992     classAsString: 'MaterialRipple',
3993     cssClass: 'mdl-js-ripple-effect',
3994     widget: false
3995 });
3996 }());