Skip to content

Commit 27cfbb5

Browse files
committed
fix: rollback on keyboardType, added digits
1 parent 81ca30c commit 27cfbb5

File tree

5 files changed

+152
-104
lines changed

5 files changed

+152
-104
lines changed

src/core/textbase/cssproperties.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,8 @@ export const buttonColorProperty = new CssProperty<Style, Color>({
6767
valueConverter: v => new Color(v)
6868
});
6969
buttonColorProperty.register(Style);
70+
export const digitsProperty = new CssProperty<Style, string>({
71+
name: 'digits',
72+
cssName: 'digits'
73+
});
74+
digitsProperty.register(Style);

src/textfield/textfield.android.ts

Lines changed: 11 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { getLayout, handleClearFocus, stateSets } from 'nativescript-material-core/android/utils';
22
import { Color } from '@nativescript/core/color';
3-
import { backgroundInternalProperty, borderBottomLeftRadiusProperty, hintProperty, placeholderColorProperty, keyboardTypeProperty } from '@nativescript/core/ui/editable-text-base';
3+
import { backgroundInternalProperty, borderBottomLeftRadiusProperty, hintProperty, placeholderColorProperty } from '@nativescript/core/ui/editable-text-base';
44
import { Background } from '@nativescript/core/ui/styling/background';
55
import { ad } from '@nativescript/core/utils/utils';
6-
import { KeyboardType, TextFieldBase } from './textfield.common';
6+
import { TextFieldBase } from './textfield.common';
77
import {
8+
digitsProperty,
89
errorColorProperty,
910
errorProperty,
1011
floatingColorProperty,
@@ -223,6 +224,14 @@ export class TextField extends TextFieldBase {
223224
// this.editText.setBackgroundTintList(android.content.res.ColorStateList.valueOf(color));
224225
}
225226

227+
[digitsProperty.setNative](value: string) {
228+
if (value && value.length > 0) {
229+
this.nativeTextViewProtected.setKeyListener(android.text.method.DigitsKeyListener.getInstance(value));
230+
} else {
231+
this.nativeTextViewProtected.setKeyListener(null);
232+
}
233+
}
234+
226235
[backgroundInternalProperty.setNative](value: Background) {
227236
switch (this.variant) {
228237
case 'none':
@@ -261,54 +270,5 @@ export class TextField extends TextFieldBase {
261270
}
262271
}
263272
}
264-
265-
266-
[keyboardTypeProperty.setNative](value: KeyboardType) {
267-
let newInputType;
268-
269-
switch (value) {
270-
case "datetime":
271-
newInputType = android.text.InputType.TYPE_CLASS_DATETIME | android.text.InputType.TYPE_DATETIME_VARIATION_NORMAL;
272-
break;
273-
274-
case "phone":
275-
newInputType = android.text.InputType.TYPE_CLASS_PHONE;
276-
break;
277-
278-
case "number":
279-
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;
280-
break;
281-
282-
case "numberDecimal":
283-
newInputType = android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL;
284-
break;
285-
286-
case "numberPassword":
287-
newInputType = android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
288-
break;
289-
290-
case "numberSigned":
291-
newInputType = android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED;
292-
break;
293-
294-
case "url":
295-
newInputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_URI;
296-
break;
297-
298-
case "email":
299-
newInputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
300-
break;
301-
302-
case "integer":
303-
newInputType = android.text.InputType.TYPE_CLASS_NUMBER;
304-
break;
305-
306-
default:
307-
newInputType = value;
308-
break;
309-
}
310-
311-
this._setInputType(newInputType);
312-
}
313273
}
314274
//

src/textfield/textfield.common.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { Color } from '@nativescript/core/color';
33
import { CSSType } from '@nativescript/core/ui/core/view';
44
import { cssProperty } from 'nativescript-material-core/cssproperties';
55

6-
7-
export type KeyboardType = "datetime" | "phone" | "number" | "numberSigned" | "numberPassword" | "numberDecimal" | "url" | "email" | "integer"
86
@CSSType('MDTextField')
97
export abstract class TextFieldBase extends NTextField {
10-
118
abstract requestFocus();
129
abstract clearFocus();
1310

11+
// those 2 are not released yet
12+
secureWithoutAutofill:boolean
13+
closeOnReturn:boolean
14+
1415
@cssProperty helper: string;
1516
@cssProperty maxLength: number;
1617
@cssProperty errorColor: Color;
@@ -23,4 +24,5 @@ export abstract class TextFieldBase extends NTextField {
2324
@cssProperty floatingColor: Color;
2425
@cssProperty floatingInactiveColor: Color;
2526
@cssProperty buttonColor: Color;
27+
@cssProperty digits: string;
2628
}

src/textfield/textfield.ios.ts

Lines changed: 131 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { KeyboardType, TextFieldBase } from './textfield.common';
2-
import { backgroundInternalProperty, placeholderColorProperty, keyboardTypeProperty } from '@nativescript/core/ui/editable-text-base';
1+
import { TextFieldBase } from './textfield.common';
2+
import { backgroundInternalProperty, placeholderColorProperty, keyboardTypeProperty, textProperty } from '@nativescript/core/ui/editable-text-base';
33
import {
44
buttonColorProperty,
5+
digitsProperty,
56
errorColorProperty,
67
errorProperty,
78
floatingColorProperty,
@@ -10,14 +11,17 @@ import {
1011
helperProperty,
1112
maxLengthProperty,
1213
strokeColorProperty,
13-
strokeInactiveColorProperty
14+
strokeInactiveColorProperty,
1415
} from 'nativescript-material-core/textbase/cssproperties';
1516
import { themer } from 'nativescript-material-core/core';
1617
import { Color } from '@nativescript/core/color';
1718
import { Style } from '@nativescript/core/ui/styling/style';
1819
import { Background } from '@nativescript/core/ui/styling/background';
1920
import { screen } from '@nativescript/core/platform/platform';
2021

22+
// it is exported but not in the typings
23+
const _updateCharactersInRangeReplacementString = require('@nativescript/core/ui/editable-text-base')._updateCharactersInRangeReplacementString;
24+
2125
let colorScheme: MDCSemanticColorScheme;
2226
function getColorScheme() {
2327
if (!colorScheme) {
@@ -104,12 +108,120 @@ class TextInputControllerFilledImpl extends MDCTextInputControllerFilled {
104108
}
105109
}
106110

111+
class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
112+
public static ObjCProtocols = [UITextFieldDelegate];
113+
114+
private _owner: WeakRef<TextField>;
115+
private firstEdit: boolean;
116+
117+
public static initWithOwner(owner: WeakRef<TextField>): UITextFieldDelegateImpl {
118+
const delegate = <UITextFieldDelegateImpl>UITextFieldDelegateImpl.new();
119+
delegate._owner = owner;
120+
121+
return delegate;
122+
}
123+
124+
public textFieldShouldBeginEditing(textField: UITextField): boolean {
125+
this.firstEdit = true;
126+
const owner = this._owner.get();
127+
if (owner) {
128+
return owner.editable;
129+
}
130+
131+
return true;
132+
}
133+
134+
public textFieldDidBeginEditing(textField: UITextField): void {
135+
const owner = this._owner.get();
136+
if (owner) {
137+
owner.notify({ eventName: TextField.focusEvent, object: owner });
138+
}
139+
}
140+
141+
public textFieldDidEndEditing(textField: UITextField) {
142+
const owner = this._owner.get();
143+
if (owner) {
144+
if (owner.updateTextTrigger === 'focusLost') {
145+
textProperty.nativeValueChange(owner, textField.text);
146+
}
147+
148+
owner.dismissSoftInput();
149+
}
150+
}
151+
152+
public textFieldShouldClear(textField: UITextField) {
153+
this.firstEdit = false;
154+
const owner = this._owner.get();
155+
if (owner) {
156+
textProperty.nativeValueChange(owner, '');
157+
}
158+
159+
return true;
160+
}
161+
162+
public textFieldShouldReturn(textField: UITextField): boolean {
163+
// Called when the user presses the return button.
164+
const owner = this._owner.get();
165+
if (owner) {
166+
if (owner.closeOnReturn) {
167+
owner.dismissSoftInput();
168+
}
169+
owner.notify({ eventName: TextField.returnPressEvent, object: owner });
170+
}
171+
172+
return true;
173+
}
174+
175+
public textFieldShouldChangeCharactersInRangeReplacementString(textField: UITextField, range: NSRange, replacementString: string): boolean {
176+
const owner = this._owner.get();
177+
if (owner) {
178+
// ignore if not in our alllowed digits
179+
if (owner.nsdigits && replacementString.length > 0 && NSString.stringWithString(replacementString).rangeOfCharacterFromSet(owner.nsdigits).location === NSNotFound) {
180+
return false;
181+
}
182+
if (owner.secureWithoutAutofill && !textField.secureTextEntry) {
183+
/**
184+
* Helps avoid iOS 12+ autofill strong password suggestion prompt
185+
* Discussed in several circles but for example:
186+
* https://github.com/expo/expo/issues/2571#issuecomment-473347380
187+
*/
188+
textField.secureTextEntry = true;
189+
}
190+
const delta = replacementString.length - range.length;
191+
if (delta > 0) {
192+
if (textField.text.length + delta > owner.maxLength) {
193+
return false;
194+
}
195+
}
196+
197+
if (owner.updateTextTrigger === 'textChanged') {
198+
if (textField.secureTextEntry && this.firstEdit) {
199+
textProperty.nativeValueChange(owner, replacementString);
200+
} else {
201+
if (range.location <= textField.text.length) {
202+
const newText = NSString.stringWithString(textField.text).stringByReplacingCharactersInRangeWithString(range, replacementString);
203+
textProperty.nativeValueChange(owner, newText);
204+
}
205+
}
206+
}
207+
208+
if (owner.formattedText) {
209+
_updateCharactersInRangeReplacementString(owner.formattedText, range.location, range.length, replacementString);
210+
}
211+
}
212+
213+
this.firstEdit = false;
214+
215+
return true;
216+
}
217+
}
218+
107219
export class TextField extends TextFieldBase {
108220
nativeViewProtected: MDCTextField;
109221
nativeTextViewProtected: MDCTextField;
110222
private _controller: MDCTextInputControllerBase;
111223
public readonly style: Style & { variant: 'outline' | 'underline' | 'filled' };
112-
224+
public nsdigits?: NSCharacterSet;
113225
public clearFocus() {
114226
this.dismissSoftInput();
115227
}
@@ -162,6 +274,13 @@ export class TextField extends TextFieldBase {
162274
}
163275
return view;
164276
}
277+
private _delegate: UITextFieldDelegateImpl;
278+
279+
initNativeView() {
280+
super.initNativeView();
281+
// it will get picked in onLoaded
282+
this._delegate = UITextFieldDelegateImpl.initWithOwner(new WeakRef(this));
283+
}
165284

166285
// TODO: check why i was checking for isFirstResponder
167286
// with it the blur event is not fired anymore
@@ -179,7 +298,7 @@ export class TextField extends TextFieldBase {
179298
this.dismissSoftInput();
180299
}
181300

182-
public setSelection(start:number, stop?:number) {
301+
public setSelection(start: number, stop?: number) {
183302
const view = this.nativeTextViewProtected;
184303
if (stop !== undefined) {
185304
const begin = view.beginningOfDocument;
@@ -238,6 +357,13 @@ export class TextField extends TextFieldBase {
238357
[errorProperty.setNative](value: string) {
239358
this._controller.setErrorTextErrorAccessibilityValue(value, value);
240359
}
360+
[digitsProperty.setNative](value: string) {
361+
if (value && value.length > 0) {
362+
this.nsdigits = NSCharacterSet.characterSetWithCharactersInString(value);
363+
} else {
364+
this.nsdigits = null;
365+
}
366+
}
241367
[backgroundInternalProperty.setNative](value: Background) {
242368
switch (this.variant) {
243369
case 'none':
@@ -256,48 +382,4 @@ export class TextField extends TextFieldBase {
256382
}
257383
}
258384
}
259-
260-
261-
[keyboardTypeProperty.setNative](value:KeyboardType) {
262-
let newKeyboardType: UIKeyboardType;
263-
switch (value) {
264-
case "datetime":
265-
newKeyboardType = UIKeyboardType.NumbersAndPunctuation;
266-
break;
267-
268-
case "phone":
269-
newKeyboardType = UIKeyboardType.PhonePad;
270-
break;
271-
272-
case "number":
273-
case "numberDecimal":
274-
case "numberSigned":
275-
newKeyboardType = UIKeyboardType.NumbersAndPunctuation;
276-
break;
277-
278-
case "url":
279-
newKeyboardType = UIKeyboardType.URL;
280-
break
281-
;
282-
case "email":
283-
newKeyboardType = UIKeyboardType.EmailAddress;
284-
break;
285-
286-
case "integer":
287-
case "numberPassword":
288-
newKeyboardType = UIKeyboardType.NumberPad;
289-
break;
290-
291-
default:
292-
let kt = +value;
293-
if (!isNaN(kt)) {
294-
newKeyboardType = <UIKeyboardType>kt;
295-
} else {
296-
newKeyboardType = UIKeyboardType.Default;
297-
}
298-
break;
299-
}
300-
301-
this.nativeTextViewProtected.keyboardType = newKeyboardType;
302-
}
303385
}

src/textview/textview.ios.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ class TextViewDelegateImpl extends NSObject implements UITextViewDelegate {
111111
}
112112

113113
public textViewShouldBeginEditing(textView: UITextView): boolean {
114-
const owner = this._owner.get();
115114
return true;
116115
}
117116

0 commit comments

Comments
 (0)