UNPKG

20.6 kBJavaScriptView Raw
1import { EditableTextBase as EditableTextBaseCommon, autofillTypeProperty, keyboardTypeProperty, returnKeyTypeProperty, editableProperty, autocapitalizationTypeProperty, autocorrectProperty, hintProperty, placeholderColorProperty, maxLengthProperty } from './editable-text-base-common';
2import { textTransformProperty, textProperty, resetSymbol } from '../text-base';
3import { Color } from '../../color';
4import { ad } from '../../utils';
5import { SDK_VERSION } from '../../utils/constants';
6import * as timer from '../../timer';
7export * from './editable-text-base-common';
8//https://github.com/NativeScript/NativeScript/issues/2942
9export let dismissKeyboardTimeoutId;
10let EditTextListeners;
11function clearDismissTimer() {
12 if (dismissKeyboardTimeoutId) {
13 clearTimeout(dismissKeyboardTimeoutId);
14 dismissKeyboardTimeoutId = null;
15 }
16}
17function dismissSoftInput(view) {
18 clearDismissTimer();
19 if (!dismissKeyboardTimeoutId) {
20 dismissKeyboardTimeoutId = timer.setTimeout(() => {
21 const activity = view._context;
22 dismissKeyboardTimeoutId = null;
23 const focused = activity && activity.getCurrentFocus();
24 if (focused && !(focused instanceof android.widget.EditText)) {
25 // warning `ad.dismissSoftInput` will actually focus the next view
26 // if we pass a null parameter!!!
27 // => focus and show keyboard again
28 // the fix was for where there were multiple TextField for which it would work!
29 // with this it will still work without breaking for single TextField
30 ad.dismissSoftInput(focused);
31 }
32 }, 10);
33 }
34}
35function initializeEditTextListeners() {
36 if (EditTextListeners) {
37 return;
38 }
39 var EditTextListenersImpl = /** @class */ (function (_super) {
40 __extends(EditTextListenersImpl, _super);
41 function EditTextListenersImpl(owner) {
42 var _this = _super.call(this) || this;
43 _this.owner = owner;
44 return global.__native(_this);
45 }
46 EditTextListenersImpl.prototype.beforeTextChanged = function (text, start, count, after) {
47 var _a, _b;
48 (_b = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.beforeTextChanged(text, start, count, after);
49 };
50 EditTextListenersImpl.prototype.onTextChanged = function (text, start, before, count) {
51 var _a, _b;
52 (_b = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.onTextChanged(text, start, before, count);
53 };
54 EditTextListenersImpl.prototype.afterTextChanged = function (editable) {
55 var _a, _b;
56 (_b = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.afterTextChanged(editable);
57 };
58 EditTextListenersImpl.prototype.onFocusChange = function (view, hasFocus) {
59 var _a, _b;
60 (_b = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.onFocusChange(view, hasFocus);
61 };
62 EditTextListenersImpl.prototype.onEditorAction = function (textView, actionId, event) {
63 var _a, _b;
64 return ((_b = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.onEditorAction(textView, actionId, event)) || false;
65 };
66 var _a;
67 EditTextListenersImpl = __decorate([
68 Interfaces([android.text.TextWatcher, android.view.View.OnFocusChangeListener, android.widget.TextView.OnEditorActionListener]),
69 __metadata("design:paramtypes", [typeof (_a = typeof WeakRef !== "undefined" && WeakRef) === "function" ? _a : Object])
70 ], EditTextListenersImpl);
71 return EditTextListenersImpl;
72}(java.lang.Object));
73 EditTextListeners = EditTextListenersImpl;
74}
75export class EditableTextBase extends EditableTextBaseCommon {
76 _onReturnPress() {
77 //
78 }
79 createNativeView() {
80 return new android.widget.EditText(this._context);
81 }
82 initNativeView() {
83 super.initNativeView();
84 const editText = this.nativeTextViewProtected;
85 this._configureEditText(editText);
86 initializeEditTextListeners();
87 const listeners = new EditTextListeners(new WeakRef(this));
88 editText.addTextChangedListener(listeners);
89 editText.setOnFocusChangeListener(listeners);
90 editText.setOnEditorActionListener(listeners);
91 editText.listener = listeners;
92 this._inputType = editText.getInputType();
93 }
94 disposeNativeView() {
95 const editText = this.nativeTextViewProtected;
96 editText.removeTextChangedListener(editText.listener);
97 editText.setOnFocusChangeListener(null);
98 editText.setOnEditorActionListener(null);
99 editText.listener.owner = null;
100 editText.listener = null;
101 this._keyListenerCache = null;
102 super.disposeNativeView();
103 }
104 resetNativeView() {
105 super.resetNativeView();
106 this.nativeTextViewProtected.setInputType(this._inputType);
107 }
108 onUnloaded() {
109 this.dismissSoftInput();
110 super.onUnloaded();
111 }
112 dismissSoftInput() {
113 const nativeView = this.nativeTextViewProtected;
114 if (!nativeView) {
115 return;
116 }
117 ad.dismissSoftInput(nativeView);
118 }
119 focus() {
120 const nativeView = this.nativeTextViewProtected;
121 if (!nativeView) {
122 return;
123 }
124 const result = super.focus();
125 if (result) {
126 ad.showSoftInput(this.nativeTextViewProtected);
127 }
128 return result;
129 }
130 _setInputType(inputType) {
131 const nativeView = this.nativeTextViewProtected;
132 try {
133 this._changeFromCode = true;
134 nativeView.setInputType(parseInt(inputType, 10));
135 }
136 finally {
137 this._changeFromCode = false;
138 }
139 // setInputType will change the keyListener so we should cache it again
140 const listener = nativeView.getKeyListener();
141 if (listener) {
142 this._keyListenerCache = listener;
143 }
144 // clear these fields instead of clearing listener.
145 // this allows input Type to be changed even after editable is false.
146 if (!this.editable) {
147 nativeView.setFocusable(false);
148 nativeView.setFocusableInTouchMode(false);
149 nativeView.setLongClickable(false);
150 nativeView.setClickable(false);
151 }
152 }
153 [textProperty.getDefault]() {
154 return resetSymbol;
155 }
156 [textProperty.setNative](value) {
157 try {
158 this._changeFromCode = true;
159 this._setNativeText(value === resetSymbol);
160 }
161 finally {
162 this._changeFromCode = false;
163 }
164 }
165 [keyboardTypeProperty.getDefault]() {
166 return this.nativeTextViewProtected.getInputType();
167 }
168 [keyboardTypeProperty.setNative](value) {
169 let newInputType;
170 switch (value) {
171 case 'datetime':
172 newInputType = android.text.InputType.TYPE_CLASS_DATETIME | android.text.InputType.TYPE_DATETIME_VARIATION_NORMAL;
173 break;
174 case 'phone':
175 newInputType = android.text.InputType.TYPE_CLASS_PHONE;
176 break;
177 case 'number':
178 newInputType = android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_VARIATION_NORMAL | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL;
179 break;
180 case 'url':
181 newInputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_URI;
182 break;
183 case 'email':
184 newInputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
185 break;
186 case 'integer':
187 newInputType = android.text.InputType.TYPE_CLASS_NUMBER;
188 break;
189 default: {
190 const inputType = +value;
191 if (!isNaN(inputType)) {
192 newInputType = inputType;
193 }
194 else {
195 newInputType = android.text.InputType.TYPE_CLASS_TEXT;
196 }
197 break;
198 }
199 }
200 this._setInputType(newInputType);
201 }
202 [autofillTypeProperty.setNative](value) {
203 if (SDK_VERSION < 26) {
204 return;
205 }
206 let newOptions;
207 switch (value) {
208 case 'phone':
209 newOptions = 'phone'; // android.view.View.AUTOFILL_HINT_PHONE
210 break;
211 case 'postalCode':
212 newOptions = 'postalCode'; // android.view.View.AUTOFILL_HINT_POSTAL_CODE
213 break;
214 case 'creditCardNumber':
215 newOptions = 'creditCardNumber'; // android.view.View.AUTOFILL_HINT_CREDIT_CARD_NUMBER
216 break;
217 case 'email':
218 newOptions = 'emailAddress'; // android.view.View.AUTOFILL_HINT_EMAIL_ADDRESS
219 break;
220 case 'name':
221 newOptions = 'name'; // android.view.View.AUTOFILL_HINT_NAME
222 break;
223 case 'username':
224 newOptions = 'username'; // android.view.View.AUTOFILL_HINT_USERNAME
225 break;
226 case 'password':
227 newOptions = 'password'; // android.view.View.AUTOFILL_HINT_PASSWORD
228 break;
229 case 'newPassword':
230 newOptions = 'newPassword'; // android.view.View.AUTOFILL_HINT_NEW_PASSWORD
231 break;
232 case 'newUsername':
233 newOptions = 'newUsername'; // android.view.View.AUTOFILL_HINT_NEW_USERNAME
234 break;
235 case 'oneTimeCode':
236 newOptions = '2faAppOTPCode'; // android.view.View.AUTOFILL_HINT_2FA_APP_OTP
237 break;
238 case 'none':
239 newOptions = null;
240 break;
241 default: {
242 newOptions = value;
243 break;
244 }
245 }
246 if (newOptions) {
247 const array = Array.create(java.lang.String, 1);
248 array[0] = newOptions;
249 this.nativeTextViewProtected.setAutofillHints(array);
250 }
251 else {
252 this.nativeTextViewProtected.setAutofillHints(null);
253 }
254 }
255 [returnKeyTypeProperty.getDefault]() {
256 const ime = this.nativeTextViewProtected.getImeOptions();
257 switch (ime) {
258 case android.view.inputmethod.EditorInfo.IME_ACTION_DONE:
259 return 'done';
260 case android.view.inputmethod.EditorInfo.IME_ACTION_GO:
261 return 'go';
262 case android.view.inputmethod.EditorInfo.IME_ACTION_NEXT:
263 return 'next';
264 case android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH:
265 return 'search';
266 case android.view.inputmethod.EditorInfo.IME_ACTION_SEND:
267 return 'send';
268 default:
269 return ime.toString();
270 }
271 }
272 [returnKeyTypeProperty.setNative](value) {
273 let newImeOptions;
274 switch (value) {
275 case 'done':
276 newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
277 break;
278 case 'go':
279 newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
280 break;
281 case 'next':
282 newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
283 break;
284 case 'search':
285 newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH;
286 break;
287 case 'send':
288 newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND;
289 break;
290 default: {
291 const ime = +value;
292 if (!isNaN(ime)) {
293 newImeOptions = ime;
294 }
295 else {
296 newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_UNSPECIFIED;
297 }
298 break;
299 }
300 }
301 this.nativeTextViewProtected.setImeOptions(newImeOptions);
302 }
303 [editableProperty.setNative](value) {
304 const nativeView = this.nativeTextViewProtected;
305 if (value) {
306 nativeView.setKeyListener(this._keyListenerCache);
307 }
308 else {
309 if (!this._keyListenerCache) {
310 this._keyListenerCache = nativeView.getKeyListener();
311 }
312 nativeView.setKeyListener(null);
313 }
314 }
315 [autocapitalizationTypeProperty.getDefault]() {
316 const inputType = this.nativeTextViewProtected.getInputType();
317 if ((inputType & android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS) === android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS) {
318 return 'words';
319 }
320 else if ((inputType & android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) === android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) {
321 return 'sentences';
322 }
323 else if ((inputType & android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) === android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) {
324 return 'allcharacters';
325 }
326 else {
327 return inputType.toString();
328 }
329 }
330 [autocapitalizationTypeProperty.setNative](value) {
331 let inputType = this.nativeTextViewProtected.getInputType();
332 inputType = inputType & ~28672; //28672 (0x00070000) 13,14,15bits (111 0000 0000 0000)
333 switch (value) {
334 case 'none':
335 //Do nothing, we have lowered the three bits above.
336 break;
337 case 'words':
338 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS; //8192 (0x00020000) 14th bit
339 break;
340 case 'sentences':
341 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; //16384(0x00040000) 15th bit
342 break;
343 case 'allcharacters':
344 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; //4096 (0x00010000) 13th bit
345 break;
346 default: {
347 const number = +value;
348 // We set the default value.
349 if (!isNaN(number)) {
350 inputType = number;
351 }
352 else {
353 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
354 }
355 break;
356 }
357 }
358 this._setInputType(inputType);
359 }
360 [autocorrectProperty.getDefault]() {
361 const autocorrect = this.nativeTextViewProtected.getInputType();
362 if ((autocorrect & android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) === android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) {
363 return true;
364 }
365 return false;
366 }
367 [autocorrectProperty.setNative](value) {
368 let inputType = this.nativeTextViewProtected.getInputType();
369 switch (value) {
370 case true:
371 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
372 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
373 inputType = inputType & ~android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
374 break;
375 case false:
376 inputType = inputType & ~android.text.InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
377 inputType = inputType & ~android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
378 inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
379 break;
380 default:
381 // We can't do anything.
382 break;
383 }
384 this._setInputType(inputType);
385 }
386 [hintProperty.getDefault]() {
387 return this.nativeTextViewProtected.getHint();
388 }
389 [hintProperty.setNative](value) {
390 const text = value === null || value === undefined ? null : value.toString();
391 this.nativeTextViewProtected.setHint(text);
392 }
393 [placeholderColorProperty.getDefault]() {
394 return this.nativeTextViewProtected.getHintTextColors();
395 }
396 [placeholderColorProperty.setNative](value) {
397 const color = value instanceof Color ? value.android : value;
398 this.nativeTextViewProtected.setHintTextColor(color);
399 }
400 [textTransformProperty.setNative](value) {
401 //
402 }
403 [maxLengthProperty.setNative](value) {
404 if (value === Number.POSITIVE_INFINITY) {
405 this.nativeTextViewProtected.setFilters([]);
406 }
407 else {
408 const lengthFilter = new android.text.InputFilter.LengthFilter(value);
409 const filters = this.nativeTextViewProtected.getFilters();
410 const newFilters = [];
411 // retain existing filters
412 for (let i = 0; i < filters.length; i++) {
413 const filter = filters[i];
414 if (!(filter instanceof android.text.InputFilter.LengthFilter)) {
415 newFilters.push(filter);
416 }
417 }
418 newFilters.push(lengthFilter);
419 this.nativeTextViewProtected.setFilters(newFilters);
420 }
421 }
422 setSelection(start, stop) {
423 const view = this.nativeTextViewProtected;
424 if (view) {
425 if (stop !== undefined) {
426 view.setSelection(start, stop);
427 }
428 else {
429 view.setSelection(start);
430 }
431 }
432 }
433 beforeTextChanged(text, start, count, after) {
434 // called by android.text.TextWatcher
435 }
436 onTextChanged(text, start, before, count) {
437 // called by android.text.TextWatcher
438 if (this.valueFormatter) {
439 this.text = this.valueFormatter(text.toString());
440 this.android.setSelection((this.text || '').length);
441 }
442 // const owner = this.owner;
443 // let selectionStart = owner.android.getSelectionStart();
444 // owner.android.removeTextChangedListener(owner._editTextListeners);
445 // owner.android.addTextChangedListener(owner._editTextListeners);
446 // owner.android.setSelection(selectionStart);
447 }
448 afterTextChanged(editable) {
449 // called by android.text.TextWatcher
450 if (this._changeFromCode) {
451 return;
452 }
453 switch (this.updateTextTrigger) {
454 case 'focusLost':
455 this._dirtyTextAccumulator = editable.toString();
456 break;
457 case 'textChanged':
458 textProperty.nativeValueChange(this, editable.toString());
459 break;
460 default:
461 throw new Error('Invalid updateTextTrigger: ' + this.updateTextTrigger);
462 }
463 }
464 onFocusChange(view, hasFocus) {
465 if (hasFocus) {
466 clearDismissTimer();
467 this.notify({ eventName: EditableTextBase.focusEvent });
468 }
469 else {
470 if (this._dirtyTextAccumulator || this._dirtyTextAccumulator === '') {
471 textProperty.nativeValueChange(this, this._dirtyTextAccumulator);
472 this._dirtyTextAccumulator = undefined;
473 }
474 this.notify({ eventName: EditableTextBase.blurEvent });
475 dismissSoftInput(this);
476 }
477 }
478 onEditorAction(textView, actionId, event) {
479 if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_DONE || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_UNSPECIFIED || (event && event.getKeyCode() === android.view.KeyEvent.KEYCODE_ENTER)) {
480 // If it is TextField, close the keyboard. If it is TextView, do not close it since the TextView is multiline
481 // https://github.com/NativeScript/NativeScript/issues/3111
482 if (textView.getMaxLines() === 1) {
483 this.dismissSoftInput();
484 }
485 this._onReturnPress();
486 }
487 else if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_NEXT || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS) {
488 // do not close keyboard for ACTION_NEXT or ACTION_PREVIOUS
489 this._onReturnPress();
490 }
491 return false;
492 }
493}
494//# sourceMappingURL=index.android.js.map
\No newline at end of file