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