Skip to content

Commit f7d59c9

Browse files
authored
Merge branch 'master' into dTsvetkov/feat-9020-master
2 parents cdc41c7 + 34ef29e commit f7d59c9

File tree

5 files changed

+168
-13
lines changed

5 files changed

+168
-13
lines changed

projects/igniteui-angular/src/lib/expansion-panel/expansion-panel.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,39 @@ describe('igxExpansionPanel', () => {
198198
expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1);
199199
}));
200200

201+
it('Should expand/collapse without animation when animationSettings === null', fakeAsync(() => {
202+
const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent);
203+
fixture.detectChanges();
204+
const panel = fixture.componentInstance.panel;
205+
panel.animationSettings = null;
206+
expect(panel).toBeTruthy();
207+
208+
spyOn(panel.contentCollapsed, 'emit');
209+
spyOn(panel.contentExpanded, 'emit');
210+
spyOn(panel.contentCollapsing, 'emit');
211+
spyOn(panel.contentExpanding, 'emit');
212+
213+
panel.toggle();
214+
tick();
215+
fixture.detectChanges();
216+
expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(0); // Initially collapsed
217+
expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(0);
218+
expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1);
219+
expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1);
220+
expect(panel.contentExpanding.emit).toHaveBeenCalledBefore(panel.contentExpanded.emit);
221+
expect(panel.collapsed).toBeFalsy();
222+
223+
panel.toggle();
224+
tick();
225+
fixture.detectChanges();
226+
expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1);
227+
expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(1);
228+
expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1);
229+
expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1);
230+
expect(panel.contentCollapsing.emit).toHaveBeenCalledBefore(panel.contentCollapsed.emit);
231+
expect(panel.collapsed).toBeTruthy();
232+
}));
233+
201234
it('Should allow expanding and collapsing events to be cancelled', fakeAsync(() => {
202235
const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent);
203236
fixture.detectChanges();

projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AnimationBuilder } from '@angular/animations';
22
import { TestBed } from '@angular/core/testing';
33
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
44
import { noop } from 'rxjs';
5+
import { growVerIn, growVerOut } from '../animations/main';
56
import { configureTestSuite } from '../test-utils/configure-suite';
67
import { ToggleAnimationPlayer ,ANIMATION_TYPE } from './toggle-animation-component';
78

@@ -40,5 +41,43 @@ describe('Toggle animation component', () => {
4041
player.playCloseAnimation(null, mockCB);
4142
expect(startPlayerSpy).toHaveBeenCalledWith(ANIMATION_TYPE.CLOSE, null, mockCB);
4243
});
44+
45+
it('Should allow overwriting animation setting with falsy value', () => {
46+
const player = new MockTogglePlayer(mockBuilder);
47+
expect(player.animationSettings).toEqual({
48+
openAnimation: growVerIn,
49+
closeAnimation: growVerOut
50+
});
51+
player.animationSettings = null;
52+
expect(player.animationSettings).toEqual(null);
53+
});
54+
55+
it('Should not throw if called with a falsy animationSettings value', () => {
56+
const player = new MockTogglePlayer(mockBuilder);
57+
player.animationSettings = null;
58+
const mockCb = jasmine.createSpy('mockCb');
59+
const mockElement = jasmine.createSpy('element');
60+
spyOn(player.openAnimationStart, 'emit');
61+
spyOn(player.openAnimationDone, 'emit');
62+
spyOn(player.closeAnimationStart, 'emit');
63+
spyOn(player.closeAnimationDone, 'emit');
64+
65+
player.playOpenAnimation({ nativeElement: mockElement }, mockCb);
66+
expect(player.openAnimationStart.emit).toHaveBeenCalledTimes(1);
67+
expect(player.openAnimationDone.emit).toHaveBeenCalledTimes(1);
68+
expect(player.closeAnimationStart.emit).toHaveBeenCalledTimes(0);
69+
expect(player.closeAnimationDone.emit).toHaveBeenCalledTimes(0);
70+
expect(player.openAnimationStart.emit).toHaveBeenCalledBefore(player.openAnimationDone.emit);
71+
expect(mockCb).toHaveBeenCalledTimes(1);
72+
73+
player.playCloseAnimation({ nativeElement: mockElement }, mockCb);
74+
expect(player.openAnimationStart.emit).toHaveBeenCalledTimes(1);
75+
expect(player.openAnimationDone.emit).toHaveBeenCalledTimes(1);
76+
expect(player.closeAnimationStart.emit).toHaveBeenCalledTimes(1);
77+
expect(player.closeAnimationDone.emit).toHaveBeenCalledTimes(1);
78+
expect(player.closeAnimationStart.emit).toHaveBeenCalledBefore(player.closeAnimationDone.emit);
79+
80+
expect(mockCb).toHaveBeenCalledTimes(2);
81+
});
4382
});
4483
});

projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,33 @@ export abstract class ToggleAnimationPlayer implements ToggleAnimationOwner, OnD
9999
target = this.initializePlayer(type, targetElement, callback);
100100
}
101101

102-
if (target.hasStarted()) {
102+
// V.S. Jun 28th, 2021 #9783: player will NOT be initialized w/ null settings
103+
// events will already be emitted
104+
if (!target || target.hasStarted()) {
103105
return;
104106
}
105107

106108
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationStart : this.closeAnimationStart;
107109
targetEmitter.emit();
108-
target.play();
110+
if (target) {
111+
target.play();
112+
}
109113
}
110114

111115
private initializePlayer(type: ANIMATION_TYPE, targetElement: ElementRef, callback: () => void): AnimationPlayer {
112116
const oppositeType = type === ANIMATION_TYPE.OPEN ? ANIMATION_TYPE.CLOSE : ANIMATION_TYPE.OPEN;
117+
// V.S. Jun 28th, 2021 #9783: Treat falsy animation settings as disabled animations
118+
const targetAnimationSettings = this.animationSettings || { closeAnimation: null, openAnimation: null };
113119
const animationSettings = type === ANIMATION_TYPE.OPEN ?
114-
this.animationSettings.openAnimation : this.animationSettings.closeAnimation;
120+
targetAnimationSettings.openAnimation : targetAnimationSettings.closeAnimation;
121+
// V.S. Jun 28th, 2021 #9783: When no animation in target direction, emit start and done events and return
122+
if (!animationSettings) {
123+
this.setCallback(type, callback);
124+
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationStart : this.closeAnimationStart;
125+
targetEmitter.emit();
126+
this.onDoneHandler(type);
127+
return;
128+
}
115129
const animation = useAnimation(animationSettings);
116130
const animationBuilder = this.builder.build(animation);
117131
const opposite = this.getPlayer(oppositeType);
@@ -132,23 +146,31 @@ export abstract class ToggleAnimationPlayer implements ToggleAnimationOwner, OnD
132146
const target = this.getPlayer(type);
133147
target.init();
134148
this.getPlayer(type).setPosition(1 - oppositePosition);
149+
this.setCallback(type, callback);
150+
target.onDone(() => {
151+
this.onDoneHandler(type);
152+
});
153+
return target;
154+
}
155+
156+
private onDoneHandler(type) {
157+
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationDone : this.closeAnimationDone;
158+
const targetCallback = type === ANIMATION_TYPE.OPEN ? this.onOpenedCallback : this.onClosedCallback;
159+
targetCallback();
160+
if (!(type === ANIMATION_TYPE.OPEN ? this.openInterrupted : this.closeInterrupted)) {
161+
targetEmitter.emit();
162+
}
163+
this.cleanUpPlayer(type);
164+
}
165+
166+
private setCallback(type: ANIMATION_TYPE, callback: () => void) {
135167
if (type === ANIMATION_TYPE.OPEN) {
136168
this.onOpenedCallback = callback;
137169
this.openInterrupted = false;
138170
} else if (type === ANIMATION_TYPE.CLOSE) {
139171
this.onClosedCallback = callback;
140172
this.closeInterrupted = false;
141173
}
142-
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationDone : this.closeAnimationDone;
143-
target.onDone(() => {
144-
const targetCallback = type === ANIMATION_TYPE.OPEN ? this.onOpenedCallback : this.onClosedCallback;
145-
targetCallback();
146-
if (!(type === ANIMATION_TYPE.OPEN ? this.openInterrupted : this.closeInterrupted)) {
147-
targetEmitter.emit();
148-
}
149-
this.cleanUpPlayer(type);
150-
});
151-
return target;
152174
}
153175

154176

projects/igniteui-angular/src/lib/list/list-item.component.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,16 @@ export class IgxListItemComponent implements IListChild {
321321
}
322322
}
323323

324+
/**
325+
* @hidden
326+
*/
327+
@HostListener('pancancel')
328+
public pancancel() {
329+
this.setContentElementLeft(0);
330+
this._panState = IgxListPanState.NONE;
331+
this.hideLeftAndRightPanTemplates();
332+
}
333+
324334
/**
325335
* @hidden
326336
*/

projects/igniteui-angular/src/lib/list/list.component.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,44 @@ describe('List', () => {
594594
expect(rightPanTmpl.nativeElement.style.visibility).toBe('hidden');
595595
}));
596596

597+
it('cancel left panning', fakeAsync(() => {
598+
const fixture = TestBed.createComponent(ListWithPanningTemplatesComponent);
599+
const list = fixture.componentInstance.list;
600+
fixture.detectChanges();
601+
602+
const firstItem = list.items[0] as IgxListItemComponent;
603+
const leftPanTmpl = firstItem.leftPanningTemplateElement;
604+
const rightPanTmpl = firstItem.rightPanningTemplateElement;
605+
const itemNativeElements = fixture.debugElement.queryAll(By.css('igx-list-item'));
606+
607+
/* Pan item left */
608+
cancelItemPanning(itemNativeElements[1], -2, -8);
609+
tick(600);
610+
611+
expect(firstItem.panState).toBe(IgxListPanState.NONE);
612+
expect(leftPanTmpl.nativeElement.style.visibility).toBe('hidden');
613+
expect(rightPanTmpl.nativeElement.style.visibility).toBe('hidden');
614+
}));
615+
616+
it('cancel right panning', fakeAsync(() => {
617+
const fixture = TestBed.createComponent(ListWithPanningTemplatesComponent);
618+
const list = fixture.componentInstance.list;
619+
fixture.detectChanges();
620+
621+
const firstItem = list.items[0] as IgxListItemComponent;
622+
const leftPanTmpl = firstItem.leftPanningTemplateElement;
623+
const rightPanTmpl = firstItem.rightPanningTemplateElement;
624+
const itemNativeElements = fixture.debugElement.queryAll(By.css('igx-list-item'));
625+
626+
/* Pan item right */
627+
cancelItemPanning(itemNativeElements[1], 2, 8);
628+
tick(600);
629+
630+
expect(firstItem.panState).toBe(IgxListPanState.NONE);
631+
expect(leftPanTmpl.nativeElement.style.visibility).toBe('hidden');
632+
expect(rightPanTmpl.nativeElement.style.visibility).toBe('hidden');
633+
}));
634+
597635
it('checking the header list item does not have panning and content containers.', () => {
598636
const fixture = TestBed.createComponent(ListWithPanningTemplatesComponent);
599637
const list = fixture.componentInstance.list;
@@ -818,6 +856,19 @@ describe('List', () => {
818856
});
819857
};
820858

859+
const cancelItemPanning = (itemNativeElement, factorX, factorY) => {
860+
itemNativeElement.triggerEventHandler('panstart', {
861+
deltaX: factorX
862+
});
863+
itemNativeElement.triggerEventHandler('panmove', {
864+
deltaX: factorX,
865+
deltaY: factorY,
866+
additionalEvent: 'panup'
867+
});
868+
869+
itemNativeElement.triggerEventHandler('pancancel', null);
870+
};
871+
821872
const clickItem = (currentItem: IgxListItemComponent) => Promise.resolve(currentItem.element.click());
822873

823874
const verifyItemsCount = (list, expectedCount) => {

0 commit comments

Comments
 (0)