@syncfusion/ej2-inputs 31.1.17 → 31.1.20
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/ej2-inputs.min.js +2 -2
- package/dist/ej2-inputs.umd.min.js +2 -2
- package/dist/ej2-inputs.umd.min.js.map +1 -1
- package/dist/es6/ej2-inputs.es2015.js +4 -3
- package/dist/es6/ej2-inputs.es2015.js.map +1 -1
- package/dist/es6/ej2-inputs.es5.js +4 -3
- package/dist/es6/ej2-inputs.es5.js.map +1 -1
- package/dist/global/ej2-inputs.min.js +2 -2
- package/dist/global/ej2-inputs.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/package.json +10 -60
- package/src/color-picker/color-picker.js +4 -3
- package/styles/bootstrap4-lite.css +2 -2
- package/styles/bootstrap4.css +2 -2
- package/styles/bootstrap5-dark-lite.css +2 -2
- package/styles/bootstrap5-dark.css +2 -2
- package/styles/bootstrap5-lite.css +2 -2
- package/styles/bootstrap5.css +2 -2
- package/styles/input/_bootstrap4-definition.scss +1 -1
- package/styles/input/_bootstrap5-definition.scss +1 -1
- package/styles/input/bootstrap4.css +2 -2
- package/styles/input/bootstrap5-dark.css +2 -2
- package/styles/input/bootstrap5.css +2 -2
- package/dist/ts/color-picker/color-picker-model.d.ts +0 -186
- package/dist/ts/color-picker/color-picker.d.ts +0 -398
- package/dist/ts/color-picker/color-picker.ts +0 -2209
- package/dist/ts/color-picker/index.d.ts +0 -5
- package/dist/ts/color-picker/index.ts +0 -5
- package/dist/ts/common/index.d.ts +0 -4
- package/dist/ts/common/index.ts +0 -4
- package/dist/ts/common/signature-base.d.ts +0 -340
- package/dist/ts/common/signature-base.ts +0 -1170
- package/dist/ts/form-validator/form-validator-model.d.ts +0 -121
- package/dist/ts/form-validator/form-validator.d.ts +0 -312
- package/dist/ts/form-validator/form-validator.ts +0 -1068
- package/dist/ts/form-validator/index.d.ts +0 -5
- package/dist/ts/form-validator/index.ts +0 -5
- package/dist/ts/index.d.ts +0 -18
- package/dist/ts/index.ts +0 -18
- package/dist/ts/input/index.d.ts +0 -4
- package/dist/ts/input/index.ts +0 -4
- package/dist/ts/input/input.d.ts +0 -345
- package/dist/ts/input/input.ts +0 -1277
- package/dist/ts/maskedtextbox/base/index.d.ts +0 -4
- package/dist/ts/maskedtextbox/base/index.ts +0 -4
- package/dist/ts/maskedtextbox/base/mask-base.d.ts +0 -134
- package/dist/ts/maskedtextbox/base/mask-base.ts +0 -1207
- package/dist/ts/maskedtextbox/index.d.ts +0 -5
- package/dist/ts/maskedtextbox/index.ts +0 -5
- package/dist/ts/maskedtextbox/maskedtextbox/index.d.ts +0 -5
- package/dist/ts/maskedtextbox/maskedtextbox/index.ts +0 -5
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox-model.d.ts +0 -167
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.d.ts +0 -307
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.ts +0 -709
- package/dist/ts/numerictextbox/index.d.ts +0 -5
- package/dist/ts/numerictextbox/index.ts +0 -5
- package/dist/ts/numerictextbox/numerictextbox-model.d.ts +0 -228
- package/dist/ts/numerictextbox/numerictextbox.d.ts +0 -431
- package/dist/ts/numerictextbox/numerictextbox.ts +0 -1672
- package/dist/ts/otp-input/index.d.ts +0 -5
- package/dist/ts/otp-input/index.ts +0 -5
- package/dist/ts/otp-input/otp-input-model.d.ts +0 -165
- package/dist/ts/otp-input/otp-input.d.ts +0 -365
- package/dist/ts/otp-input/otp-input.ts +0 -924
- package/dist/ts/rating/index.d.ts +0 -5
- package/dist/ts/rating/index.ts +0 -5
- package/dist/ts/rating/rating-model.d.ts +0 -239
- package/dist/ts/rating/rating.d.ts +0 -416
- package/dist/ts/rating/rating.ts +0 -1101
- package/dist/ts/signature/index.d.ts +0 -5
- package/dist/ts/signature/index.ts +0 -5
- package/dist/ts/signature/signature-model.d.ts +0 -131
- package/dist/ts/signature/signature.d.ts +0 -167
- package/dist/ts/signature/signature.ts +0 -266
- package/dist/ts/slider/index.d.ts +0 -5
- package/dist/ts/slider/index.ts +0 -5
- package/dist/ts/slider/slider-model.d.ts +0 -401
- package/dist/ts/slider/slider.d.ts +0 -721
- package/dist/ts/slider/slider.ts +0 -3497
- package/dist/ts/smart-textarea/caret-helper.d.ts +0 -17
- package/dist/ts/smart-textarea/caret-helper.ts +0 -95
- package/dist/ts/smart-textarea/index.d.ts +0 -5
- package/dist/ts/smart-textarea/index.ts +0 -5
- package/dist/ts/smart-textarea/smart-textarea-model.d.ts +0 -44
- package/dist/ts/smart-textarea/smart-textarea.d.ts +0 -80
- package/dist/ts/smart-textarea/smart-textarea.ts +0 -518
- package/dist/ts/speech-to-text/index.d.ts +0 -5
- package/dist/ts/speech-to-text/index.ts +0 -5
- package/dist/ts/speech-to-text/speech-to-text-model.d.ts +0 -270
- package/dist/ts/speech-to-text/speech-to-text.d.ts +0 -487
- package/dist/ts/speech-to-text/speech-to-text.ts +0 -1008
- package/dist/ts/textarea/index.d.ts +0 -5
- package/dist/ts/textarea/index.ts +0 -5
- package/dist/ts/textarea/textarea-model.d.ts +0 -161
- package/dist/ts/textarea/textarea.d.ts +0 -237
- package/dist/ts/textarea/textarea.ts +0 -812
- package/dist/ts/textbox/index.d.ts +0 -5
- package/dist/ts/textbox/index.ts +0 -5
- package/dist/ts/textbox/textbox-model.d.ts +0 -155
- package/dist/ts/textbox/textbox.d.ts +0 -288
- package/dist/ts/textbox/textbox.ts +0 -872
- package/dist/ts/uploader/index.d.ts +0 -5
- package/dist/ts/uploader/index.ts +0 -5
- package/dist/ts/uploader/uploader-model.d.ts +0 -555
- package/dist/ts/uploader/uploader.d.ts +0 -1216
- package/dist/ts/uploader/uploader.ts +0 -4391
|
@@ -1,518 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
2
|
-
///<reference path='../textarea/textarea-model.d.ts'/>
|
|
3
|
-
import { EventHandler, Property, createElement } from '@syncfusion/ej2-base';
|
|
4
|
-
import { TextArea } from '../textarea/textarea';
|
|
5
|
-
import { CaretPosition, CaretPositionHelper } from './caret-helper';
|
|
6
|
-
import { SmartTextAreaModel } from './smart-textarea-model';
|
|
7
|
-
|
|
8
|
-
export interface ChatParameters {
|
|
9
|
-
messages: ChatMessage[];
|
|
10
|
-
temperature?: number;
|
|
11
|
-
maxTokens?: number;
|
|
12
|
-
stopSequences: string[];
|
|
13
|
-
frequencyPenalty?: number;
|
|
14
|
-
presencePenalty?: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export enum ChatMessageRole {
|
|
18
|
-
System = 'system',
|
|
19
|
-
User = 'user',
|
|
20
|
-
Assistant = 'assistant',
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ChatMessage {
|
|
24
|
-
role: ChatMessageRole;
|
|
25
|
-
content: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type SuggestionMode = 'Enable' | 'Disable' | 'None';
|
|
29
|
-
|
|
30
|
-
export class SmartTextArea extends TextArea {
|
|
31
|
-
private pendingSuggestionAbort: any;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Represents the user's role or designation, which can be used to provide role-specific suggestions or content within the smart textarea.
|
|
35
|
-
* Provide a string that describes who is typing and for what reason, optionally giving other contextual information.
|
|
36
|
-
*
|
|
37
|
-
* @default ''
|
|
38
|
-
*/
|
|
39
|
-
@Property('')
|
|
40
|
-
public userRole: string;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Specifies a collection of phrases commonly used by the user, which can be leveraged for auto-completion and suggestions.
|
|
44
|
-
* Provide an array of string phrases commonly used by the user to enhance auto-completion and suggestions. Include preferred tone, voice, and any relevant information such as policies, URLs, or keywords for improved suggestions.
|
|
45
|
-
*
|
|
46
|
-
* @default []
|
|
47
|
-
*/
|
|
48
|
-
@Property([])
|
|
49
|
-
public UserPhrases: string[];
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Callback function to get suggestion text from server to display smart suggestion.
|
|
53
|
-
*
|
|
54
|
-
* @returns {string}
|
|
55
|
-
*/
|
|
56
|
-
@Property()
|
|
57
|
-
public aiSuggestionHandler: Function;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Specifies whether suggestions should appear in a popup or inline within the text area.
|
|
61
|
-
* possible values are:
|
|
62
|
-
* * `Enable` - Suggestions are always shown as a floating overlay, which can be tapped or clicked.
|
|
63
|
-
* * `Disable` - Suggestions are always shown inline and can be accepted by pressing `Tab` key.
|
|
64
|
-
* * `None` - Touch devices display suggestions as an overlay, while non-touch devices use inline suggestions.
|
|
65
|
-
*
|
|
66
|
-
* @default None
|
|
67
|
-
*/
|
|
68
|
-
@Property('None')
|
|
69
|
-
public showSuggestionOnPopup: SuggestionMode;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Constructor for creating the widget
|
|
73
|
-
*
|
|
74
|
-
* @private
|
|
75
|
-
* @param {SmartTextArea} options - Specifies Smart text area model
|
|
76
|
-
* @param {string | HTMLTextAreaElement} element - Specifies target element
|
|
77
|
-
*/
|
|
78
|
-
public constructor(options?: SmartTextAreaModel, element?: string | HTMLTextAreaElement) {
|
|
79
|
-
super(options, <string | HTMLTextAreaElement>element);
|
|
80
|
-
}
|
|
81
|
-
private textArea: HTMLTextAreaElement;
|
|
82
|
-
private suggestionDisplay: InlineSuggestion | ContextSuggestion;
|
|
83
|
-
private typingDebounceTimeout: any;
|
|
84
|
-
|
|
85
|
-
public render(): void {
|
|
86
|
-
super.render();
|
|
87
|
-
if (!(this.element instanceof HTMLTextAreaElement)) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
this.textArea = this.element;
|
|
91
|
-
const smartTextArea: HTMLElement = createElement('smart-textarea');
|
|
92
|
-
smartTextArea.classList.add('e-smart-textarea');
|
|
93
|
-
this.textArea.after(smartTextArea);
|
|
94
|
-
if (this.showSuggestionOnPopup !== 'None') {
|
|
95
|
-
const suggestionState: string = this.showSuggestionOnPopup === 'Enable' ? 'false' : 'true';
|
|
96
|
-
this.textArea.setAttribute('data-inline-suggestions', suggestionState);
|
|
97
|
-
}
|
|
98
|
-
this.suggestionDisplay = this.shouldShowInlineSuggestions(this.textArea) ?
|
|
99
|
-
new InlineSuggestion(smartTextArea, this.textArea) : new ContextSuggestion(smartTextArea, this.textArea);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
protected wireEvents(): void {
|
|
103
|
-
super.wireEvents();
|
|
104
|
-
EventHandler.add(this.element, 'keyup', this.handleKeyUp, this);
|
|
105
|
-
EventHandler.add(this.element, 'keydown', this.handleKeyDown, this);
|
|
106
|
-
EventHandler.add(this.element, 'mousedown', this.removeExistingOrPendingSuggestion, this);
|
|
107
|
-
EventHandler.add(this.element, 'focusout', this.removeExistingOrPendingSuggestion, this);
|
|
108
|
-
this.element.addEventListener('scroll', (() => this.suggestionDisplay.reject()), {
|
|
109
|
-
passive: true
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
protected unWireEvents(): void {
|
|
114
|
-
super.unWireEvents();
|
|
115
|
-
EventHandler.remove(this.element, 'keyup', this.handleKeyUp);
|
|
116
|
-
EventHandler.remove(this.element, 'keydown', this.handleKeyDown);
|
|
117
|
-
EventHandler.remove(this.element, 'mousedown', this.removeExistingOrPendingSuggestion);
|
|
118
|
-
EventHandler.remove(this.element, 'focusout', this.removeExistingOrPendingSuggestion);
|
|
119
|
-
this.element.removeEventListener('scroll', (() => this.suggestionDisplay.reject()));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
protected keydownHandler (): void {
|
|
123
|
-
// Overridden to prevent default behavior
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private shouldShowInlineSuggestions(textArea: any): boolean {
|
|
127
|
-
const inlineSuggestions: string | null = textArea.getAttribute('data-inline-suggestions');
|
|
128
|
-
if (inlineSuggestions) {
|
|
129
|
-
return inlineSuggestions.toLowerCase() === 'true';
|
|
130
|
-
}
|
|
131
|
-
return !('ontouchstart' in window);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private handleKeyDown(event: any): void {
|
|
135
|
-
switch (event.key) {
|
|
136
|
-
case 'Tab':
|
|
137
|
-
if (this.suggestionDisplay.isShowing()) {
|
|
138
|
-
this.suggestionDisplay.accept();
|
|
139
|
-
event.preventDefault();
|
|
140
|
-
}
|
|
141
|
-
break;
|
|
142
|
-
case 'Alt':
|
|
143
|
-
case 'Control':
|
|
144
|
-
case 'Shift':
|
|
145
|
-
case 'Command':
|
|
146
|
-
break;
|
|
147
|
-
default:
|
|
148
|
-
if (this.suggestionDisplay.isShowing() && this.suggestionDisplay.currentSuggestion.startsWith(event.key)) {
|
|
149
|
-
CaretPositionHelper.insertCharacter(this.textArea, event.key);
|
|
150
|
-
event.preventDefault();
|
|
151
|
-
this.suggestionDisplay.show(this.suggestionDisplay.currentSuggestion.substring(event.key.length));
|
|
152
|
-
CaretPositionHelper.adjustScrollToCaretPosition(this.textArea);
|
|
153
|
-
} else {
|
|
154
|
-
this.removeExistingOrPendingSuggestion();
|
|
155
|
-
}
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private handleKeyUp(): void {
|
|
161
|
-
if (!this.suggestionDisplay.isShowing()) {
|
|
162
|
-
clearTimeout(this.typingDebounceTimeout);
|
|
163
|
-
this.typingDebounceTimeout = setTimeout(() => this.handleTypingPaused(), 350);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
private async handleTypingPaused(): Promise<void> {
|
|
168
|
-
if (document.activeElement !== this.textArea) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (this.textArea.selectionStart === this.textArea.selectionEnd &&
|
|
172
|
-
(this.textArea.selectionStart === this.textArea.value.length ||
|
|
173
|
-
this.textArea.value[this.textArea.selectionStart] === '\n')) {
|
|
174
|
-
await this.requestSuggestionAsync();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
private removeExistingOrPendingSuggestion(): void {
|
|
179
|
-
clearTimeout(this.typingDebounceTimeout);
|
|
180
|
-
if (this.pendingSuggestionAbort) {
|
|
181
|
-
this.pendingSuggestionAbort.abort();
|
|
182
|
-
this.pendingSuggestionAbort = null;
|
|
183
|
-
}
|
|
184
|
-
this.suggestionDisplay.reject();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private createSuggestionPrompt(textBefore: string, textAfter: string): ChatParameters {
|
|
188
|
-
let stringBuilder: string = 'Predict what text the user in the given ROLE would insert at the cursor position indicated by ^^^.\nOnly give predictions for which you have' +
|
|
189
|
-
' an EXTREMELY high confidence that the user would insert that EXACT text.\nDo not make up new information. If you are not sure, ' +
|
|
190
|
-
'just reply with NO_PREDICTION.\n\nRULES:\n1. Reply with OK:, then in square brackets the predicted text, then END_INSERTION, and no other output.\n2. ' +
|
|
191
|
-
'When a specific value or quantity cannot be inferred and would need to be provided, use the word NEED_INFO.\n3. ' +
|
|
192
|
-
'If there is not enough information to predict any words that the user would type next, just reply with the word NO_PREDICTION.' +
|
|
193
|
-
'\n4. NEVER invent new information. If you can not be sure what the user is about to type, ALWAYS stop the prediction with END_INSERTION.';
|
|
194
|
-
const userPhrases: string[] = this.UserPhrases;
|
|
195
|
-
if (userPhrases && userPhrases.length > 0) {
|
|
196
|
-
stringBuilder += '\nAlways try to use variations on the following phrases as part of the predictions:\n';
|
|
197
|
-
for (const phrase of userPhrases) {
|
|
198
|
-
stringBuilder += `- ${phrase}\n`;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const chatMessageList: ChatMessage[] = [
|
|
202
|
-
{ role: ChatMessageRole.System, content: stringBuilder },
|
|
203
|
-
{ role: ChatMessageRole.User, content: 'ROLE: Family member sending a text\nUSER_TEXT: Hey, it is a nice day - the weather is ^^^' },
|
|
204
|
-
{ role: ChatMessageRole.Assistant, content: 'OK:[great!]END_INSERTION' },
|
|
205
|
-
{ role: ChatMessageRole.User, content: 'ROLE: Customer service assistant\nUSER_TEXT: You can find more information on^^^\n\nAlternatively, phone us.' },
|
|
206
|
-
{ role: ChatMessageRole.Assistant, content: 'OK:[ our website at NEED_INFO]END_INSERTION' },
|
|
207
|
-
{ role: ChatMessageRole.User, content: 'ROLE: Casual\nUSER_TEXT: Oh I see!\n\nWell sure thing, we can' },
|
|
208
|
-
{ role: ChatMessageRole.Assistant, content: 'OK:[ help you out with that!]END_INSERTION' },
|
|
209
|
-
{ role: ChatMessageRole.User, content: 'ROLE: Storyteller\nUSER_TEXT: Sir Digby Chicken Caesar, also know^^^' },
|
|
210
|
-
{ role: ChatMessageRole.Assistant, content: 'OK:[n as NEED_INFO]END_INSERTION' },
|
|
211
|
-
{ role: ChatMessageRole.User, content: 'ROLE: Customer support agent\nUSER_TEXT: Goodbye for now.^^^' },
|
|
212
|
-
{ role: ChatMessageRole.Assistant, content: 'NO_PREDICTION END_INSERTION' },
|
|
213
|
-
{ role: ChatMessageRole.User, content: 'ROLE: Pirate\nUSER_TEXT: Have you found^^^' },
|
|
214
|
-
{ role: ChatMessageRole.Assistant, content: 'OK:[ the treasure, me hearties?]END_INSERTION' },
|
|
215
|
-
{ role: ChatMessageRole.User, content: `ROLE: ${this.userRole}\nUSER_TEXT: ${textBefore}^^^${textAfter}` }
|
|
216
|
-
];
|
|
217
|
-
return {
|
|
218
|
-
messages: chatMessageList,
|
|
219
|
-
temperature: 0.0,
|
|
220
|
-
maxTokens: 400,
|
|
221
|
-
stopSequences: ['END_INSERTION', 'NEED_INFO'],
|
|
222
|
-
frequencyPenalty: 0.0,
|
|
223
|
-
presencePenalty: 0.0
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
private async requestSuggestionAsync(): Promise<void> {
|
|
228
|
-
if (this.pendingSuggestionAbort) {
|
|
229
|
-
this.pendingSuggestionAbort.abort();
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
this.pendingSuggestionAbort = new AbortController();
|
|
233
|
-
const requestDetails: { textAreaValue: string; cursorPosition: number } = {
|
|
234
|
-
textAreaValue: this.textArea.value,
|
|
235
|
-
cursorPosition: this.textArea.selectionStart
|
|
236
|
-
};
|
|
237
|
-
const suggestionData: {[key: string]: string} = {
|
|
238
|
-
textBefore: requestDetails.textAreaValue.substring(0, requestDetails.cursorPosition),
|
|
239
|
-
textAfter: requestDetails.textAreaValue.substring(requestDetails.cursorPosition)
|
|
240
|
-
};
|
|
241
|
-
const chatConfig: ChatParameters = this.createSuggestionPrompt(suggestionData.textBefore, suggestionData.textAfter);
|
|
242
|
-
let insertSuggestion: string;
|
|
243
|
-
if (typeof this.aiSuggestionHandler === 'function') {
|
|
244
|
-
const response: string = await this.aiSuggestionHandler(chatConfig);
|
|
245
|
-
insertSuggestion = this.validateSuggestion(response, suggestionData.textBefore);
|
|
246
|
-
}
|
|
247
|
-
if (insertSuggestion && requestDetails.textAreaValue === this.textArea.value &&
|
|
248
|
-
requestDetails.cursorPosition === this.textArea.selectionStart) {
|
|
249
|
-
if (!insertSuggestion.endsWith(' ')) {
|
|
250
|
-
insertSuggestion += ' ';
|
|
251
|
-
}
|
|
252
|
-
this.suggestionDisplay.show(insertSuggestion);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
private validateSuggestion(response: string, textBefore: string): string {
|
|
257
|
-
let suggestion: string;
|
|
258
|
-
if (typeof response !== 'string' || response.length <= 5 || response.indexOf('OK:[') !== 0) {
|
|
259
|
-
return '';
|
|
260
|
-
}
|
|
261
|
-
const endIndex: number = this.indexOfAny(response, ['.', '?', '!']);
|
|
262
|
-
if (endIndex > 0 && response.length > endIndex + 1 && response[endIndex + 1] === ' ') {
|
|
263
|
-
response = response.substring(0, endIndex + 1);
|
|
264
|
-
}
|
|
265
|
-
suggestion = response.substring(4).replace(/[\]\s]+$/, '');
|
|
266
|
-
if (textBefore.length > 0 && textBefore[textBefore.length - 1] === ' ') {
|
|
267
|
-
suggestion = suggestion.replace(/^\s+/, '');
|
|
268
|
-
}
|
|
269
|
-
return suggestion;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
private indexOfAny(str: string, chars: string[]): number {
|
|
273
|
-
for (let i: number = 0; i < str.length; i++) {
|
|
274
|
-
if (chars.indexOf(str[`${i}` as any]) !== -1) {
|
|
275
|
-
return i;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return -1;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
public getModuleName(): string {
|
|
282
|
-
return 'smarttextarea';
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
public destroy(): void {
|
|
286
|
-
super.destroy();
|
|
287
|
-
this.textArea = null;
|
|
288
|
-
this.suggestionDisplay = null;
|
|
289
|
-
this.typingDebounceTimeout = null;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
class InlineSuggestion {
|
|
294
|
-
private owner: HTMLElement;
|
|
295
|
-
private textArea: HTMLTextAreaElement;
|
|
296
|
-
private latestSuggestionText: string;
|
|
297
|
-
private suggestionStartPos: number;
|
|
298
|
-
private suggestionEndPos: number;
|
|
299
|
-
private virtualCaret: VirtualCaret;
|
|
300
|
-
private originalValueProperty: any;
|
|
301
|
-
|
|
302
|
-
private get value(): string {
|
|
303
|
-
const value: string = this.originalValueProperty.get.call(this.textArea);
|
|
304
|
-
return this.isShowing() ? value.substring(0, this.suggestionStartPos) + value.substring(this.suggestionEndPos) : value;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
private set value(newValue: string) {
|
|
308
|
-
this.originalValueProperty.set.call(this.textArea, newValue);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
constructor(smartTextArea: HTMLElement, textArea: HTMLTextAreaElement) {
|
|
312
|
-
this.owner = smartTextArea;
|
|
313
|
-
this.textArea = textArea;
|
|
314
|
-
this.latestSuggestionText = '';
|
|
315
|
-
this.suggestionStartPos = null;
|
|
316
|
-
this.suggestionEndPos = null;
|
|
317
|
-
this.virtualCaret = null;
|
|
318
|
-
this.originalValueProperty = this.getOriginalValueProperty(textArea, 'value');
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
private getOriginalValueProperty(obj: any, property: any): PropertyDescriptor {
|
|
322
|
-
while (obj) {
|
|
323
|
-
const descriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(obj, property);
|
|
324
|
-
if (descriptor) {
|
|
325
|
-
return descriptor;
|
|
326
|
-
}
|
|
327
|
-
obj = Object.getPrototypeOf(obj);
|
|
328
|
-
}
|
|
329
|
-
throw new Error(`Property ${property} not found on object or its prototype chain`);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
public get valueIncludingSuggestion(): string {
|
|
333
|
-
return this.originalValueProperty.get.call(this.textArea);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
public set valueIncludingSuggestion(newValue: string) {
|
|
337
|
-
this.originalValueProperty.set.call(this.textArea, newValue);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
public isShowing(): boolean {
|
|
341
|
-
return this.suggestionStartPos !== null;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
public show(suggestionText: string): void {
|
|
345
|
-
this.latestSuggestionText = suggestionText;
|
|
346
|
-
this.suggestionStartPos = this.textArea.selectionStart;
|
|
347
|
-
this.suggestionEndPos = this.suggestionStartPos + suggestionText.length;
|
|
348
|
-
this.textArea.setAttribute('data-suggestion-visible', '');
|
|
349
|
-
this.valueIncludingSuggestion = this.valueIncludingSuggestion.substring(0, this.suggestionStartPos) +
|
|
350
|
-
suggestionText +
|
|
351
|
-
this.valueIncludingSuggestion.substring(this.suggestionStartPos);
|
|
352
|
-
this.textArea.setSelectionRange(this.suggestionStartPos, this.suggestionEndPos);
|
|
353
|
-
if (!this.virtualCaret) {
|
|
354
|
-
this.virtualCaret = new VirtualCaret(this.owner, this.textArea);
|
|
355
|
-
}
|
|
356
|
-
this.virtualCaret.show();
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
public get currentSuggestion(): string {
|
|
360
|
-
return this.latestSuggestionText;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
public accept(): void {
|
|
364
|
-
this.textArea.setSelectionRange(this.suggestionEndPos, this.suggestionEndPos);
|
|
365
|
-
this.suggestionStartPos = null;
|
|
366
|
-
this.suggestionEndPos = null;
|
|
367
|
-
if (this.virtualCaret) {
|
|
368
|
-
this.virtualCaret.hide();
|
|
369
|
-
}
|
|
370
|
-
this.textArea.removeAttribute('data-suggestion-visible');
|
|
371
|
-
CaretPositionHelper.adjustScrollToCaretPosition(this.textArea);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
public reject(): void {
|
|
375
|
-
if (!this.isShowing()) {
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
const selectionStart: number = this.textArea.selectionStart;
|
|
379
|
-
const selectionEnd: number = this.textArea.selectionEnd;
|
|
380
|
-
this.valueIncludingSuggestion = this.valueIncludingSuggestion.substring(0, this.suggestionStartPos) +
|
|
381
|
-
this.valueIncludingSuggestion.substring(this.suggestionEndPos);
|
|
382
|
-
if (this.suggestionStartPos === selectionStart && this.suggestionEndPos === selectionEnd) {
|
|
383
|
-
this.textArea.setSelectionRange(selectionStart, selectionStart);
|
|
384
|
-
}
|
|
385
|
-
this.suggestionStartPos = null;
|
|
386
|
-
this.suggestionEndPos = null;
|
|
387
|
-
this.textArea.removeAttribute('data-suggestion-visible');
|
|
388
|
-
if (this.virtualCaret) {
|
|
389
|
-
this.virtualCaret.hide();
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
class ContextSuggestion {
|
|
395
|
-
private textArea: HTMLTextAreaElement;
|
|
396
|
-
private latestSuggestionText: string = '';
|
|
397
|
-
private suggestionElement: HTMLDivElement;
|
|
398
|
-
private suggestionPrefixElement: HTMLSpanElement;
|
|
399
|
-
private suggestionTextElement: HTMLSpanElement;
|
|
400
|
-
private showing: boolean = false;
|
|
401
|
-
|
|
402
|
-
constructor(container: HTMLElement, textArea: HTMLTextAreaElement) {
|
|
403
|
-
this.textArea = textArea;
|
|
404
|
-
this.suggestionElement = document.createElement('div');
|
|
405
|
-
this.suggestionElement.classList.add('smart-textarea-suggestion-overlay');
|
|
406
|
-
this.suggestionElement.addEventListener('mousedown', (event: MouseEvent) => this.handleSuggestionClicked(event));
|
|
407
|
-
this.suggestionElement.addEventListener('touchend', (event: TouchEvent) => this.handleSuggestionClicked(event));
|
|
408
|
-
this.suggestionPrefixElement = document.createElement('span');
|
|
409
|
-
this.suggestionTextElement = document.createElement('span');
|
|
410
|
-
this.suggestionElement.appendChild(this.suggestionPrefixElement);
|
|
411
|
-
this.suggestionElement.appendChild(this.suggestionTextElement);
|
|
412
|
-
this.suggestionPrefixElement.style.opacity = '0.3';
|
|
413
|
-
const computedStyle: CSSStyleDeclaration = window.getComputedStyle(this.textArea);
|
|
414
|
-
this.suggestionElement.style.font = computedStyle.font;
|
|
415
|
-
this.suggestionElement.style.marginTop = `${1.4 * parseFloat(computedStyle.fontSize)}px`;
|
|
416
|
-
container.appendChild(this.suggestionElement);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
public get currentSuggestion(): string {
|
|
420
|
-
return this.latestSuggestionText;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
public show(suggestionText: string): void {
|
|
424
|
-
this.latestSuggestionText = suggestionText;
|
|
425
|
-
this.suggestionPrefixElement.textContent = suggestionText[0] !== ' ' ? this.getPrefixText(this.textArea, 20) : '';
|
|
426
|
-
this.suggestionTextElement.textContent = suggestionText;
|
|
427
|
-
const position: CaretPosition = CaretPositionHelper.getTextAreaPosition(this.textArea);
|
|
428
|
-
const style: CSSStyleDeclaration = this.suggestionElement.style;
|
|
429
|
-
style.minWidth = null;
|
|
430
|
-
this.suggestionElement.classList.add('smart-textarea-suggestion-overlay-visible');
|
|
431
|
-
style.zIndex = this.textArea.style.zIndex + 1;
|
|
432
|
-
style.top = `${position.top}px`;
|
|
433
|
-
const leftPosition: number = position.left - this.suggestionPrefixElement.offsetWidth;
|
|
434
|
-
if (!style.left || Math.abs(parseFloat(style.left) - leftPosition) > 10) {
|
|
435
|
-
style.left = `${leftPosition}px`;
|
|
436
|
-
}
|
|
437
|
-
this.showing = true;
|
|
438
|
-
const computedStyle: CSSStyleDeclaration = window.getComputedStyle(this.suggestionElement);
|
|
439
|
-
const lineHeight: number = parseFloat(computedStyle.lineHeight);
|
|
440
|
-
const paddingTop: number = parseFloat(computedStyle.paddingTop);
|
|
441
|
-
const paddingBottom: number = parseFloat(computedStyle.paddingBottom);
|
|
442
|
-
const lines: number = Math.round((this.suggestionElement.offsetHeight - paddingTop - paddingBottom) / lineHeight);
|
|
443
|
-
if (lines > 2) {
|
|
444
|
-
const elementWidth: number = this.suggestionElement.offsetWidth;
|
|
445
|
-
style.minWidth = `calc(min(70vw, ${(lines * elementWidth) / 2}px))`;
|
|
446
|
-
}
|
|
447
|
-
const rect: any = this.suggestionElement.getBoundingClientRect();
|
|
448
|
-
if (rect.right > document.body.clientWidth - 20) {
|
|
449
|
-
style.left = `calc(${parseFloat(style.left) - (rect.right - document.body.clientWidth)}px - 2rem)`;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
public accept(): void {
|
|
454
|
-
if (this.showing) {
|
|
455
|
-
CaretPositionHelper.insertCharacter(this.textArea, this.currentSuggestion);
|
|
456
|
-
CaretPositionHelper.adjustScrollToCaretPosition(this.textArea);
|
|
457
|
-
this.hide();
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
public reject(): void {
|
|
462
|
-
this.hide();
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
public hide(): void {
|
|
466
|
-
if (this.showing) {
|
|
467
|
-
this.showing = false;
|
|
468
|
-
this.suggestionElement.classList.remove('smart-textarea-suggestion-overlay-visible');
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
public isShowing(): boolean {
|
|
473
|
-
return this.showing;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
private handleSuggestionClicked(event: MouseEvent | TouchEvent): void {
|
|
477
|
-
event.preventDefault();
|
|
478
|
-
event.stopImmediatePropagation();
|
|
479
|
-
this.accept();
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
private getPrefixText(textArea: HTMLTextAreaElement, maxLength: number): string {
|
|
483
|
-
const value: string = textArea.value;
|
|
484
|
-
const selectionStart: number = textArea.selectionStart;
|
|
485
|
-
for (let i: number = selectionStart - 1; i > selectionStart - maxLength; i--) {
|
|
486
|
-
if (i < 0 || /\s/.test(value[`${i}` as any])) {
|
|
487
|
-
return value.substring(i + 1, selectionStart);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
return '';
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
class VirtualCaret {
|
|
495
|
-
private textArea: HTMLTextAreaElement;
|
|
496
|
-
private caretDiv: HTMLDivElement;
|
|
497
|
-
constructor(smartTextArea: HTMLElement, textArea: HTMLTextAreaElement) {
|
|
498
|
-
this.textArea = textArea;
|
|
499
|
-
this.caretDiv = document.createElement('div');
|
|
500
|
-
this.caretDiv.classList.add('smart-textarea-caret');
|
|
501
|
-
smartTextArea.appendChild(this.caretDiv);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
public show(): void {
|
|
505
|
-
const textAreaPosition: CaretPosition = CaretPositionHelper.getTextAreaPosition(this.textArea);
|
|
506
|
-
const caretStyle: CSSStyleDeclaration = this.caretDiv.style;
|
|
507
|
-
caretStyle.display = 'block';
|
|
508
|
-
caretStyle.top = textAreaPosition.top + 'px';
|
|
509
|
-
caretStyle.left = textAreaPosition.left + 'px';
|
|
510
|
-
caretStyle.height = textAreaPosition.height + 'px';
|
|
511
|
-
caretStyle.zIndex = this.textArea.style.zIndex;
|
|
512
|
-
caretStyle.backgroundColor = (textAreaPosition as any).elemStyle.caretColor;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
public hide(): void {
|
|
516
|
-
this.caretDiv.style.display = 'none';
|
|
517
|
-
}
|
|
518
|
-
}
|