@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.
- package/fesm2022/myrmidon-cadmus-ui.mjs +495 -287
- package/fesm2022/myrmidon-cadmus-ui.mjs.map +1 -1
- package/index.d.ts +144 -69
- package/package.json +4 -3
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, Component, effect, ViewChild, Injectable, Inject, model, computed
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
18
|
-
import {
|
|
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 {
|
|
21
|
-
import
|
|
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.
|
|
33
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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()) {\
|
|
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
|
|
78
|
+
this.text.set(this._textLayerService.render(text, locations, selectedLocation));
|
|
71
79
|
}
|
|
72
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.
|
|
73
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.
|
|
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.
|
|
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.
|
|
86
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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) {\
|
|
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.
|
|
237
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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
|
|
319
|
-
this.contrastColor
|
|
320
|
-
this.tip
|
|
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.
|
|
323
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.
|
|
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.
|
|
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
|
|
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.
|
|
352
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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) { ◆ } @else { ⬤ }\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.
|
|
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) { ◆ } @else { ⬤ }\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) { ◆ } @else { ⬤ }\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.
|
|
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.
|
|
423
|
-
|
|
424
|
-
|
|
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.
|
|
433
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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()
|
|
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
|
|
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
|
|
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.
|
|
573
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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
|
|
701
|
-
this.typeName
|
|
702
|
-
this.roleName
|
|
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
|
|
706
|
-
this.typeName
|
|
707
|
-
this.roleName
|
|
1089
|
+
this.color.set('transparent');
|
|
1090
|
+
this.typeName.set(undefined);
|
|
1091
|
+
this.roleName.set(undefined);
|
|
708
1092
|
}
|
|
709
|
-
this.contrastColor
|
|
1093
|
+
this.contrastColor.set(this._colorService.getContrastColor(this.color()));
|
|
710
1094
|
}
|
|
711
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.
|
|
712
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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 ? [
|
|
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
|
-
*
|
|
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
|
-
|
|
861
|
-
const
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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.
|
|
925
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
1182
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.
|
|
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.
|
|
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.
|
|
1267
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.
|
|
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.
|
|
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
|