From 0b6dfb256cc3bc41e88b2024650920569fb097c2 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 13 Nov 2019 15:38:29 +0200 Subject: [PATCH 1/9] chore(*): add initial pan implementation --- .../src/lib/carousel/carousel.component.ts | 179 +++++++++++++----- .../components/carousel/_carousel-theme.scss | 2 + 2 files changed, 137 insertions(+), 44 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index 75135c7b871..ac39681dc66 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -235,17 +235,17 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { * An accessor that sets the resource strings. * By default it uses EN resources. */ - @Input() - set resourceStrings(value: ICarouselResourceStrings) { - this._resourceStrings = Object.assign({}, this._resourceStrings, value); - } + @Input() + set resourceStrings(value: ICarouselResourceStrings) { + this._resourceStrings = Object.assign({}, this._resourceStrings, value); + } - /** - * An accessor that returns the resource strings. - */ - get resourceStrings(): ICarouselResourceStrings { - return this._resourceStrings; - } + /** + * An accessor that returns the resource strings. + */ + get resourceStrings(): ICarouselResourceStrings { + return this._resourceStrings; + } @ViewChild('defaultIndicator', { read: TemplateRef, static: true }) protected defaultIndicator: TemplateRef; @@ -272,13 +272,13 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { @ContentChild(IgxCarouselIndicatorDirective, { read: TemplateRef, static: false }) public indicatorTemplate: TemplateRef = null; - /** - * The collection of `slides` currently in the carousel. - * ```typescript - * let slides: QueryList = this.carousel.slides; - * ``` - * @memberOf IgxCarouselComponent - */ + /** + * The collection of `slides` currently in the carousel. + * ```typescript + * let slides: QueryList = this.carousel.slides; + * ``` + * @memberOf IgxCarouselComponent + */ @ContentChildren(IgxSlideComponent) public slides: QueryList; @@ -344,6 +344,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { private currentSlide: IgxSlideComponent; private previousSlide: IgxSlideComponent; private animationDuration = 320; + private incomingSlide: IgxSlideComponent; + private animationPosition = 0; + private newDuration = 0; constructor(private element: ElementRef, private _iterableDiffers: IterableDiffers, private builder: AnimationBuilder) { this._differ = this._iterableDiffers.find([]).create(null); @@ -410,7 +413,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } private finishAnimations(): boolean { - let animationWasStarted = false; + let animationWasStarted = false; if (this.previousSlide && this.previousSlide.previous) { this.previousSlide.previous = false; } @@ -426,17 +429,25 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } private getAnimation(): CarouselAnimationSettings { + let duration; + if (this.newDuration) { + duration = this.animationPosition ? this.animationPosition * this.newDuration : this.newDuration; + } else { + duration = this.animationPosition ? this.animationPosition * this.animationDuration : this.animationDuration; + } + switch (this.animationType) { case CarouselAnimationType.slide: + const trans = this.animationPosition ? this.animationPosition * 100 : 100; return { enterAnimation: useAnimation(slideInLeft, { params: { delay: '0s', - duration: `${this.animationDuration}ms`, + duration: `${duration}ms`, endOpacity: 1, startOpacity: 1, - fromPosition: `translateX(${this.currentSlide.direction === 1 ? 100 : -100}%)`, + fromPosition: `translateX(${this.currentSlide.direction === 1 ? trans : -trans}%)`, toPosition: 'translateX(0%)' } }), @@ -444,21 +455,22 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { { params: { delay: '0s', - duration: `${this.animationDuration}ms`, + duration: `${duration}ms`, endOpacity: 1, startOpacity: 1, fromPosition: `translateX(0%)`, - toPosition: `translateX(${this.currentSlide.direction === 1 ? -100 : 100}%)`, + toPosition: `translateX(${this.currentSlide.direction === 1 ? -trans : trans}%)`, } }) }; case CarouselAnimationType.fade: return { - enterAnimation: useAnimation(fadeIn, { params: { duration: `${this.animationDuration}ms` } }), + enterAnimation: useAnimation(fadeIn, + { params: { duration: `${duration}ms`, startOpacity: `${this.animationPosition}` } }), leaveAnimation: null }; } - return { + return { enterAnimation: null, leaveAnimation: null }; @@ -474,6 +486,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.enterAnimationPlayer.reset(); this.enterAnimationPlayer = null; } + this.animationPosition = 0; + this.newDuration = 0; this.previousSlide.previous = false; }); this.previousSlide.previous = true; @@ -490,6 +504,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.leaveAnimationPlayer.reset(); this.leaveAnimationPlayer = null; } + this.animationPosition = 0; + this.newDuration = 0; }); this.leaveAnimationPlayer.play(); } @@ -531,7 +547,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.slides.first.active = true; } this.play(); - }); + }); } /** @@ -576,10 +592,10 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return this.total > this.maximumIndicatorsCount; } - /** - * @hidden - * @memberof IgxCarouselComponent - */ + /** + * @hidden + * @memberof IgxCarouselComponent + */ public get getCarouselLabel() { return `${this.current + 1} ${this.resourceStrings.igx_carousel_of} ${this.total}`; } @@ -807,18 +823,19 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** @hidden */ - @HostListener('keydown.Tab') + @HostListener('tap') public onTab() { if (this.isPlaying) { this.stop(); } else { this.play(); } + console.log('tap'); } - /** - *@hidden - */ + /** + *@hidden + */ @HostListener('keydown.home') public onKeydownHome() { if (this.keyboardSupport && this.slides.length > 0) { @@ -828,9 +845,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } -/** - *@hidden - */ + /** + *@hidden + */ @HostListener('keydown.end') public onKeydownEnd() { if (this.keyboardSupport && this.slides.length > 0) { @@ -859,17 +876,91 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { /** * @hidden */ - @HostListener('swipeleft') - public swipeLeft() { - this.next(); + @HostListener('pan', ['$event']) + public onPan(event) { + event.preventDefault(); + this.finishAnimations(); + const slideWidth = this.currentSlide.nativeElement.offsetWidth; + const panOffset = (slideWidth / 100); + const deltaX = event.deltaX; + if (Math.abs(deltaX) + panOffset >= slideWidth + || (!this.loop && ((this.current === 0 && deltaX > 0) || (this.current === this.total - 1 && deltaX < 0)))) { + return; + } + let index; + let offset; + if (deltaX < 0) { + index = (this.current + 1) % this.total; + offset = slideWidth + event.deltaX; + + } else { + index = this.current - 1 < 0 ? this.total - 1 : this.current - 1; + offset = -slideWidth + event.deltaX; + } + if (this.incomingSlide) { + if (index !== this.incomingSlide.index) { + this.incomingSlide.nativeElement.style.transform = ''; + this.incomingSlide.nativeElement.style.opacity = ''; + this.incomingSlide.previous = false; + this.incomingSlide = this.get(index); + } + } else { + this.incomingSlide = this.get(index); + } + this.incomingSlide.previous = true; + + if (this.animationType === CarouselAnimationType.fade) { + this.currentSlide.nativeElement.style.opacity = `${Math.abs(offset) / slideWidth}`; + } else { + this.currentSlide.nativeElement.style.transform = `translateX(${event.deltaX}px)`; + this.incomingSlide.nativeElement.style.transform = `translateX(${offset}px)`; + } } /** - * @hidden - */ - @HostListener('swiperight') - public swipeRight() { - this.prev(); + * @hidden + */ + @HostListener('panend', ['$event']) + public onPanEnd(event) { + event.preventDefault(); + const slideWidth = this.currentSlide.nativeElement.offsetWidth; + const panOffset = (slideWidth / 100); + const deltaX = Math.abs(event.deltaX) + panOffset < slideWidth ? Math.abs(event.deltaX) : slideWidth - panOffset; + const direction = event.deltaX < 0 ? Direction.NEXT : Direction.PREV; + const velocity = Math.abs(event.velocity); + this.currentSlide.nativeElement.style.transform = ''; + this.currentSlide.nativeElement.style.opacity = ''; + if (this.incomingSlide) { + this.incomingSlide.nativeElement.style.transform = ''; + this.incomingSlide.nativeElement.style.opacity = ''; + if (slideWidth / 2 < deltaX) { + this.incomingSlide.direction = direction; + this.incomingSlide.previous = false; + + this.animationPosition = this.animationType === CarouselAnimationType.fade ? + deltaX / slideWidth : (slideWidth - deltaX) / slideWidth; + + if (velocity > 1) { + this.newDuration = this.animationDuration / velocity; + } + this.incomingSlide.active = true; + } else if (velocity > 1) { + this.incomingSlide.direction = direction; + this.incomingSlide.previous = false; + this.animationPosition = this.animationType === CarouselAnimationType.fade ? + deltaX / slideWidth : (slideWidth - deltaX) / slideWidth; + this.newDuration = this.animationDuration / velocity; + this.incomingSlide.active = true; + } else { + this.currentSlide.direction = direction === Direction.PREV ? Direction.NEXT : Direction.PREV; + this.previousSlide = this.incomingSlide; + this.previousSlide.previous = true; + this.animationPosition = this.animationType === CarouselAnimationType.fade ? + Math.abs((slideWidth - deltaX) / slideWidth) : deltaX / slideWidth; + this.playEnterAnimation(); + this.playLeaveAnimation(); + } + } } } diff --git a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss index 88bdf1ffe95..633853a2a19 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss @@ -299,5 +299,7 @@ width: inherit; height: inherit; object-fit: cover; + touch-action: none; + pointer-events: none; } } From b41609ba13d55ceff3b5578a868a6a04f2f82947 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Tue, 19 Nov 2019 15:23:28 +0200 Subject: [PATCH 2/9] chore(*): update pan event --- .../src/lib/carousel/carousel.component.ts | 68 +++++++++++++++++-- .../components/carousel/_carousel-theme.scss | 1 + 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index 60222a0a78e..5a7b4e968a9 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -17,7 +17,8 @@ import { IterableChangeRecord, TemplateRef, ViewChild, - ContentChild + ContentChild, + Injectable } from '@angular/core'; import { IgxIconModule } from '../icon/index'; import { IBaseEventArgs } from '../core/utils'; @@ -29,6 +30,7 @@ import { slideInLeft, fadeIn, rotateInCenter } from '../animations/main'; import { IgxSlideComponent, Direction } from './slide.component'; import { ICarouselResourceStrings } from '../core/i18n/carousel-resources'; import { CurrentResourceStrings } from '../core/i18n/resources'; +import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser'; let NEXT_ID = 0; @@ -48,6 +50,13 @@ export interface CarouselAnimationSettings { enterAnimation: AnimationReferenceMetadata; leaveAnimation: AnimationReferenceMetadata; } + +@Injectable() +export class CarouselHammerConfig extends HammerGestureConfig { + public overrides = { + pan: { direction: Hammer.DIRECTION_HORIZONTAL } + }; +} /** * **Ignite UI for Angular Carousel** - * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/carousel.html) @@ -70,6 +79,12 @@ export interface CarouselAnimationSettings { * ``` */ @Component({ + providers: [ + { + provide: HAMMER_GESTURE_CONFIG, + useClass: CarouselHammerConfig + } + ], selector: 'igx-carousel', templateUrl: 'carousel.component.html', styles: [` @@ -199,6 +214,16 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @Input() public keyboardSupport = true; + /** + * Controls whether the carousel should support gestures. + * Default value is `true`. + * ```html + * + * ``` + * @memberOf IgxCarouselComponent + */ + @Input() public gesturesSupport = true; + /** * Controls the maximum indexes that can be shown. * Default value is `5`. @@ -828,7 +853,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { @HostListener('tap') public onTap() { if (this.isPlaying) { - if (this.pause && this.isPlaying) { + if (this.pause) { this.stoppedByInteraction = true; } this.stop(); @@ -880,16 +905,41 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('mouseleave') public onMouseLeave() { - if ( this.stoppedByInteraction ) { + if (this.stoppedByInteraction) { this.play(); - } + } } - /** + + /** + * @hidden + */ + @HostListener('panleft', ['$event']) + public onPanLeft(event) { + this.onPan(event); + } + + /** * @hidden */ - @HostListener('pan', ['$event']) + @HostListener('panright', ['$event']) + public onPanRight(event) { + this.onPan(event); + } + + public onPan(event) { + if (this.isPlaying) { + this.stoppedByInteraction = true; + this.stop(); + } + // if (event.direction === 8 || event.direction === 16) { + // return; + // } + if (this.isPlaying) { + this.stoppedByInteraction = true; + this.stop(); + } event.preventDefault(); this.finishAnimations(); const slideWidth = this.currentSlide.nativeElement.offsetWidth; @@ -934,6 +984,12 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panend', ['$event']) public onPanEnd(event) { + if (this.stoppedByInteraction) { + this.play(); + } + if (event.direction === 8 || event.direction === 16) { + return; + } event.preventDefault(); const slideWidth = this.currentSlide.nativeElement.offsetWidth; const panOffset = (slideWidth / 100); diff --git a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss index 633853a2a19..cc2ae732be3 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss @@ -134,6 +134,7 @@ height: 100%; align-items: center; flex-flow: column nowrap; + touch-action: pan-y !important; } %igx-carousel-arrow { From 7acdee396085f8d5e69f0e7af79c224d7a164d8b Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 20 Nov 2019 09:01:38 +0200 Subject: [PATCH 3/9] chore(*): update pan event --- .../src/lib/carousel/carousel.component.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index 5a7b4e968a9..4bdd9412307 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -916,7 +916,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panleft', ['$event']) public onPanLeft(event) { - this.onPan(event); + if (!event.isFinal) { + this.onPan(event); + } } /** @@ -924,7 +926,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panright', ['$event']) public onPanRight(event) { - this.onPan(event); + if (!event.isFinal) { + this.onPan(event); + } } @@ -933,9 +937,6 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.stoppedByInteraction = true; this.stop(); } - // if (event.direction === 8 || event.direction === 16) { - // return; - // } if (this.isPlaying) { this.stoppedByInteraction = true; this.stop(); From ac65e62acdf086a9976a9273c141b251fad084db Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 20 Nov 2019 09:42:03 +0200 Subject: [PATCH 4/9] chore(*): update sample with gesturesSupport --- .../src/lib/carousel/carousel.component.ts | 29 +++++++++++++++---- .../components/carousel/_carousel-theme.scss | 1 - src/app/carousel/carousel.sample.html | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index 4bdd9412307..ca7e942cd65 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -149,6 +149,17 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { @HostBinding('class.igx-carousel') public cssClass = 'igx-carousel'; + /** + * Gets the `touch-action` style of the `list item`. + * ```typescript + * let touchAction = this.listItem.touchAction; + * ``` + */ + @HostBinding('style.touch-action') + get touchAction() { + return this.gesturesSupport ? 'pan-y' : 'auto'; + } + /** * Sets whether the carousel should `loop` back to the first slide after reaching the last slide. * Default value is `true`. @@ -503,6 +514,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } private playEnterAnimation() { + if (this.getAnimation().enterAnimation) { + return; + } const animationBuilder = this.builder.build(this.getAnimation().enterAnimation); this.enterAnimationPlayer = animationBuilder.create(this.currentSlide.nativeElement); @@ -522,6 +536,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { private playLeaveAnimation() { if (this.getAnimation().leaveAnimation) { + return; + } + const animationBuilder = this.builder.build(this.getAnimation().leaveAnimation); this.leaveAnimationPlayer = animationBuilder.create(this.previousSlide.nativeElement); @@ -534,7 +551,6 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.newDuration = 0; }); this.leaveAnimationPlayer.play(); - } } private initSlides(change: QueryList) { @@ -916,7 +932,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panleft', ['$event']) public onPanLeft(event) { - if (!event.isFinal) { + if (this.gesturesSupport && !event.isFinal) { this.onPan(event); } } @@ -926,13 +942,14 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panright', ['$event']) public onPanRight(event) { - if (!event.isFinal) { + if (this.gesturesSupport && !event.isFinal) { this.onPan(event); } } public onPan(event) { + if (this.isPlaying) { this.stoppedByInteraction = true; this.stop(); @@ -985,12 +1002,12 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panend', ['$event']) public onPanEnd(event) { + if (!this.gesturesSupport) { + return; + } if (this.stoppedByInteraction) { this.play(); } - if (event.direction === 8 || event.direction === 16) { - return; - } event.preventDefault(); const slideWidth = this.currentSlide.nativeElement.offsetWidth; const panOffset = (slideWidth / 100); diff --git a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss index cc2ae732be3..633853a2a19 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss @@ -134,7 +134,6 @@ height: 100%; align-items: center; flex-flow: column nowrap; - touch-action: pan-y !important; } %igx-carousel-arrow { diff --git a/src/app/carousel/carousel.sample.html b/src/app/carousel/carousel.sample.html index d94edb0c002..2efc65ab5ba 100644 --- a/src/app/carousel/carousel.sample.html +++ b/src/app/carousel/carousel.sample.html @@ -11,6 +11,7 @@

Desktop

navigation keyboardSupport + gesturesSupport loop pause From d501ef09916cf1a917f6dd1a8a6658ba4b4763c8 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 20 Nov 2019 13:45:42 +0200 Subject: [PATCH 5/9] chore(carousel): updatre pan method --- .../src/lib/carousel/carousel.component.ts | 179 +++++++++--------- 1 file changed, 86 insertions(+), 93 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index ca7e942cd65..a8aec3e888a 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -42,8 +42,7 @@ export enum CarouselIndicatorsOrientation { export enum CarouselAnimationType { none = 'none', slide = 'slide', - fade = 'fade', - grow = 'grow' + fade = 'fade' } export interface CarouselAnimationSettings { @@ -149,12 +148,12 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { @HostBinding('class.igx-carousel') public cssClass = 'igx-carousel'; - /** - * Gets the `touch-action` style of the `list item`. - * ```typescript - * let touchAction = this.listItem.touchAction; - * ``` - */ + /** + * Gets the `touch-action` style of the `list item`. + * ```typescript + * let touchAction = this.listItem.touchAction; + * ``` + */ @HostBinding('style.touch-action') get touchAction() { return this.gesturesSupport ? 'pan-y' : 'auto'; @@ -225,14 +224,14 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @Input() public keyboardSupport = true; - /** - * Controls whether the carousel should support gestures. - * Default value is `true`. - * ```html - * - * ``` - * @memberOf IgxCarouselComponent - */ + /** + * Controls whether the carousel should support gestures. + * Default value is `true`. + * ```html + * + * ``` + * @memberOf IgxCarouselComponent + */ @Input() public gesturesSupport = true; /** @@ -433,12 +432,10 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { if (this.animationType !== CarouselAnimationType.none) { if (animationWasStarted) { requestAnimationFrame(() => { - this.playLeaveAnimation(); - this.playEnterAnimation(); + this.playAnimations(); }); } else { - this.playLeaveAnimation(); - this.playEnterAnimation(); + this.playAnimations(); } } } else { @@ -449,6 +446,11 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } + private playAnimations() { + this.playLeaveAnimation(); + this.playEnterAnimation(); + } + private finishAnimations(): boolean { let animationWasStarted = false; if (this.previousSlide && this.previousSlide.previous) { @@ -514,7 +516,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } private playEnterAnimation() { - if (this.getAnimation().enterAnimation) { + if (!this.getAnimation().enterAnimation) { return; } const animationBuilder = this.builder.build(this.getAnimation().enterAnimation); @@ -535,22 +537,22 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } private playLeaveAnimation() { - if (this.getAnimation().leaveAnimation) { + if (!this.getAnimation().leaveAnimation) { return; } - const animationBuilder = this.builder.build(this.getAnimation().leaveAnimation); - this.leaveAnimationPlayer = animationBuilder.create(this.previousSlide.nativeElement); + const animationBuilder = this.builder.build(this.getAnimation().leaveAnimation); + this.leaveAnimationPlayer = animationBuilder.create(this.previousSlide.nativeElement); - this.leaveAnimationPlayer.onDone(() => { - if (this.leaveAnimationPlayer) { - this.leaveAnimationPlayer.reset(); - this.leaveAnimationPlayer = null; - } - this.animationPosition = 0; - this.newDuration = 0; - }); - this.leaveAnimationPlayer.play(); + this.leaveAnimationPlayer.onDone(() => { + if (this.leaveAnimationPlayer) { + this.leaveAnimationPlayer.reset(); + this.leaveAnimationPlayer = null; + } + this.animationPosition = 0; + this.newDuration = 0; + }); + this.leaveAnimationPlayer.play(); } private initSlides(change: QueryList) { @@ -866,19 +868,19 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** @hidden */ - @HostListener('tap') - public onTap() { - if (this.isPlaying) { - if (this.pause) { - this.stoppedByInteraction = true; - } - this.stop(); - } else { - if (this.stoppedByInteraction) { + @HostListener('tap', ['$event']) + public onTap(event) { + // play pause only when tap on slide + if (event.target && event.target.classList.contains('igx-slide')) { + if (this.isPlaying) { + if (this.pause) { + this.stoppedByInteraction = true; + } + this.stop(); + } else if (this.stoppedByInteraction) { this.play(); } } - console.log('tap'); } /** @@ -927,60 +929,60 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } - /** - * @hidden - */ + /** + * @hidden + */ @HostListener('panleft', ['$event']) public onPanLeft(event) { - if (this.gesturesSupport && !event.isFinal) { - this.onPan(event); - } + this.onPan(event); } - /** - * @hidden - */ + /** + * @hidden + */ @HostListener('panright', ['$event']) public onPanRight(event) { - if (this.gesturesSupport && !event.isFinal) { - this.onPan(event); - } + this.onPan(event); } + private resetSlideStyles(slide: IgxSlideComponent) { + slide.nativeElement.style.transform = ''; + slide.nativeElement.style.opacity = ''; + } - public onPan(event) { + private onPan(event) { + const slideWidth = this.currentSlide.nativeElement.offsetWidth; + const panOffset = (slideWidth / 1000); + const deltaX = event.deltaX; + let index, offset; - if (this.isPlaying) { - this.stoppedByInteraction = true; - this.stop(); + if (!this.gesturesSupport || event.isFinal || Math.abs(deltaX) + panOffset >= slideWidth) { + return; } + + if (!this.loop && ((this.current === 0 && deltaX > 0) || (this.current === this.total - 1 && deltaX < 0))) { + this.incomingSlide = null; + return; + } + + event.preventDefault(); if (this.isPlaying) { this.stoppedByInteraction = true; this.stop(); } - event.preventDefault(); this.finishAnimations(); - const slideWidth = this.currentSlide.nativeElement.offsetWidth; - const panOffset = (slideWidth / 100); - const deltaX = event.deltaX; - if (Math.abs(deltaX) + panOffset >= slideWidth - || (!this.loop && ((this.current === 0 && deltaX > 0) || (this.current === this.total - 1 && deltaX < 0)))) { - return; - } - let index; - let offset; + if (deltaX < 0) { index = (this.current + 1) % this.total; offset = slideWidth + event.deltaX; - } else { index = this.current - 1 < 0 ? this.total - 1 : this.current - 1; offset = -slideWidth + event.deltaX; } + if (this.incomingSlide) { if (index !== this.incomingSlide.index) { - this.incomingSlide.nativeElement.style.transform = ''; - this.incomingSlide.nativeElement.style.opacity = ''; + this.resetSlideStyles(this.incomingSlide); this.incomingSlide.previous = false; this.incomingSlide = this.get(index); } @@ -1005,22 +1007,17 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { if (!this.gesturesSupport) { return; } - if (this.stoppedByInteraction) { - this.play(); - } event.preventDefault(); + const slideWidth = this.currentSlide.nativeElement.offsetWidth; - const panOffset = (slideWidth / 100); + const panOffset = (slideWidth / 1000); const deltaX = Math.abs(event.deltaX) + panOffset < slideWidth ? Math.abs(event.deltaX) : slideWidth - panOffset; - const direction = event.deltaX < 0 ? Direction.NEXT : Direction.PREV; const velocity = Math.abs(event.velocity); - this.currentSlide.nativeElement.style.transform = ''; - this.currentSlide.nativeElement.style.opacity = ''; + this.resetSlideStyles(this.currentSlide); if (this.incomingSlide) { - this.incomingSlide.nativeElement.style.transform = ''; - this.incomingSlide.nativeElement.style.opacity = ''; - if (slideWidth / 2 < deltaX) { - this.incomingSlide.direction = direction; + this.resetSlideStyles(this.incomingSlide); + if (slideWidth / 2 < deltaX || velocity > 1) { + this.incomingSlide.direction = event.deltaX < 0 ? Direction.NEXT : Direction.PREV;; this.incomingSlide.previous = false; this.animationPosition = this.animationType === CarouselAnimationType.fade ? @@ -1030,23 +1027,19 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.newDuration = this.animationDuration / velocity; } this.incomingSlide.active = true; - } else if (velocity > 1) { - this.incomingSlide.direction = direction; - this.incomingSlide.previous = false; - this.animationPosition = this.animationType === CarouselAnimationType.fade ? - deltaX / slideWidth : (slideWidth - deltaX) / slideWidth; - this.newDuration = this.animationDuration / velocity; - this.incomingSlide.active = true; } else { - this.currentSlide.direction = direction === Direction.PREV ? Direction.NEXT : Direction.PREV; + this.currentSlide.direction = event.deltaX > 0 ? Direction.NEXT : Direction.PREV; this.previousSlide = this.incomingSlide; this.previousSlide.previous = true; this.animationPosition = this.animationType === CarouselAnimationType.fade ? Math.abs((slideWidth - deltaX) / slideWidth) : deltaX / slideWidth; - this.playEnterAnimation(); - this.playLeaveAnimation(); + this.playAnimations(); } } + + if (this.stoppedByInteraction) { + this.play(); + } } } From 188bc2f94032aec166ba86e691df734e216f017f Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 20 Nov 2019 16:53:59 +0200 Subject: [PATCH 6/9] chore(*): add test for pan event --- .../lib/carousel/carousel.component.spec.ts | 184 ++++++++++++++---- .../src/lib/carousel/carousel.component.ts | 73 ++++--- 2 files changed, 178 insertions(+), 79 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.spec.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.spec.ts index e59ba0809b6..23948e186ad 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.spec.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.spec.ts @@ -2,10 +2,8 @@ import { Component, ViewChild, TemplateRef } from '@angular/core'; import { async, TestBed, - ComponentFixture, fakeAsync, - tick, - flush + tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { @@ -472,46 +470,7 @@ describe('Carousel', () => { expect(carousel.onCarouselPlaying.emit).toHaveBeenCalledTimes(1); }); - it('should stop/play on tap ', async () => { - carousel.interval = 1000; - carousel.play(); - fixture.detectChanges(); - - spyOn(carousel.onCarouselPaused, 'emit'); - spyOn(carousel.onCarouselPlaying, 'emit'); - - expect(carousel.isPlaying).toBeTruthy(); - - Simulator.gestures.press(carousel.nativeElement, { duration: 180 }); - fixture.detectChanges(); - await wait(200); - - expect(carousel.isPlaying).toBeFalsy(); - - Simulator.gestures.press(carousel.nativeElement, { duration: 180 }); - fixture.detectChanges(); - await wait(200); - - expect(carousel.isPlaying).toBeTruthy(); - - // When the carousel is stopped tap does not start playing - carousel.stop(); - fixture.detectChanges(); - - expect(carousel.isPlaying).toBeFalsy(); - - Simulator.gestures.press(carousel.nativeElement, { duration: 180 }); - fixture.detectChanges(); - await wait(200); - - expect(carousel.isPlaying).toBeFalsy(); - Simulator.gestures.press(carousel.nativeElement, { duration: 180 }); - fixture.detectChanges(); - await wait(200); - - expect(carousel.isPlaying).toBeFalsy(); - }); }); describe('Templates Tests: ', () => { @@ -738,6 +697,125 @@ describe('Carousel', () => { expect(HelperTestFunctions.getPreviousButton(fixture).hidden).toBeFalsy(); })); }); + + describe('Gestures Tests: ', () => { + beforeEach(() => { + fixture = TestBed.createComponent(CarouselDynamicSlidesComponent); + fixture.detectChanges(); + carousel = fixture.componentInstance.carousel; + }); + + it('should stop/play on tap ', async () => { + carousel.interval = 1000; + carousel.play(); + fixture.detectChanges(); + + spyOn(carousel.onCarouselPaused, 'emit'); + spyOn(carousel.onCarouselPlaying, 'emit'); + + expect(carousel.isPlaying).toBeTruthy(); + + HelperTestFunctions.simulateTap(carousel); + fixture.detectChanges(); + await wait(200); + + expect(carousel.isPlaying).toBeFalsy(); + + HelperTestFunctions.simulateTap(carousel); + fixture.detectChanges(); + await wait(200); + + expect(carousel.isPlaying).toBeTruthy(); + + // When the carousel is stopped tap does not start playing + carousel.stop(); + fixture.detectChanges(); + + expect(carousel.isPlaying).toBeFalsy(); + + HelperTestFunctions.simulateTap(carousel); + fixture.detectChanges(); + await wait(200); + + expect(carousel.isPlaying).toBeFalsy(); + + HelperTestFunctions.simulateTap(carousel); + fixture.detectChanges(); + await wait(200); + + expect(carousel.isPlaying).toBeFalsy(); + }); + + it('verify changing slides with pan left ', () => { + expect(carousel.current).toEqual(2); + + HelperTestFunctions.simulatePan(fixture, carousel, -0.05, 0.1); + + expect(carousel.current).toEqual(2); + + HelperTestFunctions.simulatePan(fixture, carousel, -0.7, 0.1); + + expect(carousel.current).toEqual(3); + + HelperTestFunctions.simulatePan(fixture, carousel, -0.2, 2); + + expect(carousel.current).toEqual(0); + }); + + it('verify changing slides with pan right ', () => { + expect(carousel.current).toEqual(2); + + HelperTestFunctions.simulatePan(fixture, carousel, 0.1, 0.1); + + expect(carousel.current).toEqual(2); + + HelperTestFunctions.simulatePan(fixture, carousel, 0.6, 0.1); + + expect(carousel.current).toEqual(1); + + HelperTestFunctions.simulatePan(fixture, carousel, 0.05, 2); + + expect(carousel.current).toEqual(0); + }); + + it('verify pan when loop is false', () => { + carousel.loop = false; + fixture.detectChanges(); + + carousel.select(carousel.get(0)); + fixture.detectChanges(); + + expect(carousel.current).toEqual(0); + + HelperTestFunctions.simulatePan(fixture, carousel, 0.9, 2); + + expect(carousel.current).toEqual(0); + + carousel.select(carousel.get(3)); + fixture.detectChanges(); + + expect(carousel.current).toEqual(3); + + HelperTestFunctions.simulatePan(fixture, carousel, -0.9, 2); + + expect(carousel.current).toEqual(3); + }); + + it('verify pan when gesturesSupport is false', () => { + carousel.gesturesSupport = false; + fixture.detectChanges(); + + expect(carousel.current).toEqual(2); + + HelperTestFunctions.simulatePan(fixture, carousel, 0.9, 2); + + expect(carousel.current).toEqual(2); + + HelperTestFunctions.simulatePan(fixture, carousel, -0.6, 2); + + expect(carousel.current).toEqual(2); + }); + }); }); class HelperTestFunctions { @@ -803,7 +881,29 @@ class HelperTestFunctions { expect(carousel.slides.find((slide) => slide.active && slide.index !== index)).toBeUndefined(); } + public static simulateTap(carousel) { + const activeSlide = carousel.get(carousel.current).nativeElement; + Simulator.gestures.press(activeSlide, { duration: 180 }); + } + public static simulatePan(fixture, carousel, deltaXOffset, velocity) { + const activeSlide = carousel.get(carousel.current).nativeElement; + const carouselElement = fixture.debugElement.query(By.css('igx-carousel')); + const deltaX = activeSlide.offsetWidth * deltaXOffset; + const event = deltaXOffset < 0 ? 'panleft' : 'panright'; + const panOptions = { + deltaX: deltaX, + deltaY: 0, + duration: 100, + velocity: velocity, + preventDefault: ( ( e: any ) => { }) + }; + + carouselElement.triggerEventHandler(event, panOptions); + fixture.detectChanges(); + carouselElement.triggerEventHandler('panend', panOptions); + fixture.detectChanges(); + } } @Component({ template: ` diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index 2ece8ee43a9..bc6dd30362e 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -248,7 +248,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { * Gets/sets the display mode of carousel indicators. It can be top or bottom. * Default value is `bottom`. * ```html - * + * * * ``` * @memberOf IgxSlideComponent @@ -259,7 +259,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { * Gets/sets the animation type of carousel. * Default value is `slide`. * ```html - * + * * * ``` * @memberOf IgxSlideComponent @@ -359,13 +359,13 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { @ContentChild(IgxCarouselPrevButtonDirective, { read: TemplateRef, static: false }) public prevButtonTemplate: TemplateRef = null; - /** - * The collection of `slides` currently in the carousel. - * ```typescript - * let slides: QueryList = this.carousel.slides; - * ``` - * @memberOf IgxCarouselComponent - */ + /** + * The collection of `slides` currently in the carousel. + * ```typescript + * let slides: QueryList = this.carousel.slides; + * ``` + * @memberOf IgxCarouselComponent + */ @ContentChildren(IgxSlideComponent) public slides: QueryList; @@ -656,9 +656,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return this.defaultIndicator; } - /** - * @hidden - */ + /** + * @hidden + */ public get getNextButtonTemplate(): TemplateRef { if (this.nextButtonTemplate) { return this.nextButtonTemplate; @@ -666,9 +666,9 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return this.defaultNextButton; } - /** - * @hidden - */ + /** + * @hidden + */ public get getPrevButtonTemplate(): TemplateRef { if (this.prevButtonTemplate) { return this.prevButtonTemplate; @@ -738,6 +738,14 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return !this.currentSlide ? 0 : this.currentSlide.index; } + private getNextIndex(): number { + return (this.current + 1) % this.total; + } + + private getPrevIndex(): number { + return this.current - 1 < 0 ? this.total - 1 : this.current - 1; + } + /** * Returns a boolean indicating if the carousel is playing. * ```typescript @@ -833,7 +841,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { * @memberOf IgxCarouselComponent */ public next() { - const index = (this.current + 1) % this.total; + const index = this.getNextIndex(); if (index === 0 && !this.loop) { this.stop(); @@ -850,8 +858,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { * @memberOf IgxCarouselComponent */ public prev() { - const index = this.current - 1 < 0 ? - this.total - 1 : this.current - 1; + const index = this.getPrevIndex(); if (!this.loop && index === this.total - 1) { this.stop(); @@ -1016,13 +1023,12 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } - /** - * @hidden - */ + * @hidden + */ @HostListener('panleft', ['$event']) public onPanLeft(event) { - this.onPan(event); + this.pan(event); } /** @@ -1030,7 +1036,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { */ @HostListener('panright', ['$event']) public onPanRight(event) { - this.onPan(event); + this.pan(event); } private resetSlideStyles(slide: IgxSlideComponent) { @@ -1038,11 +1044,12 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { slide.nativeElement.style.opacity = ''; } - private onPan(event) { + private pan(event) { const slideWidth = this.currentSlide.nativeElement.offsetWidth; const panOffset = (slideWidth / 1000); const deltaX = event.deltaX; - let index, offset; + const index = deltaX < 0 ? this.getNextIndex() : this.getPrevIndex(); + const offset = deltaX < 0 ? slideWidth + deltaX : -slideWidth + deltaX; if (!this.gesturesSupport || event.isFinal || Math.abs(deltaX) + panOffset >= slideWidth) { return; @@ -1060,14 +1067,6 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } this.finishAnimations(); - if (deltaX < 0) { - index = (this.current + 1) % this.total; - offset = slideWidth + event.deltaX; - } else { - index = this.current - 1 < 0 ? this.total - 1 : this.current - 1; - offset = -slideWidth + event.deltaX; - } - if (this.incomingSlide) { if (index !== this.incomingSlide.index) { this.resetSlideStyles(this.incomingSlide); @@ -1082,7 +1081,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { if (this.animationType === CarouselAnimationType.fade) { this.currentSlide.nativeElement.style.opacity = `${Math.abs(offset) / slideWidth}`; } else { - this.currentSlide.nativeElement.style.transform = `translateX(${event.deltaX}px)`; + this.currentSlide.nativeElement.style.transform = `translateX(${deltaX}px)`; this.incomingSlide.nativeElement.style.transform = `translateX(${offset}px)`; } } @@ -1105,7 +1104,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { if (this.incomingSlide) { this.resetSlideStyles(this.incomingSlide); if (slideWidth / 2 < deltaX || velocity > 1) { - this.incomingSlide.direction = event.deltaX < 0 ? Direction.NEXT : Direction.PREV;; + this.incomingSlide.direction = event.deltaX < 0 ? Direction.NEXT : Direction.PREV; this.incomingSlide.previous = false; this.animationPosition = this.animationType === CarouselAnimationType.fade ? @@ -1146,14 +1145,14 @@ export interface ISlideEventArgs extends IBaseEventArgs { IgxCarouselIndicatorDirective, IgxCarouselNextButtonDirective, IgxCarouselPrevButtonDirective - ], + ], exports: [ IgxCarouselComponent, IgxSlideComponent, IgxCarouselIndicatorDirective, IgxCarouselNextButtonDirective, IgxCarouselPrevButtonDirective - ], + ], imports: [CommonModule, IgxIconModule] }) export class IgxCarouselModule { From 5ffc220aac5855aa6ec0be1accfc5ad50cdeb8f8 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 20 Nov 2019 18:06:01 +0200 Subject: [PATCH 7/9] chore(*): update Changelog and Readme --- CHANGELOG.md | 1 + .../src/lib/carousel/README.md | 1 + .../src/lib/carousel/carousel.component.ts | 91 +++++-------------- 3 files changed, 25 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 987e4040046..96d3f3269f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ All notable changes for each version of this project will be documented in this ``` - `IgxCarousel`: - `keyboardSupport` input is added, which can be used to enable and disable keyboard navigation + - `gesturesSupport` input is added, which can be used to enable and disable gestures - `maximumIndicatorsCount` input is added, which can be used to set the number of visible indicators - `indicatorsOrientation` input is added, which can be used to set the position of indicators it can be top or bottom - `animationType` input is added, which can be used to set animation when changing slides diff --git a/projects/igniteui-angular/src/lib/carousel/README.md b/projects/igniteui-angular/src/lib/carousel/README.md index e8770a77810..626e4f49be2 100644 --- a/projects/igniteui-angular/src/lib/carousel/README.md +++ b/projects/igniteui-angular/src/lib/carousel/README.md @@ -14,6 +14,7 @@ A walkthrough of how to get started can be found [here](https://www.infragistics | `interval` | number | The amount of time in milliseconds between slides transition. | | `navigation` | boolean | Controls should the carousel render the left/right navigation buttons. Defaults to `true`. | | `keyboardSupport` | boolean | Controls should the keyboard navigation should be supported. Defaults to `true`. | +| `gesturesSupport` | boolean | Controls should the gestures should be supported. Defaults to `true`. | | `maximumIndicatorsCount` | number | The number of visible indicators. Defaults to `5`. | | `indicatorsOrientation` | CarouselIndicatorsOrientation | Controls whether the indicators should be previewed on top or on bottom of carousel. Defaults to `bottom`. | | `animationType` | CarouselAnimationType | Controls what animation should be played when slides are changing. Defaults to `slide`. | diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index bc6dd30362e..b563e75b40b 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -440,9 +440,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.differ = this.iterableDiffers.find([]).create(null); } - /** - * @hidden - */ + /** @hidden */ public ngAfterContentInit() { this.slides.changes .pipe(takeUntil(this.destroy$)) @@ -451,9 +449,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.initSlides(this.slides); } - /** - *@hidden - */ + /** @hidden */ public ngOnDestroy() { this.destroy$.next(true); this.destroy$.complete(); @@ -646,9 +642,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { }); } - /** - * @hidden - */ + /** @hidden */ public get getIndicatorTemplate(): TemplateRef { if (this.indicatorTemplate) { return this.indicatorTemplate; @@ -656,9 +650,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return this.defaultIndicator; } - /** - * @hidden - */ + /** @hidden */ public get getNextButtonTemplate(): TemplateRef { if (this.nextButtonTemplate) { return this.nextButtonTemplate; @@ -666,9 +658,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return this.defaultNextButton; } - /** - * @hidden - */ + /** @hidden */ public get getPrevButtonTemplate(): TemplateRef { if (this.prevButtonTemplate) { return this.prevButtonTemplate; @@ -676,42 +666,27 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { return this.defaultPrevButton; } - /** - * @hidden - * @memberof IgxCarouselComponent - */ + /** @hidden */ public setAriaLabel(slide) { return `Item ${slide.index + 1} of ${this.total}`; } - /** - * @hidden - * @memberof IgxCarouselComponent - */ + /** @hidden */ public get indicatorsOrientationClass() { return `igx-carousel-indicators--${this.indicatorsOrientation}`; } - /** - * @hidden - * @memberof IgxCarouselComponent - */ + /** @hidden */ public get showIndicators(): boolean { return this.total <= this.maximumIndicatorsCount && this.total > 0; } - /** - * @hidden - * @memberof IgxCarouselComponent - */ + /** @hidden */ public get showIndicatorsLabel(): boolean { return this.total > this.maximumIndicatorsCount; } - /** - * @hidden - * @memberof IgxCarouselComponent - */ + /** @hidden */ public get getCarouselLabel() { return `${this.current + 1} ${this.resourceStrings.igx_carousel_of} ${this.total}`; } @@ -924,24 +899,17 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } - /** - *@hidden - */ + /** @hidden */ public get nextButtonDisabled() { return !this.loop && this.current === (this.total - 1); } - /** - *@hidden - */ + /** @hidden */ public get prevButtonDisabled() { return !this.loop && this.current === 0; } - - /** - *@hidden - */ + /** @hidden */ @HostListener('keydown.arrowright') public onKeydownArrowRight() { if (this.keyboardSupport) { @@ -950,9 +918,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { requestAnimationFrame(() => this.nativeElement.focus()); } } - /** - *@hidden - */ + + /** @hidden */ @HostListener('keydown.arrowleft') public onKeydownArrowLeft() { if (this.keyboardSupport) { @@ -978,9 +945,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } - /** - *@hidden - */ + /** @hidden */ @HostListener('keydown.home') public onKeydownHome() { if (this.keyboardSupport && this.slides.length > 0) { @@ -990,9 +955,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } - /** - *@hidden - */ + /** @hidden */ @HostListener('keydown.end') public onKeydownEnd() { if (this.keyboardSupport && this.slides.length > 0) { @@ -1002,9 +965,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } - /** - * @hidden - */ + /** @hidden */ @HostListener('mouseenter') public onMouseEnter() { if (this.pause && this.isPlaying) { @@ -1013,9 +974,7 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { this.stop(); } - /** - * @hidden - */ + /** @hidden */ @HostListener('mouseleave') public onMouseLeave() { if (this.stoppedByInteraction) { @@ -1023,17 +982,13 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } } - /** - * @hidden - */ + /** @hidden */ @HostListener('panleft', ['$event']) public onPanLeft(event) { this.pan(event); } - /** - * @hidden - */ + /** @hidden */ @HostListener('panright', ['$event']) public onPanRight(event) { this.pan(event); @@ -1087,8 +1042,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** - * @hidden - */ + * @hidden + */ @HostListener('panend', ['$event']) public onPanEnd(event) { if (!this.gesturesSupport) { From 311a5754db1203228aedd2e77c2929cc93862e81 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Fri, 22 Nov 2019 10:19:29 +0200 Subject: [PATCH 8/9] chore(*): update slides when a custem color is set --- .../lib/core/styles/components/carousel/_carousel-theme.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss index a8f2d05e5a6..5a3c0e1ef1a 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/carousel/_carousel-theme.scss @@ -306,14 +306,17 @@ bottom: 0; z-index: -1; background: --var($theme, 'slide-background'); + visibility: hidden; } %igx-carousel-slide--previous { z-index: 1; + visibility: visible; } %igx-carousel-slide--current { z-index: 2; + visibility: visible; } %igx-carousel-slide img { From 9506cef94582e2d60927f97dcf71a430e3d76c2d Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Fri, 22 Nov 2019 11:50:36 +0200 Subject: [PATCH 9/9] chore(*): update keydown events --- .../src/lib/carousel/carousel.component.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts index b563e75b40b..888b8e09e6a 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel.component.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel.component.ts @@ -910,8 +910,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** @hidden */ - @HostListener('keydown.arrowright') - public onKeydownArrowRight() { + @HostListener('keydown.arrowright', ['$event']) + public onKeydownArrowRight(event) { if (this.keyboardSupport) { event.preventDefault(); this.next(); @@ -920,8 +920,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** @hidden */ - @HostListener('keydown.arrowleft') - public onKeydownArrowLeft() { + @HostListener('keydown.arrowleft', ['$event']) + public onKeydownArrowLeft(event) { if (this.keyboardSupport) { event.preventDefault(); this.prev(); @@ -946,8 +946,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** @hidden */ - @HostListener('keydown.home') - public onKeydownHome() { + @HostListener('keydown.home', ['$event']) + public onKeydownHome(event) { if (this.keyboardSupport && this.slides.length > 0) { event.preventDefault(); this.slides.first.active = true; @@ -956,8 +956,8 @@ export class IgxCarouselComponent implements OnDestroy, AfterContentInit { } /** @hidden */ - @HostListener('keydown.end') - public onKeydownEnd() { + @HostListener('keydown.end', ['$event']) + public onKeydownEnd(event) { if (this.keyboardSupport && this.slides.length > 0) { event.preventDefault(); this.slides.last.active = true;