Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/lib/core/ripple/ripple-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {RippleConfig, RippleRenderer} from './ripple-renderer';
*/
export class RippleRef {

/** Whether the ripple finished it's fade-in animation. */
fadedIn: boolean = false;
Copy link
Member

@crisbeto crisbeto Mar 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be more flexible to have this as a string (custom type) along the lines of state? That way we can expand it later to check for other cases, if we need to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sounds like a good idea. Made the changes. Please take another look!


constructor(
private _renderer: RippleRenderer,
public element: HTMLElement,
Expand Down
20 changes: 13 additions & 7 deletions src/lib/core/ripple/ripple-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ export class RippleRenderer {
// Exposed reference to the ripple that will be returned.
let rippleRef = new RippleRef(this, ripple, config);

// Add the ripple reference to the list of all active ripples.
this._activeRipples.add(rippleRef);

// Wait for the ripple element to be completely faded in.
// Once it's faded in, the ripple can be hidden immediately if the mouse is released.
this.runTimeoutOutsideZone(() => {
if (config.persistent || this._isMousedown) {
this._activeRipples.add(rippleRef);
} else {
rippleRef.fadedIn = true;

if (!config.persistent && !this._isMousedown) {
rippleRef.fadeOut();
}
}, duration);
Expand All @@ -116,9 +119,12 @@ export class RippleRenderer {

/** Fades out a ripple reference. */
fadeOutRipple(ripple: RippleRef) {
let rippleEl = ripple.element;
// For ripples that are not active anymore, don't re-un the fade-out animation.
if (!this._activeRipples.delete(ripple)) {
return;
}

this._activeRipples.delete(ripple);
let rippleEl = ripple.element;

rippleEl.style.transitionDuration = `${RIPPLE_FADE_OUT_DURATION}ms`;
rippleEl.style.opacity = '0';
Expand Down Expand Up @@ -163,9 +169,9 @@ export class RippleRenderer {
private onMouseup() {
this._isMousedown = false;

// On mouseup, fade-out all ripples that are active and not persistent.
// Fade-out all ripples that are completely faded-in and not persistent.
this._activeRipples.forEach(ripple => {
if (!ripple.config.persistent) {
if (!ripple.config.persistent && ripple.fadedIn) {
ripple.fadeOut();
}
});
Expand Down
50 changes: 50 additions & 0 deletions src/lib/core/ripple/ripple.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,39 @@ describe('MdRipple', () => {
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
}));

it('should remove ripples after mouseup', fakeAsync(() => {
dispatchMouseEvent(rippleTarget, 'mousedown');

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);

// Fakes the duration of fading-in and fading-out normal ripples.
// The fade-out duration has been added to ensure that didn't start fading out.
tick(RIPPLE_FADE_IN_DURATION + RIPPLE_FADE_OUT_DURATION);

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);

dispatchMouseEvent(rippleTarget, 'mouseup');
tick(RIPPLE_FADE_OUT_DURATION);

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
}));

it('should not hide ripples while animating.', fakeAsync(() => {
// Calculates the duration for fading-in and fading-out the ripple.
let hideDuration = RIPPLE_FADE_IN_DURATION + RIPPLE_FADE_OUT_DURATION;

dispatchMouseEvent(rippleTarget, 'mousedown');
dispatchMouseEvent(rippleTarget, 'mouseup');

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);

tick(hideDuration - 10);
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);

tick(10);
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
}));

it('creates ripples when manually triggered', () => {
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);

Expand Down Expand Up @@ -270,6 +303,23 @@ describe('MdRipple', () => {
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
}));

it('should remove ripples that are not done fading-in', fakeAsync(() => {
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);

rippleDirective.launch(0, 0);

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);

tick(RIPPLE_FADE_IN_DURATION / 2);

rippleDirective.fadeOutAll();

tick(RIPPLE_FADE_OUT_DURATION);

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
.toBe(0, 'Expected no ripples to be active after calling fadeOutAll.');
}));

});

describe('configuring behavior', () => {
Expand Down