Skip to content

Commit 29dceba

Browse files
Le0Michinevalorkin
authored andcommitted
fix(dropdown): fixed disabled tests, removed outdated (#1605)
* fixed disabled tests, removed outdated * fixed karma config * fixed event creation to support IE this "browser" just can't use ctor of Event class... * chore(build): fixed karma config (#1606) * fixed disabled tests, removed outdated * fixed event creation to support IE this "browser" just can't use ctor of Event class...
1 parent f21bd8d commit 29dceba

File tree

7 files changed

+113
-191
lines changed

7 files changed

+113
-191
lines changed

src/dropdown/dropdown-keyboard-nav.directive.ts

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/dropdown/dropdown.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ export class DropdownConfig {
77
/** default dropdown auto closing behavior */
88
public autoClose: string = NONINPUT;
99
/** is keyboard navigation enabled by default */
10-
public keyboardNav: Boolean = false;
10+
public keyboardNav: boolean = false;
1111
}

src/dropdown/dropdown.directive.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
} from '@angular/core';
55

66
import { isBs3 } from '../utils/ng2-bootstrap-config';
7-
import { dropdownService } from './dropdown.service';
7+
import { DropdownService } from './dropdown.service';
88
import { DropdownConfig } from './dropdown.config';
99

1010
/**
@@ -17,6 +17,7 @@ import { DropdownConfig } from './dropdown.config';
1717
host: {'[class.show]': 'isOpen && !isBs3'}
1818
})
1919
export class DropdownDirective implements OnInit, OnDestroy {
20+
private dropdownService: DropdownService;
2021
/** if `true` dropdown will be opened */
2122
@HostBinding('class.open')
2223
@HostBinding('class.active')
@@ -26,6 +27,11 @@ export class DropdownDirective implements OnInit, OnDestroy {
2627
}
2728

2829
public set isOpen(value: boolean) {
30+
if (this._isOpen === !!value) {
31+
// don't emit events
32+
return;
33+
}
34+
2935
this._isOpen = !!value;
3036

3137
// todo: implement after porting position
@@ -37,9 +43,9 @@ export class DropdownDirective implements OnInit, OnDestroy {
3743
// ready
3844
if (this.isOpen) {
3945
this.focusToggleElement();
40-
dropdownService.open(this);
46+
this.dropdownService.open(this);
4147
} else {
42-
dropdownService.close(this);
48+
this.dropdownService.close(this);
4349
this.selectedOption = void 0;
4450
}
4551
this.onToggle.emit(this.isOpen);
@@ -78,15 +84,21 @@ export class DropdownDirective implements OnInit, OnDestroy {
7884
// drop down toggle element
7985
public toggleEl: ElementRef;
8086
public el: ElementRef;
81-
protected _isOpen: boolean;
87+
protected _isOpen: boolean = false;
8288

8389
protected _changeDetector: ChangeDetectorRef;
8490

85-
public constructor(el: ElementRef, ref: ChangeDetectorRef, config: DropdownConfig) {
91+
public constructor(
92+
el: ElementRef,
93+
ref: ChangeDetectorRef,
94+
dropdownService: DropdownService,
95+
config: DropdownConfig
96+
) {
8697
// @Query('dropdownMenu', {descendants: false})
8798
// dropdownMenuList:QueryList<ElementRef>) {
8899
this.el = el;
89100
this._changeDetector = ref;
101+
this.dropdownService = dropdownService;
90102
Object.assign(this, config);
91103
// todo: bind to route change event
92104
}
@@ -118,10 +130,14 @@ export class DropdownDirective implements OnInit, OnDestroy {
118130
}
119131

120132
public show():void {
133+
/** prevent global event handling */
134+
this.dropdownService.preventEventHandling();
121135
this.isOpen = true;
122136
}
123137

124138
public hide():void {
139+
/** prevent global event handling */
140+
this.dropdownService.preventEventHandling();
125141
this.isOpen = false;
126142
}
127143

src/dropdown/dropdown.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import { DropdownMenuDirective } from './dropdown-menu.directive';
44
import { DropdownToggleDirective } from './dropdown-toggle.directive';
55
import { DropdownDirective } from './dropdown.directive';
66
import { DropdownConfig } from './dropdown.config';
7+
import { DropdownService } from './dropdown.service';
78

89
@NgModule({
910
declarations: [DropdownDirective, DropdownMenuDirective, DropdownToggleDirective],
1011
exports: [DropdownDirective, DropdownMenuDirective, DropdownToggleDirective]
1112
})
1213
export class DropdownModule {
1314
public static forRoot(): ModuleWithProviders {
14-
return {ngModule: DropdownModule, providers: [DropdownConfig]};
15+
return {ngModule: DropdownModule, providers: [DropdownConfig, DropdownService]};
1516
}
1617
}

src/dropdown/dropdown.service.ts

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
1+
import { Injectable } from '@angular/core';
2+
3+
import { DropdownDirective } from './dropdown.directive';
4+
15
export const ALWAYS = 'always';
26
export const DISABLED = 'disabled';
37
export const OUTSIDECLICK = 'outsideClick';
48
export const NONINPUT = 'nonInput';
59

6-
import { DropdownDirective } from './dropdown.directive';
7-
810
/* tslint:disable-next-line */
911
const KeyboardEvent = (global as any).KeyboardEvent as KeyboardEvent;
1012
/* tslint:disable-next-line */
1113
const MouseEvent = (global as any).MouseEvent as MouseEvent;
1214

15+
@Injectable()
1316
export class DropdownService {
14-
protected openScope:DropdownDirective;
17+
private openScope:DropdownDirective;
18+
19+
private closeDropdownBind:EventListener = this.closeDropdown.bind(this);
20+
private keybindFilterBind:EventListener = this.keybindFilter.bind(this);
1521

16-
protected closeDropdownBind:EventListener = this.closeDropdown.bind(this);
17-
protected keybindFilterBind:EventListener = this.keybindFilter.bind(this);
22+
private suspendedEvent: any;
1823

1924
public open(dropdownScope:DropdownDirective):void {
2025
if (!this.openScope) {
@@ -39,34 +44,44 @@ export class DropdownService {
3944
window.document.removeEventListener('keydown', this.keybindFilterBind);
4045
}
4146

42-
protected closeDropdown(event:MouseEvent):void {
43-
if (!this.openScope) {
44-
return;
45-
}
46-
47-
if (event && this.openScope.autoClose === DISABLED) {
48-
return;
49-
}
50-
51-
if (event && this.openScope.toggleEl &&
52-
this.openScope.toggleEl.nativeElement.contains(event.target)) {
53-
return;
54-
}
55-
56-
if (event && this.openScope.autoClose === NONINPUT &&
57-
this.openScope.menuEl &&
58-
/input|textarea/i.test((event.target as any).tagName) &&
59-
this.openScope.menuEl.nativeElement.contains(event.target)) {
60-
return;
61-
}
62-
63-
if (event && this.openScope.autoClose === OUTSIDECLICK &&
64-
this.openScope.menuEl &&
65-
this.openScope.menuEl.nativeElement.contains(event.target)) {
66-
return;
67-
}
47+
public preventEventHandling(): void {
48+
clearTimeout(this.suspendedEvent);
49+
}
6850

69-
this.openScope.isOpen = false;
51+
protected closeDropdown(event:MouseEvent):void {
52+
this.suspendedEvent = setTimeout(() => {
53+
if (!this.openScope) {
54+
return;
55+
}
56+
57+
if (event && this.openScope.autoClose === DISABLED) {
58+
return;
59+
}
60+
61+
if (event && this.openScope.toggleEl &&
62+
this.openScope.toggleEl.nativeElement.contains(event.target)) {
63+
return;
64+
}
65+
66+
if (event && this.openScope.autoClose === NONINPUT &&
67+
this.openScope.menuEl &&
68+
/input|textarea/i.test((event.target as any).tagName) &&
69+
this.openScope.menuEl.nativeElement.contains(event.target)) {
70+
return;
71+
}
72+
73+
if (event && this.openScope.autoClose === OUTSIDECLICK &&
74+
this.openScope.menuEl &&
75+
this.openScope.menuEl.nativeElement.contains(event.target)) {
76+
return;
77+
}
78+
79+
if (event) {
80+
event.preventDefault();
81+
event.stopPropagation();
82+
}
83+
this.openScope.isOpen = false;
84+
}, 0);
7085
}
7186

7287
protected keybindFilter(event:KeyboardEvent):void {
@@ -84,5 +99,3 @@ export class DropdownService {
8499
}
85100
}
86101
}
87-
88-
export let dropdownService = new DropdownService();

src/spec/dropdown.directive.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* tslint:disable:max-file-line-count */
22
import { Component } from '@angular/core';
3-
import { TestBed } from '@angular/core/testing';
3+
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
44

55
import { DropdownModule } from '../dropdown/dropdown.module';
66
import { DropdownConfig } from '../dropdown/dropdown.config';
@@ -77,7 +77,7 @@ describe('Directive: Dropdown', () => {
7777
expect(element.querySelector('.dropdown').classList).not.toContain('open');
7878
});
7979

80-
it('should close by click on nonInput menu item', () => {
80+
it('should close by click on nonInput menu item', fakeAsync(() => {
8181
const html = `
8282
<div dropdown>
8383
<button dropdownToggle>Dropdown</button>
@@ -100,10 +100,10 @@ describe('Directive: Dropdown', () => {
100100
fixture.detectChanges();
101101
expect(element.querySelector('.dropdown').classList).toContain('open');
102102
element.querySelector('li').click();
103+
tick();
103104
fixture.detectChanges();
104105
expect(element.querySelector('.dropdown').classList).not.toContain('open');
105-
106-
});
106+
}));
107107

108108
it('should not close by click on input or textarea menu item', () => {
109109
const html = `

0 commit comments

Comments
 (0)