@syncfusion/ej2-inputs 30.2.4 → 31.1.17
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 +1 -1
- package/dist/es6/ej2-inputs.es2015.js.map +1 -1
- package/dist/es6/ej2-inputs.es5.js +1 -1
- 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/dist/ts/color-picker/color-picker-model.d.ts +186 -0
- package/dist/ts/color-picker/color-picker.d.ts +398 -0
- package/dist/ts/color-picker/color-picker.ts +2209 -0
- package/dist/ts/color-picker/index.d.ts +5 -0
- package/dist/ts/color-picker/index.ts +5 -0
- package/dist/ts/common/index.d.ts +4 -0
- package/dist/ts/common/index.ts +4 -0
- package/dist/ts/common/signature-base.d.ts +340 -0
- package/dist/ts/common/signature-base.ts +1170 -0
- package/dist/ts/form-validator/form-validator-model.d.ts +121 -0
- package/dist/ts/form-validator/form-validator.d.ts +312 -0
- package/dist/ts/form-validator/form-validator.ts +1068 -0
- package/dist/ts/form-validator/index.d.ts +5 -0
- package/dist/ts/form-validator/index.ts +5 -0
- package/dist/ts/index.d.ts +18 -0
- package/dist/ts/index.ts +18 -0
- package/dist/ts/input/index.d.ts +4 -0
- package/dist/ts/input/index.ts +4 -0
- package/dist/ts/input/input.d.ts +345 -0
- package/dist/ts/input/input.ts +1277 -0
- package/dist/ts/maskedtextbox/base/index.d.ts +4 -0
- package/dist/ts/maskedtextbox/base/index.ts +4 -0
- package/dist/ts/maskedtextbox/base/mask-base.d.ts +134 -0
- package/dist/ts/maskedtextbox/base/mask-base.ts +1207 -0
- package/dist/ts/maskedtextbox/index.d.ts +5 -0
- package/dist/ts/maskedtextbox/index.ts +5 -0
- package/dist/ts/maskedtextbox/maskedtextbox/index.d.ts +5 -0
- package/dist/ts/maskedtextbox/maskedtextbox/index.ts +5 -0
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox-model.d.ts +167 -0
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.d.ts +307 -0
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.ts +709 -0
- package/dist/ts/numerictextbox/index.d.ts +5 -0
- package/dist/ts/numerictextbox/index.ts +5 -0
- package/dist/ts/numerictextbox/numerictextbox-model.d.ts +228 -0
- package/dist/ts/numerictextbox/numerictextbox.d.ts +431 -0
- package/dist/ts/numerictextbox/numerictextbox.ts +1672 -0
- package/dist/ts/otp-input/index.d.ts +5 -0
- package/dist/ts/otp-input/index.ts +5 -0
- package/dist/ts/otp-input/otp-input-model.d.ts +165 -0
- package/dist/ts/otp-input/otp-input.d.ts +365 -0
- package/dist/ts/otp-input/otp-input.ts +924 -0
- package/dist/ts/rating/index.d.ts +5 -0
- package/dist/ts/rating/index.ts +5 -0
- package/dist/ts/rating/rating-model.d.ts +239 -0
- package/dist/ts/rating/rating.d.ts +416 -0
- package/dist/ts/rating/rating.ts +1101 -0
- package/dist/ts/signature/index.d.ts +5 -0
- package/dist/ts/signature/index.ts +5 -0
- package/dist/ts/signature/signature-model.d.ts +131 -0
- package/dist/ts/signature/signature.d.ts +167 -0
- package/dist/ts/signature/signature.ts +266 -0
- package/dist/ts/slider/index.d.ts +5 -0
- package/dist/ts/slider/index.ts +5 -0
- package/dist/ts/slider/slider-model.d.ts +401 -0
- package/dist/ts/slider/slider.d.ts +721 -0
- package/dist/ts/slider/slider.ts +3497 -0
- package/dist/ts/smart-textarea/caret-helper.d.ts +17 -0
- package/dist/ts/smart-textarea/caret-helper.ts +95 -0
- package/dist/ts/smart-textarea/index.d.ts +5 -0
- package/dist/ts/smart-textarea/index.ts +5 -0
- package/dist/ts/smart-textarea/smart-textarea-model.d.ts +44 -0
- package/dist/ts/smart-textarea/smart-textarea.d.ts +80 -0
- package/dist/ts/smart-textarea/smart-textarea.ts +518 -0
- package/dist/ts/speech-to-text/index.d.ts +5 -0
- package/dist/ts/speech-to-text/index.ts +5 -0
- package/dist/ts/speech-to-text/speech-to-text-model.d.ts +270 -0
- package/dist/ts/speech-to-text/speech-to-text.d.ts +487 -0
- package/dist/ts/speech-to-text/speech-to-text.ts +1008 -0
- package/dist/ts/textarea/index.d.ts +5 -0
- package/dist/ts/textarea/index.ts +5 -0
- package/dist/ts/textarea/textarea-model.d.ts +161 -0
- package/dist/ts/textarea/textarea.d.ts +237 -0
- package/dist/ts/textarea/textarea.ts +812 -0
- package/dist/ts/textbox/index.d.ts +5 -0
- package/dist/ts/textbox/index.ts +5 -0
- package/dist/ts/textbox/textbox-model.d.ts +155 -0
- package/dist/ts/textbox/textbox.d.ts +288 -0
- package/dist/ts/textbox/textbox.ts +872 -0
- package/dist/ts/uploader/index.d.ts +5 -0
- package/dist/ts/uploader/index.ts +5 -0
- package/dist/ts/uploader/uploader-model.d.ts +555 -0
- package/dist/ts/uploader/uploader.d.ts +1216 -0
- package/dist/ts/uploader/uploader.ts +4391 -0
- package/package.json +62 -12
- package/src/input/input.js +1 -1
- package/styles/bootstrap5.3-lite.css +3 -3
- package/styles/bootstrap5.3.css +5 -5
- package/styles/input/_layout.scss +0 -1
- package/styles/input/tailwind3.css +0 -1
- package/styles/tailwind-dark-lite.css +3 -3
- package/styles/tailwind-dark.css +5 -5
- package/styles/tailwind-lite.css +3 -3
- package/styles/tailwind.css +5 -5
- package/styles/tailwind3-lite.css +0 -1
- package/styles/tailwind3.css +0 -1
- package/styles/uploader/_bootstrap5.3-definition.scss +1 -1
- package/styles/uploader/_tailwind-definition.scss +1 -1
- package/styles/uploader/bootstrap5.3.css +5 -5
- package/styles/uploader/tailwind-dark.css +5 -5
- package/styles/uploader/tailwind.css +5 -5
|
@@ -0,0 +1,1008 @@
|
|
|
1
|
+
|
|
2
|
+
import { NotifyPropertyChanges, INotifyPropertyChanged, Component, getUniqueID, Property, isNullOrUndefined as isNOU, EmitType, Event, EventHandler, ChildProperty, BaseEventArgs, Complex, removeClass, addClass, L10n } from '@syncfusion/ej2-base';
|
|
3
|
+
import { SpeechToTextModel, TooltipSettingsModel, ButtonSettingsModel } from './speech-to-text-model';
|
|
4
|
+
import { Button, IconPosition } from '@syncfusion/ej2-buttons';
|
|
5
|
+
import { Tooltip } from '@syncfusion/ej2-popups';
|
|
6
|
+
|
|
7
|
+
//#region Interfaces
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Applicable positions where the Tooltip can be displayed over SpeechToText button.
|
|
11
|
+
* - TopLeft :- The tooltip appears at the top-left corner of the SpeechToText button.
|
|
12
|
+
* - TopCenter :- The tooltip appears at the top-center of the SpeechToText button.
|
|
13
|
+
* - TopRight :- The tooltip appears at the top-right corner of the SpeechToText button.
|
|
14
|
+
* - BottomLeft :- The tooltip appears at the bottom-left corner of the SpeechToText button.
|
|
15
|
+
* - BottomCenter :- The tooltip appears at the bottom-center of the SpeechToText button.
|
|
16
|
+
* - BottomRight :- The tooltip appears at the bottom-right corner of the SpeechToText button.
|
|
17
|
+
* - LeftTop :- The tooltip appears at the left-top corner of the SpeechToText button.
|
|
18
|
+
* - LeftCenter :- The tooltip appears at the left-center of the SpeechToText button.
|
|
19
|
+
* - LeftBottom :- The tooltip appears at the left-bottom corner of the SpeechToText button.
|
|
20
|
+
* - RightTop :- The tooltip appears at the right-top corner of the SpeechToText button.
|
|
21
|
+
* - RightCenter :- The tooltip appears at the right-center of the SpeechToText button.
|
|
22
|
+
* - RightBottom :- The tooltip appears at the right-bottom corner of the SpeechToText button.
|
|
23
|
+
*/
|
|
24
|
+
export type TooltipPosition = 'TopLeft' | 'TopCenter' | 'TopRight' | 'BottomLeft' | 'BottomCenter' | 'BottomRight' | 'LeftTop' | 'LeftCenter' | 'LeftBottom' | 'RightTop' | 'RightCenter' | 'RightBottom';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Configuration settings for the toggle button used in the SpeechToText component.
|
|
28
|
+
*/
|
|
29
|
+
export class ButtonSettings extends ChildProperty<ButtonSettings> {
|
|
30
|
+
/**
|
|
31
|
+
* Specifies the text content to be displayed when the SpeechToText button is in the "start" state.
|
|
32
|
+
* This content appears alongside the icon or as standalone text based on the configuration.
|
|
33
|
+
*
|
|
34
|
+
* @type {string}
|
|
35
|
+
* @default ""
|
|
36
|
+
*/
|
|
37
|
+
@Property('')
|
|
38
|
+
public content: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Specifies the text content to be displayed when the SpeechToText button is in the "stop" state.
|
|
42
|
+
* This content appears alongside the icon or as standalone text based on the configuration.
|
|
43
|
+
*
|
|
44
|
+
* @type {string}
|
|
45
|
+
* @default ""
|
|
46
|
+
*/
|
|
47
|
+
@Property('')
|
|
48
|
+
public stopContent: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Specifies the CSS classes for the icon displayed on the SpeechToText button.
|
|
52
|
+
* This class determines the appearance of the button icon in "start" state.
|
|
53
|
+
*
|
|
54
|
+
* @type {string}
|
|
55
|
+
* @default ""
|
|
56
|
+
*/
|
|
57
|
+
@Property('')
|
|
58
|
+
public iconCss: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Specifies the CSS classes for the icon displayed when the SpeechToText button is in the "stop" state.
|
|
62
|
+
* This class determines the styling of the button icon in the stop state, allowing for clear visual feedback.
|
|
63
|
+
*
|
|
64
|
+
* @type {string}
|
|
65
|
+
* @default ""
|
|
66
|
+
*/
|
|
67
|
+
@Property('')
|
|
68
|
+
public stopIconCss: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Specifies the position of the icon relative to the button text content in the SpeechToText component.
|
|
72
|
+
* This property can accept either a string or an IconPosition enum to determine the position of the icon.
|
|
73
|
+
*
|
|
74
|
+
* @type {string | IconPosition}
|
|
75
|
+
* @default "Left"
|
|
76
|
+
*/
|
|
77
|
+
@Property('Left')
|
|
78
|
+
public iconPosition: string | IconPosition;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Specifies whether the button should be styled as a primary action button in the SpeechToText component.
|
|
82
|
+
* When set to `true`, the button applies primary styling.
|
|
83
|
+
*
|
|
84
|
+
* @type {boolean}
|
|
85
|
+
* @default false
|
|
86
|
+
*/
|
|
87
|
+
@Property(false)
|
|
88
|
+
public isPrimary: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Configuration settings for tooltip in the SpeechToText component.
|
|
94
|
+
* This allows customization of the tooltip content and its positioning.
|
|
95
|
+
*/
|
|
96
|
+
export class TooltipSettings extends ChildProperty<TooltipSettings> {
|
|
97
|
+
/**
|
|
98
|
+
* The text displayed when the user hovers over the button while it is in the listening state,
|
|
99
|
+
* showing the start listening option.
|
|
100
|
+
* @type {string}
|
|
101
|
+
* @default 'Start listening'
|
|
102
|
+
*/
|
|
103
|
+
@Property('Start listening')
|
|
104
|
+
public content: string;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The text displayed when the user hovers over the button while listening is in progress,
|
|
108
|
+
* and the button shows the stop icon.
|
|
109
|
+
* @type {string}
|
|
110
|
+
* @default 'Stop listening'
|
|
111
|
+
*/
|
|
112
|
+
@Property('Stop listening')
|
|
113
|
+
public stopContent: string;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Specifies the position of the tooltip in the UI, indicating where the tooltip should appear.
|
|
117
|
+
*
|
|
118
|
+
* @isenumeration true
|
|
119
|
+
* @asptype TooltipPosition
|
|
120
|
+
* @default 'TopCenter'
|
|
121
|
+
*/
|
|
122
|
+
@Property('TopCenter')
|
|
123
|
+
public position: TooltipPosition;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Enum representing the operational states of the SpeechToText component.
|
|
128
|
+
*/
|
|
129
|
+
export enum SpeechToTextState {
|
|
130
|
+
/**
|
|
131
|
+
* Specifies the state where the SpeechToText component is inactive and not processing spoken input.
|
|
132
|
+
*/
|
|
133
|
+
Inactive = 'Inactive',
|
|
134
|
+
/**
|
|
135
|
+
* Specifies the state where the SpeechToText component is actively listening to spoken input.
|
|
136
|
+
*/
|
|
137
|
+
Listening = 'Listening',
|
|
138
|
+
/**
|
|
139
|
+
* Specifies the state where the SpeechToText component has stopped processing spoken input.
|
|
140
|
+
*/
|
|
141
|
+
Stopped = 'Stopped'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Represents the event arguments when a listening is started in the Speech to text component.
|
|
146
|
+
*/
|
|
147
|
+
export interface StartListeningEventArgs extends BaseEventArgs {
|
|
148
|
+
/**
|
|
149
|
+
* Indicates whether the listening or speech action should be canceled.
|
|
150
|
+
* Setting this to `true` prevents listening.
|
|
151
|
+
*
|
|
152
|
+
* @type {boolean}
|
|
153
|
+
* @default false
|
|
154
|
+
*/
|
|
155
|
+
cancel: boolean;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Specifies the event type associated with the start listening action.
|
|
159
|
+
*
|
|
160
|
+
* @type {Event}
|
|
161
|
+
*/
|
|
162
|
+
event: Event;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Represents the current state of the component when listening starts.
|
|
166
|
+
*
|
|
167
|
+
* @isenumeration true
|
|
168
|
+
* @asptype SpeechToTextState
|
|
169
|
+
* @default 'Inactive'
|
|
170
|
+
*/
|
|
171
|
+
listeningState: SpeechToTextState;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Indicates whether the listening event was triggered by user interaction (`true`)
|
|
175
|
+
* or programmatically (`false`).
|
|
176
|
+
*
|
|
177
|
+
* @type {boolean}
|
|
178
|
+
* @default false
|
|
179
|
+
*/
|
|
180
|
+
isInteracted: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Represents the event arguments triggered when listening stops in the SpeechToText component.
|
|
185
|
+
*/
|
|
186
|
+
export interface StopListeningEventArgs extends BaseEventArgs {
|
|
187
|
+
/**
|
|
188
|
+
* Specifies the event type associated with the stop listening action.
|
|
189
|
+
*
|
|
190
|
+
* @type {Event}
|
|
191
|
+
*/
|
|
192
|
+
event: Event;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Represents the current state of the component when listening stops.
|
|
196
|
+
*
|
|
197
|
+
* @isenumeration true
|
|
198
|
+
* @asptype SpeechToTextState
|
|
199
|
+
* @default 'Inactive'
|
|
200
|
+
*/
|
|
201
|
+
listeningState: SpeechToTextState;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Indicates whether the listening event was triggered by user interaction (`true`)
|
|
205
|
+
* or programmatically (`false`).
|
|
206
|
+
* @type {boolean}
|
|
207
|
+
* @default false
|
|
208
|
+
*/
|
|
209
|
+
isInteracted: boolean;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Represents the event arguments triggered when a transcript is updated in the SpeechToText component.
|
|
214
|
+
*/
|
|
215
|
+
export interface TranscriptChangedEventArgs extends BaseEventArgs {
|
|
216
|
+
/**
|
|
217
|
+
* Specifies the event type associated with the transcript been update in the SpeechToText component.
|
|
218
|
+
* Represents the event arguments when a listening is processed in the speech to text component.
|
|
219
|
+
*
|
|
220
|
+
* @type {Event}
|
|
221
|
+
*/
|
|
222
|
+
event: Event;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Specifies the transcribed text captured from the speech to text.
|
|
226
|
+
* This property contains the text representation of recorded speech.
|
|
227
|
+
*
|
|
228
|
+
* @type {string}
|
|
229
|
+
* @default ''
|
|
230
|
+
*/
|
|
231
|
+
transcript: string;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Specifies whether the recognized speech result is interim or final.
|
|
235
|
+
* Returns `true` when interim results are returned and `false` when it is a final result.
|
|
236
|
+
* The value is determined based on the `allowInterimResults` property.
|
|
237
|
+
*
|
|
238
|
+
* @type {boolean}
|
|
239
|
+
* @default true
|
|
240
|
+
*/
|
|
241
|
+
isInterimResult: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Represents the event arguments triggered when listening is disabled or exceptions are raised in the SpeechToText component.
|
|
246
|
+
*/
|
|
247
|
+
export interface ErrorEventArgs extends BaseEventArgs {
|
|
248
|
+
/**
|
|
249
|
+
* Specifies the data provided when an error event is triggered during speech-to-text actions.
|
|
250
|
+
* This property helps identify the specific error event that occurred during listening or speaking,
|
|
251
|
+
* allowing to differentiate between various issues such as microphone access failures,
|
|
252
|
+
* unsupported language models, or network issues.
|
|
253
|
+
*
|
|
254
|
+
* @type {Event}
|
|
255
|
+
*/
|
|
256
|
+
event?: Event;
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Represents a string describing the error type that occurred during speech-to-text actions.
|
|
260
|
+
* This value indicates what went wrong, such as 'audio-capture' or 'not-allowed', and helps to find
|
|
261
|
+
* the cause of the failure for better troubleshooting.
|
|
262
|
+
*
|
|
263
|
+
* @type {string}
|
|
264
|
+
* @default ''
|
|
265
|
+
*/
|
|
266
|
+
error: string;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* A message providing further details about the error.
|
|
270
|
+
* This message gives more context or clarification on the error that occurred,
|
|
271
|
+
* helping user to better understand the issue.
|
|
272
|
+
* It could include user-facing messages or more technical error details.
|
|
273
|
+
*
|
|
274
|
+
* @type {string}
|
|
275
|
+
* @default ''
|
|
276
|
+
*/
|
|
277
|
+
errorMessage: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
|
|
282
|
+
@NotifyPropertyChanges
|
|
283
|
+
export class SpeechToText extends Component<HTMLElement> implements INotifyPropertyChanged {
|
|
284
|
+
|
|
285
|
+
//#region Public properties
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* The transcribed text from the speech-to-text process.
|
|
289
|
+
* This property updates dynamically during speech recognition, providing both interim and final results.
|
|
290
|
+
* It can be used to display or process the transcribed speech.
|
|
291
|
+
*
|
|
292
|
+
* @type {string}
|
|
293
|
+
* @default ''
|
|
294
|
+
*/
|
|
295
|
+
@Property('')
|
|
296
|
+
public transcript: string;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* The language and locale used for speech recognition.
|
|
300
|
+
* This ensures proper transcription by selecting the correct language model.
|
|
301
|
+
* Common formats: 'en-US' (English, United States), 'es-ES' (Spanish, Spain), 'fr-FR' (French, France).
|
|
302
|
+
*
|
|
303
|
+
* @type {string}
|
|
304
|
+
* @default ''
|
|
305
|
+
*/
|
|
306
|
+
@Property('')
|
|
307
|
+
public lang: string;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Determines whether interim results should be provided during speech recognition.
|
|
311
|
+
* If true, partial results are delivered in real-time, allowing for a dynamic user experience.
|
|
312
|
+
* If false, only final results will be provided after the recognition process is complete.
|
|
313
|
+
*
|
|
314
|
+
* @type {boolean}
|
|
315
|
+
* @default true
|
|
316
|
+
*/
|
|
317
|
+
@Property(true)
|
|
318
|
+
public allowInterimResults: boolean;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Determines whether the tooltip should be displayed on hover over the SpeechToText button.
|
|
322
|
+
* If true, the tooltip will be shown to provide additional information about the current state or action.
|
|
323
|
+
*
|
|
324
|
+
* @type {boolean}
|
|
325
|
+
* @default true
|
|
326
|
+
*/
|
|
327
|
+
@Property(true)
|
|
328
|
+
public showTooltip: boolean;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Represents the current operational state of the component.
|
|
332
|
+
* This state helps manage transitions and control the component's behavior.
|
|
333
|
+
* Possible values:
|
|
334
|
+
* - 'Inactive': Component is idle.
|
|
335
|
+
* - 'Listening': The component is actively listening for speech input.
|
|
336
|
+
* - 'Stopped': Listening has stopped.
|
|
337
|
+
*
|
|
338
|
+
* @isenumeration true
|
|
339
|
+
* @asptype SpeechToTextState
|
|
340
|
+
* @default 'Inactive'
|
|
341
|
+
*/
|
|
342
|
+
@Property('Inactive')
|
|
343
|
+
public listeningState: SpeechToTextState;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Customizes the appearance and functionality of the record button.
|
|
347
|
+
* This allows for customization of button content, icons, and positions.
|
|
348
|
+
* Use it to adjust the button's visual and functional properties according to your needs.
|
|
349
|
+
*
|
|
350
|
+
* @default null
|
|
351
|
+
* @type {ButtonSettingsModel}
|
|
352
|
+
*/
|
|
353
|
+
@Complex<ButtonSettingsModel>({}, ButtonSettings)
|
|
354
|
+
public buttonSettings: ButtonSettingsModel;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Defines tooltip content and positioning for guiding user interactions.
|
|
358
|
+
* Tooltip provides helpful instructions or descriptions for button actions, improving user experience.
|
|
359
|
+
*
|
|
360
|
+
* @default null
|
|
361
|
+
* @type {TooltipSettingsModel}
|
|
362
|
+
*/
|
|
363
|
+
@Complex<TooltipSettingsModel>({}, TooltipSettings)
|
|
364
|
+
public tooltipSettings: TooltipSettingsModel;
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Indicates whether the component is disabled.
|
|
368
|
+
* When true, all interactions with the component (e.g., clicking, listening) are disabled.
|
|
369
|
+
* Useful for preventing user interaction in specific states, such as during processing or error handling.
|
|
370
|
+
*
|
|
371
|
+
* @type {boolean}
|
|
372
|
+
* @default false
|
|
373
|
+
*/
|
|
374
|
+
@Property(false)
|
|
375
|
+
public disabled: boolean;
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Specifies additional CSS classes for customizing the component's appearance.
|
|
379
|
+
* Allows applying custom styles to match application requirements
|
|
380
|
+
* This property can be used to extend the component's default style.
|
|
381
|
+
*
|
|
382
|
+
* @type {string}
|
|
383
|
+
* @default ''
|
|
384
|
+
*/
|
|
385
|
+
@Property('')
|
|
386
|
+
public cssClass: string;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Allows additional HTML attributes to be added to the root element of the SpeechToText button.
|
|
390
|
+
* This property accepts a key-value pair format for attributes such as name, aria-label, and others.
|
|
391
|
+
* This helps to make the button more accessible and adaptable to specific requirements.
|
|
392
|
+
*
|
|
393
|
+
* @type {Object}
|
|
394
|
+
* @default null
|
|
395
|
+
*/
|
|
396
|
+
@Property({})
|
|
397
|
+
public htmlAttributes: { [key: string]: string };
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Triggered when the SpeechToText component is initialized and ready for interaction.
|
|
401
|
+
* This event indicates that the component is fully loaded and can start processing user input.
|
|
402
|
+
* Use this event to execute initialization logic or show the component's ready state.
|
|
403
|
+
*
|
|
404
|
+
* @event created
|
|
405
|
+
*/
|
|
406
|
+
@Event()
|
|
407
|
+
public created: EmitType<Event>;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Triggered when speech recognition begins listening for audio input.
|
|
411
|
+
* This event fires when the user starts the speech-to-text process.
|
|
412
|
+
* Use this event to execute logic or display feedback (e.g., a "Listening..." message).
|
|
413
|
+
*
|
|
414
|
+
* @param {StartListeningEventArgs} args - The event arguments containing the state and context information for the start of the listening process.
|
|
415
|
+
* @event onStart
|
|
416
|
+
*/
|
|
417
|
+
@Event()
|
|
418
|
+
public onStart: EmitType<StartListeningEventArgs>;
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Triggered when speech recognition stops listening for audio input.
|
|
422
|
+
* This event marks the end of the listening session, either due to user action or completion of recognition.
|
|
423
|
+
* Use this event to trigger post-processing logic or indicate that listening has ended (e.g., show "Listening stopped").
|
|
424
|
+
*
|
|
425
|
+
* @param {StopListeningEventArgs} args - The event arguments containing the state and context information for the stop action.
|
|
426
|
+
* @event onStop
|
|
427
|
+
*/
|
|
428
|
+
@Event()
|
|
429
|
+
public onStop: EmitType<StopListeningEventArgs>;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Triggered when an error occurs during speech recognition or listening, this event provides details to handle exceptions, display messages, and troubleshoot issues like microphone failures, network errors, or unsupported browsers and language models.
|
|
433
|
+
*
|
|
434
|
+
* Common error strings may include:
|
|
435
|
+
* - `no-speech`: No speech detected. Please speak into the microphone.
|
|
436
|
+
* - `aborted`: Speech recognition was aborted.
|
|
437
|
+
* - `audio-capture`: No microphone detected. Ensure your microphone is connected.
|
|
438
|
+
* - `not-allowed`: Microphone access denied. Allow microphone permissions.
|
|
439
|
+
* - `service-not-allowed`: Speech recognition service is not allowed in this context.
|
|
440
|
+
* - `network`: Network error occurred. Check your internet connection.
|
|
441
|
+
* - `unsupported-browser`: The browser does not support the SpeechRecognition API.
|
|
442
|
+
*
|
|
443
|
+
* In addition to handling common speech recognition errors, it is essential to handle unsupported browser errors. For example, if the browser does not support the `SpeechRecognition` API, the `unsupported-browser` error string will be triggered. This can help notify users to switch to a compatible browser.
|
|
444
|
+
*
|
|
445
|
+
* For more details on the error strings and how to handle them, refer to the documentation:
|
|
446
|
+
* [SpeechRecognitionErrorEvent error](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognitionErrorEvent/error)
|
|
447
|
+
*
|
|
448
|
+
* @param {ErrorEventArgs} args - The event arguments containing the error details:
|
|
449
|
+
* - `error`: The error string representing the specific issue that occurred.
|
|
450
|
+
* - `message`: A brief message describing the error.
|
|
451
|
+
* - `event`: The event object that triggered the error (contains details like the type of error event).
|
|
452
|
+
*
|
|
453
|
+
* @event onError
|
|
454
|
+
*/
|
|
455
|
+
@Event()
|
|
456
|
+
public onError: EmitType<ErrorEventArgs>;
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Triggered when the transcript is updated during the speech recognition process.
|
|
460
|
+
* This event delivers updated text as the user speaks. It can be used to update the UI with real-time transcription.
|
|
461
|
+
* The event provides both interim and final transcript results, depending on the configuration.
|
|
462
|
+
*
|
|
463
|
+
* @param {TranscriptChangedEventArgs} args - The event arguments containing the latest transcript text.
|
|
464
|
+
* @event transcriptChanged
|
|
465
|
+
*/
|
|
466
|
+
@Event()
|
|
467
|
+
public transcriptChanged: EmitType<TranscriptChangedEventArgs>;
|
|
468
|
+
|
|
469
|
+
//#endregion
|
|
470
|
+
|
|
471
|
+
//#region Inherited methods
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Constructor for creating the component
|
|
475
|
+
*
|
|
476
|
+
* @param {SpeechToTextModel} options - Specifies the SpeechToTextModel model.
|
|
477
|
+
* @param {string | HTMLElement} element - Specifies the element to render as component.
|
|
478
|
+
* @private
|
|
479
|
+
*/
|
|
480
|
+
public constructor(options?: SpeechToTextModel, element?: string | HTMLElement) {
|
|
481
|
+
super(options, element);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Initialize the event handler
|
|
486
|
+
*
|
|
487
|
+
* @private
|
|
488
|
+
* @returns {void}
|
|
489
|
+
*/
|
|
490
|
+
protected preRender(): void {
|
|
491
|
+
if (!this.element.id) { this.element.id = getUniqueID('e-' + this.getModuleName()); }
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
protected getDirective(): string {
|
|
495
|
+
return 'EJS-SPEECHTOTEXT';
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* To get component name.
|
|
500
|
+
*
|
|
501
|
+
* @returns {string} - It returns the current module name.
|
|
502
|
+
* @private
|
|
503
|
+
*/
|
|
504
|
+
public getModuleName(): string {
|
|
505
|
+
return 'speech-to-text';
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Get the properties to be maintained in the persisted state.
|
|
510
|
+
*
|
|
511
|
+
* @private
|
|
512
|
+
* @returns {string} - It returns the persisted data.
|
|
513
|
+
*/
|
|
514
|
+
protected getPersistData(): string {
|
|
515
|
+
return this.addOnPersist([]);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
protected render(): void {
|
|
519
|
+
this.renderSpeechToText();
|
|
520
|
+
this.initializeSpeechRecognition();
|
|
521
|
+
if (!isNOU(this.listeningState)) {
|
|
522
|
+
this.handleStateChange();
|
|
523
|
+
}
|
|
524
|
+
this.wireEvents();
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
//#endregion
|
|
528
|
+
|
|
529
|
+
//#region Private properties
|
|
530
|
+
|
|
531
|
+
private recognition: any;
|
|
532
|
+
private micOn: boolean;
|
|
533
|
+
private buttonInst: Button;
|
|
534
|
+
private tooltipInst: Tooltip;
|
|
535
|
+
private fullTranscript: string = '';
|
|
536
|
+
private isClicked: boolean = false;
|
|
537
|
+
private isUserInteracted: boolean = false;
|
|
538
|
+
private hasStarted: boolean = false;
|
|
539
|
+
private l10n: L10n;
|
|
540
|
+
|
|
541
|
+
//#endregion
|
|
542
|
+
|
|
543
|
+
//#region Private Methods
|
|
544
|
+
|
|
545
|
+
private initializeLocale(): void {
|
|
546
|
+
this.l10n = new L10n(this.getModuleName(), {
|
|
547
|
+
abortedError: 'Speech recognition was aborted.',
|
|
548
|
+
audioCaptureError: 'No microphone detected. Ensure your microphone is connected.',
|
|
549
|
+
defaultError: 'An unknown error occurred.',
|
|
550
|
+
networkError: 'Network error occurred. Check your internet connection.',
|
|
551
|
+
noSpeechError: 'No speech detected. Please speak into the microphone.',
|
|
552
|
+
notAllowedError: 'Microphone access denied. Allow microphone permissions.',
|
|
553
|
+
serviceNotAllowedError: 'Speech recognition service is not allowed in this context.',
|
|
554
|
+
unsupportedBrowserError: 'The browser does not support the SpeechRecognition API.',
|
|
555
|
+
startAriaLabel: 'Press to start speaking and transcribe your words',
|
|
556
|
+
stopAriaLabel: 'Press to stop speaking and end transcription',
|
|
557
|
+
startTooltipText: 'Start listening',
|
|
558
|
+
stopTooltipText: 'Stop listening'
|
|
559
|
+
}, this.locale);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private renderSpeechToText(): void {
|
|
563
|
+
this.initializeLocale();
|
|
564
|
+
const iconCss: string = !isNOU(this.buttonSettings.iconCss) && this.buttonSettings.iconCss !== '' ? this.buttonSettings.iconCss : 'e-icons e-listen-icon';
|
|
565
|
+
this.buttonInst = new Button({
|
|
566
|
+
iconCss: iconCss,
|
|
567
|
+
isPrimary: this.buttonSettings.isPrimary,
|
|
568
|
+
cssClass: this.updateButtonCssClass(),
|
|
569
|
+
disabled: this.disabled,
|
|
570
|
+
content: this.buttonSettings.content,
|
|
571
|
+
iconPosition: this.buttonSettings.iconPosition,
|
|
572
|
+
enableRtl: this.enableRtl
|
|
573
|
+
});
|
|
574
|
+
this.buttonInst.appendTo(this.element);
|
|
575
|
+
this.updateTooltip();
|
|
576
|
+
this.updateCssClass(this.cssClass, '');
|
|
577
|
+
this.updateAriaLabel();
|
|
578
|
+
if (!isNOU(this.htmlAttributes)) { this.addHtmlAttributes(this.htmlAttributes); }
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
private updateAriaLabel(): void {
|
|
582
|
+
let ariaLabel: string;
|
|
583
|
+
if (this.htmlAttributes && this.htmlAttributes['aria-label']) {
|
|
584
|
+
ariaLabel = this.htmlAttributes['aria-label'];
|
|
585
|
+
} else {
|
|
586
|
+
ariaLabel = this.micOn ? this.l10n.getConstant('stopAriaLabel') : this.l10n.getConstant('startAriaLabel');
|
|
587
|
+
}
|
|
588
|
+
this.element.setAttribute('aria-label', ariaLabel);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
private updateCssClass(newClass: string, oldClass: string): void {
|
|
592
|
+
if (oldClass) {
|
|
593
|
+
removeClass([this.element], oldClass.trim().split(' '));
|
|
594
|
+
}
|
|
595
|
+
if (newClass) {
|
|
596
|
+
addClass([this.element], newClass.trim().split(' '));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private updateButtonCssClass(): string {
|
|
601
|
+
const content: string = this.isClicked ? this.buttonSettings.stopContent : this.buttonSettings.content;
|
|
602
|
+
let cssClass: string;
|
|
603
|
+
if (content === '') { cssClass = 'e-round'; }
|
|
604
|
+
if (this.micOn) { cssClass += ' e-listening-state'; }
|
|
605
|
+
return cssClass;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
private updateTooltip(): void {
|
|
609
|
+
if (this.showTooltip) {
|
|
610
|
+
if (this.tooltipSettings) {
|
|
611
|
+
if (this.tooltipSettings.content === 'Start listening') {
|
|
612
|
+
this.tooltipSettings.content = this.l10n.getConstant('startTooltipText');
|
|
613
|
+
}
|
|
614
|
+
if (this.tooltipSettings.stopContent === 'Stop listening') {
|
|
615
|
+
this.tooltipSettings.stopContent = this.l10n.getConstant('stopTooltipText');
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
this.tooltipInst = new Tooltip({
|
|
619
|
+
content: this.hasStarted ? this.tooltipSettings.stopContent : this.tooltipSettings.content,
|
|
620
|
+
position: this.tooltipSettings.position,
|
|
621
|
+
windowCollision: true,
|
|
622
|
+
cssClass: this.cssClass ? ('e-speech-to-text-tooltip ' + this.cssClass) : 'e-speech-to-text-tooltip',
|
|
623
|
+
opensOn: 'Hover',
|
|
624
|
+
enableRtl: this.enableRtl
|
|
625
|
+
});
|
|
626
|
+
this.tooltipInst.appendTo(this.element);
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
if (!isNOU(this.tooltipInst)) {
|
|
630
|
+
this.tooltipInst.destroy();
|
|
631
|
+
this.tooltipInst = null;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private handleStateChange(): void {
|
|
637
|
+
if (this.disabled) { return; }
|
|
638
|
+
if (this.listeningState === SpeechToTextState.Listening) {
|
|
639
|
+
this.micOn = true;
|
|
640
|
+
this.startSpeechRecognition();
|
|
641
|
+
}
|
|
642
|
+
else if (this.listeningState === SpeechToTextState.Inactive || this.listeningState === SpeechToTextState.Stopped) {
|
|
643
|
+
if (this.micOn) {
|
|
644
|
+
this.micOn = false;
|
|
645
|
+
this.stopSpeechRecognition();
|
|
646
|
+
} else {
|
|
647
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
648
|
+
this.isProtectedOnChange = true;
|
|
649
|
+
this.listeningState = SpeechToTextState.Inactive;
|
|
650
|
+
this.isProtectedOnChange = prevOnChange;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
private addHtmlAttributes(attrs: { [key: string]: string }): void {
|
|
656
|
+
if (attrs) {
|
|
657
|
+
for (const attr in attrs) {
|
|
658
|
+
if (Object.prototype.hasOwnProperty.call(attrs, attr)) {
|
|
659
|
+
this.element.setAttribute(attr, attrs[attr as string]);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
private removeHtmlAttributes(attrs: { [key: string]: string }): void {
|
|
666
|
+
if (attrs) {
|
|
667
|
+
for (const attr in attrs) {
|
|
668
|
+
if (Object.prototype.hasOwnProperty.call(attrs, attr)) {
|
|
669
|
+
this.element.removeAttribute(attr);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
private wireEvents(): void {
|
|
676
|
+
EventHandler.add(this.element, 'click', this.handleButtonClick, this);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
private unWireEvents(): void {
|
|
680
|
+
EventHandler.remove(this.element, 'click', this.handleButtonClick);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
private handleButtonClick(event: Event): void {
|
|
684
|
+
this.isUserInteracted = true;
|
|
685
|
+
this.micOn = !this.micOn;
|
|
686
|
+
if (this.micOn) {
|
|
687
|
+
this.startSpeechRecognition(event);
|
|
688
|
+
} else {
|
|
689
|
+
this.stopSpeechRecognition(event);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
private triggerUnSupportedError(): void {
|
|
694
|
+
const eventArgs: ErrorEventArgs = {
|
|
695
|
+
error: 'unsupported-browser',
|
|
696
|
+
errorMessage: this.l10n.getConstant('unsupportedBrowserError')
|
|
697
|
+
};
|
|
698
|
+
this.trigger('onError', eventArgs);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
private initializeSpeechRecognition(): void {
|
|
702
|
+
const windowInst: any = window as any;
|
|
703
|
+
const SpeechRecognition: any = windowInst.SpeechRecognition || windowInst.webkitSpeechRecognition;
|
|
704
|
+
if (!SpeechRecognition) {
|
|
705
|
+
this.triggerUnSupportedError();
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
this.recognition = new SpeechRecognition();
|
|
709
|
+
this.recognition.continuous = true;
|
|
710
|
+
this.recognition.lang = this.lang;
|
|
711
|
+
this.recognition.interimResults = this.allowInterimResults;
|
|
712
|
+
|
|
713
|
+
this.recognition.onstart = (event: Event) => {
|
|
714
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
715
|
+
this.isProtectedOnChange = true;
|
|
716
|
+
this.transcript = this.fullTranscript = '';
|
|
717
|
+
this.isProtectedOnChange = prevOnChange;
|
|
718
|
+
const eventArgs: StartListeningEventArgs = {
|
|
719
|
+
cancel: false,
|
|
720
|
+
listeningState: SpeechToTextState.Listening,
|
|
721
|
+
event: event,
|
|
722
|
+
isInteracted: this.isUserInteracted
|
|
723
|
+
};
|
|
724
|
+
this.trigger('onStart', eventArgs, () => {
|
|
725
|
+
if (!eventArgs.cancel) {
|
|
726
|
+
this.handleStartRecognition();
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
this.recognition.abort();
|
|
730
|
+
this.micOn = false;
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
this.recognition.onend = (event: Event) => {
|
|
736
|
+
if (this.hasStarted) {
|
|
737
|
+
this.micOn = false;
|
|
738
|
+
this.handleStopRecognition(event);
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
this.recognition.onerror = (event: any) => {
|
|
743
|
+
let errorMessage: string = '';
|
|
744
|
+
switch (event.error) {
|
|
745
|
+
case 'not-allowed':
|
|
746
|
+
errorMessage = this.l10n.getConstant('notAllowedError');
|
|
747
|
+
break;
|
|
748
|
+
case 'audio-capture':
|
|
749
|
+
errorMessage = this.l10n.getConstant('audioCaptureError');
|
|
750
|
+
break;
|
|
751
|
+
case 'network':
|
|
752
|
+
errorMessage = this.l10n.getConstant('networkError');
|
|
753
|
+
break;
|
|
754
|
+
case 'no-speech':
|
|
755
|
+
errorMessage = this.l10n.getConstant('noSpeechError');
|
|
756
|
+
break;
|
|
757
|
+
case 'aborted':
|
|
758
|
+
errorMessage = this.l10n.getConstant('abortedError');
|
|
759
|
+
break;
|
|
760
|
+
case 'service-not-allowed':
|
|
761
|
+
errorMessage = this.l10n.getConstant('serviceNotAllowedError');
|
|
762
|
+
break;
|
|
763
|
+
default:
|
|
764
|
+
errorMessage = this.l10n.getConstant('defaultError');
|
|
765
|
+
}
|
|
766
|
+
const eventArgs: ErrorEventArgs = {
|
|
767
|
+
event: event,
|
|
768
|
+
error: event.error,
|
|
769
|
+
errorMessage: errorMessage
|
|
770
|
+
};
|
|
771
|
+
this.trigger('onError', eventArgs);
|
|
772
|
+
this.isUserInteracted = false;
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
this.recognition.onresult = (event: any) => {
|
|
776
|
+
const result: SpeechRecognitionResult = event.results[event.resultIndex];
|
|
777
|
+
let interimTranscript: string = '';
|
|
778
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
779
|
+
this.isProtectedOnChange = true;
|
|
780
|
+
if (result.isFinal)
|
|
781
|
+
{
|
|
782
|
+
this.fullTranscript += result[0].transcript;
|
|
783
|
+
this.transcript = this.fullTranscript;
|
|
784
|
+
} else {
|
|
785
|
+
interimTranscript += result[0].transcript;
|
|
786
|
+
this.transcript = this.fullTranscript + interimTranscript;
|
|
787
|
+
}
|
|
788
|
+
const eventArgs: TranscriptChangedEventArgs = {
|
|
789
|
+
event: event,
|
|
790
|
+
transcript: this.transcript,
|
|
791
|
+
isInterimResult: !result.isFinal
|
|
792
|
+
};
|
|
793
|
+
this.trigger('transcriptChanged', eventArgs, () => {
|
|
794
|
+
if (eventArgs.transcript !== this.transcript) {
|
|
795
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
796
|
+
this.isProtectedOnChange = true;
|
|
797
|
+
this.transcript = this.fullTranscript = eventArgs.transcript;
|
|
798
|
+
this.isProtectedOnChange = prevOnChange;
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
this.isProtectedOnChange = prevOnChange;
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
private handleStartRecognition(): void {
|
|
806
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
807
|
+
this.isProtectedOnChange = true;
|
|
808
|
+
this.hasStarted = true;
|
|
809
|
+
this.listeningState = SpeechToTextState.Listening;
|
|
810
|
+
if (!isNOU(this.tooltipInst)) { this.tooltipInst.content = this.tooltipSettings.stopContent; }
|
|
811
|
+
this.updateAriaLabel();
|
|
812
|
+
this.isClicked = true;
|
|
813
|
+
this.buttonInst.cssClass = this.updateButtonCssClass();
|
|
814
|
+
this.buttonInst.content = this.buttonSettings.stopContent;
|
|
815
|
+
const iconCss: string = !isNOU(this.buttonSettings.stopIconCss) && this.buttonSettings.stopIconCss !== '' ? this.buttonSettings.stopIconCss : 'e-icons e-listen-stop';
|
|
816
|
+
this.buttonInst.iconCss = iconCss;
|
|
817
|
+
this.isProtectedOnChange = prevOnChange;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
private triggerUnSupportedStart(event: Event): void {
|
|
821
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
822
|
+
this.isProtectedOnChange = true;
|
|
823
|
+
this.transcript = '';
|
|
824
|
+
this.isProtectedOnChange = prevOnChange;
|
|
825
|
+
const eventArgs: StartListeningEventArgs = {
|
|
826
|
+
cancel: false,
|
|
827
|
+
listeningState: SpeechToTextState.Listening,
|
|
828
|
+
event: event,
|
|
829
|
+
isInteracted: this.isUserInteracted
|
|
830
|
+
};
|
|
831
|
+
this.trigger('onStart', eventArgs, () => {
|
|
832
|
+
if (!eventArgs.cancel) {
|
|
833
|
+
this.handleStartRecognition();
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
private startSpeechRecognition(event?: Event): void {
|
|
839
|
+
if (this.hasStarted) { return; }
|
|
840
|
+
if (this.recognition) {
|
|
841
|
+
this.recognition.start();
|
|
842
|
+
} else {
|
|
843
|
+
this.triggerUnSupportedStart(event);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
private stopSpeechRecognition(event?: Event): void {
|
|
848
|
+
if (this.recognition) {
|
|
849
|
+
this.recognition.stop();
|
|
850
|
+
} else {
|
|
851
|
+
this.handleStopRecognition(event);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
private handleStopRecognition(event?: Event): void {
|
|
856
|
+
if (!this.hasStarted) { return; } // Ensure onStop is only processed if needed
|
|
857
|
+
const prevOnChange: boolean = this.isProtectedOnChange;
|
|
858
|
+
this.isProtectedOnChange = true;
|
|
859
|
+
this.listeningState = SpeechToTextState.Stopped;
|
|
860
|
+
if (!isNOU(this.tooltipInst)) { this.tooltipInst.content = this.tooltipSettings.content; }
|
|
861
|
+
this.updateAriaLabel();
|
|
862
|
+
this.isClicked = false;
|
|
863
|
+
this.buttonInst.cssClass = this.updateButtonCssClass();
|
|
864
|
+
this.buttonInst.content = this.buttonSettings.content;
|
|
865
|
+
const eventArgs: StopListeningEventArgs = {
|
|
866
|
+
listeningState: SpeechToTextState.Stopped,
|
|
867
|
+
event: event,
|
|
868
|
+
isInteracted: this.isUserInteracted
|
|
869
|
+
};
|
|
870
|
+
this.trigger('onStop', eventArgs);
|
|
871
|
+
this.listeningState = SpeechToTextState.Inactive;
|
|
872
|
+
const iconCss: string = !isNOU(this.buttonSettings.iconCss) && this.buttonSettings.iconCss !== '' ? this.buttonSettings.iconCss : 'e-icons e-listen-icon';
|
|
873
|
+
this.buttonInst.iconCss = iconCss;
|
|
874
|
+
this.hasStarted = false;
|
|
875
|
+
this.isProtectedOnChange = prevOnChange;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
private buttonSettingsChanges(oldModel: ButtonSettingsModel, newModel: ButtonSettingsModel): void {
|
|
879
|
+
if (oldModel.content !== newModel.content || oldModel.stopContent !== newModel.stopContent) {
|
|
880
|
+
this.buttonInst.content = this.hasStarted ? this.buttonSettings.stopContent : this.buttonSettings.content;
|
|
881
|
+
this.buttonInst.cssClass = this.updateButtonCssClass();
|
|
882
|
+
}
|
|
883
|
+
if (oldModel.iconCss !== newModel.iconCss || oldModel.stopIconCss !== newModel.stopIconCss) {
|
|
884
|
+
const iconCss: string = !isNOU(this.buttonSettings.iconCss) && this.buttonSettings.iconCss !== '' ? this.buttonSettings.iconCss : 'e-icons e-listen-icon';
|
|
885
|
+
const stopIconCss: string = !isNOU(this.buttonSettings.stopIconCss) && this.buttonSettings.stopIconCss !== '' ? this.buttonSettings.stopIconCss : 'e-icons e-listen-stop';
|
|
886
|
+
this.buttonInst.iconCss = this.hasStarted ? stopIconCss : iconCss;
|
|
887
|
+
}
|
|
888
|
+
if (oldModel.iconPosition !== newModel.iconPosition) {
|
|
889
|
+
this.buttonInst.iconPosition = this.buttonSettings.iconPosition;
|
|
890
|
+
}
|
|
891
|
+
if (oldModel.isPrimary !== newModel.isPrimary) {
|
|
892
|
+
this.buttonInst.isPrimary = this.buttonSettings.isPrimary;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
private destroyAndNullify(obj: any): void {
|
|
897
|
+
if (obj) {
|
|
898
|
+
obj.destroy();
|
|
899
|
+
obj = null;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
//#endregion
|
|
904
|
+
|
|
905
|
+
//#region Public Methods
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Destroy the SpeechToText.
|
|
909
|
+
*
|
|
910
|
+
* @returns {void}
|
|
911
|
+
*/
|
|
912
|
+
public destroy(): void {
|
|
913
|
+
super.destroy();
|
|
914
|
+
this.unWireEvents();
|
|
915
|
+
|
|
916
|
+
this.destroyAndNullify(this.buttonInst);
|
|
917
|
+
this.destroyAndNullify(this.tooltipInst);
|
|
918
|
+
|
|
919
|
+
this.recognition = null;
|
|
920
|
+
this.micOn = null;
|
|
921
|
+
|
|
922
|
+
this.htmlAttributes = this.tooltipSettings = this.buttonSettings = null;
|
|
923
|
+
this.element.classList.remove('e-rtl');
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Begins the audio capture process by listening to the user's microphone input.
|
|
928
|
+
* This method initiates the speech-to-text process and continuously updates the `transcript` property with interim and final recognition results.
|
|
929
|
+
*
|
|
930
|
+
* @returns {void} No return value.
|
|
931
|
+
*/
|
|
932
|
+
public startListening(): void {
|
|
933
|
+
if (!this.disabled && !this.isClicked) {
|
|
934
|
+
this.isUserInteracted = false;
|
|
935
|
+
this.micOn = true;
|
|
936
|
+
this.startSpeechRecognition();
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Stops the audio capture process and finalizes the speech recognition.
|
|
942
|
+
* This method ends the ongoing speech-to-text operation and completes the recognition process, storing the final transcription.
|
|
943
|
+
* It is typically called to stop listening when the user is finished speaking.
|
|
944
|
+
*
|
|
945
|
+
* @returns {void} No return value.
|
|
946
|
+
*/
|
|
947
|
+
public stopListening(): void {
|
|
948
|
+
if (!this.disabled && this.isClicked) {
|
|
949
|
+
this.isUserInteracted = false;
|
|
950
|
+
this.micOn = false;
|
|
951
|
+
this.stopSpeechRecognition();
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* Called if any of the property value is changed.
|
|
957
|
+
*
|
|
958
|
+
* @param {SpeechToTextModel} newProp - Specifies new properties
|
|
959
|
+
* @param {SpeechToTextModel} oldProp - Specifies old properties
|
|
960
|
+
* @returns {void}
|
|
961
|
+
* @private
|
|
962
|
+
*/
|
|
963
|
+
public onPropertyChanged(newProp: SpeechToTextModel, oldProp?: SpeechToTextModel): void {
|
|
964
|
+
for (const prop of Object.keys(newProp)) {
|
|
965
|
+
switch (prop) {
|
|
966
|
+
case 'lang':
|
|
967
|
+
if (this.recognition) { this.recognition.lang = this.lang; }
|
|
968
|
+
break;
|
|
969
|
+
case 'allowInterimResults':
|
|
970
|
+
if (this.recognition) { this.recognition.interimResults = this.allowInterimResults; }
|
|
971
|
+
break;
|
|
972
|
+
case 'buttonSettings':
|
|
973
|
+
this.buttonSettingsChanges(oldProp.buttonSettings, newProp.buttonSettings);
|
|
974
|
+
break;
|
|
975
|
+
case 'cssClass':
|
|
976
|
+
this.updateCssClass(newProp.cssClass, oldProp.cssClass);
|
|
977
|
+
break;
|
|
978
|
+
case 'disabled':
|
|
979
|
+
this.buttonInst.disabled = this.disabled;
|
|
980
|
+
this.handleStateChange();
|
|
981
|
+
break;
|
|
982
|
+
case 'htmlAttributes':
|
|
983
|
+
this.removeHtmlAttributes(oldProp.htmlAttributes);
|
|
984
|
+
this.addHtmlAttributes(newProp.htmlAttributes);
|
|
985
|
+
break;
|
|
986
|
+
case 'listeningState':
|
|
987
|
+
this.handleStateChange();
|
|
988
|
+
break;
|
|
989
|
+
case 'tooltipSettings':
|
|
990
|
+
case 'showTooltip':
|
|
991
|
+
this.updateTooltip();
|
|
992
|
+
break;
|
|
993
|
+
case 'transcript':
|
|
994
|
+
this.transcript = this.fullTranscript = newProp.transcript;
|
|
995
|
+
break;
|
|
996
|
+
case 'enableRtl':
|
|
997
|
+
this.buttonInst.enableRtl = this.tooltipInst.enableRtl = this.enableRtl;
|
|
998
|
+
break;
|
|
999
|
+
case 'locale':
|
|
1000
|
+
this.l10n.setLocale(this.locale);
|
|
1001
|
+
this.updateAriaLabel();
|
|
1002
|
+
this.updateTooltip();
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
//#endregion
|
|
1008
|
+
}
|