Skip to content

Commit e9c6b59

Browse files
authored
Merge branch '9.1.x' into ibarakov/fix-8162-9.1.x
2 parents d2c27d4 + 9276e1d commit e9c6b59

File tree

2 files changed

+135
-2
lines changed

2 files changed

+135
-2
lines changed

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

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,92 @@ describe('igxOverlay', () => {
188188
UIInteractions.clearOverlay();
189189
});
190190

191+
describe('Pure Unit Test', () => {
192+
configureTestSuite();
193+
let mockElement: any;
194+
let mockElementRef: any;
195+
let mockFactoryResolver: any;
196+
let mockApplicationRef: any;
197+
let mockInjector: any;
198+
let mockAnimationBuilder: any;
199+
let mockDocument: any;
200+
let mockNgZone: any;
201+
let mockPlatformUtil: any;
202+
let overlay: IgxOverlayService;
203+
beforeEach(() => {
204+
mockElement = {
205+
style: { visibility: '', cursor: '', transitionDuration: '' },
206+
classList: { add: () => { }, remove: () => { } },
207+
appendChild: () => { },
208+
removeChild: () => { },
209+
addEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { },
210+
removeEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { },
211+
getBoundingClientRect: () => ({ width: 10, height: 10 }),
212+
insertBefore: (newChild: HTMLDivElement, refChild: Node) => { },
213+
contains: () => { }
214+
};
215+
mockElement.parent = mockElement;
216+
mockElement.parentElement = mockElement;
217+
mockElementRef = { nativeElement: mockElement };
218+
mockFactoryResolver = {
219+
resolveComponentFactory: (c: any) => {
220+
return {
221+
create: (i: any) => {
222+
return {
223+
hostView: '',
224+
location: mockElementRef,
225+
changeDetectorRef: { detectChanges: () => { } },
226+
destroy: () => { }
227+
};
228+
}
229+
};
230+
}
231+
};
232+
mockApplicationRef = { attachView: (h: any) => { }, detachView: (h: any) => { } };
233+
mockInjector = {};
234+
mockAnimationBuilder = {};
235+
mockDocument = {
236+
body: mockElement,
237+
defaultView: mockElement,
238+
createElement: () => mockElement,
239+
appendChild: () => { },
240+
addEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { },
241+
removeEventListener: (type: string, listener: (this: HTMLElement, ev: MouseEvent) => any) => { }
242+
};
243+
mockNgZone = {};
244+
mockPlatformUtil = { isIOS: false };
245+
246+
overlay = new IgxOverlayService(
247+
mockFactoryResolver, mockApplicationRef, mockInjector, mockAnimationBuilder, mockDocument, mockNgZone, mockPlatformUtil);
248+
});
249+
250+
it('Should set cursor to pointer on iOS', () => {
251+
mockPlatformUtil.isIOS = true;
252+
mockDocument.body.style.cursor = 'initialCursorValue';
253+
254+
const mockOverlaySettings: OverlaySettings = {
255+
modal: false,
256+
positionStrategy: new GlobalPositionStrategy({ openAnimation: null, closeAnimation: null })
257+
};
258+
let id = overlay.attach(mockElementRef, mockOverlaySettings);
259+
260+
overlay.show(id);
261+
expect(mockDocument.body.style.cursor).toEqual('pointer');
262+
263+
overlay.hide(id);
264+
expect(mockDocument.body.style.cursor).toEqual('initialCursorValue');
265+
266+
mockPlatformUtil.isIOS = false;
267+
id = overlay.attach(mockElementRef, mockOverlaySettings);
268+
269+
overlay.show(id);
270+
expect(mockDocument.body.style.cursor).toEqual('initialCursorValue');
271+
272+
overlay.hide(id);
273+
expect(mockDocument.body.style.cursor).toEqual('initialCursorValue');
274+
});
275+
});
276+
191277
describe('Unit Tests: ', () => {
192278
configureTestSuite();
193279
beforeEach(async(() => {
@@ -881,6 +967,35 @@ describe('igxOverlay', () => {
881967
expect(element.style.width).toBe('200px');
882968
expect(element.style.height).toBe('100px');
883969
});
970+
971+
it('should close overlay on outside click when target is point, #8297', fakeAsync(() => {
972+
const fix = TestBed.createComponent(EmptyPageComponent);
973+
const button = fix.componentInstance.buttonElement;
974+
const overlay = fix.componentInstance.overlay;
975+
fix.detectChanges();
976+
977+
const overlaySettings: OverlaySettings = {
978+
modal: false,
979+
closeOnOutsideClick: true,
980+
positionStrategy: new ConnectedPositioningStrategy()
981+
};
982+
983+
overlaySettings.positionStrategy.settings.target = new Point(10, 10);
984+
985+
overlay.show(overlay.attach(SimpleDynamicComponent), overlaySettings);
986+
tick();
987+
fix.detectChanges();
988+
989+
let overlayDiv: Element = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0];
990+
expect(overlayDiv).toBeDefined();
991+
992+
document.body.click();
993+
tick();
994+
fix.detectChanges();
995+
996+
overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0];
997+
expect(overlayDiv).toBeUndefined();
998+
}));
884999
});
8851000

8861001
describe('Unit Tests - Scroll Strategies: ', () => {

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { fromEvent, Subject } from 'rxjs';
3030
import { filter, takeUntil } from 'rxjs/operators';
3131
import { IAnimationParams } from '../../animations/main';
3232
import { showMessage } from '../../core/deprecateDecorators';
33+
import { PlatformUtil } from '../../core/utils';
3334

3435
let warningShown = false;
3536

@@ -44,6 +45,8 @@ export class IgxOverlayService implements OnDestroy {
4445
private _overlayElement: HTMLElement;
4546
private _document: Document;
4647
private destroy$ = new Subject<boolean>();
48+
private _cursorStyleIsSet = false;
49+
private _cursorOriginalValue: string;
4750

4851
private _defaultSettings: OverlaySettings = {
4952
positionStrategy: new GlobalPositionStrategy(),
@@ -118,7 +121,8 @@ export class IgxOverlayService implements OnDestroy {
118121
private _injector: Injector,
119122
private builder: AnimationBuilder,
120123
@Inject(DOCUMENT) private document: any,
121-
private _zone: NgZone) {
124+
private _zone: NgZone,
125+
protected platformUtil: PlatformUtil) {
122126
this._document = <Document>this.document;
123127
}
124128

@@ -660,7 +664,7 @@ export class IgxOverlayService implements OnDestroy {
660664
// if we should exclude position target check if the click is over it. If so do not close overlay
661665
const positionTarget = info.settings.positionStrategy.settings.target as HTMLElement;
662666
let clickOnPositionTarget = false;
663-
if (positionTarget) {
667+
if (positionTarget && positionTarget.contains) {
664668
clickOnPositionTarget = positionTarget.contains(target);
665669
}
666670

@@ -690,6 +694,15 @@ export class IgxOverlayService implements OnDestroy {
690694
this._overlayInfos.filter(x => x.settings.closeOnOutsideClick && !x.settings.modal &&
691695
x.closeAnimationPlayer &&
692696
x.closeAnimationPlayer.hasStarted()).length === 1) {
697+
698+
// click event is not fired on iOS. To make element "clickable" we are
699+
// setting the cursor to pointer
700+
if (this.platformUtil.isIOS && !this._cursorStyleIsSet) {
701+
this._cursorOriginalValue = this._document.body.style.cursor;
702+
this._document.body.style.cursor = 'pointer';
703+
this._cursorStyleIsSet = true;
704+
}
705+
693706
this._document.addEventListener('click', this.documentClicked, true);
694707
}
695708
}
@@ -705,6 +718,11 @@ export class IgxOverlayService implements OnDestroy {
705718
});
706719

707720
if (shouldRemoveClickEventListener) {
721+
if (this._cursorStyleIsSet) {
722+
this._document.body.style.cursor = this._cursorOriginalValue;
723+
this._cursorOriginalValue = '';
724+
this._cursorStyleIsSet = false;
725+
}
708726
this._document.removeEventListener('click', this.documentClicked, true);
709727
}
710728
}

0 commit comments

Comments
 (0)