From 4a8a35e0f61824ab7eb02caa3247741ebd99457f Mon Sep 17 00:00:00 2001 From: Alexey Umanskiy Date: Thu, 4 Jul 2024 19:54:05 +0300 Subject: [PATCH 1/3] chore: sorted versions in docs dropdown (#6659) * 13.0.0 * 14.0.0 * 15.0.0 * 16.0.0 * 17.0.0 * 18.0.0 * chore: version of the lib synced with the version of the angular * chore(common-docs): added versions sorting * chore(common-docs): switched from '+' to Number() for more explicit conversion --- .../src/lib/common/top-menu/top-menu.component.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/common-docs/src/lib/common/top-menu/top-menu.component.ts b/libs/common-docs/src/lib/common/top-menu/top-menu.component.ts index 06f7d2e2f6..b21e45da08 100644 --- a/libs/common-docs/src/lib/common/top-menu/top-menu.component.ts +++ b/libs/common-docs/src/lib/common/top-menu/top-menu.component.ts @@ -44,8 +44,11 @@ export class TopMenuComponent implements AfterViewInit { this.http .get<{ url: string; version: string; unprefixedUrl: string }[]>('assets/json/versions.json') .subscribe((data) => { - this.previousDocs.push(data[0]); - this.previousDocs = this.previousDocs.concat(data.reverse()).slice(0, -1); + this.previousDocs = data.sort((versionA, versionB) => { + const versionAsNumberA = Number(versionA.version.split('.').join('')); + const versionAsNumberB = Number(versionB.version.split('.').join('')); + return versionAsNumberB - versionAsNumberA; + }); }); this.http.get<{ version: string }>('assets/json/current-version.json').subscribe((data: { version: string }) => { From e6e374d2d077221378d185f2a4bc1e7d48edafa6 Mon Sep 17 00:00:00 2001 From: hansi_reit Date: Fri, 5 Jul 2024 09:36:00 +0200 Subject: [PATCH 2/3] test(timepicker): fix silently failing unit-tests (#6628) Unit-tests that cannot fail are useless, therefore this fix * unit test now fail if the expected value does not match * remove duplicated unit test Closes #6545 Co-authored-by: Alexey Umanskiy --- .../testing/bs-daterangepicker.spec.ts | 52 +++++-------------- 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/src/datepicker/testing/bs-daterangepicker.spec.ts b/src/datepicker/testing/bs-daterangepicker.spec.ts index bb085ab6a2..617235f365 100644 --- a/src/datepicker/testing/bs-daterangepicker.spec.ts +++ b/src/datepicker/testing/bs-daterangepicker.spec.ts @@ -7,6 +7,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { By } from '@angular/platform-browser'; import { BsCustomDates } from '../themes/bs/bs-custom-dates-view.component'; +import { firstValueFrom } from 'rxjs'; @Component({ selector: 'test-cmp', @@ -87,7 +88,7 @@ describe('daterangepicker:', () => { expect(timepickerZone).not.toBeTruthy(); }); - it('should update time when time is changed in timepicker', () => { + it('should update time when time is changed in timepicker', (done) => { const directive = getDaterangepickerDirective(fixture); directive.bsConfig = { withTimepicker: true @@ -119,6 +120,7 @@ describe('daterangepicker:', () => { .subscribe(view => { expect(view[0].getMinutes()).toEqual(ranges[1].value[0].getMinutes()); expect(view[1].getMinutes()).toEqual(ranges[1].value[1].getMinutes()); + done(); }); }); @@ -185,7 +187,7 @@ describe('daterangepicker:', () => { expect(getDaterangepickerContainer(datepicker)).toBeNull(); }); - it('should display correct date range in input when selected from ranges', () => { + it('should display correct date range in input when selected from ranges', (done) => { const datepicker = showDatepicker(fixture); const ranges = [ { @@ -207,6 +209,7 @@ describe('daterangepicker:', () => { .select(state => state.selectedRange) .subscribe(view => { expect(view).toEqual(ranges[0].value); + done(); }); }); @@ -230,31 +233,6 @@ describe('daterangepicker:', () => { const rangesButton = document.querySelector('.bs-datepicker-predefined-btns'); expect(rangesButton.childElementCount).toEqual(ranges.length); - - }); - - it('should display correct date range in input when selected from ranges', () => { - const datepicker = showDatepicker(fixture); - const ranges = [ - { - label: 'Last 7 days', - value: [new Date('12-10-2019'), new Date('12-16-2019')] - }, - { - label: 'Next 7 days', - value: [new Date('12-16-2019'), new Date('12-22-2019')] - } - ]; - datepicker.bsConfig.ranges = ranges; - const datepickerContainerInstance = getDaterangepickerContainer(datepicker); - datepickerContainerInstance.setRangeOnCalendar(ranges[0]); - - fixture.detectChanges(); - datepickerContainerInstance[`_store`] - .select(state => state.selectedRange) - .subscribe(view => { - expect(view).toEqual(ranges[0].value); - }); }); it('should correctly display the selected range button with active custom class', () => { @@ -286,7 +264,7 @@ describe('daterangepicker:', () => { expect(activeRangeButton[0].innerHTML.trim()).toEqual(ranges[0].label); }); - it('should not allow to select date behind max value', () => { + it('should not allow to select date behind max value', async () => { const datepicker = showDatepicker(fixture); datepicker.bsConfig.maxDate = new Date(); datepicker.bsConfig.maxDateRange = 10; @@ -300,15 +278,12 @@ describe('daterangepicker:', () => { value: [correctDateStart, correctDateEnd] }; - datepickerContainerInstance.setMaxDateRangeOnCalendar(correctDateStart); + datepickerContainerInstance.setMaxDateRangeOnCalendar(correctDateEnd); datepickerContainerInstance.setRangeOnCalendar(selectedRange); fixture.detectChanges(); - datepickerContainerInstance[`_store`] - .select(state => state) - .subscribe(view => { - expect(view.maxDate).toEqual(correctDateEnd); - }); + let view = await firstValueFrom(datepickerContainerInstance[`_store`].select((state) => state)); + expect(view.maxDate).toEqual(correctDateEnd); const incorrectCaseStart = new Date(new Date().setDate(new Date().getDate() - 5)); const incorrectCaseEnd = new Date(new Date().setDate(new Date().getDate() + 15)); @@ -321,10 +296,7 @@ describe('daterangepicker:', () => { datepickerContainerInstance.setRangeOnCalendar(selectedRange1); fixture.detectChanges(); - datepickerContainerInstance[`_store`] - .select(state => state) - .subscribe(view => { - expect(view.maxDate).not.toEqual(incorrectCaseEnd); - }); - }); + view = await firstValueFrom(datepickerContainerInstance[`_store`].select((state) => state)); + expect(view.maxDate).not.toEqual(incorrectCaseEnd); }); +}); From 876f20d29042c53b0d111eecd84e87fad8e6f22d Mon Sep 17 00:00:00 2001 From: Joschua Schneider Date: Fri, 5 Jul 2024 13:27:36 +0200 Subject: [PATCH 3/3] fix(ComponentLoader): loader leaks memory in multiple places (#6625) * fix(ComponentLoader): loader leaks memory in multiple places * Fix(component-loader): fixing lint --------- Co-authored-by: Alexey Umanskiy --- src/component-loader/component-loader.class.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/component-loader/component-loader.class.ts b/src/component-loader/component-loader.class.ts index 2f60d5f23c..a6e46f5eb5 100644 --- a/src/component-loader/component-loader.class.ts +++ b/src/component-loader/component-loader.class.ts @@ -226,6 +226,7 @@ export class ComponentLoader { ); } this._contentRef?.viewRef?.destroy(); + this._componentRef?.destroy(); this._contentRef = void 0; this._componentRef = void 0; @@ -312,12 +313,16 @@ export class ComponentLoader { if (!this._componentRef || !this._componentRef.location) { return; } + + let unsubscribeOutsideClick = Function.prototype; + let unsubscribeEscClick = Function.prototype; + // why: should run after first event bubble if (this._listenOpts.outsideClick) { const target = this._componentRef.location.nativeElement; setTimeout(() => { if (this._renderer && this._elementRef) { - this._globalListener = registerOutsideClick(this._renderer, { + unsubscribeOutsideClick = registerOutsideClick(this._renderer, { targets: [target, this._elementRef.nativeElement], outsideClick: this._listenOpts.outsideClick, hide: () => this._listenOpts.hide && this._listenOpts.hide() @@ -327,12 +332,17 @@ export class ComponentLoader { } if (this._listenOpts.outsideEsc && this._renderer && this._elementRef) { const target = this._componentRef.location.nativeElement; - this._globalListener = registerEscClick(this._renderer, { + unsubscribeEscClick = registerEscClick(this._renderer, { targets: [target, this._elementRef.nativeElement], outsideEsc: this._listenOpts.outsideEsc, hide: () => this._listenOpts.hide && this._listenOpts.hide() }); } + + this._globalListener = () => { + unsubscribeOutsideClick(); + unsubscribeEscClick(); + }; } getInnerComponent(): ComponentRef | undefined {