mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 04:18:52 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			564 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			564 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { EditableTextBase as EditableTextBaseCommon, autofillTypeProperty, keyboardTypeProperty, returnKeyTypeProperty, editableProperty, autocapitalizationTypeProperty, autocorrectProperty, hintProperty, placeholderColorProperty, maxLengthProperty } from './editable-text-base-common';
 | 
						|
import { textTransformProperty, textProperty, resetSymbol } from '../text-base';
 | 
						|
import { Color } from '../../color';
 | 
						|
import { ad } from '../../utils';
 | 
						|
import { SDK_VERSION } from '../../utils/constants';
 | 
						|
import { CoreTypes } from '../../core-types';
 | 
						|
import * as timer from '../../timer';
 | 
						|
 | 
						|
export * from './editable-text-base-common';
 | 
						|
 | 
						|
//https://github.com/NativeScript/NativeScript/issues/2942
 | 
						|
export let dismissKeyboardTimeoutId: number;
 | 
						|
 | 
						|
interface EditTextListeners extends android.text.TextWatcher, android.view.View.OnFocusChangeListener, android.widget.TextView.OnEditorActionListener {}
 | 
						|
 | 
						|
interface EditTextListenersClass {
 | 
						|
	prototype: EditTextListeners;
 | 
						|
	new (owner: WeakRef<EditableTextBase>): EditTextListeners;
 | 
						|
}
 | 
						|
 | 
						|
let EditTextListeners: EditTextListenersClass;
 | 
						|
 | 
						|
function clearDismissTimer(): void {
 | 
						|
	if (dismissKeyboardTimeoutId) {
 | 
						|
		clearTimeout(dismissKeyboardTimeoutId);
 | 
						|
		dismissKeyboardTimeoutId = null;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function dismissSoftInput(view: EditableTextBase): void {
 | 
						|
	clearDismissTimer();
 | 
						|
	if (!dismissKeyboardTimeoutId) {
 | 
						|
		dismissKeyboardTimeoutId = timer.setTimeout(() => {
 | 
						|
			const activity = view._context as androidx.appcompat.app.AppCompatActivity;
 | 
						|
			dismissKeyboardTimeoutId = null;
 | 
						|
			const focused = activity && activity.getCurrentFocus();
 | 
						|
			if (focused && !(focused instanceof android.widget.EditText)) {
 | 
						|
				// warning `ad.dismissSoftInput` will actually focus the next view
 | 
						|
				// if we pass a null parameter!!!
 | 
						|
				// => focus and show keyboard again
 | 
						|
				// the fix was for where there were multiple TextField for which it would work!
 | 
						|
				// with this it will still work without breaking for single TextField
 | 
						|
				ad.dismissSoftInput(focused);
 | 
						|
			}
 | 
						|
		}, 10);
 | 
						|
	}
 | 
						|
}
 | 
						|
function initializeEditTextListeners(): void {
 | 
						|
	if (EditTextListeners) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	@NativeClass
 | 
						|
	@Interfaces([android.text.TextWatcher, android.view.View.OnFocusChangeListener, android.widget.TextView.OnEditorActionListener])
 | 
						|
	class EditTextListenersImpl extends java.lang.Object implements android.text.TextWatcher, android.view.View.OnFocusChangeListener, android.widget.TextView.OnEditorActionListener {
 | 
						|
		constructor(private owner: WeakRef<EditableTextBase>) {
 | 
						|
			super();
 | 
						|
 | 
						|
			return global.__native(this);
 | 
						|
		}
 | 
						|
 | 
						|
		public beforeTextChanged(text: string, start: number, count: number, after: number): void {
 | 
						|
			this.owner?.get()?.beforeTextChanged(text, start, count, after);
 | 
						|
		}
 | 
						|
 | 
						|
		public onTextChanged(text: string, start: number, before: number, count: number): void {
 | 
						|
			this.owner?.get()?.onTextChanged(text, start, before, count);
 | 
						|
		}
 | 
						|
 | 
						|
		public afterTextChanged(editable: android.text.Editable): void {
 | 
						|
			this.owner?.get()?.afterTextChanged(editable);
 | 
						|
		}
 | 
						|
 | 
						|
		public onFocusChange(view: android.view.View, hasFocus: boolean): void {
 | 
						|
			this.owner?.get()?.onFocusChange(view, hasFocus);
 | 
						|
		}
 | 
						|
 | 
						|
		public onEditorAction(textView: android.widget.TextView, actionId: number, event: android.view.KeyEvent): boolean {
 | 
						|
			return this.owner?.get()?.onEditorAction(textView, actionId, event) || false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	EditTextListeners = EditTextListenersImpl;
 | 
						|
}
 | 
						|
 | 
						|
export abstract class EditableTextBase extends EditableTextBaseCommon {
 | 
						|
	nativeViewProtected: android.widget.EditText;
 | 
						|
	nativeTextViewProtected: android.widget.EditText;
 | 
						|
 | 
						|
	private _dirtyTextAccumulator: string;
 | 
						|
	private _keyListenerCache: android.text.method.KeyListener;
 | 
						|
	private _inputType: number;
 | 
						|
 | 
						|
	public _changeFromCode: boolean;
 | 
						|
 | 
						|
	public abstract _configureEditText(editText: android.widget.EditText): void;
 | 
						|
 | 
						|
	public _onReturnPress(): void {
 | 
						|
		//
 | 
						|
	}
 | 
						|
 | 
						|
	public createNativeView() {
 | 
						|
		return new android.widget.EditText(this._context);
 | 
						|
	}
 | 
						|
 | 
						|
	public initNativeView(): void {
 | 
						|
		super.initNativeView();
 | 
						|
		const editText = this.nativeTextViewProtected;
 | 
						|
		this._configureEditText(editText);
 | 
						|
		initializeEditTextListeners();
 | 
						|
		const listeners = new EditTextListeners(new WeakRef(this));
 | 
						|
		editText.addTextChangedListener(listeners);
 | 
						|
		editText.setOnFocusChangeListener(listeners);
 | 
						|
		editText.setOnEditorActionListener(listeners);
 | 
						|
		(<any>editText).listener = listeners;
 | 
						|
		this._inputType = editText.getInputType();
 | 
						|
	}
 | 
						|
 | 
						|
	public disposeNativeView(): void {
 | 
						|
		const editText = this.nativeTextViewProtected;
 | 
						|
 | 
						|
		editText.removeTextChangedListener((<any>editText).listener);
 | 
						|
		editText.setOnFocusChangeListener(null);
 | 
						|
		editText.setOnEditorActionListener(null);
 | 
						|
		(<any>editText).listener.owner = null;
 | 
						|
		(<any>editText).listener = null;
 | 
						|
		this._keyListenerCache = null;
 | 
						|
		this._dirtyTextAccumulator = undefined;
 | 
						|
		this._inputType = 0;
 | 
						|
 | 
						|
		super.disposeNativeView();
 | 
						|
	}
 | 
						|
 | 
						|
	public resetNativeView(): void {
 | 
						|
		super.resetNativeView();
 | 
						|
		this.nativeTextViewProtected.setInputType(this._inputType);
 | 
						|
	}
 | 
						|
 | 
						|
	public onUnloaded() {
 | 
						|
		this.dismissSoftInput();
 | 
						|
		super.onUnloaded();
 | 
						|
	}
 | 
						|
 | 
						|
	public dismissSoftInput() {
 | 
						|
		const nativeView = this.nativeTextViewProtected;
 | 
						|
		if (!nativeView) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		ad.dismissSoftInput(nativeView);
 | 
						|
	}
 | 
						|
 | 
						|
	public focus(): boolean {
 | 
						|
		const nativeView = this.nativeTextViewProtected;
 | 
						|
		if (!nativeView) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		const result = super.focus();
 | 
						|
		if (result) {
 | 
						|
			ad.showSoftInput(this.nativeTextViewProtected);
 | 
						|
		}
 | 
						|
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
 | 
						|
	public _setInputType(inputType: number): void {
 | 
						|
		const nativeView = this.nativeTextViewProtected;
 | 
						|
		try {
 | 
						|
			this._changeFromCode = true;
 | 
						|
			nativeView.setInputType(parseInt(<any>inputType, 10));
 | 
						|
		} finally {
 | 
						|
			this._changeFromCode = false;
 | 
						|
		}
 | 
						|
 | 
						|
		// setInputType will change the keyListener so we should cache it again
 | 
						|
		const listener = nativeView.getKeyListener();
 | 
						|
		if (listener) {
 | 
						|
			this._keyListenerCache = listener;
 | 
						|
		}
 | 
						|
 | 
						|
		// clear these fields instead of clearing listener.
 | 
						|
		// this allows input Type to be changed even after editable is false.
 | 
						|
		if (!this.editable) {
 | 
						|
			nativeView.setFocusable(false);
 | 
						|
			nativeView.setFocusableInTouchMode(false);
 | 
						|
			nativeView.setLongClickable(false);
 | 
						|
			nativeView.setClickable(false);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	[textProperty.getDefault](): number | symbol {
 | 
						|
		return resetSymbol;
 | 
						|
	}
 | 
						|
	[textProperty.setNative](value: string | number | symbol) {
 | 
						|
		try {
 | 
						|
			this._changeFromCode = true;
 | 
						|
			this._setNativeText(value === resetSymbol);
 | 
						|
		} finally {
 | 
						|
			this._changeFromCode = false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	[keyboardTypeProperty.getDefault](): number {
 | 
						|
		return this.nativeTextViewProtected.getInputType();
 | 
						|
	}
 | 
						|
	[keyboardTypeProperty.setNative](value: 'datetime' | 'phone' | 'number' | 'decimal' | 'url' | 'email' | 'integer' | number) {
 | 
						|
		let newInputType;
 | 
						|
 | 
						|
		switch (value) {
 | 
						|
			case 'datetime':
 | 
						|
				newInputType = android.text.InputType.TYPE_CLASS_DATETIME | android.text.InputType.TYPE_DATETIME_VARIATION_NORMAL;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'phone':
 | 
						|
				newInputType = android.text.InputType.TYPE_CLASS_PHONE;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'number':
 | 
						|
				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;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'decimal':
 | 
						|
				newInputType = android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'url':
 | 
						|
				newInputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_URI;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'email':
 | 
						|
				newInputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'integer':
 | 
						|
				newInputType = android.text.InputType.TYPE_CLASS_NUMBER;
 | 
						|
				break;
 | 
						|
 | 
						|
			default: {
 | 
						|
				const inputType = +value;
 | 
						|
				if (!isNaN(inputType)) {
 | 
						|
					newInputType = inputType;
 | 
						|
				} else {
 | 
						|
					newInputType = android.text.InputType.TYPE_CLASS_TEXT;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		this._setInputType(newInputType);
 | 
						|
	}
 | 
						|
 | 
						|
	[autofillTypeProperty.setNative](value: CoreTypes.AutofillType) {
 | 
						|
		if (SDK_VERSION < 26) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		let newOptions;
 | 
						|
		switch (value) {
 | 
						|
			case 'phone':
 | 
						|
				newOptions = 'phone'; // android.view.View.AUTOFILL_HINT_PHONE
 | 
						|
				break;
 | 
						|
			case 'postalCode':
 | 
						|
				newOptions = 'postalCode'; // android.view.View.AUTOFILL_HINT_POSTAL_CODE
 | 
						|
				break;
 | 
						|
			case 'creditCardNumber':
 | 
						|
				newOptions = 'creditCardNumber'; // android.view.View.AUTOFILL_HINT_CREDIT_CARD_NUMBER
 | 
						|
				break;
 | 
						|
			case 'email':
 | 
						|
				newOptions = 'emailAddress'; // android.view.View.AUTOFILL_HINT_EMAIL_ADDRESS
 | 
						|
				break;
 | 
						|
			case 'name':
 | 
						|
				newOptions = 'name'; // android.view.View.AUTOFILL_HINT_NAME
 | 
						|
				break;
 | 
						|
			case 'username':
 | 
						|
				newOptions = 'username'; // android.view.View.AUTOFILL_HINT_USERNAME
 | 
						|
				break;
 | 
						|
			case 'password':
 | 
						|
				newOptions = 'password'; // android.view.View.AUTOFILL_HINT_PASSWORD
 | 
						|
				break;
 | 
						|
			case 'newPassword':
 | 
						|
				newOptions = 'newPassword'; // android.view.View.AUTOFILL_HINT_NEW_PASSWORD
 | 
						|
				break;
 | 
						|
			case 'newUsername':
 | 
						|
				newOptions = 'newUsername'; // android.view.View.AUTOFILL_HINT_NEW_USERNAME
 | 
						|
				break;
 | 
						|
			case 'oneTimeCode':
 | 
						|
				newOptions = '2faAppOTPCode'; // android.view.View.AUTOFILL_HINT_2FA_APP_OTP
 | 
						|
				break;
 | 
						|
			case 'none':
 | 
						|
				newOptions = null;
 | 
						|
				break;
 | 
						|
			default: {
 | 
						|
				newOptions = value;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (newOptions) {
 | 
						|
			const array = Array.create(java.lang.String, 1);
 | 
						|
			array[0] = newOptions;
 | 
						|
			this.nativeTextViewProtected.setAutofillHints(array);
 | 
						|
		} else {
 | 
						|
			this.nativeTextViewProtected.setAutofillHints(null);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	[returnKeyTypeProperty.getDefault](): 'done' | 'next' | 'go' | 'search' | 'send' | string {
 | 
						|
		const ime = this.nativeTextViewProtected.getImeOptions();
 | 
						|
		switch (ime) {
 | 
						|
			case android.view.inputmethod.EditorInfo.IME_ACTION_DONE:
 | 
						|
				return 'done';
 | 
						|
 | 
						|
			case android.view.inputmethod.EditorInfo.IME_ACTION_GO:
 | 
						|
				return 'go';
 | 
						|
 | 
						|
			case android.view.inputmethod.EditorInfo.IME_ACTION_NEXT:
 | 
						|
				return 'next';
 | 
						|
 | 
						|
			case android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH:
 | 
						|
				return 'search';
 | 
						|
 | 
						|
			case android.view.inputmethod.EditorInfo.IME_ACTION_SEND:
 | 
						|
				return 'send';
 | 
						|
 | 
						|
			default:
 | 
						|
				return ime.toString();
 | 
						|
		}
 | 
						|
	}
 | 
						|
	[returnKeyTypeProperty.setNative](value: 'done' | 'next' | 'go' | 'search' | 'send' | string) {
 | 
						|
		let newImeOptions;
 | 
						|
		switch (value) {
 | 
						|
			case 'done':
 | 
						|
				newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
 | 
						|
				break;
 | 
						|
			case 'go':
 | 
						|
				newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
 | 
						|
				break;
 | 
						|
			case 'next':
 | 
						|
				newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
 | 
						|
				break;
 | 
						|
			case 'search':
 | 
						|
				newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH;
 | 
						|
				break;
 | 
						|
			case 'send':
 | 
						|
				newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND;
 | 
						|
				break;
 | 
						|
			default: {
 | 
						|
				const ime = +value;
 | 
						|
				if (!isNaN(ime)) {
 | 
						|
					newImeOptions = ime;
 | 
						|
				} else {
 | 
						|
					newImeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_UNSPECIFIED;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		this.nativeTextViewProtected.setImeOptions(newImeOptions);
 | 
						|
	}
 | 
						|
 | 
						|
	[editableProperty.setNative](value: boolean) {
 | 
						|
		const nativeView = this.nativeTextViewProtected;
 | 
						|
		if (value) {
 | 
						|
			nativeView.setKeyListener(this._keyListenerCache);
 | 
						|
		} else {
 | 
						|
			if (!this._keyListenerCache) {
 | 
						|
				this._keyListenerCache = nativeView.getKeyListener();
 | 
						|
			}
 | 
						|
			nativeView.setKeyListener(null);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	[autocapitalizationTypeProperty.getDefault](): 'none' | 'words' | 'sentences' | 'allcharacters' | string {
 | 
						|
		const inputType = this.nativeTextViewProtected.getInputType();
 | 
						|
		if ((inputType & android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS) === android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS) {
 | 
						|
			return 'words';
 | 
						|
		} else if ((inputType & android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) === android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) {
 | 
						|
			return 'sentences';
 | 
						|
		} else if ((inputType & android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) === android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) {
 | 
						|
			return 'allcharacters';
 | 
						|
		} else {
 | 
						|
			return inputType.toString();
 | 
						|
		}
 | 
						|
	}
 | 
						|
	[autocapitalizationTypeProperty.setNative](value: string) {
 | 
						|
		let inputType = this.nativeTextViewProtected.getInputType();
 | 
						|
		inputType = inputType & ~28672; //28672 (0x00070000) 13,14,15bits (111 0000 0000 0000)
 | 
						|
 | 
						|
		switch (value) {
 | 
						|
			case 'none':
 | 
						|
				//Do nothing, we have lowered the three bits above.
 | 
						|
				break;
 | 
						|
			case 'words':
 | 
						|
				inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS; //8192 (0x00020000) 14th bit
 | 
						|
				break;
 | 
						|
			case 'sentences':
 | 
						|
				inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; //16384(0x00040000) 15th bit
 | 
						|
				break;
 | 
						|
			case 'allcharacters':
 | 
						|
				inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; //4096 (0x00010000) 13th bit
 | 
						|
				break;
 | 
						|
			default: {
 | 
						|
				const number = +value;
 | 
						|
				// We set the default value.
 | 
						|
				if (!isNaN(number)) {
 | 
						|
					inputType = number;
 | 
						|
				} else {
 | 
						|
					inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		this._setInputType(inputType);
 | 
						|
	}
 | 
						|
 | 
						|
	[autocorrectProperty.getDefault](): boolean {
 | 
						|
		const autocorrect = this.nativeTextViewProtected.getInputType();
 | 
						|
		if ((autocorrect & android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) === android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) {
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	[autocorrectProperty.setNative](value: boolean) {
 | 
						|
		let inputType = this.nativeTextViewProtected.getInputType();
 | 
						|
		switch (value) {
 | 
						|
			case true:
 | 
						|
				inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
 | 
						|
				inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
 | 
						|
				inputType = inputType & ~android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
 | 
						|
				break;
 | 
						|
			case false:
 | 
						|
				inputType = inputType & ~android.text.InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
 | 
						|
				inputType = inputType & ~android.text.InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
 | 
						|
				inputType = inputType | android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				// We can't do anything.
 | 
						|
				break;
 | 
						|
		}
 | 
						|
 | 
						|
		this._setInputType(inputType);
 | 
						|
	}
 | 
						|
 | 
						|
	[hintProperty.getDefault](): string {
 | 
						|
		return this.nativeTextViewProtected.getHint();
 | 
						|
	}
 | 
						|
	[hintProperty.setNative](value: string) {
 | 
						|
		const text = value === null || value === undefined ? null : value.toString();
 | 
						|
		this.nativeTextViewProtected.setHint(text);
 | 
						|
	}
 | 
						|
 | 
						|
	[placeholderColorProperty.getDefault](): android.content.res.ColorStateList {
 | 
						|
		return this.nativeTextViewProtected.getHintTextColors();
 | 
						|
	}
 | 
						|
	[placeholderColorProperty.setNative](value: Color | android.content.res.ColorStateList) {
 | 
						|
		const color = value instanceof Color ? value.android : value;
 | 
						|
		this.nativeTextViewProtected.setHintTextColor(<any>color);
 | 
						|
	}
 | 
						|
 | 
						|
	[textTransformProperty.setNative](value: 'default') {
 | 
						|
		//
 | 
						|
	}
 | 
						|
 | 
						|
	[maxLengthProperty.setNative](value: number) {
 | 
						|
		if (value === Number.POSITIVE_INFINITY) {
 | 
						|
			this.nativeTextViewProtected.setFilters([]);
 | 
						|
		} else {
 | 
						|
			const lengthFilter = new android.text.InputFilter.LengthFilter(value);
 | 
						|
			const filters = this.nativeTextViewProtected.getFilters();
 | 
						|
			const newFilters = [];
 | 
						|
 | 
						|
			// retain existing filters
 | 
						|
			for (let i = 0; i < filters.length; i++) {
 | 
						|
				const filter = filters[i];
 | 
						|
				if (!(filter instanceof android.text.InputFilter.LengthFilter)) {
 | 
						|
					newFilters.push(filter);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			newFilters.push(lengthFilter);
 | 
						|
			this.nativeTextViewProtected.setFilters(newFilters);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public setSelection(start: number, stop?: number) {
 | 
						|
		const view = this.nativeTextViewProtected;
 | 
						|
		if (view) {
 | 
						|
			if (stop !== undefined) {
 | 
						|
				view.setSelection(start, stop);
 | 
						|
			} else {
 | 
						|
				view.setSelection(start);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public beforeTextChanged(text: string, start: number, count: number, after: number): void {
 | 
						|
		// called by android.text.TextWatcher
 | 
						|
	}
 | 
						|
 | 
						|
	public onTextChanged(text: string, start: number, before: number, count: number): void {
 | 
						|
		// called by android.text.TextWatcher
 | 
						|
		if (this.valueFormatter) {
 | 
						|
			this.text = this.valueFormatter(text.toString());
 | 
						|
			this.android.setSelection((this.text || '').length);
 | 
						|
		}
 | 
						|
		// const owner = this.owner;
 | 
						|
		// let selectionStart = owner.android.getSelectionStart();
 | 
						|
		// owner.android.removeTextChangedListener(owner._editTextListeners);
 | 
						|
		// owner.android.addTextChangedListener(owner._editTextListeners);
 | 
						|
		// owner.android.setSelection(selectionStart);
 | 
						|
	}
 | 
						|
 | 
						|
	public afterTextChanged(editable: android.text.Editable): void {
 | 
						|
		// called by android.text.TextWatcher
 | 
						|
		if (this._changeFromCode) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		switch (this.updateTextTrigger) {
 | 
						|
			case 'focusLost':
 | 
						|
				this._dirtyTextAccumulator = editable.toString();
 | 
						|
				break;
 | 
						|
			case 'textChanged':
 | 
						|
				textProperty.nativeValueChange(this, editable.toString());
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				throw new Error('Invalid updateTextTrigger: ' + this.updateTextTrigger);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public onFocusChange(view: android.view.View, hasFocus: boolean): void {
 | 
						|
		if (hasFocus) {
 | 
						|
			clearDismissTimer();
 | 
						|
			this.notify({ eventName: EditableTextBase.focusEvent });
 | 
						|
		} else {
 | 
						|
			if (this._dirtyTextAccumulator || this._dirtyTextAccumulator === '') {
 | 
						|
				textProperty.nativeValueChange(this, this._dirtyTextAccumulator);
 | 
						|
				this._dirtyTextAccumulator = undefined;
 | 
						|
			}
 | 
						|
 | 
						|
			this.notify({ eventName: EditableTextBase.blurEvent });
 | 
						|
			dismissSoftInput(this);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public onEditorAction(textView: android.widget.TextView, actionId: number, event: android.view.KeyEvent): boolean {
 | 
						|
		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)) {
 | 
						|
			// If it is TextField, close the keyboard. If it is TextView, do not close it since the TextView is multiline
 | 
						|
			// https://github.com/NativeScript/NativeScript/issues/3111
 | 
						|
			if (textView.getMaxLines() === 1) {
 | 
						|
				this.dismissSoftInput();
 | 
						|
			}
 | 
						|
 | 
						|
			this._onReturnPress();
 | 
						|
		} else if (actionId === android.view.inputmethod.EditorInfo.IME_ACTION_NEXT || actionId === android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS) {
 | 
						|
			// do not close keyboard for ACTION_NEXT or ACTION_PREVIOUS
 | 
						|
			this._onReturnPress();
 | 
						|
		}
 | 
						|
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
}
 |