Skip to content

Commit ceeb7cd

Browse files
author
marker dao ®
committed
feat(m_text_editor.mask.strategy.ts): Improve typing
1 parent 7ffb196 commit ceeb7cd

2 files changed

Lines changed: 101 additions & 60 deletions

File tree

Lines changed: 100 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
/* eslint-disable @typescript-eslint/no-unused-vars */
12
import EventsEngine from '@js/common/core/events/core/events_engine';
23
import { addNamespace } from '@js/common/core/events/utils/index';
4+
import type { dxElementWrapper } from '@js/core/renderer';
35
import browser from '@js/core/utils/browser';
46
import { clipboardText as getClipboardText } from '@js/core/utils/dom';
7+
import type { DxEvent } from '@js/events';
8+
import type { TextEditorBaseProperties } from '@ts/ui/text_box/m_text_editor.base';
9+
import type TextEditorMask from '@ts/ui/text_box/m_text_editor.mask';
10+
import type { HandlingArgs } from '@ts/ui/text_box/m_text_editor.mask.rule';
11+
import type { CaretRange } from '@ts/ui/text_box/utils.caret';
512

613
const MASK_EVENT_NAMESPACE = 'dxMask';
714
const BLUR_EVENT = 'blur beforedeactivate';
@@ -10,64 +17,75 @@ const DELETE_INPUT_TYPES = ['deleteContentBackward', 'deleteSoftLineBackward', '
1017
const HISTORY_INPUT_TYPES = ['historyUndo', 'historyRedo'];
1118
const EVENT_NAMES = ['focusIn', 'focusOut', 'input', 'paste', 'cut', 'drop', 'beforeInput'];
1219

13-
function getEmptyString(length) {
14-
return EMPTY_CHAR.repeat(length);
15-
}
20+
const getEmptyString = (length: number): string => EMPTY_CHAR.repeat(length);
1621

1722
export default class MaskStrategy {
18-
editor: any;
23+
editor: TextEditorMask;
1924

20-
_dragTimer?: any;
25+
_dragTimer?: ReturnType<typeof setTimeout>;
2126

22-
_inputHandlerTimer?: any;
27+
_inputHandlerTimer?: ReturnType<typeof setTimeout>;
2328

24-
_caretTimeout?: any;
29+
_caretTimeout?: ReturnType<typeof setTimeout>;
2530

26-
_prevCaret?: any;
31+
_prevCaret?: CaretRange;
2732

2833
_previousText?: string;
2934

30-
constructor(editor) {
35+
constructor(editor: TextEditorMask) {
3136
this.editor = editor;
3237
}
3338

34-
_editorOption() {
39+
_editorOption<K extends keyof TextEditorBaseProperties>(name: K): TextEditorBaseProperties[K];
40+
_editorOption<K extends keyof TextEditorBaseProperties>(
41+
name: K,
42+
value: TextEditorBaseProperties[K],
43+
): void;
44+
_editorOption<K extends keyof TextEditorBaseProperties>(
45+
name: K,
46+
value?: TextEditorBaseProperties[K],
47+
): TextEditorBaseProperties[K] | void {
48+
// eslint-disable-next-line prefer-rest-params
3549
return this.editor.option(...arguments);
3650
}
3751

38-
_editorInput() {
52+
_editorInput(): dxElementWrapper {
3953
return this.editor._input();
4054
}
4155

42-
_editorCaret(newCaret?: any) {
56+
_editorCaret(): CaretRange;
57+
_editorCaret(newCaret: CaretRange | undefined): void;
58+
// eslint-disable-next-line consistent-return
59+
_editorCaret(newCaret?: CaretRange | undefined): CaretRange | void {
4360
if (!newCaret) {
4461
return this.editor._caret();
4562
}
4663

4764
this.editor._caret(newCaret);
4865
}
4966

50-
_attachChangeEventHandler() {
51-
// @ts-expect-error
67+
_attachChangeEventHandler(): void {
68+
// @ts-expect-error ts-expect-error
5269
if (!this._editorOption('valueChangeEvent').split(' ').includes('change')) {
5370
return;
5471
}
5572

5673
const $input = this._editorInput();
5774
const namespace = addNamespace(BLUR_EVENT, MASK_EVENT_NAMESPACE);
75+
5876
EventsEngine.on($input, namespace, (e) => {
5977
this.editor._changeHandler(e);
6078
});
6179
}
6280

63-
_beforeInputHandler() {
64-
// @ts-expect-error
81+
_beforeInputHandler(): void {
6582
this._previousText = this._editorOption('text');
6683
this._prevCaret = this._editorCaret();
6784
}
6885

69-
_inputHandler(event) {
86+
_inputHandler(event: DxEvent<InputEvent>): void {
7087
const { originalEvent } = event;
88+
7189
if (!originalEvent) {
7290
return;
7391
}
@@ -81,7 +99,7 @@ export default class MaskStrategy {
8199
} else {
82100
const currentCaret = this._editorCaret();
83101

84-
if (!currentCaret.end) {
102+
if (!currentCaret?.end) {
85103
return;
86104
}
87105

@@ -90,63 +108,66 @@ export default class MaskStrategy {
90108
this._editorCaret(currentCaret);
91109
this._handleInsertTextInputEvent(originalEvent.data);
92110
}
93-
// @ts-expect-error
111+
94112
if (this._editorOption('text') === this._previousText) {
95113
event.stopImmediatePropagation();
96114
}
97115
}
98116

99-
_handleHistoryInputEvent() {
117+
_handleHistoryInputEvent(): void {
100118
const caret = this._editorCaret();
101119

102120
this._updateEditorMask({
103-
start: caret.start,
104-
length: caret.end - caret.start,
121+
start: caret?.start,
122+
length: (caret?.end ?? 0) - (caret?.start ?? 0),
105123
text: '',
106124
});
107125

108126
this._editorCaret(this._prevCaret);
109127
}
110128

111-
_handleBackwardDeleteInputEvent() {
129+
_handleBackwardDeleteInputEvent(): void {
112130
this._clearSelectedText(true);
113131

114132
const caret = this._editorCaret();
133+
115134
this.editor.setForwardDirection();
116135
this.editor._adjustCaret();
117136

118137
const adjustedForwardCaret = this._editorCaret();
119-
if (adjustedForwardCaret.start !== caret.start) {
138+
139+
if (adjustedForwardCaret?.start !== caret?.start) {
120140
this.editor.setBackwardDirection();
121141
this.editor._adjustCaret();
122142
}
123143
}
124144

125145
_clearSelectedText(isDeleteInputEvent?: boolean): void {
126146
const selectionLength = this._prevCaret && (this._prevCaret.end - this._prevCaret.start);
127-
const length = selectionLength || Number(isDeleteInputEvent);
147+
const length = selectionLength ?? Number(isDeleteInputEvent);
128148

129149
const caret = this._editorCaret();
130150

131151
if (!this._isAutoFill()) {
132152
this.editor.setBackwardDirection();
153+
133154
this._updateEditorMask({
134-
start: caret.start,
155+
start: caret?.start,
135156
length,
136157
text: getEmptyString(length),
137158
});
138159
}
139160
}
140161

141-
_handleInsertTextInputEvent(data) {
162+
_handleInsertTextInputEvent(data: DxEvent<InputEvent>['data']): void {
142163
// NOTE: data has length > 1 when autosuggestion is applied.
143164
const text = data ?? '';
144165

145166
this.editor.setForwardDirection();
146167

147168
const hasValidChars = this._updateEditorMask({
148169
start: this._prevCaret?.start ?? 0,
149-
length: text.length || 1,
170+
length: text.length ?? 1,
150171
text,
151172
});
152173

@@ -155,80 +176,91 @@ export default class MaskStrategy {
155176
}
156177
}
157178

158-
_updateEditorMask(args) {
159-
const textLength = args.text.length;
160-
const processedCharsCount = this.editor._handleChain(args);
179+
_updateEditorMask(args: HandlingArgs): boolean {
180+
const textLength = args.text?.length ?? 0;
181+
const processedCharsCount = this.editor._handleChain(args) ?? 0;
161182

162183
this.editor._displayMask();
163184

164185
if (this.editor.isForwardDirection()) {
165-
const { start, end } = this._editorCaret();
166-
const correction = processedCharsCount - textLength;
186+
const { start = 0, end = 0 } = this._editorCaret() ?? {};
167187

188+
const correction = processedCharsCount - textLength;
168189
const hasSkippedStub = processedCharsCount > 1;
190+
169191
if (hasSkippedStub && textLength === 1) {
170-
this._editorCaret({ start: start + correction, end: end + correction });
192+
this._editorCaret({
193+
start: start + correction,
194+
end: end + correction,
195+
});
171196
}
172197

173198
this.editor._adjustCaret();
174199
}
175200

176-
return !!processedCharsCount;
201+
return Boolean(processedCharsCount);
177202
}
178203

179-
_focusInHandler() {
204+
_focusInHandler(): void {
180205
this.editor._showMaskPlaceholder();
181206
this.editor.setForwardDirection();
182-
// @ts-expect-error
207+
183208
if (!this.editor._isValueEmpty() && this._editorOption('isValid')) {
184209
this.editor._adjustCaret();
185210
} else {
186211
const caret = this.editor._maskRulesChain.first();
212+
213+
// eslint-disable-next-line no-restricted-globals
187214
this._caretTimeout = setTimeout(() => {
188215
this._editorCaret({ start: caret, end: caret });
189216
}, 0);
190217
}
191218
}
192219

193-
_focusOutHandler(event) {
220+
_focusOutHandler(event: DxEvent<FocusEvent>): void {
194221
this.editor._changeHandler(event);
195-
// @ts-expect-error
222+
196223
if (this._editorOption('showMaskMode') === 'onFocus' && this.editor._isValueEmpty()) {
197-
// @ts-expect-error
198224
this._editorOption('text', '');
199225
this.editor._renderDisplayText('');
200226
}
201227
}
202228

203-
_delHandler(event) {
229+
_delHandler(event: DxEvent<KeyboardEvent>): void {
204230
const { editor } = this;
205231

206-
editor._maskKeyHandler(event, () => {
232+
editor._maskKeyHandler(event, (): undefined => {
207233
if (!editor._hasSelection()) {
234+
// @ts-expect-error bad editor type
208235
editor._handleKey(EMPTY_CHAR);
209236
}
210237
});
211238
}
212239

213-
_cutHandler(event) {
240+
_cutHandler(event: DxEvent<ClipboardEvent>): void {
214241
const caret = this._editorCaret();
215-
const selectedText = this._editorInput().val().substring(caret.start, caret.end);
242+
const inputVal = this._editorInput().val();
243+
244+
// @ts-expect-error dxElementWrapper.val() should return string
245+
const selectedText = inputVal.substring(caret?.start, caret?.end);
216246

217-
this.editor._maskKeyHandler(event, () => getClipboardText(event, selectedText));
247+
this.editor._maskKeyHandler(event, () => (getClipboardText(event, selectedText)) as string);
218248
}
219249

220-
_dropHandler() {
250+
_dropHandler(): void {
221251
this._clearDragTimer();
252+
253+
// eslint-disable-next-line no-restricted-globals
222254
this._dragTimer = setTimeout(() => {
223255
const value = this.editor._convertToValue(this._editorInput().val());
224-
// @ts-expect-error
256+
225257
this._editorOption('value', value);
226258
});
227259
}
228260

229-
_pasteHandler(event) {
261+
_pasteHandler(event: DxEvent<ClipboardEvent>): void {
230262
const { editor } = this;
231-
// @ts-expect-error
263+
232264
if (this._editorOption('disabled')) {
233265
return;
234266
}
@@ -237,29 +269,36 @@ export default class MaskStrategy {
237269

238270
editor._maskKeyHandler(event, () => {
239271
const pastedText = getClipboardText(event);
240-
const restText = editor._maskRulesChain.text().substring(caret.end);
241-
const accepted = editor._handleChain({ text: pastedText, start: caret.start, length: pastedText.length });
242-
const newCaret = caret.start + accepted;
272+
const restText = editor._maskRulesChain.text().substring(caret?.end);
273+
const accepted = editor._handleChain({
274+
text: pastedText,
275+
start: caret?.start,
276+
length: pastedText.length,
277+
});
278+
const newCaret = (caret?.start ?? 0) + accepted;
243279

244280
editor._handleChain({ text: restText, start: newCaret, length: restText.length });
245281
editor._caret({ start: newCaret, end: newCaret });
246282
});
247283
}
248284

249-
_autoFillHandler(event) {
285+
_autoFillHandler(event: InputEvent): void {
250286
const { editor } = this;
251287
const inputVal = this._editorInput().val();
288+
289+
// eslint-disable-next-line no-restricted-globals
252290
this._inputHandlerTimer = setTimeout(() => {
253291
if (this._isAutoFill()) {
254292
editor._maskKeyHandler(event, () => {
255293
editor._handleChain({ text: inputVal, start: 0, length: inputVal.length });
256294
});
295+
257296
editor._validateMask();
258297
}
259298
});
260299
}
261300

262-
_isAutoFill() {
301+
_isAutoFill(): boolean {
263302
const $input = this._editorInput();
264303

265304
if (browser.webkit) {
@@ -270,23 +309,23 @@ export default class MaskStrategy {
270309
return false;
271310
}
272311

273-
_clearDragTimer() {
312+
_clearDragTimer(): void {
274313
clearTimeout(this._dragTimer);
275314
}
276315

277-
_clearTimers() {
316+
_clearTimers(): void {
278317
this._clearDragTimer();
279318
clearTimeout(this._caretTimeout);
280319
clearTimeout(this._inputHandlerTimer);
281320
}
282321

283-
getHandler(handlerName) {
322+
getHandler(handlerName: string): (args: unknown) => void {
284323
return (args) => {
285324
this[`_${handlerName}Handler`]?.(args);
286325
};
287326
}
288327

289-
attachEvents() {
328+
attachEvents(): void {
290329
const $input = this._editorInput();
291330

292331
EVENT_NAMES.forEach((eventName) => {
@@ -297,12 +336,13 @@ export default class MaskStrategy {
297336
this._attachChangeEventHandler();
298337
}
299338

300-
detachEvents() {
339+
detachEvents(): void {
301340
this._clearTimers();
341+
302342
EventsEngine.off(this._editorInput(), `.${MASK_EVENT_NAMESPACE}`);
303343
}
304344

305-
clean() {
345+
clean(): void {
306346
this._clearTimers();
307347
}
308348
}

0 commit comments

Comments
 (0)