Chromium Code Reviews| Index: third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js |
| diff --git a/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js |
| index d4c41ad0f92ebf48eec311e6c4a24c2115d17c53..e5d78bd2138eb81ee960d4e3609f8491dbc37002 100644 |
| --- a/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js |
| +++ b/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js |
| @@ -1,611 +1,202 @@ |
| (function() { |
| - var Utility = { |
| - distance: function(x1, y1, x2, y2) { |
| - var xDelta = (x1 - x2); |
| - var yDelta = (y1 - y2); |
| - return Math.sqrt(xDelta * xDelta + yDelta * yDelta); |
| - }, |
| - |
| - now: window.performance && window.performance.now ? |
| - window.performance.now.bind(window.performance) : Date.now |
| - }; |
| - |
| - /** |
| - * @param {HTMLElement} element |
| - * @constructor |
| - */ |
| - function ElementMetrics(element) { |
| - this.element = element; |
| - this.width = this.boundingRect.width; |
| - this.height = this.boundingRect.height; |
| - |
| - this.size = Math.max(this.width, this.height); |
| +var MAX_RADIUS_PX = 300; |
| +var MIN_DURATION_MS = 800; |
| + |
| +/** |
| + * @param {number} x1 |
| + * @param {number} y1 |
| + * @param {number} x2 |
| + * @param {number} y2 |
| + * @return {number} The distance between (x1, y1) and (x2, y2). |
| + */ |
| +var distance = function(x1, y1, x2, y2) { |
| + var xDelta = x1 - x2; |
| + var yDelta = y1 - y2; |
| + return Math.sqrt(xDelta * xDelta + yDelta * yDelta); |
| +}; |
| + |
| +Polymer({ |
| + is: 'paper-ripple', |
| + |
| + behaviors: [Polymer.IronA11yKeysBehavior], |
| + |
| + properties: { |
| + center: {type: Boolean, value: false}, |
| + holdDown: {type: Boolean, value: false, observer: '_holdDownChanged'}, |
| + recenters: {type: Boolean, value: false}, |
| + noink: {type: Boolean, value: false}, |
| + }, |
| + |
| + keyBindings: { |
| + 'enter:keydown': '_onEnterKeydown', |
| + 'space:keydown': '_onSpaceKeydown', |
| + 'space:keyup': '_onSpaceKeyup', |
| + }, |
| + |
| + /** @override */ |
| + created: function() { |
| + /** @type {Array<!Element>} */ |
| + this.ripples = []; |
| + }, |
| + |
| + /** @override */ |
| + attached: function() { |
| + this.keyEventTarget = this.parentNode.nodeType == 11 ? |
| + Polymer.dom(this).getOwnerRoot().host : this.parentNode; |
| + this.keyEventTarget = /** @type {!EventTarget} */ (this.keyEventTarget); |
| + this.listen(this.keyEventTarget, 'up', 'uiUpAction'); |
| + this.listen(this.keyEventTarget, 'down', 'uiDownAction'); |
| + }, |
| + |
| + /** @override */ |
| + detached: function() { |
| + this.unlisten(this.keyEventTarget, 'up', 'uiUpAction'); |
| + this.unlisten(this.keyEventTarget, 'down', 'uiDownAction'); |
| + this.keyEventTarget = null; |
| + }, |
| + |
| + simulatedRipple: function() { |
| + this.downAction(); |
| + // Using a 1ms delay ensures a macro-task. |
| + this.async(function() { this.upAction(); }.bind(this), 1); |
| + }, |
| + |
| + /** @param {Event=} e */ |
| + uiDownAction: function(e) { |
| + if (!this.noink) |
| + this.downAction(e); |
| + }, |
| + |
| + /** @param {Event=} e */ |
| + downAction: function(e) { |
| + if (this.ripples.length && this.holdDown) |
| + return; |
| + // TODO(dbeam): some things (i.e. paper-icon-button-light) dynamically |
| + // create ripples on 'up', Ripples register an event listener on their |
| + // parent (or shadow DOM host) when attached(). This sometimes causes |
| + // duplicate events to fire on us. |
| + this.debounce('show ripple', function() { this.__showRipple(e); }, 1); |
| + }, |
| + |
| + /** |
| + * @param {Event=} e |
| + * @private |
| + * @suppress {checkTypes} |
| + */ |
| + __showRipple: function(e) { |
| + var rect = this.getBoundingClientRect(); |
| + |
| + var roundedCenterX = function() { return Math.round(rect.width / 2); }; |
| + var roundedCenterY = function() { return Math.round(rect.height / 2); }; |
| + |
| + var centered = !e || this.center; |
| + if (centered) { |
| + var x = roundedCenterX(); |
| + var y = roundedCenterY(); |
| + } else { |
| + var sourceEvent = e.detail.sourceEvent; |
| + var x = Math.round(sourceEvent.clientX - rect.left); |
| + var y = Math.round(sourceEvent.clientY - rect.top); |
| } |
| - ElementMetrics.prototype = { |
| - get boundingRect () { |
| - return this.element.getBoundingClientRect(); |
| - }, |
| - |
| - furthestCornerDistanceFrom: function(x, y) { |
| - var topLeft = Utility.distance(x, y, 0, 0); |
| - var topRight = Utility.distance(x, y, this.width, 0); |
| - var bottomLeft = Utility.distance(x, y, 0, this.height); |
| - var bottomRight = Utility.distance(x, y, this.width, this.height); |
| + var corners = [ |
| + {x: 0, y: 0}, |
| + {x: rect.width, y: 0}, |
| + {x: 0, y: rect.height}, |
| + {x: rect.width, y: rect.height}, |
| + ]; |
| - return Math.max(topLeft, topRight, bottomLeft, bottomRight); |
| - } |
| - }; |
| - |
| - /** |
| - * @param {HTMLElement} element |
| - * @constructor |
| - */ |
| - function Ripple(element) { |
| - this.element = element; |
| - this.color = window.getComputedStyle(element).color; |
| + var cornerDistances = corners.map(function(corner) { |
| + return Math.round(distance(x, y, corner.x, corner.y)); |
| + }); |
| - this.wave = document.createElement('div'); |
| - this.waveContainer = document.createElement('div'); |
| - this.wave.style.backgroundColor = this.color; |
| - this.wave.classList.add('wave'); |
| - this.waveContainer.classList.add('wave-container'); |
| - Polymer.dom(this.waveContainer).appendChild(this.wave); |
| + var radius = Math.min(MAX_RADIUS_PX, Math.max.apply(Math, cornerDistances)); |
| - this.resetInteractionState(); |
| + var startTranslate = (x - radius) + 'px, ' + (y - radius) + 'px'; |
| + if (this.recenters && !centered) { |
| + var endTranslate = (roundedCenterX() - radius) + 'px, ' + |
| + (roundedCenterY() - radius) + 'px'; |
| + } else { |
| + var endTranslate = startTranslate; |
| } |
| - Ripple.MAX_RADIUS = 300; |
| - |
| - Ripple.prototype = { |
| - get recenters() { |
| - return this.element.recenters; |
| - }, |
| - |
| - get center() { |
| - return this.element.center; |
| - }, |
| - |
| - get mouseDownElapsed() { |
| - var elapsed; |
| - |
| - if (!this.mouseDownStart) { |
| - return 0; |
| - } |
| - |
| - elapsed = Utility.now() - this.mouseDownStart; |
| - |
| - if (this.mouseUpStart) { |
| - elapsed -= this.mouseUpElapsed; |
| - } |
| - |
| - return elapsed; |
| - }, |
| - |
| - get mouseUpElapsed() { |
| - return this.mouseUpStart ? |
| - Utility.now () - this.mouseUpStart : 0; |
| - }, |
| - |
| - get mouseDownElapsedSeconds() { |
| - return this.mouseDownElapsed / 1000; |
| - }, |
| - |
| - get mouseUpElapsedSeconds() { |
| - return this.mouseUpElapsed / 1000; |
| - }, |
| - |
| - get mouseInteractionSeconds() { |
| - return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds; |
| - }, |
| - |
| - get initialOpacity() { |
| - return this.element.initialOpacity; |
| - }, |
| - |
| - get opacityDecayVelocity() { |
| - return this.element.opacityDecayVelocity; |
| - }, |
| - |
| - get radius() { |
| - var width2 = this.containerMetrics.width * this.containerMetrics.width; |
| - var height2 = this.containerMetrics.height * this.containerMetrics.height; |
| - var waveRadius = Math.min( |
| - Math.sqrt(width2 + height2), |
| - Ripple.MAX_RADIUS |
| - ) * 1.1 + 5; |
| - |
| - var duration = 1.1 - 0.2 * (waveRadius / Ripple.MAX_RADIUS); |
| - var timeNow = this.mouseInteractionSeconds / duration; |
| - var size = waveRadius * (1 - Math.pow(80, -timeNow)); |
| - |
| - return Math.abs(size); |
| - }, |
| - |
| - get opacity() { |
| - if (!this.mouseUpStart) { |
| - return this.initialOpacity; |
| - } |
| - |
| - return Math.max( |
| - 0, |
| - this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVelocity |
| - ); |
| - }, |
| - |
| - get outerOpacity() { |
| - // Linear increase in background opacity, capped at the opacity |
| - // of the wavefront (waveOpacity). |
| - var outerOpacity = this.mouseUpElapsedSeconds * 0.3; |
| - var waveOpacity = this.opacity; |
| - |
| - return Math.max( |
| - 0, |
| - Math.min(outerOpacity, waveOpacity) |
| - ); |
| - }, |
| - |
| - get isOpacityFullyDecayed() { |
| - return this.opacity < 0.01 && |
| - this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS); |
| - }, |
| - |
| - get isRestingAtMaxRadius() { |
| - return this.opacity >= this.initialOpacity && |
| - this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS); |
| - }, |
| - |
| - get isAnimationComplete() { |
| - return this.mouseUpStart ? |
| - this.isOpacityFullyDecayed : this.isRestingAtMaxRadius; |
| - }, |
| - |
| - get translationFraction() { |
| - return Math.min( |
| - 1, |
| - this.radius / this.containerMetrics.size * 2 / Math.sqrt(2) |
| - ); |
| - }, |
| - |
| - get xNow() { |
| - if (this.xEnd) { |
| - return this.xStart + this.translationFraction * (this.xEnd - this.xStart); |
| - } |
| - |
| - return this.xStart; |
| - }, |
| - |
| - get yNow() { |
| - if (this.yEnd) { |
| - return this.yStart + this.translationFraction * (this.yEnd - this.yStart); |
| - } |
| - |
| - return this.yStart; |
| - }, |
| - |
| - get isMouseDown() { |
| - return this.mouseDownStart && !this.mouseUpStart; |
| - }, |
| - |
| - resetInteractionState: function() { |
| - this.maxRadius = 0; |
| - this.mouseDownStart = 0; |
| - this.mouseUpStart = 0; |
| - |
| - this.xStart = 0; |
| - this.yStart = 0; |
| - this.xEnd = 0; |
| - this.yEnd = 0; |
| - this.slideDistance = 0; |
| - |
| - this.containerMetrics = new ElementMetrics(this.element); |
| - }, |
| - |
| - draw: function() { |
| - var scale; |
| - var translateString; |
| - var dx; |
| - var dy; |
| - |
| - this.wave.style.opacity = this.opacity; |
| - |
| - scale = this.radius / (this.containerMetrics.size / 2); |
| - dx = this.xNow - (this.containerMetrics.width / 2); |
| - dy = this.yNow - (this.containerMetrics.height / 2); |
| - |
| - |
| - // 2d transform for safari because of border-radius and overflow:hidden clipping bug. |
| - // https://bugs.webkit.org/show_bug.cgi?id=98538 |
| - this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)'; |
| - this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)'; |
| - this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')'; |
| - this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)'; |
| - }, |
| - |
| - /** @param {Event=} event */ |
| - downAction: function(event) { |
| - var xCenter = this.containerMetrics.width / 2; |
| - var yCenter = this.containerMetrics.height / 2; |
| - |
| - this.resetInteractionState(); |
| - this.mouseDownStart = Utility.now(); |
| - |
| - if (this.center) { |
| - this.xStart = xCenter; |
| - this.yStart = yCenter; |
| - this.slideDistance = Utility.distance( |
| - this.xStart, this.yStart, this.xEnd, this.yEnd |
| - ); |
| - } else { |
| - this.xStart = event ? |
| - event.detail.x - this.containerMetrics.boundingRect.left : |
| - this.containerMetrics.width / 2; |
| - this.yStart = event ? |
| - event.detail.y - this.containerMetrics.boundingRect.top : |
| - this.containerMetrics.height / 2; |
| - } |
| - |
| - if (this.recenters) { |
| - this.xEnd = xCenter; |
| - this.yEnd = yCenter; |
| - this.slideDistance = Utility.distance( |
| - this.xStart, this.yStart, this.xEnd, this.yEnd |
| - ); |
| - } |
| - |
| - this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom( |
| - this.xStart, |
| - this.yStart |
| - ); |
| - |
| - this.waveContainer.style.top = |
| - (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px'; |
| - this.waveContainer.style.left = |
| - (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px'; |
| - |
| - this.waveContainer.style.width = this.containerMetrics.size + 'px'; |
| - this.waveContainer.style.height = this.containerMetrics.size + 'px'; |
| - }, |
| - |
| - /** @param {Event=} event */ |
| - upAction: function(event) { |
| - if (!this.isMouseDown) { |
| - return; |
| - } |
| - |
| - this.mouseUpStart = Utility.now(); |
| - }, |
| - |
| - remove: function() { |
| - Polymer.dom(this.waveContainer.parentNode).removeChild( |
| - this.waveContainer |
| - ); |
| - } |
| - }; |
| - |
| - Polymer({ |
| - is: 'paper-ripple', |
| - |
| - behaviors: [ |
| - Polymer.IronA11yKeysBehavior |
| - ], |
| - |
| - properties: { |
| - /** |
| - * The initial opacity set on the wave. |
| - * |
| - * @attribute initialOpacity |
| - * @type number |
| - * @default 0.25 |
| - */ |
| - initialOpacity: { |
| - type: Number, |
| - value: 0.25 |
| - }, |
| - |
| - /** |
| - * How fast (opacity per second) the wave fades out. |
| - * |
| - * @attribute opacityDecayVelocity |
| - * @type number |
| - * @default 0.8 |
| - */ |
| - opacityDecayVelocity: { |
| - type: Number, |
| - value: 0.8 |
| - }, |
| - |
| - /** |
| - * If true, ripples will exhibit a gravitational pull towards |
| - * the center of their container as they fade away. |
| - * |
| - * @attribute recenters |
| - * @type boolean |
| - * @default false |
| - */ |
| - recenters: { |
| - type: Boolean, |
| - value: false |
| - }, |
| - |
| - /** |
| - * If true, ripples will center inside its container |
| - * |
| - * @attribute recenters |
| - * @type boolean |
| - * @default false |
| - */ |
| - center: { |
| - type: Boolean, |
| - value: false |
| - }, |
| - |
| - /** |
| - * A list of the visual ripples. |
| - * |
| - * @attribute ripples |
| - * @type Array |
| - * @default [] |
| - */ |
| - ripples: { |
| - type: Array, |
| - value: function() { |
| - return []; |
| - } |
| - }, |
| - |
| - /** |
| - * True when there are visible ripples animating within the |
| - * element. |
| - */ |
| - animating: { |
| - type: Boolean, |
| - readOnly: true, |
| - reflectToAttribute: true, |
| - value: false |
| - }, |
| - |
| - /** |
| - * If true, the ripple will remain in the "down" state until `holdDown` |
| - * is set to false again. |
| - */ |
| - holdDown: { |
| - type: Boolean, |
| - value: false, |
| - observer: '_holdDownChanged' |
| - }, |
| - |
| - /** |
| - * If true, the ripple will not generate a ripple effect |
| - * via pointer interaction. |
| - * Calling ripple's imperative api like `simulatedRipple` will |
| - * still generate the ripple effect. |
| - */ |
| - noink: { |
| - type: Boolean, |
| - value: false |
| - }, |
| - |
| - _animating: { |
| - type: Boolean |
| - }, |
| - |
| - _boundAnimate: { |
| - type: Function, |
| - value: function() { |
| - return this.animate.bind(this); |
| - } |
| - } |
| - }, |
| - |
| - get target () { |
| - return this.keyEventTarget; |
| - }, |
| - |
| - keyBindings: { |
| - 'enter:keydown': '_onEnterKeydown', |
| - 'space:keydown': '_onSpaceKeydown', |
| - 'space:keyup': '_onSpaceKeyup' |
| - }, |
| - |
| - attached: function() { |
| - // Set up a11yKeysBehavior to listen to key events on the target, |
| - // so that space and enter activate the ripple even if the target doesn't |
| - // handle key events. The key handlers deal with `noink` themselves. |
| - if (this.parentNode.nodeType == 11) { // DOCUMENT_FRAGMENT_NODE |
| - this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host; |
| - } else { |
| - this.keyEventTarget = this.parentNode; |
| - } |
| - var keyEventTarget = /** @type {!EventTarget} */ (this.keyEventTarget); |
| - this.listen(keyEventTarget, 'up', 'uiUpAction'); |
| - this.listen(keyEventTarget, 'down', 'uiDownAction'); |
| - }, |
| - |
| - detached: function() { |
| - this.unlisten(this.keyEventTarget, 'up', 'uiUpAction'); |
| - this.unlisten(this.keyEventTarget, 'down', 'uiDownAction'); |
| - this.keyEventTarget = null; |
| - }, |
| - |
| - get shouldKeepAnimating () { |
| - for (var index = 0; index < this.ripples.length; ++index) { |
| - if (!this.ripples[index].isAnimationComplete) { |
| - return true; |
| - } |
| - } |
| - |
| - return false; |
| - }, |
| - |
| - simulatedRipple: function() { |
| - this.downAction(null); |
| - |
| - // Please see polymer/polymer#1305 |
| - this.async(function() { |
| - this.upAction(); |
| - }, 1); |
| - }, |
| - |
| - /** |
| - * Provokes a ripple down effect via a UI event, |
| - * respecting the `noink` property. |
| - * @param {Event=} event |
| - */ |
| - uiDownAction: function(event) { |
| - if (!this.noink) { |
| - this.downAction(event); |
| - } |
| - }, |
| - |
| - /** |
| - * Provokes a ripple down effect via a UI event, |
| - * *not* respecting the `noink` property. |
| - * @param {Event=} event |
| - */ |
| - downAction: function(event) { |
| - if (this.holdDown && this.ripples.length > 0) { |
| - return; |
| - } |
| - |
| - var ripple = this.addRipple(); |
| - |
| - ripple.downAction(event); |
| - |
| - if (!this._animating) { |
| - this._animating = true; |
| - this.animate(); |
| - } |
| - }, |
| - |
| - /** |
| - * Provokes a ripple up effect via a UI event, |
| - * respecting the `noink` property. |
| - * @param {Event=} event |
| - */ |
| - uiUpAction: function(event) { |
| - if (!this.noink) { |
| - this.upAction(event); |
| - } |
| - }, |
| - |
| - /** |
| - * Provokes a ripple up effect via a UI event, |
| - * *not* respecting the `noink` property. |
| - * @param {Event=} event |
| - */ |
| - upAction: function(event) { |
| - if (this.holdDown) { |
| - return; |
| - } |
| - |
| - this.ripples.forEach(function(ripple) { |
| - ripple.upAction(event); |
| - }); |
| - |
| - this._animating = true; |
| - this.animate(); |
| - }, |
| - |
| - onAnimationComplete: function() { |
| - this._animating = false; |
| - this.$.background.style.backgroundColor = null; |
| - this.fire('transitionend'); |
| - }, |
| - |
| - addRipple: function() { |
| - var ripple = new Ripple(this); |
| - |
| - Polymer.dom(this.$.waves).appendChild(ripple.waveContainer); |
| - this.$.background.style.backgroundColor = ripple.color; |
| - this.ripples.push(ripple); |
| - |
| - this._setAnimating(true); |
| - |
| - return ripple; |
| - }, |
| - |
| - removeRipple: function(ripple) { |
| - var rippleIndex = this.ripples.indexOf(ripple); |
| - |
| - if (rippleIndex < 0) { |
| - return; |
| - } |
| - |
| - this.ripples.splice(rippleIndex, 1); |
| - |
| - ripple.remove(); |
| - |
| - if (!this.ripples.length) { |
| - this._setAnimating(false); |
| - } |
| - }, |
| - |
| - /** |
| - * This conflicts with Element#antimate(). |
| - * https://developer.mozilla.org/en-US/docs/Web/API/Element/animate |
| - * @suppress {checkTypes} |
| - */ |
| - animate: function() { |
|
Dan Beam
2017/02/23 05:50:23
see here ^
|
| - if (!this._animating) { |
| - return; |
| - } |
| - var index; |
| - var ripple; |
| - |
| - for (index = 0; index < this.ripples.length; ++index) { |
| - ripple = this.ripples[index]; |
| - |
| - ripple.draw(); |
| - |
| - this.$.background.style.opacity = ripple.outerOpacity; |
| - |
| - if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) { |
| - this.removeRipple(ripple); |
| - } |
| - } |
| - |
| - if (!this.shouldKeepAnimating && this.ripples.length === 0) { |
| - this.onAnimationComplete(); |
| - } else { |
| - window.requestAnimationFrame(this._boundAnimate); |
| - } |
| - }, |
| - |
| - _onEnterKeydown: function() { |
| - this.uiDownAction(); |
| - this.async(this.uiUpAction, 1); |
| - }, |
| - |
| - _onSpaceKeydown: function() { |
| - this.uiDownAction(); |
| - }, |
| - |
| - _onSpaceKeyup: function() { |
| - this.uiUpAction(); |
| - }, |
| - |
| - // note: holdDown does not respect noink since it can be a focus based |
| - // effect. |
| - _holdDownChanged: function(newVal, oldVal) { |
| - if (oldVal === undefined) { |
| - return; |
| - } |
| - if (newVal) { |
| - this.downAction(); |
| - } else { |
| - this.upAction(); |
| - } |
| - } |
| - |
| - /** |
| - Fired when the animation finishes. |
| - This is useful if you want to wait until |
| - the ripple animation finishes to perform some action. |
| - |
| - @event transitionend |
| - @param {{node: Object}} detail Contains the animated node. |
| - */ |
| + var ripple = document.createElement('div'); |
| + ripple.classList.add('ripple'); |
| + ripple.style.height = ripple.style.width = (2 * radius) + 'px'; |
| + |
| + this.ripples.push(ripple); |
| + this.shadowRoot.appendChild(ripple); |
| + |
| + ripple.animate({ |
| + // TODO(dbeam): scale to 90% of radius at .75 offset? |
| + transform: ['translate(' + startTranslate + ') scale(0)', |
| + 'translate(' + endTranslate + ') scale(1)'], |
| + }, { |
| + duration: Math.max(MIN_DURATION_MS, Math.log(radius) * radius), |
| + easing: 'cubic-bezier(.2, .9, .1, .9)', |
| + fill: 'forwards', |
| + }); |
| + }, |
| + |
| + /** @param {Event=} e */ |
| + uiUpAction: function(e) { |
| + if (!this.noink) |
| + this.upAction(); |
| + }, |
| + |
| + /** @param {Event=} e */ |
| + upAction: function(e) { |
| + if (!this.holdDown) |
| + this.debounce('hide ripple', function() { this.__hideRipple(); }, 1); |
| + }, |
| + |
| + /** |
| + * @private |
| + * @suppress {checkTypes} |
| + */ |
| + __hideRipple: function() { |
| + this.ripples.forEach(function(ripple) { |
| + var animation = ripple.animate({ |
| + opacity: [getComputedStyle(ripple).opacity, 0], |
| + }, { |
| + duration: 150, |
| + fill: 'forwards', |
| + }); |
| + // TODO(dbeam): should we be firing a transitionend event here? Does |
| + // anybody actually use it? It's in the original paper-ripple. |
| + var removeRipple = function() { ripple.remove(); }; |
| + animation.addEventListener('finish', removeRipple); |
| + animation.addEventListener('cancel', removeRipple); |
| }); |
| - })(); |
| + this.ripples = []; |
| + }, |
| + |
| + /** @protected */ |
| + _onEnterKeydown: function() { |
| + this.uiDownAction(); |
| + this.async(this.uiUpAction, 1); |
| + }, |
| + |
| + /** @protected */ |
| + _onSpaceKeydown: function() { |
| + this.uiDownAction(); |
| + }, |
| + |
| + /** @protected */ |
| + _onSpaceKeyup: function() { |
| + this.uiUpAction(); |
| + }, |
| + |
| + /** @protected */ |
| + _holdDownChanged: function(newHoldDown, oldHoldDown) { |
| + if (oldHoldDown === undefined) |
| + return; |
| + if (newHoldDown) |
| + this.downAction(); |
| + else |
| + this.upAction(); |
| + }, |
| +}); |
| + |
| +})(); |