From 58dacef8ba11a57b74688887bb81e937cce037ec Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 2 Mar 2017 12:02:04 +0100 Subject: [PATCH 1/2] feat(ripple): add way to globally disable ripples * Currently ripples can be only disable component-wise. This isn't very elegant if users want to disable ripples for all components. * This commit introduces a new `OpaqueToken`/ `InjectionToken` that can be used to globally disable all ripples. * Makes the `tab-nav-bar` ripple directive more clean. Since Angular v2.3.0 (as we recently upgraded) the inherited metadata can be used. For upcoming accessibility features (focus indicators) we don't want to allow developers to disable programmatic ripples. --- src/lib/core/ripple/index.ts | 2 +- src/lib/core/ripple/ripple.spec.ts | 48 +++++++++++++++++++++++-- src/lib/core/ripple/ripple.ts | 11 ++++-- src/lib/tabs/tab-nav-bar/tab-nav-bar.ts | 9 +---- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/lib/core/ripple/index.ts b/src/lib/core/ripple/index.ts index 45dea58ec64f..075ac021e9c2 100644 --- a/src/lib/core/ripple/index.ts +++ b/src/lib/core/ripple/index.ts @@ -4,7 +4,7 @@ import {CompatibilityModule} from '../compatibility/compatibility'; import {VIEWPORT_RULER_PROVIDER} from '../overlay/position/viewport-ruler'; import {SCROLL_DISPATCHER_PROVIDER} from '../overlay/scroll/scroll-dispatcher'; -export {MdRipple} from './ripple'; +export {MdRipple, MD_RIPPLES_DISABLE} from './ripple'; export {RippleRef, RippleState} from './ripple-ref'; export {RippleConfig} from './ripple-renderer'; diff --git a/src/lib/core/ripple/ripple.spec.ts b/src/lib/core/ripple/ripple.spec.ts index 6db9435fdd0a..ac3b8dfbdedb 100644 --- a/src/lib/core/ripple/ripple.spec.ts +++ b/src/lib/core/ripple/ripple.spec.ts @@ -1,6 +1,6 @@ import {TestBed, ComponentFixture, fakeAsync, tick, inject} from '@angular/core/testing'; import {Component, ViewChild} from '@angular/core'; -import {MdRipple, MdRippleModule, RippleState} from './index'; +import {MdRipple, MdRippleModule, MD_RIPPLES_DISABLE, RippleState} from './index'; import {ViewportRuler} from '../overlay/position/viewport-ruler'; import {RIPPLE_FADE_OUT_DURATION, RIPPLE_FADE_IN_DURATION} from './ripple-renderer'; import {dispatchMouseEvent} from '../testing/dispatch-events'; @@ -18,7 +18,7 @@ describe('MdRipple', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MdRippleModule.forRoot()], + imports: [MdRippleModule], declarations: [ BasicRippleContainer, RippleContainerWithInputBindings, @@ -346,6 +346,50 @@ describe('MdRipple', () => { }); + describe('with ripples disabled', () => { + let rippleDirective: MdRipple; + + beforeEach(() => { + // Reset the previously configured testing module to be able to disable ripples globally. + // The testing module has been initialized in the root describe group for the ripples. + TestBed.resetTestingModule(); + TestBed.configureTestingModule({ + imports: [MdRippleModule], + declarations: [BasicRippleContainer], + providers: [{ provide: MD_RIPPLES_DISABLE, useValue: true }] + }); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(BasicRippleContainer); + fixture.detectChanges(); + + rippleTarget = fixture.nativeElement.querySelector('[mat-ripple]'); + rippleDirective = fixture.componentInstance.ripple; + }); + + it('should not show any ripples on mousedown', () => { + dispatchMouseEvent(rippleTarget, 'mousedown'); + dispatchMouseEvent(rippleTarget, 'mouseup'); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + + dispatchMouseEvent(rippleTarget, 'mousedown'); + dispatchMouseEvent(rippleTarget, 'mouseup'); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + }); + + it('should still allow manual ripples', () => { + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + + rippleDirective.launch(0, 0); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); + }); + + }); + describe('configuring behavior', () => { let controller: RippleContainerWithInputBindings; let rippleComponent: MdRipple; diff --git a/src/lib/core/ripple/ripple.ts b/src/lib/core/ripple/ripple.ts index 5218e7e75e94..14e8b1c2d348 100644 --- a/src/lib/core/ripple/ripple.ts +++ b/src/lib/core/ripple/ripple.ts @@ -2,15 +2,20 @@ import { Directive, ElementRef, Input, + Inject, NgZone, OnChanges, SimpleChanges, OnDestroy, + OpaqueToken, + Optional, } from '@angular/core'; import {RippleConfig, RippleRenderer} from './ripple-renderer'; import {ViewportRuler} from '../overlay/position/viewport-ruler'; import {RippleRef} from './ripple-ref'; +/** OpaqueToken that can be used to globally disable all ripples. Except programmatic ones. */ +export const MD_RIPPLES_DISABLE = new OpaqueToken('md-ripples-disable'); @Directive({ selector: '[md-ripple], [mat-ripple]', @@ -65,7 +70,9 @@ export class MdRipple implements OnChanges, OnDestroy { /** Renderer for the ripple DOM manipulations. */ private _rippleRenderer: RippleRenderer; - constructor(elementRef: ElementRef, ngZone: NgZone, ruler: ViewportRuler) { + constructor(elementRef: ElementRef, ngZone: NgZone, ruler: ViewportRuler, + @Optional() @Inject(MD_RIPPLES_DISABLE) private _forceDisableRipples: boolean) { + this._rippleRenderer = new RippleRenderer(elementRef, ngZone, ruler); } @@ -74,7 +81,7 @@ export class MdRipple implements OnChanges, OnDestroy { this._rippleRenderer.setTriggerElement(this.trigger); } - this._rippleRenderer.rippleDisabled = this.disabled; + this._rippleRenderer.rippleDisabled = this._forceDisableRipples || this.disabled; this._rippleRenderer.rippleConfig = this.rippleConfig; } diff --git a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts index 930f8a9a2f1e..5a0968b36f7f 100644 --- a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts @@ -5,11 +5,9 @@ import { ElementRef, ViewEncapsulation, Directive, - NgZone, } from '@angular/core'; import {MdInkBar} from '../ink-bar'; import {MdRipple} from '../../core/ripple/index'; -import {ViewportRuler} from '../../core/overlay/position/viewport-ruler'; /** * Navigation component matching the styles of the tab group header. @@ -81,9 +79,4 @@ export class MdTabLink { '[class.mat-tab-link]': 'true', }, }) -export class MdTabLinkRipple extends MdRipple { - constructor(elementRef: ElementRef, ngZone: NgZone, ruler: ViewportRuler) { - super(elementRef, ngZone, ruler); - } - -} +export class MdTabLinkRipple extends MdRipple {} From f4df111b1c64de217fb93cf3cec9be4ef5cee18c Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 2 Mar 2017 18:46:41 +0100 Subject: [PATCH 2/2] Rename token to `MD_DISABLE_RIPPLES` --- src/lib/core/ripple/index.ts | 2 +- src/lib/core/ripple/ripple.spec.ts | 4 ++-- src/lib/core/ripple/ripple.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/core/ripple/index.ts b/src/lib/core/ripple/index.ts index 075ac021e9c2..aab611db0302 100644 --- a/src/lib/core/ripple/index.ts +++ b/src/lib/core/ripple/index.ts @@ -4,7 +4,7 @@ import {CompatibilityModule} from '../compatibility/compatibility'; import {VIEWPORT_RULER_PROVIDER} from '../overlay/position/viewport-ruler'; import {SCROLL_DISPATCHER_PROVIDER} from '../overlay/scroll/scroll-dispatcher'; -export {MdRipple, MD_RIPPLES_DISABLE} from './ripple'; +export {MdRipple, MD_DISABLE_RIPPLES} from './ripple'; export {RippleRef, RippleState} from './ripple-ref'; export {RippleConfig} from './ripple-renderer'; diff --git a/src/lib/core/ripple/ripple.spec.ts b/src/lib/core/ripple/ripple.spec.ts index ac3b8dfbdedb..330da08fea53 100644 --- a/src/lib/core/ripple/ripple.spec.ts +++ b/src/lib/core/ripple/ripple.spec.ts @@ -1,6 +1,6 @@ import {TestBed, ComponentFixture, fakeAsync, tick, inject} from '@angular/core/testing'; import {Component, ViewChild} from '@angular/core'; -import {MdRipple, MdRippleModule, MD_RIPPLES_DISABLE, RippleState} from './index'; +import {MdRipple, MdRippleModule, MD_DISABLE_RIPPLES, RippleState} from './index'; import {ViewportRuler} from '../overlay/position/viewport-ruler'; import {RIPPLE_FADE_OUT_DURATION, RIPPLE_FADE_IN_DURATION} from './ripple-renderer'; import {dispatchMouseEvent} from '../testing/dispatch-events'; @@ -356,7 +356,7 @@ describe('MdRipple', () => { TestBed.configureTestingModule({ imports: [MdRippleModule], declarations: [BasicRippleContainer], - providers: [{ provide: MD_RIPPLES_DISABLE, useValue: true }] + providers: [{ provide: MD_DISABLE_RIPPLES, useValue: true }] }); }); diff --git a/src/lib/core/ripple/ripple.ts b/src/lib/core/ripple/ripple.ts index 14e8b1c2d348..844cf20144b7 100644 --- a/src/lib/core/ripple/ripple.ts +++ b/src/lib/core/ripple/ripple.ts @@ -15,7 +15,7 @@ import {ViewportRuler} from '../overlay/position/viewport-ruler'; import {RippleRef} from './ripple-ref'; /** OpaqueToken that can be used to globally disable all ripples. Except programmatic ones. */ -export const MD_RIPPLES_DISABLE = new OpaqueToken('md-ripples-disable'); +export const MD_DISABLE_RIPPLES = new OpaqueToken('md-disable-ripples'); @Directive({ selector: '[md-ripple], [mat-ripple]', @@ -71,7 +71,7 @@ export class MdRipple implements OnChanges, OnDestroy { private _rippleRenderer: RippleRenderer; constructor(elementRef: ElementRef, ngZone: NgZone, ruler: ViewportRuler, - @Optional() @Inject(MD_RIPPLES_DISABLE) private _forceDisableRipples: boolean) { + @Optional() @Inject(MD_DISABLE_RIPPLES) private _forceDisableRipples: boolean) { this._rippleRenderer = new RippleRenderer(elementRef, ngZone, ruler); }