diff --git a/ng2-material/components/backdrop/backdrop.ts b/ng2-material/components/backdrop/backdrop.ts index 4ec2294c..d65673ad 100644 --- a/ng2-material/components/backdrop/backdrop.ts +++ b/ng2-material/components/backdrop/backdrop.ts @@ -9,11 +9,14 @@ import {Output} from "angular2/core"; import {EventEmitter} from "angular2/core"; /** - * A transparent overlay for content on the page. + * An overlay for content on the page. + * Can optionally dismiss when clicked on. + * Has outputs for show/showing and hide/hiding. */ @Component({ selector: 'md-backdrop', host: { + 'class': 'md-backdrop', '(click)': 'onClick()', }, }) @@ -51,13 +54,22 @@ export class MdBackdrop { @Output() onShown: EventEmitter<MdBackdrop> = new EventEmitter<MdBackdrop>(); - constructor(public element: ElementRef) { } + /** + * The CSS class name to transition on/off when the backdrop is hidden/shown. + */ + @Input() + public transitionClass: string = 'md-active'; + + /** + * Whether to add the {@see transitionClass} or remove it when the backdrop is shown. The + * opposite will happen when the backdrop is hidden. + */ + @Input() + public transitionAddClass = true; - private _visible: boolean = false; - private _transitioning: boolean = false; /** * Read-only property indicating whether the backdrop is visible or not. @@ -66,6 +78,9 @@ export class MdBackdrop { return this._visible; } + private _visible: boolean = false; + private _transitioning: boolean = false; + onClick() { if (this.clickClose && !this._transitioning && this.visible) { this.hide(); @@ -83,7 +98,8 @@ export class MdBackdrop { this._visible = true; this._transitioning = true; this.onShowing.emit(this); - return Animate.enter(this.element.nativeElement, 'md-active').then(() => { + let action = this.transitionAddClass ? Animate.enter : Animate.leave; + return action(this.element.nativeElement, this.transitionClass).then(() => { this._transitioning = false; this.onShown.emit(this); }); @@ -100,7 +116,8 @@ export class MdBackdrop { this._visible = false; this._transitioning = true; this.onHiding.emit(this); - return Animate.leave(this.element.nativeElement, 'md-active').then(() => { + let action = this.transitionAddClass ? Animate.leave : Animate.enter; + return action(this.element.nativeElement, this.transitionClass).then(() => { this._transitioning = false; this.onHidden.emit(this); }); diff --git a/test/components/backdrop/backdrop_spec.ts b/test/components/backdrop/backdrop_spec.ts index faa301f0..2de8ec67 100644 --- a/test/components/backdrop/backdrop_spec.ts +++ b/test/components/backdrop/backdrop_spec.ts @@ -17,6 +17,7 @@ import {ComponentFixture} from "angular2/testing"; import {MdBackdrop} from "../../../ng2-material/components/backdrop/backdrop"; import {TimerWrapper} from "angular2/src/facade/async"; import {By} from 'angular2/platform/browser'; +import {DOM} from "angular2/src/platform/dom/dom_adapter"; export function main() { @@ -37,13 +38,16 @@ export function main() { describe('Backdrop', () => { let builder: TestComponentBuilder; - function setup(show: boolean = false): Promise<IBackdropFixture> { - let result = {}; - return builder.createAsync(TestComponent) + function setup(show: boolean = false, transitionAddClass: boolean = true): Promise<IBackdropFixture> { + return new Promise<IBackdropFixture>((resolve, reject) => { + TimerWrapper.setTimeout(() => { + let result:IBackdropFixture = null; + builder.createAsync(TestComponent) .then((fixture: ComponentFixture) => { - fixture.detectChanges(); let debug = fixture.debugElement.query(By.css('md-backdrop')); let backdrop = <MdBackdrop>debug.componentInstance; + backdrop.transitionAddClass = transitionAddClass; + fixture.detectChanges(); result = { fixture: fixture, debug: debug, @@ -53,8 +57,10 @@ export function main() { return backdrop.show(); } }) - .then(() => result) - .catch(console.error.bind(console)); + .then(() => resolve(result)) + .catch((e) => reject(e)); + }, 10); + }); } @@ -67,6 +73,51 @@ export function main() { })); describe('md-backdrop', () => { + + describe('transitionClass', () => { + it('should be added to classList when shown', inject([AsyncTestCompleter], (async) => { + setup(true).then((api: IBackdropFixture) => { + let el = api.debug.elementRef.nativeElement; + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(true); + async.done(); + }); + })); + it('should be removed from classList when hidden', inject([AsyncTestCompleter], (async) => { + setup(true).then((api: IBackdropFixture) => { + let el = api.debug.elementRef.nativeElement; + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(true); + api.backdrop.hide().then(() => { + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(false); + async.done(); + }); + }); + })); + }); + + describe('transitionAddClass=false', () => { + it('should remove transitionClass when shown', inject([AsyncTestCompleter], (async) => { + setup(false, false).then((api: IBackdropFixture) => { + let el = api.debug.elementRef.nativeElement; + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(false); + DOM.addClass(el, api.backdrop.transitionClass); + api.backdrop.show().then(() => { + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(false); + async.done(); + }); + }); + })); + it('should add transitionClass when hidden', inject([AsyncTestCompleter], (async) => { + setup(true, false).then((api: IBackdropFixture) => { + let el = api.debug.elementRef.nativeElement; + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(false); + api.backdrop.hide().then(() => { + expect(DOM.hasClass(el, api.backdrop.transitionClass)).toBe(true); + async.done(); + }); + }); + })); + }); + describe('clickClose', () => { it('should be hidden by a click when true', inject([AsyncTestCompleter], (async) => { setup(true).then((api: IBackdropFixture) => {