@myrmidon/gve-core 2.0.0 → 3.0.3
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 +7 -16
- package/fesm2022/myrmidon-gve-core.mjs +843 -833
- package/fesm2022/myrmidon-gve-core.mjs.map +1 -1
- package/lib/components/animation-timeline/animation-timeline.component.d.ts +7 -10
- package/lib/components/animation-timeline-set/animation-timeline-set.component.d.ts +8 -11
- package/lib/components/animation-tween/animation-tween.component.d.ts +6 -8
- package/lib/components/base-text-char/base-text-char.component.d.ts +3 -6
- package/lib/components/base-text-editor/base-text-editor.component.d.ts +5 -7
- package/lib/components/base-text-view/base-text-view.component.d.ts +10 -14
- package/lib/components/batch-operation-editor/batch-operation-editor.component.d.ts +5 -7
- package/lib/components/chain-operation-editor/chain-operation-editor.component.d.ts +10 -14
- package/lib/components/chain-result-view/chain-result-view.component.d.ts +6 -10
- package/lib/components/chain-view/chain-view.component.d.ts +42 -0
- package/lib/components/feature-editor/feature-editor.component.d.ts +8 -12
- package/lib/components/feature-set-editor/feature-set-editor.component.d.ts +11 -13
- package/lib/components/feature-set-view/feature-set-view.component.d.ts +5 -7
- package/lib/components/ln-heights-editor/ln-heights-editor.component.d.ts +5 -8
- package/lib/components/operation-source-editor/operation-source-editor.component.d.ts +8 -11
- package/lib/components/snapshot-editor/snapshot-editor.component.d.ts +17 -25
- package/lib/components/snapshot-text-editor/snapshot-text-editor.component.d.ts +4 -6
- package/lib/components/steps-map/steps-map.component.d.ts +6 -10
- package/lib/services/gve-api.service.d.ts +37 -0
- package/lib/services/gve-graphviz.service.d.ts +20 -0
- package/package.json +2 -2
- package/public-api.d.ts +2 -1
- package/lib/components/simple-tree/simple-tree.component.d.ts +0 -35
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import { model, input, output, effect, Component, ViewChild, Injectable, Optional, Inject, computed, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { Validators, ReactiveFormsModule, FormControl, FormGroup, FormsModule } from '@angular/forms';
|
|
5
5
|
import * as i2 from '@angular/common';
|
|
@@ -18,7 +18,7 @@ import * as i6 from '@angular/material/input';
|
|
|
18
18
|
import { MatInputModule } from '@angular/material/input';
|
|
19
19
|
import * as i8 from '@angular/material/select';
|
|
20
20
|
import { MatSelectModule } from '@angular/material/select';
|
|
21
|
-
import * as
|
|
21
|
+
import * as i16 from '@angular/material/tabs';
|
|
22
22
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
23
23
|
import * as i10 from '@angular/material/tooltip';
|
|
24
24
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
@@ -35,17 +35,20 @@ import * as i1$1 from '@angular/common/http';
|
|
|
35
35
|
import { filter, debounceTime as debounceTime$1 } from 'rxjs/operators';
|
|
36
36
|
import * as i2$3 from '@angular/cdk/clipboard';
|
|
37
37
|
import { ClipboardModule } from '@angular/cdk/clipboard';
|
|
38
|
-
import * as
|
|
38
|
+
import * as i6$1 from '@angular/material/badge';
|
|
39
|
+
import { MatBadgeModule } from '@angular/material/badge';
|
|
40
|
+
import * as i17 from '@cisstech/nge/monaco';
|
|
39
41
|
import { NgeMonacoModule } from '@cisstech/nge/monaco';
|
|
40
42
|
import { customAlphabet } from 'nanoid';
|
|
43
|
+
import { VizComponent } from '@myrmidon/ngx-viz';
|
|
44
|
+
import * as i4$2 from '@angular/material/snack-bar';
|
|
45
|
+
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
41
46
|
import * as i8$1 from '@angular/material/button-toggle';
|
|
42
47
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
43
|
-
import * as
|
|
48
|
+
import * as i14 from '@angular/material/progress-bar';
|
|
44
49
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
45
|
-
import * as
|
|
50
|
+
import * as i15 from '@angular/material/slider';
|
|
46
51
|
import { MatSliderModule } from '@angular/material/slider';
|
|
47
|
-
import * as i5$2 from '@angular/material/snack-bar';
|
|
48
|
-
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
49
52
|
|
|
50
53
|
/**
|
|
51
54
|
* 🔑 `gve-animation-tween`
|
|
@@ -59,28 +62,24 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
|
59
62
|
* - 🔥 `tweenCancel` (`void`): emitted when the user cancels the edit.
|
|
60
63
|
*/
|
|
61
64
|
class AnimationTweenComponent {
|
|
62
|
-
/**
|
|
63
|
-
* The tween to edit.
|
|
64
|
-
*/
|
|
65
|
-
get tween() {
|
|
66
|
-
return this._tween;
|
|
67
|
-
}
|
|
68
|
-
set tween(value) {
|
|
69
|
-
if (this._tween === value) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
this._tween = value || undefined;
|
|
73
|
-
this.updateForm(this._tween);
|
|
74
|
-
}
|
|
75
65
|
constructor(formBuilder) {
|
|
66
|
+
/**
|
|
67
|
+
* The tween to edit.
|
|
68
|
+
*/
|
|
69
|
+
this.tween = model();
|
|
70
|
+
/**
|
|
71
|
+
* The IDs of the elements that can be selected by the tween.
|
|
72
|
+
* This list is used to allow the user to select an element from a dropdown.
|
|
73
|
+
*/
|
|
74
|
+
this.elementIds = input();
|
|
76
75
|
/**
|
|
77
76
|
* Emitted when the tween is changed.
|
|
78
77
|
*/
|
|
79
|
-
this.tweenChange =
|
|
78
|
+
this.tweenChange = output();
|
|
80
79
|
/**
|
|
81
80
|
* Emitted when the user cancels the edit.
|
|
82
81
|
*/
|
|
83
|
-
this.tweenCancel =
|
|
82
|
+
this.tweenCancel = output();
|
|
84
83
|
this.types = ['to', 'from', 'fromTo', 'set'];
|
|
85
84
|
this.label = formBuilder.control('', {
|
|
86
85
|
nonNullable: true,
|
|
@@ -108,6 +107,9 @@ class AnimationTweenComponent {
|
|
|
108
107
|
position: this.position,
|
|
109
108
|
});
|
|
110
109
|
this.elementId = formBuilder.control(null);
|
|
110
|
+
effect(() => {
|
|
111
|
+
this.updateForm(this.tween());
|
|
112
|
+
});
|
|
111
113
|
}
|
|
112
114
|
ngOnInit() {
|
|
113
115
|
// set selector when elementId changes
|
|
@@ -179,13 +181,13 @@ class AnimationTweenComponent {
|
|
|
179
181
|
if (!this.form.valid) {
|
|
180
182
|
return;
|
|
181
183
|
}
|
|
182
|
-
this.
|
|
183
|
-
this.tweenChange.emit(this.
|
|
184
|
+
this.tween.set(this.getTween());
|
|
185
|
+
this.tweenChange.emit(this.tween());
|
|
184
186
|
}
|
|
185
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
186
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
187
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AnimationTweenComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
188
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: AnimationTweenComponent, isStandalone: true, selector: "gve-animation-tween", inputs: { tween: { classPropertyName: "tween", publicName: "tween", isSignal: true, isRequired: false, transformFunction: null }, elementIds: { classPropertyName: "elementIds", publicName: "elementIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tween: "tweenChange", tweenChange: "tweenChange", tweenCancel: "tweenCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- label -->\r\n <mat-form-field>\r\n <mat-label>label</mat-label>\r\n <input matInput [formControl]=\"label\" />\r\n <mat-error\r\n *ngIf=\"$any(label).errors?.required && (label.dirty || label.touched)\"\r\n >label required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(label).errors?.maxLength && (label.dirty || label.touched)\"\r\n >label too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option *ngFor=\"let t of types\" [value]=\"t\">{{ t }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- position -->\r\n <mat-form-field>\r\n <mat-label>position</mat-label>\r\n <input matInput [formControl]=\"position\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n [attr.aria-label]=\"'Information about position'\"\r\n (click)=\"\r\n openUrl(\r\n 'https://gsap.com/docs/v3/GSAP/Timeline/#positioning-animations-in-a-timeline'\r\n )\r\n \"\r\n >\r\n <mat-icon>info</mat-icon>\r\n </button>\r\n <mat-hint>time label < > += -=</mat-hint>\r\n <mat-error\r\n *ngIf=\"\r\n $any(position).errors?.maxLength &&\r\n (position.dirty || position.touched)\r\n \"\r\n >position too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <div class=\"form-row\">\r\n <!-- selector -->\r\n <mat-form-field>\r\n <mat-label>selector</mat-label>\r\n <input matInput [formControl]=\"selector\" />\r\n <mat-hint>CSS selector</mat-hint>\r\n <mat-error\r\n *ngIf=\"\r\n $any(selector).errors?.required &&\r\n (selector.dirty || selector.touched)\r\n \"\r\n >selector required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(selector).errors?.maxLength &&\r\n (selector.dirty || selector.touched)\r\n \"\r\n >selector too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- element id -->\r\n @if ((elementIds())?.length) {\r\n <mat-form-field>\r\n <mat-label>element ID</mat-label>\r\n <mat-select [formControl]=\"elementId\">\r\n <mat-option *ngFor=\"let id of elementIds()\" [value]=\"id\">{{\r\n id\r\n }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n </div>\r\n\r\n <!-- note -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea rows=\"2\" matInput [formControl]=\"note\"></textarea>\r\n <mat-error\r\n *ngIf=\"$any(note).errors?.maxLength && (note.dirty || note.touched)\"\r\n >note too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error\r\n *ngIf=\"$any(vars).errors?.required && (vars.dirty || vars.touched)\"\r\n >vars required</mat-error\r\n >\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- vars2 only when type is fromTo -->\r\n @if (type.value === 'fromTo') {\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>2nd vars</mat-label>\r\n <textarea matInput [formControl]=\"vars2\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error\r\n *ngIf=\"$any(vars2).errors?.required && (vars2.dirty || vars2.touched)\"\r\n >vars required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(vars2).errors?.json && (vars2.dirty || vars2.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close tween\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-icon-button\r\n matTooltip=\"Save tween\"\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</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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],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: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
187
189
|
}
|
|
188
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AnimationTweenComponent, decorators: [{
|
|
189
191
|
type: Component,
|
|
190
192
|
args: [{ selector: 'gve-animation-tween', imports: [
|
|
191
193
|
CommonModule,
|
|
@@ -198,16 +200,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
198
200
|
MatSelectModule,
|
|
199
201
|
MatTabsModule,
|
|
200
202
|
MatTooltipModule,
|
|
201
|
-
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- label -->\r\n <mat-form-field>\r\n <mat-label>label</mat-label>\r\n <input matInput [formControl]=\"label\" />\r\n <mat-error\r\n *ngIf=\"$any(label).errors?.required && (label.dirty || label.touched)\"\r\n >label required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(label).errors?.maxLength && (label.dirty || label.touched)\"\r\n >label too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option *ngFor=\"let t of types\" [value]=\"t\">{{ t }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- position -->\r\n <mat-form-field>\r\n <mat-label>position</mat-label>\r\n <input matInput [formControl]=\"position\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n [attr.aria-label]=\"'Information about position'\"\r\n (click)=\"\r\n openUrl(\r\n 'https://gsap.com/docs/v3/GSAP/Timeline/#positioning-animations-in-a-timeline'\r\n )\r\n \"\r\n >\r\n <mat-icon>info</mat-icon>\r\n </button>\r\n <mat-hint>time label < > += -=</mat-hint>\r\n <mat-error\r\n *ngIf=\"\r\n $any(position).errors?.maxLength &&\r\n (position.dirty || position.touched)\r\n \"\r\n >position too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <div class=\"form-row\">\r\n <!-- selector -->\r\n <mat-form-field>\r\n <mat-label>selector</mat-label>\r\n <input matInput [formControl]=\"selector\" />\r\n <mat-hint>CSS selector</mat-hint>\r\n <mat-error\r\n *ngIf=\"\r\n $any(selector).errors?.required &&\r\n (selector.dirty || selector.touched)\r\n \"\r\n >selector required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(selector).errors?.maxLength &&\r\n (selector.dirty || selector.touched)\r\n \"\r\n >selector too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- element id -->\r\n @if (elementIds?.length) {\r\n <mat-form-field>\r\n <mat-label>element ID</mat-label>\r\n <mat-select [formControl]=\"elementId\">\r\n <mat-option *ngFor=\"let id of elementIds\" [value]=\"id\">{{\r\n id\r\n }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n </div>\r\n\r\n <!-- note -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea rows=\"2\" matInput [formControl]=\"note\"></textarea>\r\n <mat-error\r\n *ngIf=\"$any(note).errors?.maxLength && (note.dirty || note.touched)\"\r\n >note too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error\r\n *ngIf=\"$any(vars).errors?.required && (vars.dirty || vars.touched)\"\r\n >vars required</mat-error\r\n >\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- vars2 only when type is fromTo -->\r\n @if (type.value === 'fromTo') {\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>2nd vars</mat-label>\r\n <textarea matInput [formControl]=\"vars2\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error\r\n *ngIf=\"$any(vars2).errors?.required && (vars2.dirty || vars2.touched)\"\r\n >vars required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(vars2).errors?.json && (vars2.dirty || vars2.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close tween\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-icon-button\r\n matTooltip=\"Save tween\"\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</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}\n"] }]
|
|
202
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
203
|
-
type: Input
|
|
204
|
-
}], elementIds: [{
|
|
205
|
-
type: Input
|
|
206
|
-
}], tweenChange: [{
|
|
207
|
-
type: Output
|
|
208
|
-
}], tweenCancel: [{
|
|
209
|
-
type: Output
|
|
210
|
-
}] } });
|
|
203
|
+
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- label -->\r\n <mat-form-field>\r\n <mat-label>label</mat-label>\r\n <input matInput [formControl]=\"label\" />\r\n <mat-error\r\n *ngIf=\"$any(label).errors?.required && (label.dirty || label.touched)\"\r\n >label required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(label).errors?.maxLength && (label.dirty || label.touched)\"\r\n >label too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option *ngFor=\"let t of types\" [value]=\"t\">{{ t }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- position -->\r\n <mat-form-field>\r\n <mat-label>position</mat-label>\r\n <input matInput [formControl]=\"position\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n [attr.aria-label]=\"'Information about position'\"\r\n (click)=\"\r\n openUrl(\r\n 'https://gsap.com/docs/v3/GSAP/Timeline/#positioning-animations-in-a-timeline'\r\n )\r\n \"\r\n >\r\n <mat-icon>info</mat-icon>\r\n </button>\r\n <mat-hint>time label < > += -=</mat-hint>\r\n <mat-error\r\n *ngIf=\"\r\n $any(position).errors?.maxLength &&\r\n (position.dirty || position.touched)\r\n \"\r\n >position too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <div class=\"form-row\">\r\n <!-- selector -->\r\n <mat-form-field>\r\n <mat-label>selector</mat-label>\r\n <input matInput [formControl]=\"selector\" />\r\n <mat-hint>CSS selector</mat-hint>\r\n <mat-error\r\n *ngIf=\"\r\n $any(selector).errors?.required &&\r\n (selector.dirty || selector.touched)\r\n \"\r\n >selector required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(selector).errors?.maxLength &&\r\n (selector.dirty || selector.touched)\r\n \"\r\n >selector too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- element id -->\r\n @if ((elementIds())?.length) {\r\n <mat-form-field>\r\n <mat-label>element ID</mat-label>\r\n <mat-select [formControl]=\"elementId\">\r\n <mat-option *ngFor=\"let id of elementIds()\" [value]=\"id\">{{\r\n id\r\n }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n </div>\r\n\r\n <!-- note -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea rows=\"2\" matInput [formControl]=\"note\"></textarea>\r\n <mat-error\r\n *ngIf=\"$any(note).errors?.maxLength && (note.dirty || note.touched)\"\r\n >note too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error\r\n *ngIf=\"$any(vars).errors?.required && (vars.dirty || vars.touched)\"\r\n >vars required</mat-error\r\n >\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- vars2 only when type is fromTo -->\r\n @if (type.value === 'fromTo') {\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>2nd vars</mat-label>\r\n <textarea matInput [formControl]=\"vars2\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error\r\n *ngIf=\"$any(vars2).errors?.required && (vars2.dirty || vars2.touched)\"\r\n >vars required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(vars2).errors?.json && (vars2.dirty || vars2.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close tween\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-icon-button\r\n matTooltip=\"Save tween\"\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</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}\n"] }]
|
|
204
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
211
205
|
|
|
212
206
|
/**
|
|
213
207
|
* 🔑 `gve-animation-timeline`
|
|
@@ -224,29 +218,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
224
218
|
* - 🔥 `timelineCancel` (`void`): emitted when the timeline editing is canceled.
|
|
225
219
|
*/
|
|
226
220
|
class AnimationTimelineComponent {
|
|
227
|
-
/**
|
|
228
|
-
* The animation timeline to edit.
|
|
229
|
-
*/
|
|
230
|
-
get timeline() {
|
|
231
|
-
return this._timeline;
|
|
232
|
-
}
|
|
233
|
-
set timeline(value) {
|
|
234
|
-
this._timeline = value || undefined;
|
|
235
|
-
this.updateForm(this._timeline);
|
|
236
|
-
}
|
|
237
221
|
constructor(formBuilder) {
|
|
222
|
+
/**
|
|
223
|
+
* The animation timeline to edit.
|
|
224
|
+
*/
|
|
225
|
+
this.timeline = model();
|
|
226
|
+
/**
|
|
227
|
+
* The IDs of the elements that can be selected by the tween.
|
|
228
|
+
* This list is used to allow the user to select an element from a dropdown.
|
|
229
|
+
*/
|
|
230
|
+
this.elementIds = input();
|
|
238
231
|
/**
|
|
239
232
|
* The tags that can be used by the timeline.
|
|
240
233
|
*/
|
|
241
|
-
this.tags = [];
|
|
234
|
+
this.tags = input([]);
|
|
242
235
|
/**
|
|
243
236
|
* Emitted when the timeline is changed.
|
|
244
237
|
*/
|
|
245
|
-
this.timelineChange =
|
|
238
|
+
this.timelineChange = output();
|
|
246
239
|
/**
|
|
247
240
|
* Emitted when the timeline editing is canceled.
|
|
248
241
|
*/
|
|
249
|
-
this.timelineCancel =
|
|
242
|
+
this.timelineCancel = output();
|
|
250
243
|
this.editedTweenIndex = -1;
|
|
251
244
|
this.tag = formBuilder.control('', {
|
|
252
245
|
nonNullable: true,
|
|
@@ -262,6 +255,10 @@ class AnimationTimelineComponent {
|
|
|
262
255
|
tweens: this.tweens,
|
|
263
256
|
vars: this.vars,
|
|
264
257
|
});
|
|
258
|
+
// when the timeline changes, update the form
|
|
259
|
+
effect(() => {
|
|
260
|
+
this.updateForm(this.timeline());
|
|
261
|
+
});
|
|
265
262
|
}
|
|
266
263
|
jsonValidator(control) {
|
|
267
264
|
if (!control.value) {
|
|
@@ -355,14 +352,14 @@ class AnimationTimelineComponent {
|
|
|
355
352
|
if (this.form.invalid) {
|
|
356
353
|
return;
|
|
357
354
|
}
|
|
358
|
-
this.
|
|
359
|
-
this.timelineChange.emit(this.
|
|
355
|
+
this.timeline.set(this.getTimeline());
|
|
356
|
+
this.timelineChange.emit(this.timeline());
|
|
360
357
|
this.form.markAsPristine();
|
|
361
358
|
}
|
|
362
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
363
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: AnimationTimelineComponent, isStandalone: true, selector: "gve-animation-timeline", inputs: { timeline: "timeline", elementIds: "elementIds", tags: "tags" }, outputs: { timelineChange: "timelineChange", timelineCancel: "timelineCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- tag (bound) -->\r\n @if (tags.length) {\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n @for (t of tags; track t) {\r\n <mat-option [value]=\"t\">{{ t }}</mat-option>\r\n }\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n </mat-form-field>\r\n } @else {\r\n <!-- tag (free) -->\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <input matInput [formControl]=\"tag\" />\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.maxLength && (tag.dirty || tag.touched)\"\r\n >tag too long</mat-error\r\n >\r\n </mat-form-field>\r\n }\r\n\r\n <button\r\n mat-flat-button\r\n type=\"button\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addTween()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> tween\r\n </button>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- tweens -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>label</th>\r\n <th>type</th>\r\n <th>selector</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of tweens.value; track t; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"primary\"\r\n (click)=\"editTween(index)\"\r\n matTooltip=\"Edit tween\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"warn\"\r\n (click)=\"deleteTween(index)\"\r\n matTooltip=\"Delete tween\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n <!-- up -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenUp(index)\"\r\n matTooltip=\"Move tween up\"\r\n [disabled]=\"index === 0\"\r\n >\r\n <mat-icon>arrow_circle_up</mat-icon>\r\n </button>\r\n <!-- down -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenDown(index)\"\r\n matTooltip=\"Move tween down\"\r\n [disabled]=\"index === tweens.value.length - 1\"\r\n >\r\n <mat-icon>arrow_circle_down</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n {{ t.label }}\r\n </td>\r\n <td>\r\n {{ t.type }}\r\n </td>\r\n <td>\r\n {{ t.selector }}\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- tween editor -->\r\n <mat-expansion-panel [expanded]=\"editedTween\" [disabled]=\"!editedTween\">\r\n @if (editedTween) {\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>tween {{ editedTween.label }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n }\r\n <fieldset>\r\n <gve-animation-tween\r\n [elementIds]=\"elementIds\"\r\n [tween]=\"editedTween\"\r\n (tweenChange)=\"saveTween($event)\"\r\n (tweenCancel)=\"closeTween()\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- buttons -->\r\n <div class=\"button-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close timeline\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save timeline\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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],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: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: AnimationTweenComponent, selector: "gve-animation-tween", inputs: ["tween", "elementIds"], outputs: ["tweenChange", "tweenCancel"] }] }); }
|
|
359
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AnimationTimelineComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
360
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: AnimationTimelineComponent, isStandalone: true, selector: "gve-animation-timeline", inputs: { timeline: { classPropertyName: "timeline", publicName: "timeline", isSignal: true, isRequired: false, transformFunction: null }, elementIds: { classPropertyName: "elementIds", publicName: "elementIds", isSignal: true, isRequired: false, transformFunction: null }, tags: { classPropertyName: "tags", publicName: "tags", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timeline: "timelineChange", timelineChange: "timelineChange", timelineCancel: "timelineCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- tag (bound) -->\r\n @if (tags().length) {\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n @for (t of tags(); track t) {\r\n <mat-option [value]=\"t\">{{ t }}</mat-option>\r\n }\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n </mat-form-field>\r\n } @else {\r\n <!-- tag (free) -->\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <input matInput [formControl]=\"tag\" />\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.maxLength && (tag.dirty || tag.touched)\"\r\n >tag too long</mat-error\r\n >\r\n </mat-form-field>\r\n }\r\n\r\n <button\r\n mat-flat-button\r\n type=\"button\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addTween()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> tween\r\n </button>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- tweens -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>label</th>\r\n <th>type</th>\r\n <th>selector</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of tweens.value; track t; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"primary\"\r\n (click)=\"editTween(index)\"\r\n matTooltip=\"Edit tween\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"warn\"\r\n (click)=\"deleteTween(index)\"\r\n matTooltip=\"Delete tween\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n <!-- up -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenUp(index)\"\r\n matTooltip=\"Move tween up\"\r\n [disabled]=\"index === 0\"\r\n >\r\n <mat-icon>arrow_circle_up</mat-icon>\r\n </button>\r\n <!-- down -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenDown(index)\"\r\n matTooltip=\"Move tween down\"\r\n [disabled]=\"index === tweens.value.length - 1\"\r\n >\r\n <mat-icon>arrow_circle_down</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n {{ t.label }}\r\n </td>\r\n <td>\r\n {{ t.type }}\r\n </td>\r\n <td>\r\n {{ t.selector }}\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- tween editor -->\r\n <mat-expansion-panel [expanded]=\"editedTween\" [disabled]=\"!editedTween\">\r\n @if (editedTween) {\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>tween {{ editedTween.label }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n }\r\n <fieldset>\r\n <gve-animation-tween\r\n [elementIds]=\"elementIds()\"\r\n [tween]=\"editedTween\"\r\n (tweenChange)=\"saveTween($event)\"\r\n (tweenCancel)=\"closeTween()\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- buttons -->\r\n <div class=\"button-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close timeline\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save timeline\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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],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: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: AnimationTweenComponent, selector: "gve-animation-tween", inputs: ["tween", "elementIds"], outputs: ["tweenChange", "tweenCancel"] }] }); }
|
|
364
361
|
}
|
|
365
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
362
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AnimationTimelineComponent, decorators: [{
|
|
366
363
|
type: Component,
|
|
367
364
|
args: [{ selector: 'gve-animation-timeline', imports: [
|
|
368
365
|
CommonModule,
|
|
@@ -377,18 +374,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
377
374
|
MatTabsModule,
|
|
378
375
|
MatTooltipModule,
|
|
379
376
|
AnimationTweenComponent,
|
|
380
|
-
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- tag (bound) -->\r\n @if (tags.length) {\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n @for (t of tags; track t) {\r\n <mat-option [value]=\"t\">{{ t }}</mat-option>\r\n }\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n </mat-form-field>\r\n } @else {\r\n <!-- tag (free) -->\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <input matInput [formControl]=\"tag\" />\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.maxLength && (tag.dirty || tag.touched)\"\r\n >tag too long</mat-error\r\n >\r\n </mat-form-field>\r\n }\r\n\r\n <button\r\n mat-flat-button\r\n type=\"button\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addTween()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> tween\r\n </button>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- tweens -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>label</th>\r\n <th>type</th>\r\n <th>selector</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of tweens.value; track t; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"primary\"\r\n (click)=\"editTween(index)\"\r\n matTooltip=\"Edit tween\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"warn\"\r\n (click)=\"deleteTween(index)\"\r\n matTooltip=\"Delete tween\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n <!-- up -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenUp(index)\"\r\n matTooltip=\"Move tween up\"\r\n [disabled]=\"index === 0\"\r\n >\r\n <mat-icon>arrow_circle_up</mat-icon>\r\n </button>\r\n <!-- down -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenDown(index)\"\r\n matTooltip=\"Move tween down\"\r\n [disabled]=\"index === tweens.value.length - 1\"\r\n >\r\n <mat-icon>arrow_circle_down</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n {{ t.label }}\r\n </td>\r\n <td>\r\n {{ t.type }}\r\n </td>\r\n <td>\r\n {{ t.selector }}\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- tween editor -->\r\n <mat-expansion-panel [expanded]=\"editedTween\" [disabled]=\"!editedTween\">\r\n @if (editedTween) {\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>tween {{ editedTween.label }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n }\r\n <fieldset>\r\n <gve-animation-tween\r\n [elementIds]=\"elementIds\"\r\n [tween]=\"editedTween\"\r\n (tweenChange)=\"saveTween($event)\"\r\n (tweenCancel)=\"closeTween()\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- buttons -->\r\n <div class=\"button-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close timeline\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save timeline\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}\n"] }]
|
|
381
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
382
|
-
type: Input
|
|
383
|
-
}], elementIds: [{
|
|
384
|
-
type: Input
|
|
385
|
-
}], tags: [{
|
|
386
|
-
type: Input
|
|
387
|
-
}], timelineChange: [{
|
|
388
|
-
type: Output
|
|
389
|
-
}], timelineCancel: [{
|
|
390
|
-
type: Output
|
|
391
|
-
}] } });
|
|
377
|
+
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- tag (bound) -->\r\n @if (tags().length) {\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n @for (t of tags(); track t) {\r\n <mat-option [value]=\"t\">{{ t }}</mat-option>\r\n }\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n </mat-form-field>\r\n } @else {\r\n <!-- tag (free) -->\r\n <mat-form-field>\r\n <mat-label>tag</mat-label>\r\n <input matInput [formControl]=\"tag\" />\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.required && (tag.dirty || tag.touched)\"\r\n >tag required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(tag).errors?.maxLength && (tag.dirty || tag.touched)\"\r\n >tag too long</mat-error\r\n >\r\n </mat-form-field>\r\n }\r\n\r\n <button\r\n mat-flat-button\r\n type=\"button\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addTween()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> tween\r\n </button>\r\n </div>\r\n\r\n <!-- vars -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>vars</mat-label>\r\n <textarea matInput [formControl]=\"vars\"></textarea>\r\n <mat-hint>JSON object</mat-hint>\r\n <mat-error *ngIf=\"$any(vars).errors?.json && (vars.dirty || vars.touched)\"\r\n >invalid JSON</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- tweens -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>label</th>\r\n <th>type</th>\r\n <th>selector</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of tweens.value; track t; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"primary\"\r\n (click)=\"editTween(index)\"\r\n matTooltip=\"Edit tween\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n color=\"warn\"\r\n (click)=\"deleteTween(index)\"\r\n matTooltip=\"Delete tween\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n <!-- up -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenUp(index)\"\r\n matTooltip=\"Move tween up\"\r\n [disabled]=\"index === 0\"\r\n >\r\n <mat-icon>arrow_circle_up</mat-icon>\r\n </button>\r\n <!-- down -->\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"moveTweenDown(index)\"\r\n matTooltip=\"Move tween down\"\r\n [disabled]=\"index === tweens.value.length - 1\"\r\n >\r\n <mat-icon>arrow_circle_down</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n {{ t.label }}\r\n </td>\r\n <td>\r\n {{ t.type }}\r\n </td>\r\n <td>\r\n {{ t.selector }}\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- tween editor -->\r\n <mat-expansion-panel [expanded]=\"editedTween\" [disabled]=\"!editedTween\">\r\n @if (editedTween) {\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>tween {{ editedTween.label }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n }\r\n <fieldset>\r\n <gve-animation-tween\r\n [elementIds]=\"elementIds()\"\r\n [tween]=\"editedTween\"\r\n (tweenChange)=\"saveTween($event)\"\r\n (tweenCancel)=\"closeTween()\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- buttons -->\r\n <div class=\"button-row\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-icon-button\r\n matTooltip=\"Close timeline\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save timeline\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}\n"] }]
|
|
378
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
392
379
|
|
|
393
380
|
/**
|
|
394
381
|
* 🔑 `gve-base-text-char`
|
|
@@ -401,34 +388,25 @@ class BaseTextCharComponent {
|
|
|
401
388
|
this.defaultColor = '#D8D8D8';
|
|
402
389
|
this.defaultBorderColor = '#D8D8D8';
|
|
403
390
|
this.defaultEmSize = 1.5;
|
|
391
|
+
/**
|
|
392
|
+
* The character to display.
|
|
393
|
+
*/
|
|
394
|
+
this.char = input();
|
|
404
395
|
/**
|
|
405
396
|
* Emitted when the character is clicked.
|
|
406
397
|
*/
|
|
407
|
-
this.charPick =
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* The character to display.
|
|
411
|
-
*/
|
|
412
|
-
get char() {
|
|
413
|
-
return this._char;
|
|
414
|
-
}
|
|
415
|
-
set char(value) {
|
|
416
|
-
this._char = value || undefined;
|
|
398
|
+
this.charPick = output();
|
|
417
399
|
}
|
|
418
400
|
onCharClick(event) {
|
|
419
|
-
this.charPick.emit({ char: this.
|
|
401
|
+
this.charPick.emit({ char: this.char(), event });
|
|
420
402
|
}
|
|
421
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
422
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
403
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BaseTextCharComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
404
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: BaseTextCharComponent, isStandalone: true, selector: "gve-base-text-char", inputs: { char: { classPropertyName: "char", publicName: "char", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { charPick: "charPick" }, ngImport: i0, template: "@if (char()) {\r\n<div matRipple id=\"container\" (click)=\"onCharClick($event)\">\r\n <div\r\n id=\"c-label\"\r\n [style.fontSize]=\"char()!.emSize + 'em'\"\r\n [style.borderColor]=\"char()!.borderColor\"\r\n >\r\n {{ char()!.label }}\r\n </div>\r\n <div\r\n id=\"c-id\"\r\n [style.fontSize]=\"char()!.emSize / 2 + 'em'\"\r\n [style.color]=\"char()!.color | colorToContrast\"\r\n [style.borderColor]=\"char()!.borderColor\"\r\n [style.backgroundColor]=\"char()!.color\"\r\n >\r\n {{ char()!.id }}\r\n </div>\r\n</div>\r\n}\r\n", styles: ["div#container{cursor:pointer;flex-direction:column;align-items:center}div#c-label{border:1px solid silver;border-radius:6px;padding:6px;height:1.5em;align-items:center;justify-content:center;text-align:center}div#c-id{margin-top:4px;margin-bottom:16px;border:1px solid silver;border-radius:6px;padding:6px;align-items:center;justify-content:center;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "pipe", type: ColorToContrastPipe, name: "colorToContrast" }] }); }
|
|
423
405
|
}
|
|
424
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
406
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BaseTextCharComponent, decorators: [{
|
|
425
407
|
type: Component,
|
|
426
|
-
args: [{ selector: 'gve-base-text-char', imports: [MatRippleModule, ColorToContrastPipe], template: "@if (char) {\r\n<div matRipple id=\"container\" (click)=\"onCharClick($event)\">\r\n <div\r\n id=\"c-label\"\r\n [style.fontSize]=\"char
|
|
427
|
-
}]
|
|
428
|
-
type: Input
|
|
429
|
-
}], charPick: [{
|
|
430
|
-
type: Output
|
|
431
|
-
}] } });
|
|
408
|
+
args: [{ selector: 'gve-base-text-char', imports: [MatRippleModule, ColorToContrastPipe], template: "@if (char()) {\r\n<div matRipple id=\"container\" (click)=\"onCharClick($event)\">\r\n <div\r\n id=\"c-label\"\r\n [style.fontSize]=\"char()!.emSize + 'em'\"\r\n [style.borderColor]=\"char()!.borderColor\"\r\n >\r\n {{ char()!.label }}\r\n </div>\r\n <div\r\n id=\"c-id\"\r\n [style.fontSize]=\"char()!.emSize / 2 + 'em'\"\r\n [style.color]=\"char()!.color | colorToContrast\"\r\n [style.borderColor]=\"char()!.borderColor\"\r\n [style.backgroundColor]=\"char()!.color\"\r\n >\r\n {{ char()!.id }}\r\n </div>\r\n</div>\r\n}\r\n", styles: ["div#container{cursor:pointer;flex-direction:column;align-items:center}div#c-label{border:1px solid silver;border-radius:6px;padding:6px;height:1.5em;align-items:center;justify-content:center;text-align:center}div#c-id{margin-top:4px;margin-bottom:16px;border:1px solid silver;border-radius:6px;padding:6px;align-items:center;justify-content:center;text-align:center}\n"] }]
|
|
409
|
+
}] });
|
|
432
410
|
|
|
433
411
|
/**
|
|
434
412
|
* 🔑 `gve-base-text-view`
|
|
@@ -446,73 +424,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
446
424
|
*/
|
|
447
425
|
class BaseTextViewComponent {
|
|
448
426
|
constructor() {
|
|
449
|
-
this._text = [];
|
|
450
427
|
/**
|
|
451
428
|
* The default color for the text.
|
|
452
429
|
*/
|
|
453
|
-
this.defaultColor = '#DBDBDB';
|
|
430
|
+
this.defaultColor = input('#DBDBDB');
|
|
454
431
|
/**
|
|
455
432
|
* The default border color for the text.
|
|
456
433
|
*/
|
|
457
|
-
this.defaultBorderColor = '#DBDBDB';
|
|
434
|
+
this.defaultBorderColor = input('#DBDBDB');
|
|
458
435
|
/**
|
|
459
436
|
* The color for the selected text.
|
|
460
437
|
*/
|
|
461
|
-
this.selectionColor = '#3E92CC';
|
|
438
|
+
this.selectionColor = input('#3E92CC');
|
|
462
439
|
/**
|
|
463
440
|
* True if line numbers should be displayed next to each line.
|
|
464
441
|
*/
|
|
465
|
-
this.hasLineNumber = false;
|
|
442
|
+
this.hasLineNumber = input(false);
|
|
443
|
+
/**
|
|
444
|
+
* The text to display.
|
|
445
|
+
*/
|
|
446
|
+
this.text = input([]);
|
|
447
|
+
/**
|
|
448
|
+
* An optional callback to get the color of a character node.
|
|
449
|
+
* Return null to use the default color.
|
|
450
|
+
*/
|
|
451
|
+
this.borderColorCallback = input();
|
|
466
452
|
/**
|
|
467
453
|
* Emitted when a character is picked.
|
|
468
454
|
*/
|
|
469
|
-
this.charPick =
|
|
455
|
+
this.charPick = output();
|
|
470
456
|
/**
|
|
471
457
|
* Emitted when a range is picked. This is preceded by a character pick event.
|
|
472
458
|
* The range is defined by the starting character and the number of characters.
|
|
473
459
|
* The range is inclusive.
|
|
474
460
|
*/
|
|
475
|
-
this.rangePick =
|
|
461
|
+
this.rangePick = output();
|
|
476
462
|
this.lines = [];
|
|
463
|
+
// build lines when text or border color callback change
|
|
464
|
+
effect(() => {
|
|
465
|
+
this.buildLines(this.text(), this.borderColorCallback());
|
|
466
|
+
});
|
|
477
467
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
*/
|
|
481
|
-
get text() {
|
|
482
|
-
return this._text;
|
|
483
|
-
}
|
|
484
|
-
set text(value) {
|
|
485
|
-
this._text = value || [];
|
|
486
|
-
this.buildLines();
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* An optional callback to get the color of a character node.
|
|
490
|
-
* Return null to use the default color.
|
|
491
|
-
*/
|
|
492
|
-
get borderColorCallback() {
|
|
493
|
-
return this._borderColorCallback;
|
|
494
|
-
}
|
|
495
|
-
set borderColorCallback(value) {
|
|
496
|
-
this._borderColorCallback = value;
|
|
497
|
-
this.buildLines();
|
|
498
|
-
}
|
|
499
|
-
buildLines() {
|
|
500
|
-
if (!this._text) {
|
|
468
|
+
buildLines(text, borderColorCallback) {
|
|
469
|
+
if (!text) {
|
|
501
470
|
this.lines = [];
|
|
502
471
|
return;
|
|
503
472
|
}
|
|
504
473
|
const newLines = [];
|
|
505
474
|
newLines.push([]);
|
|
506
|
-
const nodes =
|
|
475
|
+
const nodes = text;
|
|
507
476
|
for (let i = 0; i < nodes.length; i++) {
|
|
508
477
|
const char = {
|
|
509
478
|
id: nodes[i].id,
|
|
510
479
|
value: nodes[i].data,
|
|
511
480
|
label: nodes[i].label,
|
|
512
|
-
color: this.defaultColor,
|
|
513
|
-
borderColor:
|
|
514
|
-
?
|
|
515
|
-
: this.defaultBorderColor,
|
|
481
|
+
color: this.defaultColor(),
|
|
482
|
+
borderColor: borderColorCallback
|
|
483
|
+
? borderColorCallback(nodes[i]) || this.defaultBorderColor()
|
|
484
|
+
: this.defaultBorderColor(),
|
|
516
485
|
emSize: 1.5,
|
|
517
486
|
};
|
|
518
487
|
newLines[newLines.length - 1].push(char);
|
|
@@ -525,8 +494,8 @@ class BaseTextViewComponent {
|
|
|
525
494
|
resetColors() {
|
|
526
495
|
for (const line of this.lines) {
|
|
527
496
|
for (const c of line) {
|
|
528
|
-
c.color = this.defaultColor;
|
|
529
|
-
c.borderColor = this.defaultBorderColor;
|
|
497
|
+
c.color = this.defaultColor();
|
|
498
|
+
c.borderColor = this.defaultBorderColor();
|
|
530
499
|
}
|
|
531
500
|
}
|
|
532
501
|
}
|
|
@@ -540,8 +509,8 @@ class BaseTextViewComponent {
|
|
|
540
509
|
for (const line of this.lines) {
|
|
541
510
|
for (const c of line) {
|
|
542
511
|
if (c.id >= minId && c.id <= maxId) {
|
|
543
|
-
c.color = this.selectionColor;
|
|
544
|
-
c.borderColor = this.selectionColor;
|
|
512
|
+
c.color = this.selectionColor();
|
|
513
|
+
c.borderColor = this.selectionColor();
|
|
545
514
|
}
|
|
546
515
|
}
|
|
547
516
|
}
|
|
@@ -551,36 +520,20 @@ class BaseTextViewComponent {
|
|
|
551
520
|
}
|
|
552
521
|
else {
|
|
553
522
|
// select current char
|
|
554
|
-
event.char.color = this.selectionColor;
|
|
555
|
-
event.char.borderColor = this.selectionColor;
|
|
523
|
+
event.char.color = this.selectionColor();
|
|
524
|
+
event.char.borderColor = this.selectionColor();
|
|
556
525
|
this.charPick.emit(event);
|
|
557
526
|
this.rangePick.emit({ at: event.char.id, run: 1 });
|
|
558
527
|
}
|
|
559
528
|
this._lastSelectedChar = event.char;
|
|
560
529
|
}
|
|
561
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
562
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
530
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BaseTextViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
531
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: BaseTextViewComponent, isStandalone: true, selector: "gve-base-text-view", inputs: { defaultColor: { classPropertyName: "defaultColor", publicName: "defaultColor", isSignal: true, isRequired: false, transformFunction: null }, defaultBorderColor: { classPropertyName: "defaultBorderColor", publicName: "defaultBorderColor", isSignal: true, isRequired: false, transformFunction: null }, selectionColor: { classPropertyName: "selectionColor", publicName: "selectionColor", isSignal: true, isRequired: false, transformFunction: null }, hasLineNumber: { classPropertyName: "hasLineNumber", publicName: "hasLineNumber", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, borderColorCallback: { classPropertyName: "borderColorCallback", publicName: "borderColorCallback", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { charPick: "charPick", rangePick: "rangePick" }, ngImport: i0, template: "<div id=\"text\">\r\n @for (line of lines; track $index) {\r\n <div class=\"line\">\r\n @if (hasLineNumber()) {\r\n <div class=\"nr\">\r\n {{ lines.indexOf(line) + 1 }}\r\n </div>\r\n } @for (c of line; track c.id) {\r\n <gve-base-text-char [char]=\"c\" (charPick)=\"onCharPick($event)\" />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".line{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.line *{flex:0 0 auto}.nr{font-size:.8em;font-weight:700;color:silver;margin:0 4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BaseTextCharComponent, selector: "gve-base-text-char", inputs: ["char"], outputs: ["charPick"] }] }); }
|
|
563
532
|
}
|
|
564
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
533
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BaseTextViewComponent, decorators: [{
|
|
565
534
|
type: Component,
|
|
566
|
-
args: [{ selector: 'gve-base-text-view', imports: [CommonModule, BaseTextCharComponent], template: "<div id=\"text\">\r\n @for (line of lines; track $index) {\r\n <div class=\"line\">\r\n @if (hasLineNumber) {\r\n <div class=\"nr\">\r\n {{ lines.indexOf(line) + 1 }}\r\n </div>\r\n } @for (c of line; track c.id) {\r\n <gve-base-text-char [char]=\"c\" (charPick)=\"onCharPick($event)\" />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".line{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.line *{flex:0 0 auto}.nr{font-size:.8em;font-weight:700;color:silver;margin:0 4px}\n"] }]
|
|
567
|
-
}],
|
|
568
|
-
type: Input
|
|
569
|
-
}], defaultBorderColor: [{
|
|
570
|
-
type: Input
|
|
571
|
-
}], selectionColor: [{
|
|
572
|
-
type: Input
|
|
573
|
-
}], hasLineNumber: [{
|
|
574
|
-
type: Input
|
|
575
|
-
}], text: [{
|
|
576
|
-
type: Input
|
|
577
|
-
}], borderColorCallback: [{
|
|
578
|
-
type: Input
|
|
579
|
-
}], charPick: [{
|
|
580
|
-
type: Output
|
|
581
|
-
}], rangePick: [{
|
|
582
|
-
type: Output
|
|
583
|
-
}] } });
|
|
535
|
+
args: [{ selector: 'gve-base-text-view', imports: [CommonModule, BaseTextCharComponent], template: "<div id=\"text\">\r\n @for (line of lines; track $index) {\r\n <div class=\"line\">\r\n @if (hasLineNumber()) {\r\n <div class=\"nr\">\r\n {{ lines.indexOf(line) + 1 }}\r\n </div>\r\n } @for (c of line; track c.id) {\r\n <gve-base-text-char [char]=\"c\" (charPick)=\"onCharPick($event)\" />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".line{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.line *{flex:0 0 auto}.nr{font-size:.8em;font-weight:700;color:silver;margin:0 4px}\n"] }]
|
|
536
|
+
}], ctorParameters: () => [] });
|
|
584
537
|
|
|
585
538
|
/**
|
|
586
539
|
* 🔑 `gve-feature-editor`
|
|
@@ -602,48 +555,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
602
555
|
* - 🔥 `featureCancel`: emitted when the user cancels the feature editing.
|
|
603
556
|
*/
|
|
604
557
|
class FeatureEditorComponent {
|
|
605
|
-
/**
|
|
606
|
-
* The feature values map. When specified and the user selects a feature
|
|
607
|
-
* name present in the map keys, the corresponding values will be used
|
|
608
|
-
* to populate the value selection.
|
|
609
|
-
*/
|
|
610
|
-
get featValues() {
|
|
611
|
-
return this._map;
|
|
612
|
-
}
|
|
613
|
-
set featValues(value) {
|
|
614
|
-
this._map = value || undefined;
|
|
615
|
-
this.nameIds = this.getLabeledIdsFor(this.name.value);
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* The feature to edit.
|
|
619
|
-
*/
|
|
620
|
-
get feature() {
|
|
621
|
-
return this._feature;
|
|
622
|
-
}
|
|
623
|
-
set feature(value) {
|
|
624
|
-
if (this._feature === value) {
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
this._feature = value || undefined;
|
|
628
|
-
this.updateForm(this._feature);
|
|
629
|
-
setTimeout(() => {
|
|
630
|
-
this.nameControl?.nativeElement?.focus();
|
|
631
|
-
}, 500);
|
|
632
|
-
}
|
|
633
558
|
constructor(formBuilder) {
|
|
559
|
+
/**
|
|
560
|
+
* The list of feature names to display in the name selection.
|
|
561
|
+
* This is used when you have a closed list of features.
|
|
562
|
+
*/
|
|
563
|
+
this.featNames = input();
|
|
564
|
+
/**
|
|
565
|
+
* The feature values map. When specified and the user selects a feature
|
|
566
|
+
* name present in the map keys, the corresponding values will be used
|
|
567
|
+
* to populate the value selection.
|
|
568
|
+
*/
|
|
569
|
+
this.featValues = input();
|
|
570
|
+
/**
|
|
571
|
+
* The feature to edit.
|
|
572
|
+
*/
|
|
573
|
+
this.feature = model();
|
|
634
574
|
/**
|
|
635
575
|
* True if the feature is a variant operation feature, which has
|
|
636
576
|
* additional properties like negation, global, and short-lived.
|
|
637
577
|
*/
|
|
638
|
-
this.isVar = false;
|
|
578
|
+
this.isVar = input(false);
|
|
639
579
|
/**
|
|
640
580
|
* Event emitted when the user cancels the feature editing.
|
|
641
581
|
*/
|
|
642
|
-
this.featureCancel =
|
|
582
|
+
this.featureCancel = output();
|
|
643
583
|
/**
|
|
644
584
|
* Event emitted when the user saves the edited feature.
|
|
645
585
|
*/
|
|
646
|
-
this.featureChange =
|
|
586
|
+
this.featureChange = output();
|
|
647
587
|
this.name = formBuilder.control('', {
|
|
648
588
|
validators: [Validators.required, Validators.maxLength(50)],
|
|
649
589
|
nonNullable: true,
|
|
@@ -666,26 +606,35 @@ class FeatureEditorComponent {
|
|
|
666
606
|
isGlobal: this.isGlobal,
|
|
667
607
|
isShortLived: this.isShortLived,
|
|
668
608
|
});
|
|
609
|
+
// when feature changes, update the form
|
|
610
|
+
effect(() => {
|
|
611
|
+
this.updateForm(this.feature());
|
|
612
|
+
setTimeout(() => {
|
|
613
|
+
this.nameControl?.nativeElement?.focus();
|
|
614
|
+
this.nameIds = this.getLabeledIdsFor(this.name.value, this.featValues());
|
|
615
|
+
}, 500);
|
|
616
|
+
});
|
|
669
617
|
}
|
|
670
618
|
ngOnInit() {
|
|
671
619
|
// whenever the name changes, update the value selection
|
|
672
620
|
this._sub = this.name.valueChanges
|
|
673
621
|
.pipe(debounceTime(300), distinctUntilChanged())
|
|
674
622
|
.subscribe((name) => {
|
|
675
|
-
if (!this._frozen && this.featNames?.length) {
|
|
623
|
+
if (!this._frozen && this.featNames()?.length) {
|
|
676
624
|
this.value.reset();
|
|
677
|
-
this.nameIds = this.getLabeledIdsFor(name);
|
|
625
|
+
this.nameIds = this.getLabeledIdsFor(name, this.featValues());
|
|
678
626
|
}
|
|
679
627
|
});
|
|
680
628
|
}
|
|
681
629
|
ngOnDestroy() {
|
|
682
630
|
this._sub?.unsubscribe();
|
|
683
631
|
}
|
|
684
|
-
getLabeledIdsFor(id) {
|
|
632
|
+
getLabeledIdsFor(id, featValues) {
|
|
685
633
|
if (!id) {
|
|
686
634
|
return undefined;
|
|
687
635
|
}
|
|
688
|
-
|
|
636
|
+
console.log('getLabeledIdsFor', id, featValues);
|
|
637
|
+
return featValues ? featValues[id] : undefined;
|
|
689
638
|
}
|
|
690
639
|
updateForm(feature) {
|
|
691
640
|
if (!feature) {
|
|
@@ -709,7 +658,7 @@ class FeatureEditorComponent {
|
|
|
709
658
|
if (!this.form.valid) {
|
|
710
659
|
return;
|
|
711
660
|
}
|
|
712
|
-
this.feature
|
|
661
|
+
this.feature.set(this.isVar()
|
|
713
662
|
? {
|
|
714
663
|
name: this.name.value.trim(),
|
|
715
664
|
value: this.value.value.trim(),
|
|
@@ -722,13 +671,13 @@ class FeatureEditorComponent {
|
|
|
722
671
|
name: this.name.value.trim(),
|
|
723
672
|
value: this.value.value.trim(),
|
|
724
673
|
setPolicy: this.setPolicy.value,
|
|
725
|
-
};
|
|
726
|
-
this.featureChange.emit(this.feature);
|
|
674
|
+
});
|
|
675
|
+
this.featureChange.emit(this.feature());
|
|
727
676
|
}
|
|
728
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
729
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
677
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: FeatureEditorComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
678
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: FeatureEditorComponent, isStandalone: true, selector: "gve-feature-editor", inputs: { featNames: { classPropertyName: "featNames", publicName: "featNames", isSignal: true, isRequired: false, transformFunction: null }, featValues: { classPropertyName: "featValues", publicName: "featValues", isSignal: true, isRequired: false, transformFunction: null }, feature: { classPropertyName: "feature", publicName: "feature", isSignal: true, isRequired: false, transformFunction: null }, isVar: { classPropertyName: "isVar", publicName: "isVar", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { feature: "featureChange", featureCancel: "featureCancel", featureChange: "featureChange" }, viewQueries: [{ propertyName: "nameControl", first: true, predicate: ["nameCtl"], descendants: true }], ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n @if (featNames()?.length) {\r\n <!-- name (bound) -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <mat-select #nameCtl [formControl]=\"name\">\r\n <mat-option *ngFor=\"let i of featNames()\" [value]=\"i.id\">{{\r\n i.label\r\n }}</mat-option>\r\n </mat-select>\r\n @if ($any(name).errors?.required && (name.dirty || name.touched)) {\r\n <mat-error>name required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- name (free) -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <input #nameCtl matInput [formControl]=\"name\" />\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >name required</mat-error\r\n >\r\n @if ($any(name).errors?.maxLength && (name.dirty || name.touched)) {\r\n <mat-error>name too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- value (bound) -->\r\n @if (nameIds?.length) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <mat-select [formControl]=\"value\">\r\n <mat-option *ngFor=\"let e of nameIds\" [value]=\"e.id\">{{\r\n e.label\r\n }}</mat-option>\r\n </mat-select>\r\n @if ($any(value).errors?.required && (value.dirty || value.touched)) {\r\n <mat-error>value required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- value (free) -->\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 <mat-error>value too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- setPolicy -->\r\n <mat-form-field>\r\n <mat-label>set policy</mat-label>\r\n <mat-select [formControl]=\"setPolicy\">\r\n <mat-option [value]=\"0\">multiple</mat-option>\r\n <mat-option [value]=\"1\">single</mat-option>\r\n <mat-option [value]=\"2\">single first</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n @if (isVar()) {\r\n <div class=\"form-row\">\r\n <!-- isNegated -->\r\n <mat-checkbox [formControl]=\"isNegated\">negated</mat-checkbox>\r\n\r\n <!-- isShortLived -->\r\n <mat-checkbox [formControl]=\"isShortLived\">short-lived</mat-checkbox>\r\n\r\n <!-- isGlobal -->\r\n <mat-checkbox [formControl]=\"isGlobal\">global</mat-checkbox>\r\n </div>\r\n }\r\n\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\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 color=\"primary\"\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</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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],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: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4$1.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: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
730
679
|
}
|
|
731
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
680
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: FeatureEditorComponent, decorators: [{
|
|
732
681
|
type: Component,
|
|
733
682
|
args: [{ selector: 'gve-feature-editor', imports: [
|
|
734
683
|
CommonModule,
|
|
@@ -740,22 +689,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
740
689
|
MatInputModule,
|
|
741
690
|
MatSelectModule,
|
|
742
691
|
MatTooltipModule,
|
|
743
|
-
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n @if (featNames?.length) {\r\n <!-- name (bound) -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <mat-select #nameCtl [formControl]=\"name\">\r\n <mat-option *ngFor=\"let i of featNames\" [value]=\"i.id\">{{\r\n i.label\r\n }}</mat-option>\r\n </mat-select>\r\n @if ($any(name).errors?.required && (name.dirty || name.touched)) {\r\n <mat-error>name required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- name (free) -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <input #nameCtl matInput [formControl]=\"name\" />\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >name required</mat-error\r\n >\r\n @if ($any(name).errors?.maxLength && (name.dirty || name.touched)) {\r\n <mat-error>name too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- value (bound) -->\r\n @if (nameIds?.length) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <mat-select [formControl]=\"value\">\r\n <mat-option *ngFor=\"let e of nameIds\" [value]=\"e.id\">{{\r\n e.label\r\n }}</mat-option>\r\n </mat-select>\r\n @if ($any(value).errors?.required && (value.dirty || value.touched)) {\r\n <mat-error>value required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- value (free) -->\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 <mat-error>value too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- setPolicy -->\r\n <mat-form-field>\r\n <mat-label>set policy</mat-label>\r\n <mat-select [formControl]=\"setPolicy\">\r\n <mat-option [value]=\"0\">multiple</mat-option>\r\n <mat-option [value]=\"1\">single</mat-option>\r\n <mat-option [value]=\"2\">single first</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n @if (isVar) {\r\n <div class=\"form-row\">\r\n <!-- isNegated -->\r\n <mat-checkbox [formControl]=\"isNegated\">negated</mat-checkbox>\r\n\r\n <!-- isShortLived -->\r\n <mat-checkbox [formControl]=\"isShortLived\">short-lived</mat-checkbox>\r\n\r\n <!-- isGlobal -->\r\n <mat-checkbox [formControl]=\"isGlobal\">global</mat-checkbox>\r\n </div>\r\n }\r\n\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\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 color=\"primary\"\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</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
692
|
+
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n @if (featNames()?.length) {\r\n <!-- name (bound) -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <mat-select #nameCtl [formControl]=\"name\">\r\n <mat-option *ngFor=\"let i of featNames()\" [value]=\"i.id\">{{\r\n i.label\r\n }}</mat-option>\r\n </mat-select>\r\n @if ($any(name).errors?.required && (name.dirty || name.touched)) {\r\n <mat-error>name required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- name (free) -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <input #nameCtl matInput [formControl]=\"name\" />\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >name required</mat-error\r\n >\r\n @if ($any(name).errors?.maxLength && (name.dirty || name.touched)) {\r\n <mat-error>name too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- value (bound) -->\r\n @if (nameIds?.length) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <mat-select [formControl]=\"value\">\r\n <mat-option *ngFor=\"let e of nameIds\" [value]=\"e.id\">{{\r\n e.label\r\n }}</mat-option>\r\n </mat-select>\r\n @if ($any(value).errors?.required && (value.dirty || value.touched)) {\r\n <mat-error>value required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- value (free) -->\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 <mat-error>value too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- setPolicy -->\r\n <mat-form-field>\r\n <mat-label>set policy</mat-label>\r\n <mat-select [formControl]=\"setPolicy\">\r\n <mat-option [value]=\"0\">multiple</mat-option>\r\n <mat-option [value]=\"1\">single</mat-option>\r\n <mat-option [value]=\"2\">single first</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n @if (isVar()) {\r\n <div class=\"form-row\">\r\n <!-- isNegated -->\r\n <mat-checkbox [formControl]=\"isNegated\">negated</mat-checkbox>\r\n\r\n <!-- isShortLived -->\r\n <mat-checkbox [formControl]=\"isShortLived\">short-lived</mat-checkbox>\r\n\r\n <!-- isGlobal -->\r\n <mat-checkbox [formControl]=\"isGlobal\">global</mat-checkbox>\r\n </div>\r\n }\r\n\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\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 color=\"primary\"\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</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
744
693
|
}], ctorParameters: () => [{ type: i1.FormBuilder }], propDecorators: { nameControl: [{
|
|
745
694
|
type: ViewChild,
|
|
746
695
|
args: ['nameCtl']
|
|
747
|
-
}], featNames: [{
|
|
748
|
-
type: Input
|
|
749
|
-
}], featValues: [{
|
|
750
|
-
type: Input
|
|
751
|
-
}], feature: [{
|
|
752
|
-
type: Input
|
|
753
|
-
}], isVar: [{
|
|
754
|
-
type: Input
|
|
755
|
-
}], featureCancel: [{
|
|
756
|
-
type: Output
|
|
757
|
-
}], featureChange: [{
|
|
758
|
-
type: Output
|
|
759
696
|
}] } });
|
|
760
697
|
|
|
761
698
|
/**
|
|
@@ -774,58 +711,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
774
711
|
* - ▶️ `filterThreshold` (`number`): the threshold at which the features filter
|
|
775
712
|
* should become visible. If set to 0, the filter is always visible; if set to -1,
|
|
776
713
|
* it is always invisible; otherwise, it gets visible when the number of features
|
|
777
|
-
* is greater than the threshold. Default is 5.
|
|
714
|
+
* is equal to or greater than the threshold. Default is 5.
|
|
778
715
|
* - ▶️ `features` (`Feature[]`): the features to edit.
|
|
779
716
|
* - ▶️ `isVar`: true if the feature is a variant operation feature, which
|
|
780
717
|
* has additional properties like negation, global, and short-lived.
|
|
781
718
|
* - 🔥 `featuresChange` (`Feature[]`): emitted when features have changed.
|
|
782
719
|
*/
|
|
783
720
|
class FeatureSetEditorComponent {
|
|
784
|
-
/**
|
|
785
|
-
* The features to edit.
|
|
786
|
-
*/
|
|
787
|
-
get features() {
|
|
788
|
-
return this._features;
|
|
789
|
-
}
|
|
790
|
-
set features(value) {
|
|
791
|
-
if (this._features === value) {
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
this._features = value;
|
|
795
|
-
this.applyFeatureFilter(this.filter.value);
|
|
796
|
-
}
|
|
797
721
|
constructor(formBuilder) {
|
|
798
722
|
this.POLICIES = ['M', 'S', 'SF'];
|
|
799
723
|
/**
|
|
800
724
|
* True if the features are variable features.
|
|
801
725
|
*/
|
|
802
|
-
this.isVar = false;
|
|
726
|
+
this.isVar = input(false);
|
|
727
|
+
/**
|
|
728
|
+
* The list of feature names to display in the name selection.
|
|
729
|
+
* This is used when you have a closed list of features.
|
|
730
|
+
*/
|
|
731
|
+
this.featNames = input();
|
|
732
|
+
/**
|
|
733
|
+
* The feature values map. When specified and the user selects a feature
|
|
734
|
+
* name present in the map keys, the corresponding values will be used
|
|
735
|
+
* to populate the value selection.
|
|
736
|
+
*/
|
|
737
|
+
this.featValues = input();
|
|
803
738
|
/**
|
|
804
739
|
* The threshold at which the features filter should become visible.
|
|
805
740
|
* If set to 0, the filter is always visible; if set to -1, it is always
|
|
806
741
|
* invisible; otherwise, it gets visible when the number of features
|
|
807
|
-
* is greater than the threshold. Default is 5.
|
|
742
|
+
* is greater than or equal to the threshold. Default is 5.
|
|
808
743
|
*/
|
|
809
|
-
this.filterThreshold = 5;
|
|
744
|
+
this.filterThreshold = input(5);
|
|
745
|
+
/**
|
|
746
|
+
* The features to edit.
|
|
747
|
+
*/
|
|
748
|
+
this.features = model([]);
|
|
810
749
|
/**
|
|
811
750
|
* Emitted when the features change.
|
|
812
751
|
*/
|
|
813
|
-
this.featuresChange =
|
|
814
|
-
this._features = [];
|
|
752
|
+
this.featuresChange = output();
|
|
815
753
|
this.filteredFeatures = [];
|
|
816
754
|
this.filter = formBuilder.control(null);
|
|
817
755
|
this._editedFeatureIndex = -1;
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
return !name || feature.name.toLowerCase().includes(name.toLowerCase());
|
|
756
|
+
// when features change, apply the filter
|
|
757
|
+
effect(() => {
|
|
758
|
+
this.applyFeatureFilter(this.features(), this.filter.value);
|
|
822
759
|
});
|
|
823
760
|
}
|
|
761
|
+
applyFeatureFilter(features, name) {
|
|
762
|
+
this.filteredFeatures =
|
|
763
|
+
features.filter((feature) => {
|
|
764
|
+
return !name || feature.name.toLowerCase().includes(name.toLowerCase());
|
|
765
|
+
}) || [];
|
|
766
|
+
}
|
|
824
767
|
ngOnInit() {
|
|
768
|
+
// when the filter changes, apply the filter
|
|
825
769
|
this._sub = this.filter.valueChanges
|
|
826
770
|
.pipe(distinctUntilChanged(), debounceTime(300))
|
|
827
771
|
.subscribe((value) => {
|
|
828
|
-
this.applyFeatureFilter(value);
|
|
772
|
+
this.applyFeatureFilter(this.features(), value);
|
|
829
773
|
});
|
|
830
774
|
}
|
|
831
775
|
ngOnDestroy() {
|
|
@@ -841,20 +785,23 @@ class FeatureSetEditorComponent {
|
|
|
841
785
|
}
|
|
842
786
|
editFeature(feature) {
|
|
843
787
|
this.editedFeature = feature;
|
|
844
|
-
this._editedFeatureIndex = this.features.indexOf(feature);
|
|
788
|
+
this._editedFeatureIndex = this.features().indexOf(feature);
|
|
845
789
|
}
|
|
846
790
|
deleteFeature(feature) {
|
|
847
|
-
const index = this.features.indexOf(feature);
|
|
791
|
+
const index = this.features().indexOf(feature);
|
|
848
792
|
if (index < 0) {
|
|
849
793
|
return;
|
|
850
794
|
}
|
|
851
|
-
const features = [...this.features];
|
|
795
|
+
const features = [...this.features()];
|
|
852
796
|
features.splice(index, 1);
|
|
853
|
-
this.features
|
|
854
|
-
this.featuresChange.emit(this.features);
|
|
797
|
+
this.features.set(features);
|
|
798
|
+
this.featuresChange.emit(this.features());
|
|
855
799
|
}
|
|
856
800
|
onFeatureChange(feature) {
|
|
857
|
-
|
|
801
|
+
if (!feature) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const features = [...this.features()];
|
|
858
805
|
for (let i = features.length - 1; i >= 0; i--) {
|
|
859
806
|
if (features[i].name === feature.name) {
|
|
860
807
|
if (feature.setPolicy === FeatureSetPolicy.single ||
|
|
@@ -869,19 +816,18 @@ class FeatureSetEditorComponent {
|
|
|
869
816
|
else {
|
|
870
817
|
features.splice(this._editedFeatureIndex, 1, feature);
|
|
871
818
|
}
|
|
872
|
-
this.
|
|
873
|
-
this.
|
|
874
|
-
this.
|
|
875
|
-
this.featuresChange.emit(this.features);
|
|
819
|
+
this.onFeatureCancel();
|
|
820
|
+
this.features.set(features);
|
|
821
|
+
this.featuresChange.emit(this.features());
|
|
876
822
|
}
|
|
877
823
|
onFeatureCancel() {
|
|
878
824
|
this.editedFeature = undefined;
|
|
879
825
|
this._editedFeatureIndex = -1;
|
|
880
826
|
}
|
|
881
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
882
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
827
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: FeatureSetEditorComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
828
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: FeatureSetEditorComponent, isStandalone: true, selector: "gve-feature-set-editor", inputs: { isVar: { classPropertyName: "isVar", publicName: "isVar", isSignal: true, isRequired: false, transformFunction: null }, featNames: { classPropertyName: "featNames", publicName: "featNames", isSignal: true, isRequired: false, transformFunction: null }, featValues: { classPropertyName: "featValues", publicName: "featValues", isSignal: true, isRequired: false, transformFunction: null }, filterThreshold: { classPropertyName: "filterThreshold", publicName: "filterThreshold", isSignal: true, isRequired: false, transformFunction: null }, features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { features: "featuresChange", featuresChange: "featuresChange" }, ngImport: i0, template: "<div>\r\n <div class=\"form-row\">\r\n <!-- filter -->\r\n @if (filterThreshold() === 0 || features().length >= filterThreshold()) {\r\n <mat-form-field>\r\n <input matInput placeholder=\"filter\" [formControl]=\"filter\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n (click)=\"filter.reset()\"\r\n [disabled]=\"!filter.value\"\r\n [attr.aria-label]=\"'Reset filter'\"\r\n >\r\n <mat-icon color=\"warn\" class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n }\r\n\r\n <!-- add feature button -->\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Add a new feature\"\r\n (click)=\"addFeature()\"\r\n [class.in-row-button]=\"\r\n filterThreshold() === 0 || features()!.length >= filterThreshold()\r\n \"\r\n >\r\n <mat-icon>add</mat-icon>\r\n feature\r\n </button>\r\n </div>\r\n\r\n <!-- list -->\r\n @if (features().length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>feature</th>\r\n <th>value</th>\r\n <th>policy</th>\r\n @if (isVar()) {\r\n <th>negated</th>\r\n <th>global</th>\r\n <th>short-lived</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (feature of filteredFeatures; track feature) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n mat-icon-button\r\n matTooltip=\"Edit this feature\"\r\n (click)=\"editFeature(feature)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\r\n mat-icon-button\r\n matTooltip=\"Delete this feature\"\r\n (click)=\"deleteFeature(feature)\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n @if (featNames()?.length) {\r\n <span>{{\r\n feature.name | flatLookup : featNames : \"id\" : \"label\"\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.name }}</span>\r\n }\r\n </td>\r\n <td>\r\n @if (featValues()) {\r\n <span>{{\r\n feature.value | flatLookup : featValues()![feature.name]\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.value }}</span>\r\n }\r\n </td>\r\n <td>\r\n <span>{{ POLICIES[feature.setPolicy] }}</span>\r\n </td>\r\n @if (isVar()) {\r\n <td>\r\n <span>{{ $any(feature).isNegated ? \"yes\" : \"no\" }}</span>\r\n </td>\r\n <td>\r\n <span>{{ $any(feature).isGlobal ? \"yes\" : \"no\" }}</span>\r\n </td>\r\n <td>\r\n <span>{{ $any(feature).isShortLived ? \"yes\" : \"no\" }}</span>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- editor -->\r\n <mat-expansion-panel [disabled]=\"!editedFeature\" [expanded]=\"editedFeature\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>\r\n <span>{{ editedFeature?.name || \"feature\" }}</span>\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-feature-editor\r\n [isVar]=\"isVar()\"\r\n [featNames]=\"featNames()\"\r\n [featValues]=\"featValues()\"\r\n [feature]=\"editedFeature\"\r\n (featureChange)=\"onFeatureChange($event)\"\r\n (featureCancel)=\"onFeatureCancel()\"\r\n />\r\n </mat-expansion-panel>\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.in-row-button{margin-top:-16px}table{width:100%;border-collapse:collapse;margin-top:8px}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: FlatLookupPipe, name: "flatLookup" }, { kind: "component", type: FeatureEditorComponent, selector: "gve-feature-editor", inputs: ["featNames", "featValues", "feature", "isVar"], outputs: ["featureChange", "featureCancel"] }] }); }
|
|
883
829
|
}
|
|
884
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
830
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: FeatureSetEditorComponent, decorators: [{
|
|
885
831
|
type: Component,
|
|
886
832
|
args: [{ selector: 'gve-feature-set-editor', imports: [
|
|
887
833
|
CommonModule,
|
|
@@ -895,20 +841,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
895
841
|
MatTooltipModule,
|
|
896
842
|
FlatLookupPipe,
|
|
897
843
|
FeatureEditorComponent,
|
|
898
|
-
], template: "<div>\r\n <div class=\"form-row\">\r\n <!-- filter -->\r\n @if (filterThreshold === 0 || features.length
|
|
899
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
900
|
-
type: Input
|
|
901
|
-
}], featNames: [{
|
|
902
|
-
type: Input
|
|
903
|
-
}], featValues: [{
|
|
904
|
-
type: Input
|
|
905
|
-
}], filterThreshold: [{
|
|
906
|
-
type: Input
|
|
907
|
-
}], features: [{
|
|
908
|
-
type: Input
|
|
909
|
-
}], featuresChange: [{
|
|
910
|
-
type: Output
|
|
911
|
-
}] } });
|
|
844
|
+
], template: "<div>\r\n <div class=\"form-row\">\r\n <!-- filter -->\r\n @if (filterThreshold() === 0 || features().length >= filterThreshold()) {\r\n <mat-form-field>\r\n <input matInput placeholder=\"filter\" [formControl]=\"filter\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n (click)=\"filter.reset()\"\r\n [disabled]=\"!filter.value\"\r\n [attr.aria-label]=\"'Reset filter'\"\r\n >\r\n <mat-icon color=\"warn\" class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n }\r\n\r\n <!-- add feature button -->\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Add a new feature\"\r\n (click)=\"addFeature()\"\r\n [class.in-row-button]=\"\r\n filterThreshold() === 0 || features()!.length >= filterThreshold()\r\n \"\r\n >\r\n <mat-icon>add</mat-icon>\r\n feature\r\n </button>\r\n </div>\r\n\r\n <!-- list -->\r\n @if (features().length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>feature</th>\r\n <th>value</th>\r\n <th>policy</th>\r\n @if (isVar()) {\r\n <th>negated</th>\r\n <th>global</th>\r\n <th>short-lived</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (feature of filteredFeatures; track feature) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n mat-icon-button\r\n matTooltip=\"Edit this feature\"\r\n (click)=\"editFeature(feature)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\r\n mat-icon-button\r\n matTooltip=\"Delete this feature\"\r\n (click)=\"deleteFeature(feature)\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n @if (featNames()?.length) {\r\n <span>{{\r\n feature.name | flatLookup : featNames : \"id\" : \"label\"\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.name }}</span>\r\n }\r\n </td>\r\n <td>\r\n @if (featValues()) {\r\n <span>{{\r\n feature.value | flatLookup : featValues()![feature.name]\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.value }}</span>\r\n }\r\n </td>\r\n <td>\r\n <span>{{ POLICIES[feature.setPolicy] }}</span>\r\n </td>\r\n @if (isVar()) {\r\n <td>\r\n <span>{{ $any(feature).isNegated ? \"yes\" : \"no\" }}</span>\r\n </td>\r\n <td>\r\n <span>{{ $any(feature).isGlobal ? \"yes\" : \"no\" }}</span>\r\n </td>\r\n <td>\r\n <span>{{ $any(feature).isShortLived ? \"yes\" : \"no\" }}</span>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- editor -->\r\n <mat-expansion-panel [disabled]=\"!editedFeature\" [expanded]=\"editedFeature\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>\r\n <span>{{ editedFeature?.name || \"feature\" }}</span>\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-feature-editor\r\n [isVar]=\"isVar()\"\r\n [featNames]=\"featNames()\"\r\n [featValues]=\"featValues()\"\r\n [feature]=\"editedFeature\"\r\n (featureChange)=\"onFeatureChange($event)\"\r\n (featureCancel)=\"onFeatureCancel()\"\r\n />\r\n </mat-expansion-panel>\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.in-row-button{margin-top:-16px}table{width:100%;border-collapse:collapse;margin-top:8px}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"] }]
|
|
845
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
912
846
|
|
|
913
847
|
/**
|
|
914
848
|
* 🔑 `gve-base-text-editor`
|
|
@@ -920,37 +854,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
920
854
|
* Used by the `gve-snapshot-editor` component.
|
|
921
855
|
*/
|
|
922
856
|
class BaseTextEditorComponent {
|
|
923
|
-
/**
|
|
924
|
-
* The text to edit. In input this can be a string, an array of `CharNode`
|
|
925
|
-
* objects. In output this will be an array of `CharNode` objects.
|
|
926
|
-
*/
|
|
927
|
-
get text() {
|
|
928
|
-
return this._text;
|
|
929
|
-
}
|
|
930
|
-
set text(value) {
|
|
931
|
-
this.resetSelectedChar();
|
|
932
|
-
if (this._text === value) {
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
if (!value) {
|
|
936
|
-
this._text = [];
|
|
937
|
-
}
|
|
938
|
-
else {
|
|
939
|
-
this._text = Array.isArray(value)
|
|
940
|
-
? value
|
|
941
|
-
: SnapshotViewService.stringToBaseChars(value);
|
|
942
|
-
}
|
|
943
|
-
this.userText.setValue(this._text.map((c) => c.label).join(''));
|
|
944
|
-
this.userText.markAsPristine();
|
|
945
|
-
this.userText.updateValueAndValidity();
|
|
946
|
-
}
|
|
947
857
|
constructor(formBuilder, _dialogService) {
|
|
948
858
|
this._dialogService = _dialogService;
|
|
949
|
-
|
|
859
|
+
/**
|
|
860
|
+
* The text to edit. In input this can be a string, an array of `CharNode`
|
|
861
|
+
* objects, or undefined. In output this will be an array of `CharNode`
|
|
862
|
+
* objects.
|
|
863
|
+
*/
|
|
864
|
+
this.text = input.required({
|
|
865
|
+
transform: (value) => {
|
|
866
|
+
if (value === undefined) {
|
|
867
|
+
return undefined;
|
|
868
|
+
}
|
|
869
|
+
if (Array.isArray(value)) {
|
|
870
|
+
return value;
|
|
871
|
+
}
|
|
872
|
+
if (typeof value === 'string') {
|
|
873
|
+
return SnapshotViewService.stringToBaseChars(value);
|
|
874
|
+
}
|
|
875
|
+
return undefined;
|
|
876
|
+
},
|
|
877
|
+
});
|
|
950
878
|
/**
|
|
951
879
|
* Emitted for the edited text as an array of `CharNode`'s whenever it changes.
|
|
952
880
|
*/
|
|
953
|
-
this.textChange =
|
|
881
|
+
this.textChange = output();
|
|
954
882
|
this.userText = formBuilder.control('', {
|
|
955
883
|
nonNullable: true,
|
|
956
884
|
validators: [Validators.required, Validators.maxLength(10000)],
|
|
@@ -958,18 +886,31 @@ class BaseTextEditorComponent {
|
|
|
958
886
|
this.form = formBuilder.group({
|
|
959
887
|
userText: this.userText,
|
|
960
888
|
});
|
|
889
|
+
effect(() => {
|
|
890
|
+
this.resetSelectedChar();
|
|
891
|
+
if (!this.text()) {
|
|
892
|
+
this.userText.reset();
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
this.userText.setValue(this.text()
|
|
896
|
+
.map((c) => c.label)
|
|
897
|
+
.join(''));
|
|
898
|
+
this.userText.markAsPristine();
|
|
899
|
+
this.userText.updateValueAndValidity();
|
|
900
|
+
}
|
|
901
|
+
});
|
|
961
902
|
}
|
|
962
903
|
resetSelectedChar() {
|
|
963
904
|
this.selectedChar = undefined;
|
|
964
905
|
this.selectedCharLabel = undefined;
|
|
965
906
|
}
|
|
966
907
|
onSelectedChar(event) {
|
|
967
|
-
this.selectedChar = this.
|
|
908
|
+
this.selectedChar = this.text().find((c) => c.id === event.char.id);
|
|
968
909
|
this.selectedCharLabel = event.char.label;
|
|
969
910
|
}
|
|
970
911
|
onFeaturesChange(features) {
|
|
971
912
|
this.selectedChar.features = features;
|
|
972
|
-
this.textChange.emit(this.
|
|
913
|
+
this.textChange.emit(this.text());
|
|
973
914
|
}
|
|
974
915
|
onRangePick(range) {
|
|
975
916
|
this.textRange = range;
|
|
@@ -982,15 +923,14 @@ class BaseTextEditorComponent {
|
|
|
982
923
|
.confirm('Confirm', 'Reset text?')
|
|
983
924
|
.subscribe((yes) => {
|
|
984
925
|
if (yes) {
|
|
985
|
-
this.
|
|
986
|
-
this.textChange.emit(this._text);
|
|
926
|
+
this.textChange.emit(SnapshotViewService.stringToBaseChars(this.userText.value));
|
|
987
927
|
}
|
|
988
928
|
});
|
|
989
929
|
}
|
|
990
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
991
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
930
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BaseTextEditorComponent, deps: [{ token: i1.FormBuilder }, { token: i2$1.DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
931
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: BaseTextEditorComponent, isStandalone: true, selector: "gve-base-text-editor", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { textChange: "textChange" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"setTextFromUser()\">\r\n <!-- text -->\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>text</mat-label>\r\n <textarea matInput [formControl]=\"userText\" rows=\"5\"></textarea>\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.required &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.maxLength &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <!-- set -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset characters to newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"setTextFromUser()\"\r\n >\r\n set\r\n </button>\r\n <!-- patch: TODO -->\r\n <!-- <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n matTooltip=\"Patch characters with newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"patchTextFromUser()\"\r\n >\r\n patch\r\n </button> -->\r\n </div>\r\n\r\n <!-- base text -->\r\n <div id=\"text-view\">\r\n <gve-base-text-view\r\n [text]=\"text() || []\"\r\n (charPick)=\"onSelectedChar($event)\"\r\n (rangePick)=\"textRange = $event\"\r\n />\r\n\r\n <!-- text range -->\r\n @if (textRange) {\r\n <div id=\"text-range\">{{ textRange.at }} \u00D7 {{ textRange.run }}</div>\r\n }\r\n </div>\r\n\r\n <!-- char features -->\r\n @if (selectedChar) {\r\n <fieldset>\r\n <legend>features</legend>\r\n <gve-feature-set-editor\r\n [features]=\"selectedChar.features || []\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n</form>\r\n", styles: [".full-width{width:100%}#text-view{margin:8px 0}fieldset{border:1px solid #ccc;padding:10px;margin:10px 0;border-radius:5px}legend{color:silver}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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],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: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { 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: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: BaseTextViewComponent, selector: "gve-base-text-view", inputs: ["defaultColor", "defaultBorderColor", "selectionColor", "hasLineNumber", "text", "borderColorCallback"], outputs: ["charPick", "rangePick"] }, { kind: "component", type: FeatureSetEditorComponent, selector: "gve-feature-set-editor", inputs: ["isVar", "featNames", "featValues", "filterThreshold", "features"], outputs: ["featuresChange"] }] }); }
|
|
992
932
|
}
|
|
993
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
933
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BaseTextEditorComponent, decorators: [{
|
|
994
934
|
type: Component,
|
|
995
935
|
args: [{ selector: 'gve-base-text-editor', imports: [
|
|
996
936
|
CommonModule,
|
|
@@ -1002,12 +942,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1002
942
|
MatTooltipModule,
|
|
1003
943
|
BaseTextViewComponent,
|
|
1004
944
|
FeatureSetEditorComponent,
|
|
1005
|
-
], template: "<form [formGroup]=\"form\" (submit)=\"setTextFromUser()\">\r\n <!-- text -->\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>text</mat-label>\r\n <textarea matInput [formControl]=\"userText\" rows=\"5\"></textarea>\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.required &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.maxLength &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <!-- set -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset characters to newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"setTextFromUser()\"\r\n >\r\n set\r\n </button>\r\n <!-- patch: TODO -->\r\n <!-- <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n matTooltip=\"Patch characters with newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"patchTextFromUser()\"\r\n >\r\n patch\r\n </button> -->\r\n </div>\r\n\r\n <!-- base text -->\r\n <div id=\"text-view\">\r\n <gve-base-text-view\r\n [text]=\"text\"\r\n (charPick)=\"onSelectedChar($event)\"\r\n (rangePick)=\"textRange = $event\"\r\n />\r\n\r\n <!-- text range -->\r\n @if (textRange) {\r\n <div id=\"text-range\">{{ textRange.at }} \u00D7 {{ textRange.run }}</div>\r\n }\r\n </div>\r\n\r\n <!-- char features -->\r\n @if (selectedChar) {\r\n <fieldset>\r\n <legend>features</legend>\r\n <gve-feature-set-editor\r\n [features]=\"selectedChar.features || []\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n</form>\r\n", styles: [".full-width{width:100%}#text-view{margin:8px 0}fieldset{border:1px solid #ccc;padding:10px;margin:10px 0;border-radius:5px}legend{color:silver}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
1006
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$1.DialogService }]
|
|
1007
|
-
type: Input
|
|
1008
|
-
}], textChange: [{
|
|
1009
|
-
type: Output
|
|
1010
|
-
}] } });
|
|
945
|
+
], template: "<form [formGroup]=\"form\" (submit)=\"setTextFromUser()\">\r\n <!-- text -->\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>text</mat-label>\r\n <textarea matInput [formControl]=\"userText\" rows=\"5\"></textarea>\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.required &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.maxLength &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <!-- set -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset characters to newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"setTextFromUser()\"\r\n >\r\n set\r\n </button>\r\n <!-- patch: TODO -->\r\n <!-- <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n matTooltip=\"Patch characters with newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"patchTextFromUser()\"\r\n >\r\n patch\r\n </button> -->\r\n </div>\r\n\r\n <!-- base text -->\r\n <div id=\"text-view\">\r\n <gve-base-text-view\r\n [text]=\"text() || []\"\r\n (charPick)=\"onSelectedChar($event)\"\r\n (rangePick)=\"textRange = $event\"\r\n />\r\n\r\n <!-- text range -->\r\n @if (textRange) {\r\n <div id=\"text-range\">{{ textRange.at }} \u00D7 {{ textRange.run }}</div>\r\n }\r\n </div>\r\n\r\n <!-- char features -->\r\n @if (selectedChar) {\r\n <fieldset>\r\n <legend>features</legend>\r\n <gve-feature-set-editor\r\n [features]=\"selectedChar.features || []\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n</form>\r\n", styles: [".full-width{width:100%}#text-view{margin:8px 0}fieldset{border:1px solid #ccc;padding:10px;margin:10px 0;border-radius:5px}legend{color:silver}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
946
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$1.DialogService }] });
|
|
1011
947
|
|
|
1012
948
|
/**
|
|
1013
949
|
* Service to interact with the GVE API.
|
|
@@ -1059,10 +995,27 @@ class GveApiService {
|
|
|
1059
995
|
})
|
|
1060
996
|
.pipe(catchError(this._error.handleError));
|
|
1061
997
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
998
|
+
/**
|
|
999
|
+
* Get the chain corresponding to the operations run on the
|
|
1000
|
+
* specified text. This is used for diagnostic or demonstration
|
|
1001
|
+
* purposes.
|
|
1002
|
+
*
|
|
1003
|
+
* @param text The base text.
|
|
1004
|
+
* @param operations The operations to run.
|
|
1005
|
+
* @returns Result wrapper.
|
|
1006
|
+
*/
|
|
1007
|
+
getChain(text, operations) {
|
|
1008
|
+
return this._http
|
|
1009
|
+
.post(`${this._env.get('apiUrl')}text/operations/run/chain`, {
|
|
1010
|
+
text,
|
|
1011
|
+
operations,
|
|
1012
|
+
})
|
|
1013
|
+
.pipe(catchError(this._error.handleError));
|
|
1014
|
+
}
|
|
1015
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: GveApiService, deps: [{ token: i1$1.HttpClient }, { token: i2$2.ErrorService }, { token: i2$2.EnvService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1016
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: GveApiService, providedIn: 'root' }); }
|
|
1064
1017
|
}
|
|
1065
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
1018
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: GveApiService, decorators: [{
|
|
1066
1019
|
type: Injectable,
|
|
1067
1020
|
args: [{
|
|
1068
1021
|
providedIn: 'root',
|
|
@@ -1079,30 +1032,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1079
1032
|
* - 🔥 `operationsChange` (`CharChainOperation[]`): event emitted when operations change.
|
|
1080
1033
|
*/
|
|
1081
1034
|
class BatchOperationEditorComponent {
|
|
1082
|
-
/**
|
|
1083
|
-
* The preset text to parse if any. Usually you start with a blank
|
|
1084
|
-
* text, but sometimes you might want to pre-set it.
|
|
1085
|
-
*/
|
|
1086
|
-
get preset() {
|
|
1087
|
-
return this._preset;
|
|
1088
|
-
}
|
|
1089
|
-
set preset(value) {
|
|
1090
|
-
if (this._preset === value) {
|
|
1091
|
-
return;
|
|
1092
|
-
}
|
|
1093
|
-
this._preset = value || undefined;
|
|
1094
|
-
this.parseOperations();
|
|
1095
|
-
}
|
|
1096
1035
|
constructor(formBuilder, _api,
|
|
1097
1036
|
// this component can be used as a dialog
|
|
1098
1037
|
dialogRef, data) {
|
|
1099
1038
|
this._api = _api;
|
|
1100
1039
|
this.dialogRef = dialogRef;
|
|
1101
1040
|
this.data = data;
|
|
1041
|
+
/**
|
|
1042
|
+
* The preset text to parse if any. Usually you start with a blank
|
|
1043
|
+
* text, but sometimes you might want to pre-set it.
|
|
1044
|
+
*/
|
|
1045
|
+
this.preset = input();
|
|
1102
1046
|
/**
|
|
1103
1047
|
* Emitted when operations change.
|
|
1104
1048
|
*/
|
|
1105
|
-
this.operationsChange =
|
|
1049
|
+
this.operationsChange = output();
|
|
1106
1050
|
this.text = formBuilder.control(null, [
|
|
1107
1051
|
Validators.required,
|
|
1108
1052
|
Validators.maxLength(2000),
|
|
@@ -1110,24 +1054,30 @@ class BatchOperationEditorComponent {
|
|
|
1110
1054
|
this.form = formBuilder.group({
|
|
1111
1055
|
inputOps: this.text,
|
|
1112
1056
|
});
|
|
1057
|
+
effect(() => {
|
|
1058
|
+
this.parseOperations(this.preset() || undefined);
|
|
1059
|
+
});
|
|
1113
1060
|
}
|
|
1114
1061
|
ngOnInit() {
|
|
1115
1062
|
if (this.data?.payload?.preset) {
|
|
1116
|
-
this.
|
|
1117
|
-
this.parseOperations();
|
|
1063
|
+
this.parseOperations(this.data?.payload?.preset);
|
|
1118
1064
|
}
|
|
1119
1065
|
}
|
|
1120
|
-
parseOperations() {
|
|
1121
|
-
if (this.busy || !
|
|
1066
|
+
parseOperations(text) {
|
|
1067
|
+
if (this.busy || !text) {
|
|
1122
1068
|
return;
|
|
1123
1069
|
}
|
|
1124
1070
|
this.busy = true;
|
|
1125
1071
|
this.parseError = undefined;
|
|
1126
|
-
this._api.parseOperations(
|
|
1072
|
+
this._api.parseOperations(text).subscribe({
|
|
1127
1073
|
next: (wrapper) => {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1074
|
+
if (wrapper.error) {
|
|
1075
|
+
this.parseError = wrapper.error;
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
this.operationsChange.emit(wrapper.result || []);
|
|
1079
|
+
if (this.dialogRef) {
|
|
1080
|
+
this.dialogRef.close(wrapper.result);
|
|
1131
1081
|
}
|
|
1132
1082
|
},
|
|
1133
1083
|
error: (error) => {
|
|
@@ -1141,10 +1091,10 @@ class BatchOperationEditorComponent {
|
|
|
1141
1091
|
close() {
|
|
1142
1092
|
this.dialogRef?.close();
|
|
1143
1093
|
}
|
|
1144
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
1145
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
1094
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BatchOperationEditorComponent, deps: [{ token: i1.FormBuilder }, { token: GveApiService }, { token: i3$1.MatDialogRef, optional: true }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1095
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: BatchOperationEditorComponent, isStandalone: true, selector: "gve-batch-operation-editor", inputs: { preset: { classPropertyName: "preset", publicName: "preset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operationsChange: "operationsChange" }, ngImport: i0, template: "<div [style.padding]=\"dialogRef ? '8px' : '0'\">\r\n @if (dialogRef) {\r\n <div id=\"heading\">\r\n <h2>Add Operations</h2>\r\n </div>\r\n }\r\n <fieldset>\r\n <div id=\"batch-input\">\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>operations</mat-label>\r\n <textarea\r\n class=\"code\"\r\n matInput\r\n [formControl]=\"text\"\r\n rows=\"8\"\r\n spellcheck=\"false\"\r\n ></textarea>\r\n </mat-form-field>\r\n @if (parseError) {\r\n <div class=\"error\">{{ parseError }}</div>\r\n }\r\n </div>\r\n </div>\r\n <div id=\"batch-help\">\r\n <ul>\r\n <li>\r\n <strong>replace</strong>:\r\n <code>ATxRUN<strong>=</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>delete</strong>:\r\n <code>ATxRUN<strong>-</strong></code>\r\n </li>\r\n <li>\r\n <strong>add-before</strong>:\r\n <code>ATxRUN<strong>+[</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>add-after</strong>:\r\n <code>ATxRUN<strong>+]</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>move-before</strong>:\r\n <code>ATxRUN<strong>>[</strong>TO</code>\r\n </li>\r\n <li>\r\n <strong>move-after</strong>:\r\n <code>ATxRUN<strong>>]</strong>TO</code>\r\n </li>\r\n <li>\r\n <strong>swap</strong>:\r\n <code>ATxRUN<strong><></strong>TOxRUN</code>\r\n </li>\r\n <li>\r\n <strong>annotate</strong>:\r\n <code>ATxRUN<strong>:</strong></code>\r\n </li>\r\n </ul>\r\n <p>For all the operations:</p>\r\n <ul>\r\n <li>\r\n prefix <code>(ITAG:OTAG)</code> to define input and/or output tags,\r\n separated by colon.\r\n </li>\r\n <li>\r\n prepend <code>@</code> to AT to use character indexes (0-N)\r\n rather than IDs.\r\n </li>\r\n <li>RUN (where applicable) defaults to 1.</li>\r\n <li>\r\n append features like <code>[NAME OPERATOR VALUE]</code>, separated by\r\n space, where:\r\n </li>\r\n <li>\r\n <ol>\r\n <li>\r\n NAME is an arbitrary string. Prefixes:\r\n <code>*</code>=global features, <code>!</code>=remove feature (no\r\n value). Suffixes: <code>^</code>=short-lived (like\r\n <code>*version^=alpha</code>).\r\n </li>\r\n <li>\r\n OPERATOR is <code>=</code> (multiple), <code>:=</code> (single),\r\n <code>==</code> (first-single).\r\n </li>\r\n <li>\r\n VALUE is a string. If it includes spaces, wrap it in\r\n <code>\"\"</code>.\r\n </li>\r\n </ol>\r\n </li>\r\n </ul>\r\n </div>\r\n <div class=\"form-row-center\">\r\n @if (dialogRef) {\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Close dialog\"\r\n (click)=\"close()\"\r\n >\r\n close\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Parse text into operations\"\r\n [disabled]=\"!text.value || busy\"\r\n (click)=\"parseOperations(text.value!)\"\r\n >\r\n batch add\r\n </button>\r\n </div>\r\n </fieldset>\r\n</div>\r\n", styles: [".full-width{width:100%}.error{color:red}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}div#heading{margin:8px;text-align:center}div#batch-help strong{color:#ff8c00}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { 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"] }] }); }
|
|
1146
1096
|
}
|
|
1147
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
1097
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: BatchOperationEditorComponent, decorators: [{
|
|
1148
1098
|
type: Component,
|
|
1149
1099
|
args: [{ selector: 'gve-batch-operation-editor', imports: [
|
|
1150
1100
|
ReactiveFormsModule,
|
|
@@ -1152,7 +1102,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1152
1102
|
MatFormFieldModule,
|
|
1153
1103
|
MatIconModule,
|
|
1154
1104
|
MatInputModule,
|
|
1155
|
-
], template: "<div [style.padding]=\"dialogRef ? '8px' : '0'\">\r\n @if (dialogRef) {\r\n <div id=\"heading\">\r\n <h2>Add Operations</h2>\r\n </div>\r\n }\r\n <fieldset>\r\n <div id=\"batch-input\">\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>operations</mat-label>\r\n <textarea\r\n class=\"code\"\r\n matInput\r\n [formControl]=\"text\"\r\n rows=\"8\"\r\n spellcheck=\"false\"\r\n ></textarea>\r\n </mat-form-field>\r\n @if (parseError) {\r\n <div class=\"error\">{{ parseError }}</div>\r\n }\r\n </div>\r\n </div>\r\n <div id=\"batch-help\">\r\n <ul>\r\n <li>\r\n <strong>replace</strong>:\r\n <code>ATxRUN<strong>=</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>delete</strong>:\r\n <code>ATxRUN<strong>-</strong></code>\r\n </li>\r\n <li>\r\n <strong>add-before</strong>:\r\n <code>ATxRUN<strong>+[</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>add-after</strong>:\r\n <code>ATxRUN<strong>+]</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>move-before</strong>:\r\n <code>ATxRUN<strong>>[</strong>TO</code>\r\n </li>\r\n <li>\r\n <strong>move-after</strong>:\r\n <code>ATxRUN<strong>>]</strong>TO</code>\r\n </li>\r\n <li>\r\n <strong>swap</strong>:\r\n <code>ATxRUN<strong><></strong>TOxRUN</code>\r\n </li>\r\n <li>\r\n <strong>annotate</strong>:\r\n <code>ATxRUN<strong>:</strong></code>\r\n </li>\r\n </ul>\r\n <p>For all the operations:</p>\r\n <ul>\r\n <li>\r\n prefix <code>(ITAG:OTAG)</code> to define input and/or output tags,\r\n separated by colon.\r\n </li>\r\n <li>\r\n prepend <code>@</code> to AT to use character indexes (0-N)\r\n rather than IDs.\r\n </li>\r\n <li>RUN (where applicable) defaults to 1.</li>\r\n <li>\r\n append features like <code>[NAME OPERATOR VALUE]</code>, separated by\r\n space, where:\r\n </li>\r\n <li>\r\n <ol>\r\n <li>\r\n NAME is an arbitrary string. Prefixes:\r\n <code>*</code>=global features, <code>!</code>=remove feature (no\r\n value). Suffixes: <code>^</code>=short-lived (like\r\n <code>*version^=alpha</code>).\r\n </li>\r\n <li>\r\n OPERATOR is <code>=</code> (multiple), <code>:=</code> (single),\r\n <code>==</code> (first-single).\r\n </li>\r\n <li>\r\n VALUE is a string. If it includes spaces, wrap it in\r\n <code>\"\"</code>.\r\n </li>\r\n </ol>\r\n </li>\r\n </ul>\r\n </div>\r\n <div class=\"form-row-center\">\r\n @if (dialogRef) {\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Close dialog\"\r\n (click)=\"close()\"\r\n >\r\n close\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Parse text into operations\"\r\n [disabled]=\"!text.value || busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n batch add\r\n </button>\r\n </div>\r\n </fieldset>\r\n</div>\r\n", styles: [".full-width{width:100%}.error{color:red}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}div#heading{margin:8px;text-align:center}div#batch-help strong{color:#ff8c00}\n"] }]
|
|
1105
|
+
], template: "<div [style.padding]=\"dialogRef ? '8px' : '0'\">\r\n @if (dialogRef) {\r\n <div id=\"heading\">\r\n <h2>Add Operations</h2>\r\n </div>\r\n }\r\n <fieldset>\r\n <div id=\"batch-input\">\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>operations</mat-label>\r\n <textarea\r\n class=\"code\"\r\n matInput\r\n [formControl]=\"text\"\r\n rows=\"8\"\r\n spellcheck=\"false\"\r\n ></textarea>\r\n </mat-form-field>\r\n @if (parseError) {\r\n <div class=\"error\">{{ parseError }}</div>\r\n }\r\n </div>\r\n </div>\r\n <div id=\"batch-help\">\r\n <ul>\r\n <li>\r\n <strong>replace</strong>:\r\n <code>ATxRUN<strong>=</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>delete</strong>:\r\n <code>ATxRUN<strong>-</strong></code>\r\n </li>\r\n <li>\r\n <strong>add-before</strong>:\r\n <code>ATxRUN<strong>+[</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>add-after</strong>:\r\n <code>ATxRUN<strong>+]</strong>\"VALUE\"</code>\r\n </li>\r\n <li>\r\n <strong>move-before</strong>:\r\n <code>ATxRUN<strong>>[</strong>TO</code>\r\n </li>\r\n <li>\r\n <strong>move-after</strong>:\r\n <code>ATxRUN<strong>>]</strong>TO</code>\r\n </li>\r\n <li>\r\n <strong>swap</strong>:\r\n <code>ATxRUN<strong><></strong>TOxRUN</code>\r\n </li>\r\n <li>\r\n <strong>annotate</strong>:\r\n <code>ATxRUN<strong>:</strong></code>\r\n </li>\r\n </ul>\r\n <p>For all the operations:</p>\r\n <ul>\r\n <li>\r\n prefix <code>(ITAG:OTAG)</code> to define input and/or output tags,\r\n separated by colon.\r\n </li>\r\n <li>\r\n prepend <code>@</code> to AT to use character indexes (0-N)\r\n rather than IDs.\r\n </li>\r\n <li>RUN (where applicable) defaults to 1.</li>\r\n <li>\r\n append features like <code>[NAME OPERATOR VALUE]</code>, separated by\r\n space, where:\r\n </li>\r\n <li>\r\n <ol>\r\n <li>\r\n NAME is an arbitrary string. Prefixes:\r\n <code>*</code>=global features, <code>!</code>=remove feature (no\r\n value). Suffixes: <code>^</code>=short-lived (like\r\n <code>*version^=alpha</code>).\r\n </li>\r\n <li>\r\n OPERATOR is <code>=</code> (multiple), <code>:=</code> (single),\r\n <code>==</code> (first-single).\r\n </li>\r\n <li>\r\n VALUE is a string. If it includes spaces, wrap it in\r\n <code>\"\"</code>.\r\n </li>\r\n </ol>\r\n </li>\r\n </ul>\r\n </div>\r\n <div class=\"form-row-center\">\r\n @if (dialogRef) {\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Close dialog\"\r\n (click)=\"close()\"\r\n >\r\n close\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Parse text into operations\"\r\n [disabled]=\"!text.value || busy\"\r\n (click)=\"parseOperations(text.value!)\"\r\n >\r\n batch add\r\n </button>\r\n </div>\r\n </fieldset>\r\n</div>\r\n", styles: [".full-width{width:100%}.error{color:red}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}div#heading{margin:8px;text-align:center}div#batch-help strong{color:#ff8c00}\n"] }]
|
|
1156
1106
|
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: GveApiService }, { type: i3$1.MatDialogRef, decorators: [{
|
|
1157
1107
|
type: Optional
|
|
1158
1108
|
}] }, { type: undefined, decorators: [{
|
|
@@ -1160,11 +1110,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1160
1110
|
}, {
|
|
1161
1111
|
type: Inject,
|
|
1162
1112
|
args: [MAT_DIALOG_DATA]
|
|
1163
|
-
}] }]
|
|
1164
|
-
type: Input
|
|
1165
|
-
}], operationsChange: [{
|
|
1166
|
-
type: Output
|
|
1167
|
-
}] } });
|
|
1113
|
+
}] }] });
|
|
1168
1114
|
|
|
1169
1115
|
/**
|
|
1170
1116
|
* 🔑 `gve-operation-source-editor`
|
|
@@ -1183,28 +1129,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1183
1129
|
* edit is canceled.
|
|
1184
1130
|
*/
|
|
1185
1131
|
class OperationSourceEditorComponent {
|
|
1186
|
-
/**
|
|
1187
|
-
* The source to edit.
|
|
1188
|
-
*/
|
|
1189
|
-
get source() {
|
|
1190
|
-
return this._source;
|
|
1191
|
-
}
|
|
1192
|
-
set source(value) {
|
|
1193
|
-
if (this._source === value) {
|
|
1194
|
-
return;
|
|
1195
|
-
}
|
|
1196
|
-
this._source = value || undefined;
|
|
1197
|
-
this.updateForm(this._source);
|
|
1198
|
-
}
|
|
1199
1132
|
constructor(formBuilder) {
|
|
1133
|
+
/**
|
|
1134
|
+
* The source to edit.
|
|
1135
|
+
*/
|
|
1136
|
+
this.source = model();
|
|
1137
|
+
/**
|
|
1138
|
+
* The list of source IDs when it's a closed set.
|
|
1139
|
+
*/
|
|
1140
|
+
this.ids = input();
|
|
1141
|
+
/**
|
|
1142
|
+
* The list of source types when it's a closed set.
|
|
1143
|
+
*/
|
|
1144
|
+
this.types = input();
|
|
1200
1145
|
/**
|
|
1201
1146
|
* The event emitted when the source changes.
|
|
1202
1147
|
*/
|
|
1203
|
-
this.sourceChange =
|
|
1148
|
+
this.sourceChange = output();
|
|
1204
1149
|
/**
|
|
1205
1150
|
* The event emitted when the edit is canceled.
|
|
1206
1151
|
*/
|
|
1207
|
-
this.sourceCancel =
|
|
1152
|
+
this.sourceCancel = output();
|
|
1208
1153
|
this.id = new FormControl('', {
|
|
1209
1154
|
validators: [Validators.required, Validators.maxLength(50)],
|
|
1210
1155
|
nonNullable: true,
|
|
@@ -1225,6 +1170,10 @@ class OperationSourceEditorComponent {
|
|
|
1225
1170
|
rank: this.rank,
|
|
1226
1171
|
note: this.note,
|
|
1227
1172
|
});
|
|
1173
|
+
// when source changes, update form
|
|
1174
|
+
effect(() => {
|
|
1175
|
+
this.updateForm(this.source());
|
|
1176
|
+
});
|
|
1228
1177
|
}
|
|
1229
1178
|
updateForm(source) {
|
|
1230
1179
|
if (!source) {
|
|
@@ -1244,18 +1193,18 @@ class OperationSourceEditorComponent {
|
|
|
1244
1193
|
if (this.form.invalid) {
|
|
1245
1194
|
return;
|
|
1246
1195
|
}
|
|
1247
|
-
this.
|
|
1196
|
+
this.source.set({
|
|
1248
1197
|
id: this.id.value,
|
|
1249
1198
|
type: this.type.value,
|
|
1250
1199
|
rank: this.rank.value,
|
|
1251
1200
|
note: this.note.value || undefined,
|
|
1252
|
-
};
|
|
1253
|
-
this.sourceChange.emit(this.
|
|
1201
|
+
});
|
|
1202
|
+
this.sourceChange.emit(this.source());
|
|
1254
1203
|
}
|
|
1255
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
1256
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
1204
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: OperationSourceEditorComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1205
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: OperationSourceEditorComponent, isStandalone: true, selector: "gve-operation-source-editor", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, ids: { classPropertyName: "ids", publicName: "ids", isSignal: true, isRequired: false, transformFunction: null }, types: { classPropertyName: "types", publicName: "types", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { source: "sourceChange", sourceChange: "sourceChange", sourceCancel: "sourceCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <!-- id (bound) -->\r\n @if (ids()?.length) {\r\n <mat-form-field>\r\n <mat-label>id</mat-label>\r\n <mat-select [formControl]=\"id\">\r\n @for (i of ids(); track i.id) {\r\n <mat-option [value]=\"i.id\">{{ i.label }}</mat-option>\r\n }\r\n </mat-select>\r\n @if ($any(id.errors)?.required && (id.dirty || id.touched)) {\r\n <mat-error>ID required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- id (free) -->\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 }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- type (bound) -->\r\n @if (types()?.length) {\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n @for (i of types(); track i.id) {\r\n <mat-option [value]=\"i.id\">{{ i.label }}</mat-option>\r\n }\r\n </mat-select>\r\n @if ($any(type.errors)?.required && (type.dirty || type.touched)) {\r\n <mat-error>type required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- type (free) -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <input matInput [formControl]=\"type\" />\r\n @if ($any(type.errors)?.required && (type.dirty || type.touched)) {\r\n <mat-error>type required</mat-error>\r\n } @if ($any(type.errors)?.maxLength && (type.dirty || type.touched)) {\r\n <mat-error>type too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n </mat-form-field>\r\n </div>\r\n <!-- note -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput [formControl]=\"note\" class=\"long-text\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\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 color=\"primary\"\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</form>\r\n", styles: [".long-text{width:100%;max-width:800px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:5em}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { 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: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
1257
1206
|
}
|
|
1258
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
1207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: OperationSourceEditorComponent, decorators: [{
|
|
1259
1208
|
type: Component,
|
|
1260
1209
|
args: [{ selector: 'gve-operation-source-editor', imports: [
|
|
1261
1210
|
CommonModule,
|
|
@@ -1266,18 +1215,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1266
1215
|
MatInputModule,
|
|
1267
1216
|
MatSelectModule,
|
|
1268
1217
|
MatTooltipModule,
|
|
1269
|
-
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <!-- id (bound) -->\r\n @if (ids?.length) {\r\n <mat-form-field>\r\n <mat-label>id</mat-label>\r\n <mat-select [formControl]=\"id\">\r\n @for (i of ids; track i.id) {\r\n <mat-option [value]=\"i.id\">{{ i.label }}</mat-option>\r\n }\r\n </mat-select>\r\n @if ($any(id.errors)?.required && (id.dirty || id.touched)) {\r\n <mat-error>ID required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- id (free) -->\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 }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- type (bound) -->\r\n @if (types?.length) {\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n @for (i of types; track i.id) {\r\n <mat-option [value]=\"i.id\">{{ i.label }}</mat-option>\r\n }\r\n </mat-select>\r\n @if ($any(type.errors)?.required && (type.dirty || type.touched)) {\r\n <mat-error>type required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- type (free) -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <input matInput [formControl]=\"type\" />\r\n @if ($any(type.errors)?.required && (type.dirty || type.touched)) {\r\n <mat-error>type required</mat-error>\r\n } @if ($any(type.errors)?.maxLength && (type.dirty || type.touched)) {\r\n <mat-error>type too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n </mat-form-field>\r\n </div>\r\n <!-- note -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput [formControl]=\"note\" class=\"long-text\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\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 color=\"primary\"\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</form>\r\n", styles: [".long-text{width:100%;max-width:800px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:5em}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"] }]
|
|
1270
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
1271
|
-
type: Input
|
|
1272
|
-
}], ids: [{
|
|
1273
|
-
type: Input
|
|
1274
|
-
}], types: [{
|
|
1275
|
-
type: Input
|
|
1276
|
-
}], sourceChange: [{
|
|
1277
|
-
type: Output
|
|
1278
|
-
}], sourceCancel: [{
|
|
1279
|
-
type: Output
|
|
1280
|
-
}] } });
|
|
1218
|
+
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <!-- id (bound) -->\r\n @if (ids()?.length) {\r\n <mat-form-field>\r\n <mat-label>id</mat-label>\r\n <mat-select [formControl]=\"id\">\r\n @for (i of ids(); track i.id) {\r\n <mat-option [value]=\"i.id\">{{ i.label }}</mat-option>\r\n }\r\n </mat-select>\r\n @if ($any(id.errors)?.required && (id.dirty || id.touched)) {\r\n <mat-error>ID required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- id (free) -->\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 }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- type (bound) -->\r\n @if (types()?.length) {\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n @for (i of types(); track i.id) {\r\n <mat-option [value]=\"i.id\">{{ i.label }}</mat-option>\r\n }\r\n </mat-select>\r\n @if ($any(type.errors)?.required && (type.dirty || type.touched)) {\r\n <mat-error>type required</mat-error>\r\n }\r\n </mat-form-field>\r\n } @else {\r\n <!-- type (free) -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <input matInput [formControl]=\"type\" />\r\n @if ($any(type.errors)?.required && (type.dirty || type.touched)) {\r\n <mat-error>type required</mat-error>\r\n } @if ($any(type.errors)?.maxLength && (type.dirty || type.touched)) {\r\n <mat-error>type too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n </mat-form-field>\r\n </div>\r\n <!-- note -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput [formControl]=\"note\" class=\"long-text\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\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 color=\"primary\"\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</form>\r\n", styles: [".long-text{width:100%;max-width:800px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.nr{width:5em}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"] }]
|
|
1219
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
1281
1220
|
|
|
1282
1221
|
/**
|
|
1283
1222
|
* Validators for SVG.
|
|
@@ -1495,10 +1434,10 @@ class SettingsService {
|
|
|
1495
1434
|
// for when the cache was not in sync with the local storage
|
|
1496
1435
|
removedKeys.forEach((key) => this._subject.next(key));
|
|
1497
1436
|
}
|
|
1498
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
1499
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.
|
|
1437
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1438
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SettingsService, providedIn: 'root' }); }
|
|
1500
1439
|
}
|
|
1501
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
1440
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SettingsService, decorators: [{
|
|
1502
1441
|
type: Injectable,
|
|
1503
1442
|
args: [{
|
|
1504
1443
|
providedIn: 'root',
|
|
@@ -1556,36 +1495,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
1556
1495
|
* as a whole.
|
|
1557
1496
|
*/
|
|
1558
1497
|
class ChainOperationEditorComponent {
|
|
1559
|
-
/**
|
|
1560
|
-
* The operation to edit.
|
|
1561
|
-
*/
|
|
1562
|
-
get operation() {
|
|
1563
|
-
return this._operation || undefined;
|
|
1564
|
-
}
|
|
1565
|
-
set operation(value) {
|
|
1566
|
-
if (this._operation === value) {
|
|
1567
|
-
return;
|
|
1568
|
-
}
|
|
1569
|
-
this._operation = value;
|
|
1570
|
-
this.updateForm(value);
|
|
1571
|
-
}
|
|
1572
|
-
/**
|
|
1573
|
-
* The snapshot the operation refers to.
|
|
1574
|
-
*/
|
|
1575
|
-
get snapshot() {
|
|
1576
|
-
return this._snapshot;
|
|
1577
|
-
}
|
|
1578
|
-
set snapshot(value) {
|
|
1579
|
-
if (this._snapshot === value) {
|
|
1580
|
-
return;
|
|
1581
|
-
}
|
|
1582
|
-
const dirty = this.hasTextChanges(value || undefined);
|
|
1583
|
-
this._snapshot = value || undefined;
|
|
1584
|
-
if (dirty) {
|
|
1585
|
-
this.requestPreview();
|
|
1586
|
-
this._editorModel?.setValue(this.svg.value || '');
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
1498
|
constructor(formBuilder, _clipboard, _settings, _dialogService) {
|
|
1590
1499
|
this._clipboard = _clipboard;
|
|
1591
1500
|
this._settings = _settings;
|
|
@@ -1594,18 +1503,30 @@ class ChainOperationEditorComponent {
|
|
|
1594
1503
|
this._disposables = [];
|
|
1595
1504
|
this._nanoid = customAlphabet('1234567890abcdef', 10);
|
|
1596
1505
|
this._editedSourceIndex = -1;
|
|
1506
|
+
/**
|
|
1507
|
+
* The operation to edit.
|
|
1508
|
+
*/
|
|
1509
|
+
this.operation = model();
|
|
1510
|
+
/**
|
|
1511
|
+
* The snapshot the operation refers to.
|
|
1512
|
+
*/
|
|
1513
|
+
this.snapshot = input();
|
|
1514
|
+
/**
|
|
1515
|
+
* Whether to hide the preview request button.
|
|
1516
|
+
*/
|
|
1517
|
+
this.hidePreview = input();
|
|
1597
1518
|
/**
|
|
1598
1519
|
* Emitted when the operation is changed.
|
|
1599
1520
|
*/
|
|
1600
|
-
this.operationChange =
|
|
1521
|
+
this.operationChange = output();
|
|
1601
1522
|
/**
|
|
1602
1523
|
* Emitted when the operation preview is requested.
|
|
1603
1524
|
*/
|
|
1604
|
-
this.operationPreview =
|
|
1525
|
+
this.operationPreview = output();
|
|
1605
1526
|
/**
|
|
1606
1527
|
* Emitted when operation editing is cancelled.
|
|
1607
1528
|
*/
|
|
1608
|
-
this.operationCancel =
|
|
1529
|
+
this.operationCancel = output();
|
|
1609
1530
|
this.tabIndex = 0;
|
|
1610
1531
|
this.hasTo = false;
|
|
1611
1532
|
this.hasToRun = false;
|
|
@@ -1669,6 +1590,19 @@ class ChainOperationEditorComponent {
|
|
|
1669
1590
|
});
|
|
1670
1591
|
// SVG elements
|
|
1671
1592
|
this.elements = [];
|
|
1593
|
+
// when operation changes, update form
|
|
1594
|
+
effect(() => {
|
|
1595
|
+
this.updateForm(this.operation());
|
|
1596
|
+
});
|
|
1597
|
+
// when snapshot changes, update SVG
|
|
1598
|
+
effect(() => {
|
|
1599
|
+
const snapshot = this.snapshot();
|
|
1600
|
+
const dirty = this.hasTextChanges(snapshot || undefined);
|
|
1601
|
+
if (dirty) {
|
|
1602
|
+
this.requestPreview();
|
|
1603
|
+
this._editorModel?.setValue(this.svg.value || '');
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1672
1606
|
}
|
|
1673
1607
|
ngOnInit() {
|
|
1674
1608
|
// whenever svg or base change, update preview
|
|
@@ -1687,25 +1621,25 @@ class ChainOperationEditorComponent {
|
|
|
1687
1621
|
}
|
|
1688
1622
|
}
|
|
1689
1623
|
hasTextChanges(snapshot) {
|
|
1690
|
-
if ((!snapshot && this.
|
|
1624
|
+
if ((!snapshot && this.snapshot()) || (snapshot && !this.snapshot())) {
|
|
1691
1625
|
return true;
|
|
1692
1626
|
}
|
|
1693
|
-
if (snapshot?.size?.width !== this.
|
|
1694
|
-
snapshot?.size?.height !== this.
|
|
1627
|
+
if (snapshot?.size?.width !== this.snapshot()?.size?.width ||
|
|
1628
|
+
snapshot?.size?.height !== this.snapshot()?.size?.height) {
|
|
1695
1629
|
return true;
|
|
1696
1630
|
}
|
|
1697
|
-
if (snapshot?.style !== this.
|
|
1698
|
-
snapshot?.text !== this.
|
|
1699
|
-
snapshot?.textStyle !== this.
|
|
1631
|
+
if (snapshot?.style !== this.snapshot()?.style ||
|
|
1632
|
+
snapshot?.text !== this.snapshot()?.text ||
|
|
1633
|
+
snapshot?.textStyle !== this.snapshot()?.textStyle) {
|
|
1700
1634
|
return true;
|
|
1701
1635
|
}
|
|
1702
1636
|
// compare textOptions returning true if any different
|
|
1703
1637
|
const options = snapshot?.textOptions;
|
|
1704
1638
|
if (options?.lineHeightOffset !==
|
|
1705
|
-
this.
|
|
1639
|
+
this.snapshot()?.textOptions?.lineHeightOffset ||
|
|
1706
1640
|
options?.charSpacingOffset !==
|
|
1707
|
-
this.
|
|
1708
|
-
options?.spcWidthOffset !== this.
|
|
1641
|
+
this.snapshot()?.textOptions?.charSpacingOffset ||
|
|
1642
|
+
options?.spcWidthOffset !== this.snapshot()?.textOptions?.spcWidthOffset) {
|
|
1709
1643
|
return true;
|
|
1710
1644
|
}
|
|
1711
1645
|
return false;
|
|
@@ -1895,6 +1829,7 @@ class ChainOperationEditorComponent {
|
|
|
1895
1829
|
...this.elementFeatures.value,
|
|
1896
1830
|
[this.editedElementId]: features,
|
|
1897
1831
|
});
|
|
1832
|
+
this.editedElementId = undefined;
|
|
1898
1833
|
}
|
|
1899
1834
|
}
|
|
1900
1835
|
// #endregion
|
|
@@ -1999,25 +1934,26 @@ class ChainOperationEditorComponent {
|
|
|
1999
1934
|
if (!this.form.valid) {
|
|
2000
1935
|
return;
|
|
2001
1936
|
}
|
|
2002
|
-
this.
|
|
2003
|
-
this.operationChange.emit(this.
|
|
1937
|
+
this.operation.set(this.getOperation());
|
|
1938
|
+
this.operationChange.emit(this.operation());
|
|
2004
1939
|
}
|
|
2005
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2006
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ChainOperationEditorComponent, isStandalone: true, selector: "gve-chain-operation-editor", inputs: { operation: "operation", snapshot: "snapshot", hidePreview: "hidePreview" }, outputs: { operationChange: "operationChange", operationPreview: "operationPreview", operationCancel: "operationCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <!-- tabs -->\r\n <mat-tab-group\r\n [selectedIndex]=\"tabIndex\"\r\n (selectedIndexChange)=\"onTabIndexChange($event)\"\r\n >\r\n <!-- GENERAL -->\r\n <mat-tab label=\"general\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <div id=\"id\" class=\"muted\">{{ id }}</div>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option [value]=\"0\"\r\n ><mat-icon>layers</mat-icon> replace</mat-option\r\n >\r\n <mat-option [value]=\"1\"\r\n ><mat-icon>close</mat-icon>delete</mat-option\r\n >\r\n <mat-option [value]=\"2\"\r\n ><mat-icon>last_page</mat-icon>add-before</mat-option\r\n >\r\n <mat-option [value]=\"3\"\r\n ><mat-icon>first_page</mat-icon>add-after</mat-option\r\n >\r\n <mat-option [value]=\"4\"\r\n ><mat-icon>login</mat-icon>move-before</mat-option\r\n >\r\n <mat-option [value]=\"5\"\r\n ><mat-icon>logout</mat-icon>move-after</mat-option\r\n >\r\n <mat-option [value]=\"6\"\r\n ><mat-icon>compare_arrows</mat-icon>swap</mat-option\r\n >\r\n <mat-option [value]=\"7\"\r\n ><mat-icon>edit_note</mat-icon>annotate</mat-option\r\n >\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(type).errors?.required && (type.dirty || type.touched)\"\r\n >type required</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- at -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>at</mat-label>\r\n <input matInput [formControl]=\"at\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(at).errors?.required && (at.dirty || at.touched)\"\r\n >at required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- atAsIndex -->\r\n <mat-checkbox [formControl]=\"atAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- run -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>run</mat-label>\r\n <input matInput [formControl]=\"run\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(run).errors?.required && (run.dirty || run.touched)\"\r\n >run required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- to -->\r\n @if (hasTo) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to</mat-label>\r\n <input matInput [formControl]=\"to\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(to).errors?.required && (to.dirty || to.touched)\"\r\n >to required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- toAsIndex -->\r\n <mat-checkbox [formControl]=\"toAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- toRun -->\r\n @if (hasToRun) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to run</mat-label>\r\n <input matInput [formControl]=\"toRun\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(toRun).errors?.required && (toRun.dirty || toRun.touched)\r\n \"\r\n >to run required</mat-error\r\n >\r\n </mat-form-field>\r\n } }\r\n\r\n <!-- value -->\r\n @if (hasValue) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n </mat-form-field>\r\n }\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(rank).errors?.required && (rank.dirty || rank.touched)\"\r\n >rank required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- groupId -->\r\n <mat-form-field>\r\n <mat-label>group ID</mat-label>\r\n <input matInput [formControl]=\"groupId\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(groupId).errors?.required &&\r\n (groupId.dirty || groupId.touched)\r\n \"\r\n >group ID required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- inputTag -->\r\n <mat-form-field>\r\n <mat-label>input tag</mat-label>\r\n <input matInput [formControl]=\"inputTag\" />\r\n <mat-hint>blank=latest</mat-hint>\r\n </mat-form-field>\r\n\r\n <!-- outputTag -->\r\n <mat-form-field>\r\n <mat-label>output tag</mat-label>\r\n <input matInput [formControl]=\"outputTag\" />\r\n <mat-hint>blank=auto (vN)</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n <div>\r\n <!-- features -->\r\n <fieldset>\r\n <legend>operation features</legend>\r\n <gve-feature-set-editor\r\n [isVar]=\"true\"\r\n [features]=\"features.value\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </fieldset>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- SOURCES -->\r\n <mat-tab label=\"sources\">\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addSource()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n source\r\n </button>\r\n </div>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>type</th>\r\n <th>id</th>\r\n <th>rank</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (s of sources.value; track s) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n (click)=\"editSource($index)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button type=\"button\" mat-icon-button color=\"warn\">\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ s.type }}</td>\r\n <td>{{ s.id }}</td>\r\n <td>{{ s.rank }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n <!-- source editor -->\r\n <mat-expansion-panel [disabled]=\"!editedSource\" [expanded]=\"editedSource\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>source</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-operation-source-editor\r\n [source]=\"editedSource\"\r\n (sourceChange)=\"onSourceChange($event!)\"\r\n (sourceCancel)=\"closeSource()\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DIPLOMATIC -->\r\n <mat-tab label=\"diplomatic\">\r\n <div class=\"toolbar-row\">\r\n <button\r\n id=\"btn-save\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Save to file\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"saveSvg()\"\r\n >\r\n <mat-icon>save</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-load\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Load from file\"\r\n (click)=\"loadSvg()\"\r\n >\r\n <mat-icon>folder</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-copy\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Copy\"\r\n [cdkCopyToClipboard]=\"svg.value\"\r\n >\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-paste\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Set SVG from clipboard\"\r\n (click)=\"setSvgFromClipboard()\"\r\n >\r\n <mat-icon>content_paste_go</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-editor\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Open SVG external editor\"\r\n (click)=\"openSvgEditor()\"\r\n >\r\n <mat-icon>launch</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-decimals\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove decimals\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"removeDecimals()\"\r\n >\r\n <mat-icon>pin</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-group\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Wrap code in group\"\r\n (click)=\"wrapInGroup()\"\r\n >\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div id=\"code\">\r\n <nge-monaco-editor\r\n style=\"--editor-height: 400px\"\r\n (ready)=\"onCreateEditor($event)\"\r\n />\r\n @if (svg.invalid) {\r\n <mat-error>invalid SVG</mat-error>\r\n }\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- ELEMENTS -->\r\n <mat-tab label=\"elements\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>id</th>\r\n <th>visual</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (e of elements; track e.id) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Edit element features\"\r\n (click)=\"editElementFeatures(e)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n matTooltip=\"Delete all element features\"\r\n (click)=\"deleteElementFeatures(e)\"\r\n [disabled]=\"!$any(elementFeatures.value[e.id])?.length\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <span>{{ $any(elementFeatures.value[e.id])?.length || 0 }}</span>\r\n </td>\r\n <td class=\"feat-count\">{{ e.id }}</td>\r\n <td class=\"svg-cell\">\r\n <svg [innerHTML]=\"e.outerHTML | safeHtml : 'html'\"></svg>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <mat-expansion-panel\r\n [disabled]=\"!editedElementId\"\r\n [expanded]=\"editedElementId\"\r\n >\r\n <mat-expansion-panel-header>element</mat-expansion-panel-header>\r\n <gve-feature-set-editor\r\n [features]=\"elementFeatures.value[editedElementId!] || []\"\r\n (featuresChange)=\"onElementFeaturesChange($event)\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DP FEATS -->\r\n <mat-tab label=\"d-features\">\r\n <div>\r\n <mat-checkbox [formControl]=\"newTextHidden\">hide new text</mat-checkbox>\r\n </div>\r\n <gve-feature-set-editor\r\n [features]=\"dpFeatures.value\"\r\n (featuresChange)=\"onDpFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- buttons -->\r\n <div id=\"submit-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\r\n mat-icon-button\r\n matTooltip=\"Discard operation\"\r\n (click)=\"cancel()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n @if (!hidePreview) {\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n mat-icon-button\r\n matTooltip=\"Preview operation\"\r\n (click)=\"requestPreview()\"\r\n >\r\n <mat-icon class=\"mat-primary\">preview</mat-icon>\r\n </button>\r\n }\r\n <button\r\n type=\"submit\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save operation\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#submit-row{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap;margin-top:8px;border-top:1px solid silver}.toolbar-row{display:flex;align-items:center;flex-wrap:wrap}.nr{width:5em}.long-text{width:100%;max-width:800px}#id{border-radius:6px;padding:4px;background-color:#beb9b9;color:#fff;margin-top:-16px}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:silver}table{width:100%;border-collapse:collapse;margin:8px 0}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}td.feat-count{vertical-align:super;font-size:smaller}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr{border-bottom:1px solid silver}th,td{text-align:center}#btn-save{color:#072d3e}#btn-load{color:#dbd112}#btn-copy{color:#22549f}#btn-preview{color:#095409}#code{height:500px;border:1px solid silver}#monaco{height:100%}.svg-cell{padding:0 8px}.svg-cell svg{border:1px solid silver;width:100%;height:auto}#preview{box-sizing:border-box;width:100%;border:1px solid silver;border-radius:4px;padding:8px}.tree-invisible{display:none}.tree ul,.tree li{margin-top:0;margin-bottom:0;list-style-type:none}.selected-node{background-color:#e5e5e5}.child-title{font-weight:700;margin:0;background-color:#ccc;color:#fff;padding:8px}#tree-container{display:grid;grid-template-rows:auto;grid-template-columns:auto 1fr;grid-template-areas:\"nav ed\";gap:0 16px;align-items:stretch}#tree-nav{grid-area:nav;border:1px solid silver;border-radius:6px;margin:8px 0;padding-right:8px}#tree-ed{grid-area:ed;border:1px solid silver;border-radius:6px;margin:8px 0}@media only screen and (max-width: 959px){div#container{grid-template-columns:1fr;grid-template-areas:\"nav\" \"ed\";gap:16px 0;align-items:start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { 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:
|
|
1940
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: ChainOperationEditorComponent, deps: [{ token: i1.FormBuilder }, { token: i2$3.Clipboard }, { token: SettingsService }, { token: i2$1.DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1941
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: ChainOperationEditorComponent, isStandalone: true, selector: "gve-chain-operation-editor", inputs: { operation: { classPropertyName: "operation", publicName: "operation", isSignal: true, isRequired: false, transformFunction: null }, snapshot: { classPropertyName: "snapshot", publicName: "snapshot", isSignal: true, isRequired: false, transformFunction: null }, hidePreview: { classPropertyName: "hidePreview", publicName: "hidePreview", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operation: "operationChange", operationChange: "operationChange", operationPreview: "operationPreview", operationCancel: "operationCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <!-- tabs -->\r\n <mat-tab-group\r\n [selectedIndex]=\"tabIndex\"\r\n (selectedIndexChange)=\"onTabIndexChange($event)\"\r\n >\r\n <!-- GENERAL -->\r\n <mat-tab label=\"general\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <div id=\"id\" class=\"muted\">{{ id }}</div>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option [value]=\"0\"\r\n ><mat-icon>layers</mat-icon> replace</mat-option\r\n >\r\n <mat-option [value]=\"1\"\r\n ><mat-icon>close</mat-icon>delete</mat-option\r\n >\r\n <mat-option [value]=\"2\"\r\n ><mat-icon>last_page</mat-icon>add-before</mat-option\r\n >\r\n <mat-option [value]=\"3\"\r\n ><mat-icon>first_page</mat-icon>add-after</mat-option\r\n >\r\n <mat-option [value]=\"4\"\r\n ><mat-icon>login</mat-icon>move-before</mat-option\r\n >\r\n <mat-option [value]=\"5\"\r\n ><mat-icon>logout</mat-icon>move-after</mat-option\r\n >\r\n <mat-option [value]=\"6\"\r\n ><mat-icon>compare_arrows</mat-icon>swap</mat-option\r\n >\r\n <mat-option [value]=\"7\"\r\n ><mat-icon>edit_note</mat-icon>annotate</mat-option\r\n >\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(type).errors?.required && (type.dirty || type.touched)\"\r\n >type required</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- at -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>at</mat-label>\r\n <input matInput [formControl]=\"at\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(at).errors?.required && (at.dirty || at.touched)\"\r\n >at required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- atAsIndex -->\r\n <mat-checkbox [formControl]=\"atAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- run -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>run</mat-label>\r\n <input matInput [formControl]=\"run\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(run).errors?.required && (run.dirty || run.touched)\"\r\n >run required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- to -->\r\n @if (hasTo) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to</mat-label>\r\n <input matInput [formControl]=\"to\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(to).errors?.required && (to.dirty || to.touched)\"\r\n >to required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- toAsIndex -->\r\n <mat-checkbox [formControl]=\"toAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- toRun -->\r\n @if (hasToRun) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to run</mat-label>\r\n <input matInput [formControl]=\"toRun\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(toRun).errors?.required && (toRun.dirty || toRun.touched)\r\n \"\r\n >to run required</mat-error\r\n >\r\n </mat-form-field>\r\n } }\r\n\r\n <!-- value -->\r\n @if (hasValue) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n </mat-form-field>\r\n }\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(rank).errors?.required && (rank.dirty || rank.touched)\"\r\n >rank required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- groupId -->\r\n <mat-form-field>\r\n <mat-label>group ID</mat-label>\r\n <input matInput [formControl]=\"groupId\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(groupId).errors?.required &&\r\n (groupId.dirty || groupId.touched)\r\n \"\r\n >group ID required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- inputTag -->\r\n <mat-form-field>\r\n <mat-label>input tag</mat-label>\r\n <input matInput [formControl]=\"inputTag\" />\r\n <mat-hint>blank=latest</mat-hint>\r\n </mat-form-field>\r\n\r\n <!-- outputTag -->\r\n <mat-form-field>\r\n <mat-label>output tag</mat-label>\r\n <input matInput [formControl]=\"outputTag\" />\r\n <mat-hint>blank=auto (vN)</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n <div>\r\n <!-- features -->\r\n <fieldset>\r\n <legend>operation features</legend>\r\n <gve-feature-set-editor\r\n [isVar]=\"true\"\r\n [features]=\"features.value\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </fieldset>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- SOURCES -->\r\n <mat-tab label=\"sources\">\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addSource()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n source\r\n </button>\r\n </div>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>type</th>\r\n <th>id</th>\r\n <th>rank</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (s of sources.value; track s) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n (click)=\"editSource($index)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button type=\"button\" mat-icon-button color=\"warn\">\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ s.type }}</td>\r\n <td>{{ s.id }}</td>\r\n <td>{{ s.rank }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n <!-- source editor -->\r\n <mat-expansion-panel [disabled]=\"!editedSource\" [expanded]=\"editedSource\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>source</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-operation-source-editor\r\n [source]=\"editedSource\"\r\n (sourceChange)=\"onSourceChange($event!)\"\r\n (sourceCancel)=\"closeSource()\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DIPLOMATIC -->\r\n <mat-tab label=\"diplomatic\">\r\n <div class=\"toolbar-row\">\r\n <button\r\n id=\"btn-save\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Save to file\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"saveSvg()\"\r\n >\r\n <mat-icon>save</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-load\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Load from file\"\r\n (click)=\"loadSvg()\"\r\n >\r\n <mat-icon>folder</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-copy\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Copy\"\r\n [cdkCopyToClipboard]=\"svg.value\"\r\n >\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-paste\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Set SVG from clipboard\"\r\n (click)=\"setSvgFromClipboard()\"\r\n >\r\n <mat-icon>content_paste_go</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-editor\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Open SVG external editor\"\r\n (click)=\"openSvgEditor()\"\r\n >\r\n <mat-icon>launch</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-decimals\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove decimals\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"removeDecimals()\"\r\n >\r\n <mat-icon>pin</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-group\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Wrap code in group\"\r\n (click)=\"wrapInGroup()\"\r\n >\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div id=\"code\">\r\n <nge-monaco-editor\r\n style=\"--editor-height: 400px\"\r\n (ready)=\"onCreateEditor($event)\"\r\n />\r\n @if (svg.invalid) {\r\n <mat-error>invalid SVG</mat-error>\r\n }\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- ELEMENTS -->\r\n <mat-tab label=\"elements\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>id</th>\r\n <th>visual</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (e of elements; track e.id) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Edit element features\"\r\n (click)=\"editElementFeatures(e)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n matTooltip=\"Delete all element features\"\r\n (click)=\"deleteElementFeatures(e)\"\r\n [disabled]=\"!$any(elementFeatures.value)[e.id]?.length\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n <span\r\n [matBadge]=\"$any(elementFeatures.value)[e.id]?.length || 0\"\r\n [matBadgeHidden]=\"!$any(elementFeatures.value)[e.id]?.length\"\r\n matBadgeOverlap=\"false\"\r\n >{{ e.id }}</span\r\n >\r\n </td>\r\n <td class=\"svg-cell\">\r\n <svg [innerHTML]=\"e.outerHTML | safeHtml : 'html'\"></svg>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <mat-expansion-panel\r\n [disabled]=\"!editedElementId\"\r\n [expanded]=\"editedElementId\"\r\n >\r\n <mat-expansion-panel-header>{{\r\n editedElementId\r\n }}</mat-expansion-panel-header>\r\n <gve-feature-set-editor\r\n [features]=\"elementFeatures.value[editedElementId!] || []\"\r\n (featuresChange)=\"onElementFeaturesChange($event)\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DP FEATS -->\r\n <mat-tab label=\"d-features\">\r\n <div>\r\n <mat-checkbox [formControl]=\"newTextHidden\">hide new text</mat-checkbox>\r\n </div>\r\n <gve-feature-set-editor\r\n [features]=\"dpFeatures.value\"\r\n (featuresChange)=\"onDpFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- buttons -->\r\n <div id=\"submit-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\r\n mat-icon-button\r\n matTooltip=\"Discard operation\"\r\n (click)=\"cancel()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n @if (!hidePreview()) {\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n mat-icon-button\r\n matTooltip=\"Preview operation\"\r\n (click)=\"requestPreview()\"\r\n >\r\n <mat-icon class=\"mat-primary\">preview</mat-icon>\r\n </button>\r\n }\r\n <button\r\n type=\"submit\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save operation\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#submit-row{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap;margin-top:8px;border-top:1px solid silver}.toolbar-row{display:flex;align-items:center;flex-wrap:wrap}.nr{width:5em}.long-text{width:100%;max-width:800px}#id{border-radius:6px;padding:4px;background-color:#beb9b9;color:#fff;margin-top:-16px}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:silver}table{width:100%;border-collapse:collapse;margin:8px 0}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr{border-bottom:1px solid silver}th,td{text-align:center}#btn-save{color:#072d3e}#btn-load{color:#dbd112}#btn-copy{color:#22549f}#btn-preview{color:#095409}#code{height:500px;border:1px solid silver}#monaco{height:100%}.svg-cell{padding:0 8px}.svg-cell svg{border:1px solid silver;width:100%;height:auto}#preview{box-sizing:border-box;width:100%;border:1px solid silver;border-radius:4px;padding:8px}.tree-invisible{display:none}.tree ul,.tree li{margin-top:0;margin-bottom:0;list-style-type:none}.selected-node{background-color:#e5e5e5}.child-title{font-weight:700;margin:0;background-color:#ccc;color:#fff;padding:8px}#tree-container{display:grid;grid-template-rows:auto;grid-template-columns:auto 1fr;grid-template-areas:\"nav ed\";gap:0 16px;align-items:stretch}#tree-nav{grid-area:nav;border:1px solid silver;border-radius:6px;margin:8px 0;padding-right:8px}#tree-ed{grid-area:ed;border:1px solid silver;border-radius:6px;margin:8px 0}@media only screen and (max-width: 959px){div#container{grid-template-columns:1fr;grid-template-areas:\"nav\" \"ed\";gap:16px 0;align-items:start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { 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:
|
|
2007
1942
|
// material
|
|
2008
|
-
ClipboardModule }, { kind: "directive", type: i2$3.CdkCopyToClipboard, selector: "[cdkCopyToClipboard]", inputs: ["cdkCopyToClipboard", "cdkCopyToClipboardAttempts"], outputs: ["cdkCopyToClipboardCopied"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4$1.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: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type:
|
|
1943
|
+
ClipboardModule }, { kind: "directive", type: i2$3.CdkCopyToClipboard, selector: "[cdkCopyToClipboard]", inputs: ["cdkCopyToClipboard", "cdkCopyToClipboardAttempts"], outputs: ["cdkCopyToClipboardCopied"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i6$1.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4$1.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: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i16.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i16.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type:
|
|
2009
1944
|
// monaco
|
|
2010
|
-
NgeMonacoModule }, { kind: "component", type:
|
|
1945
|
+
NgeMonacoModule }, { kind: "component", type: i17.NgeMonacoEditorComponent, selector: "nge-monaco-editor", inputs: ["autoLayout", "options"], outputs: ["ready"] }, { kind: "pipe", type:
|
|
2011
1946
|
// myrmex
|
|
2012
1947
|
SafeHtmlPipe, name: "safeHtml" }, { kind: "component", type: FeatureSetEditorComponent, selector: "gve-feature-set-editor", inputs: ["isVar", "featNames", "featValues", "filterThreshold", "features"], outputs: ["featuresChange"] }, { kind: "component", type: OperationSourceEditorComponent, selector: "gve-operation-source-editor", inputs: ["source", "ids", "types"], outputs: ["sourceChange", "sourceCancel"] }] }); }
|
|
2013
1948
|
}
|
|
2014
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
1949
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: ChainOperationEditorComponent, decorators: [{
|
|
2015
1950
|
type: Component,
|
|
2016
1951
|
args: [{ selector: 'gve-chain-operation-editor', imports: [
|
|
2017
1952
|
CommonModule,
|
|
2018
1953
|
ReactiveFormsModule,
|
|
2019
1954
|
// material
|
|
2020
1955
|
ClipboardModule,
|
|
1956
|
+
MatBadgeModule,
|
|
2021
1957
|
MatButtonModule,
|
|
2022
1958
|
MatCheckboxModule,
|
|
2023
1959
|
MatExpansionModule,
|
|
@@ -2033,20 +1969,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2033
1969
|
SafeHtmlPipe,
|
|
2034
1970
|
FeatureSetEditorComponent,
|
|
2035
1971
|
OperationSourceEditorComponent,
|
|
2036
|
-
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <!-- tabs -->\r\n <mat-tab-group\r\n [selectedIndex]=\"tabIndex\"\r\n (selectedIndexChange)=\"onTabIndexChange($event)\"\r\n >\r\n <!-- GENERAL -->\r\n <mat-tab label=\"general\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <div id=\"id\" class=\"muted\">{{ id }}</div>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option [value]=\"0\"\r\n ><mat-icon>layers</mat-icon> replace</mat-option\r\n >\r\n <mat-option [value]=\"1\"\r\n ><mat-icon>close</mat-icon>delete</mat-option\r\n >\r\n <mat-option [value]=\"2\"\r\n ><mat-icon>last_page</mat-icon>add-before</mat-option\r\n >\r\n <mat-option [value]=\"3\"\r\n ><mat-icon>first_page</mat-icon>add-after</mat-option\r\n >\r\n <mat-option [value]=\"4\"\r\n ><mat-icon>login</mat-icon>move-before</mat-option\r\n >\r\n <mat-option [value]=\"5\"\r\n ><mat-icon>logout</mat-icon>move-after</mat-option\r\n >\r\n <mat-option [value]=\"6\"\r\n ><mat-icon>compare_arrows</mat-icon>swap</mat-option\r\n >\r\n <mat-option [value]=\"7\"\r\n ><mat-icon>edit_note</mat-icon>annotate</mat-option\r\n >\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(type).errors?.required && (type.dirty || type.touched)\"\r\n >type required</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- at -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>at</mat-label>\r\n <input matInput [formControl]=\"at\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(at).errors?.required && (at.dirty || at.touched)\"\r\n >at required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- atAsIndex -->\r\n <mat-checkbox [formControl]=\"atAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- run -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>run</mat-label>\r\n <input matInput [formControl]=\"run\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(run).errors?.required && (run.dirty || run.touched)\"\r\n >run required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- to -->\r\n @if (hasTo) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to</mat-label>\r\n <input matInput [formControl]=\"to\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(to).errors?.required && (to.dirty || to.touched)\"\r\n >to required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- toAsIndex -->\r\n <mat-checkbox [formControl]=\"toAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- toRun -->\r\n @if (hasToRun) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to run</mat-label>\r\n <input matInput [formControl]=\"toRun\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(toRun).errors?.required && (toRun.dirty || toRun.touched)\r\n \"\r\n >to run required</mat-error\r\n >\r\n </mat-form-field>\r\n } }\r\n\r\n <!-- value -->\r\n @if (hasValue) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n </mat-form-field>\r\n }\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(rank).errors?.required && (rank.dirty || rank.touched)\"\r\n >rank required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- groupId -->\r\n <mat-form-field>\r\n <mat-label>group ID</mat-label>\r\n <input matInput [formControl]=\"groupId\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(groupId).errors?.required &&\r\n (groupId.dirty || groupId.touched)\r\n \"\r\n >group ID required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- inputTag -->\r\n <mat-form-field>\r\n <mat-label>input tag</mat-label>\r\n <input matInput [formControl]=\"inputTag\" />\r\n <mat-hint>blank=latest</mat-hint>\r\n </mat-form-field>\r\n\r\n <!-- outputTag -->\r\n <mat-form-field>\r\n <mat-label>output tag</mat-label>\r\n <input matInput [formControl]=\"outputTag\" />\r\n <mat-hint>blank=auto (vN)</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n <div>\r\n <!-- features -->\r\n <fieldset>\r\n <legend>operation features</legend>\r\n <gve-feature-set-editor\r\n [isVar]=\"true\"\r\n [features]=\"features.value\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </fieldset>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- SOURCES -->\r\n <mat-tab label=\"sources\">\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addSource()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n source\r\n </button>\r\n </div>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>type</th>\r\n <th>id</th>\r\n <th>rank</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (s of sources.value; track s) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n (click)=\"editSource($index)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button type=\"button\" mat-icon-button color=\"warn\">\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ s.type }}</td>\r\n <td>{{ s.id }}</td>\r\n <td>{{ s.rank }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n <!-- source editor -->\r\n <mat-expansion-panel [disabled]=\"!editedSource\" [expanded]=\"editedSource\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>source</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-operation-source-editor\r\n [source]=\"editedSource\"\r\n (sourceChange)=\"onSourceChange($event!)\"\r\n (sourceCancel)=\"closeSource()\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DIPLOMATIC -->\r\n <mat-tab label=\"diplomatic\">\r\n <div class=\"toolbar-row\">\r\n <button\r\n id=\"btn-save\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Save to file\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"saveSvg()\"\r\n >\r\n <mat-icon>save</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-load\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Load from file\"\r\n (click)=\"loadSvg()\"\r\n >\r\n <mat-icon>folder</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-copy\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Copy\"\r\n [cdkCopyToClipboard]=\"svg.value\"\r\n >\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-paste\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Set SVG from clipboard\"\r\n (click)=\"setSvgFromClipboard()\"\r\n >\r\n <mat-icon>content_paste_go</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-editor\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Open SVG external editor\"\r\n (click)=\"openSvgEditor()\"\r\n >\r\n <mat-icon>launch</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-decimals\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove decimals\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"removeDecimals()\"\r\n >\r\n <mat-icon>pin</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-group\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Wrap code in group\"\r\n (click)=\"wrapInGroup()\"\r\n >\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div id=\"code\">\r\n <nge-monaco-editor\r\n style=\"--editor-height: 400px\"\r\n (ready)=\"onCreateEditor($event)\"\r\n />\r\n @if (svg.invalid) {\r\n <mat-error>invalid SVG</mat-error>\r\n }\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- ELEMENTS -->\r\n <mat-tab label=\"elements\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>id</th>\r\n <th>visual</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (e of elements; track e.id) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Edit element features\"\r\n (click)=\"editElementFeatures(e)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n matTooltip=\"Delete all element features\"\r\n (click)=\"deleteElementFeatures(e)\"\r\n [disabled]=\"!$any(elementFeatures.value[e.id])?.length\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <span>{{ $any(elementFeatures.value[e.id])?.length || 0 }}</span>\r\n </td>\r\n <td class=\"feat-count\">{{ e.id }}</td>\r\n <td class=\"svg-cell\">\r\n <svg [innerHTML]=\"e.outerHTML | safeHtml : 'html'\"></svg>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <mat-expansion-panel\r\n [disabled]=\"!editedElementId\"\r\n [expanded]=\"editedElementId\"\r\n >\r\n <mat-expansion-panel-header>element</mat-expansion-panel-header>\r\n <gve-feature-set-editor\r\n [features]=\"elementFeatures.value[editedElementId!] || []\"\r\n (featuresChange)=\"onElementFeaturesChange($event)\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DP FEATS -->\r\n <mat-tab label=\"d-features\">\r\n <div>\r\n <mat-checkbox [formControl]=\"newTextHidden\">hide new text</mat-checkbox>\r\n </div>\r\n <gve-feature-set-editor\r\n [features]=\"dpFeatures.value\"\r\n (featuresChange)=\"onDpFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- buttons -->\r\n <div id=\"submit-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\r\n mat-icon-button\r\n matTooltip=\"Discard operation\"\r\n (click)=\"cancel()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n @if (!hidePreview) {\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n mat-icon-button\r\n matTooltip=\"Preview operation\"\r\n (click)=\"requestPreview()\"\r\n >\r\n <mat-icon class=\"mat-primary\">preview</mat-icon>\r\n </button>\r\n }\r\n <button\r\n type=\"submit\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save operation\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#submit-row{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap;margin-top:8px;border-top:1px solid silver}.toolbar-row{display:flex;align-items:center;flex-wrap:wrap}.nr{width:5em}.long-text{width:100%;max-width:800px}#id{border-radius:6px;padding:4px;background-color:#beb9b9;color:#fff;margin-top:-16px}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:silver}table{width:100%;border-collapse:collapse;margin:8px 0}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}td.feat-count{vertical-align:super;font-size:smaller}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr{border-bottom:1px solid silver}th,td{text-align:center}#btn-save{color:#072d3e}#btn-load{color:#dbd112}#btn-copy{color:#22549f}#btn-preview{color:#095409}#code{height:500px;border:1px solid silver}#monaco{height:100%}.svg-cell{padding:0 8px}.svg-cell svg{border:1px solid silver;width:100%;height:auto}#preview{box-sizing:border-box;width:100%;border:1px solid silver;border-radius:4px;padding:8px}.tree-invisible{display:none}.tree ul,.tree li{margin-top:0;margin-bottom:0;list-style-type:none}.selected-node{background-color:#e5e5e5}.child-title{font-weight:700;margin:0;background-color:#ccc;color:#fff;padding:8px}#tree-container{display:grid;grid-template-rows:auto;grid-template-columns:auto 1fr;grid-template-areas:\"nav ed\";gap:0 16px;align-items:stretch}#tree-nav{grid-area:nav;border:1px solid silver;border-radius:6px;margin:8px 0;padding-right:8px}#tree-ed{grid-area:ed;border:1px solid silver;border-radius:6px;margin:8px 0}@media only screen and (max-width: 959px){div#container{grid-template-columns:1fr;grid-template-areas:\"nav\" \"ed\";gap:16px 0;align-items:start}}\n"] }]
|
|
2037
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$3.Clipboard }, { type: SettingsService }, { type: i2$1.DialogService }]
|
|
2038
|
-
type: Input
|
|
2039
|
-
}], snapshot: [{
|
|
2040
|
-
type: Input
|
|
2041
|
-
}], hidePreview: [{
|
|
2042
|
-
type: Input
|
|
2043
|
-
}], operationChange: [{
|
|
2044
|
-
type: Output
|
|
2045
|
-
}], operationPreview: [{
|
|
2046
|
-
type: Output
|
|
2047
|
-
}], operationCancel: [{
|
|
2048
|
-
type: Output
|
|
2049
|
-
}] } });
|
|
1972
|
+
], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <!-- tabs -->\r\n <mat-tab-group\r\n [selectedIndex]=\"tabIndex\"\r\n (selectedIndexChange)=\"onTabIndexChange($event)\"\r\n >\r\n <!-- GENERAL -->\r\n <mat-tab label=\"general\">\r\n <div class=\"form-row\">\r\n <!-- id -->\r\n <div id=\"id\" class=\"muted\">{{ id }}</div>\r\n\r\n <!-- type -->\r\n <mat-form-field>\r\n <mat-label>type</mat-label>\r\n <mat-select [formControl]=\"type\">\r\n <mat-option [value]=\"0\"\r\n ><mat-icon>layers</mat-icon> replace</mat-option\r\n >\r\n <mat-option [value]=\"1\"\r\n ><mat-icon>close</mat-icon>delete</mat-option\r\n >\r\n <mat-option [value]=\"2\"\r\n ><mat-icon>last_page</mat-icon>add-before</mat-option\r\n >\r\n <mat-option [value]=\"3\"\r\n ><mat-icon>first_page</mat-icon>add-after</mat-option\r\n >\r\n <mat-option [value]=\"4\"\r\n ><mat-icon>login</mat-icon>move-before</mat-option\r\n >\r\n <mat-option [value]=\"5\"\r\n ><mat-icon>logout</mat-icon>move-after</mat-option\r\n >\r\n <mat-option [value]=\"6\"\r\n ><mat-icon>compare_arrows</mat-icon>swap</mat-option\r\n >\r\n <mat-option [value]=\"7\"\r\n ><mat-icon>edit_note</mat-icon>annotate</mat-option\r\n >\r\n </mat-select>\r\n <mat-error\r\n *ngIf=\"$any(type).errors?.required && (type.dirty || type.touched)\"\r\n >type required</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- at -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>at</mat-label>\r\n <input matInput [formControl]=\"at\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(at).errors?.required && (at.dirty || at.touched)\"\r\n >at required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- atAsIndex -->\r\n <mat-checkbox [formControl]=\"atAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- run -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>run</mat-label>\r\n <input matInput [formControl]=\"run\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(run).errors?.required && (run.dirty || run.touched)\"\r\n >run required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- to -->\r\n @if (hasTo) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to</mat-label>\r\n <input matInput [formControl]=\"to\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(to).errors?.required && (to.dirty || to.touched)\"\r\n >to required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- toAsIndex -->\r\n <mat-checkbox [formControl]=\"toAsIndex\">idx</mat-checkbox>\r\n\r\n <!-- toRun -->\r\n @if (hasToRun) {\r\n <mat-form-field class=\"nr\">\r\n <mat-label>to run</mat-label>\r\n <input matInput [formControl]=\"toRun\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(toRun).errors?.required && (toRun.dirty || toRun.touched)\r\n \"\r\n >to run required</mat-error\r\n >\r\n </mat-form-field>\r\n } }\r\n\r\n <!-- value -->\r\n @if (hasValue) {\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n </mat-form-field>\r\n }\r\n </div>\r\n <div class=\"form-row\">\r\n <!-- rank -->\r\n <mat-form-field class=\"nr\">\r\n <mat-label>rank</mat-label>\r\n <input matInput [formControl]=\"rank\" type=\"number\" min=\"0\" />\r\n <mat-error\r\n *ngIf=\"$any(rank).errors?.required && (rank.dirty || rank.touched)\"\r\n >rank required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- groupId -->\r\n <mat-form-field>\r\n <mat-label>group ID</mat-label>\r\n <input matInput [formControl]=\"groupId\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(groupId).errors?.required &&\r\n (groupId.dirty || groupId.touched)\r\n \"\r\n >group ID required</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- inputTag -->\r\n <mat-form-field>\r\n <mat-label>input tag</mat-label>\r\n <input matInput [formControl]=\"inputTag\" />\r\n <mat-hint>blank=latest</mat-hint>\r\n </mat-form-field>\r\n\r\n <!-- outputTag -->\r\n <mat-form-field>\r\n <mat-label>output tag</mat-label>\r\n <input matInput [formControl]=\"outputTag\" />\r\n <mat-hint>blank=auto (vN)</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n <div>\r\n <!-- features -->\r\n <fieldset>\r\n <legend>operation features</legend>\r\n <gve-feature-set-editor\r\n [isVar]=\"true\"\r\n [features]=\"features.value\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </fieldset>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- SOURCES -->\r\n <mat-tab label=\"sources\">\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n (click)=\"addSource()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n source\r\n </button>\r\n </div>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>type</th>\r\n <th>id</th>\r\n <th>rank</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (s of sources.value; track s) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n (click)=\"editSource($index)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button type=\"button\" mat-icon-button color=\"warn\">\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ s.type }}</td>\r\n <td>{{ s.id }}</td>\r\n <td>{{ s.rank }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n <!-- source editor -->\r\n <mat-expansion-panel [disabled]=\"!editedSource\" [expanded]=\"editedSource\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>source</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <gve-operation-source-editor\r\n [source]=\"editedSource\"\r\n (sourceChange)=\"onSourceChange($event!)\"\r\n (sourceCancel)=\"closeSource()\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DIPLOMATIC -->\r\n <mat-tab label=\"diplomatic\">\r\n <div class=\"toolbar-row\">\r\n <button\r\n id=\"btn-save\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Save to file\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"saveSvg()\"\r\n >\r\n <mat-icon>save</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-load\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Load from file\"\r\n (click)=\"loadSvg()\"\r\n >\r\n <mat-icon>folder</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-copy\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Copy\"\r\n [cdkCopyToClipboard]=\"svg.value\"\r\n >\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-paste\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Set SVG from clipboard\"\r\n (click)=\"setSvgFromClipboard()\"\r\n >\r\n <mat-icon>content_paste_go</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-editor\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Open SVG external editor\"\r\n (click)=\"openSvgEditor()\"\r\n >\r\n <mat-icon>launch</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-decimals\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Remove decimals\"\r\n [disabled]=\"!svg.value\"\r\n (click)=\"removeDecimals()\"\r\n >\r\n <mat-icon>pin</mat-icon>\r\n </button>\r\n <button\r\n id=\"btn-group\"\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Wrap code in group\"\r\n (click)=\"wrapInGroup()\"\r\n >\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div id=\"code\">\r\n <nge-monaco-editor\r\n style=\"--editor-height: 400px\"\r\n (ready)=\"onCreateEditor($event)\"\r\n />\r\n @if (svg.invalid) {\r\n <mat-error>invalid SVG</mat-error>\r\n }\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- ELEMENTS -->\r\n <mat-tab label=\"elements\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>id</th>\r\n <th>visual</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (e of elements; track e.id) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Edit element features\"\r\n (click)=\"editElementFeatures(e)\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n matTooltip=\"Delete all element features\"\r\n (click)=\"deleteElementFeatures(e)\"\r\n [disabled]=\"!$any(elementFeatures.value)[e.id]?.length\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n <span\r\n [matBadge]=\"$any(elementFeatures.value)[e.id]?.length || 0\"\r\n [matBadgeHidden]=\"!$any(elementFeatures.value)[e.id]?.length\"\r\n matBadgeOverlap=\"false\"\r\n >{{ e.id }}</span\r\n >\r\n </td>\r\n <td class=\"svg-cell\">\r\n <svg [innerHTML]=\"e.outerHTML | safeHtml : 'html'\"></svg>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <mat-expansion-panel\r\n [disabled]=\"!editedElementId\"\r\n [expanded]=\"editedElementId\"\r\n >\r\n <mat-expansion-panel-header>{{\r\n editedElementId\r\n }}</mat-expansion-panel-header>\r\n <gve-feature-set-editor\r\n [features]=\"elementFeatures.value[editedElementId!] || []\"\r\n (featuresChange)=\"onElementFeaturesChange($event)\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- DP FEATS -->\r\n <mat-tab label=\"d-features\">\r\n <div>\r\n <mat-checkbox [formControl]=\"newTextHidden\">hide new text</mat-checkbox>\r\n </div>\r\n <gve-feature-set-editor\r\n [features]=\"dpFeatures.value\"\r\n (featuresChange)=\"onDpFeaturesChange($event)\"\r\n ></gve-feature-set-editor>\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- buttons -->\r\n <div id=\"submit-row\">\r\n <button\r\n type=\"button\"\r\n color=\"warn\"\r\n mat-icon-button\r\n matTooltip=\"Discard operation\"\r\n (click)=\"cancel()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n @if (!hidePreview()) {\r\n <button\r\n type=\"button\"\r\n color=\"primary\"\r\n mat-icon-button\r\n matTooltip=\"Preview operation\"\r\n (click)=\"requestPreview()\"\r\n >\r\n <mat-icon class=\"mat-primary\">preview</mat-icon>\r\n </button>\r\n }\r\n <button\r\n type=\"submit\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save operation\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#submit-row{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap;margin-top:8px;border-top:1px solid silver}.toolbar-row{display:flex;align-items:center;flex-wrap:wrap}.nr{width:5em}.long-text{width:100%;max-width:800px}#id{border-radius:6px;padding:4px;background-color:#beb9b9;color:#fff;margin-top:-16px}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:silver}table{width:100%;border-collapse:collapse;margin:8px 0}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr{border-bottom:1px solid silver}th,td{text-align:center}#btn-save{color:#072d3e}#btn-load{color:#dbd112}#btn-copy{color:#22549f}#btn-preview{color:#095409}#code{height:500px;border:1px solid silver}#monaco{height:100%}.svg-cell{padding:0 8px}.svg-cell svg{border:1px solid silver;width:100%;height:auto}#preview{box-sizing:border-box;width:100%;border:1px solid silver;border-radius:4px;padding:8px}.tree-invisible{display:none}.tree ul,.tree li{margin-top:0;margin-bottom:0;list-style-type:none}.selected-node{background-color:#e5e5e5}.child-title{font-weight:700;margin:0;background-color:#ccc;color:#fff;padding:8px}#tree-container{display:grid;grid-template-rows:auto;grid-template-columns:auto 1fr;grid-template-areas:\"nav ed\";gap:0 16px;align-items:stretch}#tree-nav{grid-area:nav;border:1px solid silver;border-radius:6px;margin:8px 0;padding-right:8px}#tree-ed{grid-area:ed;border:1px solid silver;border-radius:6px;margin:8px 0}@media only screen and (max-width: 959px){div#container{grid-template-columns:1fr;grid-template-areas:\"nav\" \"ed\";gap:16px 0;align-items:start}}\n"] }]
|
|
1973
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$3.Clipboard }, { type: SettingsService }, { type: i2$1.DialogService }] });
|
|
2050
1974
|
|
|
2051
1975
|
/**
|
|
2052
1976
|
* 🔑 `gve-feature-set-view`
|
|
@@ -2066,34 +1990,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2066
1990
|
* is greater than the threshold. Default is 5.
|
|
2067
1991
|
*/
|
|
2068
1992
|
class FeatureSetViewComponent {
|
|
2069
|
-
/**
|
|
2070
|
-
* The features.
|
|
2071
|
-
*/
|
|
2072
|
-
get features() {
|
|
2073
|
-
return this._features;
|
|
2074
|
-
}
|
|
2075
|
-
set features(value) {
|
|
2076
|
-
if (this._features === value) {
|
|
2077
|
-
return;
|
|
2078
|
-
}
|
|
2079
|
-
this._features = value || undefined;
|
|
2080
|
-
this.filter.reset();
|
|
2081
|
-
this.applyFeatureFilter();
|
|
2082
|
-
}
|
|
2083
1993
|
constructor(formBuilder) {
|
|
2084
|
-
|
|
1994
|
+
/**
|
|
1995
|
+
* The features.
|
|
1996
|
+
*/
|
|
1997
|
+
this.features = input([]);
|
|
1998
|
+
/**
|
|
1999
|
+
* The list of feature names to display in the name selection.
|
|
2000
|
+
* This is used when you have a closed list of features.
|
|
2001
|
+
*/
|
|
2002
|
+
this.featNames = input();
|
|
2003
|
+
/**
|
|
2004
|
+
* The feature values map. When specified and the user selects a feature
|
|
2005
|
+
* name present in the map keys, the corresponding values will be used
|
|
2006
|
+
* to populate the value selection.
|
|
2007
|
+
*/
|
|
2008
|
+
this.featValues = input();
|
|
2085
2009
|
/**
|
|
2086
2010
|
* The threshold at which the features filter should become visible.
|
|
2087
2011
|
* If set to 0, the filter is always visible; if set to -1, it is always
|
|
2088
2012
|
* invisible; otherwise, it gets visible when the number of features
|
|
2089
2013
|
* is greater than the threshold. Default is 5.
|
|
2090
2014
|
*/
|
|
2091
|
-
this.filterThreshold = 5;
|
|
2015
|
+
this.filterThreshold = input(5);
|
|
2092
2016
|
this.filteredFeatures = [];
|
|
2093
2017
|
this.filter = formBuilder.control(null);
|
|
2018
|
+
// when features change, reset the filter and apply it
|
|
2019
|
+
effect(() => {
|
|
2020
|
+
const features = this.features();
|
|
2021
|
+
this.filter.reset();
|
|
2022
|
+
this.applyFeatureFilter();
|
|
2023
|
+
});
|
|
2094
2024
|
}
|
|
2095
2025
|
applyFeatureFilter(name) {
|
|
2096
|
-
this.filteredFeatures = this.
|
|
2026
|
+
this.filteredFeatures = this.features().filter((feature) => {
|
|
2097
2027
|
return !name || feature.name.toLowerCase().includes(name.toLowerCase());
|
|
2098
2028
|
});
|
|
2099
2029
|
}
|
|
@@ -2108,10 +2038,10 @@ class FeatureSetViewComponent {
|
|
|
2108
2038
|
ngOnDestroy() {
|
|
2109
2039
|
this._sub?.unsubscribe();
|
|
2110
2040
|
}
|
|
2111
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2112
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
2041
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: FeatureSetViewComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2042
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: FeatureSetViewComponent, isStandalone: true, selector: "gve-feature-set-view", inputs: { features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: false, transformFunction: null }, featNames: { classPropertyName: "featNames", publicName: "featNames", isSignal: true, isRequired: false, transformFunction: null }, featValues: { classPropertyName: "featValues", publicName: "featValues", isSignal: true, isRequired: false, transformFunction: null }, filterThreshold: { classPropertyName: "filterThreshold", publicName: "filterThreshold", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div>\r\n <!-- filter -->\r\n <div>\r\n @if (filterThreshold() === 0 || features()!.length > filterThreshold()) {\r\n <div class=\"form-row\">\r\n <mat-form-field id=\"filter\">\r\n <mat-label>filter</mat-label>\r\n <input matInput [formControl]=\"filter\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n (click)=\"filter.reset()\"\r\n [disabled]=\"!filter.value\"\r\n [attr.aria-label]=\"'Reset filter'\"\r\n >\r\n <mat-icon color=\"warn\" class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n\r\n <span>{{ filteredFeatures.length }}</span>\r\n </div>\r\n }\r\n\r\n <!-- list -->\r\n @if (filteredFeatures.length) {\r\n <table>\r\n <tbody>\r\n @for (feature of filteredFeatures; track $index) {\r\n <tr>\r\n <th>\r\n @if (featNames.length) {\r\n <span>{{\r\n feature.name | flatLookup : featNames : \"id\" : \"label\"\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.name }}</span>\r\n }\r\n </th>\r\n <td>\r\n @if (featValues()) {\r\n <span>{{\r\n feature.value | flatLookup : featValues()![feature.name]\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.value }}</span>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.in-row-button{margin-top:-16px}table{width:100%;border-collapse:collapse}th{text-align:left;background-color:#c8d9eb;color:#333;font-weight:400}th,td{border:1px solid silver;padding:4px}tr:nth-child(2n){background-color:#dfdfdf}#filter{width:7em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: "pipe", type: FlatLookupPipe, name: "flatLookup" }] }); }
|
|
2113
2043
|
}
|
|
2114
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
2044
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: FeatureSetViewComponent, decorators: [{
|
|
2115
2045
|
type: Component,
|
|
2116
2046
|
args: [{ selector: 'gve-feature-set-view', imports: [
|
|
2117
2047
|
CommonModule,
|
|
@@ -2121,16 +2051,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2121
2051
|
MatIconModule,
|
|
2122
2052
|
MatInputModule,
|
|
2123
2053
|
FlatLookupPipe,
|
|
2124
|
-
], template: "<div>\r\n <!-- filter -->\r\n <div>\r\n @if (filterThreshold === 0 || features
|
|
2125
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
2126
|
-
type: Input
|
|
2127
|
-
}], featNames: [{
|
|
2128
|
-
type: Input
|
|
2129
|
-
}], featValues: [{
|
|
2130
|
-
type: Input
|
|
2131
|
-
}], filterThreshold: [{
|
|
2132
|
-
type: Input
|
|
2133
|
-
}] } });
|
|
2054
|
+
], template: "<div>\r\n <!-- filter -->\r\n <div>\r\n @if (filterThreshold() === 0 || features()!.length > filterThreshold()) {\r\n <div class=\"form-row\">\r\n <mat-form-field id=\"filter\">\r\n <mat-label>filter</mat-label>\r\n <input matInput [formControl]=\"filter\" />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n (click)=\"filter.reset()\"\r\n [disabled]=\"!filter.value\"\r\n [attr.aria-label]=\"'Reset filter'\"\r\n >\r\n <mat-icon color=\"warn\" class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n\r\n <span>{{ filteredFeatures.length }}</span>\r\n </div>\r\n }\r\n\r\n <!-- list -->\r\n @if (filteredFeatures.length) {\r\n <table>\r\n <tbody>\r\n @for (feature of filteredFeatures; track $index) {\r\n <tr>\r\n <th>\r\n @if (featNames.length) {\r\n <span>{{\r\n feature.name | flatLookup : featNames : \"id\" : \"label\"\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.name }}</span>\r\n }\r\n </th>\r\n <td>\r\n @if (featValues()) {\r\n <span>{{\r\n feature.value | flatLookup : featValues()![feature.name]\r\n }}</span>\r\n } @else {\r\n <span>{{ feature.value }}</span>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.in-row-button{margin-top:-16px}table{width:100%;border-collapse:collapse}th{text-align:left;background-color:#c8d9eb;color:#333;font-weight:400}th,td{border:1px solid silver;padding:4px}tr:nth-child(2n){background-color:#dfdfdf}#filter{width:7em}\n"] }]
|
|
2055
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
2134
2056
|
|
|
2135
2057
|
/**
|
|
2136
2058
|
* 🔑 `gve-steps-map`
|
|
@@ -2155,79 +2077,60 @@ class StepsMapComponent {
|
|
|
2155
2077
|
constructor() {
|
|
2156
2078
|
// the lines of each version text, keyed under the output tag
|
|
2157
2079
|
this.lines = {};
|
|
2080
|
+
/**
|
|
2081
|
+
* The steps to display.
|
|
2082
|
+
*/
|
|
2083
|
+
this.steps = input([]);
|
|
2084
|
+
/**
|
|
2085
|
+
* The step that is currently selected.
|
|
2086
|
+
*/
|
|
2087
|
+
this.selectedStep = model();
|
|
2158
2088
|
/**
|
|
2159
2089
|
* The font size of the steps text.
|
|
2160
2090
|
*/
|
|
2161
|
-
this.textFontSize = '0.8em';
|
|
2091
|
+
this.textFontSize = input('0.8em');
|
|
2162
2092
|
/**
|
|
2163
2093
|
* Emitted when the selected step has changed by user, or when
|
|
2164
2094
|
* the steps are set for the first time.
|
|
2165
2095
|
*/
|
|
2166
|
-
this.selectedStepChange =
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
this._selectedStep = this._steps[this._steps.length - 1];
|
|
2183
|
-
this.updateLines();
|
|
2184
|
-
this.selectedStepChange.emit(this._selectedStep);
|
|
2185
|
-
}
|
|
2186
|
-
else {
|
|
2187
|
-
this.updateLines();
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
/**
|
|
2191
|
-
* The step that is currently selected.
|
|
2192
|
-
*/
|
|
2193
|
-
get selectedStep() {
|
|
2194
|
-
return this._selectedStep;
|
|
2195
|
-
}
|
|
2196
|
-
set selectedStep(value) {
|
|
2197
|
-
if (this._selectedStep === value) {
|
|
2198
|
-
return;
|
|
2199
|
-
}
|
|
2200
|
-
this._selectedStep = value;
|
|
2096
|
+
this.selectedStepChange = output();
|
|
2097
|
+
// when the steps change, update lines and selected step
|
|
2098
|
+
effect(() => {
|
|
2099
|
+
const steps = this.steps();
|
|
2100
|
+
const first = steps === undefined;
|
|
2101
|
+
if (first && steps.length) {
|
|
2102
|
+
this.selectedStep.set(steps[steps.length - 1]);
|
|
2103
|
+
this.updateLines(steps);
|
|
2104
|
+
this.selectedStepChange.emit(this.selectedStep());
|
|
2105
|
+
}
|
|
2106
|
+
else {
|
|
2107
|
+
this.selectedStep.set(undefined);
|
|
2108
|
+
this.selectedStepChange.emit(undefined);
|
|
2109
|
+
this.updateLines(steps);
|
|
2110
|
+
}
|
|
2111
|
+
});
|
|
2201
2112
|
}
|
|
2202
|
-
updateLines() {
|
|
2203
|
-
if (!
|
|
2113
|
+
updateLines(steps) {
|
|
2114
|
+
if (!steps) {
|
|
2204
2115
|
this.lines = {};
|
|
2205
2116
|
return;
|
|
2206
2117
|
}
|
|
2207
|
-
for (let i = 0; i <
|
|
2208
|
-
const step = this.
|
|
2118
|
+
for (let i = 0; i < steps.length; i++) {
|
|
2119
|
+
const step = this.steps()[i];
|
|
2209
2120
|
this.lines[step.outputTag] = step.result?.split('\n') || [];
|
|
2210
2121
|
}
|
|
2211
2122
|
}
|
|
2212
2123
|
onStepClick(step) {
|
|
2213
|
-
this.
|
|
2214
|
-
this.selectedStepChange.emit(
|
|
2124
|
+
this.selectedStep.set(step);
|
|
2125
|
+
this.selectedStepChange.emit(this.selectedStep());
|
|
2215
2126
|
}
|
|
2216
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2217
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
2127
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: StepsMapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2128
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: StepsMapComponent, isStandalone: true, selector: "gve-steps-map", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null }, selectedStep: { classPropertyName: "selectedStep", publicName: "selectedStep", isSignal: true, isRequired: false, transformFunction: null }, textFontSize: { classPropertyName: "textFontSize", publicName: "textFontSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedStep: "selectedStepChange", selectedStepChange: "selectedStepChange" }, ngImport: i0, template: "<div>\r\n @if (steps().length) { @for (step of steps(); track step.outputTag) {\r\n <div\r\n matRipple\r\n class=\"step form-row\"\r\n [ngClass]=\"{ selected: step === selectedStep() }\"\r\n (click)=\"onStepClick(step)\"\r\n >\r\n <!-- tag -->\r\n <div class=\"tag\">\r\n <span class=\"muted-tag\">{{ step.inputTag }} ▶ </span>\r\n {{ step.outputTag }}\r\n </div>\r\n <!-- text lines -->\r\n <div class=\"text\" [style.fontSize]=\"textFontSize()\">\r\n @for (line of lines[step.outputTag]; track $index) {\r\n <div class=\"line\">{{ line }}</div>\r\n }\r\n <div></div>\r\n </div>\r\n </div>\r\n } }\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:start;flex-wrap:wrap}.form-row *{flex:0 0 auto}.selected{background-color:#ffc}.step{border:1px solid rgb(68,114,253);border-radius:6px;margin:8px 0}.tag{background-color:#4472fd;color:#fff;border:1px solid rgb(68,114,253);border-radius:6px;padding:4px;cursor:pointer}.muted-tag{color:silver}.text{font-size:.5em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: MatTooltipModule }] }); }
|
|
2218
2129
|
}
|
|
2219
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
2130
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: StepsMapComponent, decorators: [{
|
|
2220
2131
|
type: Component,
|
|
2221
|
-
args: [{ selector: 'gve-steps-map', imports: [CommonModule, MatButtonModule, MatRippleModule, MatTooltipModule], template: "<div>\r\n @if (steps
|
|
2222
|
-
}],
|
|
2223
|
-
type: Input
|
|
2224
|
-
}], selectedStep: [{
|
|
2225
|
-
type: Input
|
|
2226
|
-
}], textFontSize: [{
|
|
2227
|
-
type: Input
|
|
2228
|
-
}], selectedStepChange: [{
|
|
2229
|
-
type: Output
|
|
2230
|
-
}] } });
|
|
2132
|
+
args: [{ selector: 'gve-steps-map', imports: [CommonModule, MatButtonModule, MatRippleModule, MatTooltipModule], template: "<div>\r\n @if (steps().length) { @for (step of steps(); track step.outputTag) {\r\n <div\r\n matRipple\r\n class=\"step form-row\"\r\n [ngClass]=\"{ selected: step === selectedStep() }\"\r\n (click)=\"onStepClick(step)\"\r\n >\r\n <!-- tag -->\r\n <div class=\"tag\">\r\n <span class=\"muted-tag\">{{ step.inputTag }} ▶ </span>\r\n {{ step.outputTag }}\r\n </div>\r\n <!-- text lines -->\r\n <div class=\"text\" [style.fontSize]=\"textFontSize()\">\r\n @for (line of lines[step.outputTag]; track $index) {\r\n <div class=\"line\">{{ line }}</div>\r\n }\r\n <div></div>\r\n </div>\r\n </div>\r\n } }\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:start;flex-wrap:wrap}.form-row *{flex:0 0 auto}.selected{background-color:#ffc}.step{border:1px solid rgb(68,114,253);border-radius:6px;margin:8px 0}.tag{background-color:#4472fd;color:#fff;border:1px solid rgb(68,114,253);border-radius:6px;padding:4px;cursor:pointer}.muted-tag{color:silver}.text{font-size:.5em}\n"] }]
|
|
2133
|
+
}], ctorParameters: () => [] });
|
|
2231
2134
|
|
|
2232
2135
|
/**
|
|
2233
2136
|
* 🔑 `gve-chain-result-view`
|
|
@@ -2243,48 +2146,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2243
2146
|
* result's step is picked by the user.
|
|
2244
2147
|
*/
|
|
2245
2148
|
class ChainResultViewComponent {
|
|
2246
|
-
/**
|
|
2247
|
-
* The result to display.
|
|
2248
|
-
*/
|
|
2249
|
-
get result() {
|
|
2250
|
-
return this._result;
|
|
2251
|
-
}
|
|
2252
|
-
set result(value) {
|
|
2253
|
-
if (this._result === value) {
|
|
2254
|
-
return;
|
|
2255
|
-
}
|
|
2256
|
-
this._result = value || undefined;
|
|
2257
|
-
this.updateForm(this._result);
|
|
2258
|
-
// select the initial step if set
|
|
2259
|
-
this.selectInitialStep();
|
|
2260
|
-
}
|
|
2261
|
-
/**
|
|
2262
|
-
* The index of the initial step to display after the result is set.
|
|
2263
|
-
* If the index is negative, it is counted from the end of the steps.
|
|
2264
|
-
*/
|
|
2265
|
-
get initialStepIndex() {
|
|
2266
|
-
return this._initialStepIndex;
|
|
2267
|
-
}
|
|
2268
|
-
set initialStepIndex(value) {
|
|
2269
|
-
if (value === undefined || value === null) {
|
|
2270
|
-
this._initialStepIndex = undefined;
|
|
2271
|
-
this.step = undefined;
|
|
2272
|
-
}
|
|
2273
|
-
else {
|
|
2274
|
-
this._initialStepIndex = value;
|
|
2275
|
-
this.selectInitialStep();
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
2149
|
constructor(formBuilder) {
|
|
2150
|
+
/**
|
|
2151
|
+
* The result to display.
|
|
2152
|
+
*/
|
|
2153
|
+
this.result = input();
|
|
2154
|
+
/**
|
|
2155
|
+
* The index of the initial step to display after the result is set.
|
|
2156
|
+
* If the index is negative, it is counted from the end of the steps.
|
|
2157
|
+
*/
|
|
2158
|
+
this.initialStepIndex = input();
|
|
2279
2159
|
/**
|
|
2280
2160
|
* Emitted when a result's step is picked by the user.
|
|
2281
2161
|
*/
|
|
2282
|
-
this.stepPick =
|
|
2162
|
+
this.stepPick = output();
|
|
2283
2163
|
this.versionTags = [];
|
|
2284
2164
|
this.tags = [];
|
|
2285
2165
|
this.selectionFeatures = [];
|
|
2166
|
+
// bind callback methods
|
|
2167
|
+
this.getCharBorderColor = this.getCharBorderColor.bind(this);
|
|
2286
2168
|
this.versionTag = formBuilder.control(null);
|
|
2287
2169
|
this.tag = formBuilder.control(null);
|
|
2170
|
+
// when result changes, update the form
|
|
2171
|
+
effect(() => {
|
|
2172
|
+
this.updateForm(this.result());
|
|
2173
|
+
// select the initial step if set
|
|
2174
|
+
this.selectInitialStep(this.initialStepIndex());
|
|
2175
|
+
});
|
|
2176
|
+
// when initialStepIndex changes, update the selected step
|
|
2177
|
+
effect(() => {
|
|
2178
|
+
this.selectInitialStep(this.initialStepIndex());
|
|
2179
|
+
});
|
|
2288
2180
|
}
|
|
2289
2181
|
ngOnInit() {
|
|
2290
2182
|
this._subs = [
|
|
@@ -2298,7 +2190,7 @@ class ChainResultViewComponent {
|
|
|
2298
2190
|
this.tag.valueChanges
|
|
2299
2191
|
.pipe(distinctUntilChanged(), debounceTime(200))
|
|
2300
2192
|
.subscribe((value) => {
|
|
2301
|
-
this.step = this.
|
|
2193
|
+
this.step = this.result()?.steps.find((step) => step.outputTag === value);
|
|
2302
2194
|
if (this.step) {
|
|
2303
2195
|
this.stepPick.emit(this.step);
|
|
2304
2196
|
}
|
|
@@ -2308,25 +2200,28 @@ class ChainResultViewComponent {
|
|
|
2308
2200
|
getCharBorderColor(node) {
|
|
2309
2201
|
return this.step?.refNodeIds.includes(node.id) ? 'orange' : null;
|
|
2310
2202
|
}
|
|
2311
|
-
selectInitialStep() {
|
|
2312
|
-
if (
|
|
2203
|
+
selectInitialStep(initialStepIndex) {
|
|
2204
|
+
if (initialStepIndex !== undefined && this.result()?.steps) {
|
|
2313
2205
|
this.step =
|
|
2314
|
-
this.
|
|
2315
|
-
? this.
|
|
2316
|
-
:
|
|
2206
|
+
this.result().steps[initialStepIndex < 0
|
|
2207
|
+
? this.result().steps.length + initialStepIndex
|
|
2208
|
+
: initialStepIndex];
|
|
2209
|
+
}
|
|
2210
|
+
else {
|
|
2211
|
+
this.step = undefined;
|
|
2317
2212
|
}
|
|
2318
2213
|
}
|
|
2319
2214
|
ngOnDestroy() {
|
|
2320
2215
|
this._subs?.forEach((sub) => sub.unsubscribe());
|
|
2321
2216
|
}
|
|
2322
2217
|
updateVersionTags() {
|
|
2323
|
-
if (!this.
|
|
2218
|
+
if (!this.result()) {
|
|
2324
2219
|
this.versionTags = [];
|
|
2325
2220
|
return;
|
|
2326
2221
|
}
|
|
2327
2222
|
// extract version tags from result steps features named 'version'
|
|
2328
2223
|
const tags = new Set();
|
|
2329
|
-
for (const step of this.
|
|
2224
|
+
for (const step of this.result().steps) {
|
|
2330
2225
|
for (const feature of step.featureSet.features) {
|
|
2331
2226
|
if (feature.name === 'version') {
|
|
2332
2227
|
tags.add(feature.value);
|
|
@@ -2336,10 +2231,10 @@ class ChainResultViewComponent {
|
|
|
2336
2231
|
this.versionTags = Array.from(tags).sort();
|
|
2337
2232
|
}
|
|
2338
2233
|
getTagFromVersion(version) {
|
|
2339
|
-
if (!this.
|
|
2234
|
+
if (!this.result() || !version) {
|
|
2340
2235
|
return undefined;
|
|
2341
2236
|
}
|
|
2342
|
-
for (const step of this.
|
|
2237
|
+
for (const step of this.result().steps) {
|
|
2343
2238
|
for (const feature of step.featureSet.features) {
|
|
2344
2239
|
if (feature.name === 'version' && feature.value === version) {
|
|
2345
2240
|
return step.outputTag;
|
|
@@ -2371,8 +2266,8 @@ class ChainResultViewComponent {
|
|
|
2371
2266
|
if (!this.step) {
|
|
2372
2267
|
return null;
|
|
2373
2268
|
}
|
|
2374
|
-
for (let key of Object.keys(this.
|
|
2375
|
-
const node = this.
|
|
2269
|
+
for (let key of Object.keys(this.result().taggedNodes)) {
|
|
2270
|
+
const node = this.result().taggedNodes[key].find((n) => n.id === id);
|
|
2376
2271
|
if (node) {
|
|
2377
2272
|
return node;
|
|
2378
2273
|
}
|
|
@@ -2393,7 +2288,7 @@ class ChainResultViewComponent {
|
|
|
2393
2288
|
this.selection = range.at + '×' + range.run;
|
|
2394
2289
|
const end = range.at + range.run;
|
|
2395
2290
|
const features = [];
|
|
2396
|
-
const tagNodes = this.
|
|
2291
|
+
const tagNodes = this.result().taggedNodes[this.tag.value];
|
|
2397
2292
|
for (let node of tagNodes) {
|
|
2398
2293
|
// if in range, intersect features
|
|
2399
2294
|
if (node.id >= range.at && node.id < end) {
|
|
@@ -2412,14 +2307,16 @@ class ChainResultViewComponent {
|
|
|
2412
2307
|
this.selectionFeatures = features;
|
|
2413
2308
|
}
|
|
2414
2309
|
onStepChange(step) {
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2310
|
+
if (step) {
|
|
2311
|
+
// setting the tag will trigger the step change
|
|
2312
|
+
this.tag.setValue(step.outputTag);
|
|
2313
|
+
this.selectionFeatures = [];
|
|
2314
|
+
}
|
|
2418
2315
|
}
|
|
2419
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2420
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
2316
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: ChainResultViewComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2317
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: ChainResultViewComponent, isStandalone: true, selector: "gve-chain-result-view", inputs: { result: { classPropertyName: "result", publicName: "result", isSignal: true, isRequired: false, transformFunction: null }, initialStepIndex: { classPropertyName: "initialStepIndex", publicName: "initialStepIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stepPick: "stepPick" }, ngImport: i0, template: "@if (result()) {\r\n<div id=\"container\">\r\n <div id=\"bar\" class=\"form-row\">\r\n <!-- version -->\r\n <mat-form-field *ngIf=\"versionTags?.length\">\r\n <mat-label>version</mat-label>\r\n <mat-select [formControl]=\"versionTag\">\r\n <mat-option [value]=\"null\">-</mat-option>\r\n <mat-option *ngFor=\"let t of versionTags\" [value]=\"t\">{{\r\n t\r\n }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n <!-- tag -->\r\n <mat-form-field *ngIf=\"tags?.length\">\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n <mat-option *ngFor=\"let t of tags\" [value]=\"t\">{{ t }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- step -->\r\n @if (step) {\r\n <div id=\"step\">\r\n <!-- text -->\r\n <div id=\"text\">\r\n <gve-base-text-view\r\n [text]=\"result()!.taggedNodes[step.outputTag]\"\r\n [borderColorCallback]=\"getCharBorderColor\"\r\n (charPick)=\"onStepCharPick($event)\"\r\n (rangePick)=\"onStepRangePick($event)\"\r\n />\r\n </div>\r\n <!-- features -->\r\n <div id=\"feats\" class=\"form-row-top\">\r\n <div id=\"g-feats\">\r\n <div class=\"feat-header\">{{ step.outputTag }}</div>\r\n <gve-feature-set-view [features]=\"step.featureSet.features\" />\r\n </div>\r\n <div id=\"n-feats\">\r\n @if (selectionFeatures.length) {\r\n <div class=\"feat-header\">{{ selection }}</div>\r\n <gve-feature-set-view [features]=\"selectionFeatures\" />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- steps map -->\r\n <div id=\"map\">\r\n <gve-steps-map\r\n [steps]=\"result()!.steps\"\r\n [selectedStep]=\"step\"\r\n (selectedStepChange)=\"onStepChange($event)\"\r\n />\r\n </div>\r\n</div>\r\n}\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.form-row-top{display:flex;gap:8px;align-items:start;flex-wrap:wrap}div#container{display:grid;grid-template-rows:auto 1fr;grid-template-columns:3fr 1fr;grid-template-areas:\"bar map\" \"step map\";gap:8px}div#bar{grid-area:bar}div#map{grid-area:map}div#step{grid-area:step}.feat-header{background-color:#3e92cc;color:#fff;text-align:center;border:1px solid #3e92cc;border-top-left-radius:4px;border-top-right-radius:4px}@media only screen and (max-width: 959px){div#container{grid-template-columns:1fr;grid-template-areas:\"bar\" \"step\"}#map{display:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: FeatureSetViewComponent, selector: "gve-feature-set-view", inputs: ["features", "featNames", "featValues", "filterThreshold"] }, { kind: "component", type: StepsMapComponent, selector: "gve-steps-map", inputs: ["steps", "selectedStep", "textFontSize"], outputs: ["selectedStepChange"] }, { kind: "component", type: BaseTextViewComponent, selector: "gve-base-text-view", inputs: ["defaultColor", "defaultBorderColor", "selectionColor", "hasLineNumber", "text", "borderColorCallback"], outputs: ["charPick", "rangePick"] }] }); }
|
|
2421
2318
|
}
|
|
2422
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
2319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: ChainResultViewComponent, decorators: [{
|
|
2423
2320
|
type: Component,
|
|
2424
2321
|
args: [{ selector: 'gve-chain-result-view', imports: [
|
|
2425
2322
|
CommonModule,
|
|
@@ -2431,14 +2328,231 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2431
2328
|
FeatureSetViewComponent,
|
|
2432
2329
|
StepsMapComponent,
|
|
2433
2330
|
BaseTextViewComponent,
|
|
2434
|
-
], template: "@if (result) {\r\n<div id=\"container\">\r\n <div id=\"bar\" class=\"form-row\">\r\n <!-- version -->\r\n <mat-form-field *ngIf=\"versionTags?.length\">\r\n <mat-label>version</mat-label>\r\n <mat-select [formControl]=\"versionTag\">\r\n <mat-option [value]=\"null\">-</mat-option>\r\n <mat-option *ngFor=\"let t of versionTags\" [value]=\"t\">{{\r\n t\r\n }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n <!-- tag -->\r\n <mat-form-field *ngIf=\"tags?.length\">\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n <mat-option *ngFor=\"let t of tags\" [value]=\"t\">{{ t }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- step -->\r\n @if (step) {\r\n <div id=\"step\">\r\n <!-- text -->\r\n <div id=\"text\">\r\n <gve-base-text-view\r\n [text]=\"result
|
|
2435
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2331
|
+
], template: "@if (result()) {\r\n<div id=\"container\">\r\n <div id=\"bar\" class=\"form-row\">\r\n <!-- version -->\r\n <mat-form-field *ngIf=\"versionTags?.length\">\r\n <mat-label>version</mat-label>\r\n <mat-select [formControl]=\"versionTag\">\r\n <mat-option [value]=\"null\">-</mat-option>\r\n <mat-option *ngFor=\"let t of versionTags\" [value]=\"t\">{{\r\n t\r\n }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n <!-- tag -->\r\n <mat-form-field *ngIf=\"tags?.length\">\r\n <mat-label>tag</mat-label>\r\n <mat-select [formControl]=\"tag\">\r\n <mat-option *ngFor=\"let t of tags\" [value]=\"t\">{{ t }}</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- step -->\r\n @if (step) {\r\n <div id=\"step\">\r\n <!-- text -->\r\n <div id=\"text\">\r\n <gve-base-text-view\r\n [text]=\"result()!.taggedNodes[step.outputTag]\"\r\n [borderColorCallback]=\"getCharBorderColor\"\r\n (charPick)=\"onStepCharPick($event)\"\r\n (rangePick)=\"onStepRangePick($event)\"\r\n />\r\n </div>\r\n <!-- features -->\r\n <div id=\"feats\" class=\"form-row-top\">\r\n <div id=\"g-feats\">\r\n <div class=\"feat-header\">{{ step.outputTag }}</div>\r\n <gve-feature-set-view [features]=\"step.featureSet.features\" />\r\n </div>\r\n <div id=\"n-feats\">\r\n @if (selectionFeatures.length) {\r\n <div class=\"feat-header\">{{ selection }}</div>\r\n <gve-feature-set-view [features]=\"selectionFeatures\" />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- steps map -->\r\n <div id=\"map\">\r\n <gve-steps-map\r\n [steps]=\"result()!.steps\"\r\n [selectedStep]=\"step\"\r\n (selectedStepChange)=\"onStepChange($event)\"\r\n />\r\n </div>\r\n</div>\r\n}\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}.form-row-top{display:flex;gap:8px;align-items:start;flex-wrap:wrap}div#container{display:grid;grid-template-rows:auto 1fr;grid-template-columns:3fr 1fr;grid-template-areas:\"bar map\" \"step map\";gap:8px}div#bar{grid-area:bar}div#map{grid-area:map}div#step{grid-area:step}.feat-header{background-color:#3e92cc;color:#fff;text-align:center;border:1px solid #3e92cc;border-top-left-radius:4px;border-top-right-radius:4px}@media only screen and (max-width: 959px){div#container{grid-template-columns:1fr;grid-template-areas:\"bar\" \"step\"}#map{display:none}}\n"] }]
|
|
2332
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
2333
|
+
|
|
2334
|
+
class GveGraphvizService {
|
|
2335
|
+
hashString(str) {
|
|
2336
|
+
let hash = 0;
|
|
2337
|
+
for (let i = 0; i < str.length; i++) {
|
|
2338
|
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
2339
|
+
hash = hash & hash; // convert to 32bit integer
|
|
2340
|
+
}
|
|
2341
|
+
return Math.abs(hash);
|
|
2342
|
+
}
|
|
2343
|
+
hslToRgb(hue, saturation, lightness) {
|
|
2344
|
+
const chroma = ((1 - Math.abs((2 * lightness) / 100 - 1)) * saturation) / 100;
|
|
2345
|
+
const x = chroma * (1 - Math.abs(((hue / 60) % 2) - 1));
|
|
2346
|
+
const m = lightness / 100 - chroma / 2;
|
|
2347
|
+
let r = 0, g = 0, b = 0;
|
|
2348
|
+
if (hue >= 0 && hue < 60) {
|
|
2349
|
+
r = chroma;
|
|
2350
|
+
g = x;
|
|
2351
|
+
}
|
|
2352
|
+
else if (hue >= 60 && hue < 120) {
|
|
2353
|
+
r = x;
|
|
2354
|
+
g = chroma;
|
|
2355
|
+
}
|
|
2356
|
+
else if (hue >= 120 && hue < 180) {
|
|
2357
|
+
g = chroma;
|
|
2358
|
+
b = x;
|
|
2359
|
+
}
|
|
2360
|
+
else if (hue >= 180 && hue < 240) {
|
|
2361
|
+
g = x;
|
|
2362
|
+
b = chroma;
|
|
2363
|
+
}
|
|
2364
|
+
else if (hue >= 240 && hue < 300) {
|
|
2365
|
+
r = x;
|
|
2366
|
+
b = chroma;
|
|
2367
|
+
}
|
|
2368
|
+
else if (hue >= 300 && hue < 360) {
|
|
2369
|
+
r = chroma;
|
|
2370
|
+
b = x;
|
|
2371
|
+
}
|
|
2372
|
+
r = Math.round((r + m) * 255);
|
|
2373
|
+
g = Math.round((g + m) * 255);
|
|
2374
|
+
b = Math.round((b + m) * 255);
|
|
2375
|
+
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
2376
|
+
}
|
|
2377
|
+
getColorForTag(tag) {
|
|
2378
|
+
const hash = this.hashString(tag);
|
|
2379
|
+
const hue = (hash * 137) % 360; // Use a prime number to spread out the hues
|
|
2380
|
+
const saturation = 60 + (hash % 40); // Saturation between 60% and 100%
|
|
2381
|
+
const lightness = 50 + (hash % 30); // Lightness between 50% and 80%
|
|
2382
|
+
return this.hslToRgb(hue, saturation, lightness);
|
|
2383
|
+
}
|
|
2384
|
+
getExcludedNodeIds(chain, tags) {
|
|
2385
|
+
// get only the desired links
|
|
2386
|
+
const links = chain.links.filter((link) => tags ? tags.includes(link.tag) : true);
|
|
2387
|
+
// return all the nodes not referenced by the links
|
|
2388
|
+
const excluded = new Set();
|
|
2389
|
+
chain.nodes.forEach((node) => {
|
|
2390
|
+
excluded.add(node.id);
|
|
2391
|
+
});
|
|
2392
|
+
links.forEach((link) => {
|
|
2393
|
+
excluded.delete(link.sourceId);
|
|
2394
|
+
excluded.delete(link.targetId);
|
|
2395
|
+
});
|
|
2396
|
+
return excluded;
|
|
2397
|
+
}
|
|
2398
|
+
/**
|
|
2399
|
+
* Represent the received chain as a Graphviz digraph.
|
|
2400
|
+
*
|
|
2401
|
+
* @param chain The source chain if any.
|
|
2402
|
+
* @param tags The tags to show. When set, only the links with these tags are shown.
|
|
2403
|
+
* @param rankdir The rank direction.
|
|
2404
|
+
* @returns Graphviz representation of the chain.
|
|
2405
|
+
*/
|
|
2406
|
+
generateGraph(chain, tags, rankdir = 'LR') {
|
|
2407
|
+
if (!chain) {
|
|
2408
|
+
return 'digraph G {}';
|
|
2409
|
+
}
|
|
2410
|
+
const sb = [];
|
|
2411
|
+
const excludedNodeIds = this.getExcludedNodeIds(chain, tags);
|
|
2412
|
+
sb.push('digraph G {');
|
|
2413
|
+
sb.push(' bgcolor=transparent;');
|
|
2414
|
+
sb.push(' node [style=filled];');
|
|
2415
|
+
sb.push(` rankdir=${rankdir};`);
|
|
2416
|
+
chain.nodes.forEach((node) => {
|
|
2417
|
+
// note that in label we must escape the double quotes
|
|
2418
|
+
sb.push(` ${node.id} [label="${node.label === '"' ? '"' : node.label}"` +
|
|
2419
|
+
(node.sourceTag
|
|
2420
|
+
? ` fillcolor="${this.getColorForTag(node.sourceTag)}"`
|
|
2421
|
+
: '') +
|
|
2422
|
+
(node.sourceTag && excludedNodeIds.has(node.id)
|
|
2423
|
+
? ` xlabel="${node.sourceTag}"`
|
|
2424
|
+
: '') +
|
|
2425
|
+
'];');
|
|
2426
|
+
});
|
|
2427
|
+
chain.links.forEach((link) => {
|
|
2428
|
+
if (!link.sourceId ||
|
|
2429
|
+
!link.targetId ||
|
|
2430
|
+
(tags && !tags.includes(link.tag))) {
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
const color = this.getColorForTag(link.tag);
|
|
2434
|
+
sb.push(` ${link.sourceId} -> ${link.targetId} [label="${link.tag}", color="${color}"];`);
|
|
2435
|
+
});
|
|
2436
|
+
sb.push('}');
|
|
2437
|
+
return sb.join('\n');
|
|
2438
|
+
}
|
|
2439
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: GveGraphvizService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2440
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: GveGraphvizService, providedIn: 'root' }); }
|
|
2441
|
+
}
|
|
2442
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: GveGraphvizService, decorators: [{
|
|
2443
|
+
type: Injectable,
|
|
2444
|
+
args: [{
|
|
2445
|
+
providedIn: 'root',
|
|
2446
|
+
}]
|
|
2447
|
+
}] });
|
|
2448
|
+
|
|
2449
|
+
class ChainViewComponent {
|
|
2450
|
+
constructor(_graphviz, _settings, _clipboard, _snackbar) {
|
|
2451
|
+
this._graphviz = _graphviz;
|
|
2452
|
+
this._settings = _settings;
|
|
2453
|
+
this._clipboard = _clipboard;
|
|
2454
|
+
this._snackbar = _snackbar;
|
|
2455
|
+
/**
|
|
2456
|
+
* The chain to display.
|
|
2457
|
+
*/
|
|
2458
|
+
this.chain = input();
|
|
2459
|
+
/**
|
|
2460
|
+
* The direction of the graph.
|
|
2461
|
+
*/
|
|
2462
|
+
this.direction = input('LR');
|
|
2463
|
+
/**
|
|
2464
|
+
* All the distinct tags in the chain.
|
|
2465
|
+
*/
|
|
2466
|
+
this.tags = computed(() => {
|
|
2467
|
+
const chain = this.chain();
|
|
2468
|
+
if (!chain) {
|
|
2469
|
+
return [];
|
|
2470
|
+
}
|
|
2471
|
+
const set = new Set();
|
|
2472
|
+
for (const link of chain.links) {
|
|
2473
|
+
set.add(link.tag);
|
|
2474
|
+
}
|
|
2475
|
+
return Array.from(set).sort();
|
|
2476
|
+
});
|
|
2477
|
+
/**
|
|
2478
|
+
* The tags to show, or empty to show all of them.
|
|
2479
|
+
*/
|
|
2480
|
+
this.selectedTags = model([]);
|
|
2481
|
+
/**
|
|
2482
|
+
* The Graphviz representation of the chain.
|
|
2483
|
+
*/
|
|
2484
|
+
this.graph = computed(() => {
|
|
2485
|
+
let tags = this.selectedTags();
|
|
2486
|
+
if (tags && tags.length === 0) {
|
|
2487
|
+
tags = undefined;
|
|
2488
|
+
}
|
|
2489
|
+
return this._graphviz.generateGraph(this.chain(), tags, this.direction());
|
|
2490
|
+
});
|
|
2491
|
+
this.userTags = new FormControl([], {
|
|
2492
|
+
nonNullable: true,
|
|
2493
|
+
});
|
|
2494
|
+
// when the user changes the tags, update the selected tags
|
|
2495
|
+
this._sub = this.userTags.valueChanges.subscribe((value) => {
|
|
2496
|
+
this.selectedTags.set([...value]);
|
|
2497
|
+
});
|
|
2498
|
+
effect(() => {
|
|
2499
|
+
// update the user tags when tags change
|
|
2500
|
+
const tags = this.tags();
|
|
2501
|
+
let userTags = [];
|
|
2502
|
+
if (tags.length > 1) {
|
|
2503
|
+
// pick first and last tag from tags
|
|
2504
|
+
userTags = [tags[0], tags[tags.length - 1]];
|
|
2505
|
+
}
|
|
2506
|
+
else {
|
|
2507
|
+
// if there is only one tag, pick it
|
|
2508
|
+
userTags = [...tags];
|
|
2509
|
+
}
|
|
2510
|
+
this.userTags.setValue(userTags);
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
ngOnDestroy() {
|
|
2514
|
+
this._sub?.unsubscribe();
|
|
2515
|
+
}
|
|
2516
|
+
copyGraph() {
|
|
2517
|
+
const graph = this.graph();
|
|
2518
|
+
if (!graph) {
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
this._clipboard.copy(graph);
|
|
2522
|
+
this._snackbar.open('Graph copied to clipboard', 'OK', {
|
|
2523
|
+
duration: 2000,
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
openExternalEditor() {
|
|
2527
|
+
let url = this._settings.get('graphviz-editor', 'https://dreampuf.github.io/GraphvizOnline?engine=dot#CODE');
|
|
2528
|
+
if (!url) {
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2531
|
+
const graph = this.graph();
|
|
2532
|
+
if (!graph) {
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
if (url.indexOf('CODE') > -1) {
|
|
2536
|
+
url = url.replace('CODE', encodeURIComponent(graph));
|
|
2537
|
+
}
|
|
2538
|
+
window.open(url, '_blank');
|
|
2539
|
+
}
|
|
2540
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: ChainViewComponent, deps: [{ token: GveGraphvizService }, { token: SettingsService }, { token: i2$3.Clipboard }, { token: i4$2.MatSnackBar }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2541
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: ChainViewComponent, isStandalone: true, selector: "gve-chain-view", inputs: { chain: { classPropertyName: "chain", publicName: "chain", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, selectedTags: { classPropertyName: "selectedTags", publicName: "selectedTags", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedTags: "selectedTagsChange" }, ngImport: i0, template: "<div id=\"container\">\r\n <div>\r\n <ngx-viz [code]=\"graph()\" />\r\n </div>\r\n <div class=\"button-row\">\r\n <!-- select -->\r\n <mat-form-field>\r\n <mat-label>tags</mat-label>\r\n <mat-select [formControl]=\"userTags\" multiple>\r\n @for (tag of tags(); track tag) {\r\n <mat-option [value]=\"tag\">{{ tag }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n <!-- copy -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Copy graphviz code\"\r\n [disabled]=\"!graph()\"\r\n (click)=\"copyGraph()\"\r\n >\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <!--editor -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Open in editor\"\r\n [disabled]=\"!graph()\"\r\n (click)=\"openExternalEditor()\"\r\n >\r\n <mat-icon>launch</mat-icon>\r\n </button>\r\n </div>\r\n</div>\r\n", styles: ["div#container{border:1px solid silver;border-radius:6px;padding:4px}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: VizComponent, selector: "ngx-viz", inputs: ["code"] }] }); }
|
|
2542
|
+
}
|
|
2543
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: ChainViewComponent, decorators: [{
|
|
2544
|
+
type: Component,
|
|
2545
|
+
args: [{ selector: 'gve-chain-view', imports: [
|
|
2546
|
+
CommonModule,
|
|
2547
|
+
ReactiveFormsModule,
|
|
2548
|
+
MatButtonModule,
|
|
2549
|
+
MatFormFieldModule,
|
|
2550
|
+
MatIconModule,
|
|
2551
|
+
MatSelectModule,
|
|
2552
|
+
MatTooltipModule,
|
|
2553
|
+
VizComponent,
|
|
2554
|
+
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div id=\"container\">\r\n <div>\r\n <ngx-viz [code]=\"graph()\" />\r\n </div>\r\n <div class=\"button-row\">\r\n <!-- select -->\r\n <mat-form-field>\r\n <mat-label>tags</mat-label>\r\n <mat-select [formControl]=\"userTags\" multiple>\r\n @for (tag of tags(); track tag) {\r\n <mat-option [value]=\"tag\">{{ tag }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n <!-- copy -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Copy graphviz code\"\r\n [disabled]=\"!graph()\"\r\n (click)=\"copyGraph()\"\r\n >\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <!--editor -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Open in editor\"\r\n [disabled]=\"!graph()\"\r\n (click)=\"openExternalEditor()\"\r\n >\r\n <mat-icon>launch</mat-icon>\r\n </button>\r\n </div>\r\n</div>\r\n", styles: ["div#container{border:1px solid silver;border-radius:6px;padding:4px}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}\n"] }]
|
|
2555
|
+
}], ctorParameters: () => [{ type: GveGraphvizService }, { type: SettingsService }, { type: i2$3.Clipboard }, { type: i4$2.MatSnackBar }] });
|
|
2442
2556
|
|
|
2443
2557
|
/**
|
|
2444
2558
|
* 🔑 `gve-ln-heights-editor`
|
|
@@ -2452,39 +2566,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2452
2566
|
* emitted when the heights change.
|
|
2453
2567
|
*/
|
|
2454
2568
|
class LnHeightsEditorComponent {
|
|
2455
|
-
/**
|
|
2456
|
-
* The total number of lines in the text.
|
|
2457
|
-
*/
|
|
2458
|
-
get lineCount() {
|
|
2459
|
-
return this._lineCount;
|
|
2460
|
-
}
|
|
2461
|
-
set lineCount(value) {
|
|
2462
|
-
if (this._lineCount === value)
|
|
2463
|
-
return;
|
|
2464
|
-
this._lineCount = value;
|
|
2465
|
-
this.lineNumbers = Array.from({ length: value }, (_, i) => i + 1);
|
|
2466
|
-
}
|
|
2467
|
-
/**
|
|
2468
|
-
* The heights map of the lines. Each key is a line number and the value is
|
|
2469
|
-
* the height of the line.
|
|
2470
|
-
*/
|
|
2471
|
-
get heights() {
|
|
2472
|
-
return this._heights;
|
|
2473
|
-
}
|
|
2474
|
-
set heights(value) {
|
|
2475
|
-
if (this._heights === value)
|
|
2476
|
-
return;
|
|
2477
|
-
this._heights = value || undefined;
|
|
2478
|
-
}
|
|
2479
2569
|
constructor(formBuilder) {
|
|
2480
|
-
|
|
2570
|
+
/**
|
|
2571
|
+
* The total number of lines in the text.
|
|
2572
|
+
*/
|
|
2573
|
+
this.lineCount = input(0);
|
|
2574
|
+
/**
|
|
2575
|
+
* The heights map of the lines. Each key is a line number and the value is
|
|
2576
|
+
* the height of the line.
|
|
2577
|
+
*/
|
|
2578
|
+
this.heights = input();
|
|
2481
2579
|
/**
|
|
2482
2580
|
* The event emitted when the heights change.
|
|
2483
2581
|
*/
|
|
2484
|
-
this.heightsChange =
|
|
2582
|
+
this.heightsChange = output();
|
|
2485
2583
|
this.lineNumbers = [];
|
|
2486
2584
|
this.lineNumber = formBuilder.control(0, { nonNullable: true });
|
|
2487
2585
|
this.height = formBuilder.control(0, { nonNullable: true });
|
|
2586
|
+
// when lineCount changes, update lineNumbers
|
|
2587
|
+
effect(() => {
|
|
2588
|
+
this.lineNumbers = Array.from({ length: this.lineCount() }, (_, i) => i + 1);
|
|
2589
|
+
});
|
|
2488
2590
|
}
|
|
2489
2591
|
pruneHeights() {
|
|
2490
2592
|
// remove all the heigths with value=0
|
|
@@ -2523,10 +2625,10 @@ class LnHeightsEditorComponent {
|
|
|
2523
2625
|
this._heights = undefined;
|
|
2524
2626
|
this.heightsChange.emit(undefined);
|
|
2525
2627
|
}
|
|
2526
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2527
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
2628
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: LnHeightsEditorComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2629
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: LnHeightsEditorComponent, isStandalone: true, selector: "gve-ln-heights-editor", inputs: { lineCount: { classPropertyName: "lineCount", publicName: "lineCount", isSignal: true, isRequired: false, transformFunction: null }, heights: { classPropertyName: "heights", publicName: "heights", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { heightsChange: "heightsChange" }, ngImport: i0, template: "@if (lineNumbers.length) {\r\n<div class=\"form-row\">\r\n <!-- line number -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>line</mat-label>\r\n <mat-select [formControl]=\"lineNumber\">\r\n <mat-option *ngFor=\"let n of lineNumbers\" [value]=\"n\">\r\n {{ n }}\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n @if (lineNumber.value) {\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input matInput type=\"number\" [formControl]=\"height\" min=\"0\" />\r\n </mat-form-field>\r\n }\r\n\r\n <!-- reset button -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n (click)=\"reset()\"\r\n matTooltip=\"Remove all the heights\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n</div>\r\n}\r\n", styles: [".input-nr{width:5em}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
2528
2630
|
}
|
|
2529
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
2631
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: LnHeightsEditorComponent, decorators: [{
|
|
2530
2632
|
type: Component,
|
|
2531
2633
|
args: [{ selector: 'gve-ln-heights-editor', imports: [
|
|
2532
2634
|
CommonModule,
|
|
@@ -2538,76 +2640,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2538
2640
|
MatSelectModule,
|
|
2539
2641
|
MatTooltipModule,
|
|
2540
2642
|
], template: "@if (lineNumbers.length) {\r\n<div class=\"form-row\">\r\n <!-- line number -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>line</mat-label>\r\n <mat-select [formControl]=\"lineNumber\">\r\n <mat-option *ngFor=\"let n of lineNumbers\" [value]=\"n\">\r\n {{ n }}\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n @if (lineNumber.value) {\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input matInput type=\"number\" [formControl]=\"height\" min=\"0\" />\r\n </mat-form-field>\r\n }\r\n\r\n <!-- reset button -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n (click)=\"reset()\"\r\n matTooltip=\"Remove all the heights\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n</div>\r\n}\r\n", styles: [".input-nr{width:5em}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
2541
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }]
|
|
2542
|
-
type: Input
|
|
2543
|
-
}], heights: [{
|
|
2544
|
-
type: Input
|
|
2545
|
-
}], heightsChange: [{
|
|
2546
|
-
type: Output
|
|
2547
|
-
}] } });
|
|
2548
|
-
|
|
2549
|
-
/**
|
|
2550
|
-
* 🔑 `gve-simple-tree`
|
|
2551
|
-
*
|
|
2552
|
-
* A simple tree component.
|
|
2553
|
-
*
|
|
2554
|
-
* - ▶️ `node` (`TreeNode<any>`): the node to display.
|
|
2555
|
-
* - ▶️ `selectedNode` (`TreeNode<any> | null`): the selected node.
|
|
2556
|
-
* - 🔥 `selectedNodeChange` (`EventEmitter<TreeNode<any> | null>`): the event
|
|
2557
|
-
* emitted when the selected node changes.
|
|
2558
|
-
*/
|
|
2559
|
-
class SimpleTreeComponent {
|
|
2560
|
-
constructor() {
|
|
2561
|
-
/**
|
|
2562
|
-
* The event emitted when the selected node changes.
|
|
2563
|
-
*/
|
|
2564
|
-
this.selectedNodeChange = new EventEmitter();
|
|
2565
|
-
this.level = 0;
|
|
2566
|
-
}
|
|
2567
|
-
/**
|
|
2568
|
-
* The node to display.
|
|
2569
|
-
*/
|
|
2570
|
-
get node() {
|
|
2571
|
-
return this._node;
|
|
2572
|
-
}
|
|
2573
|
-
set node(value) {
|
|
2574
|
-
if (this._node === value) {
|
|
2575
|
-
return;
|
|
2576
|
-
}
|
|
2577
|
-
this._node = value;
|
|
2578
|
-
this.level = this.calculateLevel(value);
|
|
2579
|
-
}
|
|
2580
|
-
ngOnInit() {
|
|
2581
|
-
this.level = this.calculateLevel(this.node);
|
|
2582
|
-
}
|
|
2583
|
-
calculateLevel(node) {
|
|
2584
|
-
let level = 0;
|
|
2585
|
-
if (node) {
|
|
2586
|
-
let n = node;
|
|
2587
|
-
while (n.parent) {
|
|
2588
|
-
level++;
|
|
2589
|
-
n = n.parent;
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
return level;
|
|
2593
|
-
}
|
|
2594
|
-
selectNode(node) {
|
|
2595
|
-
this.selectedNode = node;
|
|
2596
|
-
this.selectedNodeChange.emit(node);
|
|
2597
|
-
}
|
|
2598
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: SimpleTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2599
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: SimpleTreeComponent, isStandalone: true, selector: "gve-simple-tree", inputs: { node: "node", selectedNode: "selectedNode" }, outputs: { selectedNodeChange: "selectedNodeChange" }, ngImport: i0, template: "@if (node) {\r\n<div [style.margin-left]=\"level * 8 + 'px'\">\r\n <ng-template\r\n #tree\r\n let-node\r\n let-parentLevel=\"level\"\r\n let-selectedNode=\"selectedNode\"\r\n >\r\n <div\r\n [style.margin-left]=\"parentLevel * 8 + 'px'\"\r\n [class.selected]=\"node === selectedNode\"\r\n >\r\n <div class=\"toolbar-row\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"node.isExpanded = !node.isExpanded\"\r\n >\r\n <mat-icon>{{\r\n node.isExpanded ? \"expand_more\" : \"chevron_right\"\r\n }}</mat-icon>\r\n </button>\r\n <span class=\"label\" (click)=\"selectNode(node)\">\r\n {{ node.label }}\r\n </span>\r\n </div>\r\n <div *ngIf=\"node.children && node.isExpanded\">\r\n <ng-container *ngFor=\"let child of node.children\">\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n tree;\r\n context: {\r\n $implicit: child,\r\n level: parentLevel + 1,\r\n selectedNode: selectedNode\r\n }\r\n \"\r\n ></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- $implicit is the source of let-node -->\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n tree;\r\n context: { $implicit: node, level: level, selectedNode: selectedNode }\r\n \"\r\n ></ng-container>\r\n</div>\r\n}\r\n", styles: [".label{cursor:pointer}.toolbar-row{display:flex;align-items:center;flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }] }); }
|
|
2600
|
-
}
|
|
2601
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: SimpleTreeComponent, decorators: [{
|
|
2602
|
-
type: Component,
|
|
2603
|
-
args: [{ selector: 'gve-simple-tree', imports: [CommonModule, MatButtonModule, MatIconModule, MatTooltipModule], template: "@if (node) {\r\n<div [style.margin-left]=\"level * 8 + 'px'\">\r\n <ng-template\r\n #tree\r\n let-node\r\n let-parentLevel=\"level\"\r\n let-selectedNode=\"selectedNode\"\r\n >\r\n <div\r\n [style.margin-left]=\"parentLevel * 8 + 'px'\"\r\n [class.selected]=\"node === selectedNode\"\r\n >\r\n <div class=\"toolbar-row\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"node.isExpanded = !node.isExpanded\"\r\n >\r\n <mat-icon>{{\r\n node.isExpanded ? \"expand_more\" : \"chevron_right\"\r\n }}</mat-icon>\r\n </button>\r\n <span class=\"label\" (click)=\"selectNode(node)\">\r\n {{ node.label }}\r\n </span>\r\n </div>\r\n <div *ngIf=\"node.children && node.isExpanded\">\r\n <ng-container *ngFor=\"let child of node.children\">\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n tree;\r\n context: {\r\n $implicit: child,\r\n level: parentLevel + 1,\r\n selectedNode: selectedNode\r\n }\r\n \"\r\n ></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- $implicit is the source of let-node -->\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n tree;\r\n context: { $implicit: node, level: level, selectedNode: selectedNode }\r\n \"\r\n ></ng-container>\r\n</div>\r\n}\r\n", styles: [".label{cursor:pointer}.toolbar-row{display:flex;align-items:center;flex-wrap:wrap}\n"] }]
|
|
2604
|
-
}], propDecorators: { node: [{
|
|
2605
|
-
type: Input
|
|
2606
|
-
}], selectedNode: [{
|
|
2607
|
-
type: Input
|
|
2608
|
-
}], selectedNodeChange: [{
|
|
2609
|
-
type: Output
|
|
2610
|
-
}] } });
|
|
2643
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }] });
|
|
2611
2644
|
|
|
2612
2645
|
/**
|
|
2613
2646
|
* 🔑 `gve-animation-timeline-set`
|
|
@@ -2622,43 +2655,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2622
2655
|
* - 🔥 `timelinesCancel` (`void`): emitted when the timeline editing is canceled.
|
|
2623
2656
|
*/
|
|
2624
2657
|
class AnimationTimelineSetComponent {
|
|
2625
|
-
/**
|
|
2626
|
-
* The animation timelines to edit.
|
|
2627
|
-
*/
|
|
2628
|
-
get timelines() {
|
|
2629
|
-
return this._timelines;
|
|
2630
|
-
}
|
|
2631
|
-
set timelines(value) {
|
|
2632
|
-
if (this._timelines === value) {
|
|
2633
|
-
return;
|
|
2634
|
-
}
|
|
2635
|
-
this._timelines = value || [];
|
|
2636
|
-
this.updateForm(this._timelines);
|
|
2637
|
-
}
|
|
2638
2658
|
constructor(formBuilder, _dialogService) {
|
|
2639
2659
|
this._dialogService = _dialogService;
|
|
2640
|
-
|
|
2660
|
+
/**
|
|
2661
|
+
* The animation timelines to edit.
|
|
2662
|
+
*/
|
|
2663
|
+
this.timelines = model([]);
|
|
2664
|
+
/**
|
|
2665
|
+
* The IDs of the elements that can be selected by the tween.
|
|
2666
|
+
* This list is used to allow the user to select an element from a dropdown.
|
|
2667
|
+
*/
|
|
2668
|
+
this.elementIds = input();
|
|
2641
2669
|
/**
|
|
2642
2670
|
* The tags that can be used by the timeline.
|
|
2643
2671
|
*/
|
|
2644
|
-
this.tags = [];
|
|
2672
|
+
this.tags = input([]);
|
|
2645
2673
|
/**
|
|
2646
2674
|
* Emitted when the timelines are changed.
|
|
2647
2675
|
*/
|
|
2648
|
-
this.timelinesChange =
|
|
2676
|
+
this.timelinesChange = output();
|
|
2649
2677
|
/**
|
|
2650
2678
|
* Emitted when the timeline editing is canceled.
|
|
2651
2679
|
*/
|
|
2652
|
-
this.timelinesCancel =
|
|
2680
|
+
this.timelinesCancel = output();
|
|
2653
2681
|
this.set = formBuilder.control([], {
|
|
2654
2682
|
nonNullable: true,
|
|
2655
2683
|
});
|
|
2656
2684
|
this.form = formBuilder.group({
|
|
2657
2685
|
sets: this.set,
|
|
2658
2686
|
});
|
|
2687
|
+
effect(() => {
|
|
2688
|
+
this.updateForm(this.timelines());
|
|
2689
|
+
});
|
|
2659
2690
|
}
|
|
2660
2691
|
updateForm(animations) {
|
|
2661
|
-
if (!animations
|
|
2692
|
+
if (!animations?.length) {
|
|
2662
2693
|
this.form.reset();
|
|
2663
2694
|
}
|
|
2664
2695
|
else {
|
|
@@ -2676,7 +2707,7 @@ class AnimationTimelineSetComponent {
|
|
|
2676
2707
|
};
|
|
2677
2708
|
}
|
|
2678
2709
|
editTimeline(index) {
|
|
2679
|
-
this.editedTimeline = this.
|
|
2710
|
+
this.editedTimeline = this.timelines()[index];
|
|
2680
2711
|
}
|
|
2681
2712
|
onTimelineChange(timeline) {
|
|
2682
2713
|
const timelines = [...this.set.value];
|
|
@@ -2693,8 +2724,8 @@ class AnimationTimelineSetComponent {
|
|
|
2693
2724
|
this.set.setValue(timelines);
|
|
2694
2725
|
this.set.markAsDirty();
|
|
2695
2726
|
this.set.updateValueAndValidity();
|
|
2696
|
-
this.
|
|
2697
|
-
this.timelinesChange.emit(this.
|
|
2727
|
+
this.timelines.set(this.set.value);
|
|
2728
|
+
this.timelinesChange.emit(this.timelines());
|
|
2698
2729
|
}
|
|
2699
2730
|
deleteTimeline(index) {
|
|
2700
2731
|
this._dialogService
|
|
@@ -2706,15 +2737,15 @@ class AnimationTimelineSetComponent {
|
|
|
2706
2737
|
this.set.setValue(timelines);
|
|
2707
2738
|
this.set.markAsDirty();
|
|
2708
2739
|
this.set.updateValueAndValidity();
|
|
2709
|
-
this.
|
|
2710
|
-
this.timelinesChange.emit(this.
|
|
2740
|
+
this.timelines.set(this.set.value);
|
|
2741
|
+
this.timelinesChange.emit(this.timelines());
|
|
2711
2742
|
}
|
|
2712
2743
|
});
|
|
2713
2744
|
}
|
|
2714
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2715
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
2745
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AnimationTimelineSetComponent, deps: [{ token: i1.FormBuilder }, { token: i2$1.DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2746
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: AnimationTimelineSetComponent, isStandalone: true, selector: "gve-animation-timeline-set", inputs: { timelines: { classPropertyName: "timelines", publicName: "timelines", isSignal: true, isRequired: false, transformFunction: null }, elementIds: { classPropertyName: "elementIds", publicName: "elementIds", isSignal: true, isRequired: false, transformFunction: null }, tags: { classPropertyName: "tags", publicName: "tags", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timelines: "timelinesChange", timelinesChange: "timelinesChange", timelinesCancel: "timelinesCancel" }, ngImport: i0, template: "<form [formGroup]=\"form\">\r\n <!-- add -->\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n (click)=\"newTimeline()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n\r\n <!-- table -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>tag</th>\r\n <th>tweens</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of set.value; track t.tag; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button type=\"button\" mat-icon-button (click)=\"editTimeline(index)\">\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button type=\"button\" mat-icon-button (click)=\"deleteTimeline(index)\">\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ t.tag }}</td>\r\n <td>{{ t.tweens.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- editor -->\r\n <mat-expansion-panel [disabled]=\"!editedTimeline\" [expanded]=\"editedTimeline\">\r\n <mat-expansion-panel-header>\r\n timeline {{ editedTimeline?.tag }}\r\n </mat-expansion-panel-header>\r\n <gve-animation-timeline\r\n [elementIds]=\"elementIds()\"\r\n [tags]=\"tags()\"\r\n [timeline]=\"editedTimeline\"\r\n (timelineChange)=\"onTimelineChange($event)\"\r\n (timelineCancel)=\"closeTimeline()\"\r\n />\r\n </mat-expansion-panel>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}table{width:100%;border-collapse:collapse;margin:8px 0}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: AnimationTimelineComponent, selector: "gve-animation-timeline", inputs: ["timeline", "elementIds", "tags"], outputs: ["timelineChange", "timelineCancel"] }] }); }
|
|
2716
2747
|
}
|
|
2717
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
2748
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AnimationTimelineSetComponent, decorators: [{
|
|
2718
2749
|
type: Component,
|
|
2719
2750
|
args: [{ selector: 'gve-animation-timeline-set', imports: [
|
|
2720
2751
|
CommonModule,
|
|
@@ -2729,18 +2760,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2729
2760
|
MatTabsModule,
|
|
2730
2761
|
MatTooltipModule,
|
|
2731
2762
|
AnimationTimelineComponent,
|
|
2732
|
-
], template: "<form [formGroup]=\"form\">\r\n <!-- add -->\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n (click)=\"newTimeline()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n\r\n <!-- table -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>tag</th>\r\n <th>tweens</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of set.value; track t.tag; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button type=\"button\" mat-icon-button (click)=\"editTimeline(index)\">\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button type=\"button\" mat-icon-button (click)=\"deleteTimeline(index)\">\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ t.tag }}</td>\r\n <td>{{ t.tweens.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- editor -->\r\n <mat-expansion-panel [disabled]=\"!editedTimeline\" [expanded]=\"editedTimeline\">\r\n <mat-expansion-panel-header>\r\n timeline {{ editedTimeline?.tag }}\r\n </mat-expansion-panel-header>\r\n <gve-animation-timeline\r\n [elementIds]=\"elementIds\"\r\n [tags]=\"tags\"\r\n [timeline]=\"editedTimeline\"\r\n (timelineChange)=\"onTimelineChange($event)\"\r\n (timelineCancel)=\"closeTimeline()\"\r\n />\r\n </mat-expansion-panel>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}table{width:100%;border-collapse:collapse;margin:8px 0}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"] }]
|
|
2733
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$1.DialogService }]
|
|
2734
|
-
type: Input
|
|
2735
|
-
}], elementIds: [{
|
|
2736
|
-
type: Input
|
|
2737
|
-
}], tags: [{
|
|
2738
|
-
type: Input
|
|
2739
|
-
}], timelinesChange: [{
|
|
2740
|
-
type: Output
|
|
2741
|
-
}], timelinesCancel: [{
|
|
2742
|
-
type: Output
|
|
2743
|
-
}] } });
|
|
2763
|
+
], template: "<form [formGroup]=\"form\">\r\n <!-- add -->\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n (click)=\"newTimeline()\"\r\n >\r\n <mat-icon>add_circle</mat-icon>\r\n timeline\r\n </button>\r\n </div>\r\n\r\n <!-- table -->\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>tag</th>\r\n <th>tweens</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (t of set.value; track t.tag; let index = $index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button type=\"button\" mat-icon-button (click)=\"editTimeline(index)\">\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button type=\"button\" mat-icon-button (click)=\"deleteTimeline(index)\">\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ t.tag }}</td>\r\n <td>{{ t.tweens.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n <!-- editor -->\r\n <mat-expansion-panel [disabled]=\"!editedTimeline\" [expanded]=\"editedTimeline\">\r\n <mat-expansion-panel-header>\r\n timeline {{ editedTimeline?.tag }}\r\n </mat-expansion-panel-header>\r\n <gve-animation-timeline\r\n [elementIds]=\"elementIds()\"\r\n [tags]=\"tags()\"\r\n [timeline]=\"editedTimeline\"\r\n (timelineChange)=\"onTimelineChange($event)\"\r\n (timelineCancel)=\"closeTimeline()\"\r\n />\r\n </mat-expansion-panel>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}table{width:100%;border-collapse:collapse;margin:8px 0}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"] }]
|
|
2764
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$1.DialogService }] });
|
|
2744
2765
|
|
|
2745
2766
|
/**
|
|
2746
2767
|
* 🔑 `gve-snapshot-text-editor`
|
|
@@ -2752,26 +2773,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2752
2773
|
* - 🔥 `textChange` (`CharNode[]`): event emitted when text changes.
|
|
2753
2774
|
*/
|
|
2754
2775
|
class SnapshotTextEditorComponent {
|
|
2755
|
-
get text() {
|
|
2756
|
-
return this._nodes;
|
|
2757
|
-
}
|
|
2758
|
-
set text(value) {
|
|
2759
|
-
if (this._nodes === value) {
|
|
2760
|
-
return;
|
|
2761
|
-
}
|
|
2762
|
-
this._nodes = value || [];
|
|
2763
|
-
this.updateUserText();
|
|
2764
|
-
}
|
|
2765
2776
|
constructor(formBuilder,
|
|
2766
2777
|
// this component can be used as a dialog
|
|
2767
2778
|
dialogRef, data) {
|
|
2768
2779
|
this.dialogRef = dialogRef;
|
|
2769
2780
|
this.data = data;
|
|
2770
|
-
this.
|
|
2781
|
+
this.text = model([]);
|
|
2771
2782
|
/**
|
|
2772
2783
|
* Emitted when text changes.
|
|
2773
2784
|
*/
|
|
2774
|
-
this.textChange =
|
|
2785
|
+
this.textChange = output();
|
|
2775
2786
|
this.userText = formBuilder.control('', {
|
|
2776
2787
|
nonNullable: true,
|
|
2777
2788
|
validators: [Validators.required, Validators.maxLength(5000)],
|
|
@@ -2779,16 +2790,19 @@ class SnapshotTextEditorComponent {
|
|
|
2779
2790
|
this.form = new FormGroup({
|
|
2780
2791
|
userText: this.userText,
|
|
2781
2792
|
});
|
|
2793
|
+
// when text changes, update the user text
|
|
2794
|
+
effect(() => {
|
|
2795
|
+
this.updateUserText(this.text());
|
|
2796
|
+
});
|
|
2782
2797
|
}
|
|
2783
|
-
updateUserText() {
|
|
2784
|
-
this.userText.setValue(
|
|
2798
|
+
updateUserText(nodes) {
|
|
2799
|
+
this.userText.setValue(nodes.map((node) => node.label).join(''));
|
|
2785
2800
|
this.userText.markAsPristine();
|
|
2786
2801
|
this.userText.updateValueAndValidity();
|
|
2787
2802
|
}
|
|
2788
2803
|
ngOnInit() {
|
|
2789
2804
|
if (this.data?.payload?.text) {
|
|
2790
|
-
this.
|
|
2791
|
-
this.updateUserText();
|
|
2805
|
+
this.text.set(this.data.payload.text);
|
|
2792
2806
|
}
|
|
2793
2807
|
}
|
|
2794
2808
|
close() {
|
|
@@ -2802,14 +2816,14 @@ class SnapshotTextEditorComponent {
|
|
|
2802
2816
|
if (!this.userText.value) {
|
|
2803
2817
|
return;
|
|
2804
2818
|
}
|
|
2805
|
-
this.
|
|
2806
|
-
this.textChange.emit(this.
|
|
2807
|
-
this.dialogRef?.close(this.
|
|
2819
|
+
this.text.set(SnapshotViewService.stringToBaseChars(this.userText.value));
|
|
2820
|
+
this.textChange.emit(this.text());
|
|
2821
|
+
this.dialogRef?.close(this.text());
|
|
2808
2822
|
}
|
|
2809
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
2810
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.
|
|
2823
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SnapshotTextEditorComponent, deps: [{ token: i1.FormBuilder }, { token: i3$1.MatDialogRef, optional: true }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2824
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SnapshotTextEditorComponent, isStandalone: true, selector: "gve-snapshot-text-editor", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { text: "textChange", textChange: "textChange" }, ngImport: i0, template: "<div [style.padding]=\"dialogRef ? '8px' : '0'\">\r\n @if (dialogRef) {\r\n <div id=\"heading\">\r\n <h2>Set Base Text</h2>\r\n </div>\r\n }\r\n <form [formGroup]=\"form\" (submit)=\"save()\">\r\n <fieldset>\r\n <div id=\"batch-input\">\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>base text</mat-label>\r\n <textarea matInput [formControl]=\"userText\" rows=\"8\"></textarea>\r\n @if ($any(userText).errors?.required && (userText.dirty ||\r\n userText.touched)) {\r\n <mat-error>text required</mat-error>\r\n } @if ($any(userText).errors?.maxLength && (userText.dirty ||\r\n userText.touched)) {\r\n <mat-error>text too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div class=\"form-row-center\">\r\n @if (dialogRef) {\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Close dialog\"\r\n (click)=\"close()\"\r\n >\r\n close\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Set base text\"\r\n [disabled]=\"form.invalid\"\r\n (click)=\"save()\"\r\n >\r\n set\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n</div>\r\n", styles: [".full-width{width:100%}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}div#heading{margin:8px;text-align:center}\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],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: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { 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"] }] }); }
|
|
2811
2825
|
}
|
|
2812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
2826
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SnapshotTextEditorComponent, decorators: [{
|
|
2813
2827
|
type: Component,
|
|
2814
2828
|
args: [{ selector: 'gve-snapshot-text-editor', imports: [
|
|
2815
2829
|
ReactiveFormsModule,
|
|
@@ -2825,11 +2839,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
2825
2839
|
}, {
|
|
2826
2840
|
type: Inject,
|
|
2827
2841
|
args: [MAT_DIALOG_DATA]
|
|
2828
|
-
}] }]
|
|
2829
|
-
type: Input
|
|
2830
|
-
}], textChange: [{
|
|
2831
|
-
type: Output
|
|
2832
|
-
}] } });
|
|
2842
|
+
}] }] });
|
|
2833
2843
|
|
|
2834
2844
|
// default snapshot view title
|
|
2835
2845
|
const VIEW_TITLE = 'preview';
|
|
@@ -2848,36 +2858,36 @@ const SVG_TRANSP_SUFFIX = '_t';
|
|
|
2848
2858
|
* - 🔥 `snapshotCancel` (`void`): emitted when the user cancels the snapshot editing.
|
|
2849
2859
|
*/
|
|
2850
2860
|
class SnapshotEditorComponent {
|
|
2851
|
-
/**
|
|
2852
|
-
* The snapshot to edit.
|
|
2853
|
-
*/
|
|
2854
|
-
get snapshot() {
|
|
2855
|
-
return this._snapshot;
|
|
2856
|
-
}
|
|
2857
|
-
set snapshot(value) {
|
|
2858
|
-
if (this._snapshot === value) {
|
|
2859
|
-
return;
|
|
2860
|
-
}
|
|
2861
|
-
this._snapshot = value || undefined;
|
|
2862
|
-
this.updateForm(this._snapshot);
|
|
2863
|
-
setTimeout(() => {
|
|
2864
|
-
this.runToLast();
|
|
2865
|
-
}, 0);
|
|
2866
|
-
}
|
|
2867
2861
|
constructor(formBuilder, _api, _dialog, _dialogService, _snackbar) {
|
|
2868
2862
|
this._api = _api;
|
|
2869
2863
|
this._dialog = _dialog;
|
|
2870
2864
|
this._dialogService = _dialogService;
|
|
2871
2865
|
this._snackbar = _snackbar;
|
|
2872
2866
|
this._nanoid = customAlphabet('1234567890abcdef', 10);
|
|
2867
|
+
/**
|
|
2868
|
+
* The snapshot to edit.
|
|
2869
|
+
*/
|
|
2870
|
+
this.snapshot = model();
|
|
2871
|
+
/**
|
|
2872
|
+
* The batch operations text to set for the editor.
|
|
2873
|
+
*/
|
|
2874
|
+
this.batchOps = input();
|
|
2875
|
+
/**
|
|
2876
|
+
* True to disable saving.
|
|
2877
|
+
*/
|
|
2878
|
+
this.noSave = input();
|
|
2879
|
+
/**
|
|
2880
|
+
* True to enable debug mode for view rendition.
|
|
2881
|
+
*/
|
|
2882
|
+
this.debug = input();
|
|
2873
2883
|
/**
|
|
2874
2884
|
* Emitted when the user saves the edited snapshot.
|
|
2875
2885
|
*/
|
|
2876
|
-
this.snapshotChange =
|
|
2886
|
+
this.snapshotChange = output();
|
|
2877
2887
|
/**
|
|
2878
2888
|
* Emitted when the user cancels the snapshot editing.
|
|
2879
2889
|
*/
|
|
2880
|
-
this.snapshotCancel =
|
|
2890
|
+
this.snapshotCancel = output();
|
|
2881
2891
|
// list of operations output tags
|
|
2882
2892
|
this.opTags = [];
|
|
2883
2893
|
// list of operation diplomatic.g element IDs
|
|
@@ -2899,6 +2909,7 @@ class SnapshotEditorComponent {
|
|
|
2899
2909
|
this.viewTitle = VIEW_TITLE;
|
|
2900
2910
|
this.rulers = true;
|
|
2901
2911
|
this.initialStepIndex = -1;
|
|
2912
|
+
this.showChain = new FormControl(false, { nonNullable: true });
|
|
2902
2913
|
// general
|
|
2903
2914
|
this.width = new FormControl(800, { nonNullable: true });
|
|
2904
2915
|
this.height = new FormControl(600, { nonNullable: true });
|
|
@@ -2958,6 +2969,13 @@ class SnapshotEditorComponent {
|
|
|
2958
2969
|
// timelines
|
|
2959
2970
|
timelines: this.timelines,
|
|
2960
2971
|
});
|
|
2972
|
+
// when snapshot changes, update the form
|
|
2973
|
+
effect(() => {
|
|
2974
|
+
this.updateForm(this.snapshot());
|
|
2975
|
+
setTimeout(() => {
|
|
2976
|
+
this.runToLast();
|
|
2977
|
+
}, 0);
|
|
2978
|
+
});
|
|
2961
2979
|
}
|
|
2962
2980
|
/**
|
|
2963
2981
|
* Set the view data for the snapshot view.
|
|
@@ -2978,7 +2996,7 @@ class SnapshotEditorComponent {
|
|
|
2978
2996
|
this.viewData = {
|
|
2979
2997
|
snapshot: snapshot,
|
|
2980
2998
|
options: {
|
|
2981
|
-
debug: this.debug,
|
|
2999
|
+
debug: this.debug(),
|
|
2982
3000
|
delayedRender: true,
|
|
2983
3001
|
showRulers: true,
|
|
2984
3002
|
showGrid: true,
|
|
@@ -3142,6 +3160,9 @@ class SnapshotEditorComponent {
|
|
|
3142
3160
|
* @param op The changed operation.
|
|
3143
3161
|
*/
|
|
3144
3162
|
onOperationChange(op) {
|
|
3163
|
+
if (!op) {
|
|
3164
|
+
return;
|
|
3165
|
+
}
|
|
3145
3166
|
console.log('operation change');
|
|
3146
3167
|
const operations = [...this.operations.value];
|
|
3147
3168
|
// replace or add the operation
|
|
@@ -3398,6 +3419,10 @@ class SnapshotEditorComponent {
|
|
|
3398
3419
|
this.playTimeline(tl);
|
|
3399
3420
|
}, 0);
|
|
3400
3421
|
}
|
|
3422
|
+
// get the chain model if requested
|
|
3423
|
+
if (this.showChain.value) {
|
|
3424
|
+
this.getChainAt(index);
|
|
3425
|
+
}
|
|
3401
3426
|
},
|
|
3402
3427
|
error: (error) => {
|
|
3403
3428
|
console.error(error);
|
|
@@ -3423,6 +3448,46 @@ class SnapshotEditorComponent {
|
|
|
3423
3448
|
this.result = undefined;
|
|
3424
3449
|
}
|
|
3425
3450
|
}
|
|
3451
|
+
getChainAt(index, lastOperation) {
|
|
3452
|
+
// get the snapshot to run operations on
|
|
3453
|
+
const snapshot = this.getSnapshot();
|
|
3454
|
+
if (!snapshot.text) {
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3457
|
+
// remove from the snapshot the operations past the specified index,
|
|
3458
|
+
// also replacing the last operation when this was received as a parameter
|
|
3459
|
+
if (lastOperation) {
|
|
3460
|
+
snapshot.operations = snapshot.operations.slice(0, index);
|
|
3461
|
+
snapshot.operations.push(lastOperation);
|
|
3462
|
+
}
|
|
3463
|
+
else {
|
|
3464
|
+
lastOperation = snapshot.operations[index];
|
|
3465
|
+
snapshot.operations = snapshot.operations.slice(0, index + 1);
|
|
3466
|
+
}
|
|
3467
|
+
this.busy = true;
|
|
3468
|
+
this._api
|
|
3469
|
+
.getChain(snapshot.text, snapshot.operations)
|
|
3470
|
+
.subscribe({
|
|
3471
|
+
next: (wrapper) => {
|
|
3472
|
+
// handle operation (non-fatal) error or result
|
|
3473
|
+
if (wrapper.error) {
|
|
3474
|
+
this._snackbar.open(wrapper.error, 'OK');
|
|
3475
|
+
this.chain = undefined;
|
|
3476
|
+
}
|
|
3477
|
+
else {
|
|
3478
|
+
this.chain = wrapper.result;
|
|
3479
|
+
}
|
|
3480
|
+
},
|
|
3481
|
+
error: (error) => {
|
|
3482
|
+
console.error(error);
|
|
3483
|
+
this._transparentIds = undefined;
|
|
3484
|
+
this._snackbar.open('Error running operations', 'OK');
|
|
3485
|
+
},
|
|
3486
|
+
complete: () => {
|
|
3487
|
+
this.busy = false;
|
|
3488
|
+
},
|
|
3489
|
+
});
|
|
3490
|
+
}
|
|
3426
3491
|
/**
|
|
3427
3492
|
* Update the snapshot view by running the operations up to the
|
|
3428
3493
|
* currently edited operation if any.
|
|
@@ -3441,63 +3506,6 @@ class SnapshotEditorComponent {
|
|
|
3441
3506
|
}, 0);
|
|
3442
3507
|
}
|
|
3443
3508
|
// #endregion
|
|
3444
|
-
/**
|
|
3445
|
-
* Build the snapshot at the specified execution step. This implies adding
|
|
3446
|
-
* the nodes introduced by the operations up to the specified step, and
|
|
3447
|
-
* updating the features of the nodes introduced by the specified step.
|
|
3448
|
-
* Also, the operations after the specified step are removed from the
|
|
3449
|
-
* snapshot.
|
|
3450
|
-
*
|
|
3451
|
-
* @param step The step to build the snapshot at.
|
|
3452
|
-
* @returns The snapshot at the specified step.
|
|
3453
|
-
*/
|
|
3454
|
-
buildSnapshotAtStep(step) {
|
|
3455
|
-
// no result, nothing to do
|
|
3456
|
-
if (!this.result) {
|
|
3457
|
-
return null;
|
|
3458
|
-
}
|
|
3459
|
-
// get the currently edited snapshot
|
|
3460
|
-
const snapshot = this.getSnapshot();
|
|
3461
|
-
// find the max ID in snapshot.text (=original) nodes,
|
|
3462
|
-
// so that any ID greater than it belongs to new nodes
|
|
3463
|
-
const maxOriginalId = snapshot.text.reduce((max, n) => Math.max(max, n.id), 0);
|
|
3464
|
-
// get the nodes of the picked step
|
|
3465
|
-
const nodes = snapshot.text;
|
|
3466
|
-
const stepNodes = this.result.taggedNodes[step.outputTag] || [];
|
|
3467
|
-
// update the snapshot text nodes copies with the picked step nodes,
|
|
3468
|
-
// by updating their features if existing, or adding new nodes if not.
|
|
3469
|
-
for (const sn of stepNodes) {
|
|
3470
|
-
// find the node in the original snapshot text
|
|
3471
|
-
const i = nodes.findIndex((n) => n.id === sn.id);
|
|
3472
|
-
// if found, update its features, else add it
|
|
3473
|
-
if (i > -1) {
|
|
3474
|
-
nodes[i].features = sn.features;
|
|
3475
|
-
}
|
|
3476
|
-
else {
|
|
3477
|
-
// new node: we assume that it has a manually set position (x,y features)
|
|
3478
|
-
nodes.push(sn);
|
|
3479
|
-
}
|
|
3480
|
-
}
|
|
3481
|
-
// append nodes introduced *before* the picked step, if any
|
|
3482
|
-
// (those introduced by the picked step have already been added)
|
|
3483
|
-
const stepIndex = this.result.steps.indexOf(step);
|
|
3484
|
-
for (let i = 0; i < stepIndex; i++) {
|
|
3485
|
-
const stepNodes = this.result.taggedNodes[this.result.steps[i].outputTag];
|
|
3486
|
-
for (const n of stepNodes) {
|
|
3487
|
-
if (n.id > maxOriginalId && !nodes.find((x) => x.id === n.id)) {
|
|
3488
|
-
nodes.push(n);
|
|
3489
|
-
}
|
|
3490
|
-
}
|
|
3491
|
-
}
|
|
3492
|
-
// update the snapshot text nodes
|
|
3493
|
-
snapshot.text = nodes;
|
|
3494
|
-
// remove from the snapshot the operations after the picked step
|
|
3495
|
-
const i = snapshot.operations.findIndex((o) => o.id === step.operation.id);
|
|
3496
|
-
if (i > -1) {
|
|
3497
|
-
snapshot.operations = snapshot.operations.slice(0, i + 1);
|
|
3498
|
-
}
|
|
3499
|
-
return snapshot;
|
|
3500
|
-
}
|
|
3501
3509
|
playTimeline(tl) {
|
|
3502
3510
|
const shadowRoot = this.snapshotView?.nativeElement?.shadowRoot;
|
|
3503
3511
|
if (tl && shadowRoot) {
|
|
@@ -3556,9 +3564,16 @@ class SnapshotEditorComponent {
|
|
|
3556
3564
|
* @param event The event.
|
|
3557
3565
|
*/
|
|
3558
3566
|
onVisualEvent(event) {
|
|
3567
|
+
if (this._handlingOver) {
|
|
3568
|
+
return;
|
|
3569
|
+
}
|
|
3559
3570
|
const d = event.detail;
|
|
3560
3571
|
if (d.event.type === 'mouseover') {
|
|
3561
3572
|
const visual = d.source;
|
|
3573
|
+
if (visual.id === this._lastOverId) {
|
|
3574
|
+
return;
|
|
3575
|
+
}
|
|
3576
|
+
this._handlingOver = true;
|
|
3562
3577
|
const sb = [];
|
|
3563
3578
|
// id (type)
|
|
3564
3579
|
sb.push('#' + visual.id);
|
|
@@ -3578,7 +3593,9 @@ class SnapshotEditorComponent {
|
|
|
3578
3593
|
sb.push(` (@${visual.x.toFixed(1)},${visual.y.toFixed(1)} ` +
|
|
3579
3594
|
`◻${visual.width.toFixed(1)}×${visual.height.toFixed(1)})`);
|
|
3580
3595
|
this.visualInfo = sb.join('');
|
|
3596
|
+
this._lastOverId = visual.id;
|
|
3581
3597
|
}
|
|
3598
|
+
this._handlingOver = false;
|
|
3582
3599
|
}
|
|
3583
3600
|
/**
|
|
3584
3601
|
* Handle the change of line heights by updating the form control.
|
|
@@ -3596,6 +3613,9 @@ class SnapshotEditorComponent {
|
|
|
3596
3613
|
* @param timelines The timelines.
|
|
3597
3614
|
*/
|
|
3598
3615
|
onTimelinesChange(timelines) {
|
|
3616
|
+
if (!timelines) {
|
|
3617
|
+
return;
|
|
3618
|
+
}
|
|
3599
3619
|
this.timelines.setValue(timelines);
|
|
3600
3620
|
this.timelines.markAsDirty();
|
|
3601
3621
|
this.timelines.updateValueAndValidity();
|
|
@@ -3719,16 +3739,16 @@ class SnapshotEditorComponent {
|
|
|
3719
3739
|
* in the snapshot change event.
|
|
3720
3740
|
*/
|
|
3721
3741
|
save() {
|
|
3722
|
-
if (this.form.invalid || this.noSave) {
|
|
3742
|
+
if (this.form.invalid || this.noSave()) {
|
|
3723
3743
|
return;
|
|
3724
3744
|
}
|
|
3725
|
-
this.
|
|
3726
|
-
this.snapshotChange.emit(this.
|
|
3745
|
+
this.snapshot.set(this.getSnapshot());
|
|
3746
|
+
this.snapshotChange.emit(this.snapshot());
|
|
3727
3747
|
}
|
|
3728
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.
|
|
3729
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: SnapshotEditorComponent, isStandalone: true, selector: "gve-snapshot-editor", inputs: { snapshot: "snapshot", batchOps: "batchOps", noSave: "noSave", debug: "debug" }, outputs: { snapshotChange: "snapshotChange", snapshotCancel: "snapshotCancel" }, viewQueries: [{ propertyName: "snapshotView", first: true, predicate: ["snapshotView"], descendants: true }], ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- text -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>article</mat-icon> <span class=\"label\">text</span>\r\n </ng-template>\r\n <mat-expansion-panel>\r\n <mat-expansion-panel-header>\r\n <mat-panel-title> base text </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <!-- base text -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"mat-warn\"\r\n matTooltip=\"Enter base text\"\r\n (click)=\"inputBaseText()\"\r\n [disabled]=\"busy\"\r\n >\r\n <mat-icon>edit</mat-icon> base text\r\n </button>\r\n <!-- base text metadata -->\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- offsetX -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetX\"\r\n placeholder=\"X offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- offsetY -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetY\"\r\n placeholder=\"Y offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- lineHeightOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>ln h-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"lineHeightOffset\"\r\n placeholder=\"ln h-offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- charSpacingOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>char spacing</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"charSpacingOffset\"\r\n placeholder=\"char spacing\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- spcWidthOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>spc w-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"spcWidthOffset\"\r\n placeholder=\"spc w-offset\"\r\n />\r\n </mat-form-field>\r\n <!-- minLineHeights -->\r\n <div class=\"boxed\">\r\n <gve-ln-heights-editor\r\n [lineCount]=\"lineCount\"\r\n [heights]=\"lnHeights.value\"\r\n (heightsChange)=\"onHeightsChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n <!-- textStyle -->\r\n <div>\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>text style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"textStyle\"\r\n placeholder=\"text style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </fieldset>\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- operations -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>edit</mat-icon> <span class=\"label\">operations</span>\r\n </ng-template>\r\n\r\n <div id=\"snapshot-container\">\r\n <div id=\"general\">\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"width\"\r\n placeholder=\"width\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"height\"\r\n placeholder=\"height\"\r\n />\r\n </mat-form-field>\r\n\r\n <div class=\"form-row right\">\r\n <!-- remove ops -->\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Remove all the operations\"\r\n [disabled]=\"!operations.value.length || busy\"\r\n (click)=\"clearOperations()\"\r\n >\r\n <mat-icon>delete_forever</mat-icon> clear\r\n </button>\r\n\r\n <!-- batch add ops -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n matTooltip=\"Add a batch of operations\"\r\n class=\"mat-primary\"\r\n [disabled]=\"busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n <mat-icon>post_add</mat-icon> batch\r\n </button>\r\n\r\n <!-- add op -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n [disabled]=\"!baseText.value\"\r\n (click)=\"editNewOperation()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> operation\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ops -->\r\n <div id=\"ops\">\r\n <!-- operations list -->\r\n @if (operations.value.length) {\r\n <table id=\"list\">\r\n <thead>\r\n <tr>\r\n <th>nr.</th>\r\n <th></th>\r\n <th>ID</th>\r\n <th>type</th>\r\n <th>at</th>\r\n <th>run</th>\r\n <th>value</th>\r\n <th>itag</th>\r\n <th>otag</th>\r\n <th>gid</th>\r\n <th>feats</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (operation of operations.value; track operation.id; let\r\n index=$index) {\r\n <tr\r\n [ngClass]=\"{ selected: operation.id === resultOperationId }\"\r\n [ngClass]=\"{ edited: operation.id === editedOp?.id }\"\r\n >\r\n <td class=\"fit-width\">{{ index + 1 }}.</td>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-primary\"\r\n (click)=\"editOperation(index)\"\r\n matTooltip=\"Edit operation\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n (click)=\"deleteOperation(index)\"\r\n matTooltip=\"Delete operation\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <!-- run to -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-accent\"\r\n (click)=\"runTo(index)\"\r\n matTooltip=\"Run to this operation\"\r\n >\r\n <mat-icon class=\"mat-accent\">subscriptions</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ operation.id }}</td>\r\n <td>{{ operation.type | flatLookup : opTypeMap }}</td>\r\n <td>{{ operation.at }}</td>\r\n <td>{{ operation.run }}</td>\r\n <td>{{ operation.value }}</td>\r\n <td>{{ operation.inputTag }}</td>\r\n <td>{{ operation.outputTag }}</td>\r\n <td>{{ operation.groupId }}</td>\r\n <td>{{ operation.features?.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- operation editor -->\r\n <mat-expansion-panel [expanded]=\"editedOp\" [disabled]=\"!editedOp\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>operation {{ editedOp?.id }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset>\r\n <gve-chain-operation-editor\r\n [hidePreview]=\"editedOpIndex === -1\"\r\n [operation]=\"editedOp\"\r\n (operationCancel)=\"onOperationCancel()\"\r\n (operationChange)=\"onOperationChange($event)\"\r\n (operationPreview)=\"onOperationPreview($event)\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- opStyle -->\r\n <div id=\"opStyle\">\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>operations style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"opStyle\"\r\n placeholder=\"operations style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- image -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>image</mat-icon> <span class=\"label\">image</span>\r\n </ng-template>\r\n\r\n <div id=\"image\">\r\n <div id=\"image-ctl\">\r\n <!-- url -->\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>URL</mat-label>\r\n <input matInput [formControl]=\"imageUrl\" />\r\n </mat-form-field>\r\n <div class=\"form-row\">\r\n <!-- x -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageX\"\r\n placeholder=\"X\"\r\n />\r\n </mat-form-field>\r\n <!-- y -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageY\"\r\n placeholder=\"Y\"\r\n />\r\n </mat-form-field>\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageWidth\"\r\n />\r\n </mat-form-field>\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageHeight\"\r\n />\r\n </mat-form-field>\r\n <!-- reset -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset image metadata\"\r\n (click)=\"resetImgMetadata()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n <div>\r\n <!-- image opacity -->\r\n <mat-slider\r\n min=\"0\"\r\n max=\"1\"\r\n step=\"0.01\"\r\n thumbLabel\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n matTooltip=\"Image opacity\"\r\n >\r\n <input\r\n matSliderThumb\r\n [value]=\"imageOpacity.value\"\r\n (valueChange)=\"onImageOpacityChange($event)\"\r\n />\r\n </mat-slider>\r\n <span id=\"opacity-value\">{{\r\n imageOpacity.value | number : \"1.2-2\"\r\n }}</span>\r\n </div>\r\n <!-- defs -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>defs</mat-label>\r\n <textarea matInput [formControl]=\"defs\" rows=\"3\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div id=\"image-view\">\r\n @if (imageUrl.value) {\r\n <img\r\n #imgElement\r\n alt=\"background\"\r\n [src]=\"imageUrl.value\"\r\n width=\"600\"\r\n (load)=\"onImageLoad(imgElement)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- timelines -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>animation</mat-icon> <span class=\"label\">animation</span>\r\n </ng-template>\r\n\r\n <gve-animation-timeline-set\r\n [tags]=\"opTags\"\r\n [elementIds]=\"opElementIds\"\r\n [timelines]=\"timelines.value\"\r\n (timelinesChange)=\"onTimelinesChange($event)\"\r\n />\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- progress -->\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\" *ngIf=\"busy\" />\r\n </div>\r\n\r\n <!-- result -->\r\n @if (result) {\r\n <fieldset id=\"result\">\r\n <legend>result</legend>\r\n <gve-chain-result-view\r\n [result]=\"result\"\r\n [initialStepIndex]=\"initialStepIndex\"\r\n (stepPick)=\"onStepPick($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- snapshot view -->\r\n <fieldset id=\"preview\">\r\n <legend class=\"button-row\">\r\n <span>{{ viewTitle }}</span>\r\n </legend>\r\n <!-- snapshot view -->\r\n <gve-snapshot-view\r\n #snapshotView\r\n [debug]=\"debug\"\r\n [data]=\"viewData\"\r\n (snapshotRender)=\"onSnapshotRender($any($event))\"\r\n (visualEvent)=\"onVisualEvent($any($event))\"\r\n />\r\n <div class=\"button-row\">\r\n <!-- toggle ruler -->\r\n <mat-button-toggle\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Toggle rulers\"\r\n [checked]=\"rulers\"\r\n (change)=\"toggleRulers()\"\r\n >\r\n <mat-icon class=\"mat-primary\">straighten</mat-icon>\r\n </mat-button-toggle>\r\n <!-- run to last -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"primary\"\r\n matTooltip=\"Refresh preview\"\r\n (click)=\"runToLast()\"\r\n >\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n </div>\r\n @if (visualInfo) {\r\n <div id=\"visual-info\">{{ visualInfo }}</div>\r\n }\r\n </fieldset>\r\n\r\n <!--buttons -->\r\n <div class=\"form-row-center\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave) {\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save changes\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}.form-row .right{margin-left:auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}#text-range{margin:8px;border:1px solid silver;border-radius:6px;padding:6px}mat-expansion-panel{margin:8px 0}div#visual-info{font-size:95%;color:#909090;margin:8px}#list{margin:8px 0}#opStyle{margin-top:8px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#c8d9eb}tr.edited{background-color:#f6f6e4}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:#909090}.error{color:red}.input-nr{width:6em}.full-width{width:100%}.code{font-family:Courier New,Courier,monospace}.boxed{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}span.label{margin-left:8px}gve-animation-timeline-set{margin:8px 0}div#image{display:grid;gap:8px;grid-template-rows:auto;grid-template-columns:1fr auto;grid-template-areas:\"image-ctl image-view\"}div#image-ctl{grid-area:image-ctl}div#image-view{grid-area:image-view}@media only screen and (max-width: 959px){div#image{grid-template-columns:1fr;grid-template-areas:\"image-ctl\" \"image-view\"}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "ngmodule", type: FormsModule }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "component", type: i8$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: i13.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i14.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i14.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i15.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i15.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i15.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ChainOperationEditorComponent, selector: "gve-chain-operation-editor", inputs: ["operation", "snapshot", "hidePreview"], outputs: ["operationChange", "operationPreview", "operationCancel"] }, { kind: "component", type: ChainResultViewComponent, selector: "gve-chain-result-view", inputs: ["result", "initialStepIndex"], outputs: ["stepPick"] }, { kind: "component", type: LnHeightsEditorComponent, selector: "gve-ln-heights-editor", inputs: ["lineCount", "heights"], outputs: ["heightsChange"] }, { kind: "component", type: AnimationTimelineSetComponent, selector: "gve-animation-timeline-set", inputs: ["timelines", "elementIds", "tags"], outputs: ["timelinesChange", "timelinesCancel"] }, { kind: "pipe", type: FlatLookupPipe, name: "flatLookup" }] }); }
|
|
3748
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SnapshotEditorComponent, deps: [{ token: i1.FormBuilder }, { token: GveApiService }, { token: i3$1.MatDialog }, { token: i2$1.DialogService }, { token: i4$2.MatSnackBar }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3749
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SnapshotEditorComponent, isStandalone: true, selector: "gve-snapshot-editor", inputs: { snapshot: { classPropertyName: "snapshot", publicName: "snapshot", isSignal: true, isRequired: false, transformFunction: null }, batchOps: { classPropertyName: "batchOps", publicName: "batchOps", isSignal: true, isRequired: false, transformFunction: null }, noSave: { classPropertyName: "noSave", publicName: "noSave", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { snapshot: "snapshotChange", snapshotChange: "snapshotChange", snapshotCancel: "snapshotCancel" }, viewQueries: [{ propertyName: "snapshotView", first: true, predicate: ["snapshotView"], descendants: true }], ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- text -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>article</mat-icon> <span class=\"label\">text</span>\r\n </ng-template>\r\n <mat-expansion-panel>\r\n <mat-expansion-panel-header>\r\n <mat-panel-title> base text </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <!-- base text -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"mat-warn\"\r\n matTooltip=\"Enter base text\"\r\n (click)=\"inputBaseText()\"\r\n [disabled]=\"busy\"\r\n >\r\n <mat-icon>edit</mat-icon> base text\r\n </button>\r\n\r\n @if (textRange) {\r\n <span id=\"text-range\">{{ textRange.at }}\u00D7{{ textRange.run }}</span>\r\n }\r\n </div>\r\n <!-- base text metadata -->\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- offsetX -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetX\"\r\n placeholder=\"X offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- offsetY -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetY\"\r\n placeholder=\"Y offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- lineHeightOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>ln h-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"lineHeightOffset\"\r\n placeholder=\"ln h-offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- charSpacingOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>char spacing</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"charSpacingOffset\"\r\n placeholder=\"char spacing\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- spcWidthOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>spc w-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"spcWidthOffset\"\r\n placeholder=\"spc w-offset\"\r\n />\r\n </mat-form-field>\r\n <!-- minLineHeights -->\r\n <div class=\"boxed\">\r\n <gve-ln-heights-editor\r\n [lineCount]=\"lineCount\"\r\n [heights]=\"lnHeights.value || undefined\"\r\n (heightsChange)=\"onHeightsChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n <!-- textStyle -->\r\n <div>\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>text style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"textStyle\"\r\n placeholder=\"text style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </fieldset>\r\n <!-- text characters -->\r\n <gve-base-text-view\r\n [text]=\"baseText.value\"\r\n [hasLineNumber]=\"true\"\r\n (rangePick)=\"onRangePick($event)\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- operations -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>edit</mat-icon> <span class=\"label\">operations</span>\r\n </ng-template>\r\n\r\n <div id=\"snapshot-container\">\r\n <div id=\"general\">\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"width\"\r\n placeholder=\"width\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"height\"\r\n placeholder=\"height\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- chain -->\r\n <mat-checkbox [formControl]=\"showChain\">show chain</mat-checkbox>\r\n\r\n <div class=\"form-row right\">\r\n <!-- remove ops -->\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Remove all the operations\"\r\n [disabled]=\"!operations.value.length || busy\"\r\n (click)=\"clearOperations()\"\r\n >\r\n <mat-icon>delete_forever</mat-icon> clear\r\n </button>\r\n\r\n <!-- batch add ops -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n matTooltip=\"Add a batch of operations\"\r\n class=\"mat-primary\"\r\n [disabled]=\"busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n <mat-icon>post_add</mat-icon> batch\r\n </button>\r\n\r\n <!-- add op -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n [disabled]=\"!baseText.value\"\r\n (click)=\"editNewOperation()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> operation\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ops -->\r\n <div id=\"ops\">\r\n <!-- operations list -->\r\n @if (operations.value.length) {\r\n <table id=\"list\">\r\n <thead>\r\n <tr>\r\n <th>nr.</th>\r\n <th></th>\r\n <th>ID</th>\r\n <th>type</th>\r\n <th>at</th>\r\n <th>run</th>\r\n <th>value</th>\r\n <th>itag</th>\r\n <th>otag</th>\r\n <th>gid</th>\r\n <th>feats</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (operation of operations.value; track operation.id; let\r\n index=$index) {\r\n <tr\r\n [ngClass]=\"{ selected: operation.id === resultOperationId }\"\r\n [ngClass]=\"{ edited: operation.id === editedOp?.id }\"\r\n >\r\n <td class=\"fit-width\">{{ index + 1 }}.</td>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-primary\"\r\n (click)=\"editOperation(index)\"\r\n matTooltip=\"Edit operation\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n (click)=\"deleteOperation(index)\"\r\n matTooltip=\"Delete operation\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <!-- run to -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-accent\"\r\n (click)=\"runTo(index)\"\r\n matTooltip=\"Run to this operation\"\r\n >\r\n <mat-icon class=\"mat-accent\">subscriptions</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ operation.id }}</td>\r\n <td>{{ operation.type | flatLookup : opTypeMap }}</td>\r\n <td>{{ operation.at }}</td>\r\n <td>{{ operation.run }}</td>\r\n <td>{{ operation.value }}</td>\r\n <td>{{ operation.inputTag }}</td>\r\n <td>{{ operation.outputTag }}</td>\r\n <td>{{ operation.groupId }}</td>\r\n <td>{{ operation.features?.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- operation editor -->\r\n <mat-expansion-panel [expanded]=\"editedOp\" [disabled]=\"!editedOp\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>operation {{ editedOp?.id }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset>\r\n <gve-chain-operation-editor\r\n [hidePreview]=\"editedOpIndex === -1\"\r\n [operation]=\"editedOp\"\r\n (operationCancel)=\"onOperationCancel()\"\r\n (operationChange)=\"onOperationChange($event)\"\r\n (operationPreview)=\"onOperationPreview($event)\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- opStyle -->\r\n <div id=\"opStyle\">\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>operations style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"opStyle\"\r\n placeholder=\"operations style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- image -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>image</mat-icon> <span class=\"label\">image</span>\r\n </ng-template>\r\n\r\n <div id=\"image\">\r\n <div id=\"image-ctl\">\r\n <!-- url -->\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>URL</mat-label>\r\n <input matInput [formControl]=\"imageUrl\" />\r\n </mat-form-field>\r\n <div class=\"form-row\">\r\n <!-- x -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageX\"\r\n placeholder=\"X\"\r\n />\r\n </mat-form-field>\r\n <!-- y -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageY\"\r\n placeholder=\"Y\"\r\n />\r\n </mat-form-field>\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageWidth\"\r\n />\r\n </mat-form-field>\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageHeight\"\r\n />\r\n </mat-form-field>\r\n <!-- reset -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Reset image metadata\"\r\n (click)=\"resetImgMetadata()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </div>\r\n <div>\r\n <!-- image opacity -->\r\n <mat-slider\r\n min=\"0\"\r\n max=\"1\"\r\n step=\"0.01\"\r\n thumbLabel\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n matTooltip=\"Image opacity\"\r\n >\r\n <input\r\n matSliderThumb\r\n [value]=\"imageOpacity.value\"\r\n (valueChange)=\"onImageOpacityChange($event)\"\r\n />\r\n </mat-slider>\r\n <span id=\"opacity-value\">{{\r\n imageOpacity.value | number : \"1.2-2\"\r\n }}</span>\r\n </div>\r\n <!-- defs -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>defs</mat-label>\r\n <textarea matInput [formControl]=\"defs\" rows=\"3\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div id=\"image-view\">\r\n @if (imageUrl.value) {\r\n <img\r\n #imgElement\r\n alt=\"background\"\r\n [src]=\"imageUrl.value\"\r\n width=\"600\"\r\n (load)=\"onImageLoad(imgElement)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- timelines -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>animation</mat-icon> <span class=\"label\">animation</span>\r\n </ng-template>\r\n\r\n <gve-animation-timeline-set\r\n [tags]=\"opTags\"\r\n [elementIds]=\"opElementIds\"\r\n [timelines]=\"timelines.value\"\r\n (timelinesChange)=\"onTimelinesChange($event)\"\r\n />\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- progress -->\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\" *ngIf=\"busy\" />\r\n </div>\r\n\r\n <!-- result -->\r\n @if (result) {\r\n <fieldset id=\"result\">\r\n <legend>result</legend>\r\n <gve-chain-result-view\r\n [result]=\"result\"\r\n [initialStepIndex]=\"initialStepIndex\"\r\n (stepPick)=\"onStepPick($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- snapshot view -->\r\n <fieldset id=\"preview\">\r\n <legend class=\"button-row\">\r\n <span>{{ viewTitle }}</span>\r\n </legend>\r\n <!-- snapshot view -->\r\n <gve-snapshot-view\r\n #snapshotView\r\n [debug]=\"debug()\"\r\n [data]=\"viewData\"\r\n (snapshotRender)=\"onSnapshotRender($any($event))\"\r\n (visualEvent)=\"onVisualEvent($any($event))\"\r\n />\r\n <div class=\"button-row\">\r\n <!-- toggle ruler -->\r\n <mat-button-toggle\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Toggle rulers\"\r\n [checked]=\"rulers\"\r\n (change)=\"toggleRulers()\"\r\n >\r\n <mat-icon class=\"mat-primary\">straighten</mat-icon>\r\n </mat-button-toggle>\r\n <!-- run to last -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"primary\"\r\n matTooltip=\"Refresh preview\"\r\n (click)=\"runToLast()\"\r\n >\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n </div>\r\n @if (visualInfo) {\r\n <div id=\"visual-info\">{{ visualInfo }}</div>\r\n }\r\n </fieldset>\r\n\r\n <!-- chain view -->\r\n @if (chain) {\r\n <div id=\"chain-view\">\r\n <gve-chain-view [chain]=\"chain\" />\r\n </div>\r\n }\r\n\r\n <!--buttons -->\r\n <div class=\"form-row-center\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave()) {\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save changes\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}.form-row .right{margin-left:auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}#text-range{margin:8px;border:1px solid silver;border-radius:6px;padding:6px}mat-expansion-panel{margin:8px 0}div#visual-info{font-size:95%;color:#909090;margin:8px}#list{margin:8px 0}#opStyle{margin-top:8px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#c8d9eb}tr.edited{background-color:#f6f6e4}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:#909090}.error{color:red}.input-nr{width:6em}.full-width{width:100%}.code{font-family:Courier New,Courier,monospace}.boxed{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}span.label{margin-left:8px}gve-animation-timeline-set{margin:8px 0}div#image{display:grid;gap:8px;grid-template-rows:auto;grid-template-columns:1fr auto;grid-template-areas:\"image-ctl image-view\"}div#image-ctl{grid-area:image-ctl}div#image-view{grid-area:image-view}div#chain-view{margin-bottom:8px}@media only screen and (max-width: 959px){div#image{grid-template-columns:1fr;grid-template-areas:\"image-ctl\" \"image-view\"}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "ngmodule", type: FormsModule }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "component", type: i8$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4$1.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: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.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: i14.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i15.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i15.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i16.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i16.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i16.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ChainOperationEditorComponent, selector: "gve-chain-operation-editor", inputs: ["operation", "snapshot", "hidePreview"], outputs: ["operationChange", "operationPreview", "operationCancel"] }, { kind: "component", type: ChainResultViewComponent, selector: "gve-chain-result-view", inputs: ["result", "initialStepIndex"], outputs: ["stepPick"] }, { kind: "component", type: BaseTextViewComponent, selector: "gve-base-text-view", inputs: ["defaultColor", "defaultBorderColor", "selectionColor", "hasLineNumber", "text", "borderColorCallback"], outputs: ["charPick", "rangePick"] }, { kind: "component", type: LnHeightsEditorComponent, selector: "gve-ln-heights-editor", inputs: ["lineCount", "heights"], outputs: ["heightsChange"] }, { kind: "component", type: AnimationTimelineSetComponent, selector: "gve-animation-timeline-set", inputs: ["timelines", "elementIds", "tags"], outputs: ["timelinesChange", "timelinesCancel"] }, { kind: "pipe", type: FlatLookupPipe, name: "flatLookup" }, { kind: "component", type: ChainViewComponent, selector: "gve-chain-view", inputs: ["chain", "direction", "selectedTags"], outputs: ["selectedTagsChange"] }] }); }
|
|
3730
3750
|
}
|
|
3731
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.
|
|
3751
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SnapshotEditorComponent, decorators: [{
|
|
3732
3752
|
type: Component,
|
|
3733
3753
|
args: [{ selector: 'gve-snapshot-editor', imports: [
|
|
3734
3754
|
CommonModule,
|
|
@@ -3748,25 +3768,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
3748
3768
|
MatTooltipModule,
|
|
3749
3769
|
ChainOperationEditorComponent,
|
|
3750
3770
|
ChainResultViewComponent,
|
|
3771
|
+
BaseTextViewComponent,
|
|
3751
3772
|
LnHeightsEditorComponent,
|
|
3752
3773
|
AnimationTimelineSetComponent,
|
|
3753
3774
|
FlatLookupPipe,
|
|
3754
|
-
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- text -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>article</mat-icon> <span class=\"label\">text</span>\r\n </ng-template>\r\n <mat-expansion-panel>\r\n <mat-expansion-panel-header>\r\n <mat-panel-title> base text </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <!-- base text -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"mat-warn\"\r\n matTooltip=\"Enter base text\"\r\n (click)=\"inputBaseText()\"\r\n [disabled]=\"busy\"\r\n >\r\n <mat-icon>edit</mat-icon> base text\r\n </button>\r\n <!-- base text metadata -->\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- offsetX -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetX\"\r\n placeholder=\"X offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- offsetY -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetY\"\r\n placeholder=\"Y offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- lineHeightOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>ln h-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"lineHeightOffset\"\r\n placeholder=\"ln h-offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- charSpacingOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>char spacing</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"charSpacingOffset\"\r\n placeholder=\"char spacing\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- spcWidthOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>spc w-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"spcWidthOffset\"\r\n placeholder=\"spc w-offset\"\r\n />\r\n </mat-form-field>\r\n <!-- minLineHeights -->\r\n <div class=\"boxed\">\r\n <gve-ln-heights-editor\r\n [lineCount]=\"lineCount\"\r\n [heights]=\"lnHeights.value\"\r\n (heightsChange)=\"onHeightsChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n <!-- textStyle -->\r\n <div>\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>text style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"textStyle\"\r\n placeholder=\"text style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </fieldset>\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- operations -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>edit</mat-icon> <span class=\"label\">operations</span>\r\n </ng-template>\r\n\r\n <div id=\"snapshot-container\">\r\n <div id=\"general\">\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"width\"\r\n placeholder=\"width\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"height\"\r\n placeholder=\"height\"\r\n />\r\n </mat-form-field>\r\n\r\n <div class=\"form-row right\">\r\n <!-- remove ops -->\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Remove all the operations\"\r\n [disabled]=\"!operations.value.length || busy\"\r\n (click)=\"clearOperations()\"\r\n >\r\n <mat-icon>delete_forever</mat-icon> clear\r\n </button>\r\n\r\n <!-- batch add ops -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n matTooltip=\"Add a batch of operations\"\r\n class=\"mat-primary\"\r\n [disabled]=\"busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n <mat-icon>post_add</mat-icon> batch\r\n </button>\r\n\r\n <!-- add op -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n [disabled]=\"!baseText.value\"\r\n (click)=\"editNewOperation()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> operation\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ops -->\r\n <div id=\"ops\">\r\n <!-- operations list -->\r\n @if (operations.value.length) {\r\n <table id=\"list\">\r\n <thead>\r\n <tr>\r\n <th>nr.</th>\r\n <th></th>\r\n <th>ID</th>\r\n <th>type</th>\r\n <th>at</th>\r\n <th>run</th>\r\n <th>value</th>\r\n <th>itag</th>\r\n <th>otag</th>\r\n <th>gid</th>\r\n <th>feats</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (operation of operations.value; track operation.id; let\r\n index=$index) {\r\n <tr\r\n [ngClass]=\"{ selected: operation.id === resultOperationId }\"\r\n [ngClass]=\"{ edited: operation.id === editedOp?.id }\"\r\n >\r\n <td class=\"fit-width\">{{ index + 1 }}.</td>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-primary\"\r\n (click)=\"editOperation(index)\"\r\n matTooltip=\"Edit operation\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n (click)=\"deleteOperation(index)\"\r\n matTooltip=\"Delete operation\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <!-- run to -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-accent\"\r\n (click)=\"runTo(index)\"\r\n matTooltip=\"Run to this operation\"\r\n >\r\n <mat-icon class=\"mat-accent\">subscriptions</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ operation.id }}</td>\r\n <td>{{ operation.type | flatLookup : opTypeMap }}</td>\r\n <td>{{ operation.at }}</td>\r\n <td>{{ operation.run }}</td>\r\n <td>{{ operation.value }}</td>\r\n <td>{{ operation.inputTag }}</td>\r\n <td>{{ operation.outputTag }}</td>\r\n <td>{{ operation.groupId }}</td>\r\n <td>{{ operation.features?.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- operation editor -->\r\n <mat-expansion-panel [expanded]=\"editedOp\" [disabled]=\"!editedOp\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>operation {{ editedOp?.id }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset>\r\n <gve-chain-operation-editor\r\n [hidePreview]=\"editedOpIndex === -1\"\r\n [operation]=\"editedOp\"\r\n (operationCancel)=\"onOperationCancel()\"\r\n (operationChange)=\"onOperationChange($event)\"\r\n (operationPreview)=\"onOperationPreview($event)\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- opStyle -->\r\n <div id=\"opStyle\">\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>operations style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"opStyle\"\r\n placeholder=\"operations style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- image -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>image</mat-icon> <span class=\"label\">image</span>\r\n </ng-template>\r\n\r\n <div id=\"image\">\r\n <div id=\"image-ctl\">\r\n <!-- url -->\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>URL</mat-label>\r\n <input matInput [formControl]=\"imageUrl\" />\r\n </mat-form-field>\r\n <div class=\"form-row\">\r\n <!-- x -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageX\"\r\n placeholder=\"X\"\r\n />\r\n </mat-form-field>\r\n <!-- y -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageY\"\r\n placeholder=\"Y\"\r\n />\r\n </mat-form-field>\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageWidth\"\r\n />\r\n </mat-form-field>\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageHeight\"\r\n />\r\n </mat-form-field>\r\n <!-- reset -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset image metadata\"\r\n (click)=\"resetImgMetadata()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n </div>\r\n <div>\r\n <!-- image opacity -->\r\n <mat-slider\r\n min=\"0\"\r\n max=\"1\"\r\n step=\"0.01\"\r\n thumbLabel\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n matTooltip=\"Image opacity\"\r\n >\r\n <input\r\n matSliderThumb\r\n [value]=\"imageOpacity.value\"\r\n (valueChange)=\"onImageOpacityChange($event)\"\r\n />\r\n </mat-slider>\r\n <span id=\"opacity-value\">{{\r\n imageOpacity.value | number : \"1.2-2\"\r\n }}</span>\r\n </div>\r\n <!-- defs -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>defs</mat-label>\r\n <textarea matInput [formControl]=\"defs\" rows=\"3\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div id=\"image-view\">\r\n @if (imageUrl.value) {\r\n <img\r\n #imgElement\r\n alt=\"background\"\r\n [src]=\"imageUrl.value\"\r\n width=\"600\"\r\n (load)=\"onImageLoad(imgElement)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- timelines -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>animation</mat-icon> <span class=\"label\">animation</span>\r\n </ng-template>\r\n\r\n <gve-animation-timeline-set\r\n [tags]=\"opTags\"\r\n [elementIds]=\"opElementIds\"\r\n [timelines]=\"timelines.value\"\r\n (timelinesChange)=\"onTimelinesChange($event)\"\r\n />\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- progress -->\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\" *ngIf=\"busy\" />\r\n </div>\r\n\r\n <!-- result -->\r\n @if (result) {\r\n <fieldset id=\"result\">\r\n <legend>result</legend>\r\n <gve-chain-result-view\r\n [result]=\"result\"\r\n [initialStepIndex]=\"initialStepIndex\"\r\n (stepPick)=\"onStepPick($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- snapshot view -->\r\n <fieldset id=\"preview\">\r\n <legend class=\"button-row\">\r\n <span>{{ viewTitle }}</span>\r\n </legend>\r\n <!-- snapshot view -->\r\n <gve-snapshot-view\r\n #snapshotView\r\n [debug]=\"debug\"\r\n [data]=\"viewData\"\r\n (snapshotRender)=\"onSnapshotRender($any($event))\"\r\n (visualEvent)=\"onVisualEvent($any($event))\"\r\n />\r\n <div class=\"button-row\">\r\n <!-- toggle ruler -->\r\n <mat-button-toggle\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Toggle rulers\"\r\n [checked]=\"rulers\"\r\n (change)=\"toggleRulers()\"\r\n >\r\n <mat-icon class=\"mat-primary\">straighten</mat-icon>\r\n </mat-button-toggle>\r\n <!-- run to last -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"primary\"\r\n matTooltip=\"Refresh preview\"\r\n (click)=\"runToLast()\"\r\n >\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n </div>\r\n @if (visualInfo) {\r\n <div id=\"visual-info\">{{ visualInfo }}</div>\r\n }\r\n </fieldset>\r\n\r\n <!--buttons -->\r\n <div class=\"form-row-center\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave) {\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save changes\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}.form-row .right{margin-left:auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}#text-range{margin:8px;border:1px solid silver;border-radius:6px;padding:6px}mat-expansion-panel{margin:8px 0}div#visual-info{font-size:95%;color:#909090;margin:8px}#list{margin:8px 0}#opStyle{margin-top:8px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#c8d9eb}tr.edited{background-color:#f6f6e4}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:#909090}.error{color:red}.input-nr{width:6em}.full-width{width:100%}.code{font-family:Courier New,Courier,monospace}.boxed{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}span.label{margin-left:8px}gve-animation-timeline-set{margin:8px 0}div#image{display:grid;gap:8px;grid-template-rows:auto;grid-template-columns:1fr auto;grid-template-areas:\"image-ctl image-view\"}div#image-ctl{grid-area:image-ctl}div#image-view{grid-area:image-view}@media only screen and (max-width: 959px){div#image{grid-template-columns:1fr;grid-template-areas:\"image-ctl\" \"image-view\"}}\n"] }]
|
|
3755
|
-
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: GveApiService }, { type: i3$1.MatDialog }, { type: i2$1.DialogService }, { type: i5$2.MatSnackBar }], propDecorators: { snapshotView: [{
|
|
3775
|
+
ChainViewComponent,
|
|
3776
|
+
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- text -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>article</mat-icon> <span class=\"label\">text</span>\r\n </ng-template>\r\n <mat-expansion-panel>\r\n <mat-expansion-panel-header>\r\n <mat-panel-title> base text </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <!-- base text -->\r\n <div class=\"form-row\">\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n color=\"mat-warn\"\r\n matTooltip=\"Enter base text\"\r\n (click)=\"inputBaseText()\"\r\n [disabled]=\"busy\"\r\n >\r\n <mat-icon>edit</mat-icon> base text\r\n </button>\r\n\r\n @if (textRange) {\r\n <span id=\"text-range\">{{ textRange.at }}\u00D7{{ textRange.run }}</span>\r\n }\r\n </div>\r\n <!-- base text metadata -->\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- offsetX -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetX\"\r\n placeholder=\"X offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- offsetY -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"offsetY\"\r\n placeholder=\"Y offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- lineHeightOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>ln h-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"lineHeightOffset\"\r\n placeholder=\"ln h-offset\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- charSpacingOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>char spacing</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"charSpacingOffset\"\r\n placeholder=\"char spacing\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- spcWidthOffset -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>spc w-offset</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"spcWidthOffset\"\r\n placeholder=\"spc w-offset\"\r\n />\r\n </mat-form-field>\r\n <!-- minLineHeights -->\r\n <div class=\"boxed\">\r\n <gve-ln-heights-editor\r\n [lineCount]=\"lineCount\"\r\n [heights]=\"lnHeights.value || undefined\"\r\n (heightsChange)=\"onHeightsChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n <!-- textStyle -->\r\n <div>\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>text style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"textStyle\"\r\n placeholder=\"text style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </fieldset>\r\n <!-- text characters -->\r\n <gve-base-text-view\r\n [text]=\"baseText.value\"\r\n [hasLineNumber]=\"true\"\r\n (rangePick)=\"onRangePick($event)\"\r\n />\r\n </mat-expansion-panel>\r\n </mat-tab>\r\n\r\n <!-- operations -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>edit</mat-icon> <span class=\"label\">operations</span>\r\n </ng-template>\r\n\r\n <div id=\"snapshot-container\">\r\n <div id=\"general\">\r\n <div class=\"form-row\">\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"width\"\r\n placeholder=\"width\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"height\"\r\n placeholder=\"height\"\r\n />\r\n </mat-form-field>\r\n\r\n <!-- chain -->\r\n <mat-checkbox [formControl]=\"showChain\">show chain</mat-checkbox>\r\n\r\n <div class=\"form-row right\">\r\n <!-- remove ops -->\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Remove all the operations\"\r\n [disabled]=\"!operations.value.length || busy\"\r\n (click)=\"clearOperations()\"\r\n >\r\n <mat-icon>delete_forever</mat-icon> clear\r\n </button>\r\n\r\n <!-- batch add ops -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n matTooltip=\"Add a batch of operations\"\r\n class=\"mat-primary\"\r\n [disabled]=\"busy\"\r\n (click)=\"parseOperations()\"\r\n >\r\n <mat-icon>post_add</mat-icon> batch\r\n </button>\r\n\r\n <!-- add op -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n [disabled]=\"!baseText.value\"\r\n (click)=\"editNewOperation()\"\r\n >\r\n <mat-icon>add_circle</mat-icon> operation\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ops -->\r\n <div id=\"ops\">\r\n <!-- operations list -->\r\n @if (operations.value.length) {\r\n <table id=\"list\">\r\n <thead>\r\n <tr>\r\n <th>nr.</th>\r\n <th></th>\r\n <th>ID</th>\r\n <th>type</th>\r\n <th>at</th>\r\n <th>run</th>\r\n <th>value</th>\r\n <th>itag</th>\r\n <th>otag</th>\r\n <th>gid</th>\r\n <th>feats</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (operation of operations.value; track operation.id; let\r\n index=$index) {\r\n <tr\r\n [ngClass]=\"{ selected: operation.id === resultOperationId }\"\r\n [ngClass]=\"{ edited: operation.id === editedOp?.id }\"\r\n >\r\n <td class=\"fit-width\">{{ index + 1 }}.</td>\r\n <td class=\"fit-width\">\r\n <!-- edit -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-primary\"\r\n (click)=\"editOperation(index)\"\r\n matTooltip=\"Edit operation\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <!-- delete -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-warn\"\r\n (click)=\"deleteOperation(index)\"\r\n matTooltip=\"Delete operation\"\r\n >\r\n <mat-icon class=\"mat-warn\">delete</mat-icon>\r\n </button>\r\n <!-- run to -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"mat-accent\"\r\n (click)=\"runTo(index)\"\r\n matTooltip=\"Run to this operation\"\r\n >\r\n <mat-icon class=\"mat-accent\">subscriptions</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ operation.id }}</td>\r\n <td>{{ operation.type | flatLookup : opTypeMap }}</td>\r\n <td>{{ operation.at }}</td>\r\n <td>{{ operation.run }}</td>\r\n <td>{{ operation.value }}</td>\r\n <td>{{ operation.inputTag }}</td>\r\n <td>{{ operation.outputTag }}</td>\r\n <td>{{ operation.groupId }}</td>\r\n <td>{{ operation.features?.length }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <!-- operation editor -->\r\n <mat-expansion-panel [expanded]=\"editedOp\" [disabled]=\"!editedOp\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>operation {{ editedOp?.id }}</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <fieldset>\r\n <gve-chain-operation-editor\r\n [hidePreview]=\"editedOpIndex === -1\"\r\n [operation]=\"editedOp\"\r\n (operationCancel)=\"onOperationCancel()\"\r\n (operationChange)=\"onOperationChange($event)\"\r\n (operationPreview)=\"onOperationPreview($event)\"\r\n />\r\n </fieldset>\r\n </mat-expansion-panel>\r\n\r\n <!-- opStyle -->\r\n <div id=\"opStyle\">\r\n <mat-form-field class=\"long-text\" appearance=\"outline\">\r\n <mat-label>operations style</mat-label>\r\n <textarea\r\n matInput\r\n [formControl]=\"opStyle\"\r\n placeholder=\"operations style\"\r\n ></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- image -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>image</mat-icon> <span class=\"label\">image</span>\r\n </ng-template>\r\n\r\n <div id=\"image\">\r\n <div id=\"image-ctl\">\r\n <!-- url -->\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>URL</mat-label>\r\n <input matInput [formControl]=\"imageUrl\" />\r\n </mat-form-field>\r\n <div class=\"form-row\">\r\n <!-- x -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>X</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageX\"\r\n placeholder=\"X\"\r\n />\r\n </mat-form-field>\r\n <!-- y -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>Y</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [formControl]=\"imageY\"\r\n placeholder=\"Y\"\r\n />\r\n </mat-form-field>\r\n <!-- width -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>width</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageWidth\"\r\n />\r\n </mat-form-field>\r\n <!-- height -->\r\n <mat-form-field class=\"input-nr\">\r\n <mat-label>height</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n min=\"0\"\r\n [formControl]=\"imageHeight\"\r\n />\r\n </mat-form-field>\r\n <!-- reset -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Reset image metadata\"\r\n (click)=\"resetImgMetadata()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </div>\r\n <div>\r\n <!-- image opacity -->\r\n <mat-slider\r\n min=\"0\"\r\n max=\"1\"\r\n step=\"0.01\"\r\n thumbLabel\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n matTooltip=\"Image opacity\"\r\n >\r\n <input\r\n matSliderThumb\r\n [value]=\"imageOpacity.value\"\r\n (valueChange)=\"onImageOpacityChange($event)\"\r\n />\r\n </mat-slider>\r\n <span id=\"opacity-value\">{{\r\n imageOpacity.value | number : \"1.2-2\"\r\n }}</span>\r\n </div>\r\n <!-- defs -->\r\n <div>\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>defs</mat-label>\r\n <textarea matInput [formControl]=\"defs\" rows=\"3\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n <div id=\"image-view\">\r\n @if (imageUrl.value) {\r\n <img\r\n #imgElement\r\n alt=\"background\"\r\n [src]=\"imageUrl.value\"\r\n width=\"600\"\r\n (load)=\"onImageLoad(imgElement)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- timelines -->\r\n <mat-tab>\r\n <ng-template mat-tab-label>\r\n <mat-icon>animation</mat-icon> <span class=\"label\">animation</span>\r\n </ng-template>\r\n\r\n <gve-animation-timeline-set\r\n [tags]=\"opTags\"\r\n [elementIds]=\"opElementIds\"\r\n [timelines]=\"timelines.value\"\r\n (timelinesChange)=\"onTimelinesChange($event)\"\r\n />\r\n </mat-tab>\r\n </mat-tab-group>\r\n\r\n <!-- progress -->\r\n <div>\r\n <mat-progress-bar mode=\"indeterminate\" *ngIf=\"busy\" />\r\n </div>\r\n\r\n <!-- result -->\r\n @if (result) {\r\n <fieldset id=\"result\">\r\n <legend>result</legend>\r\n <gve-chain-result-view\r\n [result]=\"result\"\r\n [initialStepIndex]=\"initialStepIndex\"\r\n (stepPick)=\"onStepPick($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- snapshot view -->\r\n <fieldset id=\"preview\">\r\n <legend class=\"button-row\">\r\n <span>{{ viewTitle }}</span>\r\n </legend>\r\n <!-- snapshot view -->\r\n <gve-snapshot-view\r\n #snapshotView\r\n [debug]=\"debug()\"\r\n [data]=\"viewData\"\r\n (snapshotRender)=\"onSnapshotRender($any($event))\"\r\n (visualEvent)=\"onVisualEvent($any($event))\"\r\n />\r\n <div class=\"button-row\">\r\n <!-- toggle ruler -->\r\n <mat-button-toggle\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n matTooltip=\"Toggle rulers\"\r\n [checked]=\"rulers\"\r\n (change)=\"toggleRulers()\"\r\n >\r\n <mat-icon class=\"mat-primary\">straighten</mat-icon>\r\n </mat-button-toggle>\r\n <!-- run to last -->\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n class=\"primary\"\r\n matTooltip=\"Refresh preview\"\r\n (click)=\"runToLast()\"\r\n >\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n </div>\r\n @if (visualInfo) {\r\n <div id=\"visual-info\">{{ visualInfo }}</div>\r\n }\r\n </fieldset>\r\n\r\n <!-- chain view -->\r\n @if (chain) {\r\n <div id=\"chain-view\">\r\n <gve-chain-view [chain]=\"chain\" />\r\n </div>\r\n }\r\n\r\n <!--buttons -->\r\n <div class=\"form-row-center\">\r\n <button\r\n type=\"button\"\r\n class=\"mat-warn\"\r\n mat-flat-button\r\n matTooltip=\"Discard changes\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon>clear</mat-icon>\r\n close\r\n </button>\r\n @if (!noSave()) {\r\n <button\r\n type=\"submit\"\r\n class=\"mat-primary\"\r\n mat-flat-button\r\n matTooltip=\"Save changes\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon>check_circle</mat-icon>\r\n save\r\n </button>\r\n }\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row-center{display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap}.form-row,.form-row-center *{flex:0 0 auto}.form-row .right{margin-left:auto}.button-row{display:flex;align-items:center;flex-wrap:wrap}.button-row *{flex:0 0 auto}.long-text{width:100%;max-width:800px}#text-range{margin:8px;border:1px solid silver;border-radius:6px;padding:6px}mat-expansion-panel{margin:8px 0}div#visual-info{font-size:95%;color:#909090;margin:8px}#list{margin:8px 0}#opStyle{margin-top:8px}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#c8d9eb}tr.edited{background-color:#f6f6e4}fieldset{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}legend{color:#909090}.error{color:red}.input-nr{width:6em}.full-width{width:100%}.code{font-family:Courier New,Courier,monospace}.boxed{border:1px solid silver;border-radius:6px;padding:8px;margin:8px 0}span.label{margin-left:8px}gve-animation-timeline-set{margin:8px 0}div#image{display:grid;gap:8px;grid-template-rows:auto;grid-template-columns:1fr auto;grid-template-areas:\"image-ctl image-view\"}div#image-ctl{grid-area:image-ctl}div#image-view{grid-area:image-view}div#chain-view{margin-bottom:8px}@media only screen and (max-width: 959px){div#image{grid-template-columns:1fr;grid-template-areas:\"image-ctl\" \"image-view\"}}\n"] }]
|
|
3777
|
+
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: GveApiService }, { type: i3$1.MatDialog }, { type: i2$1.DialogService }, { type: i4$2.MatSnackBar }], propDecorators: { snapshotView: [{
|
|
3756
3778
|
type: ViewChild,
|
|
3757
3779
|
args: ['snapshotView', { static: false }]
|
|
3758
|
-
}], snapshot: [{
|
|
3759
|
-
type: Input
|
|
3760
|
-
}], batchOps: [{
|
|
3761
|
-
type: Input
|
|
3762
|
-
}], noSave: [{
|
|
3763
|
-
type: Input
|
|
3764
|
-
}], debug: [{
|
|
3765
|
-
type: Input
|
|
3766
|
-
}], snapshotChange: [{
|
|
3767
|
-
type: Output
|
|
3768
|
-
}], snapshotCancel: [{
|
|
3769
|
-
type: Output
|
|
3770
3780
|
}] } });
|
|
3771
3781
|
|
|
3772
3782
|
/*
|
|
@@ -3777,5 +3787,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
|
|
|
3777
3787
|
* Generated bundle index. Do not edit.
|
|
3778
3788
|
*/
|
|
3779
3789
|
|
|
3780
|
-
export { AnimationTimelineComponent, AnimationTweenComponent, BaseTextCharComponent, BaseTextEditorComponent, BaseTextViewComponent, BatchOperationEditorComponent, ChainOperationEditorComponent, ChainResultViewComponent, FeatureEditorComponent, FeatureSetEditorComponent, FeatureSetViewComponent, GveApiService, LnHeightsEditorComponent, OperationSourceEditorComponent, SettingsService,
|
|
3790
|
+
export { AnimationTimelineComponent, AnimationTweenComponent, BaseTextCharComponent, BaseTextEditorComponent, BaseTextViewComponent, BatchOperationEditorComponent, ChainOperationEditorComponent, ChainResultViewComponent, ChainViewComponent, FeatureEditorComponent, FeatureSetEditorComponent, FeatureSetViewComponent, GveApiService, GveGraphvizService, LnHeightsEditorComponent, OperationSourceEditorComponent, SettingsService, SnapshotEditorComponent, SnapshotTextEditorComponent, StepsMapComponent };
|
|
3781
3791
|
//# sourceMappingURL=myrmidon-gve-core.mjs.map
|