@memberjunction/ng-composer 6.2.0-edge.0 → 6.2.0-edge.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.
- package/dist/lib/components/mention/mention-dropdown.component.d.ts +64 -8
- package/dist/lib/components/mention/mention-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-dropdown.component.js +123 -23
- package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts +202 -20
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +462 -146
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +7 -1
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +31 -19
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/package.json +5 -5
|
@@ -71,12 +71,52 @@ function MentionEditorComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
|
71
71
|
export class MentionEditorComponent {
|
|
72
72
|
cdr;
|
|
73
73
|
hostRef;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
EditorRef;
|
|
75
|
+
/** @deprecated Use {@link EditorRef}. */
|
|
76
|
+
get editorRef() {
|
|
77
|
+
return this.EditorRef;
|
|
78
|
+
}
|
|
79
|
+
/** @deprecated Use {@link EditorRef}. */
|
|
80
|
+
set editorRef(value) {
|
|
81
|
+
this.EditorRef = value;
|
|
82
|
+
}
|
|
83
|
+
Placeholder = 'Type @ to mention agents or users, # for entities...';
|
|
84
|
+
/** @deprecated Use {@link Placeholder}. */
|
|
85
|
+
set placeholder(value) {
|
|
86
|
+
this.Placeholder = value;
|
|
87
|
+
}
|
|
88
|
+
/** @deprecated Use {@link Placeholder}. */
|
|
89
|
+
get placeholder() {
|
|
90
|
+
return this.Placeholder;
|
|
91
|
+
}
|
|
92
|
+
Disabled = false;
|
|
93
|
+
/** @deprecated Use {@link Disabled}. */
|
|
94
|
+
set disabled(value) {
|
|
95
|
+
this.Disabled = value;
|
|
96
|
+
}
|
|
97
|
+
/** @deprecated Use {@link Disabled}. */
|
|
98
|
+
get disabled() {
|
|
99
|
+
return this.Disabled;
|
|
100
|
+
}
|
|
101
|
+
CurrentUser;
|
|
102
|
+
/** @deprecated Use {@link CurrentUser}. */
|
|
103
|
+
set currentUser(value) {
|
|
104
|
+
this.CurrentUser = value;
|
|
105
|
+
}
|
|
106
|
+
/** @deprecated Use {@link CurrentUser}. */
|
|
107
|
+
get currentUser() {
|
|
108
|
+
return this.CurrentUser;
|
|
109
|
+
}
|
|
78
110
|
/** Master switch for all mention/command triggers. When false no providers are consulted. */
|
|
79
|
-
|
|
111
|
+
EnableMentions = true;
|
|
112
|
+
/** @deprecated Use {@link EnableMentions}. */
|
|
113
|
+
set enableMentions(value) {
|
|
114
|
+
this.EnableMentions = value;
|
|
115
|
+
}
|
|
116
|
+
/** @deprecated Use {@link EnableMentions}. */
|
|
117
|
+
get enableMentions() {
|
|
118
|
+
return this.EnableMentions;
|
|
119
|
+
}
|
|
80
120
|
/**
|
|
81
121
|
* Explicit trigger-provider list — when bound, EXACTLY these providers are active
|
|
82
122
|
* (explicit list wins over discovery). Leave null to discover providers registered
|
|
@@ -91,30 +131,182 @@ export class MentionEditorComponent {
|
|
|
91
131
|
/** Optional metadata provider scoping this editor (multi-provider hosts); passed through to trigger providers. */
|
|
92
132
|
Provider = null;
|
|
93
133
|
/** Auto-focus the editor after view init (the composer default). Disable when embedded in forms. */
|
|
94
|
-
|
|
134
|
+
AutoFocus = true;
|
|
135
|
+
/** @deprecated Use {@link AutoFocus}. */
|
|
136
|
+
set autoFocus(value) {
|
|
137
|
+
this.AutoFocus = value;
|
|
138
|
+
}
|
|
139
|
+
/** @deprecated Use {@link AutoFocus}. */
|
|
140
|
+
get autoFocus() {
|
|
141
|
+
return this.AutoFocus;
|
|
142
|
+
}
|
|
95
143
|
// Attachment settings
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
144
|
+
EnableAttachments = true;
|
|
145
|
+
/** @deprecated Use {@link EnableAttachments}. */
|
|
146
|
+
set enableAttachments(value) {
|
|
147
|
+
this.EnableAttachments = value;
|
|
148
|
+
}
|
|
149
|
+
/** @deprecated Use {@link EnableAttachments}. */
|
|
150
|
+
get enableAttachments() {
|
|
151
|
+
return this.EnableAttachments;
|
|
152
|
+
}
|
|
153
|
+
MaxAttachments = 10;
|
|
154
|
+
/** @deprecated Use {@link MaxAttachments}. */
|
|
155
|
+
set maxAttachments(value) {
|
|
156
|
+
this.MaxAttachments = value;
|
|
157
|
+
}
|
|
158
|
+
/** @deprecated Use {@link MaxAttachments}. */
|
|
159
|
+
get maxAttachments() {
|
|
160
|
+
return this.MaxAttachments;
|
|
161
|
+
}
|
|
162
|
+
MaxAttachmentSizeBytes = 20 * 1024 * 1024;
|
|
163
|
+
/** @deprecated Use {@link MaxAttachmentSizeBytes}. */
|
|
164
|
+
set maxAttachmentSizeBytes(value) {
|
|
165
|
+
this.MaxAttachmentSizeBytes = value;
|
|
166
|
+
}
|
|
167
|
+
/** @deprecated Use {@link MaxAttachmentSizeBytes}. */
|
|
168
|
+
get maxAttachmentSizeBytes() {
|
|
169
|
+
return this.MaxAttachmentSizeBytes;
|
|
170
|
+
} // 20MB default
|
|
171
|
+
AcceptedFileTypes = 'image/*';
|
|
172
|
+
/** @deprecated Use {@link AcceptedFileTypes}. */
|
|
173
|
+
set acceptedFileTypes(value) {
|
|
174
|
+
this.AcceptedFileTypes = value;
|
|
175
|
+
}
|
|
176
|
+
/** @deprecated Use {@link AcceptedFileTypes}. */
|
|
177
|
+
get acceptedFileTypes() {
|
|
178
|
+
return this.AcceptedFileTypes;
|
|
179
|
+
} // MIME types to accept
|
|
180
|
+
ValueChange = new EventEmitter();
|
|
181
|
+
/**
|
|
182
|
+
* @deprecated Use {@link ValueChange}.
|
|
183
|
+
*
|
|
184
|
+
* The same emitter under the old binding name, so a template still binding
|
|
185
|
+
* (valueChange) keeps working. Must stay AFTER ValueChange: class fields
|
|
186
|
+
* initialise in order, and the other way round this captures undefined.
|
|
187
|
+
*/
|
|
188
|
+
valueChange = this.ValueChange;
|
|
189
|
+
MentionSelected = new EventEmitter();
|
|
190
|
+
/**
|
|
191
|
+
* @deprecated Use {@link MentionSelected}.
|
|
192
|
+
*
|
|
193
|
+
* The same emitter under the old binding name, so a template still binding
|
|
194
|
+
* (mentionSelected) keeps working. Must stay AFTER MentionSelected: class fields
|
|
195
|
+
* initialise in order, and the other way round this captures undefined.
|
|
196
|
+
*/
|
|
197
|
+
mentionSelected = this.MentionSelected;
|
|
198
|
+
EnterPressed = new EventEmitter();
|
|
199
|
+
/**
|
|
200
|
+
* @deprecated Use {@link EnterPressed}.
|
|
201
|
+
*
|
|
202
|
+
* The same emitter under the old binding name, so a template still binding
|
|
203
|
+
* (enterPressed) keeps working. Must stay AFTER EnterPressed: class fields
|
|
204
|
+
* initialise in order, and the other way round this captures undefined.
|
|
205
|
+
*/
|
|
206
|
+
enterPressed = this.EnterPressed;
|
|
207
|
+
AttachmentsChanged = new EventEmitter();
|
|
208
|
+
/**
|
|
209
|
+
* @deprecated Use {@link AttachmentsChanged}.
|
|
210
|
+
*
|
|
211
|
+
* The same emitter under the old binding name, so a template still binding
|
|
212
|
+
* (attachmentsChanged) keeps working. Must stay AFTER AttachmentsChanged: class fields
|
|
213
|
+
* initialise in order, and the other way round this captures undefined.
|
|
214
|
+
*/
|
|
215
|
+
attachmentsChanged = this.AttachmentsChanged;
|
|
216
|
+
AttachmentError = new EventEmitter();
|
|
217
|
+
/**
|
|
218
|
+
* @deprecated Use {@link AttachmentError}.
|
|
219
|
+
*
|
|
220
|
+
* The same emitter under the old binding name, so a template still binding
|
|
221
|
+
* (attachmentError) keeps working. Must stay AFTER AttachmentError: class fields
|
|
222
|
+
* initialise in order, and the other way round this captures undefined.
|
|
223
|
+
*/
|
|
224
|
+
attachmentError = this.AttachmentError;
|
|
225
|
+
AttachmentClicked = new EventEmitter();
|
|
226
|
+
/**
|
|
227
|
+
* @deprecated Use {@link AttachmentClicked}.
|
|
228
|
+
*
|
|
229
|
+
* The same emitter under the old binding name, so a template still binding
|
|
230
|
+
* (attachmentClicked) keeps working. Must stay AFTER AttachmentClicked: class fields
|
|
231
|
+
* initialise in order, and the other way round this captures undefined.
|
|
232
|
+
*/
|
|
233
|
+
attachmentClicked = this.AttachmentClicked;
|
|
106
234
|
/** Fires when the contenteditable loses focus (hosts persist drafts on this). */
|
|
107
|
-
|
|
235
|
+
EditorBlurred = new EventEmitter();
|
|
236
|
+
/**
|
|
237
|
+
* @deprecated Use {@link EditorBlurred}.
|
|
238
|
+
*
|
|
239
|
+
* The same emitter under the old binding name, so a template still binding
|
|
240
|
+
* (editorBlurred) keeps working. Must stay AFTER EditorBlurred: class fields
|
|
241
|
+
* initialise in order, and the other way round this captures undefined.
|
|
242
|
+
*/
|
|
243
|
+
editorBlurred = this.EditorBlurred;
|
|
108
244
|
// Pending attachments state
|
|
109
|
-
|
|
110
|
-
|
|
245
|
+
PendingAttachments = [];
|
|
246
|
+
/** @deprecated Use {@link PendingAttachments}. */
|
|
247
|
+
get pendingAttachments() {
|
|
248
|
+
return this.PendingAttachments;
|
|
249
|
+
}
|
|
250
|
+
/** @deprecated Use {@link PendingAttachments}. */
|
|
251
|
+
set pendingAttachments(value) {
|
|
252
|
+
this.PendingAttachments = value;
|
|
253
|
+
}
|
|
254
|
+
IsDragOver = false;
|
|
255
|
+
/** @deprecated Use {@link IsDragOver}. */
|
|
256
|
+
get isDragOver() {
|
|
257
|
+
return this.IsDragOver;
|
|
258
|
+
}
|
|
259
|
+
/** @deprecated Use {@link IsDragOver}. */
|
|
260
|
+
set isDragOver(value) {
|
|
261
|
+
this.IsDragOver = value;
|
|
262
|
+
}
|
|
111
263
|
// Mention dropdown state
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
264
|
+
ShowMentionDropdown = false;
|
|
265
|
+
/** @deprecated Use {@link ShowMentionDropdown}. */
|
|
266
|
+
get showMentionDropdown() {
|
|
267
|
+
return this.ShowMentionDropdown;
|
|
268
|
+
}
|
|
269
|
+
/** @deprecated Use {@link ShowMentionDropdown}. */
|
|
270
|
+
set showMentionDropdown(value) {
|
|
271
|
+
this.ShowMentionDropdown = value;
|
|
272
|
+
}
|
|
273
|
+
MentionSuggestions = [];
|
|
274
|
+
/** @deprecated Use {@link MentionSuggestions}. */
|
|
275
|
+
get mentionSuggestions() {
|
|
276
|
+
return this.MentionSuggestions;
|
|
277
|
+
}
|
|
278
|
+
/** @deprecated Use {@link MentionSuggestions}. */
|
|
279
|
+
set mentionSuggestions(value) {
|
|
280
|
+
this.MentionSuggestions = value;
|
|
281
|
+
}
|
|
282
|
+
MentionDropdownPosition = { top: 0, left: 0 };
|
|
283
|
+
/** @deprecated Use {@link MentionDropdownPosition}. */
|
|
284
|
+
get mentionDropdownPosition() {
|
|
285
|
+
return this.MentionDropdownPosition;
|
|
286
|
+
}
|
|
287
|
+
/** @deprecated Use {@link MentionDropdownPosition}. */
|
|
288
|
+
set mentionDropdownPosition(value) {
|
|
289
|
+
this.MentionDropdownPosition = value;
|
|
290
|
+
}
|
|
291
|
+
MentionDropdownShowAbove = false;
|
|
292
|
+
/** @deprecated Use {@link MentionDropdownShowAbove}. */
|
|
293
|
+
get mentionDropdownShowAbove() {
|
|
294
|
+
return this.MentionDropdownShowAbove;
|
|
295
|
+
}
|
|
296
|
+
/** @deprecated Use {@link MentionDropdownShowAbove}. */
|
|
297
|
+
set mentionDropdownShowAbove(value) {
|
|
298
|
+
this.MentionDropdownShowAbove = value;
|
|
299
|
+
}
|
|
116
300
|
/** Right-align the dropdown against its anchor. Only the button path sets this. */
|
|
117
|
-
|
|
301
|
+
MentionDropdownAlignRight = false;
|
|
302
|
+
/** @deprecated Use {@link MentionDropdownAlignRight}. */
|
|
303
|
+
get mentionDropdownAlignRight() {
|
|
304
|
+
return this.MentionDropdownAlignRight;
|
|
305
|
+
}
|
|
306
|
+
/** @deprecated Use {@link MentionDropdownAlignRight}. */
|
|
307
|
+
set mentionDropdownAlignRight(value) {
|
|
308
|
+
this.MentionDropdownAlignRight = value;
|
|
309
|
+
}
|
|
118
310
|
mentionStartIndex = -1;
|
|
119
311
|
mentionQuery = '';
|
|
120
312
|
/** The trigger char that opened the current mention dropdown */
|
|
@@ -145,7 +337,7 @@ export class MentionEditorComponent {
|
|
|
145
337
|
*/
|
|
146
338
|
suggestionRequestSeq = 0;
|
|
147
339
|
/** Cap on the suggestions displayed; passed to providers as `MaxResults`. */
|
|
148
|
-
static
|
|
340
|
+
static maxSuggestions = 50;
|
|
149
341
|
/**
|
|
150
342
|
* The trigger providers this editor consults: the explicit `TriggerProviders` list
|
|
151
343
|
* when bound, otherwise ClassFactory discovery filtered by `ExcludedTriggerKeys`.
|
|
@@ -153,7 +345,7 @@ export class MentionEditorComponent {
|
|
|
153
345
|
* behaves as a plain text editor.
|
|
154
346
|
*/
|
|
155
347
|
get activeProviders() {
|
|
156
|
-
if (!this.
|
|
348
|
+
if (!this.EnableMentions) {
|
|
157
349
|
return [];
|
|
158
350
|
}
|
|
159
351
|
return this.TriggerProviders ?? DiscoverComposerTriggerProviders(this.ExcludedTriggerKeys);
|
|
@@ -169,7 +361,15 @@ export class MentionEditorComponent {
|
|
|
169
361
|
return triggers;
|
|
170
362
|
}
|
|
171
363
|
onChange = () => { };
|
|
172
|
-
|
|
364
|
+
OnTouched = () => { };
|
|
365
|
+
/** @deprecated Use {@link OnTouched}. */
|
|
366
|
+
get onTouched() {
|
|
367
|
+
return this.OnTouched;
|
|
368
|
+
}
|
|
369
|
+
/** @deprecated Use {@link OnTouched}. */
|
|
370
|
+
set onTouched(value) {
|
|
371
|
+
this.OnTouched = value;
|
|
372
|
+
}
|
|
173
373
|
/** Value written via writeValue() before the view (editorRef) exists — applied in ngAfterViewInit. */
|
|
174
374
|
pendingWriteValue = null;
|
|
175
375
|
constructor(cdr, hostRef) {
|
|
@@ -196,21 +396,21 @@ export class MentionEditorComponent {
|
|
|
196
396
|
// hundreds of ms, and without this the user's dismissing click is ignored and the menu pops
|
|
197
397
|
// open afterwards, unbidden. closeMentionDropdown bumps the request sequence, which drops the
|
|
198
398
|
// in-flight response.
|
|
199
|
-
if (!this.
|
|
399
|
+
if (!this.ShowMentionDropdown && !this.virtualTriggerOpen) {
|
|
200
400
|
return;
|
|
201
401
|
}
|
|
202
402
|
const target = event.target;
|
|
203
403
|
if (target && this.hostRef.nativeElement.contains(target)) {
|
|
204
404
|
return;
|
|
205
405
|
}
|
|
206
|
-
this.
|
|
406
|
+
this.CloseMentionDropdown();
|
|
207
407
|
this.cdr.markForCheck();
|
|
208
408
|
}
|
|
209
409
|
async ngOnInit() {
|
|
210
410
|
// Warm up the active providers (best-effort — a provider that fails to warm
|
|
211
411
|
// simply serves its first real request cold).
|
|
212
|
-
if (this.
|
|
213
|
-
const user = this.
|
|
412
|
+
if (this.EnableMentions) {
|
|
413
|
+
const user = this.CurrentUser ?? null;
|
|
214
414
|
await Promise.all(this.activeProviders.map((p) => p.Initialize(user).catch(() => undefined)));
|
|
215
415
|
}
|
|
216
416
|
}
|
|
@@ -222,18 +422,18 @@ export class MentionEditorComponent {
|
|
|
222
422
|
this.pendingWriteValue = null;
|
|
223
423
|
}
|
|
224
424
|
// Auto-focus the editor
|
|
225
|
-
if (this.
|
|
425
|
+
if (this.AutoFocus) {
|
|
226
426
|
setTimeout(() => {
|
|
227
|
-
this.
|
|
427
|
+
this.EditorRef?.nativeElement?.focus();
|
|
228
428
|
}, 100);
|
|
229
429
|
}
|
|
230
430
|
}
|
|
231
431
|
/**
|
|
232
432
|
* Handle clicks on the container - focus the editor if clicking outside the contentEditable
|
|
233
433
|
*/
|
|
234
|
-
|
|
434
|
+
OnContainerClick(event) {
|
|
235
435
|
const target = event.target;
|
|
236
|
-
const editor = this.
|
|
436
|
+
const editor = this.EditorRef?.nativeElement;
|
|
237
437
|
// Don't handle clicks on the dropdown or its children
|
|
238
438
|
if (target.closest('mj-mention-dropdown')) {
|
|
239
439
|
return;
|
|
@@ -252,39 +452,51 @@ export class MentionEditorComponent {
|
|
|
252
452
|
}
|
|
253
453
|
}
|
|
254
454
|
}
|
|
455
|
+
/** @deprecated Use {@link OnContainerClick}. */
|
|
456
|
+
onContainerClick(event) {
|
|
457
|
+
return this.OnContainerClick(event);
|
|
458
|
+
}
|
|
255
459
|
/**
|
|
256
460
|
* Handle input changes in contentEditable
|
|
257
461
|
*/
|
|
258
|
-
|
|
462
|
+
OnInput() {
|
|
259
463
|
const plainText = this.getPlainText();
|
|
260
464
|
this.onChange(plainText);
|
|
261
|
-
this.
|
|
465
|
+
this.ValueChange.emit(plainText);
|
|
262
466
|
// Handle mention/command autocomplete via the active trigger providers
|
|
263
|
-
if (this.
|
|
467
|
+
if (this.EnableMentions) {
|
|
264
468
|
this.handleMentionInput();
|
|
265
469
|
}
|
|
266
470
|
}
|
|
471
|
+
/** @deprecated Use {@link OnInput}. */
|
|
472
|
+
onInput() {
|
|
473
|
+
return this.OnInput();
|
|
474
|
+
}
|
|
267
475
|
/**
|
|
268
476
|
* Handle blur event - close dropdown when editor loses focus
|
|
269
477
|
*/
|
|
270
|
-
|
|
478
|
+
OnBlur() {
|
|
271
479
|
// Call form control touched callback
|
|
272
|
-
this.
|
|
273
|
-
this.
|
|
480
|
+
this.OnTouched();
|
|
481
|
+
this.EditorBlurred.emit();
|
|
274
482
|
// Close dropdown when editor loses focus
|
|
275
483
|
// Use setTimeout to allow mousedown events on dropdown to fire first
|
|
276
484
|
setTimeout(() => {
|
|
277
|
-
if (this.
|
|
278
|
-
this.
|
|
485
|
+
if (this.ShowMentionDropdown || this.virtualTriggerOpen) {
|
|
486
|
+
this.CloseMentionDropdown();
|
|
279
487
|
}
|
|
280
488
|
}, 200);
|
|
281
489
|
}
|
|
490
|
+
/** @deprecated Use {@link OnBlur}. */
|
|
491
|
+
onBlur() {
|
|
492
|
+
return this.OnBlur();
|
|
493
|
+
}
|
|
282
494
|
/**
|
|
283
495
|
* Handle paste event - images or plain text
|
|
284
496
|
*/
|
|
285
|
-
|
|
497
|
+
OnPaste(event) {
|
|
286
498
|
// Check for image data in clipboard
|
|
287
|
-
if (this.
|
|
499
|
+
if (this.EnableAttachments && event.clipboardData?.items) {
|
|
288
500
|
const items = Array.from(event.clipboardData.items);
|
|
289
501
|
const imageItems = items.filter(item => item.type.startsWith('image/'));
|
|
290
502
|
if (imageItems.length > 0) {
|
|
@@ -320,24 +532,28 @@ export class MentionEditorComponent {
|
|
|
320
532
|
selection.removeAllRanges();
|
|
321
533
|
selection.addRange(range);
|
|
322
534
|
// Trigger input event to update model
|
|
323
|
-
this.
|
|
535
|
+
this.OnInput();
|
|
536
|
+
}
|
|
537
|
+
/** @deprecated Use {@link OnPaste}. */
|
|
538
|
+
onPaste(event) {
|
|
539
|
+
return this.OnPaste(event);
|
|
324
540
|
}
|
|
325
541
|
/**
|
|
326
542
|
* Handle keydown events
|
|
327
543
|
*/
|
|
328
|
-
|
|
544
|
+
OnKeyDown(event) {
|
|
329
545
|
// Enter alone: Send message. The dropdown only earns Enter when it has something to pick. A
|
|
330
546
|
// button-opened menu stays open on an empty result set (so the press is not a silent no-op),
|
|
331
547
|
// which made "showing but empty" reachable for the first time — and there Enter was neither
|
|
332
548
|
// handled nor prevented, so it fell through to the contenteditable and inserted a newline
|
|
333
549
|
// instead of sending.
|
|
334
|
-
if (event.key === 'Enter' && !event.shiftKey && (!this.
|
|
550
|
+
if (event.key === 'Enter' && !event.shiftKey && (!this.ShowMentionDropdown || this.MentionSuggestions.length === 0)) {
|
|
335
551
|
event.preventDefault();
|
|
336
|
-
if (this.
|
|
337
|
-
this.
|
|
552
|
+
if (this.ShowMentionDropdown) {
|
|
553
|
+
this.CloseMentionDropdown();
|
|
338
554
|
}
|
|
339
555
|
const plainText = this.getPlainText();
|
|
340
|
-
this.
|
|
556
|
+
this.EnterPressed.emit(plainText);
|
|
341
557
|
return;
|
|
342
558
|
}
|
|
343
559
|
// Backspace: Check if deleting a mention chip
|
|
@@ -345,11 +561,15 @@ export class MentionEditorComponent {
|
|
|
345
561
|
this.handleBackspace(event);
|
|
346
562
|
}
|
|
347
563
|
// Handle mention dropdown navigation
|
|
348
|
-
if (this.
|
|
564
|
+
if (this.ShowMentionDropdown) {
|
|
349
565
|
// Let the dropdown handle arrow keys, enter, escape
|
|
350
566
|
// (We'll pass these through to mention-dropdown component)
|
|
351
567
|
}
|
|
352
568
|
}
|
|
569
|
+
/** @deprecated Use {@link OnKeyDown}. */
|
|
570
|
+
onKeyDown(event) {
|
|
571
|
+
return this.OnKeyDown(event);
|
|
572
|
+
}
|
|
353
573
|
/**
|
|
354
574
|
* Handle mention/command trigger detection — finds the nearest active trigger char
|
|
355
575
|
* before the cursor and kicks off the (async) provider suggestion fetch.
|
|
@@ -360,7 +580,7 @@ export class MentionEditorComponent {
|
|
|
360
580
|
return;
|
|
361
581
|
const activeTriggers = this.mentionTriggers;
|
|
362
582
|
if (activeTriggers.length === 0) {
|
|
363
|
-
this.
|
|
583
|
+
this.CloseMentionDropdown();
|
|
364
584
|
return;
|
|
365
585
|
}
|
|
366
586
|
const range = selection.getRangeAt(0);
|
|
@@ -393,13 +613,13 @@ export class MentionEditorComponent {
|
|
|
393
613
|
return;
|
|
394
614
|
}
|
|
395
615
|
}
|
|
396
|
-
this.
|
|
616
|
+
this.CloseMentionDropdown();
|
|
397
617
|
return;
|
|
398
618
|
}
|
|
399
619
|
// Check if there's a space between the trigger and cursor (means mention was completed)
|
|
400
620
|
const textAfterTrigger = textBeforeCursor.substring(triggerIndex + 1);
|
|
401
621
|
if (textAfterTrigger.includes(' ')) {
|
|
402
|
-
this.
|
|
622
|
+
this.CloseMentionDropdown();
|
|
403
623
|
return;
|
|
404
624
|
}
|
|
405
625
|
// A real trigger character now owns the session, so the virtual one must let go: otherwise
|
|
@@ -409,7 +629,7 @@ export class MentionEditorComponent {
|
|
|
409
629
|
this.virtualTriggerOpen = false;
|
|
410
630
|
this.virtualTriggerBaseline = 0;
|
|
411
631
|
this.virtualTriggerAnchor = null;
|
|
412
|
-
this.
|
|
632
|
+
this.MentionDropdownAlignRight = false;
|
|
413
633
|
}
|
|
414
634
|
// Extract query
|
|
415
635
|
this.mentionQuery = textAfterTrigger;
|
|
@@ -428,18 +648,18 @@ export class MentionEditorComponent {
|
|
|
428
648
|
const providers = this.activeProviders.filter((p) => p.TriggerChar === triggerChar);
|
|
429
649
|
const request = {
|
|
430
650
|
Query: query,
|
|
431
|
-
MaxResults: MentionEditorComponent.
|
|
432
|
-
ContextUser: this.
|
|
651
|
+
MaxResults: MentionEditorComponent.maxSuggestions,
|
|
652
|
+
ContextUser: this.CurrentUser ?? null,
|
|
433
653
|
Provider: this.Provider
|
|
434
654
|
};
|
|
435
655
|
const resultSets = await Promise.all(providers.map((p) => p.GetSuggestions(request).catch(() => [])));
|
|
436
656
|
if (seq !== this.suggestionRequestSeq) {
|
|
437
657
|
return; // superseded by a newer keystroke or an explicit close
|
|
438
658
|
}
|
|
439
|
-
const merged = resultSets.flat().slice(0, MentionEditorComponent.
|
|
440
|
-
this.
|
|
659
|
+
const merged = resultSets.flat().slice(0, MentionEditorComponent.maxSuggestions);
|
|
660
|
+
this.MentionSuggestions = merged;
|
|
441
661
|
if (merged.length > 0) {
|
|
442
|
-
this.
|
|
662
|
+
this.ShowMentionDropdown = true;
|
|
443
663
|
this.positionMentionDropdown();
|
|
444
664
|
}
|
|
445
665
|
else if (this.virtualTriggerOpen) {
|
|
@@ -447,11 +667,11 @@ export class MentionEditorComponent {
|
|
|
447
667
|
// trigger (the user is mid-word and nothing matched yet), but a host with zero skills clicking
|
|
448
668
|
// the button would get no feedback at all and read it as broken. Staying open surfaces the
|
|
449
669
|
// dropdown's own empty state, which was otherwise unreachable.
|
|
450
|
-
this.
|
|
670
|
+
this.ShowMentionDropdown = true;
|
|
451
671
|
this.positionMentionDropdown();
|
|
452
672
|
}
|
|
453
673
|
else {
|
|
454
|
-
this.
|
|
674
|
+
this.CloseMentionDropdown();
|
|
455
675
|
}
|
|
456
676
|
this.cdr.detectChanges();
|
|
457
677
|
}
|
|
@@ -460,7 +680,7 @@ export class MentionEditorComponent {
|
|
|
460
680
|
*/
|
|
461
681
|
getTextBeforeCursor(range) {
|
|
462
682
|
const tempRange = range.cloneRange();
|
|
463
|
-
tempRange.selectNodeContents(this.
|
|
683
|
+
tempRange.selectNodeContents(this.EditorRef.nativeElement);
|
|
464
684
|
tempRange.setEnd(range.startContainer, range.startOffset);
|
|
465
685
|
return tempRange.toString();
|
|
466
686
|
}
|
|
@@ -468,7 +688,7 @@ export class MentionEditorComponent {
|
|
|
468
688
|
* Position the mention dropdown
|
|
469
689
|
*/
|
|
470
690
|
positionMentionDropdown() {
|
|
471
|
-
const editor = this.
|
|
691
|
+
const editor = this.EditorRef?.nativeElement;
|
|
472
692
|
if (!editor)
|
|
473
693
|
return;
|
|
474
694
|
// Get the parent container (message-input-box-container) for alignment
|
|
@@ -498,22 +718,22 @@ export class MentionEditorComponent {
|
|
|
498
718
|
// Check space below vs above
|
|
499
719
|
const spaceBelow = window.innerHeight - cursorRect.bottom;
|
|
500
720
|
const spaceAbove = cursorRect.top;
|
|
501
|
-
const dropdownHeight = Math.min(this.
|
|
721
|
+
const dropdownHeight = Math.min(this.MentionSuggestions.length * 56, 300);
|
|
502
722
|
// Prefer ABOVE. The composer sits at the bottom of the chat, so a dropdown that grows downward
|
|
503
723
|
// lands on top of the very text being typed. Below is the fallback for the rare host that
|
|
504
724
|
// mounts the composer high in a tall viewport.
|
|
505
|
-
this.
|
|
506
|
-
this.
|
|
507
|
-
if (this.
|
|
725
|
+
this.MentionDropdownAlignRight = false;
|
|
726
|
+
this.MentionDropdownShowAbove = spaceAbove >= dropdownHeight || spaceAbove > spaceBelow;
|
|
727
|
+
if (this.MentionDropdownShowAbove) {
|
|
508
728
|
// Position above, aligning with container top if possible
|
|
509
|
-
this.
|
|
729
|
+
this.MentionDropdownPosition = {
|
|
510
730
|
top: (containerRect ? containerRect.top : cursorRect.top) + window.scrollY - 8,
|
|
511
731
|
left: cursorRect.left + window.scrollX
|
|
512
732
|
};
|
|
513
733
|
}
|
|
514
734
|
else {
|
|
515
735
|
// Position below cursor, but align bottom edge with container top
|
|
516
|
-
this.
|
|
736
|
+
this.MentionDropdownPosition = {
|
|
517
737
|
top: containerRect ? containerRect.top + window.scrollY : cursorRect.bottom + window.scrollY + 4,
|
|
518
738
|
left: cursorRect.left + window.scrollX
|
|
519
739
|
};
|
|
@@ -542,7 +762,7 @@ export class MentionEditorComponent {
|
|
|
542
762
|
// which is what a menu anchored to a right-hand control needs.
|
|
543
763
|
const assumedWidth = Math.min(400, window.innerWidth - GUTTER * 2);
|
|
544
764
|
const overflowsRight = rect.left + assumedWidth > window.innerWidth - GUTTER;
|
|
545
|
-
this.
|
|
765
|
+
this.MentionDropdownAlignRight = overflowsRight;
|
|
546
766
|
// align-right shifts the box back by its own width, so `left` is then its RIGHT edge; otherwise
|
|
547
767
|
// `left` is its left edge. Clamp both forms inside the gutter.
|
|
548
768
|
//
|
|
@@ -562,14 +782,14 @@ export class MentionEditorComponent {
|
|
|
562
782
|
// Not unconditional: `show-above` lifts the box by its own height, so forcing it where there is
|
|
563
783
|
// no room renders it off the top of the viewport where it cannot be reached.
|
|
564
784
|
const anchorTop = containerRect ? containerRect.top : rect.top;
|
|
565
|
-
const dropdownHeight = Math.min(Math.max(this.
|
|
785
|
+
const dropdownHeight = Math.min(Math.max(this.MentionSuggestions.length, 1) * 56, 300);
|
|
566
786
|
// Prefer above, but when it does not fit, take whichever side has MORE room rather than
|
|
567
787
|
// dropping below unconditionally — the composer is bottom-docked, so below is usually the worse
|
|
568
788
|
// side. In a short viewport (a popped-out chat, or mobile with the keyboard up) that difference
|
|
569
789
|
// is the whole menu versus a clipped sliver.
|
|
570
790
|
const spaceBelow = window.innerHeight - rect.bottom;
|
|
571
791
|
const showAbove = anchorTop >= dropdownHeight + GUTTER || anchorTop > spaceBelow;
|
|
572
|
-
this.
|
|
792
|
+
this.MentionDropdownShowAbove = showAbove;
|
|
573
793
|
// Above: `top` is the box's BOTTOM edge (the transform lifts it). Below: it is the top edge.
|
|
574
794
|
// Clamped either way, because dropdownHeight is an estimate (rows with descriptions run taller
|
|
575
795
|
// than 56px) and an underestimate would otherwise clip the first row off the top of the screen.
|
|
@@ -577,20 +797,24 @@ export class MentionEditorComponent {
|
|
|
577
797
|
const top = showAbove
|
|
578
798
|
? Math.max(GUTTER + dropdownHeight, Math.min(rawTop, window.innerHeight - GUTTER))
|
|
579
799
|
: Math.max(GUTTER, Math.min(rawTop, window.innerHeight - GUTTER - dropdownHeight));
|
|
580
|
-
this.
|
|
800
|
+
this.MentionDropdownPosition = { top, left };
|
|
581
801
|
}
|
|
582
802
|
/**
|
|
583
803
|
* Handle mention selection from dropdown
|
|
584
804
|
*/
|
|
585
|
-
|
|
805
|
+
OnMentionSelected(suggestion) {
|
|
586
806
|
this.insertMentionChip(suggestion);
|
|
587
|
-
this.
|
|
588
|
-
this.
|
|
807
|
+
this.CloseMentionDropdown();
|
|
808
|
+
this.MentionSelected.emit(suggestion);
|
|
589
809
|
// Refocus the editor after selection
|
|
590
810
|
setTimeout(() => {
|
|
591
|
-
this.
|
|
811
|
+
this.EditorRef?.nativeElement?.focus();
|
|
592
812
|
}, 50);
|
|
593
813
|
}
|
|
814
|
+
/** @deprecated Use {@link OnMentionSelected}. */
|
|
815
|
+
onMentionSelected(suggestion) {
|
|
816
|
+
return this.OnMentionSelected(suggestion);
|
|
817
|
+
}
|
|
594
818
|
/**
|
|
595
819
|
* Insert a mention chip at the current cursor position
|
|
596
820
|
*/
|
|
@@ -606,7 +830,7 @@ export class MentionEditorComponent {
|
|
|
606
830
|
*/
|
|
607
831
|
/** Focuses the editor and places the caret at the very end of its content. */
|
|
608
832
|
FocusCaretAtEnd() {
|
|
609
|
-
const editor = this.
|
|
833
|
+
const editor = this.EditorRef?.nativeElement;
|
|
610
834
|
if (!editor) {
|
|
611
835
|
return false;
|
|
612
836
|
}
|
|
@@ -637,8 +861,8 @@ export class MentionEditorComponent {
|
|
|
637
861
|
* @returns false when the editor is disabled, unavailable, or no active provider owns the char.
|
|
638
862
|
*/
|
|
639
863
|
OpenTrigger(triggerChar, anchorEl) {
|
|
640
|
-
const editor = this.
|
|
641
|
-
if (!editor || this.
|
|
864
|
+
const editor = this.EditorRef?.nativeElement;
|
|
865
|
+
if (!editor || this.Disabled) {
|
|
642
866
|
return false;
|
|
643
867
|
}
|
|
644
868
|
if (!this.mentionTriggers.includes(triggerChar)) {
|
|
@@ -674,15 +898,15 @@ export class MentionEditorComponent {
|
|
|
674
898
|
// virtualTriggerOpen covers the window between the press and the provider's response. Reporting
|
|
675
899
|
// "closed" there makes the second press of a quick double-click re-run the open path instead of
|
|
676
900
|
// toggling, re-emitting the Before/After pair.
|
|
677
|
-
return (this.
|
|
901
|
+
return (this.ShowMentionDropdown || this.virtualTriggerOpen) && this.activeTrigger === triggerChar;
|
|
678
902
|
}
|
|
679
903
|
/** True when keyboard focus currently sits inside this editor. */
|
|
680
904
|
get HasFocus() {
|
|
681
|
-
const editor = this.
|
|
905
|
+
const editor = this.EditorRef?.nativeElement;
|
|
682
906
|
return !!editor && (editor === document.activeElement || editor.contains(document.activeElement));
|
|
683
907
|
}
|
|
684
908
|
InsertMention(suggestion, focus = true) {
|
|
685
|
-
const editor = this.
|
|
909
|
+
const editor = this.EditorRef?.nativeElement;
|
|
686
910
|
if (!editor) {
|
|
687
911
|
return false;
|
|
688
912
|
}
|
|
@@ -708,7 +932,7 @@ export class MentionEditorComponent {
|
|
|
708
932
|
if (!focus) {
|
|
709
933
|
editor.blur();
|
|
710
934
|
}
|
|
711
|
-
this.
|
|
935
|
+
this.OnInput();
|
|
712
936
|
return true;
|
|
713
937
|
}
|
|
714
938
|
insertMentionChip(suggestion) {
|
|
@@ -741,7 +965,7 @@ export class MentionEditorComponent {
|
|
|
741
965
|
selection.removeAllRanges();
|
|
742
966
|
selection.addRange(range);
|
|
743
967
|
// Trigger change detection
|
|
744
|
-
this.
|
|
968
|
+
this.OnInput();
|
|
745
969
|
}
|
|
746
970
|
/**
|
|
747
971
|
* Create a mention chip DOM element
|
|
@@ -1082,33 +1306,37 @@ export class MentionEditorComponent {
|
|
|
1082
1306
|
if (prevNode && prevNode.classList?.contains('mention-chip')) {
|
|
1083
1307
|
event.preventDefault();
|
|
1084
1308
|
prevNode.remove();
|
|
1085
|
-
this.
|
|
1309
|
+
this.OnInput();
|
|
1086
1310
|
}
|
|
1087
1311
|
}
|
|
1088
1312
|
}
|
|
1089
1313
|
/**
|
|
1090
1314
|
* Close mention dropdown
|
|
1091
1315
|
*/
|
|
1092
|
-
|
|
1316
|
+
CloseMentionDropdown() {
|
|
1093
1317
|
// No text cleanup: a virtual trigger never wrote anything into the editor, which is the whole
|
|
1094
1318
|
// point of it. Dismissing leaves the message exactly as the user left it.
|
|
1095
1319
|
this.virtualTriggerOpen = false;
|
|
1096
1320
|
this.virtualTriggerBaseline = 0;
|
|
1097
1321
|
this.virtualTriggerAnchor = null;
|
|
1098
|
-
this.
|
|
1322
|
+
this.MentionDropdownAlignRight = false;
|
|
1099
1323
|
// Invalidate any in-flight suggestion fetch so a late response can't reopen the dropdown
|
|
1100
1324
|
this.suggestionRequestSeq++;
|
|
1101
|
-
this.
|
|
1102
|
-
this.
|
|
1325
|
+
this.ShowMentionDropdown = false;
|
|
1326
|
+
this.MentionSuggestions = [];
|
|
1103
1327
|
this.mentionStartIndex = -1;
|
|
1104
1328
|
this.mentionQuery = '';
|
|
1105
1329
|
this.activeTrigger = '@';
|
|
1106
1330
|
}
|
|
1331
|
+
/** @deprecated Use {@link CloseMentionDropdown}. */
|
|
1332
|
+
closeMentionDropdown() {
|
|
1333
|
+
return this.CloseMentionDropdown();
|
|
1334
|
+
}
|
|
1107
1335
|
/**
|
|
1108
1336
|
* Convert editor HTML to plain text with @mentions
|
|
1109
1337
|
*/
|
|
1110
1338
|
getPlainText() {
|
|
1111
|
-
const editor = this.
|
|
1339
|
+
const editor = this.EditorRef?.nativeElement;
|
|
1112
1340
|
if (!editor)
|
|
1113
1341
|
return '';
|
|
1114
1342
|
let text = '';
|
|
@@ -1180,7 +1408,7 @@ export class MentionEditorComponent {
|
|
|
1180
1408
|
* strings (no tokens) take the fast path.
|
|
1181
1409
|
*/
|
|
1182
1410
|
setEditorContent(text) {
|
|
1183
|
-
const editor = this.
|
|
1411
|
+
const editor = this.EditorRef?.nativeElement;
|
|
1184
1412
|
if (!editor)
|
|
1185
1413
|
return;
|
|
1186
1414
|
const segments = MentionEditorComponent.ParseSerializedMentions(text);
|
|
@@ -1290,7 +1518,7 @@ export class MentionEditorComponent {
|
|
|
1290
1518
|
}
|
|
1291
1519
|
// ControlValueAccessor implementation
|
|
1292
1520
|
writeValue(value) {
|
|
1293
|
-
const editor = this.
|
|
1521
|
+
const editor = this.EditorRef?.nativeElement;
|
|
1294
1522
|
if (!editor) {
|
|
1295
1523
|
// View not created yet — buffer the value; ngAfterViewInit applies it
|
|
1296
1524
|
this.pendingWriteValue = value ?? '';
|
|
@@ -1307,36 +1535,44 @@ export class MentionEditorComponent {
|
|
|
1307
1535
|
this.onChange = fn;
|
|
1308
1536
|
}
|
|
1309
1537
|
registerOnTouched(fn) {
|
|
1310
|
-
this.
|
|
1538
|
+
this.OnTouched = fn;
|
|
1311
1539
|
}
|
|
1312
1540
|
setDisabledState(isDisabled) {
|
|
1313
|
-
this.
|
|
1314
|
-
if (this.
|
|
1315
|
-
this.
|
|
1541
|
+
this.Disabled = isDisabled;
|
|
1542
|
+
if (this.EditorRef?.nativeElement) {
|
|
1543
|
+
this.EditorRef.nativeElement.contentEditable = (!isDisabled).toString();
|
|
1316
1544
|
}
|
|
1317
1545
|
}
|
|
1318
1546
|
/**
|
|
1319
1547
|
* Focus the editor
|
|
1320
1548
|
*/
|
|
1549
|
+
Focus() {
|
|
1550
|
+
this.EditorRef?.nativeElement?.focus();
|
|
1551
|
+
}
|
|
1552
|
+
/** @deprecated Use {@link Focus}. */
|
|
1321
1553
|
focus() {
|
|
1322
|
-
this.
|
|
1554
|
+
return this.Focus();
|
|
1323
1555
|
}
|
|
1324
1556
|
/**
|
|
1325
1557
|
* Clear the editor content and pending attachments
|
|
1326
1558
|
*/
|
|
1327
|
-
|
|
1328
|
-
if (this.
|
|
1329
|
-
this.
|
|
1330
|
-
this.
|
|
1559
|
+
Clear() {
|
|
1560
|
+
if (this.EditorRef?.nativeElement) {
|
|
1561
|
+
this.EditorRef.nativeElement.textContent = '';
|
|
1562
|
+
this.OnInput();
|
|
1331
1563
|
}
|
|
1332
|
-
this.
|
|
1564
|
+
this.ClearPendingAttachments();
|
|
1565
|
+
}
|
|
1566
|
+
/** @deprecated Use {@link Clear}. */
|
|
1567
|
+
clear() {
|
|
1568
|
+
return this.Clear();
|
|
1333
1569
|
}
|
|
1334
1570
|
/**
|
|
1335
1571
|
* Extract mention chips with their configuration data
|
|
1336
1572
|
* Returns array of objects containing mention info and preset configuration
|
|
1337
1573
|
*/
|
|
1338
|
-
|
|
1339
|
-
const editor = this.
|
|
1574
|
+
GetMentionChipsData() {
|
|
1575
|
+
const editor = this.EditorRef?.nativeElement;
|
|
1340
1576
|
if (!editor)
|
|
1341
1577
|
return [];
|
|
1342
1578
|
const chips = [];
|
|
@@ -1358,13 +1594,17 @@ export class MentionEditorComponent {
|
|
|
1358
1594
|
});
|
|
1359
1595
|
return chips;
|
|
1360
1596
|
}
|
|
1597
|
+
/** @deprecated Use {@link GetMentionChipsData}. */
|
|
1598
|
+
getMentionChipsData() {
|
|
1599
|
+
return this.GetMentionChipsData();
|
|
1600
|
+
}
|
|
1361
1601
|
/**
|
|
1362
1602
|
* Get the plain text value with mentions encoded as JSON
|
|
1363
1603
|
* This format preserves configuration information when messages are saved
|
|
1364
1604
|
* Format: @{type:"agent",id:"uuid",name:"Agent Name",configId:"uuid",config:"High"}
|
|
1365
1605
|
*/
|
|
1366
|
-
|
|
1367
|
-
const editor = this.
|
|
1606
|
+
GetPlainTextWithJsonMentions() {
|
|
1607
|
+
const editor = this.EditorRef?.nativeElement;
|
|
1368
1608
|
if (!editor)
|
|
1369
1609
|
return '';
|
|
1370
1610
|
let plainText = '';
|
|
@@ -1413,34 +1653,46 @@ export class MentionEditorComponent {
|
|
|
1413
1653
|
}
|
|
1414
1654
|
return plainText;
|
|
1415
1655
|
}
|
|
1656
|
+
/** @deprecated Use {@link GetPlainTextWithJsonMentions}. */
|
|
1657
|
+
getPlainTextWithJsonMentions() {
|
|
1658
|
+
return this.GetPlainTextWithJsonMentions();
|
|
1659
|
+
}
|
|
1416
1660
|
// ==================== Attachment Handling Methods ====================
|
|
1417
1661
|
/**
|
|
1418
1662
|
* Handle drag over event
|
|
1419
1663
|
*/
|
|
1420
|
-
|
|
1421
|
-
if (!this.
|
|
1664
|
+
OnDragOver(event) {
|
|
1665
|
+
if (!this.EnableAttachments)
|
|
1422
1666
|
return;
|
|
1423
1667
|
event.preventDefault();
|
|
1424
1668
|
event.stopPropagation();
|
|
1425
|
-
this.
|
|
1669
|
+
this.IsDragOver = true;
|
|
1670
|
+
}
|
|
1671
|
+
/** @deprecated Use {@link OnDragOver}. */
|
|
1672
|
+
onDragOver(event) {
|
|
1673
|
+
return this.OnDragOver(event);
|
|
1426
1674
|
}
|
|
1427
1675
|
/**
|
|
1428
1676
|
* Handle drag leave event
|
|
1429
1677
|
*/
|
|
1430
|
-
|
|
1678
|
+
OnDragLeave(event) {
|
|
1431
1679
|
event.preventDefault();
|
|
1432
1680
|
event.stopPropagation();
|
|
1433
|
-
this.
|
|
1681
|
+
this.IsDragOver = false;
|
|
1682
|
+
}
|
|
1683
|
+
/** @deprecated Use {@link OnDragLeave}. */
|
|
1684
|
+
onDragLeave(event) {
|
|
1685
|
+
return this.OnDragLeave(event);
|
|
1434
1686
|
}
|
|
1435
1687
|
/**
|
|
1436
1688
|
* Handle drop event
|
|
1437
1689
|
*/
|
|
1438
|
-
|
|
1439
|
-
if (!this.
|
|
1690
|
+
OnDrop(event) {
|
|
1691
|
+
if (!this.EnableAttachments)
|
|
1440
1692
|
return;
|
|
1441
1693
|
event.preventDefault();
|
|
1442
1694
|
event.stopPropagation();
|
|
1443
|
-
this.
|
|
1695
|
+
this.IsDragOver = false;
|
|
1444
1696
|
if (event.dataTransfer?.files) {
|
|
1445
1697
|
const files = Array.from(event.dataTransfer.files);
|
|
1446
1698
|
for (const file of files) {
|
|
@@ -1450,10 +1702,14 @@ export class MentionEditorComponent {
|
|
|
1450
1702
|
}
|
|
1451
1703
|
}
|
|
1452
1704
|
}
|
|
1705
|
+
/** @deprecated Use {@link OnDrop}. */
|
|
1706
|
+
onDrop(event) {
|
|
1707
|
+
return this.OnDrop(event);
|
|
1708
|
+
}
|
|
1453
1709
|
/**
|
|
1454
1710
|
* Handle file input change (from file picker)
|
|
1455
1711
|
*/
|
|
1456
|
-
|
|
1712
|
+
OnFileSelected(event) {
|
|
1457
1713
|
const input = event.target;
|
|
1458
1714
|
if (input.files) {
|
|
1459
1715
|
const files = Array.from(input.files);
|
|
@@ -1464,6 +1720,10 @@ export class MentionEditorComponent {
|
|
|
1464
1720
|
input.value = '';
|
|
1465
1721
|
}
|
|
1466
1722
|
}
|
|
1723
|
+
/** @deprecated Use {@link OnFileSelected}. */
|
|
1724
|
+
onFileSelected(event) {
|
|
1725
|
+
return this.OnFileSelected(event);
|
|
1726
|
+
}
|
|
1467
1727
|
/**
|
|
1468
1728
|
* Process a file for attachment
|
|
1469
1729
|
*/
|
|
@@ -1471,13 +1731,13 @@ export class MentionEditorComponent {
|
|
|
1471
1731
|
// Validate file
|
|
1472
1732
|
const validation = this.validateFile(file);
|
|
1473
1733
|
if (!validation.valid) {
|
|
1474
|
-
this.
|
|
1734
|
+
this.AttachmentError.emit(validation.error);
|
|
1475
1735
|
return;
|
|
1476
1736
|
}
|
|
1477
1737
|
// Read file as data URL
|
|
1478
1738
|
const dataUrl = await this.readFileAsDataUrl(file);
|
|
1479
1739
|
if (!dataUrl) {
|
|
1480
|
-
this.
|
|
1740
|
+
this.AttachmentError.emit('Failed to read file');
|
|
1481
1741
|
return;
|
|
1482
1742
|
}
|
|
1483
1743
|
// Get image dimensions if applicable
|
|
@@ -1501,8 +1761,8 @@ export class MentionEditorComponent {
|
|
|
1501
1761
|
thumbnailUrl: file.type.startsWith('image/') ? dataUrl : undefined
|
|
1502
1762
|
};
|
|
1503
1763
|
// Add to pending attachments
|
|
1504
|
-
this.
|
|
1505
|
-
this.
|
|
1764
|
+
this.PendingAttachments.push(attachment);
|
|
1765
|
+
this.AttachmentsChanged.emit([...this.PendingAttachments]);
|
|
1506
1766
|
this.cdr.detectChanges();
|
|
1507
1767
|
}
|
|
1508
1768
|
/**
|
|
@@ -1510,15 +1770,15 @@ export class MentionEditorComponent {
|
|
|
1510
1770
|
*/
|
|
1511
1771
|
validateFile(file) {
|
|
1512
1772
|
// Check count limit
|
|
1513
|
-
if (this.
|
|
1773
|
+
if (this.PendingAttachments.length >= this.MaxAttachments) {
|
|
1514
1774
|
return {
|
|
1515
1775
|
valid: false,
|
|
1516
|
-
error: `Maximum ${this.
|
|
1776
|
+
error: `Maximum ${this.MaxAttachments} attachments allowed`
|
|
1517
1777
|
};
|
|
1518
1778
|
}
|
|
1519
1779
|
// Check size limit
|
|
1520
|
-
if (file.size > this.
|
|
1521
|
-
const maxMB = (this.
|
|
1780
|
+
if (file.size > this.MaxAttachmentSizeBytes) {
|
|
1781
|
+
const maxMB = (this.MaxAttachmentSizeBytes / (1024 * 1024)).toFixed(1);
|
|
1522
1782
|
const fileMB = (file.size / (1024 * 1024)).toFixed(1);
|
|
1523
1783
|
return {
|
|
1524
1784
|
valid: false,
|
|
@@ -1538,10 +1798,10 @@ export class MentionEditorComponent {
|
|
|
1538
1798
|
* Check if file type is accepted
|
|
1539
1799
|
*/
|
|
1540
1800
|
isAcceptedFile(file) {
|
|
1541
|
-
if (this.
|
|
1801
|
+
if (this.AcceptedFileTypes === '*' || this.AcceptedFileTypes === '*/*') {
|
|
1542
1802
|
return true;
|
|
1543
1803
|
}
|
|
1544
|
-
const acceptedTypes = this.
|
|
1804
|
+
const acceptedTypes = this.AcceptedFileTypes.split(',').map(t => t.trim());
|
|
1545
1805
|
for (const accepted of acceptedTypes) {
|
|
1546
1806
|
// Handle universal wildcard */* anywhere in the list
|
|
1547
1807
|
if (accepted === '*/*') {
|
|
@@ -1602,19 +1862,27 @@ export class MentionEditorComponent {
|
|
|
1602
1862
|
/**
|
|
1603
1863
|
* Remove a pending attachment by ID
|
|
1604
1864
|
*/
|
|
1605
|
-
|
|
1606
|
-
const index = this.
|
|
1865
|
+
RemoveAttachment(id) {
|
|
1866
|
+
const index = this.PendingAttachments.findIndex(a => a.id === id);
|
|
1607
1867
|
if (index !== -1) {
|
|
1608
|
-
this.
|
|
1609
|
-
this.
|
|
1868
|
+
this.PendingAttachments.splice(index, 1);
|
|
1869
|
+
this.AttachmentsChanged.emit([...this.PendingAttachments]);
|
|
1610
1870
|
this.cdr.detectChanges();
|
|
1611
1871
|
}
|
|
1612
1872
|
}
|
|
1873
|
+
/** @deprecated Use {@link RemoveAttachment}. */
|
|
1874
|
+
removeAttachment(id) {
|
|
1875
|
+
return this.RemoveAttachment(id);
|
|
1876
|
+
}
|
|
1613
1877
|
/**
|
|
1614
1878
|
* Get all pending attachments
|
|
1615
1879
|
*/
|
|
1880
|
+
GetPendingAttachments() {
|
|
1881
|
+
return [...this.PendingAttachments];
|
|
1882
|
+
}
|
|
1883
|
+
/** @deprecated Use {@link GetPendingAttachments}. */
|
|
1616
1884
|
getPendingAttachments() {
|
|
1617
|
-
return
|
|
1885
|
+
return this.GetPendingAttachments();
|
|
1618
1886
|
}
|
|
1619
1887
|
/**
|
|
1620
1888
|
* Add an artifact as a pending attachment programmatically.
|
|
@@ -1632,51 +1900,67 @@ export class MentionEditorComponent {
|
|
|
1632
1900
|
source: 'artifact',
|
|
1633
1901
|
artifactVersionId: artifact.artifactVersionId
|
|
1634
1902
|
};
|
|
1635
|
-
this.
|
|
1636
|
-
this.
|
|
1903
|
+
this.PendingAttachments.push(attachment);
|
|
1904
|
+
this.AttachmentsChanged.emit([...this.PendingAttachments]);
|
|
1637
1905
|
return attachment;
|
|
1638
1906
|
}
|
|
1639
1907
|
/**
|
|
1640
1908
|
* Clear all pending attachments
|
|
1641
1909
|
*/
|
|
1642
|
-
|
|
1643
|
-
this.
|
|
1644
|
-
this.
|
|
1910
|
+
ClearPendingAttachments() {
|
|
1911
|
+
this.PendingAttachments = [];
|
|
1912
|
+
this.AttachmentsChanged.emit([]);
|
|
1645
1913
|
this.cdr.detectChanges();
|
|
1646
1914
|
}
|
|
1915
|
+
/** @deprecated Use {@link ClearPendingAttachments}. */
|
|
1916
|
+
clearPendingAttachments() {
|
|
1917
|
+
return this.ClearPendingAttachments();
|
|
1918
|
+
}
|
|
1647
1919
|
/**
|
|
1648
1920
|
* Handle click on an attachment thumbnail
|
|
1649
1921
|
*/
|
|
1922
|
+
OnAttachmentClick(attachment) {
|
|
1923
|
+
this.AttachmentClicked.emit(attachment);
|
|
1924
|
+
}
|
|
1925
|
+
/** @deprecated Use {@link OnAttachmentClick}. */
|
|
1650
1926
|
onAttachmentClick(attachment) {
|
|
1651
|
-
this.
|
|
1927
|
+
return this.OnAttachmentClick(attachment);
|
|
1652
1928
|
}
|
|
1653
1929
|
/**
|
|
1654
1930
|
* Check if there are any pending attachments
|
|
1655
1931
|
*/
|
|
1932
|
+
HasAttachments() {
|
|
1933
|
+
return this.PendingAttachments.length > 0;
|
|
1934
|
+
}
|
|
1935
|
+
/** @deprecated Use {@link HasAttachments}. */
|
|
1656
1936
|
hasAttachments() {
|
|
1657
|
-
return this.
|
|
1937
|
+
return this.HasAttachments();
|
|
1658
1938
|
}
|
|
1659
1939
|
/**
|
|
1660
1940
|
* Trigger file picker programmatically
|
|
1661
1941
|
*/
|
|
1662
|
-
|
|
1942
|
+
OpenFilePicker() {
|
|
1663
1943
|
const input = document.createElement('input');
|
|
1664
1944
|
input.type = 'file';
|
|
1665
1945
|
// If */* is in the list, accept all files (some browsers don't handle */* correctly)
|
|
1666
|
-
input.accept = this.
|
|
1946
|
+
input.accept = this.AcceptedFileTypes.includes('*/*') ? '' : this.AcceptedFileTypes;
|
|
1667
1947
|
input.multiple = true;
|
|
1668
|
-
input.onchange = (e) => this.
|
|
1948
|
+
input.onchange = (e) => this.OnFileSelected(e);
|
|
1669
1949
|
input.click();
|
|
1670
1950
|
}
|
|
1951
|
+
/** @deprecated Use {@link OpenFilePicker}. */
|
|
1952
|
+
openFilePicker() {
|
|
1953
|
+
return this.OpenFilePicker();
|
|
1954
|
+
}
|
|
1671
1955
|
static ɵfac = function MentionEditorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MentionEditorComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef)); };
|
|
1672
1956
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MentionEditorComponent, selectors: [["mj-mention-editor"]], viewQuery: function MentionEditorComponent_Query(rf, ctx) { if (rf & 1) {
|
|
1673
1957
|
i0.ɵɵviewQuery(_c0, 5);
|
|
1674
1958
|
} if (rf & 2) {
|
|
1675
1959
|
let _t;
|
|
1676
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.
|
|
1960
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.EditorRef = _t.first);
|
|
1677
1961
|
} }, hostBindings: function MentionEditorComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
1678
1962
|
i0.ɵɵlistener("mousedown", function MentionEditorComponent_mousedown_HostBindingHandler($event) { return ctx.onDocumentMouseDown($event); }, i0.ɵɵresolveDocument);
|
|
1679
|
-
} }, inputs: { placeholder: "placeholder", disabled: "disabled", currentUser: "currentUser", enableMentions: "enableMentions", TriggerProviders: "TriggerProviders", ExcludedTriggerKeys: "ExcludedTriggerKeys", Provider: "Provider", autoFocus: "autoFocus", enableAttachments: "enableAttachments", maxAttachments: "maxAttachments", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", acceptedFileTypes: "acceptedFileTypes" }, outputs: { valueChange: "valueChange", mentionSelected: "mentionSelected", enterPressed: "enterPressed", attachmentsChanged: "attachmentsChanged", attachmentError: "attachmentError", attachmentClicked: "attachmentClicked", editorBlurred: "editorBlurred" }, standalone: false, features: [i0.ɵɵProvidersFeature([
|
|
1963
|
+
} }, inputs: { Placeholder: "Placeholder", placeholder: "placeholder", Disabled: "Disabled", disabled: "disabled", CurrentUser: "CurrentUser", currentUser: "currentUser", EnableMentions: "EnableMentions", enableMentions: "enableMentions", TriggerProviders: "TriggerProviders", ExcludedTriggerKeys: "ExcludedTriggerKeys", Provider: "Provider", AutoFocus: "AutoFocus", autoFocus: "autoFocus", EnableAttachments: "EnableAttachments", enableAttachments: "enableAttachments", MaxAttachments: "MaxAttachments", maxAttachments: "maxAttachments", MaxAttachmentSizeBytes: "MaxAttachmentSizeBytes", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", AcceptedFileTypes: "AcceptedFileTypes", acceptedFileTypes: "acceptedFileTypes" }, outputs: { ValueChange: "ValueChange", valueChange: "valueChange", MentionSelected: "MentionSelected", mentionSelected: "mentionSelected", EnterPressed: "EnterPressed", enterPressed: "enterPressed", AttachmentsChanged: "AttachmentsChanged", attachmentsChanged: "attachmentsChanged", AttachmentError: "AttachmentError", attachmentError: "attachmentError", AttachmentClicked: "AttachmentClicked", attachmentClicked: "attachmentClicked", EditorBlurred: "EditorBlurred", editorBlurred: "editorBlurred" }, standalone: false, features: [i0.ɵɵProvidersFeature([
|
|
1680
1964
|
{
|
|
1681
1965
|
provide: NG_VALUE_ACCESSOR,
|
|
1682
1966
|
useExisting: forwardRef(() => MentionEditorComponent),
|
|
@@ -1713,15 +1997,23 @@ export class MentionEditorComponent {
|
|
|
1713
1997
|
multi: true
|
|
1714
1998
|
}
|
|
1715
1999
|
], template: "<div class=\"mention-editor-container\"\n [class.drag-over]=\"isDragOver\"\n (click)=\"onContainerClick($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n\n <!-- Pending Attachments Preview -->\n @if (pendingAttachments.length > 0) {\n <div class=\"pending-attachments\">\n @for (attachment of pendingAttachments; track attachment) {\n <div class=\"attachment-thumbnail\"\n (click)=\"onAttachmentClick(attachment)\">\n @if (attachment.thumbnailUrl) {\n <img\n [src]=\"attachment.thumbnailUrl\"\n [alt]=\"attachment.fileName\"\n class=\"thumbnail-image\">\n }\n @if (!attachment.thumbnailUrl) {\n <div class=\"thumbnail-placeholder\">\n <i class=\"fa-solid fa-file\"></i>\n <span class=\"file-name\">{{ attachment.fileName }}</span>\n </div>\n }\n <button class=\"remove-attachment\"\n (click)=\"removeAttachment(attachment.id); $event.stopPropagation()\"\n title=\"Remove attachment\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n </div>\n }\n\n <div\n #editor\n class=\"mention-editor\"\n contenteditable=\"true\"\n [attr.contenteditable]=\"!disabled\"\n [attr.data-placeholder]=\"placeholder\"\n (input)=\"onInput()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n (paste)=\"onPaste($event)\"\n ></div>\n\n <!-- Drag & Drop Overlay -->\n @if (isDragOver) {\n <div class=\"drop-overlay\">\n <div class=\"drop-message\">\n <i class=\"fa-solid fa-cloud-arrow-up\"></i>\n <span>Drop files here</span>\n </div>\n </div>\n }\n\n <!-- Mention Dropdown -->\n @if (showMentionDropdown && enableMentions) {\n <mj-mention-dropdown\n [suggestions]=\"mentionSuggestions\"\n [position]=\"mentionDropdownPosition\"\n [showAbove]=\"mentionDropdownShowAbove\"\n [alignRight]=\"mentionDropdownAlignRight\"\n [useFixedPositioning]=\"true\"\n [visible]=\"true\"\n (suggestionSelected)=\"onMentionSelected($event)\"\n (closed)=\"closeMentionDropdown()\">\n </mj-mention-dropdown>\n }\n</div>\n", styles: [".mention-editor-container {\n position: relative;\n width: 100%;\n display: block;\n}\n\n.mention-editor-container.drag-over {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--mj-brand-primary);\n}\n\n.mention-editor {\n display: block;\n width: 100%;\n min-height: 100px;\n max-height: 300px;\n padding: 7px 3.5rem 7px 12px;\n outline: none;\n border: none;\n background: transparent;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n overflow-y: auto;\n overflow-x: hidden;\n word-wrap: break-word;\n white-space: pre-wrap;\n cursor: text;\n user-select: text;\n box-sizing: border-box;\n}\n.mention-editor:empty:before {\n content: attr(data-placeholder);\n color: var(--mj-text-muted);\n pointer-events: none;\n position: absolute;\n}\n.mention-editor:focus {\n outline: none;\n}\n.mention-editor[contenteditable=false] {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--mj-bg-surface-sunken);\n}\n@media (max-width: 768px) {\n .mention-editor {\n font-size: 16px;\n padding: 5px;\n padding-right: 3rem;\n }\n}\n\n::ng-deep .mention-chip {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 4px 12px;\n margin: 0 3px;\n border-radius: 16px;\n font-size: 13px;\n font-weight: 600;\n cursor: default;\n user-select: none;\n vertical-align: middle;\n white-space: nowrap;\n pointer-events: all;\n -webkit-user-modify: read-only;\n -moz-user-modify: read-only;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n box-shadow: var(--mj-shadow-md);\n animation: chipInsert 0.15s ease-out;\n}\n::ng-deep .mention-chip i {\n font-size: 12px;\n opacity: 0.95;\n}\n::ng-deep .mention-chip[data-mention-type=user] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n::ng-deep .mention-chip:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-lg);\n transition: all 0.2s ease;\n}\n::ng-deep .mention-chip:focus, ::ng-deep .mention-chip.selected {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n@keyframes chipInsert {\n 0% {\n transform: scale(0.8);\n opacity: 0;\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n.mention-editor .mention-chip + .mention-chip {\n margin-left: 4px;\n}\n.mention-editor br {\n display: block;\n content: \"\";\n margin: 0;\n}\n\n.mention-editor::-webkit-scrollbar {\n width: 6px;\n}\n.mention-editor::-webkit-scrollbar-track {\n background: transparent;\n}\n.mention-editor::-webkit-scrollbar-thumb {\n background: color-mix(in srgb, var(--mj-text-primary) 20%, transparent);\n border-radius: 3px;\n}\n.mention-editor::-webkit-scrollbar-thumb:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n}\n\n/* ==================== Attachment Styles ==================== */\n\n.pending-attachments {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, transparent);\n}\n\n.attachment-thumbnail {\n position: relative;\n width: 80px;\n height: 80px;\n border-radius: 8px;\n overflow: hidden;\n cursor: pointer;\n transition: transform 0.2s, box-shadow 0.2s;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n}\n\n.attachment-thumbnail:hover {\n transform: scale(1.05);\n box-shadow: var(--mj-shadow-lg);\n}\n\n.thumbnail-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.thumbnail-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 8px;\n color: var(--mj-text-secondary);\n}\n\n.thumbnail-placeholder i {\n font-size: 24px;\n margin-bottom: 4px;\n color: var(--mj-text-muted);\n}\n\n.thumbnail-placeholder .file-name {\n font-size: 10px;\n text-align: center;\n word-break: break-all;\n line-height: 1.2;\n max-height: 36px;\n overflow: hidden;\n}\n\n.remove-attachment {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-text-primary) 60%, transparent);\n color: var(--mj-text-inverse);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.2s, background 0.2s;\n}\n\n.attachment-thumbnail:hover .remove-attachment {\n opacity: 1;\n}\n\n.remove-attachment:hover {\n background: color-mix(in srgb, var(--mj-status-error) 90%, transparent);\n}\n\n.remove-attachment i {\n font-size: 10px;\n}\n\n/* Drop Overlay */\n.drop-overlay {\n position: absolute;\n inset: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n backdrop-filter: blur(2px);\n border: 2px dashed var(--mj-brand-primary);\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 100;\n pointer-events: none;\n}\n\n.drop-message {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.drop-message i {\n font-size: 32px;\n}\n\n.drop-message span {\n font-size: 14px;\n}\n"] }]
|
|
1716
|
-
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], {
|
|
2000
|
+
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], { EditorRef: [{
|
|
1717
2001
|
type: ViewChild,
|
|
1718
2002
|
args: ['editor', { static: false }]
|
|
2003
|
+
}], Placeholder: [{
|
|
2004
|
+
type: Input
|
|
1719
2005
|
}], placeholder: [{
|
|
1720
2006
|
type: Input
|
|
2007
|
+
}], Disabled: [{
|
|
2008
|
+
type: Input
|
|
1721
2009
|
}], disabled: [{
|
|
1722
2010
|
type: Input
|
|
2011
|
+
}], CurrentUser: [{
|
|
2012
|
+
type: Input
|
|
1723
2013
|
}], currentUser: [{
|
|
1724
2014
|
type: Input
|
|
2015
|
+
}], EnableMentions: [{
|
|
2016
|
+
type: Input
|
|
1725
2017
|
}], enableMentions: [{
|
|
1726
2018
|
type: Input
|
|
1727
2019
|
}], TriggerProviders: [{
|
|
@@ -1730,28 +2022,52 @@ export class MentionEditorComponent {
|
|
|
1730
2022
|
type: Input
|
|
1731
2023
|
}], Provider: [{
|
|
1732
2024
|
type: Input
|
|
2025
|
+
}], AutoFocus: [{
|
|
2026
|
+
type: Input
|
|
1733
2027
|
}], autoFocus: [{
|
|
1734
2028
|
type: Input
|
|
2029
|
+
}], EnableAttachments: [{
|
|
2030
|
+
type: Input
|
|
1735
2031
|
}], enableAttachments: [{
|
|
1736
2032
|
type: Input
|
|
2033
|
+
}], MaxAttachments: [{
|
|
2034
|
+
type: Input
|
|
1737
2035
|
}], maxAttachments: [{
|
|
1738
2036
|
type: Input
|
|
2037
|
+
}], MaxAttachmentSizeBytes: [{
|
|
2038
|
+
type: Input
|
|
1739
2039
|
}], maxAttachmentSizeBytes: [{
|
|
1740
2040
|
type: Input
|
|
2041
|
+
}], AcceptedFileTypes: [{
|
|
2042
|
+
type: Input
|
|
1741
2043
|
}], acceptedFileTypes: [{
|
|
1742
2044
|
type: Input
|
|
2045
|
+
}], ValueChange: [{
|
|
2046
|
+
type: Output
|
|
1743
2047
|
}], valueChange: [{
|
|
1744
2048
|
type: Output
|
|
2049
|
+
}], MentionSelected: [{
|
|
2050
|
+
type: Output
|
|
1745
2051
|
}], mentionSelected: [{
|
|
1746
2052
|
type: Output
|
|
2053
|
+
}], EnterPressed: [{
|
|
2054
|
+
type: Output
|
|
1747
2055
|
}], enterPressed: [{
|
|
1748
2056
|
type: Output
|
|
2057
|
+
}], AttachmentsChanged: [{
|
|
2058
|
+
type: Output
|
|
1749
2059
|
}], attachmentsChanged: [{
|
|
1750
2060
|
type: Output
|
|
2061
|
+
}], AttachmentError: [{
|
|
2062
|
+
type: Output
|
|
1751
2063
|
}], attachmentError: [{
|
|
1752
2064
|
type: Output
|
|
2065
|
+
}], AttachmentClicked: [{
|
|
2066
|
+
type: Output
|
|
1753
2067
|
}], attachmentClicked: [{
|
|
1754
2068
|
type: Output
|
|
2069
|
+
}], EditorBlurred: [{
|
|
2070
|
+
type: Output
|
|
1755
2071
|
}], editorBlurred: [{
|
|
1756
2072
|
type: Output
|
|
1757
2073
|
}], onDocumentMouseDown: [{
|