@myrmidon/cadmus-part-lexicography-word-senses 0.0.1

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.
@@ -0,0 +1,859 @@
1
+ import * as i9$2 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { model, output, input, effect, Inject, Optional, Component, signal } from '@angular/core';
5
+ import * as i1 from '@angular/forms';
6
+ import { Validators, ReactiveFormsModule } from '@angular/forms';
7
+ import * as i4 from '@angular/material/button';
8
+ import { MatButtonModule } from '@angular/material/button';
9
+ import { MatCheckboxModule } from '@angular/material/checkbox';
10
+ import * as i5 from '@angular/material/expansion';
11
+ import { MatExpansionModule } from '@angular/material/expansion';
12
+ import * as i5$1 from '@angular/material/form-field';
13
+ import { MatFormFieldModule } from '@angular/material/form-field';
14
+ import * as i7 from '@angular/material/icon';
15
+ import { MatIconModule } from '@angular/material/icon';
16
+ import * as i7$1 from '@angular/material/input';
17
+ import { MatInputModule } from '@angular/material/input';
18
+ import { MatSelectModule } from '@angular/material/select';
19
+ import * as i8 from '@angular/material/tooltip';
20
+ import { MatTooltipModule } from '@angular/material/tooltip';
21
+ import * as i9 from '@cisstech/nge/monaco';
22
+ import { NgeMonacoModule } from '@cisstech/nge/monaco';
23
+ import * as i10 from '@cisstech/nge/markdown';
24
+ import { NgeMarkdownModule } from '@cisstech/nge/markdown';
25
+ import { ThesEntriesPickerComponent, ModelEditorComponentBase, CloseSaveButtonsComponent } from '@myrmidon/cadmus-ui';
26
+ import * as i2 from '@myrmidon/cadmus-text-ed';
27
+ import { CADMUS_TEXT_ED_BINDINGS_TOKEN } from '@myrmidon/cadmus-text-ed';
28
+ import * as i9$1 from '@angular/material/tabs';
29
+ import { MatTabsModule } from '@angular/material/tabs';
30
+ import { EllipsisPipe, FlatLookupPipe, NgxToolsValidators, deepCopy } from '@myrmidon/ngx-tools';
31
+ import { AssertedCompositeIdsComponent } from '@myrmidon/cadmus-refs-asserted-ids';
32
+ import * as i2$1 from '@myrmidon/ngx-mat-tools';
33
+ import * as i5$2 from '@angular/material/card';
34
+ import { MatCardModule } from '@angular/material/card';
35
+ import * as i1$1 from '@myrmidon/auth-jwt-login';
36
+ import * as i4$1 from '@myrmidon/cadmus-state';
37
+ import { EditPartFeatureBase } from '@myrmidon/cadmus-state';
38
+ import { CurrentItemBarComponent } from '@myrmidon/cadmus-ui-pg';
39
+ import * as i1$2 from '@angular/router';
40
+ import * as i2$2 from '@angular/material/snack-bar';
41
+ import * as i3 from '@myrmidon/cadmus-api';
42
+
43
+ /**
44
+ * The type ID used to identify the LexWordSensesPart type.
45
+ */
46
+ const LEX_WORD_SENSES_PART_TYPEID = 'it.vedph.lexicography.word-senses';
47
+ /**
48
+ * JSON schema for the LexWordSenses part.
49
+ * You can use the JSON schema tool at https://jsonschema.net/.
50
+ */
51
+ const LEX_WORD_SENSES_PART_SCHEMA = {
52
+ $schema: 'http://json-schema.org/draft-07/schema#',
53
+ $id: 'www.vedph.it/cadmus/parts/lexicography/' + LEX_WORD_SENSES_PART_TYPEID + '.json',
54
+ type: 'object',
55
+ title: 'LexWordSensesPart',
56
+ required: [
57
+ 'id',
58
+ 'itemId',
59
+ 'typeId',
60
+ 'timeCreated',
61
+ 'creatorId',
62
+ 'timeModified',
63
+ 'userId',
64
+ 'senses',
65
+ ],
66
+ properties: {
67
+ timeCreated: {
68
+ type: 'string',
69
+ pattern: '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d+Z$',
70
+ },
71
+ creatorId: {
72
+ type: 'string',
73
+ },
74
+ timeModified: {
75
+ type: 'string',
76
+ pattern: '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d+Z$',
77
+ },
78
+ userId: {
79
+ type: 'string',
80
+ },
81
+ id: {
82
+ type: 'string',
83
+ pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
84
+ },
85
+ itemId: {
86
+ type: 'string',
87
+ pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
88
+ },
89
+ typeId: {
90
+ type: 'string',
91
+ pattern: '^[a-z][-0-9a-z._]*$',
92
+ },
93
+ roleId: {
94
+ type: ['string', 'null'],
95
+ pattern: '^([a-z][-0-9a-z._]*)?$',
96
+ },
97
+ senses: {
98
+ type: 'array',
99
+ minItems: 1,
100
+ items: {
101
+ type: 'object',
102
+ required: ['definition'],
103
+ properties: {
104
+ eid: {
105
+ type: 'string',
106
+ },
107
+ tags: {
108
+ type: 'array',
109
+ items: { type: 'string' },
110
+ },
111
+ definition: {
112
+ type: 'string',
113
+ },
114
+ note: {
115
+ type: 'string',
116
+ },
117
+ relatedIds: {
118
+ type: 'array',
119
+ items: {
120
+ type: 'object',
121
+ required: ['target'],
122
+ properties: {
123
+ // PinTarget
124
+ target: {
125
+ type: 'object',
126
+ required: ['gid', 'label'],
127
+ properties: {
128
+ gid: { type: 'string' },
129
+ label: { type: 'string' },
130
+ itemId: { type: 'string' },
131
+ partId: { type: 'string' },
132
+ partTypeId: { type: 'string' },
133
+ roleId: { type: 'string' },
134
+ name: { type: 'string' },
135
+ value: { type: 'string' },
136
+ },
137
+ additionalProperties: false,
138
+ },
139
+ tag: { type: 'string' },
140
+ scope: { type: 'string' },
141
+ // Assertion
142
+ assertion: {
143
+ type: 'object',
144
+ required: ['rank'],
145
+ properties: {
146
+ tag: { type: 'string' },
147
+ rank: { type: 'number' },
148
+ note: { type: 'string' },
149
+ references: {
150
+ type: 'array',
151
+ items: {
152
+ type: 'object',
153
+ required: ['citation'],
154
+ properties: {
155
+ type: { type: 'string' },
156
+ tag: { type: 'string' },
157
+ citation: { type: 'string' },
158
+ note: { type: 'string' },
159
+ },
160
+ additionalProperties: false,
161
+ },
162
+ },
163
+ },
164
+ additionalProperties: false,
165
+ },
166
+ },
167
+ additionalProperties: false,
168
+ },
169
+ },
170
+ },
171
+ additionalProperties: false,
172
+ },
173
+ },
174
+ },
175
+ };
176
+
177
+ class WordSenseExampleEditor {
178
+ _editService;
179
+ _editorBindings;
180
+ // Monaco
181
+ _disposables = [];
182
+ _textModel;
183
+ _textEditor;
184
+ _explanationModel;
185
+ _explanationEditor;
186
+ example = model(...(ngDevMode ? [undefined, { debugName: "example" }] : []));
187
+ cancelEdit = output();
188
+ // lex-word-sense-tags
189
+ tagEntries = input(...(ngDevMode ? [undefined, { debugName: "tagEntries" }] : []));
190
+ tags;
191
+ citation;
192
+ text;
193
+ explanation;
194
+ note;
195
+ form;
196
+ constructor(formBuilder, _editService, _editorBindings) {
197
+ this._editService = _editService;
198
+ this._editorBindings = _editorBindings;
199
+ // form
200
+ this.tags = formBuilder.control([], { nonNullable: true });
201
+ this.citation = formBuilder.control(null, {
202
+ nonNullable: true,
203
+ validators: Validators.maxLength(500),
204
+ });
205
+ this.text = formBuilder.control('', {
206
+ nonNullable: true,
207
+ validators: [Validators.required, Validators.maxLength(1000)],
208
+ });
209
+ this.explanation = formBuilder.control(null, {
210
+ nonNullable: true,
211
+ validators: Validators.maxLength(1000),
212
+ });
213
+ this.note = formBuilder.control(null, {
214
+ nonNullable: true,
215
+ validators: Validators.maxLength(1000),
216
+ });
217
+ this.form = formBuilder.group({
218
+ tags: this.tags,
219
+ citation: this.citation,
220
+ text: this.text,
221
+ explanation: this.explanation,
222
+ note: this.note,
223
+ });
224
+ // when model changes, update form
225
+ effect(() => {
226
+ const data = this.example();
227
+ this.updateForm(data);
228
+ });
229
+ }
230
+ ngOnDestroy() {
231
+ this._disposables.forEach((d) => d.dispose());
232
+ }
233
+ async applyEdit(selector, editor) {
234
+ if (!editor) {
235
+ return;
236
+ }
237
+ const selection = editor.getSelection();
238
+ const text = selection ? editor.getModel().getValueInRange(selection) : '';
239
+ const result = await this._editService.edit({
240
+ selector,
241
+ text: text,
242
+ });
243
+ editor.executeEdits('my-source', [
244
+ {
245
+ range: selection,
246
+ text: result.text,
247
+ forceMoveMarkers: true,
248
+ },
249
+ ]);
250
+ }
251
+ onCreateTextEditor(editor) {
252
+ editor.updateOptions({
253
+ minimap: {
254
+ side: 'right',
255
+ },
256
+ wordWrap: 'on',
257
+ automaticLayout: true,
258
+ });
259
+ this._textModel =
260
+ this._textModel || monaco.editor.createModel(this.text?.value || '', 'markdown');
261
+ editor.setModel(this._textModel);
262
+ this._textEditor = editor;
263
+ this._disposables.push(this._textModel.onDidChangeContent((e) => {
264
+ this.text.setValue(this._textModel.getValue());
265
+ this.text.markAsDirty();
266
+ this.text.updateValueAndValidity();
267
+ }));
268
+ // plugins
269
+ if (this._editorBindings) {
270
+ Object.keys(this._editorBindings).forEach((key) => {
271
+ const n = parseInt(key, 10);
272
+ console.log('Binding ' + n + ' to ' + this._editorBindings[key]);
273
+ this._textEditor.addCommand(n, () => {
274
+ this.applyEdit(this._editorBindings[key], this._textEditor);
275
+ });
276
+ });
277
+ }
278
+ }
279
+ onCreateExplanationEditor(editor) {
280
+ editor.updateOptions({
281
+ minimap: {
282
+ enabled: false,
283
+ },
284
+ wordWrap: 'on',
285
+ automaticLayout: true,
286
+ });
287
+ this._explanationModel =
288
+ this._explanationModel ||
289
+ monaco.editor.createModel(this.explanation?.value || '', 'markdown');
290
+ editor.setModel(this._explanationModel);
291
+ this._explanationEditor = editor;
292
+ this._disposables.push(this._explanationModel.onDidChangeContent((e) => {
293
+ this.explanation.setValue(this._explanationModel.getValue());
294
+ this.explanation.markAsDirty();
295
+ this.explanation.updateValueAndValidity();
296
+ }));
297
+ // plugins
298
+ if (this._editorBindings) {
299
+ Object.keys(this._editorBindings).forEach((key) => {
300
+ const n = parseInt(key, 10);
301
+ console.log('Binding ' + n + ' to ' + this._editorBindings[key]);
302
+ this._explanationEditor.addCommand(n, () => {
303
+ this.applyEdit(this._editorBindings[key], this._explanationEditor);
304
+ });
305
+ });
306
+ }
307
+ }
308
+ mapIdToEntry(id, entries) {
309
+ if (!id)
310
+ return null;
311
+ if (!entries)
312
+ return { id, value: id };
313
+ return entries.find((e) => e.id === id) || { id, value: id };
314
+ }
315
+ mapIdToEntries(ids, entries) {
316
+ if (!entries)
317
+ return ids.map((id) => ({ id, value: id }));
318
+ return ids.map((id) => entries.find((e) => e.id === id) || { id, value: id });
319
+ }
320
+ updateForm(example) {
321
+ if (!example) {
322
+ this.form.reset();
323
+ }
324
+ else {
325
+ this.tags.setValue(this.mapIdToEntries(example.tags || [], this.tagEntries()));
326
+ this.citation.setValue(example.citation || null);
327
+ this._textModel?.setValue(example.text || '');
328
+ this._explanationModel?.setValue(example.explanation || '');
329
+ this.note.setValue(example.note || null);
330
+ this.form.markAsPristine();
331
+ }
332
+ }
333
+ getExample() {
334
+ return {
335
+ tags: this.tags.value?.length ? this.tags.value.map((e) => e.id) : undefined,
336
+ citation: this.citation.value?.trim() || undefined,
337
+ text: this.text.value?.trim() || '',
338
+ explanation: this.explanation.value?.trim() || undefined,
339
+ note: this.note.value?.trim() || undefined,
340
+ };
341
+ }
342
+ cancel() {
343
+ this.cancelEdit.emit();
344
+ }
345
+ /**
346
+ * Saves the current form data by updating the example model signal.
347
+ * This method can be called manually (e.g., by a Save button) or
348
+ * automatically (via auto-save).
349
+ * @param pristine If true (default), the form is marked as pristine
350
+ * after saving.
351
+ * Set to false for auto-save if you want the form to remain dirty.
352
+ */
353
+ save(pristine = true) {
354
+ if (this.form.invalid) {
355
+ // show validation errors
356
+ this.form.markAllAsTouched();
357
+ return;
358
+ }
359
+ const example = this.getExample();
360
+ this.example.set(example);
361
+ if (pristine) {
362
+ this.form.markAsPristine();
363
+ }
364
+ }
365
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: WordSenseExampleEditor, deps: [{ token: i1.FormBuilder }, { token: i2.CadmusTextEdService }, { token: CADMUS_TEXT_ED_BINDINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Component });
366
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: WordSenseExampleEditor, isStandalone: true, selector: "cadmus-word-sense-example-editor", inputs: { example: { classPropertyName: "example", publicName: "example", isSignal: true, isRequired: false, transformFunction: null }, tagEntries: { classPropertyName: "tagEntries", publicName: "tagEntries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { example: "exampleChange", cancelEdit: "cancelEdit" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- tags -->\r\n @if (tagEntries()?.length) {\r\n <div>\r\n <cadmus-thes-entries-picker\r\n [availableEntries]=\"tagEntries()!\"\r\n [entries]=\"tags.value\"\r\n [hierarchicLabels]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- citation -->\r\n <mat-form-field>\r\n <mat-label>citation</mat-label>\r\n <input matInput [formControl]=\"citation\" />\r\n @if ($any(citation).errors?.maxLength && (citation.dirty || citation.touched)) {\r\n <mat-error>citation too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n </div>\r\n\r\n <!-- text-->\r\n <div id=\"txt-container\" class=\"mt\">\r\n <div id=\"txt\">\r\n <nge-monaco-editor id=\"txt-editor\" (ready)=\"onCreateTextEditor($event)\" />\r\n @if (text.hasError('required') && (text.touched || text.dirty)) {\r\n <mat-error>text required</mat-error>\r\n } @if (text.hasError('maxLength') && (text.touched || text.dirty)) {\r\n <mat-error>text too long</mat-error>\r\n }\r\n </div>\r\n <!-- preview -->\r\n <div id=\"txt-preview\">\r\n <mat-expansion-panel expanded=\"true\">\r\n <div>\r\n <nge-markdown [data]=\"text.value || undefined\" />\r\n </div>\r\n </mat-expansion-panel>\r\n </div>\r\n </div>\r\n\r\n <!-- explanation -->\r\n <div id=\"exp-container\" class=\"mt\">\r\n <div id=\"exp\">\r\n <nge-monaco-editor id=\"exp-editor\" (ready)=\"onCreateExplanationEditor($event)\" />\r\n @if ($any(explanation).errors?.maxLength && (explanation.dirty || explanation.touched)) {\r\n <mat-error>explanation too long</mat-error>\r\n }\r\n </div>\r\n <!-- preview -->\r\n <div id=\"exp-preview\">\r\n <mat-expansion-panel expanded=\"true\">\r\n <div>\r\n <nge-markdown [data]=\"explanation.value || undefined\" />\r\n </div>\r\n </mat-expansion-panel>\r\n </div>\r\n </div>\r\n\r\n <!-- note -->\r\n <div class=\"mt\">\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput rows=\"3\" [formControl]=\"note\"></textarea>\r\n @if ($any(note).errors?.maxLength && (note.dirty || note.touched)) {\r\n <mat-error>note too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- buttons -->\r\n <div>\r\n <button type=\"button\" mat-icon-button matTooltip=\"Discard changes\" (click)=\"cancel()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Accept changes\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n</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}fieldset{border:1px solid silver;border-radius:6px;padding:6px}legend{color:silver}#txt-editor,#exp-editor{height:300px}.mt{margin-top:16px}#txt-container{display:grid;grid-template-rows:auto;grid-template-columns:1fr 1fr;grid-template-areas:\"txt preview\";gap:8px}#txt{grid-area:txt}#txt-preview{grid-area:preview}@media only screen and (max-width: 959px){#txt-container{grid-template-columns:1fr;grid-template-rows:auto auto;grid-template-areas:\"txt\" \"preview\"}}#exp-container{display:grid;grid-template-rows:auto;grid-template-columns:1fr 1fr;grid-template-areas:\"exp exp-preview\";gap:8px}#exp{grid-area:exp}#exp-preview{grid-area:exp-preview}@media only screen and (max-width: 959px){#exp-container{grid-template-columns:1fr;grid-template-rows:auto auto;grid-template-areas:\"exp\" \"exp-preview\"}}\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.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: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i5.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: NgeMonacoModule }, { kind: "component", type: i9.NgeMonacoEditorComponent, selector: "nge-monaco-editor", inputs: ["autoLayout", "options"], outputs: ["ready"] }, { kind: "ngmodule", type: NgeMarkdownModule }, { kind: "component", type: i10.NgeMarkdownComponent, selector: "nge-markdown, [nge-markdown]", inputs: ["file", "data", "theme"], outputs: ["render"] }, { kind: "component", type: ThesEntriesPickerComponent, selector: "cadmus-thes-entries-picker", inputs: ["availableEntries", "entries", "hierarchicLabels", "autoSort", "allowCustom", "minEntries", "maxEntries", "expanded", "emptyMessage"], outputs: ["entriesChange", "expandedChange"] }] });
367
+ }
368
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: WordSenseExampleEditor, decorators: [{
369
+ type: Component,
370
+ args: [{ selector: 'cadmus-word-sense-example-editor', imports: [
371
+ CommonModule,
372
+ ReactiveFormsModule,
373
+ MatButtonModule,
374
+ MatCheckboxModule,
375
+ MatExpansionModule,
376
+ MatFormFieldModule,
377
+ MatIconModule,
378
+ MatInputModule,
379
+ MatSelectModule,
380
+ MatTooltipModule,
381
+ NgeMonacoModule,
382
+ NgeMarkdownModule,
383
+ ThesEntriesPickerComponent,
384
+ ], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- tags -->\r\n @if (tagEntries()?.length) {\r\n <div>\r\n <cadmus-thes-entries-picker\r\n [availableEntries]=\"tagEntries()!\"\r\n [entries]=\"tags.value\"\r\n [hierarchicLabels]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- citation -->\r\n <mat-form-field>\r\n <mat-label>citation</mat-label>\r\n <input matInput [formControl]=\"citation\" />\r\n @if ($any(citation).errors?.maxLength && (citation.dirty || citation.touched)) {\r\n <mat-error>citation too long</mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n </div>\r\n\r\n <!-- text-->\r\n <div id=\"txt-container\" class=\"mt\">\r\n <div id=\"txt\">\r\n <nge-monaco-editor id=\"txt-editor\" (ready)=\"onCreateTextEditor($event)\" />\r\n @if (text.hasError('required') && (text.touched || text.dirty)) {\r\n <mat-error>text required</mat-error>\r\n } @if (text.hasError('maxLength') && (text.touched || text.dirty)) {\r\n <mat-error>text too long</mat-error>\r\n }\r\n </div>\r\n <!-- preview -->\r\n <div id=\"txt-preview\">\r\n <mat-expansion-panel expanded=\"true\">\r\n <div>\r\n <nge-markdown [data]=\"text.value || undefined\" />\r\n </div>\r\n </mat-expansion-panel>\r\n </div>\r\n </div>\r\n\r\n <!-- explanation -->\r\n <div id=\"exp-container\" class=\"mt\">\r\n <div id=\"exp\">\r\n <nge-monaco-editor id=\"exp-editor\" (ready)=\"onCreateExplanationEditor($event)\" />\r\n @if ($any(explanation).errors?.maxLength && (explanation.dirty || explanation.touched)) {\r\n <mat-error>explanation too long</mat-error>\r\n }\r\n </div>\r\n <!-- preview -->\r\n <div id=\"exp-preview\">\r\n <mat-expansion-panel expanded=\"true\">\r\n <div>\r\n <nge-markdown [data]=\"explanation.value || undefined\" />\r\n </div>\r\n </mat-expansion-panel>\r\n </div>\r\n </div>\r\n\r\n <!-- note -->\r\n <div class=\"mt\">\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput rows=\"3\" [formControl]=\"note\"></textarea>\r\n @if ($any(note).errors?.maxLength && (note.dirty || note.touched)) {\r\n <mat-error>note too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- buttons -->\r\n <div>\r\n <button type=\"button\" mat-icon-button matTooltip=\"Discard changes\" (click)=\"cancel()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Accept changes\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n</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}fieldset{border:1px solid silver;border-radius:6px;padding:6px}legend{color:silver}#txt-editor,#exp-editor{height:300px}.mt{margin-top:16px}#txt-container{display:grid;grid-template-rows:auto;grid-template-columns:1fr 1fr;grid-template-areas:\"txt preview\";gap:8px}#txt{grid-area:txt}#txt-preview{grid-area:preview}@media only screen and (max-width: 959px){#txt-container{grid-template-columns:1fr;grid-template-rows:auto auto;grid-template-areas:\"txt\" \"preview\"}}#exp-container{display:grid;grid-template-rows:auto;grid-template-columns:1fr 1fr;grid-template-areas:\"exp exp-preview\";gap:8px}#exp{grid-area:exp}#exp-preview{grid-area:exp-preview}@media only screen and (max-width: 959px){#exp-container{grid-template-columns:1fr;grid-template-rows:auto auto;grid-template-areas:\"exp\" \"exp-preview\"}}\n"] }]
385
+ }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.CadmusTextEdService }, { type: undefined, decorators: [{
386
+ type: Inject,
387
+ args: [CADMUS_TEXT_ED_BINDINGS_TOKEN]
388
+ }, {
389
+ type: Optional
390
+ }] }], propDecorators: { example: [{ type: i0.Input, args: [{ isSignal: true, alias: "example", required: false }] }, { type: i0.Output, args: ["exampleChange"] }], cancelEdit: [{ type: i0.Output, args: ["cancelEdit"] }], tagEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagEntries", required: false }] }] } });
391
+
392
+ class WordSenseEditor {
393
+ _dialogService;
394
+ _editService;
395
+ _editorBindings;
396
+ // Monaco
397
+ _disposables = [];
398
+ _definitionModel;
399
+ _definitionEditor;
400
+ sense = model(...(ngDevMode ? [undefined, { debugName: "sense" }] : []));
401
+ cancelEdit = output();
402
+ editedEx = signal(undefined, ...(ngDevMode ? [{ debugName: "editedEx" }] : []));
403
+ editedExIndex = signal(-1, ...(ngDevMode ? [{ debugName: "editedExIndex" }] : []));
404
+ // lex-word-sense-tags
405
+ tagEntries = input(...(ngDevMode ? [undefined, { debugName: "tagEntries" }] : []));
406
+ // asserted-id-scopes
407
+ assIdScopeEntries = input(...(ngDevMode ? [undefined, { debugName: "assIdScopeEntries" }] : []));
408
+ // asserted-id-tags
409
+ assIdTagEntries = input(...(ngDevMode ? [undefined, { debugName: "assIdTagEntries" }] : []));
410
+ // assertion-tags
411
+ assTagEntries = input(...(ngDevMode ? [undefined, { debugName: "assTagEntries" }] : []));
412
+ // doc-reference-types
413
+ refTypeEntries = input(...(ngDevMode ? [undefined, { debugName: "refTypeEntries" }] : []));
414
+ // doc-reference-tags
415
+ refTagEntries = input(...(ngDevMode ? [undefined, { debugName: "refTagEntries" }] : []));
416
+ eid;
417
+ tags;
418
+ definition;
419
+ note;
420
+ examples;
421
+ relatedIds;
422
+ form;
423
+ constructor(formBuilder, _dialogService, _editService, _editorBindings) {
424
+ this._dialogService = _dialogService;
425
+ this._editService = _editService;
426
+ this._editorBindings = _editorBindings;
427
+ // form
428
+ this.eid = formBuilder.control(null, {
429
+ validators: Validators.maxLength(50),
430
+ });
431
+ this.tags = formBuilder.control([], {
432
+ nonNullable: true,
433
+ });
434
+ this.definition = formBuilder.control('', {
435
+ nonNullable: true,
436
+ validators: [Validators.required, Validators.maxLength(5000)],
437
+ });
438
+ this.note = formBuilder.control(null, {
439
+ nonNullable: true,
440
+ validators: [Validators.maxLength(1000)],
441
+ });
442
+ this.examples = formBuilder.control([], {
443
+ nonNullable: true,
444
+ });
445
+ this.relatedIds = formBuilder.control([], {
446
+ nonNullable: true,
447
+ });
448
+ this.form = formBuilder.group({
449
+ eid: this.eid,
450
+ tags: this.tags,
451
+ definition: this.definition,
452
+ note: this.note,
453
+ examples: this.examples,
454
+ relatedIds: this.relatedIds,
455
+ });
456
+ // when model changes, update form
457
+ effect(() => {
458
+ const data = this.sense();
459
+ this.updateForm(data);
460
+ });
461
+ }
462
+ ngOnDestroy() {
463
+ this._disposables.forEach((d) => d.dispose());
464
+ }
465
+ async applyEdit(selector, editor) {
466
+ if (!editor) {
467
+ return;
468
+ }
469
+ const selection = editor.getSelection();
470
+ const text = selection ? editor.getModel().getValueInRange(selection) : '';
471
+ const result = await this._editService.edit({
472
+ selector,
473
+ text: text,
474
+ });
475
+ editor.executeEdits('my-source', [
476
+ {
477
+ range: selection,
478
+ text: result.text,
479
+ forceMoveMarkers: true,
480
+ },
481
+ ]);
482
+ }
483
+ onCreateTextEditor(editor) {
484
+ editor.updateOptions({
485
+ minimap: {
486
+ side: 'right',
487
+ },
488
+ wordWrap: 'on',
489
+ automaticLayout: true,
490
+ });
491
+ this._definitionModel =
492
+ this._definitionModel || monaco.editor.createModel(this.definition?.value || '', 'markdown');
493
+ editor.setModel(this._definitionModel);
494
+ this._definitionEditor = editor;
495
+ this._disposables.push(this._definitionModel.onDidChangeContent((e) => {
496
+ this.definition.setValue(this._definitionModel.getValue());
497
+ this.definition.markAsDirty();
498
+ this.definition.updateValueAndValidity();
499
+ }));
500
+ // plugins
501
+ if (this._editorBindings) {
502
+ Object.keys(this._editorBindings).forEach((key) => {
503
+ const n = parseInt(key, 10);
504
+ console.log('Binding ' + n + ' to ' + this._editorBindings[key]);
505
+ this._definitionEditor.addCommand(n, () => {
506
+ this.applyEdit(this._editorBindings[key], this._definitionEditor);
507
+ });
508
+ });
509
+ }
510
+ }
511
+ mapIdToEntry(id, entries) {
512
+ if (!id)
513
+ return null;
514
+ if (!entries)
515
+ return { id, value: id };
516
+ return entries.find((e) => e.id === id) || { id, value: id };
517
+ }
518
+ mapIdToEntries(ids, entries) {
519
+ if (!entries)
520
+ return ids.map((id) => ({ id, value: id }));
521
+ return ids.map((id) => entries.find((e) => e.id === id) || { id, value: id });
522
+ }
523
+ updateForm(sense) {
524
+ if (!sense) {
525
+ this.form.reset();
526
+ }
527
+ else {
528
+ this.eid.setValue(sense.eid || null);
529
+ this.tags.setValue(this.mapIdToEntries(sense.tags || [], this.tagEntries()));
530
+ this._definitionModel?.setValue(sense.definition || '');
531
+ this.note.setValue(sense.note || null);
532
+ this.examples.setValue(sense.examples || []);
533
+ this.relatedIds.setValue(sense.relatedIds || []);
534
+ this.form.markAsPristine();
535
+ }
536
+ }
537
+ onRelatedIdsChange(ids) {
538
+ this.relatedIds.setValue(ids);
539
+ this.relatedIds.markAsDirty();
540
+ this.relatedIds.updateValueAndValidity();
541
+ }
542
+ getSense() {
543
+ return {
544
+ eid: this.eid.value || undefined,
545
+ tags: this.tags.value?.length ? this.tags.value.map((e) => e.id) : undefined,
546
+ definition: this.definition.value?.trim() || '',
547
+ note: this.note.value?.trim() || undefined,
548
+ examples: this.examples.value?.length ? this.examples.value : undefined,
549
+ relatedIds: this.relatedIds.value?.length ? this.relatedIds.value : undefined,
550
+ };
551
+ }
552
+ addExample() {
553
+ const entry = {
554
+ text: '',
555
+ };
556
+ this.editedExIndex.set(-1);
557
+ this.editedEx.set(entry);
558
+ }
559
+ editExample(entry, index) {
560
+ this.editedExIndex.set(index);
561
+ this.editedEx.set(structuredClone(entry));
562
+ }
563
+ closeExample() {
564
+ this.editedExIndex.set(-1);
565
+ this.editedEx.set(undefined);
566
+ }
567
+ saveExample(entry) {
568
+ const entries = [...this.examples.value];
569
+ if (this.editedExIndex() === -1) {
570
+ entries.push(entry);
571
+ }
572
+ else {
573
+ entries.splice(this.editedExIndex(), 1, entry);
574
+ }
575
+ this.examples.setValue(entries);
576
+ this.examples.markAsDirty();
577
+ this.examples.updateValueAndValidity();
578
+ this.closeExample();
579
+ }
580
+ deleteExample(index) {
581
+ this._dialogService
582
+ .confirm('Confirmation', `Delete example #${index + 1}?`)
583
+ .subscribe((yes) => {
584
+ if (yes) {
585
+ if (this.editedExIndex() === index) {
586
+ this.closeExample();
587
+ }
588
+ const entries = [...this.examples.value];
589
+ entries.splice(index, 1);
590
+ this.examples.setValue(entries);
591
+ this.examples.markAsDirty();
592
+ this.examples.updateValueAndValidity();
593
+ }
594
+ });
595
+ }
596
+ moveExampleUp(index) {
597
+ if (index < 1) {
598
+ return;
599
+ }
600
+ const entry = this.examples.value[index];
601
+ const entries = [...this.examples.value];
602
+ entries.splice(index, 1);
603
+ entries.splice(index - 1, 0, entry);
604
+ this.examples.setValue(entries);
605
+ this.examples.markAsDirty();
606
+ this.examples.updateValueAndValidity();
607
+ }
608
+ moveExampleDown(index) {
609
+ if (index + 1 >= this.examples.value.length) {
610
+ return;
611
+ }
612
+ const entry = this.examples.value[index];
613
+ const entries = [...this.examples.value];
614
+ entries.splice(index, 1);
615
+ entries.splice(index + 1, 0, entry);
616
+ this.examples.setValue(entries);
617
+ this.examples.markAsDirty();
618
+ this.examples.updateValueAndValidity();
619
+ }
620
+ cancel() {
621
+ this.cancelEdit.emit();
622
+ }
623
+ /**
624
+ * Saves the current form data by updating the `sense` model signal.
625
+ * This method can be called manually (e.g., by a Save button) or
626
+ * automatically (via auto-save).
627
+ * @param pristine If true (default), the form is marked as pristine
628
+ * after saving.
629
+ * Set to false for auto-save if you want the form to remain dirty.
630
+ */
631
+ save(pristine = true) {
632
+ if (this.form.invalid) {
633
+ // show validation errors
634
+ this.form.markAllAsTouched();
635
+ return;
636
+ }
637
+ const sense = this.getSense();
638
+ this.sense.set(sense);
639
+ if (pristine) {
640
+ this.form.markAsPristine();
641
+ }
642
+ }
643
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: WordSenseEditor, deps: [{ token: i1.FormBuilder }, { token: i2$1.DialogService }, { token: i2.CadmusTextEdService }, { token: CADMUS_TEXT_ED_BINDINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Component });
644
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: WordSenseEditor, isStandalone: true, selector: "cadmus-word-sense-editor", inputs: { sense: { classPropertyName: "sense", publicName: "sense", isSignal: true, isRequired: false, transformFunction: null }, tagEntries: { classPropertyName: "tagEntries", publicName: "tagEntries", isSignal: true, isRequired: false, transformFunction: null }, assIdScopeEntries: { classPropertyName: "assIdScopeEntries", publicName: "assIdScopeEntries", isSignal: true, isRequired: false, transformFunction: null }, assIdTagEntries: { classPropertyName: "assIdTagEntries", publicName: "assIdTagEntries", isSignal: true, isRequired: false, transformFunction: null }, assTagEntries: { classPropertyName: "assTagEntries", publicName: "assTagEntries", isSignal: true, isRequired: false, transformFunction: null }, refTypeEntries: { classPropertyName: "refTypeEntries", publicName: "refTypeEntries", isSignal: true, isRequired: false, transformFunction: null }, refTagEntries: { classPropertyName: "refTagEntries", publicName: "refTagEntries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sense: "senseChange", cancelEdit: "cancelEdit" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- DEFINITION -->\r\n <mat-tab label=\"definition\">\r\n <!-- eid -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label>EID</mat-label>\r\n <input matInput [formControl]=\"eid\" />\r\n @if ($any(eid).errors?.maxLength && (eid.dirty || eid.touched)) {\r\n <mat-error>EID too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n <div>\r\n <!-- tags -->\r\n @if (tagEntries()?.length) {\r\n <div>\r\n <cadmus-thes-entries-picker\r\n [availableEntries]=\"tagEntries()!\"\r\n [entries]=\"tags.value\"\r\n [hierarchicLabels]=\"true\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- definition -->\r\n <div id=\"def-container\">\r\n <div id=\"def\">\r\n <nge-monaco-editor id=\"editor\" (ready)=\"onCreateTextEditor($event)\" />\r\n @if (definition.hasError('required') && (definition.touched || definition.dirty)) {\r\n <mat-error>text required</mat-error>\r\n } @if (definition.hasError('maxLength') && (definition.touched || definition.dirty)) {\r\n <mat-error>text too long</mat-error>\r\n }\r\n </div>\r\n <!-- preview -->\r\n <div id=\"def-preview\">\r\n <mat-expansion-panel expanded=\"true\">\r\n <div>\r\n <nge-markdown [data]=\"definition.value || undefined\" />\r\n </div>\r\n </mat-expansion-panel>\r\n </div>\r\n </div>\r\n\r\n <!-- note -->\r\n <div class=\"mt\">\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput rows=\"3\" [formControl]=\"note\"></textarea>\r\n @if ($any(note).errors?.maxLength && (note.dirty || note.touched)) {\r\n <mat-error>note too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- EXAMPLES -->\r\n <mat-tab label=\"examples\">\r\n <div>\r\n <button type=\"button\" mat-flat-button class=\"mat-primary\" (click)=\"addExample()\">\r\n <mat-icon>add_circle</mat-icon> example\r\n </button>\r\n </div>\r\n @if (examples.value.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>tags</th>\r\n <th>text</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of examples.value; track entry; let i = $index; let first = $first; let last =\r\n $last) {\r\n <tr [class.selected]=\"i === editedExIndex()\">\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this example\"\r\n (click)=\"editExample(entry, i)\"\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 matTooltip=\"Move this example up\"\r\n [disabled]=\"first\"\r\n (click)=\"moveExampleUp(i)\"\r\n >\r\n <mat-icon>arrow_upward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this example down\"\r\n [disabled]=\"last\"\r\n (click)=\"moveExampleDown(i)\"\r\n >\r\n <mat-icon>arrow_downward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this example\"\r\n (click)=\"deleteExample(i)\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n @for (tag of entry.tags; track tag; let last = $last) {\r\n {{ tag | flatLookup : tagEntries() : 'id' : 'value' }}\r\n @if (!last) {\r\n <span>, </span>\r\n } }\r\n </td>\r\n <td>{{ entry.text | ellipsis }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n } @if (editedEx()) {\r\n <fieldset>\r\n <mat-expansion-panel [expanded]=\"editedEx()\" [disabled]=\"!editedEx()\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>Example #</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <cadmus-word-sense-example-editor\r\n [tagEntries]=\"tagEntries()\"\r\n [example]=\"editedEx()\"\r\n (exampleChange)=\"saveExample($event!)\"\r\n (cancelEdit)=\"closeExample()\"\r\n />\r\n </mat-expansion-panel>\r\n </fieldset>\r\n }\r\n </mat-tab>\r\n\r\n <!-- RELATED IDS -->\r\n <mat-tab label=\"related\">\r\n <cadmus-refs-asserted-composite-ids\r\n [idScopeEntries]=\"assIdScopeEntries()\"\r\n [idTagEntries]=\"assIdTagEntries()\"\r\n [assTagEntries]=\"assTagEntries()\"\r\n [refTypeEntries]=\"refTypeEntries()\"\r\n [refTagEntries]=\"refTagEntries()\"\r\n [ids]=\"relatedIds.value\"\r\n (idsChange)=\"onRelatedIdsChange($event)\"\r\n />\r\n </mat-tab>\r\n\r\n <!-- buttons -->\r\n <div>\r\n <button type=\"button\" mat-icon-button matTooltip=\"Discard changes\" (click)=\"cancel()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Accept changes\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </mat-tab-group>\r\n</form>\r\n", styles: ["#editor{height:300px}.long-text{width:100%;max-width:800px}.mt{margin-top:16px}#def-container{display:grid;grid-template-rows:auto;grid-template-columns:1fr 1fr;grid-template-areas:\"def preview\";gap:8px}#def{grid-area:def}#def-preview{grid-area:preview}@media only screen and (max-width: 959px){#def-container{grid-template-columns:1fr;grid-template-rows:auto auto;grid-template-areas:\"def\" \"preview\"}}\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.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: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i5.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i9$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i9$1.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: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: NgeMonacoModule }, { kind: "component", type: i9.NgeMonacoEditorComponent, selector: "nge-monaco-editor", inputs: ["autoLayout", "options"], outputs: ["ready"] }, { kind: "ngmodule", type: NgeMarkdownModule }, { kind: "component", type: i10.NgeMarkdownComponent, selector: "nge-markdown, [nge-markdown]", inputs: ["file", "data", "theme"], outputs: ["render"] }, { kind: "component", type: AssertedCompositeIdsComponent, selector: "cadmus-refs-asserted-composite-ids", inputs: ["ids", "idScopeEntries", "idTagEntries", "assTagEntries", "refTypeEntries", "refTagEntries", "pinByTypeMode", "canSwitchMode", "canEditTarget", "lookupDefinitions", "defaultPartTypeKey"], outputs: ["idsChange"] }, { kind: "component", type: ThesEntriesPickerComponent, selector: "cadmus-thes-entries-picker", inputs: ["availableEntries", "entries", "hierarchicLabels", "autoSort", "allowCustom", "minEntries", "maxEntries", "expanded", "emptyMessage"], outputs: ["entriesChange", "expandedChange"] }, { kind: "component", type: WordSenseExampleEditor, selector: "cadmus-word-sense-example-editor", inputs: ["example", "tagEntries"], outputs: ["exampleChange", "cancelEdit"] }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: FlatLookupPipe, name: "flatLookup" }] });
645
+ }
646
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: WordSenseEditor, decorators: [{
647
+ type: Component,
648
+ args: [{ selector: 'cadmus-word-sense-editor', imports: [
649
+ CommonModule,
650
+ ReactiveFormsModule,
651
+ MatButtonModule,
652
+ MatCheckboxModule,
653
+ MatExpansionModule,
654
+ MatFormFieldModule,
655
+ MatIconModule,
656
+ MatInputModule,
657
+ MatSelectModule,
658
+ MatTabsModule,
659
+ MatTooltipModule,
660
+ NgeMonacoModule,
661
+ NgeMarkdownModule,
662
+ AssertedCompositeIdsComponent,
663
+ ThesEntriesPickerComponent,
664
+ WordSenseExampleEditor,
665
+ EllipsisPipe,
666
+ FlatLookupPipe
667
+ ], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-tab-group>\r\n <!-- DEFINITION -->\r\n <mat-tab label=\"definition\">\r\n <!-- eid -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label>EID</mat-label>\r\n <input matInput [formControl]=\"eid\" />\r\n @if ($any(eid).errors?.maxLength && (eid.dirty || eid.touched)) {\r\n <mat-error>EID too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n <div>\r\n <!-- tags -->\r\n @if (tagEntries()?.length) {\r\n <div>\r\n <cadmus-thes-entries-picker\r\n [availableEntries]=\"tagEntries()!\"\r\n [entries]=\"tags.value\"\r\n [hierarchicLabels]=\"true\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- definition -->\r\n <div id=\"def-container\">\r\n <div id=\"def\">\r\n <nge-monaco-editor id=\"editor\" (ready)=\"onCreateTextEditor($event)\" />\r\n @if (definition.hasError('required') && (definition.touched || definition.dirty)) {\r\n <mat-error>text required</mat-error>\r\n } @if (definition.hasError('maxLength') && (definition.touched || definition.dirty)) {\r\n <mat-error>text too long</mat-error>\r\n }\r\n </div>\r\n <!-- preview -->\r\n <div id=\"def-preview\">\r\n <mat-expansion-panel expanded=\"true\">\r\n <div>\r\n <nge-markdown [data]=\"definition.value || undefined\" />\r\n </div>\r\n </mat-expansion-panel>\r\n </div>\r\n </div>\r\n\r\n <!-- note -->\r\n <div class=\"mt\">\r\n <mat-form-field class=\"long-text\">\r\n <mat-label>note</mat-label>\r\n <textarea matInput rows=\"3\" [formControl]=\"note\"></textarea>\r\n @if ($any(note).errors?.maxLength && (note.dirty || note.touched)) {\r\n <mat-error>note too long</mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n </mat-tab>\r\n\r\n <!-- EXAMPLES -->\r\n <mat-tab label=\"examples\">\r\n <div>\r\n <button type=\"button\" mat-flat-button class=\"mat-primary\" (click)=\"addExample()\">\r\n <mat-icon>add_circle</mat-icon> example\r\n </button>\r\n </div>\r\n @if (examples.value.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>tags</th>\r\n <th>text</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of examples.value; track entry; let i = $index; let first = $first; let last =\r\n $last) {\r\n <tr [class.selected]=\"i === editedExIndex()\">\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this example\"\r\n (click)=\"editExample(entry, i)\"\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 matTooltip=\"Move this example up\"\r\n [disabled]=\"first\"\r\n (click)=\"moveExampleUp(i)\"\r\n >\r\n <mat-icon>arrow_upward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this example down\"\r\n [disabled]=\"last\"\r\n (click)=\"moveExampleDown(i)\"\r\n >\r\n <mat-icon>arrow_downward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this example\"\r\n (click)=\"deleteExample(i)\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>\r\n @for (tag of entry.tags; track tag; let last = $last) {\r\n {{ tag | flatLookup : tagEntries() : 'id' : 'value' }}\r\n @if (!last) {\r\n <span>, </span>\r\n } }\r\n </td>\r\n <td>{{ entry.text | ellipsis }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n } @if (editedEx()) {\r\n <fieldset>\r\n <mat-expansion-panel [expanded]=\"editedEx()\" [disabled]=\"!editedEx()\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>Example #</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <cadmus-word-sense-example-editor\r\n [tagEntries]=\"tagEntries()\"\r\n [example]=\"editedEx()\"\r\n (exampleChange)=\"saveExample($event!)\"\r\n (cancelEdit)=\"closeExample()\"\r\n />\r\n </mat-expansion-panel>\r\n </fieldset>\r\n }\r\n </mat-tab>\r\n\r\n <!-- RELATED IDS -->\r\n <mat-tab label=\"related\">\r\n <cadmus-refs-asserted-composite-ids\r\n [idScopeEntries]=\"assIdScopeEntries()\"\r\n [idTagEntries]=\"assIdTagEntries()\"\r\n [assTagEntries]=\"assTagEntries()\"\r\n [refTypeEntries]=\"refTypeEntries()\"\r\n [refTagEntries]=\"refTagEntries()\"\r\n [ids]=\"relatedIds.value\"\r\n (idsChange)=\"onRelatedIdsChange($event)\"\r\n />\r\n </mat-tab>\r\n\r\n <!-- buttons -->\r\n <div>\r\n <button type=\"button\" mat-icon-button matTooltip=\"Discard changes\" (click)=\"cancel()\">\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n matTooltip=\"Accept changes\"\r\n [disabled]=\"form.invalid || form.pristine\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n </mat-tab-group>\r\n</form>\r\n", styles: ["#editor{height:300px}.long-text{width:100%;max-width:800px}.mt{margin-top:16px}#def-container{display:grid;grid-template-rows:auto;grid-template-columns:1fr 1fr;grid-template-areas:\"def preview\";gap:8px}#def{grid-area:def}#def-preview{grid-area:preview}@media only screen and (max-width: 959px){#def-container{grid-template-columns:1fr;grid-template-rows:auto auto;grid-template-areas:\"def\" \"preview\"}}\n"] }]
668
+ }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2$1.DialogService }, { type: i2.CadmusTextEdService }, { type: undefined, decorators: [{
669
+ type: Inject,
670
+ args: [CADMUS_TEXT_ED_BINDINGS_TOKEN]
671
+ }, {
672
+ type: Optional
673
+ }] }], propDecorators: { sense: [{ type: i0.Input, args: [{ isSignal: true, alias: "sense", required: false }] }, { type: i0.Output, args: ["senseChange"] }], cancelEdit: [{ type: i0.Output, args: ["cancelEdit"] }], tagEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagEntries", required: false }] }], assIdScopeEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "assIdScopeEntries", required: false }] }], assIdTagEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "assIdTagEntries", required: false }] }], assTagEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "assTagEntries", required: false }] }], refTypeEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "refTypeEntries", required: false }] }], refTagEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "refTagEntries", required: false }] }] } });
674
+
675
+ /**
676
+ * Word senses part editor component.
677
+ * Thesauri: lex-word-sense-tags, asserted-id-scopes, asserted-id-tags,
678
+ * doc-reference-types, doc-reference-tags.
679
+ */
680
+ class LexWordSensesPartEditor extends ModelEditorComponentBase {
681
+ _dialogService;
682
+ editedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "editedIndex" }] : []));
683
+ edited = signal(undefined, ...(ngDevMode ? [{ debugName: "edited" }] : []));
684
+ // lex-word-sense-tags
685
+ tagEntries = signal(undefined, ...(ngDevMode ? [{ debugName: "tagEntries" }] : []));
686
+ entries;
687
+ constructor(authService, formBuilder, _dialogService) {
688
+ super(authService, formBuilder);
689
+ this._dialogService = _dialogService;
690
+ // form
691
+ this.entries = formBuilder.control([], {
692
+ // at least 1 entry
693
+ validators: NgxToolsValidators.strictMinLengthValidator(1),
694
+ nonNullable: true,
695
+ });
696
+ }
697
+ ngOnInit() {
698
+ super.ngOnInit();
699
+ }
700
+ buildForm(formBuilder) {
701
+ return formBuilder.group({
702
+ entries: this.entries,
703
+ });
704
+ }
705
+ updateThesauri(thesauri) {
706
+ const key = 'lex-word-sense-tags';
707
+ if (this.hasThesaurus(key)) {
708
+ this.tagEntries.set(thesauri[key].entries);
709
+ }
710
+ else {
711
+ this.tagEntries.set(undefined);
712
+ }
713
+ }
714
+ updateForm(part) {
715
+ if (!part) {
716
+ this.form.reset();
717
+ return;
718
+ }
719
+ this.entries.setValue(part.senses || []);
720
+ this.form.markAsPristine();
721
+ }
722
+ onDataSet(data) {
723
+ // thesauri
724
+ if (data?.thesauri) {
725
+ this.updateThesauri(data.thesauri);
726
+ }
727
+ // form
728
+ this.updateForm(data?.value);
729
+ }
730
+ getValue() {
731
+ let part = this.getEditedPart(LEX_WORD_SENSES_PART_TYPEID);
732
+ part.senses = this.entries.value || [];
733
+ return part;
734
+ }
735
+ addSense() {
736
+ const entry = {
737
+ definition: '',
738
+ };
739
+ this.editSense(entry, -1);
740
+ }
741
+ editSense(entry, index) {
742
+ this.editedIndex.set(index);
743
+ this.edited.set(deepCopy(entry));
744
+ }
745
+ closeSense() {
746
+ this.editedIndex.set(-1);
747
+ this.edited.set(undefined);
748
+ }
749
+ saveSense(entry) {
750
+ const entries = [...this.entries.value];
751
+ if (this.editedIndex() === -1) {
752
+ entries.push(entry);
753
+ }
754
+ else {
755
+ entries.splice(this.editedIndex(), 1, entry);
756
+ }
757
+ this.entries.setValue(entries);
758
+ this.entries.markAsDirty();
759
+ this.entries.updateValueAndValidity();
760
+ this.closeSense();
761
+ }
762
+ deleteSense(index) {
763
+ this._dialogService
764
+ .confirm('Confirmation', 'Delete sense?')
765
+ .subscribe((yes) => {
766
+ if (yes) {
767
+ if (this.editedIndex() === index) {
768
+ this.closeSense();
769
+ }
770
+ const entries = [...this.entries.value];
771
+ entries.splice(index, 1);
772
+ this.entries.setValue(entries);
773
+ this.entries.markAsDirty();
774
+ this.entries.updateValueAndValidity();
775
+ }
776
+ });
777
+ }
778
+ moveSenseUp(index) {
779
+ if (index < 1) {
780
+ return;
781
+ }
782
+ const entry = this.entries.value[index];
783
+ const entries = [...this.entries.value];
784
+ entries.splice(index, 1);
785
+ entries.splice(index - 1, 0, entry);
786
+ this.entries.setValue(entries);
787
+ this.entries.markAsDirty();
788
+ this.entries.updateValueAndValidity();
789
+ }
790
+ moveSenseDown(index) {
791
+ if (index + 1 >= this.entries.value.length) {
792
+ return;
793
+ }
794
+ const entry = this.entries.value[index];
795
+ const entries = [...this.entries.value];
796
+ entries.splice(index, 1);
797
+ entries.splice(index + 1, 0, entry);
798
+ this.entries.setValue(entries);
799
+ this.entries.markAsDirty();
800
+ this.entries.updateValueAndValidity();
801
+ }
802
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LexWordSensesPartEditor, deps: [{ token: i1$1.AuthJwtService }, { token: i1.FormBuilder }, { token: i2$1.DialogService }], target: i0.ɵɵFactoryTarget.Component });
803
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: LexWordSensesPartEditor, isStandalone: true, selector: "cadmus-lex-word-senses-part-editor", usesInheritance: true, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-card>\r\n <mat-card-header>\r\n <div mat-card-avatar>\r\n <mat-icon>picture_in_picture</mat-icon>\r\n </div>\r\n <mat-card-title>\r\n {{ (modelName() | titlecase) || 'Word Senses Part' }}\r\n </mat-card-title>\r\n </mat-card-header>\r\n <mat-card-content>\r\n <div>\r\n <button type=\"button\" mat-flat-button class=\"mat-primary\" (click)=\"addSense()\">\r\n <mat-icon>add_circle</mat-icon> sense\r\n </button>\r\n </div>\r\n @if (entries.value.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>EID</th>\r\n <th>tags</th>\r\n <th>definition</th>\r\n <th>examples</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of entries.value; track entry; let i = $index; let first = $first; let last =\r\n $last) {\r\n <tr [class.selected]=\"entry === edited()\">\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this Sense\"\r\n (click)=\"editSense(entry, i)\"\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 matTooltip=\"Move this Sense up\"\r\n [disabled]=\"first\"\r\n (click)=\"moveSenseUp(i)\"\r\n >\r\n <mat-icon>arrow_upward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this Sense down\"\r\n [disabled]=\"last\"\r\n (click)=\"moveSenseDown(i)\"\r\n >\r\n <mat-icon>arrow_downward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this Sense\"\r\n (click)=\"deleteSense(i)\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ entry.eid }}</td>\r\n <td>\r\n @for (tag of entry.tags; track tag; let last = $last) {\r\n {{ tag | flatLookup : tagEntries() : 'id' : 'value' }}\r\n @if (!last) {\r\n <span>, </span>\r\n } }\r\n </td>\r\n <td>{{ entry.definition | ellipsis }}</td>\r\n <td>{{ entry.examples?.length || 0 }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n } @if (edited()) {\r\n <fieldset>\r\n <mat-expansion-panel [expanded]=\"edited()\" [disabled]=\"!edited()\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>Sense #</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <cadmus-word-sense-editor\r\n [tagEntries]=\"tagEntries()\"\r\n [sense]=\"edited()\"\r\n (senseChange)=\"saveSense($event!)\"\r\n (cancelEdit)=\"closeSense()\"\r\n />\r\n </mat-expansion-panel>\r\n </fieldset>\r\n }\r\n </mat-card-content>\r\n <mat-card-actions>\r\n <cadmus-close-save-buttons [form]=\"form\" [noSave]=\"userLevel < 2\" (closeRequest)=\"close()\" />\r\n </mat-card-actions>\r\n </mat-card>\r\n</form>\r\n", styles: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:#e2e2e2}th{text-align:left;font-weight:400;color:silver}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#d0d0d0!important}fieldset{border:1px solid silver;border-radius:6px;padding:6px}\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: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i5$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5$2.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i5$2.MatCardAvatar, selector: "[mat-card-avatar], [matCardAvatar]" }, { kind: "directive", type: i5$2.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i5$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i5$2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i5.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type:
804
+ // cadmus
805
+ CloseSaveButtonsComponent, selector: "cadmus-close-save-buttons", inputs: ["form", "noSave"], outputs: ["closeRequest"] }, { kind: "component", type: WordSenseEditor, selector: "cadmus-word-sense-editor", inputs: ["sense", "tagEntries", "assIdScopeEntries", "assIdTagEntries", "assTagEntries", "refTypeEntries", "refTagEntries"], outputs: ["senseChange", "cancelEdit"] }, { kind: "pipe", type: i9$2.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: FlatLookupPipe, name: "flatLookup" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }] });
806
+ }
807
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LexWordSensesPartEditor, decorators: [{
808
+ type: Component,
809
+ args: [{ selector: 'cadmus-lex-word-senses-part-editor', imports: [
810
+ CommonModule,
811
+ ReactiveFormsModule,
812
+ MatButtonModule,
813
+ MatCardModule,
814
+ MatExpansionModule,
815
+ MatFormFieldModule,
816
+ MatIconModule,
817
+ MatInputModule,
818
+ MatSelectModule,
819
+ MatTooltipModule,
820
+ // cadmus
821
+ CloseSaveButtonsComponent,
822
+ WordSenseEditor,
823
+ FlatLookupPipe,
824
+ EllipsisPipe,
825
+ ], template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <mat-card>\r\n <mat-card-header>\r\n <div mat-card-avatar>\r\n <mat-icon>picture_in_picture</mat-icon>\r\n </div>\r\n <mat-card-title>\r\n {{ (modelName() | titlecase) || 'Word Senses Part' }}\r\n </mat-card-title>\r\n </mat-card-header>\r\n <mat-card-content>\r\n <div>\r\n <button type=\"button\" mat-flat-button class=\"mat-primary\" (click)=\"addSense()\">\r\n <mat-icon>add_circle</mat-icon> sense\r\n </button>\r\n </div>\r\n @if (entries.value.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>EID</th>\r\n <th>tags</th>\r\n <th>definition</th>\r\n <th>examples</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of entries.value; track entry; let i = $index; let first = $first; let last =\r\n $last) {\r\n <tr [class.selected]=\"entry === edited()\">\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Edit this Sense\"\r\n (click)=\"editSense(entry, i)\"\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 matTooltip=\"Move this Sense up\"\r\n [disabled]=\"first\"\r\n (click)=\"moveSenseUp(i)\"\r\n >\r\n <mat-icon>arrow_upward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Move this Sense down\"\r\n [disabled]=\"last\"\r\n (click)=\"moveSenseDown(i)\"\r\n >\r\n <mat-icon>arrow_downward</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matTooltip=\"Delete this Sense\"\r\n (click)=\"deleteSense(i)\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ entry.eid }}</td>\r\n <td>\r\n @for (tag of entry.tags; track tag; let last = $last) {\r\n {{ tag | flatLookup : tagEntries() : 'id' : 'value' }}\r\n @if (!last) {\r\n <span>, </span>\r\n } }\r\n </td>\r\n <td>{{ entry.definition | ellipsis }}</td>\r\n <td>{{ entry.examples?.length || 0 }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n } @if (edited()) {\r\n <fieldset>\r\n <mat-expansion-panel [expanded]=\"edited()\" [disabled]=\"!edited()\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>Sense #</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <cadmus-word-sense-editor\r\n [tagEntries]=\"tagEntries()\"\r\n [sense]=\"edited()\"\r\n (senseChange)=\"saveSense($event!)\"\r\n (cancelEdit)=\"closeSense()\"\r\n />\r\n </mat-expansion-panel>\r\n </fieldset>\r\n }\r\n </mat-card-content>\r\n <mat-card-actions>\r\n <cadmus-close-save-buttons [form]=\"form\" [noSave]=\"userLevel < 2\" (closeRequest)=\"close()\" />\r\n </mat-card-actions>\r\n </mat-card>\r\n</form>\r\n", styles: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:#e2e2e2}th{text-align:left;font-weight:400;color:silver}td.fit-width{width:1px;white-space:nowrap}tr.selected{background-color:#d0d0d0!important}fieldset{border:1px solid silver;border-radius:6px;padding:6px}\n"] }]
826
+ }], ctorParameters: () => [{ type: i1$1.AuthJwtService }, { type: i1.FormBuilder }, { type: i2$1.DialogService }] });
827
+
828
+ class LexWordSensesPartFeature extends EditPartFeatureBase {
829
+ constructor(router, route, snackbar, itemService, thesaurusService, editorService) {
830
+ super(router, route, snackbar, itemService, thesaurusService, editorService);
831
+ }
832
+ getReqThesauriIds() {
833
+ return [
834
+ 'lex-word-sense-tags',
835
+ 'lex-word-sense-tags',
836
+ 'asserted-id-scopes',
837
+ 'asserted-id-tags',
838
+ 'doc-reference-types',
839
+ 'doc-reference-tags',
840
+ ];
841
+ }
842
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LexWordSensesPartFeature, deps: [{ token: i1$2.Router }, { token: i1$2.ActivatedRoute }, { token: i2$2.MatSnackBar }, { token: i3.ItemService }, { token: i3.ThesaurusService }, { token: i4$1.PartEditorService }], target: i0.ɵɵFactoryTarget.Component });
843
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.9", type: LexWordSensesPartFeature, isStandalone: true, selector: "cadmus-lex-word-senses-part-feature", usesInheritance: true, ngImport: i0, template: "<cadmus-current-item-bar />\r\n<cadmus-lex-word-senses-part-editor\r\n [identity]=\"identity\"\r\n [data]=\"$any(data)\"\r\n (dataChange)=\"save($event!.value!)\"\r\n (editorClose)=\"close()\"\r\n (dirtyChange)=\"onDirtyChange($event)\"\r\n/>\r\n", styles: [""], dependencies: [{ kind: "component", type: CurrentItemBarComponent, selector: "cadmus-current-item-bar" }, { kind: "component", type: LexWordSensesPartEditor, selector: "cadmus-lex-word-senses-part-editor" }] });
844
+ }
845
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LexWordSensesPartFeature, decorators: [{
846
+ type: Component,
847
+ args: [{ selector: 'cadmus-lex-word-senses-part-feature', imports: [CurrentItemBarComponent, LexWordSensesPartEditor], template: "<cadmus-current-item-bar />\r\n<cadmus-lex-word-senses-part-editor\r\n [identity]=\"identity\"\r\n [data]=\"$any(data)\"\r\n (dataChange)=\"save($event!.value!)\"\r\n (editorClose)=\"close()\"\r\n (dirtyChange)=\"onDirtyChange($event)\"\r\n/>\r\n" }]
848
+ }], ctorParameters: () => [{ type: i1$2.Router }, { type: i1$2.ActivatedRoute }, { type: i2$2.MatSnackBar }, { type: i3.ItemService }, { type: i3.ThesaurusService }, { type: i4$1.PartEditorService }] });
849
+
850
+ /*
851
+ * Public API Surface of cadmus-part-lexicography-word-senses
852
+ */
853
+
854
+ /**
855
+ * Generated bundle index. Do not edit.
856
+ */
857
+
858
+ export { LEX_WORD_SENSES_PART_SCHEMA, LEX_WORD_SENSES_PART_TYPEID, LexWordSensesPartEditor, LexWordSensesPartFeature, WordSenseEditor, WordSenseExampleEditor };
859
+ //# sourceMappingURL=myrmidon-cadmus-part-lexicography-word-senses.mjs.map