@myrmidon/cadmus-thesaurus-store 0.0.1 → 0.0.2

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/README.md CHANGED
@@ -75,7 +75,7 @@ Internally, this component uses:
75
75
  - an instance of the `StaticThesaurusPagedTreeStoreService`.
76
76
  - an instance of the `ThesaurusBrowserComponent`, which is a readonly paged tree browser specialized to display thesaurus entries.
77
77
 
78
- ### ThesaurusEntriesPicker
78
+ ### ThesaurusEntriesPickerComponent
79
79
 
80
80
  - 🔑 `cadmus-thesaurus-entries-picker`
81
81
 
@@ -109,6 +109,10 @@ An editable paged tree browser for thesaurus entries. Editing happens in memory
109
109
 
110
110
  ## History
111
111
 
112
+ ### 0.0.2
113
+
114
+ - 2026-01-31: fixes to thesaurus browser and editable thesaurus browser replacing `ngOnInit` with `effect` and using signals instead of observables to avoid having side effects in computed signals.
115
+
112
116
  ### 0.0.1
113
117
 
114
118
  - 2026-01-17:
@@ -2,8 +2,6 @@ import * as i0 from '@angular/core';
2
2
  import { inject, model, signal, effect, Component, Optional, Inject, input, output, computed, untracked } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormBuilder, ReactiveFormsModule, FormControl, Validators, FormGroup, FormsModule } from '@angular/forms';
5
- import { AsyncPipe } from '@angular/common';
6
- import { of } from 'rxjs';
7
5
  import * as i1$1 from '@angular/material/dialog';
8
6
  import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
9
7
  import * as i8 from '@angular/material/progress-bar';
@@ -28,6 +26,7 @@ import { PagedTreeStore, BrowserTreeNodeComponent, EditablePagedTreeStoreService
28
26
  import { moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
29
27
  import { MatChipListbox, MatChipOption, MatChipRemove } from '@angular/material/chips';
30
28
  import { MatExpansionPanel } from '@angular/material/expansion';
29
+ import { of } from 'rxjs';
31
30
 
32
31
  /**
33
32
  * A filter to be used for thesaurus paged tree browsers.
@@ -241,11 +240,13 @@ class EditableThesaurusBrowserComponent {
241
240
  if (!service) {
242
241
  return null;
243
242
  }
244
- const store = new PagedTreeStore(service);
245
- return store;
243
+ return new PagedTreeStore(service);
246
244
  }, ...(ngDevMode ? [{ debugName: "store" }] : []));
247
245
  this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
248
246
  this.selectedNode = signal(null, ...(ngDevMode ? [{ debugName: "selectedNode" }] : []));
247
+ // Signals for reactive data binding (replacing observables with async pipe)
248
+ this.nodes = signal([], ...(ngDevMode ? [{ debugName: "nodes" }] : []));
249
+ this.filter = signal({}, ...(ngDevMode ? [{ debugName: "filter" }] : []));
249
250
  this.debug = new FormControl(false, {
250
251
  nonNullable: true,
251
252
  });
@@ -255,39 +256,47 @@ class EditableThesaurusBrowserComponent {
255
256
  this.hideFilter = new FormControl(false, {
256
257
  nonNullable: true,
257
258
  });
258
- this.filter$ = of({});
259
- this.nodes$ = of([]);
260
259
  this.label = new FormControl(null);
261
260
  this.form = new FormGroup({
262
261
  label: this.label,
263
262
  });
264
- }
265
- ngOnInit() {
266
- const store = this.store();
267
- if (!store) {
268
- console.error('Store not available - service input is required');
269
- return;
270
- }
271
- // setup observables (delayed because we require store to be available)
272
- this.nodes$ = store.nodes$;
273
- this.filter$ = store.filter$;
274
- if (!store.getNodes().length) {
275
- this.loading.set(true);
276
- store.setFilter({}).finally(() => {
277
- this.loading.set(false);
278
- console.log('nodes loaded', store.getNodes());
263
+ // Use effect to react to service/store changes
264
+ effect(() => {
265
+ const currentStore = this.store();
266
+ const currentService = this.service();
267
+ // Cleanup previous subscriptions
268
+ this._nodesSub?.unsubscribe();
269
+ this._filterSub?.unsubscribe();
270
+ this._changesSub?.unsubscribe();
271
+ if (!currentStore || !currentService) {
272
+ this.nodes.set([]);
273
+ this.filter.set({});
274
+ return;
275
+ }
276
+ // Subscribe to store's observables and update signals
277
+ this._nodesSub = currentStore.nodes$.subscribe((nodes) => {
278
+ this.nodes.set(nodes);
279
279
  });
280
- }
281
- // subscribe to changes state
282
- const service = this.service();
283
- if (service) {
284
- this._sub = service.hasChanges$.subscribe((hasChanges) => {
280
+ this._filterSub = currentStore.filter$.subscribe((filter) => {
281
+ this.filter.set(filter);
282
+ });
283
+ // Subscribe to changes state
284
+ this._changesSub = currentService.hasChanges$.subscribe((hasChanges) => {
285
285
  this.changesStateChange.emit(hasChanges);
286
286
  });
287
- }
287
+ // Load nodes if store is empty
288
+ if (!currentStore.getNodes().length) {
289
+ this.loading.set(true);
290
+ currentStore.setFilter({}).finally(() => {
291
+ this.loading.set(false);
292
+ });
293
+ }
294
+ });
288
295
  }
289
296
  ngOnDestroy() {
290
- this._sub?.unsubscribe();
297
+ this._nodesSub?.unsubscribe();
298
+ this._filterSub?.unsubscribe();
299
+ this._changesSub?.unsubscribe();
291
300
  }
292
301
  reset() {
293
302
  const store = this.store();
@@ -455,7 +464,6 @@ class EditableThesaurusBrowserComponent {
455
464
  const currentService = this.service();
456
465
  if (!currentService)
457
466
  return;
458
- const currentEntries = currentService.getCurrentEntries();
459
467
  const selectedKey = selected.key; // original entry ID
460
468
  // determine the parent ID for the new sibling
461
469
  const selectedParts = selectedKey.split('.');
@@ -556,12 +564,11 @@ class EditableThesaurusBrowserComponent {
556
564
  });
557
565
  }
558
566
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: EditableThesaurusBrowserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
559
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: EditableThesaurusBrowserComponent, isStandalone: true, selector: "cadmus-editable-thesaurus-browser", inputs: { service: { classPropertyName: "service", publicName: "service", isSignal: true, isRequired: false, transformFunction: null }, hasRootFilter: { classPropertyName: "hasRootFilter", publicName: "hasRootFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodePick: "nodePick", changesStateChange: "changesStateChange" }, ngImport: i0, template: "<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\">\r\n <fieldset>\r\n <legend>finder</legend>\r\n <div 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 {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <div class=\"form-row\" style=\"gap: 0\">\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </fieldset>\r\n </form>\r\n @if (hasRootFilter()) {\r\n <fieldset>\r\n <legend>global filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter$ | async\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </div>\r\n\r\n <!-- editing actions -->\r\n <div class=\"editing-actions\">\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"primary\"\r\n [disabled]=\"!selectedNode()\"\r\n [matMenuTriggerFor]=\"addMenu\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n add\r\n </button>\r\n\r\n <mat-menu #addMenu=\"matMenu\">\r\n <button type=\"button\" mat-menu-item (click)=\"addChild()\">\r\n <mat-icon>subdirectory_arrow_right</mat-icon>\r\n add child\r\n </button>\r\n <button type=\"button\" mat-menu-item (click)=\"addSibling()\">\r\n <mat-icon>arrow_right_alt</mat-icon>\r\n add sibling\r\n </button>\r\n </mat-menu>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"accent\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"editNode()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n edit\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"warn\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"removeNode()\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n remove\r\n </button>\r\n\r\n @if (selectedNode()) {\r\n <span class=\"selected-info\"> selected: {{ selectedNode()!.label }} </span>\r\n }\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\r\n class=\"button-row\"\r\n [class.hilite]=\"node.hilite\"\r\n [class.selected]=\"selectedNode()?.id === node.id\"\r\n (click)=\"onNodeClick(node)\"\r\n >\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 </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: ["#container{padding:16px}.form-row{display:flex;align-items:center;gap:8px;margin-bottom:16px}.editing-actions{display:flex;align-items:center;gap:12px;margin-bottom:16px;padding:12px;border:1px solid #e0e0e0;border-radius:4px;background-color:#fafafa}.selected-info{margin-left:auto;font-style:italic;color:#666}.button-row{cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.button-row:hover{background-color:#f5f5f5}.button-row.selected{background-color:#e3f2fd;border:1px solid #2196f3}.button-row.hilite{background-color:#fff3e0}#tree{overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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.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: i6.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: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i8.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: ThesaurusPagedTreeFilterComponent, selector: "cadmus-thesaurus-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" }] }); }
567
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: EditableThesaurusBrowserComponent, isStandalone: true, selector: "cadmus-editable-thesaurus-browser", inputs: { service: { classPropertyName: "service", publicName: "service", isSignal: true, isRequired: false, transformFunction: null }, hasRootFilter: { classPropertyName: "hasRootFilter", publicName: "hasRootFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodePick: "nodePick", changesStateChange: "changesStateChange" }, ngImport: i0, template: "<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\">\r\n <fieldset>\r\n <legend>finder</legend>\r\n <div 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 {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <div class=\"form-row\" style=\"gap: 0\">\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </fieldset>\r\n </form>\r\n @if (hasRootFilter()) {\r\n <fieldset>\r\n <legend>global filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter()\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </div>\r\n\r\n <!-- editing actions -->\r\n <div class=\"editing-actions\">\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"primary\"\r\n [disabled]=\"!selectedNode()\"\r\n [matMenuTriggerFor]=\"addMenu\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n add\r\n </button>\r\n\r\n <mat-menu #addMenu=\"matMenu\">\r\n <button type=\"button\" mat-menu-item (click)=\"addChild()\">\r\n <mat-icon>subdirectory_arrow_right</mat-icon>\r\n add child\r\n </button>\r\n <button type=\"button\" mat-menu-item (click)=\"addSibling()\">\r\n <mat-icon>arrow_right_alt</mat-icon>\r\n add sibling\r\n </button>\r\n </mat-menu>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"accent\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"editNode()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n edit\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"warn\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"removeNode()\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n remove\r\n </button>\r\n\r\n @if (selectedNode()) {\r\n <span class=\"selected-info\"> selected: {{ selectedNode()!.label }} </span>\r\n }\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(); as nodeList) {\r\n <div>\r\n @for (node of nodeList; track node.id; let i = $index) {\r\n <div\r\n class=\"button-row\"\r\n [class.hilite]=\"node.hilite\"\r\n [class.selected]=\"selectedNode()?.id === node.id\"\r\n (click)=\"onNodeClick(node)\"\r\n >\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 < nodeList.length &&\r\n nodeList[i + 1].paging.pageCount > 1\r\n ? nodeList[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 </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: ["#container{padding:16px}.form-row{display:flex;align-items:center;gap:8px;margin-bottom:16px}.editing-actions{display:flex;align-items:center;gap:12px;margin-bottom:16px;padding:12px;border:1px solid #e0e0e0;border-radius:4px;background-color:#fafafa}.selected-info{margin-left:auto;font-style:italic;color:#666}.button-row{cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.button-row:hover{background-color:#f5f5f5}.button-row.selected{background-color:#e3f2fd;border:1px solid #2196f3}.button-row.hilite{background-color:#fff3e0}#tree{overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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.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: i6.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: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i8.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: ThesaurusPagedTreeFilterComponent, selector: "cadmus-thesaurus-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"] }] }); }
560
568
  }
561
569
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: EditableThesaurusBrowserComponent, decorators: [{
562
570
  type: Component,
563
571
  args: [{ selector: 'cadmus-editable-thesaurus-browser', imports: [
564
- AsyncPipe,
565
572
  ReactiveFormsModule,
566
573
  MatButtonModule,
567
574
  MatCheckboxModule,
@@ -573,8 +580,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
573
580
  MatTooltipModule,
574
581
  ThesaurusPagedTreeFilterComponent,
575
582
  BrowserTreeNodeComponent,
576
- ], template: "<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\">\r\n <fieldset>\r\n <legend>finder</legend>\r\n <div 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 {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <div class=\"form-row\" style=\"gap: 0\">\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </fieldset>\r\n </form>\r\n @if (hasRootFilter()) {\r\n <fieldset>\r\n <legend>global filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter$ | async\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </div>\r\n\r\n <!-- editing actions -->\r\n <div class=\"editing-actions\">\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"primary\"\r\n [disabled]=\"!selectedNode()\"\r\n [matMenuTriggerFor]=\"addMenu\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n add\r\n </button>\r\n\r\n <mat-menu #addMenu=\"matMenu\">\r\n <button type=\"button\" mat-menu-item (click)=\"addChild()\">\r\n <mat-icon>subdirectory_arrow_right</mat-icon>\r\n add child\r\n </button>\r\n <button type=\"button\" mat-menu-item (click)=\"addSibling()\">\r\n <mat-icon>arrow_right_alt</mat-icon>\r\n add sibling\r\n </button>\r\n </mat-menu>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"accent\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"editNode()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n edit\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"warn\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"removeNode()\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n remove\r\n </button>\r\n\r\n @if (selectedNode()) {\r\n <span class=\"selected-info\"> selected: {{ selectedNode()!.label }} </span>\r\n }\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\r\n class=\"button-row\"\r\n [class.hilite]=\"node.hilite\"\r\n [class.selected]=\"selectedNode()?.id === node.id\"\r\n (click)=\"onNodeClick(node)\"\r\n >\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 </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: ["#container{padding:16px}.form-row{display:flex;align-items:center;gap:8px;margin-bottom:16px}.editing-actions{display:flex;align-items:center;gap:12px;margin-bottom:16px;padding:12px;border:1px solid #e0e0e0;border-radius:4px;background-color:#fafafa}.selected-info{margin-left:auto;font-style:italic;color:#666}.button-row{cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.button-row:hover{background-color:#f5f5f5}.button-row.selected{background-color:#e3f2fd;border:1px solid #2196f3}.button-row.hilite{background-color:#fff3e0}#tree{overflow-y:auto}\n"] }]
577
- }], propDecorators: { service: [{ type: i0.Input, args: [{ isSignal: true, alias: "service", required: false }] }], hasRootFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasRootFilter", required: false }] }], nodePick: [{ type: i0.Output, args: ["nodePick"] }], changesStateChange: [{ type: i0.Output, args: ["changesStateChange"] }] } });
583
+ ], template: "<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\">\r\n <fieldset>\r\n <legend>finder</legend>\r\n <div 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 {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <div class=\"form-row\" style=\"gap: 0\">\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </fieldset>\r\n </form>\r\n @if (hasRootFilter()) {\r\n <fieldset>\r\n <legend>global filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter()\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </div>\r\n\r\n <!-- editing actions -->\r\n <div class=\"editing-actions\">\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"primary\"\r\n [disabled]=\"!selectedNode()\"\r\n [matMenuTriggerFor]=\"addMenu\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n add\r\n </button>\r\n\r\n <mat-menu #addMenu=\"matMenu\">\r\n <button type=\"button\" mat-menu-item (click)=\"addChild()\">\r\n <mat-icon>subdirectory_arrow_right</mat-icon>\r\n add child\r\n </button>\r\n <button type=\"button\" mat-menu-item (click)=\"addSibling()\">\r\n <mat-icon>arrow_right_alt</mat-icon>\r\n add sibling\r\n </button>\r\n </mat-menu>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"accent\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"editNode()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n edit\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"warn\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"removeNode()\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n remove\r\n </button>\r\n\r\n @if (selectedNode()) {\r\n <span class=\"selected-info\"> selected: {{ selectedNode()!.label }} </span>\r\n }\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(); as nodeList) {\r\n <div>\r\n @for (node of nodeList; track node.id; let i = $index) {\r\n <div\r\n class=\"button-row\"\r\n [class.hilite]=\"node.hilite\"\r\n [class.selected]=\"selectedNode()?.id === node.id\"\r\n (click)=\"onNodeClick(node)\"\r\n >\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 < nodeList.length &&\r\n nodeList[i + 1].paging.pageCount > 1\r\n ? nodeList[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 </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: ["#container{padding:16px}.form-row{display:flex;align-items:center;gap:8px;margin-bottom:16px}.editing-actions{display:flex;align-items:center;gap:12px;margin-bottom:16px;padding:12px;border:1px solid #e0e0e0;border-radius:4px;background-color:#fafafa}.selected-info{margin-left:auto;font-style:italic;color:#666}.button-row{cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.button-row:hover{background-color:#f5f5f5}.button-row.selected{background-color:#e3f2fd;border:1px solid #2196f3}.button-row.hilite{background-color:#fff3e0}#tree{overflow-y:auto}\n"] }]
584
+ }], ctorParameters: () => [], propDecorators: { service: [{ type: i0.Input, args: [{ isSignal: true, alias: "service", required: false }] }], hasRootFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasRootFilter", required: false }] }], nodePick: [{ type: i0.Output, args: ["nodePick"] }], changesStateChange: [{ type: i0.Output, args: ["changesStateChange"] }] } });
578
585
 
579
586
  /**
580
587
  * A label rendering function which removes from a label
@@ -759,12 +766,12 @@ class ThesaurusBrowserComponent {
759
766
  */
760
767
  this.store = computed(() => {
761
768
  const service = this.service();
762
- const store = new PagedTreeStore(service);
763
- this.nodes$ = store.nodes$;
764
- this.filter$ = store.filter$;
765
- return store;
769
+ return new PagedTreeStore(service);
766
770
  }, ...(ngDevMode ? [{ debugName: "store" }] : []));
767
771
  this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
772
+ // Signals for reactive data binding (replacing observables with async pipe)
773
+ this.nodes = signal([], ...(ngDevMode ? [{ debugName: "nodes" }] : []));
774
+ this.filter = signal({}, ...(ngDevMode ? [{ debugName: "filter" }] : []));
768
775
  this.debug = new FormControl(false, {
769
776
  nonNullable: true,
770
777
  });
@@ -778,23 +785,31 @@ class ThesaurusBrowserComponent {
778
785
  this.form = new FormGroup({
779
786
  label: this.label,
780
787
  });
781
- const store = this.store();
782
- this.nodes$ = store.nodes$;
783
- this.filter$ = store.filter$;
784
- }
785
- ngOnInit() {
786
- if (!this.store().getNodes().length) {
787
- this.loading.set(true);
788
- this.store()
789
- .setFilter({})
790
- .finally(() => {
791
- this.loading.set(false);
792
- console.log('nodes loaded', this.store().getNodes());
788
+ // Use effect to react to service/store changes
789
+ effect(() => {
790
+ const currentStore = this.store();
791
+ // Unsubscribe from previous store's observables
792
+ this._nodesSub?.unsubscribe();
793
+ this._filterSub?.unsubscribe();
794
+ // Subscribe to new store's observables and update signals
795
+ this._nodesSub = currentStore.nodes$.subscribe((nodes) => {
796
+ this.nodes.set(nodes);
793
797
  });
794
- }
798
+ this._filterSub = currentStore.filter$.subscribe((filter) => {
799
+ this.filter.set(filter);
800
+ });
801
+ // Load nodes if store is empty
802
+ if (!currentStore.getNodes().length) {
803
+ this.loading.set(true);
804
+ currentStore.setFilter({}).finally(() => {
805
+ this.loading.set(false);
806
+ });
807
+ }
808
+ });
795
809
  }
796
810
  ngOnDestroy() {
797
- this._sub?.unsubscribe();
811
+ this._nodesSub?.unsubscribe();
812
+ this._filterSub?.unsubscribe();
798
813
  }
799
814
  reset() {
800
815
  this.loading.set(true);
@@ -878,12 +893,11 @@ class ThesaurusBrowserComponent {
878
893
  this.store().removeHilites();
879
894
  }
880
895
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ThesaurusBrowserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
881
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: ThesaurusBrowserComponent, isStandalone: true, selector: "cadmus-thesaurus-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\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thesaurus-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.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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.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: i6.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: i8.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: ThesaurusPagedTreeFilterComponent, selector: "cadmus-thesaurus-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" }] }); }
896
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: ThesaurusBrowserComponent, isStandalone: true, selector: "cadmus-thesaurus-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\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter()\"\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(); as nodeList) {\r\n <div>\r\n @for (node of nodeList; 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 < nodeList.length &&\r\n nodeList[i + 1].paging.pageCount > 1\r\n ? nodeList[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.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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.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: i6.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: i8.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: ThesaurusPagedTreeFilterComponent, selector: "cadmus-thesaurus-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"] }] }); }
882
897
  }
883
898
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ThesaurusBrowserComponent, decorators: [{
884
899
  type: Component,
885
900
  args: [{ selector: 'cadmus-thesaurus-browser', imports: [
886
- AsyncPipe,
887
901
  ReactiveFormsModule,
888
902
  MatButtonModule,
889
903
  MatCheckboxModule,
@@ -894,7 +908,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
894
908
  MatTooltipModule,
895
909
  ThesaurusPagedTreeFilterComponent,
896
910
  BrowserTreeNodeComponent,
897
- ], 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\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thesaurus-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"] }]
911
+ ], 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\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter()\"\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(); as nodeList) {\r\n <div>\r\n @for (node of nodeList; 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 < nodeList.length &&\r\n nodeList[i + 1].paging.pageCount > 1\r\n ? nodeList[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"] }]
898
912
  }], ctorParameters: () => [], propDecorators: { service: [{ type: i0.Input, args: [{ isSignal: true, alias: "service", required: false }] }], nodePick: [{ type: i0.Output, args: ["nodePick"] }] } });
899
913
 
900
914
  /**
@@ -1119,7 +1133,7 @@ class ThesaurusEntriesPickerComponent {
1119
1133
  this.entries.set(entries);
1120
1134
  }
1121
1135
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ThesaurusEntriesPickerComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
1122
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: ThesaurusEntriesPickerComponent, isStandalone: true, selector: "cadmus-thesaurus-entries-picker", inputs: { availableEntries: { classPropertyName: "availableEntries", publicName: "availableEntries", isSignal: true, isRequired: true, transformFunction: null }, entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, hierarchicLabels: { classPropertyName: "hierarchicLabels", publicName: "hierarchicLabels", isSignal: true, isRequired: false, transformFunction: null }, autoSort: { classPropertyName: "autoSort", publicName: "autoSort", isSignal: true, isRequired: false, transformFunction: null }, allowCustom: { classPropertyName: "allowCustom", publicName: "allowCustom", isSignal: true, isRequired: false, transformFunction: null }, minEntries: { classPropertyName: "minEntries", publicName: "minEntries", isSignal: true, isRequired: false, transformFunction: null }, maxEntries: { classPropertyName: "maxEntries", publicName: "maxEntries", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entries: "entriesChange", expanded: "expandedChange" }, ngImport: i0, template: "<div id=\"container\">\r\n <!-- picked entries -->\r\n <div id=\"picked\" class=\"form-row\">\r\n <!-- count -->\r\n <span class=\"nr\" [class.error]=\"entries().length < minEntries()\">{{\r\n entries().length\r\n }}</span>\r\n <!-- max-->\r\n @if (maxEntries() > 1) {\r\n <span class=\"muted\">/{{ maxEntries() }}</span>\r\n @if (remaining()) {\r\n <span class=\"muted\">: -{{ remaining() }}</span>\r\n } }\r\n <!-- min -->\r\n @if (minEntries()) {\r\n <!-- min with error -->\r\n @if (entries().length < minEntries()) {\r\n <span class=\"error\"> (min {{ minEntries() }})</span>\r\n }\r\n <!-- min without error -->\r\n @else {\r\n <span class=\"muted\"> (min {{ minEntries() }})</span>\r\n } }\r\n <!-- list -->\r\n <mat-chip-listbox\r\n [cdkDropListDisabled]=\"autoSort()\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n class=\"chip-list\"\r\n >\r\n @for (e of entries(); track e.id; let idx = $index) {\r\n <div class=\"chip-wrapper\">\r\n <mat-chip-option\r\n [cdkDragDisabled]=\"autoSort()\"\r\n cdkDrag\r\n [class.error]=\"!allowCustom() && e.id.startsWith('$')\"\r\n >\r\n {{ renderLabel(e.value) }}\r\n <button\r\n type=\"button\"\r\n matChipRemove\r\n (click)=\"removeEntry(e)\"\r\n aria-label=\"Remove entry\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-chip-option>\r\n </div>\r\n } @empty {\r\n <span class=\"muted empty-message\">{{ emptyMessage() }}</span>\r\n }\r\n </mat-chip-listbox>\r\n\r\n <!-- clear -->\r\n @if (entries().length > 0) {\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove all entries\"\r\n (click)=\"clear()\"\r\n [disabled]=\"entries().length === 0\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n }\r\n <!-- toggler -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Toggle picker\"\r\n (click)=\"expanded.set(!expanded())\"\r\n >\r\n @if (expanded()) {\r\n <mat-icon class=\"mat-primary\">publish</mat-icon>\r\n } @if (!expanded()) {\r\n <mat-icon class=\"mat-primary\">get_app</mat-icon>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- entries picker -->\r\n <div id=\"picker\">\r\n <mat-expansion-panel\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"expanded.set($event)\"\r\n >\r\n <div>\r\n <fieldset>\r\n <legend>available</legend>\r\n <cadmus-thesaurus-tree\r\n [entries]=\"availableEntries()\"\r\n [renderLabel]=\"renderLabel\"\r\n (entryChange)=\"onEntryChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n @if (allowCustom()) {\r\n <div>\r\n <form [formGroup]=\"form\" (submit)=\"addCustomEntry()\">\r\n <fieldset>\r\n <legend>custom</legend>\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"id\"\r\n placeholder=\"ID\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"value\"\r\n placeholder=\"label\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Add custom entry\"\r\n [disabled]=\"\r\n !form.valid ||\r\n (maxEntries() > 0 && entries().length >= maxEntries())\r\n \"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n </div>\r\n }\r\n </mat-expansion-panel>\r\n </div>\r\n</div>\r\n", styles: ["#container{width:100%}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.error{color:#8b0000}.nr{font-weight:700}.muted{color:gray}fieldset{border:1px solid silver;border-radius:8px;padding:8px 16px}.chip-list{display:flex;flex-wrap:wrap;gap:4px;align-items:center;padding:4px}.chip-wrapper{display:inline-flex;position:relative;margin:2px}.chip-list mat-chip-option:not([cdkDragDisabled]){cursor:grab}.chip-list mat-chip-option:not([cdkDragDisabled]):active{cursor:grabbing}.chip-list mat-chip-option[cdkDragDisabled]{cursor:default}.chip-list .empty-message{margin-left:0}.chip-list mat-chip-option.mat-mdc-chip-selected{background-color:inherit}.chip-list mat-chip-option:not(.error).mat-mdc-chip-selected{background-color:#e0e0e0}mat-chip-option.error{background-color:#ffebee!important;border:1px solid darkred}.cdk-drag-preview{opacity:.95;box-shadow:0 8px 20px #0006;transform:rotate(3deg)}.drag-placeholder{width:4px;background:#1976d2;border-radius:2px;height:36px;box-shadow:0 0 8px #1976d299;animation:pulse .5s ease-in-out infinite}@keyframes pulse{0%,to{opacity:.6;transform:scaleY(1)}50%{opacity:1;transform:scaleY(1.1)}}.chip-list .cdk-drag-placeholder{opacity:0;width:4px;min-width:4px}.chip-wrapper{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper{will-change:transform}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "directive", type: MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ThesaurusTreeComponent, selector: "cadmus-thesaurus-tree", inputs: ["entries", "renderLabel"], outputs: ["entryChange"] }] }); }
1136
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: ThesaurusEntriesPickerComponent, isStandalone: true, selector: "cadmus-thesaurus-entries-picker", inputs: { availableEntries: { classPropertyName: "availableEntries", publicName: "availableEntries", isSignal: true, isRequired: true, transformFunction: null }, entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, hierarchicLabels: { classPropertyName: "hierarchicLabels", publicName: "hierarchicLabels", isSignal: true, isRequired: false, transformFunction: null }, autoSort: { classPropertyName: "autoSort", publicName: "autoSort", isSignal: true, isRequired: false, transformFunction: null }, allowCustom: { classPropertyName: "allowCustom", publicName: "allowCustom", isSignal: true, isRequired: false, transformFunction: null }, minEntries: { classPropertyName: "minEntries", publicName: "minEntries", isSignal: true, isRequired: false, transformFunction: null }, maxEntries: { classPropertyName: "maxEntries", publicName: "maxEntries", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entries: "entriesChange", expanded: "expandedChange" }, ngImport: i0, template: "<div id=\"container\">\r\n <!-- picked entries -->\r\n <div id=\"picked\" class=\"form-row\">\r\n <!-- count -->\r\n <span class=\"nr\" [class.error]=\"entries().length < minEntries()\">{{\r\n entries().length\r\n }}</span>\r\n <!-- max-->\r\n @if (maxEntries() > 1) {\r\n <span class=\"muted\">/{{ maxEntries() }}</span>\r\n @if (remaining()) {\r\n <span class=\"muted\">: -{{ remaining() }}</span>\r\n } }\r\n <!-- min -->\r\n @if (minEntries()) {\r\n <!-- min with error -->\r\n @if (entries().length < minEntries()) {\r\n <span class=\"error\"> (min {{ minEntries() }})</span>\r\n }\r\n <!-- min without error -->\r\n @else {\r\n <span class=\"muted\"> (min {{ minEntries() }})</span>\r\n } }\r\n <!-- list -->\r\n <mat-chip-listbox\r\n [cdkDropListDisabled]=\"autoSort()\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n class=\"chip-list\"\r\n >\r\n @for (e of entries(); track e.id; let idx = $index) {\r\n <div class=\"chip-wrapper\">\r\n <mat-chip-option\r\n [cdkDragDisabled]=\"autoSort()\"\r\n cdkDrag\r\n [class.error]=\"!allowCustom() && e.id.startsWith('$')\"\r\n >\r\n {{ renderLabel(e.value) }}\r\n <button\r\n type=\"button\"\r\n matChipRemove\r\n (click)=\"removeEntry(e)\"\r\n aria-label=\"Remove entry\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-chip-option>\r\n </div>\r\n } @empty {\r\n <span class=\"muted empty-message\">{{ emptyMessage() }}</span>\r\n }\r\n </mat-chip-listbox>\r\n\r\n <!-- clear -->\r\n @if (entries().length > 0) {\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove all entries\"\r\n (click)=\"clear()\"\r\n [disabled]=\"entries().length === 0\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n }\r\n <!-- toggler -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Toggle picker\"\r\n (click)=\"expanded.set(!expanded())\"\r\n >\r\n @if (expanded()) {\r\n <mat-icon class=\"mat-primary\">publish</mat-icon>\r\n } @if (!expanded()) {\r\n <mat-icon class=\"mat-primary\">get_app</mat-icon>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- entries picker -->\r\n <div id=\"picker\">\r\n <mat-expansion-panel\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"expanded.set($event)\"\r\n >\r\n <div>\r\n <fieldset>\r\n <legend>available</legend>\r\n <cadmus-thesaurus-tree\r\n [entries]=\"availableEntries()\"\r\n [renderLabel]=\"renderLabel\"\r\n (entryChange)=\"onEntryChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n @if (allowCustom()) {\r\n <div>\r\n <form [formGroup]=\"form\" (submit)=\"addCustomEntry()\">\r\n <fieldset>\r\n <legend>custom</legend>\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"id\"\r\n placeholder=\"ID\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"value\"\r\n placeholder=\"label\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Add custom entry\"\r\n [disabled]=\"\r\n !form.valid ||\r\n (maxEntries() > 0 && entries().length >= maxEntries())\r\n \"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n </div>\r\n }\r\n </mat-expansion-panel>\r\n </div>\r\n</div>\r\n", styles: ["#container{width:100%}#picked{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-start;width:100%}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.error{color:#8b0000}.nr{font-weight:700}.muted{color:gray}fieldset{border:1px solid silver;border-radius:8px;padding:8px 16px}.chip-list{flex:1 1 100%;min-width:0;width:100%}.chip-wrapper{display:inline-flex;position:relative;margin:2px}.chip-list mat-chip-option:not([cdkDragDisabled]){cursor:grab}.chip-list mat-chip-option:not([cdkDragDisabled]):active{cursor:grabbing}.chip-list mat-chip-option[cdkDragDisabled]{cursor:default}.chip-list .empty-message{margin-left:0}.chip-list mat-chip-option.mat-mdc-chip-selected{background-color:inherit}.chip-list mat-chip-option:not(.error).mat-mdc-chip-selected{background-color:#e0e0e0}mat-chip-option.error{background-color:#ffebee!important;border:1px solid darkred}.cdk-drag-preview{opacity:.95;box-shadow:0 8px 20px #0006;transform:rotate(3deg)}.drag-placeholder{width:4px;background:#1976d2;border-radius:2px;height:36px;box-shadow:0 0 8px #1976d299;animation:pulse .5s ease-in-out infinite}@keyframes pulse{0%,to{opacity:.6;transform:scaleY(1)}50%{opacity:1;transform:scaleY(1.1)}}.chip-list .cdk-drag-placeholder{opacity:0;width:4px;min-width:4px}.chip-wrapper{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper{will-change:transform}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "directive", type: MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ThesaurusTreeComponent, selector: "cadmus-thesaurus-tree", inputs: ["entries", "renderLabel"], outputs: ["entryChange"] }] }); }
1123
1137
  }
1124
1138
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ThesaurusEntriesPickerComponent, decorators: [{
1125
1139
  type: Component,
@@ -1137,7 +1151,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
1137
1151
  MatInput,
1138
1152
  MatTooltip,
1139
1153
  ThesaurusTreeComponent,
1140
- ], template: "<div id=\"container\">\r\n <!-- picked entries -->\r\n <div id=\"picked\" class=\"form-row\">\r\n <!-- count -->\r\n <span class=\"nr\" [class.error]=\"entries().length < minEntries()\">{{\r\n entries().length\r\n }}</span>\r\n <!-- max-->\r\n @if (maxEntries() > 1) {\r\n <span class=\"muted\">/{{ maxEntries() }}</span>\r\n @if (remaining()) {\r\n <span class=\"muted\">: -{{ remaining() }}</span>\r\n } }\r\n <!-- min -->\r\n @if (minEntries()) {\r\n <!-- min with error -->\r\n @if (entries().length < minEntries()) {\r\n <span class=\"error\"> (min {{ minEntries() }})</span>\r\n }\r\n <!-- min without error -->\r\n @else {\r\n <span class=\"muted\"> (min {{ minEntries() }})</span>\r\n } }\r\n <!-- list -->\r\n <mat-chip-listbox\r\n [cdkDropListDisabled]=\"autoSort()\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n class=\"chip-list\"\r\n >\r\n @for (e of entries(); track e.id; let idx = $index) {\r\n <div class=\"chip-wrapper\">\r\n <mat-chip-option\r\n [cdkDragDisabled]=\"autoSort()\"\r\n cdkDrag\r\n [class.error]=\"!allowCustom() && e.id.startsWith('$')\"\r\n >\r\n {{ renderLabel(e.value) }}\r\n <button\r\n type=\"button\"\r\n matChipRemove\r\n (click)=\"removeEntry(e)\"\r\n aria-label=\"Remove entry\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-chip-option>\r\n </div>\r\n } @empty {\r\n <span class=\"muted empty-message\">{{ emptyMessage() }}</span>\r\n }\r\n </mat-chip-listbox>\r\n\r\n <!-- clear -->\r\n @if (entries().length > 0) {\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove all entries\"\r\n (click)=\"clear()\"\r\n [disabled]=\"entries().length === 0\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n }\r\n <!-- toggler -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Toggle picker\"\r\n (click)=\"expanded.set(!expanded())\"\r\n >\r\n @if (expanded()) {\r\n <mat-icon class=\"mat-primary\">publish</mat-icon>\r\n } @if (!expanded()) {\r\n <mat-icon class=\"mat-primary\">get_app</mat-icon>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- entries picker -->\r\n <div id=\"picker\">\r\n <mat-expansion-panel\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"expanded.set($event)\"\r\n >\r\n <div>\r\n <fieldset>\r\n <legend>available</legend>\r\n <cadmus-thesaurus-tree\r\n [entries]=\"availableEntries()\"\r\n [renderLabel]=\"renderLabel\"\r\n (entryChange)=\"onEntryChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n @if (allowCustom()) {\r\n <div>\r\n <form [formGroup]=\"form\" (submit)=\"addCustomEntry()\">\r\n <fieldset>\r\n <legend>custom</legend>\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"id\"\r\n placeholder=\"ID\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"value\"\r\n placeholder=\"label\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Add custom entry\"\r\n [disabled]=\"\r\n !form.valid ||\r\n (maxEntries() > 0 && entries().length >= maxEntries())\r\n \"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n </div>\r\n }\r\n </mat-expansion-panel>\r\n </div>\r\n</div>\r\n", styles: ["#container{width:100%}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.error{color:#8b0000}.nr{font-weight:700}.muted{color:gray}fieldset{border:1px solid silver;border-radius:8px;padding:8px 16px}.chip-list{display:flex;flex-wrap:wrap;gap:4px;align-items:center;padding:4px}.chip-wrapper{display:inline-flex;position:relative;margin:2px}.chip-list mat-chip-option:not([cdkDragDisabled]){cursor:grab}.chip-list mat-chip-option:not([cdkDragDisabled]):active{cursor:grabbing}.chip-list mat-chip-option[cdkDragDisabled]{cursor:default}.chip-list .empty-message{margin-left:0}.chip-list mat-chip-option.mat-mdc-chip-selected{background-color:inherit}.chip-list mat-chip-option:not(.error).mat-mdc-chip-selected{background-color:#e0e0e0}mat-chip-option.error{background-color:#ffebee!important;border:1px solid darkred}.cdk-drag-preview{opacity:.95;box-shadow:0 8px 20px #0006;transform:rotate(3deg)}.drag-placeholder{width:4px;background:#1976d2;border-radius:2px;height:36px;box-shadow:0 0 8px #1976d299;animation:pulse .5s ease-in-out infinite}@keyframes pulse{0%,to{opacity:.6;transform:scaleY(1)}50%{opacity:1;transform:scaleY(1.1)}}.chip-list .cdk-drag-placeholder{opacity:0;width:4px;min-width:4px}.chip-wrapper{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper{will-change:transform}\n"] }]
1154
+ ], template: "<div id=\"container\">\r\n <!-- picked entries -->\r\n <div id=\"picked\" class=\"form-row\">\r\n <!-- count -->\r\n <span class=\"nr\" [class.error]=\"entries().length < minEntries()\">{{\r\n entries().length\r\n }}</span>\r\n <!-- max-->\r\n @if (maxEntries() > 1) {\r\n <span class=\"muted\">/{{ maxEntries() }}</span>\r\n @if (remaining()) {\r\n <span class=\"muted\">: -{{ remaining() }}</span>\r\n } }\r\n <!-- min -->\r\n @if (minEntries()) {\r\n <!-- min with error -->\r\n @if (entries().length < minEntries()) {\r\n <span class=\"error\"> (min {{ minEntries() }})</span>\r\n }\r\n <!-- min without error -->\r\n @else {\r\n <span class=\"muted\"> (min {{ minEntries() }})</span>\r\n } }\r\n <!-- list -->\r\n <mat-chip-listbox\r\n [cdkDropListDisabled]=\"autoSort()\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n class=\"chip-list\"\r\n >\r\n @for (e of entries(); track e.id; let idx = $index) {\r\n <div class=\"chip-wrapper\">\r\n <mat-chip-option\r\n [cdkDragDisabled]=\"autoSort()\"\r\n cdkDrag\r\n [class.error]=\"!allowCustom() && e.id.startsWith('$')\"\r\n >\r\n {{ renderLabel(e.value) }}\r\n <button\r\n type=\"button\"\r\n matChipRemove\r\n (click)=\"removeEntry(e)\"\r\n aria-label=\"Remove entry\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-chip-option>\r\n </div>\r\n } @empty {\r\n <span class=\"muted empty-message\">{{ emptyMessage() }}</span>\r\n }\r\n </mat-chip-listbox>\r\n\r\n <!-- clear -->\r\n @if (entries().length > 0) {\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove all entries\"\r\n (click)=\"clear()\"\r\n [disabled]=\"entries().length === 0\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n }\r\n <!-- toggler -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Toggle picker\"\r\n (click)=\"expanded.set(!expanded())\"\r\n >\r\n @if (expanded()) {\r\n <mat-icon class=\"mat-primary\">publish</mat-icon>\r\n } @if (!expanded()) {\r\n <mat-icon class=\"mat-primary\">get_app</mat-icon>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- entries picker -->\r\n <div id=\"picker\">\r\n <mat-expansion-panel\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"expanded.set($event)\"\r\n >\r\n <div>\r\n <fieldset>\r\n <legend>available</legend>\r\n <cadmus-thesaurus-tree\r\n [entries]=\"availableEntries()\"\r\n [renderLabel]=\"renderLabel\"\r\n (entryChange)=\"onEntryChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n @if (allowCustom()) {\r\n <div>\r\n <form [formGroup]=\"form\" (submit)=\"addCustomEntry()\">\r\n <fieldset>\r\n <legend>custom</legend>\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"id\"\r\n placeholder=\"ID\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"value\"\r\n placeholder=\"label\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Add custom entry\"\r\n [disabled]=\"\r\n !form.valid ||\r\n (maxEntries() > 0 && entries().length >= maxEntries())\r\n \"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n </div>\r\n }\r\n </mat-expansion-panel>\r\n </div>\r\n</div>\r\n", styles: ["#container{width:100%}#picked{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-start;width:100%}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.error{color:#8b0000}.nr{font-weight:700}.muted{color:gray}fieldset{border:1px solid silver;border-radius:8px;padding:8px 16px}.chip-list{flex:1 1 100%;min-width:0;width:100%}.chip-wrapper{display:inline-flex;position:relative;margin:2px}.chip-list mat-chip-option:not([cdkDragDisabled]){cursor:grab}.chip-list mat-chip-option:not([cdkDragDisabled]):active{cursor:grabbing}.chip-list mat-chip-option[cdkDragDisabled]{cursor:default}.chip-list .empty-message{margin-left:0}.chip-list mat-chip-option.mat-mdc-chip-selected{background-color:inherit}.chip-list mat-chip-option:not(.error).mat-mdc-chip-selected{background-color:#e0e0e0}mat-chip-option.error{background-color:#ffebee!important;border:1px solid darkred}.cdk-drag-preview{opacity:.95;box-shadow:0 8px 20px #0006;transform:rotate(3deg)}.drag-placeholder{width:4px;background:#1976d2;border-radius:2px;height:36px;box-shadow:0 0 8px #1976d299;animation:pulse .5s ease-in-out infinite}@keyframes pulse{0%,to{opacity:.6;transform:scaleY(1)}50%{opacity:1;transform:scaleY(1.1)}}.chip-list .cdk-drag-placeholder{opacity:0;width:4px;min-width:4px}.chip-wrapper{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .chip-wrapper{will-change:transform}\n"] }]
1141
1155
  }], ctorParameters: () => [{ type: i1.FormBuilder }], propDecorators: { availableEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "availableEntries", required: true }] }], entries: [{ type: i0.Input, args: [{ isSignal: true, alias: "entries", required: false }] }, { type: i0.Output, args: ["entriesChange"] }], hierarchicLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "hierarchicLabels", required: false }] }], autoSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoSort", required: false }] }], allowCustom: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCustom", required: false }] }], minEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "minEntries", required: false }] }], maxEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxEntries", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }] } });
1142
1156
 
1143
1157
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"myrmidon-cadmus-thesaurus-store.mjs","sources":["../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entry-editor/thesaurus-entry-editor.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entry-editor/thesaurus-entry-editor.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/editable-thesaurus-browser/editable-thesaurus-browser.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/editable-thesaurus-browser/editable-thesaurus-browser.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/services/static-thesaurus-paged-tree-store.service.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-browser/thesaurus-browser.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-browser/thesaurus-browser.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-tree/thesaurus-tree.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-tree/thesaurus-tree.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entries-picker/thesaurus-entries-picker.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entries-picker/thesaurus-entries-picker.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/services/editable-static-thesaurus-paged-tree-store.service.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/public-api.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/myrmidon-cadmus-thesaurus-store.ts"],"sourcesContent":["import {\r\n Component,\r\n effect,\r\n inject,\r\n model,\r\n OnInit,\r\n signal,\r\n} from '@angular/core';\r\nimport {\r\n FormBuilder,\r\n FormControl,\r\n FormGroup,\r\n ReactiveFormsModule,\r\n} from '@angular/forms';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\n\r\nimport { ThesaurusEntryNodeFilter } from '../../services/static-thesaurus-paged-tree-store.service';\r\n\r\n/**\r\n * A filter to be used for thesaurus paged tree browsers.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-paged-tree-filter',\r\n imports: [\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatFormFieldModule,\r\n MatInputModule,\r\n MatIconModule,\r\n MatTooltipModule,\r\n ],\r\n templateUrl: './thesaurus-paged-tree-filter.component.html',\r\n styleUrl: './thesaurus-paged-tree-filter.component.css',\r\n})\r\nexport class ThesaurusPagedTreeFilterComponent implements OnInit {\r\n public readonly dialogRef = inject<\r\n MatDialogRef<ThesaurusPagedTreeFilterComponent>\r\n >(MatDialogRef, {\r\n optional: true,\r\n });\r\n public readonly data = inject(MAT_DIALOG_DATA, { optional: true });\r\n\r\n /**\r\n * The filter.\r\n */\r\n public readonly filter = model<ThesaurusEntryNodeFilter | null | undefined>();\r\n\r\n public readonly wrapped = signal<boolean>(false);\r\n\r\n public label: FormControl<string | null>;\r\n public form: FormGroup;\r\n\r\n constructor() {\r\n const formBuilder = inject(FormBuilder);\r\n const data = this.data;\r\n\r\n // form\r\n this.label = formBuilder.control<string | null>(null);\r\n this.form = formBuilder.group({\r\n label: this.label,\r\n });\r\n // bind dialog data if any\r\n if (this.dialogRef) {\r\n this.wrapped.set(true);\r\n if (data) {\r\n this.filter.set(data.filter);\r\n }\r\n } else {\r\n this.wrapped.set(false);\r\n }\r\n\r\n // update form when filter changes\r\n effect(() => {\r\n this.updateForm(this.filter());\r\n });\r\n }\r\n\r\n public ngOnInit(): void {\r\n this.updateForm(this.filter());\r\n }\r\n\r\n private updateForm(filter?: ThesaurusEntryNodeFilter | null): void {\r\n if (!filter) {\r\n this.form.reset();\r\n return;\r\n }\r\n this.label.setValue(filter.label ?? null);\r\n this.form.markAsPristine();\r\n }\r\n\r\n private getFilter(): ThesaurusEntryNodeFilter {\r\n return {\r\n label: this.label.value ?? undefined,\r\n };\r\n }\r\n\r\n public reset(): void {\r\n this.form.reset();\r\n this.filter.set(null);\r\n this.dialogRef?.close(null);\r\n }\r\n\r\n public apply(): void {\r\n const filter = this.getFilter();\r\n this.filter.set(filter);\r\n this.dialogRef?.close(filter);\r\n }\r\n}\r\n","<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\r\n <!-- buttons -->\r\n <div class=\"button-row\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Reset\"\r\n (click)=\"reset()\"\r\n >\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 </div>\r\n</form>\r\n","import { Component, Inject, input, model, Optional } from '@angular/core';\r\nimport {\r\n FormBuilder,\r\n FormControl,\r\n FormGroup,\r\n ReactiveFormsModule,\r\n Validators,\r\n AbstractControl,\r\n ValidationErrors,\r\n} from '@angular/forms';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport {\r\n MatDialogRef,\r\n MAT_DIALOG_DATA,\r\n MatDialogConfig,\r\n} from '@angular/material/dialog';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\n\r\n/**\r\n * An edited thesaurus entry.\r\n */\r\nexport interface EditedThesEntry {\r\n id: string;\r\n value: string;\r\n /**\r\n * True if this entry belongs to a hierarchical thesaurus. When this is true,\r\n * and parentId is set, the parentId field will be used as the prefix for the\r\n * id field when creating a new entry.\r\n */\r\n hierarchical?: boolean;\r\n /**\r\n * The ID of the parent entry, if any.\r\n */\r\n parentId?: string;\r\n /**\r\n * If true, the id field is read-only. This is used when editing an existing\r\n * entry so you cannot change its ID.\r\n */\r\n idLocked?: boolean;\r\n /**\r\n * Function used to check if the given ID exists. This is used when\r\n * creating a new entry to ensure it does not duplicate an existing ID.\r\n * @param id The ID to check.\r\n * @returns True if exists.\r\n */\r\n idExists?: (id: string) => boolean;\r\n}\r\n\r\nexport interface PayloadMatDialogConfig<T> extends MatDialogConfig {\r\n payload?: T;\r\n}\r\n\r\n/**\r\n * A dialog component to edit a thesaurus entry.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-entry-editor',\r\n imports: [\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatTooltipModule,\r\n ],\r\n templateUrl: './thesaurus-entry-editor.component.html',\r\n styleUrl: './thesaurus-entry-editor.component.scss',\r\n})\r\nexport class ThesEntryEditorComponent {\r\n public readonly entry = model<EditedThesEntry | undefined>();\r\n public wrapped = false;\r\n\r\n public id: FormControl<string>;\r\n public value: FormControl<string>;\r\n public form: FormGroup;\r\n\r\n constructor(\r\n @Optional()\r\n public dialogRef: MatDialogRef<ThesEntryEditorComponent>,\r\n @Optional()\r\n @Inject(MAT_DIALOG_DATA)\r\n public data: PayloadMatDialogConfig<EditedThesEntry>,\r\n formBuilder: FormBuilder\r\n ) {\r\n // bind to data properties if any\r\n if (data) {\r\n this.entry.set(data as EditedThesEntry);\r\n this.wrapped = true;\r\n }\r\n\r\n // custom validator for ID existence\r\n const idExistsValidator = (\r\n control: AbstractControl\r\n ): ValidationErrors | null => {\r\n const entry = this.entry();\r\n if (!entry || entry.idLocked || !entry.idExists) {\r\n return null;\r\n }\r\n const id = control.value?.trim();\r\n if (!id) {\r\n return null;\r\n }\r\n // if editing, allow the current id (do not check against itself)\r\n if (entry.id === id) {\r\n return null;\r\n }\r\n return entry.idExists(id) ? { idExists: true } : null;\r\n };\r\n\r\n // custom validator for hierarchical ID prefix\r\n const hierarchicalIdValidator = (\r\n control: AbstractControl\r\n ): ValidationErrors | null => {\r\n const entry = this.entry();\r\n if (!entry || entry.idLocked || !entry.hierarchical || !entry.parentId) {\r\n return null;\r\n }\r\n const id = control.value?.trim();\r\n if (!id) {\r\n return null;\r\n }\r\n const prefix = entry.parentId + '.';\r\n if (!id.startsWith(prefix) || id.length <= prefix.length) {\r\n return { hierarchicalPrefix: { requiredPrefix: prefix } };\r\n }\r\n return null;\r\n };\r\n\r\n // form controls\r\n this.id = new FormControl<string>((data as EditedThesEntry)?.id || '', {\r\n nonNullable: true,\r\n validators: [\r\n Validators.required,\r\n Validators.maxLength(300),\r\n idExistsValidator,\r\n hierarchicalIdValidator,\r\n ],\r\n });\r\n this.value = new FormControl<string>(\r\n (data as EditedThesEntry)?.value || '',\r\n {\r\n nonNullable: true,\r\n validators: [Validators.required, Validators.maxLength(500)],\r\n }\r\n );\r\n this.form = formBuilder.group({\r\n id: this.id,\r\n value: this.value,\r\n });\r\n }\r\n\r\n cancel(): void {\r\n this.dialogRef?.close();\r\n }\r\n\r\n save(): void {\r\n if (this.form.invalid) {\r\n return;\r\n }\r\n const old = this.entry()!;\r\n\r\n // save data and close the dialog\r\n this.dialogRef?.close({\r\n id: old.idLocked ? old.id : this.id.value?.trim(),\r\n value: this.value.value?.trim(),\r\n } as EditedThesEntry);\r\n }\r\n}\r\n","<form [formGroup]=\"form\" (submit)=\"save()\" [class.wrapped]=\"wrapped\">\r\n <fieldset>\r\n <legend>entry</legend>\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n @if (entry()!.idLocked) {\r\n <span class=\"readonly\">{{ entry()!.id }}</span>\r\n } @else {\r\n <mat-form-field>\r\n <mat-label>ID</mat-label>\r\n <input matInput [formControl]=\"id\" />\r\n @if ($any(id).errors?.required && (id.dirty || id.touched)) {\r\n <mat-error>ID required</mat-error>\r\n } @if ($any(id).errors?.maxLength && (id.dirty || id.touched)) {\r\n <mat-error>ID too long</mat-error>\r\n } @if ($any(id).errors?.idExists && (id.dirty || id.touched)) {\r\n <mat-error>ID already exists</mat-error>\r\n } @if ($any(id).errors?.requiredPrefix && (id.dirty || id.touched)) {\r\n <mat-error>ID must start with \"{{ entry()!.parentId }}.\"</mat-error>\r\n }\r\n <!-- hint -->\r\n @if (entry()?.parentId) {\r\n <mat-hint>parent: {{ entry()!.parentId }}</mat-hint>\r\n }\r\n </mat-form-field>\r\n }\r\n <!-- value -->\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n @if ($any(value).errors?.required && (value.dirty || value.touched)) {\r\n <mat-error>value required</mat-error>\r\n } @if ($any(value).errors?.maxLength && (value.dirty || value.touched))\r\n {\r\n <mat-error>value too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"cancel()\"\r\n >\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=\"Accept changes\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n</form>\r\n","import {\r\n Component,\r\n OnDestroy,\r\n OnInit,\r\n computed,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { AsyncPipe } from '@angular/common';\r\nimport { Observable, Subscription, of } from 'rxjs';\r\n\r\nimport { MatDialog } from '@angular/material/dialog';\r\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatCheckboxModule } from '@angular/material/checkbox';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatSnackBar } from '@angular/material/snack-bar';\r\n\r\nimport { DialogService } from '@myrmidon/ngx-mat-tools';\r\nimport {\r\n BrowserTreeNodeComponent,\r\n PagedTreeStore,\r\n PageChangeRequest,\r\n} from '@myrmidon/paged-data-browsers';\r\n\r\nimport { ThesaurusPagedTreeFilterComponent } from '../thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\nimport {\r\n ThesaurusEntryNodeFilter,\r\n ThesaurusEntryPagedTreeNode,\r\n} from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport {\r\n EditedThesEntry,\r\n ThesEntryEditorComponent,\r\n} from '../thesaurus-entry-editor/thesaurus-entry-editor.component';\r\nimport { EditableStaticThesaurusPagedTreeStoreService } from '../../services/editable-static-thesaurus-paged-tree-store.service';\r\n\r\n/**\r\n * An editable paged tree browser for thesaurus entries. Editing happens in memory\r\n * and when complete, the changes can be committed to the underlying data store\r\n * via the EditableStaticThesaurusPagedTreeStoreService.\r\n */\r\n@Component({\r\n selector: 'cadmus-editable-thesaurus-browser',\r\n imports: [\r\n AsyncPipe,\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatCheckboxModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatMenuModule,\r\n MatProgressBarModule,\r\n MatTooltipModule,\r\n ThesaurusPagedTreeFilterComponent,\r\n BrowserTreeNodeComponent,\r\n ],\r\n templateUrl: './editable-thesaurus-browser.component.html',\r\n styleUrls: ['./editable-thesaurus-browser.component.scss'],\r\n})\r\nexport class EditableThesaurusBrowserComponent implements OnInit, OnDestroy {\r\n private _dialog = inject(MatDialog);\r\n private _snackBar = inject(MatSnackBar);\r\n private _dialogService = inject(DialogService);\r\n private _sub?: Subscription;\r\n\r\n /**\r\n * The editable service to use to load the nodes.\r\n */\r\n public readonly service =\r\n input<EditableStaticThesaurusPagedTreeStoreService>();\r\n\r\n /**\r\n * True to show the tree root nodes filter.\r\n */\r\n public readonly hasRootFilter = input<boolean>(false);\r\n\r\n /**\r\n * Emitted when a node is clicked.\r\n */\r\n public readonly nodePick = output<ThesaurusEntryPagedTreeNode>();\r\n\r\n /**\r\n * Emitted when the changes state changes.\r\n */\r\n public readonly changesStateChange = output<boolean>();\r\n\r\n /**\r\n * The store instance, built from the service.\r\n */\r\n public readonly store = computed(() => {\r\n const service = this.service();\r\n if (!service) {\r\n return null;\r\n }\r\n const store = new PagedTreeStore<\r\n ThesaurusEntryPagedTreeNode,\r\n ThesaurusEntryNodeFilter\r\n >(service);\r\n return store;\r\n });\r\n\r\n public readonly loading = signal<boolean>(false);\r\n public readonly selectedNode = signal<ThesaurusEntryPagedTreeNode | null>(\r\n null,\r\n );\r\n\r\n public debug: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideLoc: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideFilter: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n\r\n public filter$: Observable<Readonly<ThesaurusEntryNodeFilter>> = of({});\r\n public nodes$: Observable<Readonly<ThesaurusEntryPagedTreeNode[]>> = of([]);\r\n\r\n public label: FormControl<string | null> = new FormControl(null);\r\n public form = new FormGroup({\r\n label: this.label,\r\n });\r\n\r\n public ngOnInit(): void {\r\n const store = this.store();\r\n if (!store) {\r\n console.error('Store not available - service input is required');\r\n return;\r\n }\r\n\r\n // setup observables (delayed because we require store to be available)\r\n this.nodes$ = store.nodes$;\r\n this.filter$ = store.filter$;\r\n\r\n if (!store.getNodes().length) {\r\n this.loading.set(true);\r\n store.setFilter({}).finally(() => {\r\n this.loading.set(false);\r\n console.log('nodes loaded', store.getNodes());\r\n });\r\n }\r\n\r\n // subscribe to changes state\r\n const service = this.service();\r\n if (service) {\r\n this._sub = service.hasChanges$.subscribe((hasChanges) => {\r\n this.changesStateChange.emit(hasChanges);\r\n });\r\n }\r\n }\r\n\r\n public ngOnDestroy(): void {\r\n this._sub?.unsubscribe();\r\n }\r\n\r\n public reset(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n this.loading.set(true);\r\n store.reset().finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n this.loading.set(true);\r\n if (node.expanded) {\r\n store.collapse(node.id).finally(() => {\r\n this.loading.set(false);\r\n });\r\n } else {\r\n store.expand(node.id).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n }\r\n\r\n public onPageChangeRequest(request: PageChangeRequest): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n this.loading.set(true);\r\n store.changePage(request.node.id, request.paging.pageNumber).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onFilterChange(\r\n filter: ThesaurusEntryNodeFilter | null | undefined,\r\n ): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n console.log('filter change', filter);\r\n this.loading.set(true);\r\n store.setFilter(filter || {}).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onEditFilterRequest(node: ThesaurusEntryPagedTreeNode): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n const dialogRef = this._dialog.open(ThesaurusPagedTreeFilterComponent, {\r\n data: {\r\n filter: node.filter,\r\n },\r\n });\r\n dialogRef.afterClosed().subscribe((filter) => {\r\n if (filter === null) {\r\n store.setNodeFilter(node.id, null);\r\n } else if (filter) {\r\n store.setNodeFilter(node.id, filter);\r\n }\r\n });\r\n }\r\n\r\n public expandAll(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.expandAll();\r\n }\r\n\r\n public collapseAll(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.collapseAll();\r\n }\r\n\r\n public clear(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.clear();\r\n }\r\n\r\n public onNodeClick(node: ThesaurusEntryPagedTreeNode): void {\r\n this.selectedNode.set(node);\r\n if (!node.hasChildren) {\r\n this.nodePick.emit(node);\r\n }\r\n }\r\n\r\n public findLabels(): void {\r\n const store = this.store();\r\n if (!store || !this.label.value) return;\r\n store.findLabels(this.label.value);\r\n }\r\n\r\n public removeHilites(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.removeHilites();\r\n }\r\n\r\n // editing operations\r\n private editEntry(entry: EditedThesEntry): Promise<EditedThesEntry | null> {\r\n return new Promise((resolve) => {\r\n const dialogRef = this._dialog.open(ThesEntryEditorComponent, {\r\n data: entry,\r\n });\r\n\r\n dialogRef.afterClosed().subscribe((result) => {\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n public async addChild(): Promise<void> {\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n // get the current entries to check for duplicates\r\n const currentService = this.service();\r\n if (!currentService) return;\r\n\r\n // determine the parent ID for the new child\r\n const parentKey = selected.key; // original entry ID\r\n\r\n // edit the new entry\r\n const newEntry = await this.editEntry({\r\n id: '',\r\n value: '',\r\n hierarchical: true,\r\n parentId: parentKey,\r\n idExists: (id: string) =>\r\n currentService.getCurrentEntries().some((e) => e.id === id),\r\n });\r\n if (!newEntry) {\r\n return;\r\n }\r\n\r\n store\r\n .addChild(selected.id, {\r\n label: newEntry.value,\r\n y: 0, // will be calculated by the store\r\n x: 0, // will be calculated by the store\r\n tag: selected.tag,\r\n })\r\n .then((result) => {\r\n if (result) {\r\n // update the temporary node with the user-provided ID,\r\n // this will be handled in the service's nodeToEntry method\r\n (result as any)._userProvidedId = newEntry.id;\r\n this._snackBar.open('Child added successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n }\r\n\r\n public async addSibling(): Promise<void> {\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n // get the current entries to check for duplicates\r\n const currentService = this.service();\r\n if (!currentService) return;\r\n\r\n const currentEntries = currentService.getCurrentEntries();\r\n const selectedKey = (selected as any).key; // original entry ID\r\n\r\n // determine the parent ID for the new sibling\r\n const selectedParts = selectedKey.split('.');\r\n const parentKey =\r\n selectedParts.length > 1 ? selectedParts.slice(0, -1).join('.') : '';\r\n\r\n const newEntry = await this.editEntry({\r\n id: '',\r\n value: '',\r\n hierarchical: true,\r\n parentId: parentKey,\r\n idExists: (id: string) =>\r\n currentService.getCurrentEntries().some((e) => e.id === id),\r\n });\r\n if (!newEntry) {\r\n return;\r\n }\r\n\r\n // check that the new ID has the same depth\r\n if (newEntry.id.split('.').length !== selectedParts.length) {\r\n this._snackBar.open(\r\n `Sibling must have same depth as \"${selectedKey}\"`,\r\n 'Close',\r\n { duration: 3000 },\r\n );\r\n return;\r\n }\r\n\r\n store\r\n .addSibling(selected.id, {\r\n label: newEntry.value,\r\n tag: selected.tag,\r\n })\r\n .then((result) => {\r\n if (result) {\r\n // update the temporary node with the user-provided ID\r\n (result as any)._userProvidedId = newEntry.id;\r\n this._snackBar.open('Sibling added successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n }\r\n\r\n public removeNode(): void {\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n const selectedKey = (selected as any).key || `temp_${selected.id}`;\r\n this._dialogService\r\n .confirm(\r\n 'Confirm Deletion',\r\n `Delete \"${selectedKey}\" (${selected.label}) and all its descendants?`,\r\n )\r\n .subscribe((result) => {\r\n if (!result) {\r\n return;\r\n }\r\n store.removeNode(selected.id).then((result) => {\r\n if (result) {\r\n this.selectedNode.set(null);\r\n this._snackBar.open('Node removed successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n });\r\n }\r\n\r\n public async editNode(): Promise<void> {\r\n const currentService = this.service();\r\n if (!currentService) return;\r\n\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n const selectedKey = selected.key;\r\n const isNewNode = selected.id < 0; // temporary ID means it's a new node\r\n\r\n const newEntry = await this.editEntry({\r\n id: selectedKey || '',\r\n value: selected.label,\r\n idLocked: !isNewNode,\r\n idExists: (id: string) =>\r\n currentService.getCurrentEntries().some((entry) => entry.id === id),\r\n });\r\n if (!newEntry) return;\r\n\r\n store\r\n .replaceNode(selected.id, {\r\n label: newEntry.value,\r\n tag: selected.tag,\r\n })\r\n .then((result) => {\r\n if (result) {\r\n // update the temporary node with the user-provided ID if it's a new node\r\n if (isNewNode) {\r\n (result as any)._userProvidedId = newEntry.id;\r\n }\r\n this._snackBar.open('Node updated successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n }\r\n}\r\n","<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\">\r\n <fieldset>\r\n <legend>finder</legend>\r\n <div 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 {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <div class=\"form-row\" style=\"gap: 0\">\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </fieldset>\r\n </form>\r\n @if (hasRootFilter()) {\r\n <fieldset>\r\n <legend>global filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter$ | async\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </div>\r\n\r\n <!-- editing actions -->\r\n <div class=\"editing-actions\">\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"primary\"\r\n [disabled]=\"!selectedNode()\"\r\n [matMenuTriggerFor]=\"addMenu\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n add\r\n </button>\r\n\r\n <mat-menu #addMenu=\"matMenu\">\r\n <button type=\"button\" mat-menu-item (click)=\"addChild()\">\r\n <mat-icon>subdirectory_arrow_right</mat-icon>\r\n add child\r\n </button>\r\n <button type=\"button\" mat-menu-item (click)=\"addSibling()\">\r\n <mat-icon>arrow_right_alt</mat-icon>\r\n add sibling\r\n </button>\r\n </mat-menu>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"accent\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"editNode()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n edit\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"warn\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"removeNode()\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n remove\r\n </button>\r\n\r\n @if (selectedNode()) {\r\n <span class=\"selected-info\"> selected: {{ selectedNode()!.label }} </span>\r\n }\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\r\n class=\"button-row\"\r\n [class.hilite]=\"node.hilite\"\r\n [class.selected]=\"selectedNode()?.id === node.id\"\r\n (click)=\"onNodeClick(node)\"\r\n >\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 </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","import { Observable, of } from 'rxjs';\r\n\r\nimport { DataPage } from '@myrmidon/ngx-tools';\r\nimport {\r\n PagedTreeNode,\r\n PagedTreeStoreService,\r\n TreeNodeFilter,\r\n} from '@myrmidon/paged-data-browsers';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\n\r\n/**\r\n * The filter for thesaurus entry nodes. The only filtered property is\r\n * the node's label.\r\n */\r\nexport interface ThesaurusEntryNodeFilter extends TreeNodeFilter {\r\n label?: string;\r\n}\r\n\r\n/**\r\n * The tree node for thesaurus entries in a paging tree node.\r\n */\r\nexport interface ThesaurusEntryPagedTreeNode extends PagedTreeNode<ThesaurusEntryNodeFilter> {\r\n key: string; // entry.id\r\n value: string; // entry.value (not rendered; the rendered value is in label)\r\n}\r\n\r\n/**\r\n * A label rendering function which removes from a label\r\n * all the characters past the last colon, trimming the result.\r\n * This is a typical rendering when dealing with hierarchical\r\n * thesaurus entries, e.g. \"furniture: table: color\", where\r\n * we can shorten the label to just \"color\", as \"furniture\"\r\n * and \"table\" are its ancestors.\r\n */\r\nexport function renderLabelFromLastColon(label: string): string {\r\n if (!label) {\r\n return label;\r\n }\r\n const i = label.lastIndexOf(':');\r\n return i > -1 && i + 1 < label.length ? label.substring(i + 1).trim() : label;\r\n}\r\n\r\ninterface NumberedEntry extends ThesaurusEntry {\r\n n: number;\r\n}\r\n\r\n/**\r\n * A static paged tree store service for thesaurus entries.\r\n * This builds tree nodes from all the thesaurus entries from a specific\r\n * thesaurus, assuming that entry IDs are hierarchical and\r\n * separated by dots (.).\r\n * Nodes are received all at once for a thesaurus, so this is essentially\r\n * an adapter to the paged tree store service interface.\r\n * The entries are a flat list where hierarchy is implied by the IDs:\r\n * for instance, \"animal.mammal.dog\" is a child of \"animal.mammal\"\r\n * which is a child of \"animal\". Numeric IDs are added to each node\r\n * based on the order of entries to ensure stable IDs.\r\n * The label of each node can be rendered as-is from the entry value,\r\n * or a custom rendering function can be provided to the constructor.\r\n */\r\nexport class StaticThesaurusPagedTreeStoreService implements PagedTreeStoreService<ThesaurusEntryNodeFilter> {\r\n private _nodes: ThesaurusEntryPagedTreeNode[] = [];\r\n private _built = false;\r\n private readonly _entries: NumberedEntry[];\r\n\r\n /**\r\n * Constructor.\r\n * @param entries The thesaurus entries.\r\n * @param _renderLabel An optional function to render the label\r\n * of each node.\r\n */\r\n constructor(\r\n entries: ThesaurusEntry[],\r\n private _renderLabel?: (label: string) => string,\r\n ) {\r\n // assign a number to each entry for stable IDs\r\n this._entries = entries.map((entry, index) => ({\r\n ...entry,\r\n n: index + 1,\r\n }));\r\n }\r\n\r\n /**\r\n * Ensure that nodes have been built from entries.\r\n */\r\n private ensureNodes(): void {\r\n // lazily build the nodes only once\r\n if (this._built) {\r\n return;\r\n }\r\n\r\n // create a map of sibling numbers (x) where:\r\n // - key=node.id (0 is used for the virtual root);\r\n // - value=max x value for that parent.\r\n const xMap = new Map<number, number>();\r\n\r\n // build nodes from entries\r\n for (const entry of this._entries) {\r\n const hasDot = entry.id.includes('.');\r\n const keyParts = entry.id.split('.');\r\n\r\n // create the node\r\n const node: ThesaurusEntryPagedTreeNode = {\r\n id: entry.n,\r\n label:\r\n hasDot && this._renderLabel\r\n ? this._renderLabel(entry.value)\r\n : entry.value,\r\n key: entry.id,\r\n value: entry.value,\r\n paging: { pageNumber: 0, pageCount: 0, total: 0 },\r\n y: hasDot ? keyParts.length : 1,\r\n x: 0, // will be set later\r\n parentId: undefined, // will be set later\r\n hasChildren: false, // will be set later\r\n };\r\n\r\n // if it has a dot, find its parent and set parentId\r\n if (hasDot) {\r\n // build the parent key\r\n const parentKey = keyParts.slice(0, keyParts.length - 1).join('.');\r\n // find the parent node with that key\r\n const parentNode = this._nodes.find((n) => n.key === parentKey);\r\n // if found, set parentId and x in child and hasChildren in parent\r\n if (parentNode) {\r\n node.parentId = parentNode.id;\r\n parentNode.hasChildren = true;\r\n if (xMap.has(parentNode.id)) {\r\n xMap.set(parentNode.id, xMap.get(parentNode.id)! + 1);\r\n } else {\r\n xMap.set(parentNode.id, 1);\r\n }\r\n node.x = xMap.get(parentNode.id)!;\r\n } else {\r\n // parent not found, treat as root\r\n if (xMap.has(0)) {\r\n xMap.set(0, xMap.get(0)! + 1);\r\n } else {\r\n xMap.set(0, 1);\r\n }\r\n node.x = xMap.get(0)!;\r\n }\r\n } else {\r\n // else it's a root node\r\n if (xMap.has(0)) {\r\n xMap.set(0, xMap.get(0)! + 1);\r\n } else {\r\n xMap.set(0, 1);\r\n }\r\n node.x = xMap.get(0)!;\r\n }\r\n\r\n this._nodes.push(node);\r\n }\r\n\r\n this._built = true;\r\n }\r\n\r\n /**\r\n * Get the specified page of nodes.\r\n * @param filter The filter.\r\n * @param pageNumber The page number.\r\n * @param pageSize The page size.\r\n * @param hasMockRoot Whether the root node is a mock node. Not used here.\r\n */\r\n public getNodes(\r\n filter: ThesaurusEntryNodeFilter,\r\n pageNumber: number,\r\n pageSize: number,\r\n hasMockRoot?: boolean,\r\n ): Observable<DataPage<ThesaurusEntryPagedTreeNode>> {\r\n this.ensureNodes();\r\n\r\n // apply filtering\r\n let nodes = this._nodes.filter((n) => {\r\n // filter by parentId (required by tree structure)\r\n if (filter.parentId !== undefined && filter.parentId !== null) {\r\n if (n.parentId !== filter.parentId) {\r\n return false;\r\n }\r\n } else {\r\n if (n.parentId) {\r\n return false;\r\n }\r\n }\r\n\r\n // filter by label\r\n if (filter.label) {\r\n const filterValue = filter.label.toLowerCase();\r\n if (!n.label.toLowerCase().includes(filterValue)) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n });\r\n\r\n // page and return\r\n const paged = nodes.slice(\r\n (pageNumber - 1) * pageSize,\r\n pageNumber * pageSize,\r\n );\r\n return of({\r\n items: paged,\r\n pageNumber: pageNumber,\r\n pageSize: pageSize,\r\n pageCount: Math.ceil(nodes.length / pageSize),\r\n total: nodes.length,\r\n });\r\n }\r\n}\r\n","import {\r\n Component,\r\n OnDestroy,\r\n OnInit,\r\n computed,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { AsyncPipe } from '@angular/common';\r\nimport { Observable, Subscription } from 'rxjs';\r\n\r\nimport { MatDialog } from '@angular/material/dialog';\r\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatCheckboxModule } from '@angular/material/checkbox';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\n\r\nimport {\r\n BrowserTreeNodeComponent,\r\n PagedTreeStore,\r\n PageChangeRequest,\r\n} from '@myrmidon/paged-data-browsers';\r\n\r\nimport {\r\n renderLabelFromLastColon,\r\n StaticThesaurusPagedTreeStoreService,\r\n ThesaurusEntryNodeFilter,\r\n ThesaurusEntryPagedTreeNode,\r\n} from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport { ThesaurusPagedTreeFilterComponent }\r\n from '../thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\n\r\n/**\r\n * A readonly paged tree browser for thesaurus entries. This is a lower-level component\r\n * used as an adapter between the generic paged tree browser and the thesaurus entries\r\n * data model.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-browser',\r\n imports: [\r\n AsyncPipe,\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatCheckboxModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatProgressBarModule,\r\n MatTooltipModule,\r\n ThesaurusPagedTreeFilterComponent,\r\n BrowserTreeNodeComponent,\r\n ],\r\n templateUrl: './thesaurus-browser.component.html',\r\n styleUrl: './thesaurus-browser.component.scss',\r\n})\r\nexport class ThesaurusBrowserComponent implements OnInit, OnDestroy {\r\n private _dialog = inject(MatDialog);\r\n private _sub?: Subscription;\r\n\r\n /**\r\n * The service to use to load the nodes.\r\n */\r\n public readonly service = input<StaticThesaurusPagedTreeStoreService>(\r\n new StaticThesaurusPagedTreeStoreService([], renderLabelFromLastColon)\r\n );\r\n\r\n /**\r\n * Emitted when a node is clicked.\r\n */\r\n public readonly nodePick = output<ThesaurusEntryPagedTreeNode>();\r\n\r\n /**\r\n * The store instance, built from the service.\r\n */\r\n public readonly store = computed(() => {\r\n const service = this.service();\r\n const store = new PagedTreeStore<\r\n ThesaurusEntryPagedTreeNode,\r\n ThesaurusEntryNodeFilter\r\n >(service);\r\n this.nodes$ = store.nodes$;\r\n this.filter$ = store.filter$;\r\n return store;\r\n });\r\n\r\n public readonly loading = signal<boolean>(false);\r\n\r\n public debug: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideLoc: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideFilter: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n\r\n public filter$: Observable<Readonly<ThesaurusEntryNodeFilter>>;\r\n public nodes$: Observable<Readonly<ThesaurusEntryPagedTreeNode[]>>;\r\n\r\n public label: FormControl<string | null> = new FormControl(null);\r\n public form = new FormGroup({\r\n label: this.label,\r\n });\r\n\r\n constructor() {\r\n const store = this.store();\r\n this.nodes$ = store.nodes$;\r\n this.filter$ = store.filter$;\r\n }\r\n\r\n public ngOnInit(): void {\r\n if (!this.store().getNodes().length) {\r\n this.loading.set(true);\r\n this.store()\r\n .setFilter({})\r\n .finally(() => {\r\n this.loading.set(false);\r\n console.log('nodes loaded', this.store().getNodes());\r\n });\r\n }\r\n }\r\n\r\n public ngOnDestroy(): void {\r\n this._sub?.unsubscribe();\r\n }\r\n\r\n public reset(): void {\r\n this.loading.set(true);\r\n this.store()\r\n .reset()\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void {\r\n this.loading.set(true);\r\n if (node.expanded) {\r\n this.store()\r\n .collapse(node.id)\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n } else {\r\n this.store()\r\n .expand(node.id)\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n }\r\n\r\n public onPageChangeRequest(request: PageChangeRequest): void {\r\n this.loading.set(true);\r\n this.store()\r\n .changePage(request.node.id, request.paging.pageNumber)\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onFilterChange(filter: ThesaurusEntryNodeFilter | null | undefined): void {\r\n console.log('filter change', filter);\r\n this.loading.set(true);\r\n this.store()\r\n .setFilter(filter || {})\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onEditFilterRequest(node: ThesaurusEntryPagedTreeNode): void {\r\n const dialogRef = this._dialog.open(ThesaurusPagedTreeFilterComponent, {\r\n data: {\r\n filter: node.filter,\r\n },\r\n });\r\n dialogRef.afterClosed().subscribe((filter) => {\r\n // undefined = user dismissed without changes\r\n if (filter === null) {\r\n this.store().setNodeFilter(node.id, null);\r\n } else if (filter) {\r\n this.store().setNodeFilter(node.id, filter);\r\n }\r\n });\r\n }\r\n\r\n public expandAll(): void {\r\n this.store().expandAll();\r\n }\r\n\r\n public collapseAll(): void {\r\n this.store().collapseAll();\r\n }\r\n\r\n public clear(): void {\r\n this.store().clear();\r\n }\r\n\r\n public onNodeClick(node: ThesaurusEntryPagedTreeNode): void {\r\n if (!node.hasChildren) {\r\n this.nodePick.emit(node);\r\n }\r\n }\r\n\r\n public findLabels(): void {\r\n if (!this.label.value) {\r\n return;\r\n }\r\n this.store().findLabels(this.label.value);\r\n }\r\n\r\n public removeHilites(): void {\r\n this.store().removeHilites();\r\n }\r\n}\r\n","<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\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thesaurus-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","import { Component, computed, input, output, Type } from '@angular/core';\r\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\n\r\nimport { ThesaurusPagedTreeFilterComponent } from '../thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\nimport {\r\n renderLabelFromLastColon,\r\n StaticThesaurusPagedTreeStoreService,\r\n ThesaurusEntryPagedTreeNode,\r\n} from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport { ThesaurusBrowserComponent } from '../thesaurus-browser/thesaurus-browser.component';\r\n\r\n/**\r\n * Thesaurus tree component.\r\n * This component displays a set of hierarchical thesaurus entries\r\n * in a tree, provided that each entry marks its hierarchy with\r\n * dots. For instance, say you have the hierarchy \"furniture\" -\r\n * \"type\" - \"color\". You might have an entry whose ID is\r\n * \"furniture.table.red\", with a sibling \"furniture.table.green\",\r\n * and a parent \"furniture.table\". This parent is there only to\r\n * provide a label to the parent node, but only leaf nodes can be\r\n * picked by the user. Whenever one is picked, the entryChange\r\n * event is emitted.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-tree',\r\n templateUrl: './thesaurus-tree.component.html',\r\n styleUrls: ['./thesaurus-tree.component.css'],\r\n imports: [FormsModule, ReactiveFormsModule, ThesaurusBrowserComponent],\r\n})\r\nexport class ThesaurusTreeComponent {\r\n /**\r\n * The thesaurus entries.\r\n */\r\n public readonly entries = input<ThesaurusEntry[]>();\r\n\r\n /**\r\n * The optional node label rendering function. Note that even if you\r\n * specify a label renderer function, the entryChange event always\r\n * emits the original label.\r\n */\r\n public readonly renderLabel = input<(label: string) => string>(\r\n renderLabelFromLastColon,\r\n );\r\n\r\n /**\r\n * Fired when a thesaurus entry is selected.\r\n */\r\n public readonly entryChange = output<ThesaurusEntry>();\r\n\r\n /**\r\n * The tree store service, dependent on the current entries and renderLabel.\r\n */\r\n public readonly service = computed<StaticThesaurusPagedTreeStoreService>(() => {\r\n const entries = this.entries();\r\n return new StaticThesaurusPagedTreeStoreService(\r\n entries || [],\r\n this.renderLabel(),\r\n );\r\n });\r\n\r\n /**\r\n * The filter component class to use.\r\n */\r\n public readonly filterComponent: Type<ThesaurusPagedTreeFilterComponent> =\r\n ThesaurusPagedTreeFilterComponent;\r\n\r\n public onNodePick(node: ThesaurusEntryPagedTreeNode): void {\r\n // only allow selection of leaf nodes (nodes without children)\r\n if (!node.hasChildren) {\r\n // find the original entry\r\n const entry = this.entries()?.find((e) => e.id === node.key);\r\n if (entry) {\r\n this.entryChange.emit(entry);\r\n }\r\n }\r\n }\r\n}\r\n","<div>\r\n <!-- tree -->\r\n @if (service() && entries()?.length) {\r\n <div class=\"tree-wrapper\">\r\n <cadmus-thesaurus-browser\r\n [service]=\"service()\"\r\n (nodePick)=\"onNodePick($event)\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n","import {\r\n Component,\r\n computed,\r\n effect,\r\n input,\r\n model,\r\n untracked,\r\n} from '@angular/core';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\nimport {\r\n FormBuilder,\r\n FormControl,\r\n FormGroup,\r\n ReactiveFormsModule,\r\n Validators,\r\n} from '@angular/forms';\r\n\r\nimport {\r\n CdkDragDrop,\r\n CdkDropList,\r\n CdkDrag,\r\n moveItemInArray,\r\n} from '@angular/cdk/drag-drop';\r\nimport {\r\n MatChipListbox,\r\n MatChipOption,\r\n MatChipRemove,\r\n} from '@angular/material/chips';\r\nimport { MatExpansionPanel } from '@angular/material/expansion';\r\nimport { MatFormField } from '@angular/material/form-field';\r\nimport { MatIcon } from '@angular/material/icon';\r\nimport { MatIconButton } from '@angular/material/button';\r\nimport { MatInput } from '@angular/material/input';\r\nimport { MatTooltip } from '@angular/material/tooltip';\r\n\r\nimport { renderLabelFromLastColon } from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport { ThesaurusTreeComponent } from '../thesaurus-tree/thesaurus-tree.component';\r\n\r\n/**\r\n * The prefix added to custom entries' IDs.\r\n */\r\nexport const CUSTOM_ENTRY_PREFIX = '$';\r\n\r\n/**\r\n * A picker component for thesaurus entries.\r\n * This component allows picking one or more entries from a given thesaurus.\r\n * In its collapsed state, it shows the picked entries as chips; when\r\n * expanded, it shows the thesaurus tree to pick from. Custom entries\r\n * (not in the thesaurus) can be optionally allowed.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-entries-picker',\r\n imports: [\r\n ReactiveFormsModule,\r\n CdkDropList,\r\n CdkDrag,\r\n MatChipListbox,\r\n MatChipOption,\r\n MatChipRemove,\r\n MatExpansionPanel,\r\n MatFormField,\r\n MatIconButton,\r\n MatIcon,\r\n MatInput,\r\n MatTooltip,\r\n ThesaurusTreeComponent,\r\n ],\r\n templateUrl: './thesaurus-entries-picker.component.html',\r\n styleUrl: './thesaurus-entries-picker.component.css',\r\n})\r\nexport class ThesaurusEntriesPickerComponent {\r\n /**\r\n * The thesaurus entries to pick from (required).\r\n */\r\n public readonly availableEntries = input.required<ThesaurusEntry[]>();\r\n\r\n /**\r\n * The picked entries.\r\n */\r\n public readonly entries = model<ThesaurusEntry[]>([]);\r\n\r\n /**\r\n * True to show the entries with labels shortened according to\r\n * their hierarchy.\r\n */\r\n public readonly hierarchicLabels = input<boolean>(false);\r\n\r\n /**\r\n * True to automatically sort the picked entries (disables drag-and-drop).\r\n * When false, entries can be manually reordered via drag-and-drop.\r\n */\r\n public readonly autoSort = input<boolean>(false);\r\n\r\n /**\r\n * True to allow custom values (not in the entries list).\r\n */\r\n public readonly allowCustom = input<boolean>(false);\r\n\r\n /**\r\n * The minimum number of entries to pick.\r\n */\r\n public readonly minEntries = input<number>(0);\r\n\r\n /**\r\n * The maximum number of entries to pick (0=unlimited).\r\n */\r\n public readonly maxEntries = input<number>(0);\r\n\r\n /**\r\n * True when the picker is expanded (showing the entries list).\r\n */\r\n public readonly expanded = model<boolean>(false);\r\n\r\n /**\r\n * The message to show when there are no picked entries.\r\n */\r\n public readonly emptyMessage = input<string>('no entries');\r\n\r\n /**\r\n * The number of remaining entries that can be picked (0=unlimited).\r\n * This is displayed only if maxEntries > 1.\r\n */\r\n public readonly remaining = computed(() => {\r\n if (this.maxEntries() > 0) {\r\n return this.maxEntries() - this.entries().length;\r\n }\r\n return 0;\r\n });\r\n\r\n public id: FormControl<string>;\r\n public value: FormControl<string>;\r\n public form: FormGroup;\r\n\r\n constructor(formBuilder: FormBuilder) {\r\n this.id = formBuilder.control<string>('', {\r\n validators: [Validators.required, Validators.maxLength(100)],\r\n nonNullable: true,\r\n });\r\n this.value = formBuilder.control<string>('', {\r\n validators: [Validators.required, Validators.maxLength(500)],\r\n nonNullable: true,\r\n });\r\n this.form = formBuilder.group({\r\n id: this.id,\r\n value: this.value,\r\n });\r\n // if auto-sort is turned on and we have entries, sort them\r\n effect(() => {\r\n // only track autoSort() changes, not entries()\r\n const shouldSort = this.autoSort();\r\n\r\n if (shouldSort) {\r\n // use untracked to read entries without creating a dependency\r\n const currentEntries = untracked(() => this.entries());\r\n if (currentEntries.length > 1) {\r\n const entries = [...currentEntries];\r\n this.sortEntries(entries);\r\n this.entries.set(entries);\r\n }\r\n }\r\n });\r\n }\r\n\r\n // need arrow function to use 'this'\r\n public renderLabel = (label: string): string => {\r\n return this.hierarchicLabels() ? renderLabelFromLastColon(label) : label;\r\n };\r\n\r\n private sortEntries(entries: ThesaurusEntry[]) {\r\n entries.sort((a: ThesaurusEntry, b: ThesaurusEntry) => {\r\n const aIsCustom = a.id?.startsWith(CUSTOM_ENTRY_PREFIX) ?? false;\r\n const bIsCustom = b.id?.startsWith(CUSTOM_ENTRY_PREFIX) ?? false;\r\n if (aIsCustom !== bIsCustom) {\r\n // place custom entries after non-custom ones\r\n return aIsCustom ? 1 : -1;\r\n }\r\n // same kind: sort by label/value\r\n return a.value.localeCompare(b.value);\r\n });\r\n }\r\n\r\n public onEntryChange(entry: ThesaurusEntry): void {\r\n // check if already present\r\n if (this.entries().some((e: ThesaurusEntry) => e.id === entry.id)) {\r\n return;\r\n }\r\n // check if limit is reached\r\n if (this.maxEntries() && this.entries().length >= this.maxEntries()) {\r\n return;\r\n }\r\n\r\n const entries = [...this.entries()];\r\n entries.push(entry);\r\n if (this.autoSort()) {\r\n this.sortEntries(entries);\r\n }\r\n this.entries.set(entries);\r\n }\r\n\r\n public addCustomEntry(): void {\r\n if (this.form.invalid) {\r\n return;\r\n }\r\n\r\n // create the custom entry\r\n const customEntry: ThesaurusEntry = {\r\n id: CUSTOM_ENTRY_PREFIX + this.id.value,\r\n value: this.value.value,\r\n };\r\n\r\n // check if already present\r\n if (this.entries().some((e: ThesaurusEntry) => e.id === customEntry.id)) {\r\n return;\r\n }\r\n // check if limit is reached\r\n if (this.maxEntries() && this.entries().length >= this.maxEntries()) {\r\n return;\r\n }\r\n const entries = [...this.entries()];\r\n entries.push(customEntry);\r\n if (this.autoSort()) {\r\n this.sortEntries(entries);\r\n }\r\n this.entries.set(entries);\r\n this.form.reset();\r\n }\r\n\r\n public removeEntry(entry: ThesaurusEntry): void {\r\n const entries = [...this.entries().filter((e) => e.id !== entry.id)];\r\n this.entries.set(entries);\r\n }\r\n\r\n public clear(): void {\r\n this.entries.set([]);\r\n // if min > 0, expand the picker\r\n if (this.minEntries() > 0 && !this.expanded()) {\r\n setTimeout(() => {\r\n this.expanded.set(true);\r\n }, 0);\r\n }\r\n }\r\n\r\n public onDrop(event: CdkDragDrop<ThesaurusEntry[]>): void {\r\n const entries = [...this.entries()];\r\n moveItemInArray(entries, event.previousIndex, event.currentIndex);\r\n this.entries.set(entries);\r\n }\r\n}\r\n","<div id=\"container\">\r\n <!-- picked entries -->\r\n <div id=\"picked\" class=\"form-row\">\r\n <!-- count -->\r\n <span class=\"nr\" [class.error]=\"entries().length < minEntries()\">{{\r\n entries().length\r\n }}</span>\r\n <!-- max-->\r\n @if (maxEntries() > 1) {\r\n <span class=\"muted\">/{{ maxEntries() }}</span>\r\n @if (remaining()) {\r\n <span class=\"muted\">: -{{ remaining() }}</span>\r\n } }\r\n <!-- min -->\r\n @if (minEntries()) {\r\n <!-- min with error -->\r\n @if (entries().length < minEntries()) {\r\n <span class=\"error\"> (min {{ minEntries() }})</span>\r\n }\r\n <!-- min without error -->\r\n @else {\r\n <span class=\"muted\"> (min {{ minEntries() }})</span>\r\n } }\r\n <!-- list -->\r\n <mat-chip-listbox\r\n [cdkDropListDisabled]=\"autoSort()\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n class=\"chip-list\"\r\n >\r\n @for (e of entries(); track e.id; let idx = $index) {\r\n <div class=\"chip-wrapper\">\r\n <mat-chip-option\r\n [cdkDragDisabled]=\"autoSort()\"\r\n cdkDrag\r\n [class.error]=\"!allowCustom() && e.id.startsWith('$')\"\r\n >\r\n {{ renderLabel(e.value) }}\r\n <button\r\n type=\"button\"\r\n matChipRemove\r\n (click)=\"removeEntry(e)\"\r\n aria-label=\"Remove entry\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-chip-option>\r\n </div>\r\n } @empty {\r\n <span class=\"muted empty-message\">{{ emptyMessage() }}</span>\r\n }\r\n </mat-chip-listbox>\r\n\r\n <!-- clear -->\r\n @if (entries().length > 0) {\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove all entries\"\r\n (click)=\"clear()\"\r\n [disabled]=\"entries().length === 0\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n }\r\n <!-- toggler -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Toggle picker\"\r\n (click)=\"expanded.set(!expanded())\"\r\n >\r\n @if (expanded()) {\r\n <mat-icon class=\"mat-primary\">publish</mat-icon>\r\n } @if (!expanded()) {\r\n <mat-icon class=\"mat-primary\">get_app</mat-icon>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- entries picker -->\r\n <div id=\"picker\">\r\n <mat-expansion-panel\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"expanded.set($event)\"\r\n >\r\n <div>\r\n <fieldset>\r\n <legend>available</legend>\r\n <cadmus-thesaurus-tree\r\n [entries]=\"availableEntries()\"\r\n [renderLabel]=\"renderLabel\"\r\n (entryChange)=\"onEntryChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n @if (allowCustom()) {\r\n <div>\r\n <form [formGroup]=\"form\" (submit)=\"addCustomEntry()\">\r\n <fieldset>\r\n <legend>custom</legend>\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"id\"\r\n placeholder=\"ID\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"value\"\r\n placeholder=\"label\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Add custom entry\"\r\n [disabled]=\"\r\n !form.valid ||\r\n (maxEntries() > 0 && entries().length >= maxEntries())\r\n \"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n </div>\r\n }\r\n </mat-expansion-panel>\r\n </div>\r\n</div>\r\n","import { Observable, of } from 'rxjs';\r\n\r\nimport { DataPage } from '@myrmidon/ngx-tools';\r\n\r\nimport {\r\n EditablePagedTreeStoreServiceBase,\r\n ChangeOperation,\r\n ChangeOperationType,\r\n TreeNode,\r\n} from '@myrmidon/paged-data-browsers';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\n\r\nimport {\r\n StaticThesaurusPagedTreeStoreService,\r\n ThesaurusEntryNodeFilter,\r\n ThesaurusEntryPagedTreeNode,\r\n} from './static-thesaurus-paged-tree-store.service';\r\n\r\n/**\r\n * Editable version of the static thesaurus paged tree store service.\r\n * This service allows editing operations on the flat ThesaurusEntry list\r\n * while maintaining the tree structure implied by the hierarchical IDs.\r\n */\r\nexport class EditableStaticThesaurusPagedTreeStoreService\r\n extends EditablePagedTreeStoreServiceBase<ThesaurusEntryNodeFilter> {\r\n private _entries: ThesaurusEntry[];\r\n private _staticService: StaticThesaurusPagedTreeStoreService;\r\n private _renderLabel?: (label: string) => string;\r\n\r\n constructor(\r\n entries: ThesaurusEntry[],\r\n renderLabel?: (label: string) => string,\r\n ) {\r\n super();\r\n this._entries = [...entries];\r\n this._renderLabel = renderLabel;\r\n this._staticService = new StaticThesaurusPagedTreeStoreService(\r\n this._entries,\r\n renderLabel,\r\n );\r\n }\r\n\r\n protected override fetchNodes(\r\n filter: ThesaurusEntryNodeFilter,\r\n pageNumber: number,\r\n pageSize: number,\r\n hasMockRoot?: boolean,\r\n ): Observable<DataPage<TreeNode>> {\r\n // update the static service with current entries and delegate,\r\n // preserving the renderLabel function\r\n this._staticService = new StaticThesaurusPagedTreeStoreService(\r\n this._entries,\r\n this._renderLabel,\r\n );\r\n return this._staticService.getNodes(\r\n filter,\r\n pageNumber,\r\n pageSize,\r\n hasMockRoot,\r\n );\r\n }\r\n\r\n protected override persistChanges(\r\n changes: ChangeOperation[],\r\n ): Observable<Map<number, number>> {\r\n console.log('=== SAVING CHANGES ===');\r\n console.log('Changes to persist:', changes);\r\n\r\n const idMap = new Map<number, number>();\r\n\r\n // process changes to update the flat entries list\r\n for (const change of changes) {\r\n switch (change.type) {\r\n case ChangeOperationType.ADD:\r\n if (change.node) {\r\n const newEntry = this.nodeToEntry(change.node);\r\n if (newEntry) {\r\n const existingIndex = this._entries.findIndex(\r\n (e) => e.id === newEntry.id,\r\n );\r\n if (existingIndex === -1) {\r\n this._entries.push(newEntry);\r\n\r\n // map temporary ID to the new permanent ID (array index + 1)\r\n if (change.node.id < 0) {\r\n const permanentId = this._entries.length;\r\n idMap.set(change.node.id, permanentId);\r\n }\r\n console.log('Added entry:', newEntry);\r\n } else {\r\n console.log('Entry already exists, skipping:', newEntry.id);\r\n }\r\n }\r\n }\r\n break;\r\n\r\n case ChangeOperationType.REMOVE:\r\n if (change.originalNode) {\r\n // use the 'key' property which contains the ThesaurusEntry string ID\r\n const nodeWithKey =\r\n change.originalNode as ThesaurusEntryPagedTreeNode;\r\n const entryKey = nodeWithKey.key;\r\n\r\n if (entryKey) {\r\n this.removeEntryAndDescendants(entryKey);\r\n console.log('Removed entry and descendants:', entryKey);\r\n } else {\r\n console.warn('Node missing key property:', change.originalNode);\r\n }\r\n } else if (change.id < 0) {\r\n console.log(\r\n 'Removed temporary node that was never persisted:',\r\n change.id,\r\n );\r\n } else {\r\n console.warn(\r\n 'Remove operation missing originalNode for ID:',\r\n change.id,\r\n );\r\n }\r\n break;\r\n\r\n case ChangeOperationType.UPDATE:\r\n if (change.node && change.originalNode) {\r\n const nodeWithKey =\r\n change.originalNode as ThesaurusEntryPagedTreeNode;\r\n const entryKey = nodeWithKey.key;\r\n\r\n if (entryKey) {\r\n const entryToUpdate = this._entries.find(\r\n (e) => e.id === entryKey,\r\n );\r\n\r\n if (entryToUpdate) {\r\n const updatedEntry = this.nodeToEntry(change.node);\r\n if (updatedEntry) {\r\n // preserve the original hierarchical ID\r\n updatedEntry.id = entryToUpdate.id;\r\n const index = this._entries.findIndex(\r\n (e) => e.id === entryToUpdate.id,\r\n );\r\n if (index !== -1) {\r\n this._entries[index] = updatedEntry;\r\n console.log('Updated entry:', updatedEntry);\r\n }\r\n }\r\n } else {\r\n console.warn(\r\n 'Could not find entry to update with key:',\r\n entryKey,\r\n );\r\n }\r\n } else {\r\n console.warn(\r\n 'Update node missing key property:',\r\n change.originalNode,\r\n );\r\n }\r\n } else if (change.id < 0) {\r\n console.log('Updated temporary node:', change.id);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n // Validate no duplicate IDs\r\n const ids = this._entries.map((e) => e.id);\r\n const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);\r\n if (duplicates.length > 0) {\r\n console.error('Duplicate IDs found:', duplicates);\r\n }\r\n\r\n console.log('Final entries after changes:', this._entries);\r\n console.log('ID mappings:', idMap);\r\n console.log('=== END SAVING CHANGES ===');\r\n\r\n return of(idMap);\r\n }\r\n\r\n /**\r\n * Convert a TreeNode back to a ThesaurusEntry.\r\n */\r\n private nodeToEntry(node: TreeNode): ThesaurusEntry | null {\r\n // For nodes with the key property, use it directly\r\n const nodeWithKey = node as any;\r\n if (nodeWithKey.key) {\r\n return {\r\n id: nodeWithKey.key,\r\n value: node.label,\r\n };\r\n }\r\n\r\n // For temporary nodes (negative IDs), construct a hierarchical ID\r\n if (node.id < 0) {\r\n // Check for user-provided ID\r\n const userProvidedId = nodeWithKey._userProvidedId;\r\n\r\n if (userProvidedId) {\r\n return {\r\n id: userProvidedId,\r\n value: node.label,\r\n };\r\n }\r\n\r\n // Find parent to construct the ID\r\n if (node.parentId) {\r\n const parentNode = this._nodes.get(node.parentId) as any;\r\n const parentKey = parentNode?.key;\r\n if (parentKey) {\r\n return {\r\n id: `${parentKey}.temp${Math.abs(node.id)}`,\r\n value: node.label,\r\n };\r\n }\r\n }\r\n\r\n // No parent, create a root-level temporary entry\r\n return {\r\n id: `temp${Math.abs(node.id)}`,\r\n value: node.label,\r\n };\r\n }\r\n\r\n console.warn('Could not convert node to entry:', node);\r\n return null;\r\n }\r\n\r\n /**\r\n * Remove an entry and all its descendants from the entries list.\r\n */\r\n private removeEntryAndDescendants(entryId: string): void {\r\n const toRemove: string[] = [];\r\n\r\n // find the entry and all its descendants\r\n for (const entry of this._entries) {\r\n if (entry.id === entryId || entry.id.startsWith(entryId + '.')) {\r\n toRemove.push(entry.id);\r\n }\r\n }\r\n\r\n // remove them from the list\r\n for (const id of toRemove) {\r\n const index = this._entries.findIndex((e) => e.id === id);\r\n if (index !== -1) {\r\n this._entries.splice(index, 1);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get current entries (for demonstration purposes).\r\n */\r\n public getCurrentEntries(): ThesaurusEntry[] {\r\n return [...this._entries];\r\n }\r\n}\r\n","/*\r\n * Public API Surface of cadmus-thesaurus-store\r\n */\r\n\r\nexport * from './lib/components/editable-thesaurus-browser/editable-thesaurus-browser.component';\r\nexport * from './lib/components/thesaurus-entries-picker/thesaurus-entries-picker.component';\r\nexport * from './lib/components/thesaurus-entry-editor/thesaurus-entry-editor.component';\r\nexport * from './lib/components/thesaurus-browser/thesaurus-browser.component';\r\nexport * from './lib/components/thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\nexport * from './lib/components/thesaurus-tree/thesaurus-tree.component';\r\n\r\nexport * from './lib/services/editable-static-thesaurus-paged-tree-store.service';\r\nexport * from './lib/services/static-thesaurus-paged-tree-store.service';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i3","i4","i6","i2","i7"],"mappings":"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"}
1
+ {"version":3,"file":"myrmidon-cadmus-thesaurus-store.mjs","sources":["../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entry-editor/thesaurus-entry-editor.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entry-editor/thesaurus-entry-editor.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/editable-thesaurus-browser/editable-thesaurus-browser.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/editable-thesaurus-browser/editable-thesaurus-browser.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/services/static-thesaurus-paged-tree-store.service.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-browser/thesaurus-browser.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-browser/thesaurus-browser.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-tree/thesaurus-tree.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-tree/thesaurus-tree.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entries-picker/thesaurus-entries-picker.component.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/components/thesaurus-entries-picker/thesaurus-entries-picker.component.html","../../../../projects/myrmidon/cadmus-thesaurus-store/src/lib/services/editable-static-thesaurus-paged-tree-store.service.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/public-api.ts","../../../../projects/myrmidon/cadmus-thesaurus-store/src/myrmidon-cadmus-thesaurus-store.ts"],"sourcesContent":["import {\r\n Component,\r\n effect,\r\n inject,\r\n model,\r\n OnInit,\r\n signal,\r\n} from '@angular/core';\r\nimport {\r\n FormBuilder,\r\n FormControl,\r\n FormGroup,\r\n ReactiveFormsModule,\r\n} from '@angular/forms';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\n\r\nimport { ThesaurusEntryNodeFilter } from '../../services/static-thesaurus-paged-tree-store.service';\r\n\r\n/**\r\n * A filter to be used for thesaurus paged tree browsers.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-paged-tree-filter',\r\n imports: [\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatFormFieldModule,\r\n MatInputModule,\r\n MatIconModule,\r\n MatTooltipModule,\r\n ],\r\n templateUrl: './thesaurus-paged-tree-filter.component.html',\r\n styleUrl: './thesaurus-paged-tree-filter.component.css',\r\n})\r\nexport class ThesaurusPagedTreeFilterComponent implements OnInit {\r\n public readonly dialogRef = inject<\r\n MatDialogRef<ThesaurusPagedTreeFilterComponent>\r\n >(MatDialogRef, {\r\n optional: true,\r\n });\r\n public readonly data = inject(MAT_DIALOG_DATA, { optional: true });\r\n\r\n /**\r\n * The filter.\r\n */\r\n public readonly filter = model<ThesaurusEntryNodeFilter | null | undefined>();\r\n\r\n public readonly wrapped = signal<boolean>(false);\r\n\r\n public label: FormControl<string | null>;\r\n public form: FormGroup;\r\n\r\n constructor() {\r\n const formBuilder = inject(FormBuilder);\r\n const data = this.data;\r\n\r\n // form\r\n this.label = formBuilder.control<string | null>(null);\r\n this.form = formBuilder.group({\r\n label: this.label,\r\n });\r\n // bind dialog data if any\r\n if (this.dialogRef) {\r\n this.wrapped.set(true);\r\n if (data) {\r\n this.filter.set(data.filter);\r\n }\r\n } else {\r\n this.wrapped.set(false);\r\n }\r\n\r\n // update form when filter changes\r\n effect(() => {\r\n this.updateForm(this.filter());\r\n });\r\n }\r\n\r\n public ngOnInit(): void {\r\n this.updateForm(this.filter());\r\n }\r\n\r\n private updateForm(filter?: ThesaurusEntryNodeFilter | null): void {\r\n if (!filter) {\r\n this.form.reset();\r\n return;\r\n }\r\n this.label.setValue(filter.label ?? null);\r\n this.form.markAsPristine();\r\n }\r\n\r\n private getFilter(): ThesaurusEntryNodeFilter {\r\n return {\r\n label: this.label.value ?? undefined,\r\n };\r\n }\r\n\r\n public reset(): void {\r\n this.form.reset();\r\n this.filter.set(null);\r\n this.dialogRef?.close(null);\r\n }\r\n\r\n public apply(): void {\r\n const filter = this.getFilter();\r\n this.filter.set(filter);\r\n this.dialogRef?.close(filter);\r\n }\r\n}\r\n","<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\r\n <!-- buttons -->\r\n <div class=\"button-row\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Reset\"\r\n (click)=\"reset()\"\r\n >\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 </div>\r\n</form>\r\n","import { Component, Inject, input, model, Optional } from '@angular/core';\r\nimport {\r\n FormBuilder,\r\n FormControl,\r\n FormGroup,\r\n ReactiveFormsModule,\r\n Validators,\r\n AbstractControl,\r\n ValidationErrors,\r\n} from '@angular/forms';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport {\r\n MatDialogRef,\r\n MAT_DIALOG_DATA,\r\n MatDialogConfig,\r\n} from '@angular/material/dialog';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\n\r\n/**\r\n * An edited thesaurus entry.\r\n */\r\nexport interface EditedThesEntry {\r\n id: string;\r\n value: string;\r\n /**\r\n * True if this entry belongs to a hierarchical thesaurus. When this is true,\r\n * and parentId is set, the parentId field will be used as the prefix for the\r\n * id field when creating a new entry.\r\n */\r\n hierarchical?: boolean;\r\n /**\r\n * The ID of the parent entry, if any.\r\n */\r\n parentId?: string;\r\n /**\r\n * If true, the id field is read-only. This is used when editing an existing\r\n * entry so you cannot change its ID.\r\n */\r\n idLocked?: boolean;\r\n /**\r\n * Function used to check if the given ID exists. This is used when\r\n * creating a new entry to ensure it does not duplicate an existing ID.\r\n * @param id The ID to check.\r\n * @returns True if exists.\r\n */\r\n idExists?: (id: string) => boolean;\r\n}\r\n\r\nexport interface PayloadMatDialogConfig<T> extends MatDialogConfig {\r\n payload?: T;\r\n}\r\n\r\n/**\r\n * A dialog component to edit a thesaurus entry.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-entry-editor',\r\n imports: [\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatTooltipModule,\r\n ],\r\n templateUrl: './thesaurus-entry-editor.component.html',\r\n styleUrl: './thesaurus-entry-editor.component.scss',\r\n})\r\nexport class ThesEntryEditorComponent {\r\n public readonly entry = model<EditedThesEntry | undefined>();\r\n public wrapped = false;\r\n\r\n public id: FormControl<string>;\r\n public value: FormControl<string>;\r\n public form: FormGroup;\r\n\r\n constructor(\r\n @Optional()\r\n public dialogRef: MatDialogRef<ThesEntryEditorComponent>,\r\n @Optional()\r\n @Inject(MAT_DIALOG_DATA)\r\n public data: PayloadMatDialogConfig<EditedThesEntry>,\r\n formBuilder: FormBuilder\r\n ) {\r\n // bind to data properties if any\r\n if (data) {\r\n this.entry.set(data as EditedThesEntry);\r\n this.wrapped = true;\r\n }\r\n\r\n // custom validator for ID existence\r\n const idExistsValidator = (\r\n control: AbstractControl\r\n ): ValidationErrors | null => {\r\n const entry = this.entry();\r\n if (!entry || entry.idLocked || !entry.idExists) {\r\n return null;\r\n }\r\n const id = control.value?.trim();\r\n if (!id) {\r\n return null;\r\n }\r\n // if editing, allow the current id (do not check against itself)\r\n if (entry.id === id) {\r\n return null;\r\n }\r\n return entry.idExists(id) ? { idExists: true } : null;\r\n };\r\n\r\n // custom validator for hierarchical ID prefix\r\n const hierarchicalIdValidator = (\r\n control: AbstractControl\r\n ): ValidationErrors | null => {\r\n const entry = this.entry();\r\n if (!entry || entry.idLocked || !entry.hierarchical || !entry.parentId) {\r\n return null;\r\n }\r\n const id = control.value?.trim();\r\n if (!id) {\r\n return null;\r\n }\r\n const prefix = entry.parentId + '.';\r\n if (!id.startsWith(prefix) || id.length <= prefix.length) {\r\n return { hierarchicalPrefix: { requiredPrefix: prefix } };\r\n }\r\n return null;\r\n };\r\n\r\n // form controls\r\n this.id = new FormControl<string>((data as EditedThesEntry)?.id || '', {\r\n nonNullable: true,\r\n validators: [\r\n Validators.required,\r\n Validators.maxLength(300),\r\n idExistsValidator,\r\n hierarchicalIdValidator,\r\n ],\r\n });\r\n this.value = new FormControl<string>(\r\n (data as EditedThesEntry)?.value || '',\r\n {\r\n nonNullable: true,\r\n validators: [Validators.required, Validators.maxLength(500)],\r\n }\r\n );\r\n this.form = formBuilder.group({\r\n id: this.id,\r\n value: this.value,\r\n });\r\n }\r\n\r\n cancel(): void {\r\n this.dialogRef?.close();\r\n }\r\n\r\n save(): void {\r\n if (this.form.invalid) {\r\n return;\r\n }\r\n const old = this.entry()!;\r\n\r\n // save data and close the dialog\r\n this.dialogRef?.close({\r\n id: old.idLocked ? old.id : this.id.value?.trim(),\r\n value: this.value.value?.trim(),\r\n } as EditedThesEntry);\r\n }\r\n}\r\n","<form [formGroup]=\"form\" (submit)=\"save()\" [class.wrapped]=\"wrapped\">\r\n <fieldset>\r\n <legend>entry</legend>\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n @if (entry()!.idLocked) {\r\n <span class=\"readonly\">{{ entry()!.id }}</span>\r\n } @else {\r\n <mat-form-field>\r\n <mat-label>ID</mat-label>\r\n <input matInput [formControl]=\"id\" />\r\n @if ($any(id).errors?.required && (id.dirty || id.touched)) {\r\n <mat-error>ID required</mat-error>\r\n } @if ($any(id).errors?.maxLength && (id.dirty || id.touched)) {\r\n <mat-error>ID too long</mat-error>\r\n } @if ($any(id).errors?.idExists && (id.dirty || id.touched)) {\r\n <mat-error>ID already exists</mat-error>\r\n } @if ($any(id).errors?.requiredPrefix && (id.dirty || id.touched)) {\r\n <mat-error>ID must start with \"{{ entry()!.parentId }}.\"</mat-error>\r\n }\r\n <!-- hint -->\r\n @if (entry()?.parentId) {\r\n <mat-hint>parent: {{ entry()!.parentId }}</mat-hint>\r\n }\r\n </mat-form-field>\r\n }\r\n <!-- value -->\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n @if ($any(value).errors?.required && (value.dirty || value.touched)) {\r\n <mat-error>value required</mat-error>\r\n } @if ($any(value).errors?.maxLength && (value.dirty || value.touched))\r\n {\r\n <mat-error>value too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"cancel()\"\r\n >\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=\"Accept changes\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n</form>\r\n","import {\r\n Component,\r\n OnDestroy,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { Subscription } from 'rxjs';\r\n\r\nimport { MatDialog } from '@angular/material/dialog';\r\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatCheckboxModule } from '@angular/material/checkbox';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatSnackBar } from '@angular/material/snack-bar';\r\n\r\nimport { DialogService } from '@myrmidon/ngx-mat-tools';\r\nimport {\r\n BrowserTreeNodeComponent,\r\n PagedTreeStore,\r\n PageChangeRequest,\r\n} from '@myrmidon/paged-data-browsers';\r\n\r\nimport { ThesaurusPagedTreeFilterComponent } from '../thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\nimport {\r\n ThesaurusEntryNodeFilter,\r\n ThesaurusEntryPagedTreeNode,\r\n} from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport {\r\n EditedThesEntry,\r\n ThesEntryEditorComponent,\r\n} from '../thesaurus-entry-editor/thesaurus-entry-editor.component';\r\nimport { EditableStaticThesaurusPagedTreeStoreService } from '../../services/editable-static-thesaurus-paged-tree-store.service';\r\n\r\n/**\r\n * An editable paged tree browser for thesaurus entries. Editing happens in memory\r\n * and when complete, the changes can be committed to the underlying data store\r\n * via the EditableStaticThesaurusPagedTreeStoreService.\r\n */\r\n@Component({\r\n selector: 'cadmus-editable-thesaurus-browser',\r\n imports: [\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatCheckboxModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatMenuModule,\r\n MatProgressBarModule,\r\n MatTooltipModule,\r\n ThesaurusPagedTreeFilterComponent,\r\n BrowserTreeNodeComponent,\r\n ],\r\n templateUrl: './editable-thesaurus-browser.component.html',\r\n styleUrls: ['./editable-thesaurus-browser.component.scss'],\r\n})\r\nexport class EditableThesaurusBrowserComponent implements OnDestroy {\r\n private _dialog = inject(MatDialog);\r\n private _snackBar = inject(MatSnackBar);\r\n private _dialogService = inject(DialogService);\r\n private _nodesSub?: Subscription;\r\n private _filterSub?: Subscription;\r\n private _changesSub?: Subscription;\r\n\r\n /**\r\n * The editable service to use to load the nodes.\r\n */\r\n public readonly service =\r\n input<EditableStaticThesaurusPagedTreeStoreService>();\r\n\r\n /**\r\n * True to show the tree root nodes filter.\r\n */\r\n public readonly hasRootFilter = input<boolean>(false);\r\n\r\n /**\r\n * Emitted when a node is clicked.\r\n */\r\n public readonly nodePick = output<ThesaurusEntryPagedTreeNode>();\r\n\r\n /**\r\n * Emitted when the changes state changes.\r\n */\r\n public readonly changesStateChange = output<boolean>();\r\n\r\n /**\r\n * The store instance, built from the service.\r\n */\r\n public readonly store = computed(() => {\r\n const service = this.service();\r\n if (!service) {\r\n return null;\r\n }\r\n return new PagedTreeStore<\r\n ThesaurusEntryPagedTreeNode,\r\n ThesaurusEntryNodeFilter\r\n >(service);\r\n });\r\n\r\n public readonly loading = signal<boolean>(false);\r\n public readonly selectedNode = signal<ThesaurusEntryPagedTreeNode | null>(\r\n null,\r\n );\r\n\r\n // Signals for reactive data binding (replacing observables with async pipe)\r\n public readonly nodes = signal<readonly ThesaurusEntryPagedTreeNode[]>([]);\r\n public readonly filter = signal<Readonly<ThesaurusEntryNodeFilter>>({});\r\n\r\n public debug: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideLoc: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideFilter: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n\r\n public label: FormControl<string | null> = new FormControl(null);\r\n public form = new FormGroup({\r\n label: this.label,\r\n });\r\n\r\n constructor() {\r\n // Use effect to react to service/store changes\r\n effect(() => {\r\n const currentStore = this.store();\r\n const currentService = this.service();\r\n\r\n // Cleanup previous subscriptions\r\n this._nodesSub?.unsubscribe();\r\n this._filterSub?.unsubscribe();\r\n this._changesSub?.unsubscribe();\r\n\r\n if (!currentStore || !currentService) {\r\n this.nodes.set([]);\r\n this.filter.set({});\r\n return;\r\n }\r\n\r\n // Subscribe to store's observables and update signals\r\n this._nodesSub = currentStore.nodes$.subscribe((nodes) => {\r\n this.nodes.set(nodes);\r\n });\r\n this._filterSub = currentStore.filter$.subscribe((filter) => {\r\n this.filter.set(filter);\r\n });\r\n\r\n // Subscribe to changes state\r\n this._changesSub = currentService.hasChanges$.subscribe((hasChanges) => {\r\n this.changesStateChange.emit(hasChanges);\r\n });\r\n\r\n // Load nodes if store is empty\r\n if (!currentStore.getNodes().length) {\r\n this.loading.set(true);\r\n currentStore.setFilter({}).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n });\r\n }\r\n\r\n public ngOnDestroy(): void {\r\n this._nodesSub?.unsubscribe();\r\n this._filterSub?.unsubscribe();\r\n this._changesSub?.unsubscribe();\r\n }\r\n\r\n public reset(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n this.loading.set(true);\r\n store.reset().finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n this.loading.set(true);\r\n if (node.expanded) {\r\n store.collapse(node.id).finally(() => {\r\n this.loading.set(false);\r\n });\r\n } else {\r\n store.expand(node.id).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n }\r\n\r\n public onPageChangeRequest(request: PageChangeRequest): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n this.loading.set(true);\r\n store.changePage(request.node.id, request.paging.pageNumber).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onFilterChange(\r\n filter: ThesaurusEntryNodeFilter | null | undefined,\r\n ): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n console.log('filter change', filter);\r\n this.loading.set(true);\r\n store.setFilter(filter || {}).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onEditFilterRequest(node: ThesaurusEntryPagedTreeNode): void {\r\n const store = this.store();\r\n if (!store) return;\r\n\r\n const dialogRef = this._dialog.open(ThesaurusPagedTreeFilterComponent, {\r\n data: {\r\n filter: node.filter,\r\n },\r\n });\r\n dialogRef.afterClosed().subscribe((filter) => {\r\n if (filter === null) {\r\n store.setNodeFilter(node.id, null);\r\n } else if (filter) {\r\n store.setNodeFilter(node.id, filter);\r\n }\r\n });\r\n }\r\n\r\n public expandAll(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.expandAll();\r\n }\r\n\r\n public collapseAll(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.collapseAll();\r\n }\r\n\r\n public clear(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.clear();\r\n }\r\n\r\n public onNodeClick(node: ThesaurusEntryPagedTreeNode): void {\r\n this.selectedNode.set(node);\r\n if (!node.hasChildren) {\r\n this.nodePick.emit(node);\r\n }\r\n }\r\n\r\n public findLabels(): void {\r\n const store = this.store();\r\n if (!store || !this.label.value) return;\r\n store.findLabels(this.label.value);\r\n }\r\n\r\n public removeHilites(): void {\r\n const store = this.store();\r\n if (!store) return;\r\n store.removeHilites();\r\n }\r\n\r\n // editing operations\r\n private editEntry(entry: EditedThesEntry): Promise<EditedThesEntry | null> {\r\n return new Promise((resolve) => {\r\n const dialogRef = this._dialog.open(ThesEntryEditorComponent, {\r\n data: entry,\r\n });\r\n\r\n dialogRef.afterClosed().subscribe((result) => {\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n public async addChild(): Promise<void> {\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n // get the current entries to check for duplicates\r\n const currentService = this.service();\r\n if (!currentService) return;\r\n\r\n // determine the parent ID for the new child\r\n const parentKey = selected.key; // original entry ID\r\n\r\n // edit the new entry\r\n const newEntry = await this.editEntry({\r\n id: '',\r\n value: '',\r\n hierarchical: true,\r\n parentId: parentKey,\r\n idExists: (id: string) =>\r\n currentService.getCurrentEntries().some((e) => e.id === id),\r\n });\r\n if (!newEntry) {\r\n return;\r\n }\r\n\r\n store\r\n .addChild(selected.id, {\r\n label: newEntry.value,\r\n y: 0, // will be calculated by the store\r\n x: 0, // will be calculated by the store\r\n tag: selected.tag,\r\n })\r\n .then((result) => {\r\n if (result) {\r\n // update the temporary node with the user-provided ID,\r\n // this will be handled in the service's nodeToEntry method\r\n (result as any)._userProvidedId = newEntry.id;\r\n this._snackBar.open('Child added successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n }\r\n\r\n public async addSibling(): Promise<void> {\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n // get the current entries to check for duplicates\r\n const currentService = this.service();\r\n if (!currentService) return;\r\n\r\n const selectedKey = (selected as any).key; // original entry ID\r\n\r\n // determine the parent ID for the new sibling\r\n const selectedParts = selectedKey.split('.');\r\n const parentKey =\r\n selectedParts.length > 1 ? selectedParts.slice(0, -1).join('.') : '';\r\n\r\n const newEntry = await this.editEntry({\r\n id: '',\r\n value: '',\r\n hierarchical: true,\r\n parentId: parentKey,\r\n idExists: (id: string) =>\r\n currentService.getCurrentEntries().some((e) => e.id === id),\r\n });\r\n if (!newEntry) {\r\n return;\r\n }\r\n\r\n // check that the new ID has the same depth\r\n if (newEntry.id.split('.').length !== selectedParts.length) {\r\n this._snackBar.open(\r\n `Sibling must have same depth as \"${selectedKey}\"`,\r\n 'Close',\r\n { duration: 3000 },\r\n );\r\n return;\r\n }\r\n\r\n store\r\n .addSibling(selected.id, {\r\n label: newEntry.value,\r\n tag: selected.tag,\r\n })\r\n .then((result) => {\r\n if (result) {\r\n // update the temporary node with the user-provided ID\r\n (result as any)._userProvidedId = newEntry.id;\r\n this._snackBar.open('Sibling added successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n }\r\n\r\n public removeNode(): void {\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n const selectedKey = (selected as any).key || `temp_${selected.id}`;\r\n this._dialogService\r\n .confirm(\r\n 'Confirm Deletion',\r\n `Delete \"${selectedKey}\" (${selected.label}) and all its descendants?`,\r\n )\r\n .subscribe((result) => {\r\n if (!result) {\r\n return;\r\n }\r\n store.removeNode(selected.id).then((result) => {\r\n if (result) {\r\n this.selectedNode.set(null);\r\n this._snackBar.open('Node removed successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n });\r\n }\r\n\r\n public async editNode(): Promise<void> {\r\n const currentService = this.service();\r\n if (!currentService) return;\r\n\r\n const store = this.store();\r\n const selected = this.selectedNode();\r\n if (!store || !selected) {\r\n this._snackBar.open('Please select a node first', 'Close', {\r\n duration: 2000,\r\n });\r\n return;\r\n }\r\n\r\n const selectedKey = selected.key;\r\n const isNewNode = selected.id < 0; // temporary ID means it's a new node\r\n\r\n const newEntry = await this.editEntry({\r\n id: selectedKey || '',\r\n value: selected.label,\r\n idLocked: !isNewNode,\r\n idExists: (id: string) =>\r\n currentService.getCurrentEntries().some((entry) => entry.id === id),\r\n });\r\n if (!newEntry) return;\r\n\r\n store\r\n .replaceNode(selected.id, {\r\n label: newEntry.value,\r\n tag: selected.tag,\r\n })\r\n .then((result) => {\r\n if (result) {\r\n // update the temporary node with the user-provided ID if it's a new node\r\n if (isNewNode) {\r\n (result as any)._userProvidedId = newEntry.id;\r\n }\r\n this._snackBar.open('Node updated successfully', 'Close', {\r\n duration: 2000,\r\n });\r\n }\r\n });\r\n }\r\n}\r\n","<div id=\"container\">\r\n <!-- filters -->\r\n <div id=\"filters\" class=\"form-row\">\r\n <form [formGroup]=\"form\" (submit)=\"findLabels()\">\r\n <fieldset>\r\n <legend>finder</legend>\r\n <div 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 {\r\n <mat-error>label required</mat-error>\r\n }\r\n </mat-form-field>\r\n <div class=\"form-row\" style=\"gap: 0\">\r\n <button type=\"submit\" mat-icon-button class=\"mat-primary\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </fieldset>\r\n </form>\r\n @if (hasRootFilter()) {\r\n <fieldset>\r\n <legend>global filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter()\"\r\n (filterChange)=\"onFilterChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </div>\r\n\r\n <!-- editing actions -->\r\n <div class=\"editing-actions\">\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"primary\"\r\n [disabled]=\"!selectedNode()\"\r\n [matMenuTriggerFor]=\"addMenu\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n add\r\n </button>\r\n\r\n <mat-menu #addMenu=\"matMenu\">\r\n <button type=\"button\" mat-menu-item (click)=\"addChild()\">\r\n <mat-icon>subdirectory_arrow_right</mat-icon>\r\n add child\r\n </button>\r\n <button type=\"button\" mat-menu-item (click)=\"addSibling()\">\r\n <mat-icon>arrow_right_alt</mat-icon>\r\n add sibling\r\n </button>\r\n </mat-menu>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"accent\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"editNode()\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n edit\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n mat-stroked-button\r\n color=\"warn\"\r\n [disabled]=\"!selectedNode()\"\r\n (click)=\"removeNode()\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n remove\r\n </button>\r\n\r\n @if (selectedNode()) {\r\n <span class=\"selected-info\"> selected: {{ selectedNode()!.label }} </span>\r\n }\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(); as nodeList) {\r\n <div>\r\n @for (node of nodeList; track node.id; let i = $index) {\r\n <div\r\n class=\"button-row\"\r\n [class.hilite]=\"node.hilite\"\r\n [class.selected]=\"selectedNode()?.id === node.id\"\r\n (click)=\"onNodeClick(node)\"\r\n >\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 < nodeList.length &&\r\n nodeList[i + 1].paging.pageCount > 1\r\n ? nodeList[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 </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","import { Observable, of } from 'rxjs';\r\n\r\nimport { DataPage } from '@myrmidon/ngx-tools';\r\nimport {\r\n PagedTreeNode,\r\n PagedTreeStoreService,\r\n TreeNodeFilter,\r\n} from '@myrmidon/paged-data-browsers';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\n\r\n/**\r\n * The filter for thesaurus entry nodes. The only filtered property is\r\n * the node's label.\r\n */\r\nexport interface ThesaurusEntryNodeFilter extends TreeNodeFilter {\r\n label?: string;\r\n}\r\n\r\n/**\r\n * The tree node for thesaurus entries in a paging tree node.\r\n */\r\nexport interface ThesaurusEntryPagedTreeNode extends PagedTreeNode<ThesaurusEntryNodeFilter> {\r\n key: string; // entry.id\r\n value: string; // entry.value (not rendered; the rendered value is in label)\r\n}\r\n\r\n/**\r\n * A label rendering function which removes from a label\r\n * all the characters past the last colon, trimming the result.\r\n * This is a typical rendering when dealing with hierarchical\r\n * thesaurus entries, e.g. \"furniture: table: color\", where\r\n * we can shorten the label to just \"color\", as \"furniture\"\r\n * and \"table\" are its ancestors.\r\n */\r\nexport function renderLabelFromLastColon(label: string): string {\r\n if (!label) {\r\n return label;\r\n }\r\n const i = label.lastIndexOf(':');\r\n return i > -1 && i + 1 < label.length ? label.substring(i + 1).trim() : label;\r\n}\r\n\r\ninterface NumberedEntry extends ThesaurusEntry {\r\n n: number;\r\n}\r\n\r\n/**\r\n * A static paged tree store service for thesaurus entries.\r\n * This builds tree nodes from all the thesaurus entries from a specific\r\n * thesaurus, assuming that entry IDs are hierarchical and\r\n * separated by dots (.).\r\n * Nodes are received all at once for a thesaurus, so this is essentially\r\n * an adapter to the paged tree store service interface.\r\n * The entries are a flat list where hierarchy is implied by the IDs:\r\n * for instance, \"animal.mammal.dog\" is a child of \"animal.mammal\"\r\n * which is a child of \"animal\". Numeric IDs are added to each node\r\n * based on the order of entries to ensure stable IDs.\r\n * The label of each node can be rendered as-is from the entry value,\r\n * or a custom rendering function can be provided to the constructor.\r\n */\r\nexport class StaticThesaurusPagedTreeStoreService implements PagedTreeStoreService<ThesaurusEntryNodeFilter> {\r\n private _nodes: ThesaurusEntryPagedTreeNode[] = [];\r\n private _built = false;\r\n private readonly _entries: NumberedEntry[];\r\n\r\n /**\r\n * Constructor.\r\n * @param entries The thesaurus entries.\r\n * @param _renderLabel An optional function to render the label\r\n * of each node.\r\n */\r\n constructor(\r\n entries: ThesaurusEntry[],\r\n private _renderLabel?: (label: string) => string,\r\n ) {\r\n // assign a number to each entry for stable IDs\r\n this._entries = entries.map((entry, index) => ({\r\n ...entry,\r\n n: index + 1,\r\n }));\r\n }\r\n\r\n /**\r\n * Ensure that nodes have been built from entries.\r\n */\r\n private ensureNodes(): void {\r\n // lazily build the nodes only once\r\n if (this._built) {\r\n return;\r\n }\r\n\r\n // create a map of sibling numbers (x) where:\r\n // - key=node.id (0 is used for the virtual root);\r\n // - value=max x value for that parent.\r\n const xMap = new Map<number, number>();\r\n\r\n // build nodes from entries\r\n for (const entry of this._entries) {\r\n const hasDot = entry.id.includes('.');\r\n const keyParts = entry.id.split('.');\r\n\r\n // create the node\r\n const node: ThesaurusEntryPagedTreeNode = {\r\n id: entry.n,\r\n label:\r\n hasDot && this._renderLabel\r\n ? this._renderLabel(entry.value)\r\n : entry.value,\r\n key: entry.id,\r\n value: entry.value,\r\n paging: { pageNumber: 0, pageCount: 0, total: 0 },\r\n y: hasDot ? keyParts.length : 1,\r\n x: 0, // will be set later\r\n parentId: undefined, // will be set later\r\n hasChildren: false, // will be set later\r\n };\r\n\r\n // if it has a dot, find its parent and set parentId\r\n if (hasDot) {\r\n // build the parent key\r\n const parentKey = keyParts.slice(0, keyParts.length - 1).join('.');\r\n // find the parent node with that key\r\n const parentNode = this._nodes.find((n) => n.key === parentKey);\r\n // if found, set parentId and x in child and hasChildren in parent\r\n if (parentNode) {\r\n node.parentId = parentNode.id;\r\n parentNode.hasChildren = true;\r\n if (xMap.has(parentNode.id)) {\r\n xMap.set(parentNode.id, xMap.get(parentNode.id)! + 1);\r\n } else {\r\n xMap.set(parentNode.id, 1);\r\n }\r\n node.x = xMap.get(parentNode.id)!;\r\n } else {\r\n // parent not found, treat as root\r\n if (xMap.has(0)) {\r\n xMap.set(0, xMap.get(0)! + 1);\r\n } else {\r\n xMap.set(0, 1);\r\n }\r\n node.x = xMap.get(0)!;\r\n }\r\n } else {\r\n // else it's a root node\r\n if (xMap.has(0)) {\r\n xMap.set(0, xMap.get(0)! + 1);\r\n } else {\r\n xMap.set(0, 1);\r\n }\r\n node.x = xMap.get(0)!;\r\n }\r\n\r\n this._nodes.push(node);\r\n }\r\n\r\n this._built = true;\r\n }\r\n\r\n /**\r\n * Get the specified page of nodes.\r\n * @param filter The filter.\r\n * @param pageNumber The page number.\r\n * @param pageSize The page size.\r\n * @param hasMockRoot Whether the root node is a mock node. Not used here.\r\n */\r\n public getNodes(\r\n filter: ThesaurusEntryNodeFilter,\r\n pageNumber: number,\r\n pageSize: number,\r\n hasMockRoot?: boolean,\r\n ): Observable<DataPage<ThesaurusEntryPagedTreeNode>> {\r\n this.ensureNodes();\r\n\r\n // apply filtering\r\n let nodes = this._nodes.filter((n) => {\r\n // filter by parentId (required by tree structure)\r\n if (filter.parentId !== undefined && filter.parentId !== null) {\r\n if (n.parentId !== filter.parentId) {\r\n return false;\r\n }\r\n } else {\r\n if (n.parentId) {\r\n return false;\r\n }\r\n }\r\n\r\n // filter by label\r\n if (filter.label) {\r\n const filterValue = filter.label.toLowerCase();\r\n if (!n.label.toLowerCase().includes(filterValue)) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n });\r\n\r\n // page and return\r\n const paged = nodes.slice(\r\n (pageNumber - 1) * pageSize,\r\n pageNumber * pageSize,\r\n );\r\n return of({\r\n items: paged,\r\n pageNumber: pageNumber,\r\n pageSize: pageSize,\r\n pageCount: Math.ceil(nodes.length / pageSize),\r\n total: nodes.length,\r\n });\r\n }\r\n}\r\n","import {\r\n Component,\r\n OnDestroy,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { Subscription } from 'rxjs';\r\n\r\nimport { MatDialog } from '@angular/material/dialog';\r\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatCheckboxModule } from '@angular/material/checkbox';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\n\r\nimport {\r\n BrowserTreeNodeComponent,\r\n PagedTreeStore,\r\n PageChangeRequest,\r\n} from '@myrmidon/paged-data-browsers';\r\n\r\nimport {\r\n renderLabelFromLastColon,\r\n StaticThesaurusPagedTreeStoreService,\r\n ThesaurusEntryNodeFilter,\r\n ThesaurusEntryPagedTreeNode,\r\n} from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport { ThesaurusPagedTreeFilterComponent }\r\n from '../thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\n\r\n/**\r\n * A readonly paged tree browser for thesaurus entries. This is a lower-level component\r\n * used as an adapter between the generic paged tree browser and the thesaurus entries\r\n * data model.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-browser',\r\n imports: [\r\n ReactiveFormsModule,\r\n MatButtonModule,\r\n MatCheckboxModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatProgressBarModule,\r\n MatTooltipModule,\r\n ThesaurusPagedTreeFilterComponent,\r\n BrowserTreeNodeComponent,\r\n ],\r\n templateUrl: './thesaurus-browser.component.html',\r\n styleUrl: './thesaurus-browser.component.scss',\r\n})\r\nexport class ThesaurusBrowserComponent implements OnDestroy {\r\n private _dialog = inject(MatDialog);\r\n private _nodesSub?: Subscription;\r\n private _filterSub?: Subscription;\r\n\r\n /**\r\n * The service to use to load the nodes.\r\n */\r\n public readonly service = input<StaticThesaurusPagedTreeStoreService>(\r\n new StaticThesaurusPagedTreeStoreService([], renderLabelFromLastColon)\r\n );\r\n\r\n /**\r\n * Emitted when a node is clicked.\r\n */\r\n public readonly nodePick = output<ThesaurusEntryPagedTreeNode>();\r\n\r\n /**\r\n * The store instance, built from the service.\r\n */\r\n public readonly store = computed(() => {\r\n const service = this.service();\r\n return new PagedTreeStore<\r\n ThesaurusEntryPagedTreeNode,\r\n ThesaurusEntryNodeFilter\r\n >(service);\r\n });\r\n\r\n public readonly loading = signal<boolean>(false);\r\n\r\n // Signals for reactive data binding (replacing observables with async pipe)\r\n public readonly nodes = signal<readonly ThesaurusEntryPagedTreeNode[]>([]);\r\n public readonly filter = signal<Readonly<ThesaurusEntryNodeFilter>>({});\r\n\r\n public debug: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideLoc: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n public hideFilter: FormControl<boolean> = new FormControl(false, {\r\n nonNullable: true,\r\n });\r\n\r\n public label: FormControl<string | null> = new FormControl(null);\r\n public form = new FormGroup({\r\n label: this.label,\r\n });\r\n\r\n constructor() {\r\n // Use effect to react to service/store changes\r\n effect(() => {\r\n const currentStore = this.store();\r\n\r\n // Unsubscribe from previous store's observables\r\n this._nodesSub?.unsubscribe();\r\n this._filterSub?.unsubscribe();\r\n\r\n // Subscribe to new store's observables and update signals\r\n this._nodesSub = currentStore.nodes$.subscribe((nodes) => {\r\n this.nodes.set(nodes);\r\n });\r\n this._filterSub = currentStore.filter$.subscribe((filter) => {\r\n this.filter.set(filter);\r\n });\r\n\r\n // Load nodes if store is empty\r\n if (!currentStore.getNodes().length) {\r\n this.loading.set(true);\r\n currentStore.setFilter({}).finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n });\r\n }\r\n\r\n public ngOnDestroy(): void {\r\n this._nodesSub?.unsubscribe();\r\n this._filterSub?.unsubscribe();\r\n }\r\n\r\n public reset(): void {\r\n this.loading.set(true);\r\n this.store()\r\n .reset()\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void {\r\n this.loading.set(true);\r\n if (node.expanded) {\r\n this.store()\r\n .collapse(node.id)\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n } else {\r\n this.store()\r\n .expand(node.id)\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n }\r\n\r\n public onPageChangeRequest(request: PageChangeRequest): void {\r\n this.loading.set(true);\r\n this.store()\r\n .changePage(request.node.id, request.paging.pageNumber)\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onFilterChange(filter: ThesaurusEntryNodeFilter | null | undefined): void {\r\n console.log('filter change', filter);\r\n this.loading.set(true);\r\n this.store()\r\n .setFilter(filter || {})\r\n .finally(() => {\r\n this.loading.set(false);\r\n });\r\n }\r\n\r\n public onEditFilterRequest(node: ThesaurusEntryPagedTreeNode): void {\r\n const dialogRef = this._dialog.open(ThesaurusPagedTreeFilterComponent, {\r\n data: {\r\n filter: node.filter,\r\n },\r\n });\r\n dialogRef.afterClosed().subscribe((filter) => {\r\n // undefined = user dismissed without changes\r\n if (filter === null) {\r\n this.store().setNodeFilter(node.id, null);\r\n } else if (filter) {\r\n this.store().setNodeFilter(node.id, filter);\r\n }\r\n });\r\n }\r\n\r\n public expandAll(): void {\r\n this.store().expandAll();\r\n }\r\n\r\n public collapseAll(): void {\r\n this.store().collapseAll();\r\n }\r\n\r\n public clear(): void {\r\n this.store().clear();\r\n }\r\n\r\n public onNodeClick(node: ThesaurusEntryPagedTreeNode): void {\r\n if (!node.hasChildren) {\r\n this.nodePick.emit(node);\r\n }\r\n }\r\n\r\n public findLabels(): void {\r\n if (!this.label.value) {\r\n return;\r\n }\r\n this.store().findLabels(this.label.value);\r\n }\r\n\r\n public removeHilites(): void {\r\n this.store().removeHilites();\r\n }\r\n}\r\n","<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\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"removeHilites()\"\r\n class=\"mat-warn\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </form>\r\n <fieldset>\r\n <legend>filter</legend>\r\n <cadmus-thesaurus-paged-tree-filter\r\n [filter]=\"filter()\"\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(); as nodeList) {\r\n <div>\r\n @for (node of nodeList; 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 < nodeList.length &&\r\n nodeList[i + 1].paging.pageCount > 1\r\n ? nodeList[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","import { Component, computed, input, output, Type } from '@angular/core';\r\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\n\r\nimport { ThesaurusPagedTreeFilterComponent } from '../thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\nimport {\r\n renderLabelFromLastColon,\r\n StaticThesaurusPagedTreeStoreService,\r\n ThesaurusEntryPagedTreeNode,\r\n} from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport { ThesaurusBrowserComponent } from '../thesaurus-browser/thesaurus-browser.component';\r\n\r\n/**\r\n * Thesaurus tree component.\r\n * This component displays a set of hierarchical thesaurus entries\r\n * in a tree, provided that each entry marks its hierarchy with\r\n * dots. For instance, say you have the hierarchy \"furniture\" -\r\n * \"type\" - \"color\". You might have an entry whose ID is\r\n * \"furniture.table.red\", with a sibling \"furniture.table.green\",\r\n * and a parent \"furniture.table\". This parent is there only to\r\n * provide a label to the parent node, but only leaf nodes can be\r\n * picked by the user. Whenever one is picked, the entryChange\r\n * event is emitted.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-tree',\r\n templateUrl: './thesaurus-tree.component.html',\r\n styleUrls: ['./thesaurus-tree.component.css'],\r\n imports: [FormsModule, ReactiveFormsModule, ThesaurusBrowserComponent],\r\n})\r\nexport class ThesaurusTreeComponent {\r\n /**\r\n * The thesaurus entries.\r\n */\r\n public readonly entries = input<ThesaurusEntry[]>();\r\n\r\n /**\r\n * The optional node label rendering function. Note that even if you\r\n * specify a label renderer function, the entryChange event always\r\n * emits the original label.\r\n */\r\n public readonly renderLabel = input<(label: string) => string>(\r\n renderLabelFromLastColon,\r\n );\r\n\r\n /**\r\n * Fired when a thesaurus entry is selected.\r\n */\r\n public readonly entryChange = output<ThesaurusEntry>();\r\n\r\n /**\r\n * The tree store service, dependent on the current entries and renderLabel.\r\n */\r\n public readonly service = computed<StaticThesaurusPagedTreeStoreService>(() => {\r\n const entries = this.entries();\r\n return new StaticThesaurusPagedTreeStoreService(\r\n entries || [],\r\n this.renderLabel(),\r\n );\r\n });\r\n\r\n /**\r\n * The filter component class to use.\r\n */\r\n public readonly filterComponent: Type<ThesaurusPagedTreeFilterComponent> =\r\n ThesaurusPagedTreeFilterComponent;\r\n\r\n public onNodePick(node: ThesaurusEntryPagedTreeNode): void {\r\n // only allow selection of leaf nodes (nodes without children)\r\n if (!node.hasChildren) {\r\n // find the original entry\r\n const entry = this.entries()?.find((e) => e.id === node.key);\r\n if (entry) {\r\n this.entryChange.emit(entry);\r\n }\r\n }\r\n }\r\n}\r\n","<div>\r\n <!-- tree -->\r\n @if (service() && entries()?.length) {\r\n <div class=\"tree-wrapper\">\r\n <cadmus-thesaurus-browser\r\n [service]=\"service()\"\r\n (nodePick)=\"onNodePick($event)\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n","import {\r\n Component,\r\n computed,\r\n effect,\r\n input,\r\n model,\r\n untracked,\r\n} from '@angular/core';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\nimport {\r\n FormBuilder,\r\n FormControl,\r\n FormGroup,\r\n ReactiveFormsModule,\r\n Validators,\r\n} from '@angular/forms';\r\n\r\nimport {\r\n CdkDragDrop,\r\n CdkDropList,\r\n CdkDrag,\r\n moveItemInArray,\r\n} from '@angular/cdk/drag-drop';\r\nimport {\r\n MatChipListbox,\r\n MatChipOption,\r\n MatChipRemove,\r\n} from '@angular/material/chips';\r\nimport { MatExpansionPanel } from '@angular/material/expansion';\r\nimport { MatFormField } from '@angular/material/form-field';\r\nimport { MatIcon } from '@angular/material/icon';\r\nimport { MatIconButton } from '@angular/material/button';\r\nimport { MatInput } from '@angular/material/input';\r\nimport { MatTooltip } from '@angular/material/tooltip';\r\n\r\nimport { renderLabelFromLastColon } from '../../services/static-thesaurus-paged-tree-store.service';\r\nimport { ThesaurusTreeComponent } from '../thesaurus-tree/thesaurus-tree.component';\r\n\r\n/**\r\n * The prefix added to custom entries' IDs.\r\n */\r\nexport const CUSTOM_ENTRY_PREFIX = '$';\r\n\r\n/**\r\n * A picker component for thesaurus entries.\r\n * This component allows picking one or more entries from a given thesaurus.\r\n * In its collapsed state, it shows the picked entries as chips; when\r\n * expanded, it shows the thesaurus tree to pick from. Custom entries\r\n * (not in the thesaurus) can be optionally allowed.\r\n */\r\n@Component({\r\n selector: 'cadmus-thesaurus-entries-picker',\r\n imports: [\r\n ReactiveFormsModule,\r\n CdkDropList,\r\n CdkDrag,\r\n MatChipListbox,\r\n MatChipOption,\r\n MatChipRemove,\r\n MatExpansionPanel,\r\n MatFormField,\r\n MatIconButton,\r\n MatIcon,\r\n MatInput,\r\n MatTooltip,\r\n ThesaurusTreeComponent,\r\n ],\r\n templateUrl: './thesaurus-entries-picker.component.html',\r\n styleUrl: './thesaurus-entries-picker.component.css',\r\n})\r\nexport class ThesaurusEntriesPickerComponent {\r\n /**\r\n * The thesaurus entries to pick from (required).\r\n */\r\n public readonly availableEntries = input.required<ThesaurusEntry[]>();\r\n\r\n /**\r\n * The picked entries.\r\n */\r\n public readonly entries = model<ThesaurusEntry[]>([]);\r\n\r\n /**\r\n * True to show the entries with labels shortened according to\r\n * their hierarchy.\r\n */\r\n public readonly hierarchicLabels = input<boolean>(false);\r\n\r\n /**\r\n * True to automatically sort the picked entries (disables drag-and-drop).\r\n * When false, entries can be manually reordered via drag-and-drop.\r\n */\r\n public readonly autoSort = input<boolean>(false);\r\n\r\n /**\r\n * True to allow custom values (not in the entries list).\r\n */\r\n public readonly allowCustom = input<boolean>(false);\r\n\r\n /**\r\n * The minimum number of entries to pick.\r\n */\r\n public readonly minEntries = input<number>(0);\r\n\r\n /**\r\n * The maximum number of entries to pick (0=unlimited).\r\n */\r\n public readonly maxEntries = input<number>(0);\r\n\r\n /**\r\n * True when the picker is expanded (showing the entries list).\r\n */\r\n public readonly expanded = model<boolean>(false);\r\n\r\n /**\r\n * The message to show when there are no picked entries.\r\n */\r\n public readonly emptyMessage = input<string>('no entries');\r\n\r\n /**\r\n * The number of remaining entries that can be picked (0=unlimited).\r\n * This is displayed only if maxEntries > 1.\r\n */\r\n public readonly remaining = computed(() => {\r\n if (this.maxEntries() > 0) {\r\n return this.maxEntries() - this.entries().length;\r\n }\r\n return 0;\r\n });\r\n\r\n public id: FormControl<string>;\r\n public value: FormControl<string>;\r\n public form: FormGroup;\r\n\r\n constructor(formBuilder: FormBuilder) {\r\n this.id = formBuilder.control<string>('', {\r\n validators: [Validators.required, Validators.maxLength(100)],\r\n nonNullable: true,\r\n });\r\n this.value = formBuilder.control<string>('', {\r\n validators: [Validators.required, Validators.maxLength(500)],\r\n nonNullable: true,\r\n });\r\n this.form = formBuilder.group({\r\n id: this.id,\r\n value: this.value,\r\n });\r\n // if auto-sort is turned on and we have entries, sort them\r\n effect(() => {\r\n // only track autoSort() changes, not entries()\r\n const shouldSort = this.autoSort();\r\n\r\n if (shouldSort) {\r\n // use untracked to read entries without creating a dependency\r\n const currentEntries = untracked(() => this.entries());\r\n if (currentEntries.length > 1) {\r\n const entries = [...currentEntries];\r\n this.sortEntries(entries);\r\n this.entries.set(entries);\r\n }\r\n }\r\n });\r\n }\r\n\r\n // need arrow function to use 'this'\r\n public renderLabel = (label: string): string => {\r\n return this.hierarchicLabels() ? renderLabelFromLastColon(label) : label;\r\n };\r\n\r\n private sortEntries(entries: ThesaurusEntry[]) {\r\n entries.sort((a: ThesaurusEntry, b: ThesaurusEntry) => {\r\n const aIsCustom = a.id?.startsWith(CUSTOM_ENTRY_PREFIX) ?? false;\r\n const bIsCustom = b.id?.startsWith(CUSTOM_ENTRY_PREFIX) ?? false;\r\n if (aIsCustom !== bIsCustom) {\r\n // place custom entries after non-custom ones\r\n return aIsCustom ? 1 : -1;\r\n }\r\n // same kind: sort by label/value\r\n return a.value.localeCompare(b.value);\r\n });\r\n }\r\n\r\n public onEntryChange(entry: ThesaurusEntry): void {\r\n // check if already present\r\n if (this.entries().some((e: ThesaurusEntry) => e.id === entry.id)) {\r\n return;\r\n }\r\n // check if limit is reached\r\n if (this.maxEntries() && this.entries().length >= this.maxEntries()) {\r\n return;\r\n }\r\n\r\n const entries = [...this.entries()];\r\n entries.push(entry);\r\n if (this.autoSort()) {\r\n this.sortEntries(entries);\r\n }\r\n this.entries.set(entries);\r\n }\r\n\r\n public addCustomEntry(): void {\r\n if (this.form.invalid) {\r\n return;\r\n }\r\n\r\n // create the custom entry\r\n const customEntry: ThesaurusEntry = {\r\n id: CUSTOM_ENTRY_PREFIX + this.id.value,\r\n value: this.value.value,\r\n };\r\n\r\n // check if already present\r\n if (this.entries().some((e: ThesaurusEntry) => e.id === customEntry.id)) {\r\n return;\r\n }\r\n // check if limit is reached\r\n if (this.maxEntries() && this.entries().length >= this.maxEntries()) {\r\n return;\r\n }\r\n const entries = [...this.entries()];\r\n entries.push(customEntry);\r\n if (this.autoSort()) {\r\n this.sortEntries(entries);\r\n }\r\n this.entries.set(entries);\r\n this.form.reset();\r\n }\r\n\r\n public removeEntry(entry: ThesaurusEntry): void {\r\n const entries = [...this.entries().filter((e) => e.id !== entry.id)];\r\n this.entries.set(entries);\r\n }\r\n\r\n public clear(): void {\r\n this.entries.set([]);\r\n // if min > 0, expand the picker\r\n if (this.minEntries() > 0 && !this.expanded()) {\r\n setTimeout(() => {\r\n this.expanded.set(true);\r\n }, 0);\r\n }\r\n }\r\n\r\n public onDrop(event: CdkDragDrop<ThesaurusEntry[]>): void {\r\n const entries = [...this.entries()];\r\n moveItemInArray(entries, event.previousIndex, event.currentIndex);\r\n this.entries.set(entries);\r\n }\r\n}\r\n","<div id=\"container\">\r\n <!-- picked entries -->\r\n <div id=\"picked\" class=\"form-row\">\r\n <!-- count -->\r\n <span class=\"nr\" [class.error]=\"entries().length < minEntries()\">{{\r\n entries().length\r\n }}</span>\r\n <!-- max-->\r\n @if (maxEntries() > 1) {\r\n <span class=\"muted\">/{{ maxEntries() }}</span>\r\n @if (remaining()) {\r\n <span class=\"muted\">: -{{ remaining() }}</span>\r\n } }\r\n <!-- min -->\r\n @if (minEntries()) {\r\n <!-- min with error -->\r\n @if (entries().length < minEntries()) {\r\n <span class=\"error\"> (min {{ minEntries() }})</span>\r\n }\r\n <!-- min without error -->\r\n @else {\r\n <span class=\"muted\"> (min {{ minEntries() }})</span>\r\n } }\r\n <!-- list -->\r\n <mat-chip-listbox\r\n [cdkDropListDisabled]=\"autoSort()\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n class=\"chip-list\"\r\n >\r\n @for (e of entries(); track e.id; let idx = $index) {\r\n <div class=\"chip-wrapper\">\r\n <mat-chip-option\r\n [cdkDragDisabled]=\"autoSort()\"\r\n cdkDrag\r\n [class.error]=\"!allowCustom() && e.id.startsWith('$')\"\r\n >\r\n {{ renderLabel(e.value) }}\r\n <button\r\n type=\"button\"\r\n matChipRemove\r\n (click)=\"removeEntry(e)\"\r\n aria-label=\"Remove entry\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-chip-option>\r\n </div>\r\n } @empty {\r\n <span class=\"muted empty-message\">{{ emptyMessage() }}</span>\r\n }\r\n </mat-chip-listbox>\r\n\r\n <!-- clear -->\r\n @if (entries().length > 0) {\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove all entries\"\r\n (click)=\"clear()\"\r\n [disabled]=\"entries().length === 0\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n }\r\n <!-- toggler -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Toggle picker\"\r\n (click)=\"expanded.set(!expanded())\"\r\n >\r\n @if (expanded()) {\r\n <mat-icon class=\"mat-primary\">publish</mat-icon>\r\n } @if (!expanded()) {\r\n <mat-icon class=\"mat-primary\">get_app</mat-icon>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- entries picker -->\r\n <div id=\"picker\">\r\n <mat-expansion-panel\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"expanded.set($event)\"\r\n >\r\n <div>\r\n <fieldset>\r\n <legend>available</legend>\r\n <cadmus-thesaurus-tree\r\n [entries]=\"availableEntries()\"\r\n [renderLabel]=\"renderLabel\"\r\n (entryChange)=\"onEntryChange($event)\"\r\n />\r\n </fieldset>\r\n </div>\r\n @if (allowCustom()) {\r\n <div>\r\n <form [formGroup]=\"form\" (submit)=\"addCustomEntry()\">\r\n <fieldset>\r\n <legend>custom</legend>\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"id\"\r\n placeholder=\"ID\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field>\r\n <input\r\n matInput\r\n type=\"text\"\r\n [formControl]=\"value\"\r\n placeholder=\"label\"\r\n />\r\n </mat-form-field>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Add custom entry\"\r\n [disabled]=\"\r\n !form.valid ||\r\n (maxEntries() > 0 && entries().length >= maxEntries())\r\n \"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n </div>\r\n }\r\n </mat-expansion-panel>\r\n </div>\r\n</div>\r\n","import { Observable, of } from 'rxjs';\r\n\r\nimport { DataPage } from '@myrmidon/ngx-tools';\r\n\r\nimport {\r\n EditablePagedTreeStoreServiceBase,\r\n ChangeOperation,\r\n ChangeOperationType,\r\n TreeNode,\r\n} from '@myrmidon/paged-data-browsers';\r\nimport { ThesaurusEntry } from '@myrmidon/cadmus-core';\r\n\r\nimport {\r\n StaticThesaurusPagedTreeStoreService,\r\n ThesaurusEntryNodeFilter,\r\n ThesaurusEntryPagedTreeNode,\r\n} from './static-thesaurus-paged-tree-store.service';\r\n\r\n/**\r\n * Editable version of the static thesaurus paged tree store service.\r\n * This service allows editing operations on the flat ThesaurusEntry list\r\n * while maintaining the tree structure implied by the hierarchical IDs.\r\n */\r\nexport class EditableStaticThesaurusPagedTreeStoreService\r\n extends EditablePagedTreeStoreServiceBase<ThesaurusEntryNodeFilter> {\r\n private _entries: ThesaurusEntry[];\r\n private _staticService: StaticThesaurusPagedTreeStoreService;\r\n private _renderLabel?: (label: string) => string;\r\n\r\n constructor(\r\n entries: ThesaurusEntry[],\r\n renderLabel?: (label: string) => string,\r\n ) {\r\n super();\r\n this._entries = [...entries];\r\n this._renderLabel = renderLabel;\r\n this._staticService = new StaticThesaurusPagedTreeStoreService(\r\n this._entries,\r\n renderLabel,\r\n );\r\n }\r\n\r\n protected override fetchNodes(\r\n filter: ThesaurusEntryNodeFilter,\r\n pageNumber: number,\r\n pageSize: number,\r\n hasMockRoot?: boolean,\r\n ): Observable<DataPage<TreeNode>> {\r\n // update the static service with current entries and delegate,\r\n // preserving the renderLabel function\r\n this._staticService = new StaticThesaurusPagedTreeStoreService(\r\n this._entries,\r\n this._renderLabel,\r\n );\r\n return this._staticService.getNodes(\r\n filter,\r\n pageNumber,\r\n pageSize,\r\n hasMockRoot,\r\n );\r\n }\r\n\r\n protected override persistChanges(\r\n changes: ChangeOperation[],\r\n ): Observable<Map<number, number>> {\r\n console.log('=== SAVING CHANGES ===');\r\n console.log('Changes to persist:', changes);\r\n\r\n const idMap = new Map<number, number>();\r\n\r\n // process changes to update the flat entries list\r\n for (const change of changes) {\r\n switch (change.type) {\r\n case ChangeOperationType.ADD:\r\n if (change.node) {\r\n const newEntry = this.nodeToEntry(change.node);\r\n if (newEntry) {\r\n const existingIndex = this._entries.findIndex(\r\n (e) => e.id === newEntry.id,\r\n );\r\n if (existingIndex === -1) {\r\n this._entries.push(newEntry);\r\n\r\n // map temporary ID to the new permanent ID (array index + 1)\r\n if (change.node.id < 0) {\r\n const permanentId = this._entries.length;\r\n idMap.set(change.node.id, permanentId);\r\n }\r\n console.log('Added entry:', newEntry);\r\n } else {\r\n console.log('Entry already exists, skipping:', newEntry.id);\r\n }\r\n }\r\n }\r\n break;\r\n\r\n case ChangeOperationType.REMOVE:\r\n if (change.originalNode) {\r\n // use the 'key' property which contains the ThesaurusEntry string ID\r\n const nodeWithKey =\r\n change.originalNode as ThesaurusEntryPagedTreeNode;\r\n const entryKey = nodeWithKey.key;\r\n\r\n if (entryKey) {\r\n this.removeEntryAndDescendants(entryKey);\r\n console.log('Removed entry and descendants:', entryKey);\r\n } else {\r\n console.warn('Node missing key property:', change.originalNode);\r\n }\r\n } else if (change.id < 0) {\r\n console.log(\r\n 'Removed temporary node that was never persisted:',\r\n change.id,\r\n );\r\n } else {\r\n console.warn(\r\n 'Remove operation missing originalNode for ID:',\r\n change.id,\r\n );\r\n }\r\n break;\r\n\r\n case ChangeOperationType.UPDATE:\r\n if (change.node && change.originalNode) {\r\n const nodeWithKey =\r\n change.originalNode as ThesaurusEntryPagedTreeNode;\r\n const entryKey = nodeWithKey.key;\r\n\r\n if (entryKey) {\r\n const entryToUpdate = this._entries.find(\r\n (e) => e.id === entryKey,\r\n );\r\n\r\n if (entryToUpdate) {\r\n const updatedEntry = this.nodeToEntry(change.node);\r\n if (updatedEntry) {\r\n // preserve the original hierarchical ID\r\n updatedEntry.id = entryToUpdate.id;\r\n const index = this._entries.findIndex(\r\n (e) => e.id === entryToUpdate.id,\r\n );\r\n if (index !== -1) {\r\n this._entries[index] = updatedEntry;\r\n console.log('Updated entry:', updatedEntry);\r\n }\r\n }\r\n } else {\r\n console.warn(\r\n 'Could not find entry to update with key:',\r\n entryKey,\r\n );\r\n }\r\n } else {\r\n console.warn(\r\n 'Update node missing key property:',\r\n change.originalNode,\r\n );\r\n }\r\n } else if (change.id < 0) {\r\n console.log('Updated temporary node:', change.id);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n // Validate no duplicate IDs\r\n const ids = this._entries.map((e) => e.id);\r\n const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);\r\n if (duplicates.length > 0) {\r\n console.error('Duplicate IDs found:', duplicates);\r\n }\r\n\r\n console.log('Final entries after changes:', this._entries);\r\n console.log('ID mappings:', idMap);\r\n console.log('=== END SAVING CHANGES ===');\r\n\r\n return of(idMap);\r\n }\r\n\r\n /**\r\n * Convert a TreeNode back to a ThesaurusEntry.\r\n */\r\n private nodeToEntry(node: TreeNode): ThesaurusEntry | null {\r\n // For nodes with the key property, use it directly\r\n const nodeWithKey = node as any;\r\n if (nodeWithKey.key) {\r\n return {\r\n id: nodeWithKey.key,\r\n value: node.label,\r\n };\r\n }\r\n\r\n // For temporary nodes (negative IDs), construct a hierarchical ID\r\n if (node.id < 0) {\r\n // Check for user-provided ID\r\n const userProvidedId = nodeWithKey._userProvidedId;\r\n\r\n if (userProvidedId) {\r\n return {\r\n id: userProvidedId,\r\n value: node.label,\r\n };\r\n }\r\n\r\n // Find parent to construct the ID\r\n if (node.parentId) {\r\n const parentNode = this._nodes.get(node.parentId) as any;\r\n const parentKey = parentNode?.key;\r\n if (parentKey) {\r\n return {\r\n id: `${parentKey}.temp${Math.abs(node.id)}`,\r\n value: node.label,\r\n };\r\n }\r\n }\r\n\r\n // No parent, create a root-level temporary entry\r\n return {\r\n id: `temp${Math.abs(node.id)}`,\r\n value: node.label,\r\n };\r\n }\r\n\r\n console.warn('Could not convert node to entry:', node);\r\n return null;\r\n }\r\n\r\n /**\r\n * Remove an entry and all its descendants from the entries list.\r\n */\r\n private removeEntryAndDescendants(entryId: string): void {\r\n const toRemove: string[] = [];\r\n\r\n // find the entry and all its descendants\r\n for (const entry of this._entries) {\r\n if (entry.id === entryId || entry.id.startsWith(entryId + '.')) {\r\n toRemove.push(entry.id);\r\n }\r\n }\r\n\r\n // remove them from the list\r\n for (const id of toRemove) {\r\n const index = this._entries.findIndex((e) => e.id === id);\r\n if (index !== -1) {\r\n this._entries.splice(index, 1);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get current entries (for demonstration purposes).\r\n */\r\n public getCurrentEntries(): ThesaurusEntry[] {\r\n return [...this._entries];\r\n }\r\n}\r\n","/*\r\n * Public API Surface of cadmus-thesaurus-store\r\n */\r\n\r\nexport * from './lib/components/editable-thesaurus-browser/editable-thesaurus-browser.component';\r\nexport * from './lib/components/thesaurus-entries-picker/thesaurus-entries-picker.component';\r\nexport * from './lib/components/thesaurus-entry-editor/thesaurus-entry-editor.component';\r\nexport * from './lib/components/thesaurus-browser/thesaurus-browser.component';\r\nexport * from './lib/components/thesaurus-paged-tree-filter/thesaurus-paged-tree-filter.component';\r\nexport * from './lib/components/thesaurus-tree/thesaurus-tree.component';\r\n\r\nexport * from './lib/services/editable-static-thesaurus-paged-tree-store.service';\r\nexport * from './lib/services/static-thesaurus-paged-tree-store.service';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i3","i4","i6","i2","i7"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myrmidon/cadmus-thesaurus-store",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Cadmus thesauri store components.",
5
5
  "keywords": [
6
6
  "Cadmus"
@@ -1,8 +1,8 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { OnInit, OnDestroy, Type } from '@angular/core';
2
+ import { OnDestroy, OnInit, Type } from '@angular/core';
3
3
  import { FormControl, FormGroup, FormBuilder } from '@angular/forms';
4
- import { Observable } from 'rxjs';
5
4
  import { TreeNodeFilter, PagedTreeNode, PagedTreeStoreService, EditablePagedTreeStoreServiceBase, TreeNode, ChangeOperation, PagedTreeStore, PageChangeRequest } from '@myrmidon/paged-data-browsers';
5
+ import { Observable } from 'rxjs';
6
6
  import { DataPage } from '@myrmidon/ngx-tools';
7
7
  import { ThesaurusEntry } from '@myrmidon/cadmus-core';
8
8
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
@@ -102,11 +102,13 @@ declare class EditableStaticThesaurusPagedTreeStoreService extends EditablePaged
102
102
  * and when complete, the changes can be committed to the underlying data store
103
103
  * via the EditableStaticThesaurusPagedTreeStoreService.
104
104
  */
105
- declare class EditableThesaurusBrowserComponent implements OnInit, OnDestroy {
105
+ declare class EditableThesaurusBrowserComponent implements OnDestroy {
106
106
  private _dialog;
107
107
  private _snackBar;
108
108
  private _dialogService;
109
- private _sub?;
109
+ private _nodesSub?;
110
+ private _filterSub?;
111
+ private _changesSub?;
110
112
  /**
111
113
  * The editable service to use to load the nodes.
112
114
  */
@@ -129,16 +131,16 @@ declare class EditableThesaurusBrowserComponent implements OnInit, OnDestroy {
129
131
  readonly store: _angular_core.Signal<PagedTreeStore<ThesaurusEntryPagedTreeNode, ThesaurusEntryNodeFilter> | null>;
130
132
  readonly loading: _angular_core.WritableSignal<boolean>;
131
133
  readonly selectedNode: _angular_core.WritableSignal<ThesaurusEntryPagedTreeNode | null>;
134
+ readonly nodes: _angular_core.WritableSignal<readonly ThesaurusEntryPagedTreeNode[]>;
135
+ readonly filter: _angular_core.WritableSignal<Readonly<ThesaurusEntryNodeFilter>>;
132
136
  debug: FormControl<boolean>;
133
137
  hideLoc: FormControl<boolean>;
134
138
  hideFilter: FormControl<boolean>;
135
- filter$: Observable<Readonly<ThesaurusEntryNodeFilter>>;
136
- nodes$: Observable<Readonly<ThesaurusEntryPagedTreeNode[]>>;
137
139
  label: FormControl<string | null>;
138
140
  form: FormGroup<{
139
141
  label: FormControl<string | null>;
140
142
  }>;
141
- ngOnInit(): void;
143
+ constructor();
142
144
  ngOnDestroy(): void;
143
145
  reset(): void;
144
146
  onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void;
@@ -285,9 +287,10 @@ declare class ThesEntryEditorComponent {
285
287
  * used as an adapter between the generic paged tree browser and the thesaurus entries
286
288
  * data model.
287
289
  */
288
- declare class ThesaurusBrowserComponent implements OnInit, OnDestroy {
290
+ declare class ThesaurusBrowserComponent implements OnDestroy {
289
291
  private _dialog;
290
- private _sub?;
292
+ private _nodesSub?;
293
+ private _filterSub?;
291
294
  /**
292
295
  * The service to use to load the nodes.
293
296
  */
@@ -301,17 +304,16 @@ declare class ThesaurusBrowserComponent implements OnInit, OnDestroy {
301
304
  */
302
305
  readonly store: _angular_core.Signal<PagedTreeStore<ThesaurusEntryPagedTreeNode, ThesaurusEntryNodeFilter>>;
303
306
  readonly loading: _angular_core.WritableSignal<boolean>;
307
+ readonly nodes: _angular_core.WritableSignal<readonly ThesaurusEntryPagedTreeNode[]>;
308
+ readonly filter: _angular_core.WritableSignal<Readonly<ThesaurusEntryNodeFilter>>;
304
309
  debug: FormControl<boolean>;
305
310
  hideLoc: FormControl<boolean>;
306
311
  hideFilter: FormControl<boolean>;
307
- filter$: Observable<Readonly<ThesaurusEntryNodeFilter>>;
308
- nodes$: Observable<Readonly<ThesaurusEntryPagedTreeNode[]>>;
309
312
  label: FormControl<string | null>;
310
313
  form: FormGroup<{
311
314
  label: FormControl<string | null>;
312
315
  }>;
313
316
  constructor();
314
- ngOnInit(): void;
315
317
  ngOnDestroy(): void;
316
318
  reset(): void;
317
319
  onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void;