@sumaris-net/ngx-components 18.23.0-beta.3 → 18.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/doc/changelog.md +16 -1
  2. package/esm2022/public_api.mjs +1 -4
  3. package/esm2022/src/app/core/services/platform.service.mjs +27 -3
  4. package/esm2022/src/app/core/table/column/actions-column.component.mjs +1 -1
  5. package/esm2022/src/app/core/table/table.pipes.mjs +7 -6
  6. package/esm2022/src/app/core/table/testing/table.testing.module.mjs +4 -25
  7. package/esm2022/src/app/core/table/testing/table2.testing.mjs +15 -63
  8. package/esm2022/src/app/shared/constants.mjs +2 -2
  9. package/esm2022/src/app/shared/dates.mjs +52 -20
  10. package/esm2022/src/app/shared/file/csv.utils.mjs +2 -2
  11. package/esm2022/src/app/shared/functions.mjs +1 -1
  12. package/esm2022/src/app/shared/material/autocomplete/material.autocomplete.mjs +3 -3
  13. package/esm2022/src/app/shared/material/chips/material.chips.mjs +3 -3
  14. package/esm2022/src/app/shared/regexps.mjs +18 -11
  15. package/esm2022/src/app/shared/validator/validators.mjs +2 -2
  16. package/esm2022/src/app/social/feed/feed.component.mjs +3 -3
  17. package/fesm2022/sumaris-net.ngx-components.mjs +121 -529
  18. package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
  19. package/package.json +1 -1
  20. package/public_api.d.ts +0 -3
  21. package/src/app/core/install/install-upgrade-card.component.d.ts +1 -1
  22. package/src/app/core/services/platform.service.d.ts +1 -1
  23. package/src/app/core/table/column/actions-column.component.d.ts +1 -1
  24. package/src/app/core/table/table.pipes.d.ts +1 -2
  25. package/src/app/core/table/testing/table.testing.module.d.ts +1 -3
  26. package/src/app/core/table/testing/table2.testing.d.ts +3 -7
  27. package/src/app/shared/dates.d.ts +28 -4
  28. package/src/app/shared/functions.d.ts +1 -1
  29. package/src/app/shared/inputs.d.ts +1 -1
  30. package/src/assets/manifest.json +1 -1
  31. package/src/theme/_ngx-components.table.scss +2 -48
  32. package/esm2022/src/app/shared/directives/cell-selection/cell-identifier.directive.mjs +0 -41
  33. package/esm2022/src/app/shared/directives/cell-selection/cell-selection.directive.mjs +0 -201
  34. package/esm2022/src/app/shared/directives/cell-selection/cell-selection.service.mjs +0 -180
  35. package/src/app/shared/directives/cell-selection/cell-identifier.directive.d.ts +0 -15
  36. package/src/app/shared/directives/cell-selection/cell-selection.directive.d.ts +0 -28
  37. package/src/app/shared/directives/cell-selection/cell-selection.service.d.ts +0 -62
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sumaris-net/ngx-components",
3
3
  "description": "SUMARiS Angular components",
4
- "version": "18.23.0-beta.3",
4
+ "version": "18.23.0",
5
5
  "author": "contact@e-is.pro",
6
6
  "license": "AGPL-3.0",
7
7
  "readmeFilename": "README.md",
package/public_api.d.ts CHANGED
@@ -68,9 +68,6 @@ export * from './src/app/shared/directives/resizable/resizable.directive';
68
68
  export * from './src/app/shared/directives/resizable/resizable.component';
69
69
  export * from './src/app/shared/directives/resizable/resizable.module';
70
70
  export * from './src/app/shared/directives/autoresize.directive';
71
- export * from './src/app/shared/directives/cell-selection/cell-selection.service';
72
- export * from './src/app/shared/directives/cell-selection/cell-selection.directive';
73
- export * from './src/app/shared/directives/cell-selection/cell-identifier.directive';
74
71
  export * from './src/app/shared/pipes/pipes.module';
75
72
  export * from './src/app/shared/pipes/date-format.pipe';
76
73
  export * from './src/app/shared/pipes/date-from.pipe';
@@ -46,7 +46,7 @@ export declare class AppInstallUpgradeCard implements OnInit, OnDestroy {
46
46
  download(event: Event, link: InstallAppLink): Promise<void>;
47
47
  openFile(event: Event, link: InstallAppLink): Promise<void>;
48
48
  tryOnline(): Promise<void>;
49
- getPlatformName(platform: 'android' | 'ios' | 'electron'): "" | "desktop" | "Android" | "iOS";
49
+ getPlatformName(platform: 'android' | 'ios' | 'electron'): "desktop" | "" | "Android" | "iOS";
50
50
  asLink(value: any): InstallAppLink;
51
51
  private checkNeedInstallOrUpdate;
52
52
  private getCompatibleInstallLinks;
@@ -91,7 +91,7 @@ export declare class PlatformService extends StartableService {
91
91
  filename?: string;
92
92
  } & Partial<DownloadRequest>): Observable<string | undefined>;
93
93
  copyToClipboard(data: string | WriteOptions, opts?: ShowToastOptions): Promise<void>;
94
- toggleDarkTheme(enable: boolean): void;
94
+ toggleDarkTheme(enable: boolean): Promise<void>;
95
95
  toggleHighContrast(enable: boolean): void;
96
96
  showToast(opts: ShowToastOptions): Promise<HTMLIonToastElement>;
97
97
  closeToast(id?: string): Promise<boolean>;
@@ -3,7 +3,7 @@ import { AsyncTableElement, TableElement } from '@e-is/ngx-material-table';
3
3
  import { MatColumnDef, MatTable } from '@angular/material/table';
4
4
  import { MatMenuTrigger } from '@angular/material/menu';
5
5
  import * as i0 from "@angular/core";
6
- export declare class ActionsColumnComponent<T extends TableElement<any> | AsyncTableElement<any>> implements OnInit, OnDestroy {
6
+ export declare class ActionsColumnComponent<T extends TableElement<any> | AsyncTableElement<any> = TableElement<any>> implements OnInit, OnDestroy {
7
7
  private table;
8
8
  private cd;
9
9
  columnDef: MatColumnDef;
@@ -6,11 +6,10 @@ import { Subscription } from 'rxjs';
6
6
  import { AppAsyncTable } from './async-table.class';
7
7
  import * as i0 from "@angular/core";
8
8
  export type AppTableRowCountProperty = 'visibleRowCount' | 'totalRowCount';
9
- export declare abstract class AbstractTableSelectionPipe<R, O, T extends AppTable<any> | AppAsyncTable<any> = AppTable<any> | AppAsyncTable<any>> extends AbstractSelectionModelPipe<any, R, O> implements PipeTransform, OnDestroy {
9
+ export declare abstract class AbstractTableSelectionPipe<R, O, T extends AppTable<any> | AppAsyncTable<any> = AppTable<any> | AppAsyncTable<any>> extends AbstractSelectionModelPipe<any, R, O> {
10
10
  private _onRowsChanges;
11
11
  protected constructor(_ref: ChangeDetectorRef);
12
12
  transform(selectionOrTable: SelectionModel<any> | T, tableOrOpts?: T | O, opts?: O): R;
13
- private isTable;
14
13
  protected _subscribe(selection: SelectionModel<any>, table?: T, opts?: O): Subscription;
15
14
  protected _dispose(): void;
16
15
  static ɵfac: i0.ɵɵFactoryDeclaration<AbstractTableSelectionPipe<any, any, any>, never>;
@@ -7,10 +7,8 @@ import * as i5 from "../../core.module";
7
7
  import * as i6 from "@ngx-translate/core";
8
8
  import * as i7 from "@angular/forms";
9
9
  import * as i8 from "../../../shared/directives/resizable/resizable.module";
10
- import * as i9 from "../../../shared/directives/cell-selection/cell-identifier.directive";
11
- import * as i10 from "../../../shared/directives/cell-selection/cell-selection.directive";
12
10
  export declare class TableTestingModule {
13
11
  static ɵfac: i0.ɵɵFactoryDeclaration<TableTestingModule, never>;
14
- static ɵmod: i0.ɵɵNgModuleDeclaration<TableTestingModule, [typeof i1.TableTestPage, typeof i2.Table2TestPage], [typeof i3.CommonModule, typeof i4.SharedModule, typeof i5.CoreModule, typeof i6.TranslateModule, typeof i7.FormsModule, typeof i8.ResizableModule, typeof i9.CellIdentifierDirective, typeof i10.CellSelectionDirective], [typeof i1.TableTestPage, typeof i2.Table2TestPage, typeof i6.TranslateModule]>;
12
+ static ɵmod: i0.ɵɵNgModuleDeclaration<TableTestingModule, [typeof i1.TableTestPage, typeof i2.Table2TestPage], [typeof i3.CommonModule, typeof i4.SharedModule, typeof i5.CoreModule, typeof i6.TranslateModule, typeof i7.FormsModule, typeof i8.ResizableModule], [typeof i1.TableTestPage, typeof i2.Table2TestPage, typeof i6.TranslateModule]>;
15
13
  static ɵinj: i0.ɵɵInjectorDeclaration<TableTestingModule>;
16
14
  }
@@ -1,4 +1,5 @@
1
1
  import { AfterViewInit, Injector, OnDestroy, OnInit } from '@angular/core';
2
+ import { AppTable } from '../table.class';
2
3
  import { Referential } from '../../services/model/referential.model';
3
4
  import { IonInfiniteScroll } from '@ionic/angular';
4
5
  import { InMemoryEntitiesService } from '../../../shared/services/memory-entity-service.class';
@@ -6,10 +7,8 @@ import { AppValidatorService } from '../../services/validator/base.validator.cla
6
7
  import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
7
8
  import { ReferentialFilter } from '../../services/testing/referential-filter.model';
8
9
  import { MatExpansionPanel } from '@angular/material/expansion';
9
- import { AppAsyncTable } from '../async-table.class';
10
- import { CellSelectionEvent, ICellId } from '../../../shared/directives/cell-selection/cell-selection.service';
11
10
  import * as i0 from "@angular/core";
12
- export declare class Table2TestPage extends AppAsyncTable<Referential, ReferentialFilter> implements OnInit, OnDestroy, AfterViewInit {
11
+ export declare class Table2TestPage extends AppTable<Referential, ReferentialFilter> implements OnInit, OnDestroy, AfterViewInit {
13
12
  protected validatorService: AppValidatorService;
14
13
  protected formBuilder: UntypedFormBuilder;
15
14
  static readonly maxRowCount = 100;
@@ -27,7 +26,6 @@ export declare class Table2TestPage extends AppAsyncTable<Referential, Referenti
27
26
  get hasMoreData(): boolean;
28
27
  filterExpansionPanel: MatExpansionPanel;
29
28
  infiniteScroll: IonInfiniteScroll;
30
- protected readonly selectableColumns: string[];
31
29
  get dataService(): InMemoryEntitiesService<Referential>;
32
30
  constructor(injector: Injector, validatorService: AppValidatorService, formBuilder: UntypedFormBuilder);
33
31
  ngOnInit(): void;
@@ -43,10 +41,8 @@ export declare class Table2TestPage extends AppAsyncTable<Referential, Referenti
43
41
  toggleFilterPanelFloating(): void;
44
42
  applyFilterAndClosePanel(event?: Event): void;
45
43
  closeFilterPanel(): void;
46
- resetFilter(event?: Event): Promise<void>;
44
+ resetFilter(_?: Event): void;
47
45
  protected generateData(offset?: number, size?: number): Referential[];
48
- protected onCellSelectionChange(event: CellSelectionEvent<ICellId>): void;
49
- protected onCellRightClick(event: MouseEvent): void;
50
46
  static ɵfac: i0.ɵɵFactoryDeclaration<Table2TestPage, never>;
51
47
  static ɵcmp: i0.ɵɵComponentDeclaration<Table2TestPage, "app-table2-testing", never, { "filterPanelFloating": { "alias": "filterPanelFloating"; "required": false; }; "sticky": { "alias": "sticky"; "required": false; }; "stickyEnd": { "alias": "stickyEnd"; "required": false; }; }, {}, never, ["[suffix]"], false, never>;
52
48
  }
@@ -13,6 +13,8 @@ export declare class DateUtils {
13
13
  static moment: MomentFn;
14
14
  static toDateISOString: typeof toDateISOString;
15
15
  static fromDateISOString: typeof fromDateISOString;
16
+ static fromUnixTimestamp: typeof fromUnixTimestamp;
17
+ static fromUnixMsTimestamp: typeof fromUnixMsTimestamp;
16
18
  static toDuration: typeof toDuration;
17
19
  static min(date1: Moment, date2: Moment): Moment;
18
20
  static max(date1: Moment | string, date2: Moment | string): Moment;
@@ -37,7 +39,7 @@ export declare class DateUtils {
37
39
  * @param keepLocalTime if true, only the timezone (and offset) is updated, keeping the local time same. Consequently, it will now point to a different point in time if the offset has changed.
38
40
  */
39
41
  static resetTime(value: Moment | string, timezone?: string, keepLocalTime?: boolean): Moment | undefined;
40
- static markNoTime(value: Moment): Moment | undefined;
42
+ static markNoTime(value: Moment | undefined): Moment | undefined;
41
43
  static markTime(value: Moment): Moment | undefined;
42
44
  static isNoTime(value: Moment): boolean;
43
45
  /**
@@ -53,9 +55,31 @@ export declare class DateUtils {
53
55
  seconds?: boolean;
54
56
  } | any): string;
55
57
  }
58
+ /**
59
+ * Converts the given value to an ISO date string representation.
60
+ *
61
+ * @param {any} value - The value to be transformed into an ISO date string. This can be a date, a string, or other compatible formats.
62
+ * @return {string | undefined} Returns the ISO date string if the conversion is successful; otherwise, returns undefined.
63
+ */
56
64
  export declare function toDateISOString(value: any): string | undefined;
57
- export declare function fromDateISOString(value: any): Moment | undefined;
58
- export declare function fromUnixTimestamp(timeInSec: number): momentImported.Moment;
59
- export declare function fromUnixMsTimestamp(timeInMs: number): momentImported.Moment;
65
+ /**
66
+ * Converts a given value to a Moment object if possible.
67
+ * If the given value is already a Moment object, it will simply return it.
68
+ * The method handles strings in ISO date formats, UNIX timestamps, and performs validation based on provided options.
69
+ *
70
+ * @param {any} value - The value to be converted to a Moment object. This can be a string representing a date, a UNIX timestamp, or a Moment object.
71
+ * @param {Object} [opts] - Optional parameters for controlling the method's behavior.
72
+ * @param {boolean} [opts.undefinedIfInvalid=true] - Determines if the method should return undefined for invalid dates. If set to false, an invalid Moment object will be returned instead.
73
+ * @param {boolean} [opts.strict=false] - Controls whether strict validation is performed. Strict mode enforces stricter date parsing rules.
74
+ * @param {boolean} [opts.requiredTime=false] - Allow to parse a date without any time
75
+ * @return {Moment | undefined} A Moment object if the value is successfully converted, or undefined if the conversion is not possible and undefinedIfInvalid is true.
76
+ */
77
+ export declare function fromDateISOString(value: any, opts?: {
78
+ undefinedIfInvalid?: boolean;
79
+ strict?: boolean;
80
+ requiredTime?: boolean;
81
+ }): Moment | undefined;
82
+ export declare function fromUnixTimestamp(timeInSec: MomentInput): momentImported.Moment;
83
+ export declare function fromUnixMsTimestamp(timeInMs: MomentInput): momentImported.Moment;
60
84
  export declare function toDuration(value: number, unit?: unitOfTime.DurationConstructor): Duration | undefined;
61
85
  export {};
@@ -6,7 +6,7 @@ export declare function isNotNil<T>(obj: T | null | undefined): boolean;
6
6
  export declare function isNotNilOrBlank<T>(obj: T | null | undefined): boolean;
7
7
  export declare function isNotNilOrNaN<T>(obj: T | null | undefined): boolean;
8
8
  export declare function isNilOrNaN<T>(obj: T | null | undefined): boolean;
9
- export declare function isNotEmptyArray<T>(obj: T[] | readonly T[] | null | undefined): boolean;
9
+ export declare function isNotEmptyArray<T>(obj: T[] | null | undefined): boolean;
10
10
  export declare function firstArrayValue<T>(obj: T[] | null | undefined): T | undefined;
11
11
  export declare function lastArrayValue<T>(obj: T[] | null | undefined): T | undefined;
12
12
  export declare function isEmptyArray<T>(obj: T[] | null | undefined): boolean;
@@ -17,7 +17,7 @@ export interface InputElement extends FocusableElement {
17
17
  }
18
18
  export declare function isInputElement(object: any): object is InputElement;
19
19
  export declare function asInputElement<T = any>(object: ElementRef<T>): InputElement | undefined;
20
- export declare function tabindexComparator(a: InputElement, b: InputElement): 0 | 1 | -1;
20
+ export declare function tabindexComparator(a: InputElement, b: InputElement): 1 | 0 | -1;
21
21
  export interface CanGainFocusOptions {
22
22
  minTabindex?: number;
23
23
  maxTabindex?: number;
@@ -2,7 +2,7 @@
2
2
  "name": "ngx-sumaris-components",
3
3
  "short_name": "ngx-sumaris-components",
4
4
  "manifest_version": 1,
5
- "version": "18.22.23",
5
+ "version": "18.23.0",
6
6
  "default_locale": "fr",
7
7
  "description": "Angular components for building beautiful and responsive Apps",
8
8
  "icons": [{
@@ -249,6 +249,7 @@
249
249
 
250
250
  .mat-mdc-row,
251
251
  .mat-mdc-footer-row {
252
+
252
253
  // Disabled row
253
254
  &.mat-mdc-row-disabled *,
254
255
  &.mat-row-disabled * {
@@ -549,56 +550,9 @@
549
550
  border-bottom-width: var(--mat-table-row-item-outline-width, 1px) !important;
550
551
  border-bottom-style: solid !important;
551
552
  }
552
-
553
- // Cell selection
554
- --app-cell-selected-color: var(--ion-color-secondary50);
555
- --app-cell-dragging-color: var(--ion-color-secondary50-shade);
556
- --app-cell-selection-border-color: var(--ion-color-accent, gray);
557
-
558
- td.cell-selected {
559
- background-color: var(--app-cell-selected-color) !important;
560
- }
561
-
562
- td.cell-dragging {
563
- background-color: var(--app-cell-dragging-color) !important;
564
- }
565
-
566
- div.cell-selection-overlay {
567
- position: absolute;
568
- z-index: 5;
569
- animation: linearGradientMove 0.3s infinite linear;
570
- background:
571
- linear-gradient(90deg, var(--app-cell-selection-border-color) 50%, transparent 0) repeat-x,
572
- linear-gradient(90deg, var(--app-cell-selection-border-color) 50%, transparent 0) repeat-x,
573
- linear-gradient(0deg, var(--app-cell-selection-border-color) 50%, transparent 0) repeat-y,
574
- linear-gradient(0deg, var(--app-cell-selection-border-color) 50%, transparent 0) repeat-y;
575
- background-size:
576
- 4px 2px,
577
- 4px 2px,
578
- 2px 4px,
579
- 2px 4px;
580
- background-position:
581
- 0 0,
582
- 0 100%,
583
- 0 0,
584
- 100% 0;
585
- background-color: unset;
586
- box-sizing: border-box;
587
- pointer-events: none;
588
- }
589
-
590
- // Animated dashed border keyframes
591
- @keyframes linearGradientMove {
592
- 100% {
593
- background-position:
594
- 4px 0,
595
- -4px 100%,
596
- 0 -4px,
597
- 100% 4px;
598
- }
599
- }
600
553
  }
601
554
 
555
+
602
556
  // Paginator
603
557
  .mat-mdc-paginator {
604
558
  --mat-paginator-container-size: var(--app-paginator-height, #{$app-paginator-height});
@@ -1,41 +0,0 @@
1
- import { DestroyRef, Directive, inject, input } from '@angular/core';
2
- import { APP_CELL_SELECTION_SERVICE_TOKEN } from './cell-selection.service';
3
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
- import * as i0 from "@angular/core";
5
- export class CellIdentifierDirective {
6
- cellId = input.required({ alias: 'appCellId' });
7
- isCellSelected = false;
8
- isDragging = false;
9
- service = inject(APP_CELL_SELECTION_SERVICE_TOKEN);
10
- destroyRef = inject(DestroyRef);
11
- ngOnInit() {
12
- // Listen to service selection changes and emit
13
- this.service.selectionChangeSubject
14
- .pipe(takeUntilDestroyed(this.destroyRef))
15
- .subscribe(() => (this.isCellSelected = this.service.isCellSelected(this.cellId())));
16
- }
17
- async handleMouseDown(event) {
18
- await this.service.handleCellMouseDown(event, this.cellId());
19
- }
20
- async handleMouseEnter(event) {
21
- await this.service.handleCellMouseEnter(event, this.cellId());
22
- }
23
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CellIdentifierDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
24
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.13", type: CellIdentifierDirective, isStandalone: true, selector: "[appCellId]", inputs: { cellId: { classPropertyName: "cellId", publicName: "appCellId", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "mousedown": "handleMouseDown($event)", "mouseenter": "handleMouseEnter($event)" }, properties: { "class.cell-selected": "isCellSelected", "class.cell-dragging": "isDragging", "attr.data-row-id": "cellId().rowId", "attr.data-column-name": "cellId().columnName" } }, ngImport: i0 });
25
- }
26
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CellIdentifierDirective, decorators: [{
27
- type: Directive,
28
- args: [{
29
- selector: '[appCellId]',
30
- standalone: true,
31
- host: {
32
- '(mousedown)': 'handleMouseDown($event)',
33
- '(mouseenter)': 'handleMouseEnter($event)',
34
- '[class.cell-selected]': 'isCellSelected',
35
- '[class.cell-dragging]': 'isDragging',
36
- '[attr.data-row-id]': 'cellId().rowId',
37
- '[attr.data-column-name]': 'cellId().columnName',
38
- },
39
- }]
40
- }] });
41
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VsbC1pZGVudGlmaWVyLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvc2hhcmVkL2RpcmVjdGl2ZXMvY2VsbC1zZWxlY3Rpb24vY2VsbC1pZGVudGlmaWVyLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQzdFLE9BQU8sRUFBRSxnQ0FBZ0MsRUFBVyxNQUFNLDBCQUEwQixDQUFDO0FBQ3JGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDOztBQWNoRSxNQUFNLE9BQU8sdUJBQXVCO0lBQ2xDLE1BQU0sR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFJLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFFekMsY0FBYyxHQUFHLEtBQUssQ0FBQztJQUN2QixVQUFVLEdBQUcsS0FBSyxDQUFDO0lBRVosT0FBTyxHQUFHLE1BQU0sQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO0lBQ25ELFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7SUFFakQsUUFBUTtRQUNOLCtDQUErQztRQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLHNCQUFzQjthQUNoQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQ3pDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pGLENBQUM7SUFFUyxLQUFLLENBQUMsZUFBZSxDQUFDLEtBQWlCO1FBQy9DLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVTLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFpQjtRQUNoRCxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7d0dBdEJVLHVCQUF1Qjs0RkFBdkIsdUJBQXVCOzs0RkFBdkIsdUJBQXVCO2tCQVpuQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxhQUFhO29CQUN2QixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsSUFBSSxFQUFFO3dCQUNKLGFBQWEsRUFBRSx5QkFBeUI7d0JBQ3hDLGNBQWMsRUFBRSwwQkFBMEI7d0JBQzFDLHVCQUF1QixFQUFFLGdCQUFnQjt3QkFDekMsdUJBQXVCLEVBQUUsWUFBWTt3QkFDckMsb0JBQW9CLEVBQUUsZ0JBQWdCO3dCQUN0Qyx5QkFBeUIsRUFBRSxxQkFBcUI7cUJBQ2pEO2lCQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGVzdHJveVJlZiwgRGlyZWN0aXZlLCBpbmplY3QsIGlucHV0LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFQUF9DRUxMX1NFTEVDVElPTl9TRVJWSUNFX1RPS0VOLCBJQ2VsbElkIH0gZnJvbSAnLi9jZWxsLXNlbGVjdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcblxuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnW2FwcENlbGxJZF0nLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBob3N0OiB7XG4gICAgJyhtb3VzZWRvd24pJzogJ2hhbmRsZU1vdXNlRG93bigkZXZlbnQpJyxcbiAgICAnKG1vdXNlZW50ZXIpJzogJ2hhbmRsZU1vdXNlRW50ZXIoJGV2ZW50KScsXG4gICAgJ1tjbGFzcy5jZWxsLXNlbGVjdGVkXSc6ICdpc0NlbGxTZWxlY3RlZCcsXG4gICAgJ1tjbGFzcy5jZWxsLWRyYWdnaW5nXSc6ICdpc0RyYWdnaW5nJyxcbiAgICAnW2F0dHIuZGF0YS1yb3ctaWRdJzogJ2NlbGxJZCgpLnJvd0lkJyxcbiAgICAnW2F0dHIuZGF0YS1jb2x1bW4tbmFtZV0nOiAnY2VsbElkKCkuY29sdW1uTmFtZScsXG4gIH0sXG59KVxuZXhwb3J0IGNsYXNzIENlbGxJZGVudGlmaWVyRGlyZWN0aXZlPEMgZXh0ZW5kcyBJQ2VsbElkID0gSUNlbGxJZD4gaW1wbGVtZW50cyBPbkluaXQge1xuICBjZWxsSWQgPSBpbnB1dC5yZXF1aXJlZDxDPih7IGFsaWFzOiAnYXBwQ2VsbElkJyB9KTtcblxuICBwcm90ZWN0ZWQgaXNDZWxsU2VsZWN0ZWQgPSBmYWxzZTtcbiAgcHJvdGVjdGVkIGlzRHJhZ2dpbmcgPSBmYWxzZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHNlcnZpY2UgPSBpbmplY3QoQVBQX0NFTExfU0VMRUNUSU9OX1NFUlZJQ0VfVE9LRU4pO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgLy8gTGlzdGVuIHRvIHNlcnZpY2Ugc2VsZWN0aW9uIGNoYW5nZXMgYW5kIGVtaXRcbiAgICB0aGlzLnNlcnZpY2Uuc2VsZWN0aW9uQ2hhbmdlU3ViamVjdFxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+ICh0aGlzLmlzQ2VsbFNlbGVjdGVkID0gdGhpcy5zZXJ2aWNlLmlzQ2VsbFNlbGVjdGVkKHRoaXMuY2VsbElkKCkpKSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgaGFuZGxlTW91c2VEb3duKGV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgYXdhaXQgdGhpcy5zZXJ2aWNlLmhhbmRsZUNlbGxNb3VzZURvd24oZXZlbnQsIHRoaXMuY2VsbElkKCkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGhhbmRsZU1vdXNlRW50ZXIoZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBhd2FpdCB0aGlzLnNlcnZpY2UuaGFuZGxlQ2VsbE1vdXNlRW50ZXIoZXZlbnQsIHRoaXMuY2VsbElkKCkpO1xuICB9XG59XG4iXX0=
@@ -1,201 +0,0 @@
1
- import { DestroyRef, Directive, ElementRef, inject, input, output, Renderer2 } from '@angular/core';
2
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
- import { fromEvent } from 'rxjs';
4
- import { APP_CELL_SELECTION_SERVICE_TOKEN } from './cell-selection.service';
5
- import { isEmptyArray, isNotEmptyArray } from '../../functions';
6
- import * as i0 from "@angular/core";
7
- export class CellSelectionDirective {
8
- // Inputs
9
- // eslint-disable-next-line @angular-eslint/no-input-rename
10
- selectableColumns = input([], { alias: 'appSelectableColumns' });
11
- // Outputs
12
- // eslint-disable-next-line @angular-eslint/no-output-rename
13
- selectionChange = output({ alias: 'appCellSelectionChange' });
14
- // eslint-disable-next-line @angular-eslint/no-output-rename
15
- rightClick = output({ alias: 'appCellRightClick' });
16
- // Inject service by token
17
- service = inject(APP_CELL_SELECTION_SERVICE_TOKEN);
18
- elementRef = inject(ElementRef);
19
- renderer = inject(Renderer2);
20
- destroyRef = inject(DestroyRef);
21
- overlayElements = [];
22
- constructor() { }
23
- ngOnInit() {
24
- // Initialize service with selectable columns
25
- this.setupServiceConfiguration();
26
- // Setup global mouseup listener
27
- this.setupGlobalMouseEvents();
28
- // Setup keyboard listener for copy (for test)
29
- // this.setupCopyListener();
30
- }
31
- setupServiceConfiguration() {
32
- // Pass selectable columns to service
33
- this.service.selectableColumns = this.selectableColumns();
34
- // Listen to service selection changes and emit
35
- this.service.selectionChangeSubject
36
- .pipe(takeUntilDestroyed(this.destroyRef))
37
- .subscribe((event) => this.selectionChange.emit(event));
38
- // Listen to right-click event
39
- this.service.selectionRightClickSubject.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => this.rightClick.emit(event));
40
- }
41
- setupGlobalMouseEvents() {
42
- fromEvent(document, 'mouseup')
43
- .pipe(takeUntilDestroyed(this.destroyRef))
44
- .subscribe(() => this.service.endMouseMove());
45
- }
46
- // For test purpose only (type CTRL+C)
47
- setupCopyListener() {
48
- fromEvent(document, 'keydown')
49
- .pipe(takeUntilDestroyed(this.destroyRef))
50
- .subscribe((event) => {
51
- if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
52
- const cells = this.service.selectedCells;
53
- if (isNotEmptyArray(cells)) {
54
- // Show overlay
55
- this.addCellsOverlay(cells);
56
- event.preventDefault();
57
- // Hide overlay after animation completes (1 second)
58
- setTimeout(() => {
59
- this.removeCellsOverlay();
60
- }, 1000);
61
- }
62
- }
63
- });
64
- }
65
- addCellsOverlay(cells) {
66
- // Remove existing overlays
67
- this.removeCellsOverlay();
68
- // Group cells into contiguous regions
69
- const cellGroups = this.groupContiguousCells(cells);
70
- // Create and render overlay for each contiguous region
71
- cellGroups.forEach((group) => {
72
- const bounds = this.calculateSelectionBounds(group);
73
- if (bounds) {
74
- const overlay = this.createOverlayElement(bounds);
75
- this.renderer.appendChild(this.elementRef.nativeElement, overlay);
76
- this.overlayElements.push(overlay);
77
- }
78
- });
79
- }
80
- removeCellsOverlay() {
81
- this.overlayElements.forEach((overlay) => {
82
- this.renderer.removeChild(this.elementRef.nativeElement, overlay);
83
- });
84
- this.overlayElements = [];
85
- }
86
- groupContiguousCells(cells) {
87
- // Create a map for quick lookup
88
- const cellMap = new Map();
89
- cells.forEach((cell) => {
90
- cellMap.set(this.getCellKey(cell), cell);
91
- });
92
- const visited = new Set();
93
- const groups = [];
94
- // Process each cell
95
- cells.forEach((cell) => {
96
- const key = this.getCellKey(cell);
97
- if (visited.has(key)) {
98
- return;
99
- }
100
- // Start a new contiguous group with flood-fill
101
- const group = [];
102
- const queue = [cell];
103
- visited.add(key);
104
- while (queue.length > 0) {
105
- const current = queue.shift();
106
- group.push(current);
107
- // Check all 4 adjacent cells (up, down, left, right)
108
- const neighbors = this.getAdjacentCells(current);
109
- neighbors.forEach((neighbor) => {
110
- const neighborKey = this.getCellKey(neighbor);
111
- if (cellMap.has(neighborKey) && !visited.has(neighborKey)) {
112
- visited.add(neighborKey);
113
- queue.push(neighbor);
114
- }
115
- });
116
- }
117
- groups.push(group);
118
- });
119
- return groups;
120
- }
121
- getAdjacentCells(cell) {
122
- // Returns cells adjacent to the current cell (up, down, left, right)
123
- // Note: We need to get column order from the actual table structure
124
- // For now, we'll use a simple approach based on rowId adjacency
125
- return [
126
- { rowId: cell.rowId - 1, columnName: cell.columnName }, // up
127
- { rowId: cell.rowId + 1, columnName: cell.columnName }, // down
128
- { rowId: cell.rowId, columnName: this.getNextColumnName(cell.columnName, -1) }, // left
129
- { rowId: cell.rowId, columnName: this.getNextColumnName(cell.columnName, 1) }, // right
130
- ].filter((c) => c.columnName !== null);
131
- }
132
- getNextColumnName(currentColumnName, offset) {
133
- const columns = this.service.selectableColumns;
134
- const currentIndex = columns.indexOf(currentColumnName);
135
- if (currentIndex === -1) {
136
- return null;
137
- }
138
- const newIndex = currentIndex + offset;
139
- if (newIndex < 0 || newIndex >= columns.length) {
140
- return null;
141
- }
142
- return columns[newIndex];
143
- }
144
- getCellKey(cell) {
145
- return `${cell.rowId}-${cell.columnName}`;
146
- }
147
- calculateSelectionBounds(cells) {
148
- const container = this.elementRef.nativeElement;
149
- // Find all selected cell elements
150
- const cellElements = [];
151
- cells.forEach((cell) => {
152
- const cellElement = container.querySelector(`[data-row-id="${cell.rowId}"][data-column-name="${cell.columnName}"]`);
153
- if (cellElement) {
154
- cellElements.push(cellElement);
155
- }
156
- });
157
- if (isEmptyArray(cellElements)) {
158
- return null;
159
- }
160
- // Get container position
161
- const containerRect = container.getBoundingClientRect();
162
- // Calculate bounding box
163
- let minTop = Infinity;
164
- let minLeft = Infinity;
165
- let maxBottom = -Infinity;
166
- let maxRight = -Infinity;
167
- cellElements.forEach((element) => {
168
- const rect = element.getBoundingClientRect();
169
- minTop = Math.min(minTop, rect.top - containerRect.top);
170
- minLeft = Math.min(minLeft, rect.left - containerRect.left);
171
- maxBottom = Math.max(maxBottom, rect.bottom - containerRect.top);
172
- maxRight = Math.max(maxRight, rect.right - containerRect.left);
173
- });
174
- return {
175
- top: minTop,
176
- left: minLeft,
177
- width: maxRight - minLeft,
178
- height: maxBottom - minTop,
179
- };
180
- }
181
- createOverlayElement(bounds) {
182
- const overlay = this.renderer.createElement('div');
183
- this.renderer.addClass(overlay, 'cell-selection-overlay');
184
- // Set position and size
185
- this.renderer.setStyle(overlay, 'top', `${bounds.top}px`);
186
- this.renderer.setStyle(overlay, 'left', `${bounds.left}px`);
187
- this.renderer.setStyle(overlay, 'width', `${bounds.width}px`);
188
- this.renderer.setStyle(overlay, 'height', `${bounds.height}px`);
189
- return overlay;
190
- }
191
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CellSelectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
192
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.13", type: CellSelectionDirective, isStandalone: true, selector: "[appCellSelection]", inputs: { selectableColumns: { classPropertyName: "selectableColumns", publicName: "appSelectableColumns", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "appCellSelectionChange", rightClick: "appCellRightClick" }, ngImport: i0 });
193
- }
194
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CellSelectionDirective, decorators: [{
195
- type: Directive,
196
- args: [{
197
- selector: '[appCellSelection]',
198
- standalone: true,
199
- }]
200
- }], ctorParameters: () => [] });
201
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VsbC1zZWxlY3Rpb24uZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9zaGFyZWQvZGlyZWN0aXZlcy9jZWxsLXNlbGVjdGlvbi9jZWxsLXNlbGVjdGlvbi5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQVUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM1RyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxnQ0FBZ0MsRUFBK0IsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RyxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFDOztBQWFoRSxNQUFNLE9BQU8sc0JBQXNCO0lBQ2pDLFNBQVM7SUFDVCwyREFBMkQ7SUFDM0QsaUJBQWlCLEdBQUcsS0FBSyxDQUFXLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxzQkFBc0IsRUFBRSxDQUFDLENBQUM7SUFFM0UsVUFBVTtJQUNWLDREQUE0RDtJQUM1RCxlQUFlLEdBQUcsTUFBTSxDQUF3QixFQUFFLEtBQUssRUFBRSx3QkFBd0IsRUFBRSxDQUFDLENBQUM7SUFDckYsNERBQTREO0lBQzVELFVBQVUsR0FBRyxNQUFNLENBQWEsRUFBRSxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDO0lBRWhFLDBCQUEwQjtJQUNoQixPQUFPLEdBQUcsTUFBTSxDQUFDLGdDQUFnQyxDQUFDLENBQUM7SUFFNUMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFD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QUFPLENBQUM7SUFDakIsQ0FBQzt3R0EvTlUsc0JBQXNCOzRGQUF0QixzQkFBc0I7OzRGQUF0QixzQkFBc0I7a0JBSmxDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLG9CQUFvQjtvQkFDOUIsVUFBVSxFQUFFLElBQUk7aUJBQ2pCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGVzdHJveVJlZiwgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBpbmplY3QsIGlucHV0LCBPbkluaXQsIG91dHB1dCwgUmVuZGVyZXIyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBmcm9tRXZlbnQgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEFQUF9DRUxMX1NFTEVDVElPTl9TRVJWSUNFX1RPS0VOLCBDZWxsU2VsZWN0aW9uRXZlbnQsIElDZWxsSWQgfSBmcm9tICcuL2NlbGwtc2VsZWN0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgaXNFbXB0eUFycmF5LCBpc05vdEVtcHR5QXJyYXkgfSBmcm9tICcuLi8uLi9mdW5jdGlvbnMnO1xuXG5pbnRlcmZhY2UgU2VsZWN0aW9uQm91bmRzIHtcbiAgdG9wOiBudW1iZXI7XG4gIGxlZnQ6IG51bWJlcjtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG59XG5cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ1thcHBDZWxsU2VsZWN0aW9uXScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIENlbGxTZWxlY3Rpb25EaXJlY3RpdmU8QyBleHRlbmRzIElDZWxsSWQgPSBJQ2VsbElkPiBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIC8vIElucHV0c1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L25vLWlucHV0LXJlbmFtZVxuICBzZWxlY3RhYmxlQ29sdW1ucyA9IGlucHV0PHN0cmluZ1tdPihbXSwgeyBhbGlhczogJ2FwcFNlbGVjdGFibGVDb2x1bW5zJyB9KTtcblxuICAvLyBPdXRwdXRzXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvbm8tb3V0cHV0LXJlbmFtZVxuICBzZWxlY3Rpb25DaGFuZ2UgPSBvdXRwdXQ8Q2VsbFNlbGVjdGlvbkV2ZW50PEM+Pih7IGFsaWFzOiAnYXBwQ2VsbFNlbGVjdGlvbkNoYW5nZScgfSk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvbm8tb3V0cHV0LXJlbmFtZVxuICByaWdodENsaWNrID0gb3V0cHV0PE1vdXNlRXZlbnQ+KHsgYWxpYXM6ICdhcHBDZWxsUmlnaHRDbGljaycgfSk7XG5cbiAgLy8gSW5qZWN0IHNlcnZpY2UgYnkgdG9rZW5cbiAgcHJvdGVjdGVkIHNlcnZpY2UgPSBpbmplY3QoQVBQX0NFTExfU0VMRUNUSU9OX1NFUlZJQ0VfVE9LRU4pO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZWxlbWVudFJlZiA9IGluamVjdChFbGVtZW50UmVmKTtcbiAgcHJpdmF0ZSByZWFkb25seSByZW5kZXJlciA9IGluamVjdChSZW5kZXJlcjIpO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG4gIHByaXZhdGUgb3ZlcmxheUVsZW1lbnRzOiBIVE1MRWxlbWVudFtdID0gW107XG5cbiAgY29uc3RydWN0b3IoKSB7fVxuXG4gIG5nT25Jbml0KCkge1xuICAgIC8vIEluaXRpYWxpemUgc2VydmljZSB3aXRoIHNlbGVjdGFibGUgY29sdW1uc1xuICAgIHRoaXMuc2V0dXBTZXJ2aWNlQ29uZmlndXJhdGlvbigpO1xuICAgIC8vIFNldHVwIGdsb2JhbCBtb3VzZXVwIGxpc3RlbmVyXG4gICAgdGhpcy5zZXR1cEdsb2JhbE1vdXNlRXZlbnRzKCk7XG4gICAgLy8gU2V0dXAga2V5Ym9hcmQgbGlzdGVuZXIgZm9yIGNvcHkgKGZvciB0ZXN0KVxuICAgIC8vIHRoaXMuc2V0dXBDb3B5TGlzdGVuZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBTZXJ2aWNlQ29uZmlndXJhdGlvbigpIHtcbiAgICAvLyBQYXNzIHNlbGVjdGFibGUgY29sdW1ucyB0byBzZXJ2aWNlXG4gICAgdGhpcy5zZXJ2aWNlLnNlbGVjdGFibGVDb2x1bW5zID0gdGhpcy5zZWxlY3RhYmxlQ29sdW1ucygpO1xuXG4gICAgLy8gTGlzdGVuIHRvIHNlcnZpY2Ugc2VsZWN0aW9uIGNoYW5nZXMgYW5kIGVtaXRcbiAgICB0aGlzLnNlcnZpY2Uuc2VsZWN0aW9uQ2hhbmdlU3ViamVjdFxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChldmVudCkgPT4gdGhpcy5zZWxlY3Rpb25DaGFuZ2UuZW1pdChldmVudCBhcyBDZWxsU2VsZWN0aW9uRXZlbnQ8Qz4pKTtcblxuICAgIC8vIExpc3RlbiB0byByaWdodC1jbGljayBldmVudFxuICAgIHRoaXMuc2VydmljZS5zZWxlY3Rpb25SaWdodENsaWNrU3ViamVjdC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpKS5zdWJzY3JpYmUoKGV2ZW50KSA9PiB0aGlzLnJpZ2h0Q2xpY2suZW1pdChldmVudCkpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cEdsb2JhbE1vdXNlRXZlbnRzKCkge1xuICAgIGZyb21FdmVudDxNb3VzZUV2ZW50Pihkb2N1bWVudCwgJ21vdXNldXAnKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuc2VydmljZS5lbmRNb3VzZU1vdmUoKSk7XG4gIH1cblxuICAvLyBGb3IgdGVzdCBwdXJwb3NlIG9ubHkgKHR5cGUgQ1RSTCtDKVxuICBwcml2YXRlIHNldHVwQ29weUxpc3RlbmVyKCkge1xuICAgIGZyb21FdmVudDxLZXlib2FyZEV2ZW50Pihkb2N1bWVudCwgJ2tleWRvd24nKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChldmVudCkgPT4ge1xuICAgICAgICBpZiAoKGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSkgJiYgZXZlbnQua2V5ID09PSAnYycpIHtcbiAgICAgICAgICBjb25zdCBjZWxscyA9IHRoaXMuc2VydmljZS5zZWxlY3RlZENlbGxzIGFzIENbXTtcbiAgICAgICAgICBpZiAoaXNOb3RFbXB0eUFycmF5KGNlbGxzKSkge1xuICAgICAgICAgICAgLy8gU2hvdyBvdmVybGF5XG4gICAgICAgICAgICB0aGlzLmFkZENlbGxzT3ZlcmxheShjZWxscyk7XG5cbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgICAgIC8vIEhpZGUgb3ZlcmxheSBhZnRlciBhbmltYXRpb24gY29tcGxldGVzICgxIHNlY29uZClcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICB0aGlzLnJlbW92ZUNlbGxzT3ZlcmxheSgpO1xuICAgICAgICAgICAgfSwgMTAwMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgfVxuXG4gIGFkZENlbGxzT3ZlcmxheShjZWxsczogQ1tdKSB7XG4gICAgLy8gUmVtb3ZlIGV4aXN0aW5nIG92ZXJsYXlzXG4gICAgdGhpcy5yZW1vdmVDZWxsc092ZXJsYXkoKTtcblxuICAgIC8vIEdyb3VwIGNlbGxzIGludG8gY29udGlndW91cyByZWdpb25zXG4gICAgY29uc3QgY2VsbEdyb3VwcyA9IHRoaXMuZ3JvdXBDb250aWd1b3VzQ2VsbHMoY2VsbHMpO1xuXG4gICAgLy8gQ3JlYXRlIGFuZCByZW5kZXIgb3ZlcmxheSBmb3IgZWFjaCBjb250aWd1b3VzIHJlZ2lvblxuICAgIGNlbGxHcm91cHMuZm9yRWFjaCgoZ3JvdXApID0+IHtcbiAgICAgIGNvbnN0IGJvdW5kcyA9IHRoaXMuY2FsY3VsYXRlU2VsZWN0aW9uQm91bmRzKGdyb3VwKTtcbiAgICAgIGlmIChib3VuZHMpIHtcbiAgICAgICAgY29uc3Qgb3ZlcmxheSA9IHRoaXMuY3JlYXRlT3ZlcmxheUVsZW1lbnQoYm91bmRzKTtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5hcHBlbmRDaGlsZCh0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgb3ZlcmxheSk7XG4gICAgICAgIHRoaXMub3ZlcmxheUVsZW1lbnRzLnB1c2gob3ZlcmxheSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZW1vdmVDZWxsc092ZXJsYXkoKSB7XG4gICAgdGhpcy5vdmVybGF5RWxlbWVudHMuZm9yRWFjaCgob3ZlcmxheSkgPT4ge1xuICAgICAgdGhpcy5yZW5kZXJlci5yZW1vdmVDaGlsZCh0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgb3ZlcmxheSk7XG4gICAgfSk7XG4gICAgdGhpcy5vdmVybGF5RWxlbWVudHMgPSBbXTtcbiAgfVxuXG4gIHByaXZhdGUgZ3JvdXBDb250aWd1b3VzQ2VsbHMoY2VsbHM6IENbXSk6IENbXVtdIHtcbiAgICAvLyBDcmVhdGUgYSBtYXAgZm9yIHF1aWNrIGxvb2t1cFxuICAgIGNvbnN0IGNlbGxNYXAgPSBuZXcgTWFwPHN0cmluZywgQz4oKTtcbiAgICBjZWxscy5mb3JFYWNoKChjZWxsKSA9PiB7XG4gICAgICBjZWxsTWFwLnNldCh0aGlzLmdldENlbGxLZXkoY2VsbCksIGNlbGwpO1xuICAgIH0pO1xuXG4gICAgY29uc3QgdmlzaXRlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IGdyb3VwczogQ1tdW10gPSBbXTtcblxuICAgIC8vIFByb2Nlc3MgZWFjaCBjZWxsXG4gICAgY2VsbHMuZm9yRWFjaCgoY2VsbCkgPT4ge1xuICAgICAgY29uc3Qga2V5ID0gdGhpcy5nZXRDZWxsS2V5KGNlbGwpO1xuICAgICAgaWYgKHZpc2l0ZWQuaGFzKGtleSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBTdGFydCBhIG5ldyBjb250aWd1b3VzIGdyb3VwIHdpdGggZmxvb2QtZmlsbFxuICAgICAgY29uc3QgZ3JvdXA6IENbXSA9IFtdO1xuICAgICAgY29uc3QgcXVldWU6IENbXSA9IFtjZWxsXTtcbiAgICAgIHZpc2l0ZWQuYWRkKGtleSk7XG5cbiAgICAgIHdoaWxlIChxdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnQgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAgICAgZ3JvdXAucHVzaChjdXJyZW50KTtcblxuICAgICAgICAvLyBDaGVjayBhbGwgNCBhZGphY2VudCBjZWxscyAodXAsIGRvd24sIGxlZnQsIHJpZ2h0KVxuICAgICAgICBjb25zdCBuZWlnaGJvcnMgPSB0aGlzLmdldEFkamFjZW50Q2VsbHMoY3VycmVudCk7XG4gICAgICAgIG5laWdoYm9ycy5mb3JFYWNoKChuZWlnaGJvcikgPT4ge1xuICAgICAgICAgIGNvbnN0IG5laWdoYm9yS2V5ID0gdGhpcy5nZXRDZWxsS2V5KG5laWdoYm9yKTtcbiAgICAgICAgICBpZiAoY2VsbE1hcC5oYXMobmVpZ2hib3JLZXkpICYmICF2aXNpdGVkLmhhcyhuZWlnaGJvcktleSkpIHtcbiAgICAgICAgICAgIHZpc2l0ZWQuYWRkKG5laWdoYm9yS2V5KTtcbiAgICAgICAgICAgIHF1ZXVlLnB1c2gobmVpZ2hib3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGdyb3Vwcy5wdXNoKGdyb3VwKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBncm91cHM7XG4gIH1cblxuICBwcml2YXRlIGdldEFkamFjZW50Q2VsbHMoY2VsbDogQyk6IENbXSB7XG4gICAgLy8gUmV0dXJucyBjZWxscyBhZGphY2VudCB0byB0aGUgY3VycmVudCBjZWxsICh1cCwgZG93biwgbGVmdCwgcmlnaHQpXG4gICAgLy8gTm90ZTogV2UgbmVlZCB0byBnZXQgY29sdW1uIG9yZGVyIGZyb20gdGhlIGFjdHVhbCB0YWJsZSBzdHJ1Y3R1cmVcbiAgICAvLyBGb3Igbm93LCB3ZSdsbCB1c2UgYSBzaW1wbGUgYXBwcm9hY2ggYmFzZWQgb24gcm93SWQgYWRqYWNlbmN5XG4gICAgcmV0dXJuIFtcbiAgICAgIHsgcm93SWQ6IGNlbGwucm93SWQgLSAxLCBjb2x1bW5OYW1lOiBjZWxsLmNvbHVtbk5hbWUgfSwgLy8gdXBcbiAgICAgIHsgcm93SWQ6IGNlbGwucm93SWQgKyAxLCBjb2x1bW5OYW1lOiBjZWxsLmNvbHVtbk5hbWUgfSwgLy8gZG93blxuICAgICAgeyByb3dJZDogY2VsbC5yb3dJZCwgY29sdW1uTmFtZTogdGhpcy5nZXROZXh0Q29sdW1uTmFtZShjZWxsLmNvbHVtbk5hbWUsIC0xKSB9LCAvLyBsZWZ0XG4gICAgICB7IHJvd0lkOiBjZWxsLnJvd0lkLCBjb2x1bW5OYW1lOiB0aGlzLmdldE5leHRDb2x1bW5OYW1lKGNlbGwuY29sdW1uTmFtZSwgMSkgfSwgLy8gcmlnaHRcbiAgICBdLmZpbHRlcigoYykgPT4gYy5jb2x1bW5OYW1lICE9PSBudWxsKSBhcyBDW107XG4gIH1cblxuICBwcml2YXRlIGdldE5leHRDb2x1bW5OYW1lKGN1cnJlbnRDb2x1bW5OYW1lOiBzdHJpbmcsIG9mZnNldDogbnVtYmVyKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgY29sdW1ucyA9IHRoaXMuc2VydmljZS5zZWxlY3RhYmxlQ29sdW1ucztcblxuICAgIGNvbnN0IGN1cnJlbnRJbmRleCA9IGNvbHVtbnMuaW5kZXhPZihjdXJyZW50Q29sdW1uTmFtZSk7XG4gICAgaWYgKGN1cnJlbnRJbmRleCA9PT0gLTEpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IG5ld0luZGV4ID0gY3VycmVudEluZGV4ICsgb2Zmc2V0O1xuICAgIGlmIChuZXdJbmRleCA8IDAgfHwgbmV3SW5kZXggPj0gY29sdW1ucy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBjb2x1bW5zW25ld0luZGV4XTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Q2VsbEtleShjZWxsOiBDKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYCR7Y2VsbC5yb3dJZH0tJHtjZWxsLmNvbHVtbk5hbWV9YDtcbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlU2VsZWN0aW9uQm91bmRzKGNlbGxzOiBDW10pOiBTZWxlY3Rpb25Cb3VuZHMgfCBudWxsIHtcbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCBhcyBIVE1MRWxlbWVudDtcblxuICAgIC8vIEZpbmQgYWxsIHNlbGVjdGVkIGNlbGwgZWxlbWVudHNcbiAgICBjb25zdCBjZWxsRWxlbWVudHM6IEhUTUxFbGVtZW50W10gPSBbXTtcbiAgICBjZWxscy5mb3JFYWNoKChjZWxsKSA9PiB7XG4gICAgICBjb25zdCBjZWxsRWxlbWVudCA9IGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yKGBbZGF0YS1yb3ctaWQ9XCIke2NlbGwucm93SWR9XCJdW2RhdGEtY29sdW1uLW5hbWU9XCIke2NlbGwuY29sdW1uTmFtZX1cIl1gKSBhcyBIVE1MRWxlbWVudDtcbiAgICAgIGlmIChjZWxsRWxlbWVudCkge1xuICAgICAgICBjZWxsRWxlbWVudHMucHVzaChjZWxsRWxlbWVudCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpZiAoaXNFbXB0eUFycmF5KGNlbGxFbGVtZW50cykpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIEdldCBjb250YWluZXIgcG9zaXRpb25cbiAgICBjb25zdCBjb250YWluZXJSZWN0ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIGJvdW5kaW5nIGJveFxuICAgIGxldCBtaW5Ub3AgPSBJbmZpbml0eTtcbiAgICBsZXQgbWluTGVmdCA9IEluZmluaXR5O1xuICAgIGxldCBtYXhCb3R0b20gPSAtSW5maW5pdHk7XG4gICAgbGV0IG1heFJpZ2h0ID0gLUluZmluaXR5O1xuXG4gICAgY2VsbEVsZW1lbnRzLmZvckVhY2goKGVsZW1lbnQpID0+IHtcbiAgICAgIGNvbnN0IHJlY3QgPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgbWluVG9wID0gTWF0aC5taW4obWluVG9wLCByZWN0LnRvcCAtIGNvbnRhaW5lclJlY3QudG9wKTtcbiAgICAgIG1pbkxlZnQgPSBNYXRoLm1pbihtaW5MZWZ0LCByZWN0LmxlZnQgLSBjb250YWluZXJSZWN0LmxlZnQpO1xuICAgICAgbWF4Qm90dG9tID0gTWF0aC5tYXgobWF4Qm90dG9tLCByZWN0LmJvdHRvbSAtIGNvbnRhaW5lclJlY3QudG9wKTtcbiAgICAgIG1heFJpZ2h0ID0gTWF0aC5tYXgobWF4UmlnaHQsIHJlY3QucmlnaHQgLSBjb250YWluZXJSZWN0LmxlZnQpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvcDogbWluVG9wLFxuICAgICAgbGVmdDogbWluTGVmdCxcbiAgICAgIHdpZHRoOiBtYXhSaWdodCAtIG1pbkxlZnQsXG4gICAgICBoZWlnaHQ6IG1heEJvdHRvbSAtIG1pblRvcCxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVPdmVybGF5RWxlbWVudChib3VuZHM6IFNlbGVjdGlvbkJvdW5kcyk6IEhUTUxFbGVtZW50IHtcbiAgICBjb25zdCBvdmVybGF5ID0gdGhpcy5yZW5kZXJlci5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICB0aGlzLnJlbmRlcmVyLmFkZENsYXNzKG92ZXJsYXksICdjZWxsLXNlbGVjdGlvbi1vdmVybGF5Jyk7XG5cbiAgICAvLyBTZXQgcG9zaXRpb24gYW5kIHNpemVcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKG92ZXJsYXksICd0b3AnLCBgJHtib3VuZHMudG9wfXB4YCk7XG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShvdmVybGF5LCAnbGVmdCcsIGAke2JvdW5kcy5sZWZ0fXB4YCk7XG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShvdmVybGF5LCAnd2lkdGgnLCBgJHtib3VuZHMud2lkdGh9cHhgKTtcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKG92ZXJsYXksICdoZWlnaHQnLCBgJHtib3VuZHMuaGVpZ2h0fXB4YCk7XG5cbiAgICByZXR1cm4gb3ZlcmxheTtcbiAgfVxufVxuIl19