liquid_feedback_frontend

annotate static/mdl/material.js @ 1466:f921269f7788

Fixed heading of admin newsletter edit view
author bsw
date Thu Oct 18 17:37:33 2018 +0200 (2018-10-18)
parents 32cc544d5a5b
children
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: '&#xE5D2;',
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 }());

Impressum / About Us