- {{method.name}}
-
+ {{method.name}}
+
Signature: {{ methodSignature(method) }}
Return type: {{ method.returnType }}
diff --git a/demo/src/app/api-docs/api-doc-config/api-doc-config.component.html b/demo/src/app/api-docs/api-doc-config/api-doc-config.component.html
index eb72f4e290..1a6433da1a 100644
--- a/demo/src/app/api-docs/api-doc-config/api-doc-config.component.html
+++ b/demo/src/app/api-docs/api-doc-config/api-doc-config.component.html
@@ -10,8 +10,8 @@
- {{prop.name}}
-
+ {{prop.name}}
+
Type: {{ prop.type }}
Default value: {{prop.defaultValue || '-'}}
diff --git a/demo/src/app/api-docs/api-doc/api-doc.component.html b/demo/src/app/api-docs/api-doc/api-doc.component.html
index 4e489712b8..e7c4ac2956 100644
--- a/demo/src/app/api-docs/api-doc/api-doc.component.html
+++ b/demo/src/app/api-docs/api-doc/api-doc.component.html
@@ -6,12 +6,12 @@
- Selector
- {{apiDocs.selector}}
+ Selector
+ {{apiDocs.selector}}
- Exported as
- {{apiDocs.exportAs}}
+ Exported as
+ {{apiDocs.exportAs}}
@@ -22,8 +22,8 @@
- {{input.name}}
-
+ {{input.name}}
+
Type: {{ input.type }}
@@ -45,8 +45,8 @@
Outputs
- {{output.name}}
-
+ {{output.name}}
+
@@ -59,8 +59,8 @@
Methods
- {{method.name}}
-
+ {{method.name}}
+
Signature: {{ methodSignature(method) }}
Return type: {{ method.returnType }}
diff --git a/demo/src/app/components/carousel/demos/dynamic/dynamic.html b/demo/src/app/components/carousel/demos/dynamic/dynamic.html
index 0851f4550e..52f6c0f0f1 100644
--- a/demo/src/app/components/carousel/demos/dynamic/dynamic.html
+++ b/demo/src/app/components/carousel/demos/dynamic/dynamic.html
@@ -8,7 +8,8 @@ Slide {{index}}
-
+
+
Add Slide
@@ -18,12 +19,12 @@
Slide {{index}}
Remove #3
-
-
+
+
diff --git a/demo/src/app/components/datepicker/demos/index.ts b/demo/src/app/components/datepicker/demos/index.ts
index b1fd614744..f79477a5f8 100644
--- a/demo/src/app/components/datepicker/demos/index.ts
+++ b/demo/src/app/components/datepicker/demos/index.ts
@@ -6,7 +6,7 @@ export const DEMO_COMPONENTS = [
export const DEMOS = {
old: {
- component: require('!!raw?lang=typescript!./datepicker-demo.component.html'),
- html: require('!!raw?lang=markup!./datepicker-demo.component')
+ component: require('!!raw?lang=typescript!./datepicker-demo.component.ts'),
+ html: require('!!raw?lang=markup!./datepicker-demo.component.html')
}
};
diff --git a/demo/src/app/components/dropdown/todo.md b/demo/src/app/components/dropdown/todo.md
index ab88564611..f1f3047cb8 100644
--- a/demo/src/app/components/dropdown/todo.md
+++ b/demo/src/app/components/dropdown/todo.md
@@ -9,3 +9,9 @@
- disabled menu items
- manual
- config
+
++ config:
+ /** if true dropdown will be initially opened */
+ public isOpen:boolean = false;
++ config dropup
++ fix append to body
diff --git a/demo/src/app/components/modal/demos/child/child.html b/demo/src/app/components/modal/demos/child/child.html
index 199203e03b..52b503597e 100644
--- a/demo/src/app/components/modal/demos/child/child.html
+++ b/demo/src/app/components/modal/demos/child/child.html
@@ -3,10 +3,10 @@
I am a child modal, opened from parent component!
diff --git a/demo/src/app/components/modal/demos/sizes/sizes.html b/demo/src/app/components/modal/demos/sizes/sizes.html
index c241a98e71..d802d866d6 100644
--- a/demo/src/app/components/modal/demos/sizes/sizes.html
+++ b/demo/src/app/components/modal/demos/sizes/sizes.html
@@ -5,10 +5,10 @@
...
@@ -25,10 +25,10 @@
Large modal
...
diff --git a/demo/src/app/components/modal/demos/static/static.html b/demo/src/app/components/modal/demos/static/static.html
index 1d1590ad10..60bce5c644 100644
--- a/demo/src/app/components/modal/demos/static/static.html
+++ b/demo/src/app/components/modal/demos/static/static.html
@@ -5,10 +5,10 @@
This is static modal, backdrop click will not close it.
diff --git a/demo/src/app/components/todo.md b/demo/src/app/components/todo.md
index bc7881a54d..5be5f5787b 100644
--- a/demo/src/app/components/todo.md
+++ b/demo/src/app/components/todo.md
@@ -10,7 +10,7 @@ for all add support of:
+ add input config
+ forms integration
+ mobile events
-+ theming
++ theming (it blocks bs4 testing)
+ breadcrumb
+ scrollspy
diff --git a/src/carousel/carousel.component.ts b/src/carousel/carousel.component.ts
index 20d70f38da..6f3833c2a6 100644
--- a/src/carousel/carousel.component.ts
+++ b/src/carousel/carousel.component.ts
@@ -34,12 +34,12 @@ export enum Direction {UNKNOWN, NEXT, PREV}
-
1">
-
+ 1">
+
Previous
-
1">
-
+ 1">
+
Next
@@ -70,7 +70,7 @@ export class CarouselComponent implements OnDestroy {
protected _interval: number;
/**
- * Delay of item cycling in milliseconds. If false, carousel won't cycle automatically.
+ * Delay of item cycling in milliseconds. If false, carousel won't cycle automatically.
*/
@Input()
public get interval(): number {
diff --git a/src/collapse/collapse.directive.ts b/src/collapse/collapse.directive.ts
index 45e3b5cfa6..916cc43bb7 100644
--- a/src/collapse/collapse.directive.ts
+++ b/src/collapse/collapse.directive.ts
@@ -5,7 +5,10 @@ import {
} from '@angular/core';
@Directive({
- selector: '[collapse]'/*,
+ selector: '[collapse]',
+ exportAs: 'bs-collapse',
+ /* tslint:disable-next-line */
+ host: {'[class.collapse]': 'true'}/*,
animations: [
trigger('active', [
state('void', style({height: 0})),
@@ -27,6 +30,7 @@ export class CollapseDirective {
public display: string;
// shown
@HostBinding('class.in')
+ @HostBinding('class.show')
@HostBinding('attr.aria-expanded')
public isExpanded: boolean = true;
// hidden
diff --git a/src/datepicker/daypicker.component.ts b/src/datepicker/daypicker.component.ts
index 711467a07f..1809fcb021 100644
--- a/src/datepicker/daypicker.component.ts
+++ b/src/datepicker/daypicker.component.ts
@@ -52,7 +52,7 @@ const TEMPLATE_OPTIONS: any = {
-
+
{{labelz.abbr}}
@@ -60,10 +60,10 @@ const TEMPLATE_OPTIONS: any = {
-
+
{{ weekNumbers[index] }}
-
+
= new EventEmitter(false);
+ @Output() public onToggle: EventEmitter = new EventEmitter(false);
/** fired when isOpen value changes */
- @Output() public isOpenChange:EventEmitter = new EventEmitter(false);
- @HostBinding('class.dropdown') public addClass:boolean = true;
+ @Output() public isOpenChange: EventEmitter = new EventEmitter(false);
+ @HostBinding('class.dropdown') public addClass: boolean = true;
+
+ public get isBs3(): boolean {
+ return isBs3();
+ }
// index of selected element
- public selectedOption:number;
+ public selectedOption: number;
// drop menu html
- public menuEl:ElementRef;
+ public menuEl: ElementRef;
// drop down toggle element
- public toggleEl:ElementRef;
- public el:ElementRef;
- protected _isOpen:boolean;
+ public toggleEl: ElementRef;
+ public el: ElementRef;
+ protected _isOpen: boolean;
- protected _changeDetector:ChangeDetectorRef;
+ protected _changeDetector: ChangeDetectorRef;
- public constructor(el:ElementRef, ref:ChangeDetectorRef, config: DropdownConfig) {
+ public constructor(el: ElementRef, ref: ChangeDetectorRef, config: DropdownConfig) {
// @Query('dropdownMenu', {descendants: false})
// dropdownMenuList:QueryList) {
this.el = el;
@@ -84,19 +91,19 @@ export class DropdownDirective implements OnInit, OnDestroy {
// todo: bind to route change event
}
- public ngOnInit():void {
+ public ngOnInit(): void {
if (this.isOpen) {
// todo: watch for event get-isOpen?
}
}
- public ngOnDestroy():void {
+ public ngOnDestroy(): void {
if (this.appendToBody && this.menuEl) {
this.menuEl.nativeElement.remove();
}
}
- public set dropDownMenu(dropdownMenu:{el:ElementRef}) {
+ public set dropDownMenu(dropdownMenu: { el: ElementRef }) {
// init drop down menu
this.menuEl = dropdownMenu.el;
@@ -105,16 +112,24 @@ export class DropdownDirective implements OnInit, OnDestroy {
}
}
- public set dropDownToggle(dropdownToggle:{el:ElementRef}) {
+ public set dropDownToggle(dropdownToggle: { el: ElementRef }) {
// init toggle element
this.toggleEl = dropdownToggle.el;
}
- public toggle(open?:boolean):boolean {
+ public show():void {
+ this.isOpen = true;
+ }
+
+ public hide():void {
+ this.isOpen = false;
+ }
+
+ public toggle(open?: boolean): boolean {
return this.isOpen = arguments.length ? !!open : !this.isOpen;
}
- public focusDropdownEntry(keyCode:number):void {
+ public focusDropdownEntry(keyCode: number): void {
// If append to body is used.
let hostEl = this.menuEl ?
this.menuEl.nativeElement :
@@ -165,7 +180,7 @@ export class DropdownDirective implements OnInit, OnDestroy {
elems[this.selectedOption].focus();
}
- public focusToggleElement():void {
+ public focusToggleElement(): void {
if (this.toggleEl) {
this.toggleEl.nativeElement.focus();
}
diff --git a/src/modal/modal-backdrop.component.ts b/src/modal/modal-backdrop.component.ts
index 4a1a1e8141..0edb453640 100644
--- a/src/modal/modal-backdrop.component.ts
+++ b/src/modal/modal-backdrop.component.ts
@@ -1,6 +1,7 @@
import { Component, ElementRef, Renderer } from '@angular/core';
import { ClassName } from './modal-options.class';
+import { isBs3 } from '../utils/ng2-bootstrap-config';
export class ModalBackdropOptions {
public animate:boolean = true;
@@ -34,7 +35,9 @@ export class ModalBackdropComponent {
public set isShown(value:boolean) {
this._isShown = value;
this.renderer.setElementClass(this.element.nativeElement, `${ClassName.IN}`, value);
- this.renderer.setElementClass(this.element.nativeElement, `${ClassName.ACTIVE}`, value);
+ if (!isBs3()) {
+ this.renderer.setElementClass(this.element.nativeElement, `${ClassName.SHOW}`, value);
+ }
}
public element:ElementRef;
diff --git a/src/modal/modal-options.class.ts b/src/modal/modal-options.class.ts
index 234886694a..15b26c880d 100644
--- a/src/modal/modal-options.class.ts
+++ b/src/modal/modal-options.class.ts
@@ -33,7 +33,7 @@ export const ClassName:any = {
OPEN: 'modal-open',
FADE: 'fade',
IN: 'in', // bs3
- ACTIVE: 'active' // bs4
+ SHOW: 'show' // bs4
};
export const Selector:any = {
diff --git a/src/modal/modal.component.ts b/src/modal/modal.component.ts
index 102f29905a..ca56ade3f6 100644
--- a/src/modal/modal.component.ts
+++ b/src/modal/modal.component.ts
@@ -18,6 +18,7 @@ import {
import { document } from '../utils/facade/browser';
+import { isBs3 } from '../utils/ng2-bootstrap-config';
import { Utils } from '../utils/utils.class';
import { ModalBackdropComponent } from './modal-backdrop.component';
import { ClassName, modalConfigDefaults, ModalOptions, Selector } from './modal-options.class';
@@ -165,7 +166,9 @@ export class ModalDirective implements AfterViewInit, OnDestroy {
this._isShown = false;
this._renderer.setElementClass(this._element.nativeElement, ClassName.IN, false);
- this._renderer.setElementClass(this._element.nativeElement, ClassName.ACTIVE, false);
+ if (!isBs3()) {
+ this._renderer.setElementClass(this._element.nativeElement, ClassName.SHOW, false);
+ }
// this._addClassIn = false;
if (this.isAnimated) {
@@ -204,7 +207,9 @@ export class ModalDirective implements AfterViewInit, OnDestroy {
// this._addClassIn = true;
this._renderer.setElementClass(this._element.nativeElement, ClassName.IN, true);
- this._renderer.setElementClass(this._element.nativeElement, ClassName.ACTIVE, true);
+ if (!isBs3()) {
+ this._renderer.setElementClass(this._element.nativeElement, ClassName.SHOW, true);
+ }
const transitionComplete = () => {
if (this._config.focus) {
diff --git a/src/popover/popover-container.component.ts b/src/popover/popover-container.component.ts
index 0145afe3e5..d0d099e906 100644
--- a/src/popover/popover-container.component.ts
+++ b/src/popover/popover-container.component.ts
@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, Input, Component } from '@angular/core';
import { PopoverConfig } from './popover.config';
+import { isBs3 } from '../utils/ng2-bootstrap-config';
@Component({
selector: 'popover-container',
@@ -7,6 +8,7 @@ import { PopoverConfig } from './popover.config';
// tslint:disable-next-line
host: {
'[class]': '"popover in popover-" + placement + " " + placement',
+ '[class.show]': '!isBs3',
role: 'tooltip',
style: 'display:block;'
},
@@ -19,6 +21,10 @@ export class PopoverContainerComponent {
@Input() public placement: string;
@Input() public title: string;
+ public get isBs3(): boolean {
+ return isBs3();
+ }
+
public constructor(config: PopoverConfig) {
Object.assign(this, config);
}
diff --git a/src/spec/ng-bootstrap/carousel.spec.ts b/src/spec/ng-bootstrap/carousel.spec.ts
index 71e4825f04..be6783db4c 100644
--- a/src/spec/ng-bootstrap/carousel.spec.ts
+++ b/src/spec/ng-bootstrap/carousel.spec.ts
@@ -139,15 +139,16 @@ describe('ngb-carousel', () => {
const fixture = createTestComponent(html);
- const controlElms = fixture.nativeElement.querySelectorAll('.carousel-control');
+ const prevControlElm = fixture.nativeElement.querySelector('.carousel-control-prev');
+ const nextControlElm = fixture.nativeElement.querySelector('.carousel-control-next');
expectActiveSlides(fixture.nativeElement, [true, false]);
- controlElms[1].click(); // next
+ nextControlElm.click(); // next
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [false, true]);
- controlElms[0].click(); // prev
+ prevControlElm.click(); // prev
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [true, false]);
@@ -259,20 +260,20 @@ describe('ngb-carousel', () => {
`;
const fixture = createTestComponent(html);
-
- const controlElms = fixture.nativeElement.querySelectorAll('.carousel-control');
+ const prevControlElm = fixture.nativeElement.querySelector('.carousel-control-prev');
+ const nextControlElm = fixture.nativeElement.querySelector('.carousel-control-next');
expectActiveSlides(fixture.nativeElement, [true, false]);
- controlElms[1].click(); // next
+ nextControlElm.click(); // next
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [false, true]);
- controlElms[1].click(); // next
+ nextControlElm.click(); // next
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [true, false]);
- controlElms[0].click(); // prev
+ prevControlElm.click(); // prev
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [false, true]);
@@ -289,19 +290,20 @@ describe('ngb-carousel', () => {
const fixture = createTestComponent(html);
- const controlElms = fixture.nativeElement.querySelectorAll('.carousel-control');
+ const prevControlElm = fixture.nativeElement.querySelector('.carousel-control-prev');
+ const nextControlElm = fixture.nativeElement.querySelector('.carousel-control-next');
expectActiveSlides(fixture.nativeElement, [true, false]);
- controlElms[0].click(); // prev
+ prevControlElm.click(); // prev
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [true, false]);
- controlElms[1].click(); // next
+ nextControlElm.click(); // next
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [false, true]);
- controlElms[1].click(); // next
+ nextControlElm.click(); // next
fixture.detectChanges();
expectActiveSlides(fixture.nativeElement, [false, true]);
@@ -367,7 +369,9 @@ describe('ngb-carousel', () => {
describe('Custom config', () => {
let config: CarouselConfig;
- beforeEach(() => { TestBed.configureTestingModule({imports: [CarouselModule.forRoot()]}); });
+ beforeEach(() => {
+ TestBed.configureTestingModule({imports: [CarouselModule.forRoot()]});
+ });
beforeEach(inject([CarouselConfig], (c: CarouselConfig) => {
config = c;
diff --git a/src/spec/ng-bootstrap/collapse.spec.ts b/src/spec/ng-bootstrap/collapse.spec.ts
new file mode 100644
index 0000000000..d41bbca2e2
--- /dev/null
+++ b/src/spec/ng-bootstrap/collapse.spec.ts
@@ -0,0 +1,94 @@
+// revision 6c0b585aa4a7c13c44631915d13488e6967162f4
+import { TestBed, ComponentFixture } from '@angular/core/testing';
+import { createGenericTestComponent } from './test/common';
+
+import { Component } from '@angular/core';
+
+import { CollapseModule } from '../../collapse';
+
+const createTestComponent = (html: string) =>
+ createGenericTestComponent(html, TestComponent) as ComponentFixture;
+
+function getCollapsibleContent(element: HTMLElement): HTMLDivElement {
+ return (element as HTMLDivElement).querySelector('.collapse');
+}
+
+describe('bs-collapse', () => {
+ let html = `Some content
`;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({declarations: [TestComponent], imports: [CollapseModule]});
+ TestBed.overrideComponent(TestComponent, {set: {template: html}});
+ });
+
+ it('should have content open and aria-expanded true', () => {
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ const collapseEl = getCollapsibleContent(fixture.nativeElement);
+
+ expect(collapseEl).toHaveCssClass('in');
+ expect(collapseEl).toHaveCssClass('show');
+ expect(collapseEl.getAttribute('aria-expanded')).toBe('true');
+ });
+
+ it('should have content closed and aria-expanded false', () => {
+ const fixture = TestBed.createComponent(TestComponent);
+ const tc = fixture.componentInstance;
+ tc.collapsed = true;
+ fixture.detectChanges();
+
+ const collapseEl = getCollapsibleContent(fixture.nativeElement);
+
+ expect(collapseEl).not.toHaveCssClass('in');
+ expect(collapseEl).not.toHaveCssClass('show');
+ expect(collapseEl.getAttribute('aria-expanded')).toBe('false');
+ });
+
+ it('should toggle collapsed content based on bound model change', () => {
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ const tc = fixture.componentInstance;
+ const collapseEl = getCollapsibleContent(fixture.nativeElement);
+ expect(collapseEl).toHaveCssClass('in');
+ expect(collapseEl).toHaveCssClass('show');
+
+ tc.collapsed = true;
+ fixture.detectChanges();
+ expect(collapseEl).not.toHaveCssClass('in');
+ expect(collapseEl).not.toHaveCssClass('show');
+
+ tc.collapsed = false;
+ fixture.detectChanges();
+ expect(collapseEl).toHaveCssClass('in');
+ expect(collapseEl).toHaveCssClass('show');
+ });
+
+ it('should allow toggling collapse from outside', () => {
+ html = `
+ Collapse
+
`;
+
+ const fixture = createTestComponent(html);
+
+ const compiled = fixture.nativeElement;
+ const collapseEl = getCollapsibleContent(compiled);
+ const buttonEl = compiled.querySelector('button');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(collapseEl).not.toHaveCssClass('in');
+ expect(collapseEl).not.toHaveCssClass('show');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(collapseEl).toHaveCssClass('in');
+ expect(collapseEl).toHaveCssClass('show');
+ });
+});
+
+@Component({selector: 'test-cmp', template: ''})
+class TestComponent {
+ public collapsed:string = false;
+}
diff --git a/src/spec/ng-bootstrap/dropdown.spec.ts b/src/spec/ng-bootstrap/dropdown.spec.ts
new file mode 100644
index 0000000000..18f3a5b218
--- /dev/null
+++ b/src/spec/ng-bootstrap/dropdown.spec.ts
@@ -0,0 +1,429 @@
+/* tslint:disable:max-classes-per-file max-file-line-count component-class-suffix */
+// revision 6c0b585aa4a7c13c44631915d13488e6967162f4
+import { TestBed, ComponentFixture, inject } from '@angular/core/testing';
+import { createGenericTestComponent } from './test/common';
+
+import { Component } from '@angular/core';
+import { By } from '@angular/platform-browser';
+
+// import { DropdownModule } from './dropdown.module';
+// import { DropdownDirective } from './dropdown';
+// import { DropdownConfig } from './dropdown-config';
+
+import { DropdownConfig, DropdownModule, DropdownDirective } from '../../dropdown';
+
+const createTestComponent = (html: string) =>
+ createGenericTestComponent(html, TestComponent) as ComponentFixture;
+
+function getDropdownEl(tc: any): any {
+ return tc.querySelector(`[dropdown]`);
+}
+
+xdescribe('bs-dropdown', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({declarations: [TestComponent], imports: [DropdownModule.forRoot()]});
+ });
+
+ xit('should initialize inputs with provided config', () => {
+ const defaultConfig = new DropdownConfig();
+ const dropdown = new DropdownDirective(defaultConfig);
+ expect(dropdown.up).toBe(defaultConfig.up);
+ expect(dropdown.autoClose).toBe(defaultConfig.autoClose);
+ });
+
+ it('should be closed and down by default', () => {
+ const html = `
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+
+ expect(getDropdownEl(compiled)).toHaveCssClass('dropdown');
+ expect(getDropdownEl(compiled)).not.toHaveCssClass('open');
+ });
+
+ xit('should be up if up input is true', () => {
+ const html = `
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+
+ expect(getDropdownEl(compiled)).toHaveCssClass('dropup');
+ });
+
+ xit('should be open initially if open expression is true', () => {
+ const html = `
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+
+ expect(getDropdownEl(compiled)).toHaveCssClass('dropdown');
+ expect(getDropdownEl(compiled)).toHaveCssClass('open');
+ });
+
+ it('should toggle open class', () => {
+ const html = `
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+
+ let dropdownEl = getDropdownEl(compiled);
+
+ expect(dropdownEl).not.toHaveCssClass('open');
+
+ fixture.componentInstance.isOpen = true;
+ fixture.detectChanges();
+
+ expect(dropdownEl).toHaveCssClass('open');
+
+ fixture.componentInstance.isOpen = false;
+ fixture.detectChanges();
+
+ expect(dropdownEl).not.toHaveCssClass('open');
+ });
+
+ it('should allow toggling dropdown from outside', () => {
+ const html = `
+ Open
+ Close
+ Toggle
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let buttonEls = compiled.querySelectorAll('button');
+
+ buttonEls[0].click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ buttonEls[1].click();
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+
+ buttonEls[2].click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ buttonEls[2].click();
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+ });
+
+ it('should allow binding to open output', () => {
+ const html = `
+ Toggle
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let buttonEl = compiled.querySelector('button');
+
+ expect(fixture.componentInstance.isOpen).toBe(false);
+
+ buttonEl.click();
+ fixture.detectChanges();
+
+ expect(fixture.componentInstance.isOpen).toBe(true);
+
+ buttonEl.click();
+ fixture.detectChanges();
+
+ expect(fixture.componentInstance.isOpen).toBe(false);
+ });
+
+ it('should not raise open events if open state does not change', () => {
+ const html = `
+ Open
+ Close
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let buttonEls = compiled.querySelectorAll('button');
+
+ expect(fixture.componentInstance.isOpen).toBe(false);
+ expect(fixture.componentInstance.stateChanges).toEqual([]);
+
+ buttonEls[1].click(); // close a closed one
+ fixture.detectChanges();
+ expect(fixture.componentInstance.isOpen).toBe(false);
+ expect(fixture.componentInstance.stateChanges).toEqual([]);
+
+ buttonEls[0].click(); // open a closed one
+ fixture.detectChanges();
+ expect(fixture.componentInstance.isOpen).toBe(true);
+ expect(fixture.componentInstance.stateChanges).toEqual([true]);
+
+ buttonEls[0].click(); // open an opened one
+ fixture.detectChanges();
+ expect(fixture.componentInstance.isOpen).toBe(true);
+ expect(fixture.componentInstance.stateChanges).toEqual([true]);
+
+ buttonEls[1].click(); // close an opened one
+ fixture.detectChanges();
+ expect(fixture.componentInstance.isOpen).toBe(false);
+ expect(fixture.componentInstance.stateChanges).toEqual([true, false]);
+ });
+});
+
+xdescribe('bs-dropdown-toggle', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({declarations: [TestComponent], imports: [DropdownModule.forRoot()]});
+ });
+
+ it('should toggle dropdown on click', () => {
+ const html = `
+
+ Toggle dropdown
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let buttonEl = compiled.querySelector('button');
+
+ expect(dropdownEl).not.toHaveCssClass('open');
+ expect(buttonEl.getAttribute('aria-haspopup')).toBe('true');
+ expect(buttonEl.getAttribute('aria-expanded')).toBe('false');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+ expect(buttonEl.getAttribute('aria-expanded')).toBe('true');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+ expect(buttonEl.getAttribute('aria-expanded')).toBe('false');
+ });
+
+ it('should toggle dropdown on click of child of toggle', () => {
+ const html = `
+
+
+ Toggle dropdown
+
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let toggleEl = compiled.querySelector('.toggle');
+
+ expect(dropdownEl).not.toHaveCssClass('open');
+
+ toggleEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ toggleEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+ });
+
+ it('should close on outside click', () => {
+ const html = `Outside
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let buttonEl = compiled.querySelector('button');
+
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+ });
+
+ it('should not close on outside click if autoClose is set to false', () => {
+ const html = `Outside
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let buttonEl = compiled.querySelector('button');
+
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+ });
+
+ it('should close on ESC', () => {
+ const html = `
+
+ Toggle dropdown
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let buttonEl = compiled.querySelector('button');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ fixture.debugElement.query(By.directive(DropdownDirective)).triggerEventHandler('keyup.esc', {});
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+ });
+
+ it('should not close on ESC if autoClose is set to false', () => {
+ const html = `
+
+ Toggle dropdown
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let buttonEl = compiled.querySelector('button');
+
+ buttonEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ fixture.debugElement.query(By.directive(DropdownDirective)).triggerEventHandler('keyup.esc', {});
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+ });
+
+ it('should close on item click if autoClose is set to false', () => {
+ const html = `
+
+ Toggle dropdown
+
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let linkEl = compiled.querySelector('a');
+
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ linkEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+ });
+
+ it('should close on item click', () => {
+ const html = `
+
+ Toggle dropdown
+
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+ let dropdownEl = getDropdownEl(compiled);
+ let linkEl = compiled.querySelector('a');
+
+ fixture.detectChanges();
+ expect(dropdownEl).toHaveCssClass('open');
+
+ linkEl.click();
+ fixture.detectChanges();
+ expect(dropdownEl).not.toHaveCssClass('open');
+ });
+
+ it('should close on other dropdown click', () => {
+ const html = `
+
+ Toggle dropdown 1
+
+
+
+ Toggle dropdown 2
+
+
`;
+
+ const fixture = createTestComponent(html);
+ const compiled = fixture.nativeElement;
+
+ const buttonEls = compiled.querySelectorAll('button');
+ const dropdownEls = compiled.querySelectorAll('div[dropdown]');
+
+ fixture.detectChanges();
+ expect(dropdownEls[0]).not.toHaveCssClass('open');
+ expect(dropdownEls[1]).not.toHaveCssClass('open');
+
+ buttonEls[0].click();
+ fixture.detectChanges();
+ expect(dropdownEls[0]).toHaveCssClass('open');
+ expect(dropdownEls[1]).not.toHaveCssClass('open');
+
+ buttonEls[1].click();
+ fixture.detectChanges();
+ expect(dropdownEls[0]).not.toHaveCssClass('open');
+ expect(dropdownEls[1]).toHaveCssClass('open');
+ });
+
+ describe('Custom config', () => {
+ let config: DropdownConfig;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({imports: [DropdownModule.forRoot()]});
+ TestBed.overrideComponent(TestComponent, {set: {template: '
'}});
+ });
+
+ beforeEach(inject([DropdownConfig], (c: DropdownConfig) => {
+ config = c;
+ config.up = true;
+ }));
+
+ it('should initialize inputs with provided config', () => {
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ const compiled = fixture.nativeElement;
+
+ expect(getDropdownEl(compiled)).toHaveCssClass('dropup');
+ });
+ });
+
+ describe('Custom config as provider', () => {
+ let config = new DropdownConfig();
+ config.up = true;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule(
+ {imports: [DropdownModule.forRoot()], providers: [{provide: DropdownConfig, useValue: config}]});
+ });
+
+ it('should initialize inputs with provided config as provider', () => {
+ const fixture = createTestComponent('
');
+ fixture.detectChanges();
+
+ const compiled = fixture.nativeElement;
+
+ expect(getDropdownEl(compiled)).toHaveCssClass('dropup');
+ });
+ });
+});
+
+@Component({selector: 'test-cmp', template: ''})
+class TestComponent {
+ public isOpen: string = false;
+ public stateChanges: any[] = [];
+
+ public recordStateChange($event: any): void {
+ this.stateChanges.push($event);
+ this.isOpen = $event;
+ }
+}
diff --git a/src/tooltip/tooltip-container.component.ts b/src/tooltip/tooltip-container.component.ts
index c2b4dfecac..715f5c4076 100644
--- a/src/tooltip/tooltip-container.component.ts
+++ b/src/tooltip/tooltip-container.component.ts
@@ -2,6 +2,7 @@ import {
AfterViewInit, Component, ChangeDetectionStrategy, Inject
} from '@angular/core';
import { TooltipConfig } from './tooltip.config';
+import { isBs3 } from '../utils/ng2-bootstrap-config';
@Component({
selector: 'bs-tooltip-container',
@@ -9,6 +10,7 @@ import { TooltipConfig } from './tooltip.config';
// tslint:disable-next-line
host: {
'[class]': '"tooltip in tooltip-" + placement + " " + placement',
+ '[class.show]': '!isBs3',
role: 'tooltip'
},
template: `
@@ -41,6 +43,10 @@ export class TooltipContainerComponent implements AfterViewInit {
public popupClass: string;
public animation: boolean;
+ public get isBs3(): boolean {
+ return isBs3();
+ }
+
public constructor(config: TooltipConfig) {
Object.assign(this, config);
}