Skip to content

Commit 171a172

Browse files
authored
Merge branch '11.1.x' into dTsvetkov/fiix-8819-11.1.x
2 parents 455b821 + a343de5 commit 171a172

File tree

2 files changed

+86
-10
lines changed

2 files changed

+86
-10
lines changed

projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
ViewEncapsulation
1111
} from '@angular/core';
1212
import { TestBed, fakeAsync, tick, inject, waitForAsync } from '@angular/core/testing';
13-
import { BrowserModule, By } from '@angular/platform-browser';
13+
import { BrowserModule } from '@angular/platform-browser';
1414
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
1515
import { IgxOverlayService } from './overlay';
1616
import { IgxToggleDirective, IgxToggleModule, IgxOverlayOutletDirective } from './../../directives/toggle/toggle.directive';
@@ -220,17 +220,34 @@ describe('igxOverlay', () => {
220220
beforeEach(() => {
221221
mockElement = {
222222
style: { visibility: '', cursor: '', transitionDuration: '' },
223+
children: [],
223224
classList: { add: () => { }, remove: () => { } },
224-
appendChild: () => { },
225-
removeChild: () => { },
225+
appendChild(element: any) {
226+
this.children.push(element);
227+
},
228+
removeChild(element: any) {
229+
const index = this.children.indexOf(element);
230+
if (index !== -1) {
231+
this.children.splice(index, 1);
232+
}
233+
},
226234
addEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { },
227235
removeEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { },
228236
getBoundingClientRect: () => ({ width: 10, height: 10 }),
229-
insertBefore: (newChild: HTMLDivElement, refChild: Node) => { },
230-
contains: () => { }
237+
insertBefore(newChild: HTMLDivElement, refChild: Node) {
238+
let refIndex = this.children.indexOf(refChild);
239+
if (refIndex === -1) {
240+
refIndex = 0;
241+
}
242+
this.children.splice(refIndex, 0, newChild);
243+
},
244+
contains(element: any) {
245+
return this.children.indexOf(element) !== -1;
246+
}
231247
};
232248
mockElement.parent = mockElement;
233249
mockElement.parentElement = mockElement;
250+
mockElement.parentNode = mockElement;
234251
mockElementRef = { nativeElement: mockElement };
235252
mockFactoryResolver = {
236253
resolveComponentFactory: (c: any) => ({
@@ -247,11 +264,34 @@ describe('igxOverlay', () => {
247264
mockAnimationBuilder = {};
248265
mockDocument = {
249266
body: mockElement,
267+
listeners: { },
250268
defaultView: mockElement,
269+
// this is used be able to properly invoke rxjs `fromEvent` operator, which, turns out
270+
// just adds an event listener to the element and emits accordingly
271+
dispatchEvent(event: KeyboardEvent) {
272+
const type = event.type;
273+
if (this.listeners[type]) {
274+
this.listeners[type].forEach(listener => {
275+
listener(event);
276+
});
277+
}
278+
},
251279
createElement: () => mockElement,
252280
appendChild: () => { },
253-
addEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { },
254-
removeEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { }
281+
addEventListener(type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) {
282+
if (!this.listeners[type]) {
283+
this.listeners[type] = [];
284+
}
285+
this.listeners[type].push(listener);
286+
},
287+
removeEventListener(type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) {
288+
if (this.listeners[type]) {
289+
const index = this.listeners[type].indexOf(listener);
290+
if (index !== -1) {
291+
this.listeners[type].splice(index, 1);
292+
}
293+
}
294+
}
255295
};
256296
mockNgZone = {};
257297
mockPlatformUtil = { isIOS: false };
@@ -285,6 +325,40 @@ describe('igxOverlay', () => {
285325
overlay.hide(id);
286326
expect(mockDocument.body.style.cursor).toEqual('initialCursorValue');
287327
});
328+
329+
it('Should clear listener for escape key when overlay settings have outlet specified', () => {
330+
const mockOverlaySettings: OverlaySettings = {
331+
modal: false,
332+
closeOnEscape: true,
333+
outlet: mockElement,
334+
positionStrategy: new GlobalPositionStrategy({ openAnimation: null, closeAnimation: null })
335+
};
336+
const id = overlay.attach(mockElementRef, mockOverlaySettings);
337+
338+
// show the overlay
339+
overlay.show(id);
340+
341+
// expect escape listener to be added to document
342+
expect(mockDocument.listeners['keydown'].length > 0).toBeTruthy();
343+
const keydownListener = mockDocument.listeners['keydown'][0];
344+
345+
spyOn(overlay, 'hide').and.callThrough();
346+
spyOn(mockDocument, 'removeEventListener').and.callThrough();
347+
348+
mockDocument.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
349+
350+
// expect hide to have been called
351+
expect(overlay.hide).toHaveBeenCalledTimes(1);
352+
expect(mockDocument.removeEventListener).toHaveBeenCalled();
353+
354+
// the keydown listener is now removed
355+
expect(mockDocument.removeEventListener).toHaveBeenCalledWith('keydown', keydownListener, undefined);
356+
357+
// fire event again, expecting hide NOT to be fired again
358+
mockDocument.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
359+
expect(overlay.hide).toHaveBeenCalledTimes(1);
360+
expect(mockDocument.listeners['keydown'].length).toBe(0);
361+
});
288362
});
289363

290364
describe('Unit Tests: ', () => {

projects/igniteui-angular/src/lib/services/overlay/overlay.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,11 @@ export class IgxOverlayService implements OnDestroy {
691691
this._overlayInfos.splice(index, 1);
692692

693693
// this._overlayElement.parentElement check just for tests that manually delete the element
694-
if (this._overlayInfos.length === 0 && this._overlayElement && this._overlayElement.parentElement) {
695-
this._overlayElement.parentElement.removeChild(this._overlayElement);
696-
this._overlayElement = null;
694+
if (this._overlayInfos.length === 0) {
695+
if (this._overlayElement && this._overlayElement.parentElement) {
696+
this._overlayElement.parentElement.removeChild(this._overlayElement);
697+
this._overlayElement = null;
698+
}
697699
this.removeCloseOnEscapeListener();
698700
}
699701
}

0 commit comments

Comments
 (0)