vendor/assets/javascripts/material.js in material_design_lite-rails-1.0.3 vs vendor/assets/javascripts/material.js in material_design_lite-rails-1.0.5

- old
+ new

@@ -24,11 +24,70 @@ * https://github.com/jasonmayes/mdl-component-design-pattern * * @author Jason Mayes. */ /* exported componentHandler */ -window.componentHandler = (function() { + +// Pre-defining the componentHandler interface, for closure documentation and +// static verification. +var componentHandler = { + /** + * Searches existing DOM for elements of our component type and upgrades them + * if they have not already been upgraded. + * + * @param {string=} optJsClass the programatic name of the element class we + * need to create a new instance of. + * @param {string=} optCssClass the name of the CSS class elements of this + * type will have. + */ + upgradeDom: function(optJsClass, optCssClass) {}, + /** + * Upgrades a specific element rather than all in the DOM. + * + * @param {!Element} element The element we wish to upgrade. + * @param {string=} optJsClass Optional name of the class we want to upgrade + * the element to. + */ + upgradeElement: function(element, optJsClass) {}, + /** + * Upgrades a specific list of elements rather than all in the DOM. + * + * @param {!Element|!Array<!Element>|!NodeList|!HTMLCollection} elements + * The elements we wish to upgrade. + */ + upgradeElements: function(elements) {}, + /** + * Upgrades all registered components found in the current DOM. This is + * automatically called on window load. + */ + upgradeAllRegistered: function() {}, + /** + * Allows user to be alerted to any upgrades that are performed for a given + * component type + * + * @param {string} jsClass The class name of the MDL component we wish + * to hook into for any upgrades performed. + * @param {function(!HTMLElement)} callback The function to call upon an + * upgrade. This function should expect 1 parameter - the HTMLElement which + * got upgraded. + */ + registerUpgradedCallback: function(jsClass, callback) {}, + /** + * Registers a class for future use and attempts to upgrade existing DOM. + * + * @param {componentHandler.ComponentConfigPublic} config the registration configuration + */ + register: function(config) {}, + /** + * Downgrade either a given node, an array of nodes, or a NodeList. + * + * @param {!Node|!Array<!Node>|!NodeList} nodes + */ + downgradeElements: function(nodes) {} +}; + +componentHandler = (function() { 'use strict'; /** @type {!Array<componentHandler.ComponentConfig>} */ var registeredComponents_ = []; @@ -40,19 +99,19 @@ /** * Searches registered components for a class we are interested in using. * Optionally replaces a match with passed object if specified. * - * @param {String} name The name of a class we want to use. + * @param {string} name The name of a class we want to use. * @param {componentHandler.ComponentConfig=} optReplace Optional object to replace match with. - * @return {!Object|Boolean} + * @return {!Object|boolean} * @private */ function findRegisteredClass_(name, optReplace) { for (var i = 0; i < registeredComponents_.length; i++) { if (registeredComponents_[i].className === name) { - if (optReplace !== undefined) { + if (typeof optReplace !== 'undefined') { registeredComponents_[i] = optReplace; } return registeredComponents_[i]; } } @@ -60,12 +119,12 @@ } /** * Returns an array of the classNames of the upgraded classes on the element. * - * @param {!HTMLElement} element The element to fetch data from. - * @return {!Array<String>} + * @param {!Element} element The element to fetch data from. + * @return {!Array<string>} * @private */ function getUpgradedListOfElement_(element) { var dataUpgraded = element.getAttribute('data-upgraded'); // Use `['']` as default value to conform the `,name,name...` style. @@ -74,13 +133,13 @@ /** * Returns true if the given element has already been upgraded for the given * class. * - * @param {!HTMLElement} element The element we want to check. - * @param {String} jsClass The class to check for. - * @returns {Boolean} + * @param {!Element} element The element we want to check. + * @param {string} jsClass The class to check for. + * @returns {boolean} * @private */ function isElementUpgraded_(element, jsClass) { var upgradedList = getUpgradedListOfElement_(element); return upgradedList.indexOf(jsClass) !== -1; @@ -88,24 +147,25 @@ /** * Searches existing DOM for elements of our component type and upgrades them * if they have not already been upgraded. * - * @param {String=} optJsClass the programatic name of the element class we + * @param {string=} optJsClass the programatic name of the element class we * need to create a new instance of. - * @param {String=} optCssClass the name of the CSS class elements of this + * @param {string=} optCssClass the name of the CSS class elements of this * type will have. */ function upgradeDomInternal(optJsClass, optCssClass) { - if (optJsClass === undefined && optCssClass === undefined) { + if (typeof optJsClass === 'undefined' && + typeof optCssClass === 'undefined') { for (var i = 0; i < registeredComponents_.length; i++) { upgradeDomInternal(registeredComponents_[i].className, registeredComponents_[i].cssClass); } } else { - var jsClass = /** @type {String} */ (optJsClass); - if (optCssClass === undefined) { + var jsClass = /** @type {string} */ (optJsClass); + if (typeof optCssClass === 'undefined') { var registeredClass = findRegisteredClass_(jsClass); if (registeredClass) { optCssClass = registeredClass.cssClass; } } @@ -118,12 +178,12 @@ } /** * Upgrades a specific element rather than all in the DOM. * - * @param {!HTMLElement} element The element we wish to upgrade. - * @param {String=} optJsClass Optional name of the class we want to upgrade + * @param {!Element} element The element we wish to upgrade. + * @param {string=} optJsClass Optional name of the class we want to upgrade * the element to. */ function upgradeElementInternal(element, optJsClass) { // Verify argument type. if (!(typeof element === 'object' && element instanceof Element)) { @@ -178,11 +238,11 @@ } /** * Upgrades a specific list of elements rather than all in the DOM. * - * @param {!HTMLElement|!Array<!HTMLElement>|!NodeList|!HTMLCollection} elements + * @param {!Element|!Array<!Element>|!NodeList|!HTMLCollection} elements * The elements we wish to upgrade. */ function upgradeElementsInternal(elements) { if (!Array.isArray(elements)) { if (typeof elements.item === 'function') { @@ -192,35 +252,47 @@ } } for (var i = 0, n = elements.length, element; i < n; i++) { element = elements[i]; if (element instanceof HTMLElement) { + upgradeElementInternal(element); if (element.children.length > 0) { upgradeElementsInternal(element.children); } - upgradeElementInternal(element); } } } /** * Registers a class for future use and attempts to upgrade existing DOM. * - * @param {{constructor: !Function, classAsString: String, cssClass: String, widget: String}} config + * @param {componentHandler.ComponentConfigPublic} config */ function registerInternal(config) { + // In order to support both Closure-compiled and uncompiled code accessing + // this method, we need to allow for both the dot and array syntax for + // property access. You'll therefore see the `foo.bar || foo['bar']` + // pattern repeated across this method. + var widgetMissing = (typeof config.widget === 'undefined' && + typeof config['widget'] === 'undefined'); + var widget = true; + + if (!widgetMissing) { + widget = config.widget || config['widget']; + } + var newConfig = /** @type {componentHandler.ComponentConfig} */ ({ - 'classConstructor': config.constructor, - 'className': config.classAsString, - 'cssClass': config.cssClass, - 'widget': config.widget === undefined ? true : config.widget, - 'callbacks': [] + classConstructor: config.constructor || config['constructor'], + className: config.classAsString || config['classAsString'], + cssClass: config.cssClass || config['cssClass'], + widget: widget, + callbacks: [] }); registeredComponents_.forEach(function(item) { if (item.cssClass === newConfig.cssClass) { - throw new Error('The provided cssClass has already been registered.'); + throw new Error('The provided cssClass has already been registered: ' + item.cssClass); } if (item.className === newConfig.className) { throw new Error('The provided className has already been registered'); } }); @@ -241,11 +313,11 @@ /** * Allows user to be alerted to any upgrades that are performed for a given * component type * - * @param {String} jsClass The class name of the MDL component we wish + * @param {string} jsClass The class name of the MDL component we wish * to hook into for any upgrades performed. * @param {function(!HTMLElement)} callback The function to call upon an * upgrade. This function should expect 1 parameter - the HTMLElement which * got upgraded. */ @@ -313,10 +385,14 @@ * Downgrade either a given node, an array of nodes, or a NodeList. * * @param {!Node|!Array<!Node>|!NodeList} nodes */ function downgradeNodesInternal(nodes) { + /** + * Auxiliary function to downgrade a single node. + * @param {!Node} node the node to be downgraded + */ var downgradeNode = function(node) { deconstructComponentInternal(findCreatedComponentByNodeInternal(node)); }; if (nodes instanceof Array || nodes instanceof NodeList) { for (var n = 0; n < nodes.length; n++) { @@ -340,38 +416,32 @@ register: registerInternal, downgradeElements: downgradeNodesInternal }; })(); -window.addEventListener('load', function() { - 'use strict'; +/** + * Describes the type of a registered component type managed by + * componentHandler. Provided for benefit of the Closure compiler. + * + * @typedef {{ + * constructor: Function, + * classAsString: string, + * cssClass: string, + * widget: (string|boolean|undefined) + * }} + */ +componentHandler.ComponentConfigPublic; // jshint ignore:line - /** - * Performs a "Cutting the mustard" test. If the browser supports the features - * tested, adds a mdl-js class to the <html> element. It then upgrades all MDL - * components requiring JavaScript. - */ - if ('classList' in document.createElement('div') && - 'querySelector' in document && - 'addEventListener' in window && Array.prototype.forEach) { - document.documentElement.classList.add('mdl-js'); - componentHandler.upgradeAllRegistered(); - } else { - componentHandler.upgradeElement = - componentHandler.register = function() {}; - } -}); - /** * Describes the type of a registered component type managed by * componentHandler. Provided for benefit of the Closure compiler. * * @typedef {{ * constructor: !Function, - * className: String, - * cssClass: String, - * widget: String, + * className: string, + * cssClass: string, + * widget: (string|boolean), * callbacks: !Array<function(!HTMLElement)> * }} */ componentHandler.ComponentConfig; // jshint ignore:line @@ -379,49 +449,101 @@ * Created component (i.e., upgraded element) type as managed by * componentHandler. Provided for benefit of the Closure compiler. * * @typedef {{ * element_: !HTMLElement, - * className: String, - * classAsString: String, - * cssClass: String, - * widget: String + * className: string, + * classAsString: string, + * cssClass: string, + * widget: string * }} */ componentHandler.Component; // jshint ignore:line +// Export all symbols, for the benefit of Closure compiler. +// No effect on uncompiled code. +componentHandler['upgradeDom'] = componentHandler.upgradeDom; +componentHandler['upgradeElement'] = componentHandler.upgradeElement; +componentHandler['upgradeElements'] = componentHandler.upgradeElements; +componentHandler['upgradeAllRegistered'] = + componentHandler.upgradeAllRegistered; +componentHandler['registerUpgradedCallback'] = + componentHandler.registerUpgradedCallback; +componentHandler['register'] = componentHandler.register; +componentHandler['downgradeElements'] = componentHandler.downgradeElements; +window.componentHandler = componentHandler; +window['componentHandler'] = componentHandler; + +window.addEventListener('load', function() { + 'use strict'; + + /** + * Performs a "Cutting the mustard" test. If the browser supports the features + * tested, adds a mdl-js class to the <html> element. It then upgrades all MDL + * components requiring JavaScript. + */ + if ('classList' in document.createElement('div') && + 'querySelector' in document && + 'addEventListener' in window && Array.prototype.forEach) { + document.documentElement.classList.add('mdl-js'); + componentHandler.upgradeAllRegistered(); + } else { + /** + * Dummy function to avoid JS errors. + */ + componentHandler.upgradeElement = function() {}; + /** + * Dummy function to avoid JS errors. + */ + componentHandler.register = function() {}; + } +}); + // Source: https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js // Adapted from https://gist.github.com/paulirish/1579671 which derived from // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller. // Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon // MIT license if (!Date.now) { + /** + * Date.now polyfill. + * @return {number} the current Date + */ Date.now = function () { return new Date().getTime(); }; + Date['now'] = Date.now; } var vendors = [ 'webkit', 'moz' ]; for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { var vp = vendors[i]; window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']; + window['requestAnimationFrame'] = window.requestAnimationFrame; + window['cancelAnimationFrame'] = window.cancelAnimationFrame; } if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { var lastTime = 0; + /** + * requestAnimationFrame polyfill. + * @param {!Function} callback the callback function. + */ window.requestAnimationFrame = function (callback) { var now = Date.now(); var nextTime = Math.max(lastTime + 16, now); return setTimeout(function () { callback(lastTime = nextTime); }, nextTime - now); }; window.cancelAnimationFrame = clearTimeout; + window['requestAnimationFrame'] = window.requestAnimationFrame; + window['cancelAnimationFrame'] = window.cancelAnimationFrame; } /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * @@ -447,24 +569,24 @@ var MaterialButton = function MaterialButton(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialButton = MaterialButton; +window['MaterialButton'] = MaterialButton; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialButton.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialButton.prototype.CssClasses_ = { RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_CONTAINER: 'mdl-button__ripple-container', @@ -488,18 +610,20 @@ * @public */ MaterialButton.prototype.disable = function () { this.element_.disabled = true; }; +MaterialButton.prototype['disable'] = MaterialButton.prototype.disable; /** * Enable button. * * @public */ MaterialButton.prototype.enable = function () { this.element_.disabled = false; }; +MaterialButton.prototype['enable'] = MaterialButton.prototype.enable; /** * Initialize element. */ MaterialButton.prototype.init = function () { if (this.element_) { @@ -557,31 +681,32 @@ /** * Class constructor for Checkbox MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialCheckbox = function MaterialCheckbox(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialCheckbox = MaterialCheckbox; +window['MaterialCheckbox'] = MaterialCheckbox; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialCheckbox.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialCheckbox.prototype.CssClasses_ = { INPUT: 'mdl-checkbox__input', BOX_OUTLINE: 'mdl-checkbox__box-outline', @@ -643,14 +768,13 @@ this.checkToggleState(); }; /** * Add blur. * - * @param {Event} event The event that fired. * @private */ -MaterialCheckbox.prototype.blur_ = function (event) { +MaterialCheckbox.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.inputElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); @@ -666,10 +790,11 @@ this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; +MaterialCheckbox.prototype['checkToggleState'] = MaterialCheckbox.prototype.checkToggleState; /** * Check the inputs disabled state and update display. * * @public */ @@ -678,46 +803,51 @@ this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; +MaterialCheckbox.prototype['checkDisabled'] = MaterialCheckbox.prototype.checkDisabled; /** * Disable checkbox. * * @public */ MaterialCheckbox.prototype.disable = function () { this.inputElement_.disabled = true; this.updateClasses_(); }; +MaterialCheckbox.prototype['disable'] = MaterialCheckbox.prototype.disable; /** * Enable checkbox. * * @public */ MaterialCheckbox.prototype.enable = function () { this.inputElement_.disabled = false; this.updateClasses_(); }; +MaterialCheckbox.prototype['enable'] = MaterialCheckbox.prototype.enable; /** * Check checkbox. * * @public */ MaterialCheckbox.prototype.check = function () { this.inputElement_.checked = true; this.updateClasses_(); }; +MaterialCheckbox.prototype['check'] = MaterialCheckbox.prototype.check; /** * Uncheck checkbox. * * @public */ MaterialCheckbox.prototype.uncheck = function () { this.inputElement_.checked = false; this.updateClasses_(); }; +MaterialCheckbox.prototype['uncheck'] = MaterialCheckbox.prototype.uncheck; /** * Initialize element. */ MaterialCheckbox.prototype.init = function () { if (this.element_) { @@ -797,31 +927,32 @@ /** * Class constructor for icon toggle MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialIconToggle = function MaterialIconToggle(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialIconToggle = MaterialIconToggle; +window['MaterialIconToggle'] = MaterialIconToggle; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialIconToggle.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialIconToggle.prototype.CssClasses_ = { INPUT: 'mdl-icon-toggle__input', JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', @@ -879,14 +1010,13 @@ this.checkToggleState(); }; /** * Add blur. * - * @param {Event} event The event that fired. * @private */ -MaterialIconToggle.prototype.blur_ = function (event) { +MaterialIconToggle.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.inputElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); @@ -902,10 +1032,11 @@ this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; +MaterialIconToggle.prototype['checkToggleState'] = MaterialIconToggle.prototype.checkToggleState; /** * Check the inputs disabled state and update display. * * @public */ @@ -914,46 +1045,51 @@ this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; +MaterialIconToggle.prototype['checkDisabled'] = MaterialIconToggle.prototype.checkDisabled; /** * Disable icon toggle. * * @public */ MaterialIconToggle.prototype.disable = function () { this.inputElement_.disabled = true; this.updateClasses_(); }; +MaterialIconToggle.prototype['disable'] = MaterialIconToggle.prototype.disable; /** * Enable icon toggle. * * @public */ MaterialIconToggle.prototype.enable = function () { this.inputElement_.disabled = false; this.updateClasses_(); }; +MaterialIconToggle.prototype['enable'] = MaterialIconToggle.prototype.enable; /** * Check icon toggle. * * @public */ MaterialIconToggle.prototype.check = function () { this.inputElement_.checked = true; this.updateClasses_(); }; +MaterialIconToggle.prototype['check'] = MaterialIconToggle.prototype.check; /** * Uncheck icon toggle. * * @public */ MaterialIconToggle.prototype.uncheck = function () { this.inputElement_.checked = false; this.updateClasses_(); }; +MaterialIconToggle.prototype['uncheck'] = MaterialIconToggle.prototype.uncheck; /** * Initialize element. */ MaterialIconToggle.prototype.init = function () { if (this.element_) { @@ -1024,22 +1160,23 @@ /** * Class constructor for dropdown MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialMenu = function MaterialMenu(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialMenu = MaterialMenu; +window['MaterialMenu'] = MaterialMenu; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialMenu.prototype.Constant_ = { // Total duration of the menu animation. TRANSITION_DURATION_SECONDS: 0.3, @@ -1050,11 +1187,11 @@ CLOSE_TIMEOUT: 150 }; /** * Keycodes, for code readability. * - * @enum {Number} + * @enum {number} * @private */ MaterialMenu.prototype.Keycodes_ = { ENTER: 13, ESCAPE: 27, @@ -1065,11 +1202,11 @@ /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialMenu.prototype.CssClasses_ = { CONTAINER: 'mdl-menu__container', OUTLINE: 'mdl-menu__outline', @@ -1276,18 +1413,18 @@ /** * Calculates the initial clip (for opening the menu) or final clip (for closing * it), and applies it. This allows us to animate from or to the correct point, * that is, the point it's aligned to in the "for" element. * - * @param {Number} height Height of the clip rectangle - * @param {Number} width Width of the clip rectangle + * @param {number} height Height of the clip rectangle + * @param {number} width Width of the clip rectangle * @private */ MaterialMenu.prototype.applyClip_ = function (height, width) { if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { // Do not clip. - this.element_.style.clip = null; + this.element_.style.clip = ''; } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { // Clip to the top right corner of the menu. this.element_.style.clip = 'rect(0 ' + width + 'px ' + '0 ' + width + 'px)'; } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { // Clip to the bottom left corner of the menu. @@ -1295,11 +1432,11 @@ } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { // Clip to the bottom right corner of the menu. this.element_.style.clip = 'rect(' + height + 'px ' + width + 'px ' + height + 'px ' + width + 'px)'; } else { // Default: do not clip (same as clipping to the top left corner). - this.element_.style.clip = null; + this.element_.style.clip = ''; } }; /** * Adds an event listener to clean up after the animation ends. * @@ -1366,10 +1503,11 @@ } }.bind(this); document.addEventListener('click', callback); } }; +MaterialMenu.prototype['show'] = MaterialMenu.prototype.show; /** * Hides the menu. * * @public */ @@ -1390,10 +1528,11 @@ this.container_.classList.remove(this.CssClasses_.IS_VISIBLE); // Clean up after the animation is complete. this.addAnimationEndListener_(); } }; +MaterialMenu.prototype['hide'] = MaterialMenu.prototype.hide; /** * Displays or hides the menu, depending on current state. * * @public */ @@ -1402,10 +1541,11 @@ this.hide(); } else { this.show(evt); } }; +MaterialMenu.prototype['toggle'] = MaterialMenu.prototype.toggle; /** * Downgrade the component. * * @private */ @@ -1443,56 +1583,59 @@ /** * Class constructor for Progress MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialProgress = function MaterialProgress(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialProgress = MaterialProgress; +window['MaterialProgress'] = MaterialProgress; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialProgress.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialProgress.prototype.CssClasses_ = { INDETERMINATE_CLASS: 'mdl-progress__indeterminate' }; /** * Set the current progress of the progressbar. * - * @param {Number} p Percentage of the progress (0-100) + * @param {number} p Percentage of the progress (0-100) * @public */ MaterialProgress.prototype.setProgress = function (p) { if (this.element_.classList.contains(this.CssClasses_.INDETERMINATE_CLASS)) { return; } this.progressbar_.style.width = p + '%'; }; +MaterialProgress.prototype['setProgress'] = MaterialProgress.prototype.setProgress; /** * Set the current progress of the buffer. * - * @param {Number} p Percentage of the buffer (0-100) + * @param {number} p Percentage of the buffer (0-100) * @public */ MaterialProgress.prototype.setBuffer = function (p) { this.bufferbar_.style.width = p + '%'; this.auxbar_.style.width = 100 - p + '%'; }; +MaterialProgress.prototype['setBuffer'] = MaterialProgress.prototype.setBuffer; /** * Initialize element. */ MaterialProgress.prototype.init = function () { if (this.element_) { @@ -1551,31 +1694,32 @@ /** * Class constructor for Radio MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialRadio = function MaterialRadio(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialRadio = MaterialRadio; +window['MaterialRadio'] = MaterialRadio; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialRadio.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialRadio.prototype.CssClasses_ = { IS_FOCUSED: 'is-focused', IS_DISABLED: 'is-disabled', @@ -1603,11 +1747,11 @@ var radios = document.getElementsByClassName(this.CssClasses_.JS_RADIO); for (var i = 0; i < radios.length; i++) { var button = radios[i].querySelector('.' + this.CssClasses_.RADIO_BTN); // Different name == different group, so no point updating those. if (button.getAttribute('name') === this.btnElement_.getAttribute('name')) { - radios[i].MaterialRadio.updateClasses_(); + radios[i]['MaterialRadio'].updateClasses_(); } } }; /** * Handle focus. @@ -1646,14 +1790,13 @@ this.checkToggleState(); }; /** * Add blur. * - * @param {Event} event The event that fired. * @private */ -MaterialRadio.prototype.blur_ = function (event) { +MaterialRadio.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.btnElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); @@ -1669,10 +1812,11 @@ this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; +MaterialRadio.prototype['checkDisabled'] = MaterialRadio.prototype.checkDisabled; /** * Check the components toggled state. * * @public */ @@ -1681,46 +1825,51 @@ this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; +MaterialRadio.prototype['checkToggleState'] = MaterialRadio.prototype.checkToggleState; /** * Disable radio. * * @public */ MaterialRadio.prototype.disable = function () { this.btnElement_.disabled = true; this.updateClasses_(); }; +MaterialRadio.prototype['disable'] = MaterialRadio.prototype.disable; /** * Enable radio. * * @public */ MaterialRadio.prototype.enable = function () { this.btnElement_.disabled = false; this.updateClasses_(); }; +MaterialRadio.prototype['enable'] = MaterialRadio.prototype.enable; /** * Check radio. * * @public */ MaterialRadio.prototype.check = function () { this.btnElement_.checked = true; this.updateClasses_(); }; +MaterialRadio.prototype['check'] = MaterialRadio.prototype.check; /** * Uncheck radio. * * @public */ MaterialRadio.prototype.uncheck = function () { this.btnElement_.checked = false; this.updateClasses_(); }; +MaterialRadio.prototype['uncheck'] = MaterialRadio.prototype.uncheck; /** * Initialize element. */ MaterialRadio.prototype.init = function () { if (this.element_) { @@ -1779,33 +1928,34 @@ /** * Class constructor for Slider MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialSlider = function MaterialSlider(element) { this.element_ = element; // Browser feature detection. this.isIE_ = window.navigator.msPointerEnabled; // Initialize instance. this.init(); }; -window.MaterialSlider = MaterialSlider; +window['MaterialSlider'] = MaterialSlider; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialSlider.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialSlider.prototype.CssClasses_ = { IE_CONTAINER: 'mdl-slider__ie-container', SLIDER_CONTAINER: 'mdl-slider__container', @@ -1848,10 +1998,11 @@ * exactly on the 2px slider element, as FireFox seems to be very * strict about this. * * @param {Event} event The event that fired. * @private + * @suppress {missingProperties} */ MaterialSlider.prototype.onContainerMouseDown_ = function (event) { // If this click is not on the parent element (but rather some child) // ignore. It may still bubble up. if (event.target !== this.element_.parentElement) { @@ -1869,14 +2020,13 @@ this.element_.dispatchEvent(newEvent); }; /** * Handle updating of values. * - * @param {Event} event The event that fired. * @private */ -MaterialSlider.prototype.updateValueStyles_ = function (event) { +MaterialSlider.prototype.updateValueStyles_ = function () { // Calculate and apply percentages to div structure behind slider. var fraction = (this.element_.value - this.element_.min) / (this.element_.max - this.element_.min); if (fraction === 0) { this.element_.classList.add(this.CssClasses_.IS_LOWEST_VALUE); } else { @@ -1896,30 +2046,33 @@ * @public */ MaterialSlider.prototype.disable = function () { this.element_.disabled = true; }; +MaterialSlider.prototype['disable'] = MaterialSlider.prototype.disable; /** * Enable slider. * * @public */ MaterialSlider.prototype.enable = function () { this.element_.disabled = false; }; +MaterialSlider.prototype['enable'] = MaterialSlider.prototype.enable; /** * Update slider value. * - * @param {Number} value The value to which to set the control (optional). + * @param {number} value The value to which to set the control (optional). * @public */ MaterialSlider.prototype.change = function (value) { if (typeof value !== 'undefined') { this.element_.value = value; } this.updateValueStyles_(); }; +MaterialSlider.prototype['change'] = MaterialSlider.prototype.change; /** * Initialize element. */ MaterialSlider.prototype.init = function () { if (this.element_) { @@ -2009,24 +2162,24 @@ var MaterialSpinner = function MaterialSpinner(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialSpinner = MaterialSpinner; +window['MaterialSpinner'] = MaterialSpinner; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialSpinner.prototype.Constant_ = { MDL_SPINNER_LAYER_COUNT: 4 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialSpinner.prototype.CssClasses_ = { MDL_SPINNER_LAYER: 'mdl-spinner__layer', MDL_SPINNER_CIRCLE_CLIPPER: 'mdl-spinner__circle-clipper', @@ -2036,11 +2189,11 @@ MDL_SPINNER_RIGHT: 'mdl-spinner__right' }; /** * Auxiliary method to create a spinner layer. * - * @param {Number} index Index of the layer to be created. + * @param {number} index Index of the layer to be created. * @public */ MaterialSpinner.prototype.createLayer = function (index) { var layer = document.createElement('div'); layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER); @@ -2066,29 +2219,32 @@ layer.appendChild(leftClipper); layer.appendChild(gapPatch); layer.appendChild(rightClipper); this.element_.appendChild(layer); }; +MaterialSpinner.prototype['createLayer'] = MaterialSpinner.prototype.createLayer; /** * Stops the spinner animation. * Public method for users who need to stop the spinner for any reason. * * @public */ MaterialSpinner.prototype.stop = function () { this.element_.classList.remove('is-active'); }; +MaterialSpinner.prototype['stop'] = MaterialSpinner.prototype.stop; /** * Starts the spinner animation. * Public method for users who need to manually start the spinner for any reason * (instead of just adding the 'is-active' class to their markup). * * @public */ MaterialSpinner.prototype.start = function () { this.element_.classList.add('is-active'); }; +MaterialSpinner.prototype['start'] = MaterialSpinner.prototype.start; /** * Initialize element. */ MaterialSpinner.prototype.init = function () { if (this.element_) { @@ -2125,31 +2281,32 @@ /** * Class constructor for Checkbox MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialSwitch = function MaterialSwitch(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialSwitch = MaterialSwitch; +window['MaterialSwitch'] = MaterialSwitch; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialSwitch.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialSwitch.prototype.CssClasses_ = { INPUT: 'mdl-switch__input', TRACK: 'mdl-switch__track', @@ -2212,11 +2369,11 @@ /** * Add blur. * * @private */ -MaterialSwitch.prototype.blur_ = function (event) { +MaterialSwitch.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.inputElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); @@ -2232,10 +2389,11 @@ this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; +MaterialSwitch.prototype['checkDisabled'] = MaterialSwitch.prototype.checkDisabled; /** * Check the components toggled state. * * @public */ @@ -2244,46 +2402,51 @@ this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; +MaterialSwitch.prototype['checkToggleState'] = MaterialSwitch.prototype.checkToggleState; /** * Disable switch. * * @public */ MaterialSwitch.prototype.disable = function () { this.inputElement_.disabled = true; this.updateClasses_(); }; +MaterialSwitch.prototype['disable'] = MaterialSwitch.prototype.disable; /** * Enable switch. * * @public */ MaterialSwitch.prototype.enable = function () { this.inputElement_.disabled = false; this.updateClasses_(); }; +MaterialSwitch.prototype['enable'] = MaterialSwitch.prototype.enable; /** * Activate switch. * * @public */ MaterialSwitch.prototype.on = function () { this.inputElement_.checked = true; this.updateClasses_(); }; +MaterialSwitch.prototype['on'] = MaterialSwitch.prototype.on; /** * Deactivate switch. * * @public */ MaterialSwitch.prototype.off = function () { this.inputElement_.checked = false; this.updateClasses_(); }; +MaterialSwitch.prototype['off'] = MaterialSwitch.prototype.off; /** * Initialize element. */ MaterialSwitch.prototype.init = function () { if (this.element_) { @@ -2362,32 +2525,33 @@ /** * Class constructor for Tabs MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialTabs = function MaterialTabs(element) { // Stores the HTML element. this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialTabs = MaterialTabs; +window['MaterialTabs'] = MaterialTabs; /** * Store constants in one place so they can be updated easily. * - * @enum {String} + * @enum {string} * @private */ MaterialTabs.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialTabs.prototype.CssClasses_ = { TAB_CLASS: 'mdl-tabs__tab', PANEL_CLASS: 'mdl-tabs__panel', @@ -2442,10 +2606,17 @@ MaterialTabs.prototype.init = function () { if (this.element_) { this.initTabs_(); } }; +/** + * Constructor for an individual tab. + * + * @constructor + * @param {HTMLElement} tab The HTML element for the tab. + * @param {MaterialTabs} ctx The MaterialTabs object that owns the tab. + */ function MaterialTab(tab, ctx) { if (tab) { if (ctx.element_.classList.contains(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT)) { var rippleContainer = document.createElement('span'); rippleContainer.classList.add(ctx.CssClasses_.MDL_RIPPLE_CONTAINER); @@ -2492,23 +2663,24 @@ /** * Class constructor for Textfield MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialTextfield = function MaterialTextfield(element) { this.element_ = element; this.maxRows = this.Constant_.NO_MAX_ROWS; // Initialize instance. this.init(); }; -window.MaterialTextfield = MaterialTextfield; +window['MaterialTextfield'] = MaterialTextfield; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialTextfield.prototype.Constant_ = { NO_MAX_ROWS: -1, MAX_ROWS_ATTRIBUTE: 'maxrows' @@ -2516,11 +2688,11 @@ /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialTextfield.prototype.CssClasses_ = { LABEL: 'mdl-textfield__label', INPUT: 'mdl-textfield__input', @@ -2583,10 +2755,11 @@ this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; +MaterialTextfield.prototype['checkDisabled'] = MaterialTextfield.prototype.checkDisabled; /** * Check the validity state and update field accordingly. * * @public */ @@ -2595,10 +2768,11 @@ this.element_.classList.remove(this.CssClasses_.IS_INVALID); } else { this.element_.classList.add(this.CssClasses_.IS_INVALID); } }; +MaterialTextfield.prototype['checkValidity'] = MaterialTextfield.prototype.checkValidity; /** * Check the dirty state and update field accordingly. * * @public */ @@ -2607,40 +2781,46 @@ this.element_.classList.add(this.CssClasses_.IS_DIRTY); } else { this.element_.classList.remove(this.CssClasses_.IS_DIRTY); } }; +MaterialTextfield.prototype['checkDirty'] = MaterialTextfield.prototype.checkDirty; /** * Disable text field. * * @public */ MaterialTextfield.prototype.disable = function () { this.input_.disabled = true; this.updateClasses_(); }; +MaterialTextfield.prototype['disable'] = MaterialTextfield.prototype.disable; /** * Enable text field. * * @public */ MaterialTextfield.prototype.enable = function () { this.input_.disabled = false; this.updateClasses_(); }; +MaterialTextfield.prototype['enable'] = MaterialTextfield.prototype.enable; /** * Update text field value. * - * @param {String} value The value to which to set the control (optional). + * @param {string} value The value to which to set the control (optional). * @public */ MaterialTextfield.prototype.change = function (value) { if (value) { this.input_.value = value; + } else { + this.input_.value = ''; } this.updateClasses_(); }; +MaterialTextfield.prototype['change'] = MaterialTextfield.prototype.change; /** * Initialize element. */ MaterialTextfield.prototype.init = function () { if (this.element_) { @@ -2710,31 +2890,32 @@ /** * Class constructor for Tooltip MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialTooltip = function MaterialTooltip(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialTooltip = MaterialTooltip; +window['MaterialTooltip'] = MaterialTooltip; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialTooltip.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialTooltip.prototype.CssClasses_ = { IS_ACTIVE: 'is-active' }; /** * Handle mouseenter for tooltip. @@ -2834,22 +3015,23 @@ /** * Class constructor for Layout MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialLayout = function MaterialLayout(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialLayout = MaterialLayout; +window['MaterialLayout'] = MaterialLayout; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialLayout.prototype.Constant_ = { MAX_WIDTH: '(max-width: 1024px)', TAB_SCROLL_PIXELS: 100, @@ -2858,11 +3040,11 @@ CHEVRON_RIGHT: 'chevron_right' }; /** * Modes. * - * @enum {Number} + * @enum {number} * @private */ MaterialLayout.prototype.Mode_ = { STANDARD: 0, SEAMED: 1, @@ -2872,11 +3054,11 @@ /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialLayout.prototype.CssClasses_ = { CONTAINER: 'mdl-layout__container', HEADER: 'mdl-layout__header', @@ -3054,28 +3236,35 @@ // the header. this.content_.addEventListener('scroll', this.contentScrollHandler_.bind(this)); this.contentScrollHandler_(); } } + /** + * Prevents an event from triggering the default behaviour. + * @param {Event} ev the event to eat. + */ var eatEvent = function (ev) { ev.preventDefault(); }; // Add drawer toggling button to our layout, if we have an openable drawer. if (this.drawer_) { - var drawerButton = document.createElement('div'); - drawerButton.classList.add(this.CssClasses_.DRAWER_BTN); + var drawerButton = this.element_.querySelector('.' + this.CssClasses_.DRAWER_BTN); + if (typeof drawerButton === 'undefined' || drawerButton === null) { + drawerButton = document.createElement('div'); + drawerButton.classList.add(this.CssClasses_.DRAWER_BTN); + var drawerButtonIcon = document.createElement('i'); + drawerButtonIcon.classList.add(this.CssClasses_.ICON); + drawerButtonIcon.textContent = this.Constant_.MENU_ICON; + drawerButton.appendChild(drawerButtonIcon); + } if (this.drawer_.classList.contains(this.CssClasses_.ON_LARGE_SCREEN)) { //If drawer has ON_LARGE_SCREEN class then add it to the drawer toggle button as well. drawerButton.classList.add(this.CssClasses_.ON_LARGE_SCREEN); } else if (this.drawer_.classList.contains(this.CssClasses_.ON_SMALL_SCREEN)) { //If drawer has ON_SMALL_SCREEN class then add it to the drawer toggle button as well. drawerButton.classList.add(this.CssClasses_.ON_SMALL_SCREEN); } - var drawerButtonIcon = document.createElement('i'); - drawerButtonIcon.classList.add(this.CssClasses_.ICON); - drawerButtonIcon.textContent = this.Constant_.MENU_ICON; - drawerButton.appendChild(drawerButtonIcon); drawerButton.addEventListener('click', this.drawerToggleHandler_.bind(this)); // Add a class if the layout has a drawer, for altering the left padding. // Adds the HAS_DRAWER to the elements since this.header_ may or may // not be present. this.element_.classList.add(this.CssClasses_.HAS_DRAWER); @@ -3150,10 +3339,19 @@ } } this.element_.classList.add(this.CssClasses_.IS_UPGRADED); } }; +/** + * Constructor for an individual tab. + * + * @constructor + * @param {HTMLElement} tab The HTML element for the tab. + * @param {!Array<HTMLElement>} tabs Array with HTML elements for all tabs. + * @param {!Array<HTMLElement>} panels Array with HTML elements for all panels. + * @param {MaterialLayout} layout The MaterialLayout object that owns the tab. + */ function MaterialLayoutTab(tab, tabs, panels, layout) { if (tab) { if (layout.tabBar_.classList.contains(layout.CssClasses_.JS_RIPPLE_EFFECT)) { var rippleContainer = document.createElement('span'); rippleContainer.classList.add(layout.CssClasses_.RIPPLE_CONTAINER); @@ -3200,31 +3398,32 @@ /** * Class constructor for Data Table Card MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialDataTable = function MaterialDataTable(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialDataTable = MaterialDataTable; +window['MaterialDataTable'] = MaterialDataTable; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialDataTable.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialDataTable.prototype.CssClasses_ = { DATA_TABLE: 'mdl-data-table', SELECTABLE: 'mdl-data-table--selectable', @@ -3233,66 +3432,66 @@ }; /** * Generates and returns a function that toggles the selection state of a * single row (or multiple rows). * - * @param {HTMLElement} checkbox Checkbox that toggles the selection state. + * @param {Element} checkbox Checkbox that toggles the selection state. * @param {HTMLElement} row Row to toggle when checkbox changes. - * @param {HTMLElement[]} rows Rows to toggle when checkbox changes. + * @param {(Array<Object>|NodeList)=} opt_rows Rows to toggle when checkbox changes. * @private */ -MaterialDataTable.prototype.selectRow_ = function (checkbox, row, rows) { +MaterialDataTable.prototype.selectRow_ = function (checkbox, row, opt_rows) { if (row) { return function () { if (checkbox.checked) { row.classList.add(this.CssClasses_.IS_SELECTED); } else { row.classList.remove(this.CssClasses_.IS_SELECTED); } }.bind(this); } - if (rows) { + if (opt_rows) { return function () { var i; var el; if (checkbox.checked) { - for (i = 0; i < rows.length; i++) { - el = rows[i].querySelector('td').querySelector('.mdl-checkbox'); - el.MaterialCheckbox.check(); - rows[i].classList.add(this.CssClasses_.IS_SELECTED); + for (i = 0; i < opt_rows.length; i++) { + el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox'); + el['MaterialCheckbox'].check(); + opt_rows[i].classList.add(this.CssClasses_.IS_SELECTED); } } else { - for (i = 0; i < rows.length; i++) { - el = rows[i].querySelector('td').querySelector('.mdl-checkbox'); - el.MaterialCheckbox.uncheck(); - rows[i].classList.remove(this.CssClasses_.IS_SELECTED); + for (i = 0; i < opt_rows.length; i++) { + el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox'); + el['MaterialCheckbox'].uncheck(); + opt_rows[i].classList.remove(this.CssClasses_.IS_SELECTED); } } }.bind(this); } }; /** * Creates a checkbox for a single or or multiple rows and hooks up the * event handling. * * @param {HTMLElement} row Row to toggle when checkbox changes. - * @param {HTMLElement[]} rows Rows to toggle when checkbox changes. + * @param {(Array<Object>|NodeList)=} opt_rows Rows to toggle when checkbox changes. * @private */ -MaterialDataTable.prototype.createCheckbox_ = function (row, rows) { +MaterialDataTable.prototype.createCheckbox_ = function (row, opt_rows) { var label = document.createElement('label'); label.classList.add('mdl-checkbox'); label.classList.add('mdl-js-checkbox'); label.classList.add('mdl-js-ripple-effect'); label.classList.add('mdl-data-table__select'); var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.classList.add('mdl-checkbox__input'); if (row) { checkbox.addEventListener('change', this.selectRow_(checkbox, row)); - } else if (rows) { - checkbox.addEventListener('change', this.selectRow_(checkbox, null, rows)); + } else if (opt_rows) { + checkbox.addEventListener('change', this.selectRow_(checkbox, null, opt_rows)); } label.appendChild(checkbox); componentHandler.upgradeElement(label, 'MaterialCheckbox'); return label; }; @@ -3347,22 +3546,23 @@ /** * Class constructor for Ripple MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * + * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialRipple = function MaterialRipple(element) { this.element_ = element; // Initialize instance. this.init(); }; -window.MaterialRipple = MaterialRipple; +window['MaterialRipple'] = MaterialRipple; /** * Store constants in one place so they can be updated easily. * - * @enum {String | Number} + * @enum {string | number} * @private */ MaterialRipple.prototype.Constant_ = { INITIAL_SCALE: 'scale(0.0001, 0.0001)', INITIAL_SIZE: '1px', @@ -3373,11 +3573,11 @@ /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * - * @enum {String} + * @enum {string} * @private */ MaterialRipple.prototype.CssClasses_ = { RIPPLE_CENTER: 'mdl-ripple--center', RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', @@ -3470,23 +3670,44 @@ this.boundUpHandler = this.upHandler_.bind(this); this.element_.addEventListener('mouseup', this.boundUpHandler); this.element_.addEventListener('mouseleave', this.boundUpHandler); this.element_.addEventListener('touchend', this.boundUpHandler); this.element_.addEventListener('blur', this.boundUpHandler); + /** + * Getter for frameCount_. + * @return {number} the frame count. + */ this.getFrameCount = function () { return this.frameCount_; }; + /** + * Setter for frameCount_. + * @param {number} fC the frame count. + */ this.setFrameCount = function (fC) { this.frameCount_ = fC; }; + /** + * Getter for rippleElement_. + * @return {Element} the ripple element. + */ this.getRippleElement = function () { return this.rippleElement_; }; + /** + * Sets the ripple X and Y coordinates. + * @param {number} newX the new X coordinate + * @param {number} newY the new Y coordinate + */ this.setRippleXY = function (newX, newY) { this.x_ = newX; this.y_ = newY; }; + /** + * Sets the ripple styles. + * @param {boolean} start whether or not this is the start frame. + */ this.setRippleStyles = function (start) { if (this.rippleElement_ !== null) { var transformString; var scale; var size; @@ -3510,9 +3731,12 @@ } else { this.rippleElement_.classList.add(this.CssClasses_.IS_ANIMATING); } } }; + /** + * Handles an animation frame. + */ this.animFrameHandler = function () { if (this.frameCount_-- > 0) { window.requestAnimationFrame(this.animFrameHandler.bind(this)); } else { this.setRippleStyles(false);