@myrmidon/cadmus-ui 14.0.0 → 15.1.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.
@@ -1,24 +1,32 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, Component, effect, ViewChild, Injectable, Inject, model, computed, inject } from '@angular/core';
3
- import { MatButton, MatIconButton, MatAnchor } from '@angular/material/button';
4
- import { MatIcon } from '@angular/material/icon';
2
+ import { input, output, Component, signal, effect, ViewChild, Injectable, Inject, inject, model, computed } from '@angular/core';
3
+ import * as i2$1 from '@angular/material/button';
4
+ import { MatButton, MatIconButton, MatButtonModule } from '@angular/material/button';
5
+ import * as i5 from '@angular/material/icon';
6
+ import { MatIcon, MatIconModule } from '@angular/material/icon';
5
7
  import { SafeHtmlPipe, deepCopy } from '@myrmidon/ngx-tools';
6
8
  import * as i1 from '@myrmidon/cadmus-core';
7
- import { MatTooltip } from '@angular/material/tooltip';
9
+ import * as i6 from '@angular/material/tooltip';
10
+ import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip';
8
11
  import * as i1$1 from '@angular/forms';
9
- import { FormsModule, ReactiveFormsModule, PristineChangeEvent } from '@angular/forms';
10
- import { MatCheckbox } from '@angular/material/checkbox';
12
+ import { FormsModule, ReactiveFormsModule, FormBuilder, FormControl, FormGroup, PristineChangeEvent } from '@angular/forms';
13
+ import * as i3 from '@angular/material/checkbox';
14
+ import { MatCheckbox, MatCheckboxModule } from '@angular/material/checkbox';
11
15
  import * as i2 from '@myrmidon/ngx-mat-tools';
12
- import { AsyncPipe, NgClass } from '@angular/common';
16
+ import { AsyncPipe } from '@angular/common';
13
17
  import { of, BehaviorSubject, map as map$1, Subject } from 'rxjs';
14
18
  import { debounceTime, distinctUntilChanged, switchMap, map, take } from 'rxjs/operators';
15
19
  import { MatAutocomplete, MatAutocompleteTrigger } from '@angular/material/autocomplete';
16
20
  import { MatOption } from '@angular/material/core';
17
- import { MatFormField, MatLabel, MatSuffix } from '@angular/material/form-field';
18
- import { MatInput } from '@angular/material/input';
21
+ import * as i4 from '@angular/material/form-field';
22
+ import { MatFormField, MatFormFieldModule } from '@angular/material/form-field';
23
+ import * as i4$1 from '@angular/material/input';
24
+ import { MatInput, MatInputModule } from '@angular/material/input';
19
25
  import * as i1$2 from '@myrmidon/cadmus-api';
20
- import { NestedTreeControl } from '@angular/cdk/tree';
21
- import { MatTreeNestedDataSource, MatTree, MatTreeNodeDef, MatTreeNode, MatTreeNodeToggle, MatNestedTreeNode, MatTreeNodeOutlet } from '@angular/material/tree';
26
+ import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
27
+ import * as i7 from '@angular/material/progress-bar';
28
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
29
+ import { PagedTreeStore, BrowserTreeNodeComponent } from '@myrmidon/paged-data-browsers';
22
30
  import { AppRepository } from '@myrmidon/cadmus-state';
23
31
  import * as i1$3 from '@myrmidon/auth-jwt-login';
24
32
 
@@ -29,12 +37,12 @@ class CloseSaveButtonsComponent {
29
37
  close() {
30
38
  this.closeRequest.emit();
31
39
  }
32
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CloseSaveButtonsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: CloseSaveButtonsComponent, isStandalone: true, selector: "cadmus-close-save-buttons", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, noSave: { classPropertyName: "noSave", publicName: "noSave", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequest: "closeRequest" }, ngImport: i0, template: "@if (form()) {\r\n<div class=\"form-row\">\r\n <button type=\"button\" mat-flat-button class=\"mat-warn\" (click)=\"close()\">\r\n <mat-icon>cancel</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave()) {\r\n <button\r\n type=\"submit\"\r\n [disabled]=\"form()?.invalid\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n</div>\r\n}\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
40
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: CloseSaveButtonsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
41
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: CloseSaveButtonsComponent, isStandalone: true, selector: "cadmus-close-save-buttons", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, noSave: { classPropertyName: "noSave", publicName: "noSave", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequest: "closeRequest" }, ngImport: i0, template: "@if (form()) {\n<div class=\"form-row\">\n <button type=\"button\" mat-flat-button class=\"mat-warn\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n close\n </button>\n @if (!noSave()) {\n <button\n type=\"submit\"\n [disabled]=\"form()?.invalid\"\n mat-flat-button\n class=\"mat-primary\"\n >\n <mat-icon>check_circle</mat-icon>\n save\n </button>\n }\n</div>\n}\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
34
42
  }
35
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: CloseSaveButtonsComponent, decorators: [{
43
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: CloseSaveButtonsComponent, decorators: [{
36
44
  type: Component,
37
- args: [{ selector: 'cadmus-close-save-buttons', imports: [MatButton, MatIcon], template: "@if (form()) {\r\n<div class=\"form-row\">\r\n <button type=\"button\" mat-flat-button class=\"mat-warn\" (click)=\"close()\">\r\n <mat-icon>cancel</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave()) {\r\n <button\r\n type=\"submit\"\r\n [disabled]=\"form()?.invalid\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n</div>\r\n}\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
45
+ args: [{ selector: 'cadmus-close-save-buttons', imports: [MatButton, MatIcon], template: "@if (form()) {\n<div class=\"form-row\">\n <button type=\"button\" mat-flat-button class=\"mat-warn\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n close\n </button>\n @if (!noSave()) {\n <button\n type=\"submit\"\n [disabled]=\"form()?.invalid\"\n mat-flat-button\n class=\"mat-primary\"\n >\n <mat-icon>check_circle</mat-icon>\n save\n </button>\n }\n</div>\n}\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
38
46
  }] });
39
47
 
40
48
  /**
@@ -56,7 +64,7 @@ class DecoratedTokenTextComponent {
56
64
  * A selected token-based location.
57
65
  */
58
66
  selectedLocation = input(...(ngDevMode ? [undefined, { debugName: "selectedLocation" }] : []));
59
- text; // rendered HTML text
67
+ text = signal(undefined, ...(ngDevMode ? [{ debugName: "text" }] : [])); // rendered HTML text
60
68
  constructor(_textLayerService) {
61
69
  this._textLayerService = _textLayerService;
62
70
  effect(() => {
@@ -67,14 +75,14 @@ class DecoratedTokenTextComponent {
67
75
  this.decorate(this.baseText(), this.locations(), this.selectedLocation());
68
76
  }
69
77
  decorate(text, locations, selectedLocation) {
70
- this.text = this._textLayerService.render(text, locations, selectedLocation);
78
+ this.text.set(this._textLayerService.render(text, locations, selectedLocation));
71
79
  }
72
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: DecoratedTokenTextComponent, deps: [{ token: i1.TextLayerService }], target: i0.ɵɵFactoryTarget.Component });
73
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.0", type: DecoratedTokenTextComponent, isStandalone: true, selector: "cadmus-decorated-token-text", inputs: { baseText: { classPropertyName: "baseText", publicName: "baseText", isSignal: true, isRequired: false, transformFunction: null }, locations: { classPropertyName: "locations", publicName: "locations", isSignal: true, isRequired: false, transformFunction: null }, selectedLocation: { classPropertyName: "selectedLocation", publicName: "selectedLocation", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "_textElement", first: true, predicate: ["textElem"], descendants: true }], ngImport: i0, template: "<div [innerHtml]=\"text | safeHtml : 'html'\" id=\"text\" #textElem></div>\r\n", styles: [":host ::ng-deep div#text{counter-reset:text-y-counter}:host ::ng-deep div#text p:before{content:counter(text-y-counter);counter-increment:text-y-counter;margin-right:6px;color:#a0a0a0}:host ::ng-deep span.fr{background-color:#ff0;border:1px solid silver;border-radius:6px;padding:0 4px}:host ::ng-deep span.fr-sel{background-color:orange;font-weight:700;border:1px solid #404040}\n"], dependencies: [{ kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] });
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: DecoratedTokenTextComponent, deps: [{ token: i1.TextLayerService }], target: i0.ɵɵFactoryTarget.Component });
81
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.0", type: DecoratedTokenTextComponent, isStandalone: true, selector: "cadmus-decorated-token-text", inputs: { baseText: { classPropertyName: "baseText", publicName: "baseText", isSignal: true, isRequired: false, transformFunction: null }, locations: { classPropertyName: "locations", publicName: "locations", isSignal: true, isRequired: false, transformFunction: null }, selectedLocation: { classPropertyName: "selectedLocation", publicName: "selectedLocation", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "_textElement", first: true, predicate: ["textElem"], descendants: true }], ngImport: i0, template: "<div [innerHtml]=\"text() | safeHtml : 'html'\" id=\"text\" #textElem></div>\r\n", styles: [":host ::ng-deep div#text{counter-reset:text-y-counter}:host ::ng-deep div#text p:before{content:counter(text-y-counter);counter-increment:text-y-counter;margin-right:6px;color:#a0a0a0}:host ::ng-deep span.fr{background-color:#ff0;border:1px solid silver;border-radius:6px;padding:0 4px}:host ::ng-deep span.fr-sel{background-color:orange;font-weight:700;border:1px solid #404040}\n"], dependencies: [{ kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] });
74
82
  }
75
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: DecoratedTokenTextComponent, decorators: [{
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: DecoratedTokenTextComponent, decorators: [{
76
84
  type: Component,
77
- args: [{ selector: 'cadmus-decorated-token-text', imports: [SafeHtmlPipe], template: "<div [innerHtml]=\"text | safeHtml : 'html'\" id=\"text\" #textElem></div>\r\n", styles: [":host ::ng-deep div#text{counter-reset:text-y-counter}:host ::ng-deep div#text p:before{content:counter(text-y-counter);counter-increment:text-y-counter;margin-right:6px;color:#a0a0a0}:host ::ng-deep span.fr{background-color:#ff0;border:1px solid silver;border-radius:6px;padding:0 4px}:host ::ng-deep span.fr-sel{background-color:orange;font-weight:700;border:1px solid #404040}\n"] }]
85
+ args: [{ selector: 'cadmus-decorated-token-text', imports: [SafeHtmlPipe], template: "<div [innerHtml]=\"text() | safeHtml : 'html'\" id=\"text\" #textElem></div>\r\n", styles: [":host ::ng-deep div#text{counter-reset:text-y-counter}:host ::ng-deep div#text p:before{content:counter(text-y-counter);counter-increment:text-y-counter;margin-right:6px;color:#a0a0a0}:host ::ng-deep span.fr{background-color:#ff0;border:1px solid silver;border-radius:6px;padding:0 4px}:host ::ng-deep span.fr-sel{background-color:orange;font-weight:700;border:1px solid #404040}\n"] }]
78
86
  }], ctorParameters: () => [{ type: i1.TextLayerService }], propDecorators: { _textElement: [{
79
87
  type: ViewChild,
80
88
  args: ['textElem']
@@ -82,12 +90,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
82
90
 
83
91
  class ErrorListComponent {
84
92
  errors = input(...(ngDevMode ? [undefined, { debugName: "errors" }] : []));
85
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ErrorListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
86
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: ErrorListComponent, isStandalone: true, selector: "cadmus-error-list", inputs: { errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (errors()?.length) {\r\n <ul>\r\n @for (error of errors(); track error) {\r\n <li class=\"error\">{{error}}</li>\r\n }\r\n </ul>\r\n}\r\n", styles: [".error{color:red}\n"] });
93
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ErrorListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
94
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: ErrorListComponent, isStandalone: true, selector: "cadmus-error-list", inputs: { errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (errors()?.length) {\n <ul>\n @for (error of errors(); track error) {\n <li class=\"error\">{{error}}</li>\n }\n </ul>\n}\n", styles: [".error{color:red}\n"] });
87
95
  }
88
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ErrorListComponent, decorators: [{
96
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ErrorListComponent, decorators: [{
89
97
  type: Component,
90
- args: [{ selector: 'cadmus-error-list', template: "@if (errors()?.length) {\r\n <ul>\r\n @for (error of errors(); track error) {\r\n <li class=\"error\">{{error}}</li>\r\n }\r\n </ul>\r\n}\r\n", styles: [".error{color:red}\n"] }]
98
+ args: [{ selector: 'cadmus-error-list', template: "@if (errors()?.length) {\n <ul>\n @for (error of errors(); track error) {\n <li class=\"error\">{{error}}</li>\n }\n </ul>\n}\n", styles: [".error{color:red}\n"] }]
91
99
  }] });
92
100
 
93
101
  /**
@@ -233,10 +241,10 @@ class ColorService {
233
241
  const rgb = this.hslToRgb(h, s, l);
234
242
  return this.rgbToString(rgb.r, rgb.g, rgb.b);
235
243
  }
236
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ColorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
237
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ColorService, providedIn: 'root' });
244
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ColorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
245
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ColorService, providedIn: 'root' });
238
246
  }
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ColorService, decorators: [{
247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ColorService, decorators: [{
240
248
  type: Injectable,
241
249
  args: [{
242
250
  providedIn: 'root',
@@ -247,9 +255,9 @@ class FacetBadgeComponent {
247
255
  _colorService;
248
256
  _facetColors;
249
257
  _facetTips;
250
- color;
251
- contrastColor;
252
- tip;
258
+ color = signal('transparent', ...(ngDevMode ? [{ debugName: "color" }] : []));
259
+ contrastColor = signal('black', ...(ngDevMode ? [{ debugName: "contrastColor" }] : []));
260
+ tip = signal(undefined, ...(ngDevMode ? [{ debugName: "tip" }] : []));
253
261
  /**
254
262
  * The facet data.
255
263
  */
@@ -260,8 +268,6 @@ class FacetBadgeComponent {
260
268
  this._colorService = _colorService;
261
269
  this._facetColors = {};
262
270
  this._facetTips = {};
263
- this.color = 'transparent';
264
- this.contrastColor = 'black';
265
271
  effect(() => {
266
272
  this.updateBadge(this.data());
267
273
  });
@@ -315,16 +321,16 @@ class FacetBadgeComponent {
315
321
  updateBadge(data) {
316
322
  this._facetColors = {};
317
323
  this._facetTips = {};
318
- this.color = this.getFacetColor(data?.facetId || '');
319
- this.contrastColor = this._colorService.getContrastColor(this.color);
320
- this.tip = this.getFacetTip(data?.facetId || '') ?? undefined;
324
+ this.color.set(this.getFacetColor(data?.facetId || ''));
325
+ this.contrastColor.set(this._colorService.getContrastColor(this.color()));
326
+ this.tip.set(this.getFacetTip(data?.facetId || '') ?? undefined);
321
327
  }
322
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FacetBadgeComponent, deps: [{ token: ColorService }], target: i0.ɵɵFactoryTarget.Component });
323
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.0", type: FacetBadgeComponent, isStandalone: true, selector: "cadmus-facet-badge", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span\r\n class=\"model-type\"\r\n [style.background-color]=\"color\"\r\n [style.color]=\"contrastColor\"\r\n matTooltip=\"{{ tip }}\"\r\n >{{ data().facetId }}\r\n</span>\r\n", styles: ["span.model-type{padding:4px;border-radius:6px}\n"], dependencies: [{ kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
328
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: FacetBadgeComponent, deps: [{ token: ColorService }], target: i0.ɵɵFactoryTarget.Component });
329
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.0", type: FacetBadgeComponent, isStandalone: true, selector: "cadmus-facet-badge", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span\r\n class=\"model-type\"\r\n [style.background-color]=\"color()\"\r\n [style.color]=\"contrastColor()\"\r\n matTooltip=\"{{ tip() }}\"\r\n >{{ data().facetId }}\r\n</span>\r\n", styles: ["span.model-type{padding:4px;border-radius:6px}\n"], dependencies: [{ kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
324
330
  }
325
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FacetBadgeComponent, decorators: [{
331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: FacetBadgeComponent, decorators: [{
326
332
  type: Component,
327
- args: [{ selector: 'cadmus-facet-badge', imports: [MatTooltip], template: "<span\r\n class=\"model-type\"\r\n [style.background-color]=\"color\"\r\n [style.color]=\"contrastColor\"\r\n matTooltip=\"{{ tip }}\"\r\n >{{ data().facetId }}\r\n</span>\r\n", styles: ["span.model-type{padding:4px;border-radius:6px}\n"] }]
333
+ args: [{ selector: 'cadmus-facet-badge', imports: [MatTooltip], template: "<span\r\n class=\"model-type\"\r\n [style.background-color]=\"color()\"\r\n [style.color]=\"contrastColor()\"\r\n matTooltip=\"{{ tip() }}\"\r\n >{{ data().facetId }}\r\n</span>\r\n", styles: ["span.model-type{padding:4px;border-radius:6px}\n"] }]
328
334
  }], ctorParameters: () => [{ type: ColorService }] });
329
335
 
330
336
  /**
@@ -332,8 +338,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
332
338
  * with the flag's color key.
333
339
  */
334
340
  class FlagsBadgeComponent {
335
- badgeFlags = [];
336
341
  data = input(...(ngDevMode ? [undefined, { debugName: "data" }] : []));
342
+ badgeFlags = signal([], ...(ngDevMode ? [{ debugName: "badgeFlags" }] : []));
337
343
  constructor() {
338
344
  effect(() => {
339
345
  this.updateBadge(this.data());
@@ -343,17 +349,17 @@ class FlagsBadgeComponent {
343
349
  if (!data) {
344
350
  return;
345
351
  }
346
- this.badgeFlags = data.definitions.filter((def) => {
352
+ this.badgeFlags.set(data.definitions.filter((def) => {
347
353
  // tslint:disable-next-line: no-bitwise
348
354
  return def.id & data.flags;
349
- });
355
+ }));
350
356
  }
351
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FlagsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
352
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: FlagsBadgeComponent, isStandalone: true, selector: "cadmus-flags-badge", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div>\r\n @for (def of badgeFlags; track def.id) {\r\n <span\r\n class=\"badge-flag\"\r\n [style.color]=\"'#' + def.colorKey\"\r\n [matTooltip]=\"def.label\"\r\n >\r\n @if (def.isAdmin) { &#x25c6; } @else { &#x2b24; }\r\n </span>\r\n }\r\n</div>\r\n", styles: ["span.badge-flag{font-size:1rem;cursor:default}\n"], dependencies: [{ kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
357
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: FlagsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
358
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: FlagsBadgeComponent, isStandalone: true, selector: "cadmus-flags-badge", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div>\r\n @for (def of badgeFlags(); track def.id) {\r\n <span\r\n class=\"badge-flag\"\r\n [style.color]=\"'#' + def.colorKey\"\r\n [matTooltip]=\"def.label\"\r\n >\r\n @if (def.isAdmin) { &#x25c6; } @else { &#x2b24; }\r\n </span>\r\n }\r\n</div>\r\n", styles: ["span.badge-flag{font-size:1rem;cursor:default}\n"], dependencies: [{ kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
353
359
  }
354
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FlagsBadgeComponent, decorators: [{
360
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: FlagsBadgeComponent, decorators: [{
355
361
  type: Component,
356
- args: [{ selector: 'cadmus-flags-badge', imports: [MatTooltip], template: "<div>\r\n @for (def of badgeFlags; track def.id) {\r\n <span\r\n class=\"badge-flag\"\r\n [style.color]=\"'#' + def.colorKey\"\r\n [matTooltip]=\"def.label\"\r\n >\r\n @if (def.isAdmin) { &#x25c6; } @else { &#x2b24; }\r\n </span>\r\n }\r\n</div>\r\n", styles: ["span.badge-flag{font-size:1rem;cursor:default}\n"] }]
362
+ args: [{ selector: 'cadmus-flags-badge', imports: [MatTooltip], template: "<div>\r\n @for (def of badgeFlags(); track def.id) {\r\n <span\r\n class=\"badge-flag\"\r\n [style.color]=\"'#' + def.colorKey\"\r\n [matTooltip]=\"def.label\"\r\n >\r\n @if (def.isAdmin) { &#x25c6; } @else { &#x2b24; }\r\n </span>\r\n }\r\n</div>\r\n", styles: ["span.badge-flag{font-size:1rem;cursor:default}\n"] }]
357
363
  }], ctorParameters: () => [] });
358
364
 
359
365
  class LayerHintsComponent {
@@ -381,9 +387,9 @@ class LayerHintsComponent {
381
387
  });
382
388
  }
383
389
  updateChecks(hints) {
384
- this.checks.controls = [];
390
+ this.checks.clear();
385
391
  for (let i = 0; i < hints.length; i++) {
386
- this.checks.push(this._formBuilder.control(false));
392
+ this.checks.push(this._formBuilder.control(false, { nonNullable: true }));
387
393
  }
388
394
  }
389
395
  emitRequestEdit(hint) {
@@ -419,20 +425,19 @@ class LayerHintsComponent {
419
425
  .subscribe((ok) => {
420
426
  if (ok) {
421
427
  const patches = [];
422
- for (let i = 0; i < this.checks.controls.length; i++) {
423
- const n = this.checks.controls[i].value;
424
- if (n) {
425
- patches.push(this.hints()[n - 1].patchOperation);
428
+ for (let i = 0; i < this.checks.length; i++) {
429
+ if (this.checks.at(i).value) {
430
+ patches.push(this.hints()[i].patchOperation);
426
431
  }
427
432
  }
428
433
  this.requestPatch.emit(patches);
429
434
  }
430
435
  });
431
436
  }
432
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: LayerHintsComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2.DialogService }], target: i0.ɵɵFactoryTarget.Component });
433
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: LayerHintsComponent, isStandalone: true, selector: "cadmus-layer-hints", inputs: { hints: { classPropertyName: "hints", publicName: "hints", isSignal: true, isRequired: false, transformFunction: null }, targetLocation: { classPropertyName: "targetLocation", publicName: "targetLocation", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { requestEdit: "requestEdit", requestDelete: "requestDelete", requestMove: "requestMove", requestPatch: "requestPatch" }, ngImport: i0, template: "@if (hints().length) {\r\n<form [formGroup]=\"form\" (submit)=\"emitRequestPatch()\">\r\n <table class=\"patches\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>location</th>\r\n <th>description</th>\r\n <th>patch</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (hint of hints(); track hint; let i = $index) {\r\n <tr>\r\n @if (!readonly()) {\r\n <td>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this fragment\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this fragment to {{ targetLocation() }}\"\r\n [disabled]=\"\r\n disabled() || !targetLocation() || targetLocation() === hint.location\r\n \"\r\n (click)=\"emitRequestMove(hint)\"\r\n >\r\n <mat-icon>arrow_forward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this fragment\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"emitRequestDelete(hint)\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n }\r\n <td>{{ hint.location }}</td>\r\n <td>{{ hint.description }}</td>\r\n <td>\r\n @if (hint.patchOperation) {\r\n <mat-checkbox\r\n matTooltip=\"Apply this patch\"\r\n [disabled]=\"disabled()\"\r\n [value]=\"(i + 1).toString()\"\r\n >\r\n {{ hint.patchOperation }}\r\n </mat-checkbox>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (targetLocation()) {\r\n <div>move target: {{ targetLocation() }}</div>\r\n }\r\n <button\r\n type=\"submit\"\r\n mat-flat-button\r\n [disabled]=\"readonly() || disabled() || form.invalid\"\r\n >\r\n apply patches\r\n </button>\r\n</form>\r\n}\r\n", styles: ["table.patches th{font-weight:400;color:#bdbdbd}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
437
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: LayerHintsComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2.DialogService }], target: i0.ɵɵFactoryTarget.Component });
438
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: LayerHintsComponent, isStandalone: true, selector: "cadmus-layer-hints", inputs: { hints: { classPropertyName: "hints", publicName: "hints", isSignal: true, isRequired: false, transformFunction: null }, targetLocation: { classPropertyName: "targetLocation", publicName: "targetLocation", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { requestEdit: "requestEdit", requestDelete: "requestDelete", requestMove: "requestMove", requestPatch: "requestPatch" }, ngImport: i0, template: "@if (hints().length) {\r\n<form [formGroup]=\"form\" (submit)=\"emitRequestPatch()\">\r\n <table class=\"patches\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>location</th>\r\n <th>description</th>\r\n <th>patch</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (hint of hints(); track hint; let i = $index) {\r\n <tr>\r\n @if (!readonly()) {\r\n <td>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this fragment\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this fragment to {{ targetLocation() }}\"\r\n [disabled]=\"\r\n disabled() ||\r\n !targetLocation() ||\r\n targetLocation() === hint.location\r\n \"\r\n (click)=\"emitRequestMove(hint)\"\r\n >\r\n <mat-icon>arrow_forward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this fragment\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"emitRequestDelete(hint)\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n }\r\n <td>{{ hint.location }}</td>\r\n <td>{{ hint.description }}</td>\r\n <td>\r\n @if (hint.patchOperation) {\r\n <mat-checkbox\r\n matTooltip=\"Apply this patch\"\r\n [formControl]=\"checks.at(i)\"\r\n >\r\n {{ hint.patchOperation }}\r\n </mat-checkbox>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (targetLocation()) {\r\n <div>move target: {{ targetLocation() }}</div>\r\n }\r\n <button\r\n type=\"submit\"\r\n mat-flat-button\r\n [disabled]=\"readonly() || disabled() || form.invalid\"\r\n >\r\n apply patches\r\n </button>\r\n</form>\r\n}\r\n", styles: ["table.patches th{font-weight:400;color:#bdbdbd}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
434
439
  }
435
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: LayerHintsComponent, decorators: [{
440
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: LayerHintsComponent, decorators: [{
436
441
  type: Component,
437
442
  args: [{ selector: 'cadmus-layer-hints', imports: [
438
443
  FormsModule,
@@ -442,7 +447,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
442
447
  MatIcon,
443
448
  MatCheckbox,
444
449
  MatButton,
445
- ], template: "@if (hints().length) {\r\n<form [formGroup]=\"form\" (submit)=\"emitRequestPatch()\">\r\n <table class=\"patches\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>location</th>\r\n <th>description</th>\r\n <th>patch</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (hint of hints(); track hint; let i = $index) {\r\n <tr>\r\n @if (!readonly()) {\r\n <td>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this fragment\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this fragment to {{ targetLocation() }}\"\r\n [disabled]=\"\r\n disabled() || !targetLocation() || targetLocation() === hint.location\r\n \"\r\n (click)=\"emitRequestMove(hint)\"\r\n >\r\n <mat-icon>arrow_forward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this fragment\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"emitRequestDelete(hint)\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n }\r\n <td>{{ hint.location }}</td>\r\n <td>{{ hint.description }}</td>\r\n <td>\r\n @if (hint.patchOperation) {\r\n <mat-checkbox\r\n matTooltip=\"Apply this patch\"\r\n [disabled]=\"disabled()\"\r\n [value]=\"(i + 1).toString()\"\r\n >\r\n {{ hint.patchOperation }}\r\n </mat-checkbox>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (targetLocation()) {\r\n <div>move target: {{ targetLocation() }}</div>\r\n }\r\n <button\r\n type=\"submit\"\r\n mat-flat-button\r\n [disabled]=\"readonly() || disabled() || form.invalid\"\r\n >\r\n apply patches\r\n </button>\r\n</form>\r\n}\r\n", styles: ["table.patches th{font-weight:400;color:#bdbdbd}\n"] }]
450
+ ], template: "@if (hints().length) {\r\n<form [formGroup]=\"form\" (submit)=\"emitRequestPatch()\">\r\n <table class=\"patches\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>location</th>\r\n <th>description</th>\r\n <th>patch</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (hint of hints(); track hint; let i = $index) {\r\n <tr>\r\n @if (!readonly()) {\r\n <td>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this fragment\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this fragment to {{ targetLocation() }}\"\r\n [disabled]=\"\r\n disabled() ||\r\n !targetLocation() ||\r\n targetLocation() === hint.location\r\n \"\r\n (click)=\"emitRequestMove(hint)\"\r\n >\r\n <mat-icon>arrow_forward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this fragment\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"emitRequestDelete(hint)\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n }\r\n <td>{{ hint.location }}</td>\r\n <td>{{ hint.description }}</td>\r\n <td>\r\n @if (hint.patchOperation) {\r\n <mat-checkbox\r\n matTooltip=\"Apply this patch\"\r\n [formControl]=\"checks.at(i)\"\r\n >\r\n {{ hint.patchOperation }}\r\n </mat-checkbox>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (targetLocation()) {\r\n <div>move target: {{ targetLocation() }}</div>\r\n }\r\n <button\r\n type=\"submit\"\r\n mat-flat-button\r\n [disabled]=\"readonly() || disabled() || form.invalid\"\r\n >\r\n apply patches\r\n </button>\r\n</form>\r\n}\r\n", styles: ["table.patches th{font-weight:400;color:#bdbdbd}\n"] }]
446
451
  }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i2.DialogService }] });
447
452
 
448
453
  /**
@@ -488,7 +493,7 @@ class LookupPinComponent {
488
493
  form;
489
494
  lookup;
490
495
  entries$;
491
- entry;
496
+ entry = signal(undefined, ...(ngDevMode ? [{ debugName: "entry" }] : []));
492
497
  constructor(formBuilder, _itemService, _lookupDefs) {
493
498
  this._itemService = _itemService;
494
499
  this._lookupDefs = _lookupDefs;
@@ -555,7 +560,7 @@ class LookupPinComponent {
555
560
  });
556
561
  }
557
562
  clear() {
558
- this.entry = undefined;
563
+ this.entry.set(undefined);
559
564
  this.lookup.setValue(null);
560
565
  this.entryChange.emit(null);
561
566
  }
@@ -563,16 +568,16 @@ class LookupPinComponent {
563
568
  return entry?.value;
564
569
  }
565
570
  pickEntry(entry) {
566
- this.entry = entry;
571
+ this.entry.set(entry);
567
572
  this.entryChange.emit(entry);
568
573
  if (this.resetOnPick()) {
569
574
  this.clear();
570
575
  }
571
576
  }
572
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: LookupPinComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i1$2.ItemService }, { token: 'indexLookupDefinitions' }], target: i0.ɵɵFactoryTarget.Component });
573
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: LookupPinComponent, isStandalone: true, selector: "cadmus-lookup-pin", inputs: { initialValue: { classPropertyName: "initialValue", publicName: "initialValue", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, resetOnPick: { classPropertyName: "resetOnPick", publicName: "resetOnPick", isSignal: true, isRequired: false, transformFunction: null }, lookupKey: { classPropertyName: "lookupKey", publicName: "lookupKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entryChange: "entryChange" }, ngImport: i0, template: "<form [formGroup]=\"form\">\r\n <mat-autocomplete #lookupAuto=\"matAutocomplete\" [displayWith]=\"entryToName\">\r\n @for (entry of entries$ | async; track entry) {\r\n <mat-option [value]=\"entry\" (onSelectionChange)=\"pickEntry(entry)\">\r\n {{ entry?.value }}\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [placeholder]=\"label()\"\r\n [formControl]=\"lookup\"\r\n [matAutocomplete]=\"lookupAuto\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"clear()\"\r\n [disabled]=\"!entry\"\r\n matTooltip=\"Clear\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] });
577
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: LookupPinComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i1$2.ItemService }, { token: 'indexLookupDefinitions' }], target: i0.ɵɵFactoryTarget.Component });
578
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: LookupPinComponent, isStandalone: true, selector: "cadmus-lookup-pin", inputs: { initialValue: { classPropertyName: "initialValue", publicName: "initialValue", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, resetOnPick: { classPropertyName: "resetOnPick", publicName: "resetOnPick", isSignal: true, isRequired: false, transformFunction: null }, lookupKey: { classPropertyName: "lookupKey", publicName: "lookupKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entryChange: "entryChange" }, ngImport: i0, template: "<form [formGroup]=\"form\">\r\n <mat-autocomplete #lookupAuto=\"matAutocomplete\" [displayWith]=\"entryToName\">\r\n @for (entry of entries$ | async; track entry) {\r\n <mat-option [value]=\"entry\" (onSelectionChange)=\"pickEntry(entry)\">\r\n {{ entry?.value }}\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [placeholder]=\"label()\"\r\n [formControl]=\"lookup\"\r\n [matAutocomplete]=\"lookupAuto\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"clear()\"\r\n [disabled]=\"!entry()\"\r\n matTooltip=\"Clear\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] });
574
579
  }
575
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: LookupPinComponent, decorators: [{
580
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: LookupPinComponent, decorators: [{
576
581
  type: Component,
577
582
  args: [{ selector: 'cadmus-lookup-pin', imports: [
578
583
  FormsModule,
@@ -586,12 +591,393 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
586
591
  MatTooltip,
587
592
  MatIcon,
588
593
  AsyncPipe,
589
- ], template: "<form [formGroup]=\"form\">\r\n <mat-autocomplete #lookupAuto=\"matAutocomplete\" [displayWith]=\"entryToName\">\r\n @for (entry of entries$ | async; track entry) {\r\n <mat-option [value]=\"entry\" (onSelectionChange)=\"pickEntry(entry)\">\r\n {{ entry?.value }}\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [placeholder]=\"label()\"\r\n [formControl]=\"lookup\"\r\n [matAutocomplete]=\"lookupAuto\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"clear()\"\r\n [disabled]=\"!entry\"\r\n matTooltip=\"Clear\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n</form>\r\n" }]
594
+ ], template: "<form [formGroup]=\"form\">\r\n <mat-autocomplete #lookupAuto=\"matAutocomplete\" [displayWith]=\"entryToName\">\r\n @for (entry of entries$ | async; track entry) {\r\n <mat-option [value]=\"entry\" (onSelectionChange)=\"pickEntry(entry)\">\r\n {{ entry?.value }}\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [placeholder]=\"label()\"\r\n [formControl]=\"lookup\"\r\n [matAutocomplete]=\"lookupAuto\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"clear()\"\r\n [disabled]=\"!entry()\"\r\n matTooltip=\"Clear\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n</form>\r\n" }]
590
595
  }], ctorParameters: () => [{ type: i1$1.UntypedFormBuilder }, { type: i1$2.ItemService }, { type: undefined, decorators: [{
591
596
  type: Inject,
592
597
  args: ['indexLookupDefinitions']
593
598
  }] }] });
594
599
 
600
+ /**
601
+ * A label rendering function which removes from a label
602
+ * all the characters past the last colon, trimming the result.
603
+ * This is a typical rendering when dealing with hierarchical
604
+ * thesaurus entries, e.g. "furniture: table: color", where
605
+ * we can shorten the label to just "color", as "furniture"
606
+ * and "table" are its ancestors.
607
+ */
608
+ const renderLabelFromLastColon = (label) => {
609
+ if (!label) {
610
+ return label;
611
+ }
612
+ const i = label.lastIndexOf(':');
613
+ return i > -1 && i + 1 < label.length ? label.substring(i + 1).trim() : label;
614
+ };
615
+ /**
616
+ * A static paged tree store service for thesaurus entries.
617
+ * This builds the tree nodes from the thesaurus entries, assuming
618
+ * that entry IDs are hierarchical and separated by dots (.).
619
+ */
620
+ class StaticThesPagedTreeStoreService {
621
+ _renderLabel;
622
+ _nodes = [];
623
+ _built = false;
624
+ _entries;
625
+ constructor(entries, _renderLabel) {
626
+ this._renderLabel = _renderLabel;
627
+ // assign a number to each entry for stable IDs
628
+ this._entries = entries.map((entry, index) => ({
629
+ ...entry,
630
+ n: index + 1,
631
+ }));
632
+ }
633
+ ensureNodes() {
634
+ // lazily build the nodes only once
635
+ if (this._built) {
636
+ return;
637
+ }
638
+ // map where key is node.id and value is max x value for that parent
639
+ // (0 is used for the virtual root)
640
+ const xMap = new Map();
641
+ for (const entry of this._entries) {
642
+ const hasDot = entry.id.includes('.');
643
+ const keyParts = entry.id.split('.');
644
+ // create the node
645
+ const node = {
646
+ id: entry.n,
647
+ label: hasDot && this._renderLabel
648
+ ? this._renderLabel(entry.value)
649
+ : entry.value,
650
+ key: entry.id,
651
+ value: entry.value,
652
+ paging: { pageNumber: 0, pageCount: 0, total: 0 },
653
+ y: hasDot ? keyParts.length : 1,
654
+ x: 0, // will be set later
655
+ parentId: undefined, // will be set later
656
+ hasChildren: false, // will be set later
657
+ };
658
+ // if it has a dot, find its parent and set parentId
659
+ if (hasDot) {
660
+ // build the parent key
661
+ const parentKey = keyParts.slice(0, keyParts.length - 1).join('.');
662
+ // find the parent node with that key
663
+ const parentNode = this._nodes.find((n) => n.key === parentKey);
664
+ // if found, set parentId and x in child and hasChildren in parent
665
+ if (parentNode) {
666
+ node.parentId = parentNode.id;
667
+ parentNode.hasChildren = true;
668
+ if (xMap.has(parentNode.id)) {
669
+ xMap.set(parentNode.id, xMap.get(parentNode.id) + 1);
670
+ }
671
+ else {
672
+ xMap.set(parentNode.id, 1);
673
+ }
674
+ node.x = xMap.get(parentNode.id);
675
+ }
676
+ else {
677
+ // parent not found, treat as root
678
+ if (xMap.has(0)) {
679
+ xMap.set(0, xMap.get(0) + 1);
680
+ }
681
+ else {
682
+ xMap.set(0, 1);
683
+ }
684
+ node.x = xMap.get(0);
685
+ }
686
+ }
687
+ else {
688
+ // else it's a root node
689
+ if (xMap.has(0)) {
690
+ xMap.set(0, xMap.get(0) + 1);
691
+ }
692
+ else {
693
+ xMap.set(0, 1);
694
+ }
695
+ node.x = xMap.get(0);
696
+ }
697
+ this._nodes.push(node);
698
+ }
699
+ this._built = true;
700
+ }
701
+ /**
702
+ * Get the specified page of nodes.
703
+ * @param filter The filter.
704
+ * @param pageNumber The page number.
705
+ * @param pageSize The page size.
706
+ * @param hasMockRoot Whether the root node is a mock node. Not used here.
707
+ */
708
+ getNodes(filter, pageNumber, pageSize, hasMockRoot) {
709
+ this.ensureNodes();
710
+ // apply filtering
711
+ let nodes = this._nodes.filter((n) => {
712
+ if (filter.parentId !== undefined && filter.parentId !== null) {
713
+ if (n.parentId !== filter.parentId) {
714
+ return false;
715
+ }
716
+ }
717
+ else {
718
+ if (n.parentId) {
719
+ return false;
720
+ }
721
+ }
722
+ if (filter.label) {
723
+ const filterValue = filter.label.toLowerCase();
724
+ if (!n.label.toLowerCase().includes(filterValue)) {
725
+ return false;
726
+ }
727
+ }
728
+ return true;
729
+ });
730
+ // apply paging
731
+ const startIndex = (pageNumber - 1) * pageSize;
732
+ const endIndex = startIndex + pageSize;
733
+ const pagedNodes = nodes.slice(startIndex, endIndex);
734
+ // page and return
735
+ const paged = nodes.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
736
+ return of({
737
+ items: paged,
738
+ pageNumber: pageNumber,
739
+ pageSize: pageSize,
740
+ pageCount: Math.ceil(nodes.length / pageSize),
741
+ total: nodes.length,
742
+ });
743
+ }
744
+ }
745
+
746
+ /**
747
+ * A filter to be used for thesaurus paged tree browsers.
748
+ */
749
+ class ThesPagedTreeFilterComponent {
750
+ dialogRef = inject(MatDialogRef, {
751
+ optional: true,
752
+ });
753
+ data = inject(MAT_DIALOG_DATA, { optional: true });
754
+ /**
755
+ * The filter.
756
+ */
757
+ filter = model(...(ngDevMode ? [undefined, { debugName: "filter" }] : []));
758
+ wrapped = signal(false, ...(ngDevMode ? [{ debugName: "wrapped" }] : []));
759
+ label;
760
+ form;
761
+ constructor() {
762
+ const formBuilder = inject(FormBuilder);
763
+ const data = this.data;
764
+ // form
765
+ this.label = formBuilder.control(null);
766
+ this.form = formBuilder.group({
767
+ label: this.label,
768
+ });
769
+ // bind dialog data if any
770
+ if (this.dialogRef) {
771
+ this.wrapped.set(true);
772
+ if (data) {
773
+ this.filter.set(data.filter);
774
+ }
775
+ }
776
+ else {
777
+ this.wrapped.set(false);
778
+ }
779
+ // update form when filter changes
780
+ effect(() => {
781
+ this.updateForm(this.filter());
782
+ });
783
+ }
784
+ ngOnInit() {
785
+ this.updateForm(this.filter());
786
+ }
787
+ updateForm(filter) {
788
+ if (!filter) {
789
+ this.form.reset();
790
+ return;
791
+ }
792
+ this.label.setValue(filter.label ?? null);
793
+ this.form.markAsPristine();
794
+ }
795
+ getFilter() {
796
+ return {
797
+ label: this.label.value ?? undefined,
798
+ };
799
+ }
800
+ reset() {
801
+ this.form.reset();
802
+ this.filter.set(null);
803
+ this.dialogRef?.close(null);
804
+ }
805
+ apply() {
806
+ this.filter.set(this.getFilter());
807
+ this.dialogRef?.close(this.filter());
808
+ }
809
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ThesPagedTreeFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
810
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.0", type: ThesPagedTreeFilterComponent, isStandalone: true, selector: "cadmus-thes-paged-tree-filter", inputs: { filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filter: "filterChange" }, ngImport: i0, template: "<form\r\n [formGroup]=\"form\"\r\n [style.margin.px]=\"wrapped() ? 16 : 0\"\r\n (submit)=\"apply()\"\r\n>\r\n <div class=\"form-row\">\r\n <!-- label -->\r\n <mat-form-field>\r\n <input matInput placeholder=\"label\" [formControl]=\"label\" />\r\n </mat-form-field>\r\n </div>\r\n\r\n <div class=\"form-row\">\r\n <!-- buttons -->\r\n <button type=\"button\" mat-icon-button matTooltip=\"Reset\" (click)=\"reset()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Apply\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n</form>\r\n", styles: ["form{margin:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:6em}fieldset{border:1px solid silver;border-radius:6px;padding:8px 16px;margin:8px 0}legend{color:silver}th{text-align:left;font-weight:400}#tag-selector{width:8em}.tag-chip{border:2px solid transparent;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
811
+ }
812
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ThesPagedTreeFilterComponent, decorators: [{
813
+ type: Component,
814
+ args: [{ selector: 'cadmus-thes-paged-tree-filter', imports: [
815
+ ReactiveFormsModule,
816
+ MatButtonModule,
817
+ MatFormFieldModule,
818
+ MatInputModule,
819
+ MatIconModule,
820
+ MatTooltipModule,
821
+ ], template: "<form\r\n [formGroup]=\"form\"\r\n [style.margin.px]=\"wrapped() ? 16 : 0\"\r\n (submit)=\"apply()\"\r\n>\r\n <div class=\"form-row\">\r\n <!-- label -->\r\n <mat-form-field>\r\n <input matInput placeholder=\"label\" [formControl]=\"label\" />\r\n </mat-form-field>\r\n </div>\r\n\r\n <div class=\"form-row\">\r\n <!-- buttons -->\r\n <button type=\"button\" mat-icon-button matTooltip=\"Reset\" (click)=\"reset()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Apply\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n</form>\r\n", styles: ["form{margin:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:6em}fieldset{border:1px solid silver;border-radius:6px;padding:8px 16px;margin:8px 0}legend{color:silver}th{text-align:left;font-weight:400}#tag-selector{width:8em}.tag-chip{border:2px solid transparent;border-radius:6px}\n"] }]
822
+ }], ctorParameters: () => [] });
823
+
824
+ class ThesPagedTreeBrowserComponent {
825
+ _dialog = inject(MatDialog);
826
+ _sub;
827
+ /**
828
+ * The service to use to load the nodes.
829
+ */
830
+ service = input(new StaticThesPagedTreeStoreService([], renderLabelFromLastColon), ...(ngDevMode ? [{ debugName: "service" }] : []));
831
+ /**
832
+ * Emitted when a node is clicked.
833
+ */
834
+ nodePick = output();
835
+ /**
836
+ * The store instance, built from the service.
837
+ */
838
+ store = computed(() => {
839
+ const service = this.service();
840
+ const store = new PagedTreeStore(service);
841
+ this.nodes$ = store.nodes$;
842
+ this.filter$ = store.filter$;
843
+ return store;
844
+ }, ...(ngDevMode ? [{ debugName: "store" }] : []));
845
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
846
+ debug = new FormControl(false, {
847
+ nonNullable: true,
848
+ });
849
+ hideLoc = new FormControl(false, {
850
+ nonNullable: true,
851
+ });
852
+ hideFilter = new FormControl(false, {
853
+ nonNullable: true,
854
+ });
855
+ filter$;
856
+ nodes$;
857
+ label = new FormControl(null);
858
+ form = new FormGroup({
859
+ label: this.label,
860
+ });
861
+ constructor() {
862
+ const store = this.store();
863
+ this.nodes$ = store.nodes$;
864
+ this.filter$ = store.filter$;
865
+ }
866
+ ngOnInit() {
867
+ if (!this.store().getNodes().length) {
868
+ this.loading.set(true);
869
+ this.store()
870
+ .setFilter({})
871
+ .finally(() => {
872
+ this.loading.set(false);
873
+ console.log('nodes loaded', this.store().getNodes());
874
+ });
875
+ }
876
+ }
877
+ ngOnDestroy() {
878
+ this._sub?.unsubscribe();
879
+ }
880
+ reset() {
881
+ this.loading.set(true);
882
+ this.store()
883
+ .reset()
884
+ .finally(() => {
885
+ this.loading.set(false);
886
+ });
887
+ }
888
+ onToggleExpanded(node) {
889
+ this.loading.set(true);
890
+ if (node.expanded) {
891
+ this.store()
892
+ .collapse(node.id)
893
+ .finally(() => {
894
+ this.loading.set(false);
895
+ });
896
+ }
897
+ else {
898
+ this.store()
899
+ .expand(node.id)
900
+ .finally(() => {
901
+ this.loading.set(false);
902
+ });
903
+ }
904
+ }
905
+ onPageChangeRequest(request) {
906
+ this.loading.set(true);
907
+ this.store()
908
+ .changePage(request.node.id, request.paging.pageNumber)
909
+ .finally(() => {
910
+ this.loading.set(false);
911
+ });
912
+ }
913
+ onFilterChange(filter) {
914
+ console.log('filter change', filter);
915
+ this.loading.set(true);
916
+ this.store()
917
+ .setFilter(filter || {})
918
+ .finally(() => {
919
+ this.loading.set(false);
920
+ });
921
+ }
922
+ onEditFilterRequest(node) {
923
+ const dialogRef = this._dialog.open(ThesPagedTreeFilterComponent, {
924
+ data: {
925
+ filter: node.filter,
926
+ },
927
+ });
928
+ dialogRef.afterClosed().subscribe((filter) => {
929
+ // undefined = user dismissed without changes
930
+ if (filter === null) {
931
+ this.store().setNodeFilter(node.id, null);
932
+ }
933
+ else if (filter) {
934
+ this.store().setNodeFilter(node.id, filter);
935
+ }
936
+ });
937
+ }
938
+ expandAll() {
939
+ this.store().expandAll();
940
+ }
941
+ collapseAll() {
942
+ this.store().collapseAll();
943
+ }
944
+ clear() {
945
+ this.store().clear();
946
+ }
947
+ onNodeClick(node) {
948
+ if (!node.hasChildren) {
949
+ this.nodePick.emit(node);
950
+ }
951
+ }
952
+ findLabels() {
953
+ if (!this.label.value) {
954
+ return;
955
+ }
956
+ this.store().findLabels(this.label.value);
957
+ }
958
+ removeHilites() {
959
+ this.store().removeHilites();
960
+ }
961
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ThesPagedTreeBrowserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
962
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: ThesPagedTreeBrowserComponent, isStandalone: true, selector: "cadmus-thes-paged-tree-browser", inputs: { service: { classPropertyName: "service", publicName: "service", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodePick: "nodePick" }, ngImport: i0, template: "<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\" class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label>label</mat-label>\r\n <input matInput [formControl]=\"label\" />\r\n @if ($any(label).errors?.required && (label.dirty || label.touched)) {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button type=\"button\" mat-icon-button (click)=\"removeHilites()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thes-paged-tree-filter\r\n [filter]=\"filter$ | async\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n\r\n <!-- tree -->\r\n <div id=\"tree\">\r\n <!-- progress -->\r\n @if (loading()) {\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\r\n </div>\r\n }\r\n <!-- nodes -->\r\n @if (nodes$ | async; as nodes) {\r\n <div>\r\n @for (node of nodes; track node.id; let i = $index) {\r\n <div class=\"button-row\" [class.hilite]=\"node.hilite\">\r\n <pdb-browser-tree-node\r\n [node]=\"node\"\r\n [debug]=\"debug.value\"\r\n [paging]=\"\r\n node.expanded &&\r\n i + 1 < nodes.length &&\r\n nodes[i + 1].paging.pageCount > 1\r\n ? nodes[i + 1].paging\r\n : undefined\r\n \"\r\n [hideFilter]=\"hideFilter.value\"\r\n [hideLoc]=\"hideLoc.value\"\r\n (toggleExpandedRequest)=\"onToggleExpanded($any($event))\"\r\n (changePageRequest)=\"onPageChangeRequest($event)\"\r\n (editNodeFilterRequest)=\"onEditFilterRequest($any($event))\"\r\n />\r\n @if (!node.hasChildren) {\r\n <button type=\"button\" mat-icon-button (click)=\"onNodeClick(node)\">\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n <div class=\"form-row\">\r\n <mat-checkbox [formControl]=\"debug\">debug</mat-checkbox>\r\n <mat-checkbox [formControl]=\"hideFilter\">no filter</mat-checkbox>\r\n <mat-checkbox [formControl]=\"hideLoc\">no loc.</mat-checkbox>\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n (click)=\"collapseAll()\"\r\n style=\"margin-left: 24px\"\r\n >\r\n collapse\r\n </button>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: ["form{margin:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:6em}fieldset{border:1px solid silver;border-radius:6px;padding:8px 16px;margin:8px 0}legend{color:silver}th{text-align:left;font-weight:400}#tag-selector{width:8em}.tag-chip{border:2px solid transparent;border-radius:6px}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.hilite{background-color:#ffffe0;border:2px solid gold;border-radius:6px;padding:2px 4px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i7.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: ThesPagedTreeFilterComponent, selector: "cadmus-thes-paged-tree-filter", inputs: ["filter"], outputs: ["filterChange"] }, { kind: "component", type: BrowserTreeNodeComponent, selector: "pdb-browser-tree-node", inputs: ["node", "paging", "debug", "hideLabel", "hideLoc", "hidePaging", "hideFilter", "indentSize", "rangeWidth"], outputs: ["toggleExpandedRequest", "changePageRequest", "editNodeFilterRequest"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] });
963
+ }
964
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ThesPagedTreeBrowserComponent, decorators: [{
965
+ type: Component,
966
+ args: [{ selector: 'cadmus-thes-paged-tree-browser', imports: [
967
+ AsyncPipe,
968
+ ReactiveFormsModule,
969
+ MatButtonModule,
970
+ MatCheckboxModule,
971
+ MatFormFieldModule,
972
+ MatIconModule,
973
+ MatInputModule,
974
+ MatProgressBarModule,
975
+ MatTooltipModule,
976
+ ThesPagedTreeFilterComponent,
977
+ BrowserTreeNodeComponent,
978
+ ], template: "<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\" class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label>label</mat-label>\r\n <input matInput [formControl]=\"label\" />\r\n @if ($any(label).errors?.required && (label.dirty || label.touched)) {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button type=\"button\" mat-icon-button (click)=\"removeHilites()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thes-paged-tree-filter\r\n [filter]=\"filter$ | async\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n\r\n <!-- tree -->\r\n <div id=\"tree\">\r\n <!-- progress -->\r\n @if (loading()) {\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\r\n </div>\r\n }\r\n <!-- nodes -->\r\n @if (nodes$ | async; as nodes) {\r\n <div>\r\n @for (node of nodes; track node.id; let i = $index) {\r\n <div class=\"button-row\" [class.hilite]=\"node.hilite\">\r\n <pdb-browser-tree-node\r\n [node]=\"node\"\r\n [debug]=\"debug.value\"\r\n [paging]=\"\r\n node.expanded &&\r\n i + 1 < nodes.length &&\r\n nodes[i + 1].paging.pageCount > 1\r\n ? nodes[i + 1].paging\r\n : undefined\r\n \"\r\n [hideFilter]=\"hideFilter.value\"\r\n [hideLoc]=\"hideLoc.value\"\r\n (toggleExpandedRequest)=\"onToggleExpanded($any($event))\"\r\n (changePageRequest)=\"onPageChangeRequest($event)\"\r\n (editNodeFilterRequest)=\"onEditFilterRequest($any($event))\"\r\n />\r\n @if (!node.hasChildren) {\r\n <button type=\"button\" mat-icon-button (click)=\"onNodeClick(node)\">\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n <div class=\"form-row\">\r\n <mat-checkbox [formControl]=\"debug\">debug</mat-checkbox>\r\n <mat-checkbox [formControl]=\"hideFilter\">no filter</mat-checkbox>\r\n <mat-checkbox [formControl]=\"hideLoc\">no loc.</mat-checkbox>\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n (click)=\"collapseAll()\"\r\n style=\"margin-left: 24px\"\r\n >\r\n collapse\r\n </button>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: ["form{margin:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:6em}fieldset{border:1px solid silver;border-radius:6px;padding:8px 16px;margin:8px 0}legend{color:silver}th{text-align:left;font-weight:400}#tag-selector{width:8em}.tag-chip{border:2px solid transparent;border-radius:6px}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.hilite{background-color:#ffffe0;border:2px solid gold;border-radius:6px;padding:2px 4px}\n"] }]
979
+ }], ctorParameters: () => [] });
980
+
595
981
  var PartBadgeType;
596
982
  (function (PartBadgeType) {
597
983
  PartBadgeType[PartBadgeType["partAndRole"] = 0] = "partAndRole";
@@ -636,10 +1022,6 @@ function getPartIdName(typeId, roleId, typeThesaurus, noFallback = false) {
636
1022
  class PartBadgeComponent {
637
1023
  _facetService;
638
1024
  _colorService;
639
- typeName;
640
- roleName;
641
- color;
642
- contrastColor;
643
1025
  /**
644
1026
  * The badge type: 0=part and role, 1=part only, 2=role only.
645
1027
  */
@@ -656,11 +1038,13 @@ class PartBadgeComponent {
656
1038
  * The part type IDs.
657
1039
  */
658
1040
  partTypeIds = input(...(ngDevMode ? [undefined, { debugName: "partTypeIds" }] : []));
1041
+ typeName = signal(undefined, ...(ngDevMode ? [{ debugName: "typeName" }] : []));
1042
+ roleName = signal(undefined, ...(ngDevMode ? [{ debugName: "roleName" }] : []));
1043
+ color = signal('transparent', ...(ngDevMode ? [{ debugName: "color" }] : []));
1044
+ contrastColor = signal('black', ...(ngDevMode ? [{ debugName: "contrastColor" }] : []));
659
1045
  constructor(_facetService, _colorService) {
660
1046
  this._facetService = _facetService;
661
1047
  this._colorService = _colorService;
662
- this.color = 'transparent';
663
- this.contrastColor = 'black';
664
1048
  effect(() => {
665
1049
  this.updateBadge(this.partTypeIds(), this.typeThesaurus(), this.facetDefinition());
666
1050
  });
@@ -697,40 +1081,25 @@ class PartBadgeComponent {
697
1081
  }
698
1082
  updateBadge(partTypeIds, typeThesaurus, facetDefinition) {
699
1083
  if (partTypeIds) {
700
- this.color = this.getPartColor(partTypeIds.typeId, partTypeIds.roleId, facetDefinition);
701
- this.typeName = getPartIdName(partTypeIds.typeId, partTypeIds.roleId, typeThesaurus);
702
- this.roleName = this.getRoleIdName(partTypeIds.roleId, typeThesaurus);
1084
+ this.color.set(this.getPartColor(partTypeIds.typeId, partTypeIds.roleId, facetDefinition));
1085
+ this.typeName.set(getPartIdName(partTypeIds.typeId, partTypeIds.roleId, typeThesaurus));
1086
+ this.roleName.set(this.getRoleIdName(partTypeIds.roleId, typeThesaurus));
703
1087
  }
704
1088
  else {
705
- this.color = 'transparent';
706
- this.typeName = undefined;
707
- this.roleName = undefined;
1089
+ this.color.set('transparent');
1090
+ this.typeName.set(undefined);
1091
+ this.roleName.set(undefined);
708
1092
  }
709
- this.contrastColor = this._colorService.getContrastColor(this.color);
1093
+ this.contrastColor.set(this._colorService.getContrastColor(this.color()));
710
1094
  }
711
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: PartBadgeComponent, deps: [{ token: i1$2.FacetService }, { token: ColorService }], target: i0.ɵɵFactoryTarget.Component });
712
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: PartBadgeComponent, isStandalone: true, selector: "cadmus-part-badge", inputs: { badgeType: { classPropertyName: "badgeType", publicName: "badgeType", isSignal: true, isRequired: false, transformFunction: null }, typeThesaurus: { classPropertyName: "typeThesaurus", publicName: "typeThesaurus", isSignal: true, isRequired: false, transformFunction: null }, facetDefinition: { classPropertyName: "facetDefinition", publicName: "facetDefinition", isSignal: true, isRequired: false, transformFunction: null }, partTypeIds: { classPropertyName: "partTypeIds", publicName: "partTypeIds", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (badgeType() !== 2) {\r\n<span\r\n class=\"part-badge\"\r\n [style.background-color]=\"color\"\r\n [style.color]=\"contrastColor\"\r\n>\r\n {{ typeName }}\r\n</span>\r\n} @if (badgeType() !== 1 && roleName) {\r\n<span class=\"role-badge\">\r\n {{ roleName }}\r\n</span>\r\n}\r\n", styles: [".part-badge{padding:4px;border-radius:6px}.role-badge{padding:4px;border:1px solid silver;border-radius:6px}\n"] });
1095
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: PartBadgeComponent, deps: [{ token: i1$2.FacetService }, { token: ColorService }], target: i0.ɵɵFactoryTarget.Component });
1096
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: PartBadgeComponent, isStandalone: true, selector: "cadmus-part-badge", inputs: { badgeType: { classPropertyName: "badgeType", publicName: "badgeType", isSignal: true, isRequired: false, transformFunction: null }, typeThesaurus: { classPropertyName: "typeThesaurus", publicName: "typeThesaurus", isSignal: true, isRequired: false, transformFunction: null }, facetDefinition: { classPropertyName: "facetDefinition", publicName: "facetDefinition", isSignal: true, isRequired: false, transformFunction: null }, partTypeIds: { classPropertyName: "partTypeIds", publicName: "partTypeIds", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (badgeType() !== 2) {\r\n<span\r\n class=\"part-badge\"\r\n [style.background-color]=\"color()\"\r\n [style.color]=\"contrastColor()\"\r\n>\r\n {{ typeName() }}\r\n</span>\r\n} @if (badgeType() !== 1 && roleName()) {\r\n<span class=\"role-badge\">\r\n {{ roleName() }}\r\n</span>\r\n}\r\n", styles: [".part-badge{padding:4px;border-radius:6px}.role-badge{padding:4px;border:1px solid silver;border-radius:6px}\n"] });
713
1097
  }
714
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: PartBadgeComponent, decorators: [{
1098
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: PartBadgeComponent, decorators: [{
715
1099
  type: Component,
716
- args: [{ selector: 'cadmus-part-badge', template: "@if (badgeType() !== 2) {\r\n<span\r\n class=\"part-badge\"\r\n [style.background-color]=\"color\"\r\n [style.color]=\"contrastColor\"\r\n>\r\n {{ typeName }}\r\n</span>\r\n} @if (badgeType() !== 1 && roleName) {\r\n<span class=\"role-badge\">\r\n {{ roleName }}\r\n</span>\r\n}\r\n", styles: [".part-badge{padding:4px;border-radius:6px}.role-badge{padding:4px;border:1px solid silver;border-radius:6px}\n"] }]
1100
+ args: [{ selector: 'cadmus-part-badge', template: "@if (badgeType() !== 2) {\r\n<span\r\n class=\"part-badge\"\r\n [style.background-color]=\"color()\"\r\n [style.color]=\"contrastColor()\"\r\n>\r\n {{ typeName() }}\r\n</span>\r\n} @if (badgeType() !== 1 && roleName()) {\r\n<span class=\"role-badge\">\r\n {{ roleName() }}\r\n</span>\r\n}\r\n", styles: [".part-badge{padding:4px;border-radius:6px}.role-badge{padding:4px;border:1px solid silver;border-radius:6px}\n"] }]
717
1101
  }], ctorParameters: () => [{ type: i1$2.FacetService }, { type: ColorService }] });
718
1102
 
719
- /**
720
- * A label rendering function which removes from a label
721
- * all the characters past the last colon, trimming the result.
722
- * This is a typical rendering when dealing with hierarchical
723
- * thesaurus entries, e.g. "furniture: table: color", where
724
- * we can shorten the label to just "color", as "furniture"
725
- * and "table" are its ancestors.
726
- */
727
- const renderLabelFromLastColon = (label) => {
728
- if (!label) {
729
- return label;
730
- }
731
- const i = label.lastIndexOf(':');
732
- return i > -1 && i + 1 < label.length ? label.substring(i + 1).trim() : label;
733
- };
734
1103
  /**
735
1104
  * Thesaurus tree component.
736
1105
  * This component displays a set of hierarchical thesaurus entries
@@ -749,203 +1118,42 @@ class ThesaurusTreeComponent {
749
1118
  * The thesaurus entries.
750
1119
  */
751
1120
  entries = input(...(ngDevMode ? [undefined, { debugName: "entries" }] : []));
752
- /**
753
- * The label for the root node.
754
- */
755
- rootLabel = input('-', ...(ngDevMode ? [{ debugName: "rootLabel" }] : []));
756
1121
  /**
757
1122
  * The optional node label rendering function.
758
1123
  */
759
- renderLabel = input(...(ngDevMode ? [undefined, { debugName: "renderLabel" }] : []));
1124
+ renderLabel = input(renderLabelFromLastColon, ...(ngDevMode ? [{ debugName: "renderLabel" }] : []));
760
1125
  /**
761
1126
  * Fired when a thesaurus entry is selected.
762
1127
  */
763
1128
  entryChange = output();
764
- root;
765
- // TODO: use childrenAccessor: https://material.angular.io/cdk/tree/examples
766
- treeControl;
767
- treeDataSource;
768
- filter;
769
- form;
770
- foundNodes;
771
- hasChildren = (index, node) => {
772
- return node && node.children && node.children.length > 0;
773
- };
774
- isRoot = (index, node) => {
775
- return node && node.id === '@root';
776
- };
777
- constructor(formBuilder) {
778
- // tree
779
- this.treeControl = new NestedTreeControl((node) => node.children);
780
- this.treeDataSource = new MatTreeNestedDataSource();
781
- this.root = { id: '@root', label: '-', children: [] };
782
- // filter
783
- this.filter = formBuilder.control(null);
784
- this.form = formBuilder.group({
785
- filter: this.filter,
786
- });
787
- effect(() => {
788
- this.initTree(this.entries());
789
- });
790
- }
791
- ngOnInit() {
792
- this.initTree();
793
- }
794
- initTree(entries) {
795
- this.foundNodes = undefined;
796
- this.root = this.buildTreeModel(entries || []);
797
- this.treeDataSource.data = [this.root];
798
- // https://github.com/angular/components/issues/12469
799
- this.treeControl.dataNodes = this.treeDataSource.data;
800
- }
801
- getLabel(label) {
802
- const renderer = this.renderLabel();
803
- return renderer ? renderer(label) : label;
804
- }
805
- addNode(entry, separator, root) {
806
- const components = entry.id.split(separator);
807
- // walk the tree up to the last existing component
808
- let i = 0;
809
- let node = root;
810
- const idParts = [];
811
- // for each component:
812
- while (i < components.length) {
813
- idParts.push(components[i]);
814
- // stop walking when the node has no more children
815
- if (!node.children) {
816
- break;
817
- }
818
- // find target among children
819
- const targetId = idParts.join(separator);
820
- const existing = node.children.find((c) => {
821
- return c.id === targetId;
822
- });
823
- if (existing) {
824
- node = existing;
825
- i++;
826
- }
827
- else {
828
- break;
829
- }
830
- }
831
- // node is now the last existing component; use it as the ancestor
832
- // for all the remaining components (starting from i)
833
- while (i < components.length) {
834
- if (!node.children) {
835
- node.children = [];
836
- }
837
- const isLast = i + 1 === components.length;
838
- const label = isLast ? entry.value : components[i];
839
- const child = {
840
- label: isLast ? this.getLabel(label) : label,
841
- id: isLast ? entry.id : idParts.join(separator),
842
- parent: node,
843
- children: [],
844
- };
845
- if (label !== child.label) {
846
- child.originalLabel = label;
847
- }
848
- node.children.push(child);
849
- node = child;
850
- i++;
851
- }
852
- }
853
1129
  /**
854
- * Build a tree model from a list of name=value pairs,
855
- * where each value can include one or more components separated by
856
- * the specified separator.
857
- * @param entries The entries to add.
858
- * @param separator string The separator string to use for values.
1130
+ * The tree store service, dependent on the current entries and renderLabel.
859
1131
  */
860
- buildTreeModel(entries, separator = '.') {
861
- const root = {
862
- id: '@root',
863
- label: this.rootLabel() || '-',
864
- };
865
- if (!entries) {
866
- return root;
867
- }
868
- entries.forEach((entry) => {
869
- this.addNode(entry, separator, root);
870
- });
871
- return root;
872
- }
873
- onTreeNodeClick(node) {
874
- if (node.children && node.children.length > 0) {
875
- return;
876
- }
877
- this.entryChange.emit({
878
- id: node.id,
879
- value: node.originalLabel || node.label,
880
- });
881
- }
882
- expandAll() {
883
- this.treeControl.expandAll();
884
- }
885
- collapseAll() {
886
- this.treeControl.collapseAll();
887
- }
888
- expandFromNode(node) {
889
- while (node.parent) {
890
- node = node.parent;
891
- this.treeControl.expand(node);
892
- }
893
- }
894
- expandMatchingNodes(node, filter, found) {
895
- if (node.label.toLowerCase().includes(filter)) {
896
- found.push(node);
897
- this.expandFromNode(node);
898
- }
899
- if (node.children?.length) {
900
- node.children.forEach((child) => {
901
- this.expandMatchingNodes(child, filter, found);
902
- });
903
- }
904
- }
905
- find() {
906
- if (!this.filter.value?.length) {
907
- return;
908
- }
909
- this.treeControl.collapseAll();
910
- const foundNodes = [];
911
- this.expandMatchingNodes(this.treeDataSource.data[0], this.filter.value.toLowerCase(), foundNodes);
912
- this.foundNodes = foundNodes;
913
- }
914
- resetFilter() {
915
- this.filter.reset();
916
- this.foundNodes = undefined;
917
- }
918
- isFoundNode(node) {
919
- if (!this.foundNodes) {
920
- return false;
1132
+ service = computed(() => {
1133
+ const entries = this.entries();
1134
+ return new StaticThesPagedTreeStoreService(entries || [], this.renderLabel());
1135
+ }, ...(ngDevMode ? [{ debugName: "service" }] : []));
1136
+ /**
1137
+ * The filter component class to use.
1138
+ */
1139
+ filterComponent = ThesPagedTreeFilterComponent;
1140
+ onNodePick(node) {
1141
+ // only allow selection of leaf nodes (nodes without children)
1142
+ if (!node.hasChildren) {
1143
+ // find the original entry
1144
+ const entry = this.entries()?.find((e) => e.id === node.key);
1145
+ if (entry) {
1146
+ this.entryChange.emit(entry);
1147
+ }
921
1148
  }
922
- return this.foundNodes?.length > 0 && this.foundNodes.indexOf(node) > -1;
923
1149
  }
924
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ThesaurusTreeComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
925
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: ThesaurusTreeComponent, isStandalone: true, selector: "cadmus-thesaurus-tree", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, rootLabel: { classPropertyName: "rootLabel", publicName: "rootLabel", isSignal: true, isRequired: false, transformFunction: null }, renderLabel: { classPropertyName: "renderLabel", publicName: "renderLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entryChange: "entryChange" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"find()\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Expand all\"\r\n (click)=\"expandAll()\"\r\n >\r\n <mat-icon>unfold_more</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Collapse all\"\r\n (click)=\"collapseAll()\"\r\n >\r\n <mat-icon>unfold_less</mat-icon>\r\n </button>\r\n <mat-form-field>\r\n <mat-label>find</mat-label>\r\n <input matInput [formControl]=\"filter\" />\r\n <button\r\n type=\"button\"\r\n matSuffix\r\n mat-icon-button\r\n (click)=\"resetFilter()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n @if (foundNodes) {\r\n <span\r\n [ngClass]=\"{\r\n 'found-count': foundNodes.length,\r\n 'not-found-count': foundNodes.length === 0\r\n }\"\r\n >{{ foundNodes.length }}</span\r\n >\r\n }\r\n</form>\r\n<mat-tree\r\n [dataSource]=\"treeDataSource\"\r\n [treeControl]=\"treeControl\"\r\n class=\"th-tree\"\r\n>\r\n <!-- leaf node -->\r\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodeToggle>\r\n <li>\r\n <div class=\"mat-tree-node\">\r\n <a\r\n mat-button\r\n (click)=\"onTreeNodeClick(node)\"\r\n [class.hilite]=\"isFoundNode(node)\"\r\n >\r\n {{ node.label }}\r\n </a>\r\n </div>\r\n </li>\r\n </mat-tree-node>\r\n\r\n <!-- root node -->\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: isRoot\">\r\n <div class=\"mat-tree-node\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTreeNodeToggle\r\n [attr.aria-label]=\"'Toggle ' + node.label\"\r\n >\r\n <mat-icon>\r\n {{ treeControl.isExpanded(node) ? \"expand_more\" : \"chevron_right\" }}\r\n </mat-icon>\r\n </button>\r\n {{ node.label }}\r\n </div>\r\n <ul class=\"tree-nested-node\">\r\n @if (treeControl.isExpanded(node)) {\r\n <div>\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n }\r\n </ul>\r\n </mat-nested-tree-node>\r\n\r\n <!-- parent node -->\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: hasChildren\">\r\n <li class=\"tree-container\">\r\n <div class=\"mat-tree-node\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTreeNodeToggle\r\n [attr.aria-label]=\"'Toggle ' + node.label\"\r\n >\r\n <mat-icon>\r\n {{ treeControl.isExpanded(node) ? \"expand_more\" : \"chevron_right\" }}\r\n </mat-icon>\r\n </button>\r\n <a mat-button (click)=\"onTreeNodeClick(node)\">\r\n {{ node.label }}\r\n </a>\r\n </div>\r\n <ul class=\"tree-nested-node\">\r\n @if (treeControl.isExpanded(node)) {\r\n <div>\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n }\r\n </ul>\r\n </li>\r\n </mat-nested-tree-node>\r\n</mat-tree>\r\n", styles: [".th-tree-progress-bar{margin-left:30px}.th-tree-nested-node{padding-left:30px}mat-tree{margin-left:40px}.mat-tree-node{padding:0;background-color:#fff}.mat-nested-tree-node{top:-24px}ul,li{list-style:none;margin:0;padding:0}li.th-tree-container{border-bottom:0}ul{padding-left:40px}li{padding-left:40px;border:1px dotted grey;border-width:0 0 1px 1px;position:relative;top:-24px}li.mat-tree-node,li div{margin:0;position:relative;top:24px}li ul{border-top:1px dotted grey;margin-left:-40px;padding-left:60px}.mat-nested-tree-node:last-child ul{border-left:1px solid white;margin-left:-41px}.mat-mdc-icon-button{z-index:100}span.found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#0cc078;border-radius:6px}span.not-found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#fb6962;border-radius:6px}.hilite{background-color:#fdfd96}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "directive", type: MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "component", type: MatAnchor, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }] });
1150
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ThesaurusTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1151
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: ThesaurusTreeComponent, isStandalone: true, selector: "cadmus-thesaurus-tree", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, renderLabel: { classPropertyName: "renderLabel", publicName: "renderLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entryChange: "entryChange" }, ngImport: i0, template: "<div>\r\n <!-- tree -->\r\n @if (service() && entries()?.length) {\r\n <div class=\"tree-wrapper\">\r\n <cadmus-thes-paged-tree-browser\r\n [service]=\"service()\"\r\n (nodePick)=\"onNodePick($event)\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", styles: [".th-tree-progress-bar{margin-left:30px}.th-tree-nested-node{padding-left:30px}mat-tree{margin-left:40px}.mat-tree-node{padding:0;background-color:#fff}.mat-nested-tree-node{top:-24px}ul,li{list-style:none;margin:0;padding:0}li.th-tree-container{border-bottom:0}ul{padding-left:40px}li{padding-left:40px;border:1px dotted grey;border-width:0 0 1px 1px;position:relative;top:-24px}li.mat-tree-node,li div{margin:0;position:relative;top:24px}li ul{border-top:1px dotted grey;margin-left:-40px;padding-left:60px}.mat-nested-tree-node:last-child ul{border-left:1px solid white;margin-left:-41px}.mat-mdc-icon-button{z-index:100}span.found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#0cc078;border-radius:6px}span.not-found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#fb6962;border-radius:6px}.hilite{background-color:#fdfd96}.filter-field{width:100%;margin-bottom:1rem}.tree-container{border:1px solid #e0e0e0;border-radius:4px;overflow:auto;max-height:500px}.tree-wrapper{border:1px solid #e0e0e0;border-radius:4px;overflow:hidden;background:#fff}.no-entries{text-align:center;padding:2rem;color:#666;font-style:italic;border:1px solid #e0e0e0;border-radius:4px;background:#f9f9f9}.no-entries p{margin:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: ThesPagedTreeBrowserComponent, selector: "cadmus-thes-paged-tree-browser", inputs: ["service"], outputs: ["nodePick"] }] });
926
1152
  }
927
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ThesaurusTreeComponent, decorators: [{
1153
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ThesaurusTreeComponent, decorators: [{
928
1154
  type: Component,
929
- args: [{ selector: 'cadmus-thesaurus-tree', imports: [
930
- FormsModule,
931
- ReactiveFormsModule,
932
- MatIconButton,
933
- MatTooltip,
934
- MatIcon,
935
- MatFormField,
936
- MatLabel,
937
- MatInput,
938
- MatSuffix,
939
- NgClass,
940
- MatTree,
941
- MatTreeNodeDef,
942
- MatTreeNode,
943
- MatTreeNodeToggle,
944
- MatAnchor,
945
- MatNestedTreeNode,
946
- MatTreeNodeOutlet,
947
- ], template: "<form [formGroup]=\"form\" (submit)=\"find()\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Expand all\"\r\n (click)=\"expandAll()\"\r\n >\r\n <mat-icon>unfold_more</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Collapse all\"\r\n (click)=\"collapseAll()\"\r\n >\r\n <mat-icon>unfold_less</mat-icon>\r\n </button>\r\n <mat-form-field>\r\n <mat-label>find</mat-label>\r\n <input matInput [formControl]=\"filter\" />\r\n <button\r\n type=\"button\"\r\n matSuffix\r\n mat-icon-button\r\n (click)=\"resetFilter()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n @if (foundNodes) {\r\n <span\r\n [ngClass]=\"{\r\n 'found-count': foundNodes.length,\r\n 'not-found-count': foundNodes.length === 0\r\n }\"\r\n >{{ foundNodes.length }}</span\r\n >\r\n }\r\n</form>\r\n<mat-tree\r\n [dataSource]=\"treeDataSource\"\r\n [treeControl]=\"treeControl\"\r\n class=\"th-tree\"\r\n>\r\n <!-- leaf node -->\r\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodeToggle>\r\n <li>\r\n <div class=\"mat-tree-node\">\r\n <a\r\n mat-button\r\n (click)=\"onTreeNodeClick(node)\"\r\n [class.hilite]=\"isFoundNode(node)\"\r\n >\r\n {{ node.label }}\r\n </a>\r\n </div>\r\n </li>\r\n </mat-tree-node>\r\n\r\n <!-- root node -->\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: isRoot\">\r\n <div class=\"mat-tree-node\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTreeNodeToggle\r\n [attr.aria-label]=\"'Toggle ' + node.label\"\r\n >\r\n <mat-icon>\r\n {{ treeControl.isExpanded(node) ? \"expand_more\" : \"chevron_right\" }}\r\n </mat-icon>\r\n </button>\r\n {{ node.label }}\r\n </div>\r\n <ul class=\"tree-nested-node\">\r\n @if (treeControl.isExpanded(node)) {\r\n <div>\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n }\r\n </ul>\r\n </mat-nested-tree-node>\r\n\r\n <!-- parent node -->\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: hasChildren\">\r\n <li class=\"tree-container\">\r\n <div class=\"mat-tree-node\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTreeNodeToggle\r\n [attr.aria-label]=\"'Toggle ' + node.label\"\r\n >\r\n <mat-icon>\r\n {{ treeControl.isExpanded(node) ? \"expand_more\" : \"chevron_right\" }}\r\n </mat-icon>\r\n </button>\r\n <a mat-button (click)=\"onTreeNodeClick(node)\">\r\n {{ node.label }}\r\n </a>\r\n </div>\r\n <ul class=\"tree-nested-node\">\r\n @if (treeControl.isExpanded(node)) {\r\n <div>\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n }\r\n </ul>\r\n </li>\r\n </mat-nested-tree-node>\r\n</mat-tree>\r\n", styles: [".th-tree-progress-bar{margin-left:30px}.th-tree-nested-node{padding-left:30px}mat-tree{margin-left:40px}.mat-tree-node{padding:0;background-color:#fff}.mat-nested-tree-node{top:-24px}ul,li{list-style:none;margin:0;padding:0}li.th-tree-container{border-bottom:0}ul{padding-left:40px}li{padding-left:40px;border:1px dotted grey;border-width:0 0 1px 1px;position:relative;top:-24px}li.mat-tree-node,li div{margin:0;position:relative;top:24px}li ul{border-top:1px dotted grey;margin-left:-40px;padding-left:60px}.mat-nested-tree-node:last-child ul{border-left:1px solid white;margin-left:-41px}.mat-mdc-icon-button{z-index:100}span.found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#0cc078;border-radius:6px}span.not-found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#fb6962;border-radius:6px}.hilite{background-color:#fdfd96}\n"] }]
948
- }], ctorParameters: () => [{ type: i1$1.FormBuilder }] });
1155
+ args: [{ selector: 'cadmus-thesaurus-tree', imports: [FormsModule, ReactiveFormsModule, ThesPagedTreeBrowserComponent], template: "<div>\r\n <!-- tree -->\r\n @if (service() && entries()?.length) {\r\n <div class=\"tree-wrapper\">\r\n <cadmus-thes-paged-tree-browser\r\n [service]=\"service()\"\r\n (nodePick)=\"onNodePick($event)\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", styles: [".th-tree-progress-bar{margin-left:30px}.th-tree-nested-node{padding-left:30px}mat-tree{margin-left:40px}.mat-tree-node{padding:0;background-color:#fff}.mat-nested-tree-node{top:-24px}ul,li{list-style:none;margin:0;padding:0}li.th-tree-container{border-bottom:0}ul{padding-left:40px}li{padding-left:40px;border:1px dotted grey;border-width:0 0 1px 1px;position:relative;top:-24px}li.mat-tree-node,li div{margin:0;position:relative;top:24px}li ul{border-top:1px dotted grey;margin-left:-40px;padding-left:60px}.mat-nested-tree-node:last-child ul{border-left:1px solid white;margin-left:-41px}.mat-mdc-icon-button{z-index:100}span.found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#0cc078;border-radius:6px}span.not-found-count{margin:0 4px;padding:2px 4px;color:#fff;background-color:#fb6962;border-radius:6px}.hilite{background-color:#fdfd96}.filter-field{width:100%;margin-bottom:1rem}.tree-container{border:1px solid #e0e0e0;border-radius:4px;overflow:auto;max-height:500px}.tree-wrapper{border:1px solid #e0e0e0;border-radius:4px;overflow:hidden;background:#fff}.no-entries{text-align:center;padding:2rem;color:#666;font-style:italic;border:1px solid #e0e0e0;border-radius:4px;background:#f9f9f9}.no-entries p{margin:0}\n"] }]
1156
+ }] });
949
1157
 
950
1158
  /**
951
1159
  * Base class for part/fragment editors dumb components.
@@ -1178,10 +1386,10 @@ class ModelEditorComponentBase {
1178
1386
  // the form is no more dirty
1179
1387
  this.form.markAsPristine();
1180
1388
  }
1181
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ModelEditorComponentBase, deps: [{ token: i1$3.AuthJwtService }, { token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
1182
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.0", type: ModelEditorComponentBase, isStandalone: false, selector: "ng-component", inputs: { identity: { classPropertyName: "identity", publicName: "identity", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { data: "dataChange", dirtyChange: "dirtyChange", editorClose: "editorClose" }, ngImport: i0, template: '', isInline: true });
1389
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ModelEditorComponentBase, deps: [{ token: i1$3.AuthJwtService }, { token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
1390
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.0", type: ModelEditorComponentBase, isStandalone: false, selector: "ng-component", inputs: { identity: { classPropertyName: "identity", publicName: "identity", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { data: "dataChange", dirtyChange: "dirtyChange", editorClose: "editorClose" }, ngImport: i0, template: '', isInline: true });
1183
1391
  }
1184
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ModelEditorComponentBase, decorators: [{
1392
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ModelEditorComponentBase, decorators: [{
1185
1393
  type: Component,
1186
1394
  args: [{
1187
1395
  template: '',
@@ -1263,10 +1471,10 @@ class UserRefLookupService {
1263
1471
  getName(item) {
1264
1472
  return item?.user?.userName;
1265
1473
  }
1266
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: UserRefLookupService, deps: [{ token: i1$2.UserService }], target: i0.ɵɵFactoryTarget.Injectable });
1267
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: UserRefLookupService, providedIn: 'root' });
1474
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: UserRefLookupService, deps: [{ token: i1$2.UserService }], target: i0.ɵɵFactoryTarget.Injectable });
1475
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: UserRefLookupService, providedIn: 'root' });
1268
1476
  }
1269
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: UserRefLookupService, decorators: [{
1477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: UserRefLookupService, decorators: [{
1270
1478
  type: Injectable,
1271
1479
  args: [{
1272
1480
  providedIn: 'root',
@@ -1330,5 +1538,5 @@ const extractPristineChanges = (control) => {
1330
1538
  * Generated bundle index. Do not edit.
1331
1539
  */
1332
1540
 
1333
- export { CloseSaveButtonsComponent, ColorService, CustomValidators, DecoratedTokenTextComponent, ErrorListComponent, FacetBadgeComponent, FlagsBadgeComponent, JsonValidators, LayerHintsComponent, LookupPinComponent, ModelEditorComponentBase, PartBadgeComponent, PartBadgeType, ThesaurusTreeComponent, UserRefLookupService, extractPristineChanges, extractTouchedChanges, getPartIdName, renderLabelFromLastColon };
1541
+ export { CloseSaveButtonsComponent, ColorService, CustomValidators, DecoratedTokenTextComponent, ErrorListComponent, FacetBadgeComponent, FlagsBadgeComponent, JsonValidators, LayerHintsComponent, LookupPinComponent, ModelEditorComponentBase, PartBadgeComponent, PartBadgeType, StaticThesPagedTreeStoreService, ThesPagedTreeBrowserComponent, ThesaurusTreeComponent, UserRefLookupService, extractPristineChanges, extractTouchedChanges, getPartIdName, renderLabelFromLastColon };
1334
1542
  //# sourceMappingURL=myrmidon-cadmus-ui.mjs.map