PhoneNumberKit
PhoneNumberKit copied to clipboard
Deleting bracket or space characters not possible when user moves cursor behind the bracket/space and tries to delete the character.
Steps to reproduce:
- Set the PhoneNumberTextField.isPartialFormatterEnabled to true
- enter phone number +1 (206) 333-4444
- move cursor behind the ')' character
- try to delete the ')' character
- The character is not removed and cursor stay on same position.
- Similar behaviour is also for the '('character
Expected result: I should be possible to delete the ')' character or at least the number before it. The Contacts app deletes the numbers before the ')' bracket.
Here is short example how it works on Contacts app:
- Enter the number +1 (206) 333-4444
- Move cursor behind the ')' character
- Try to delete the ')' character. +1 (203) 334-444
- Try to delete another character. +1 (233) 355-55
We have tried to fix the issue a here is why we found out during investigation: When user tries to delete the ')' character, the character is actually removed in the function PhoneNumberTextField.textField(: shouldChangeCharactersIn:, replacementString:). But, after the modified text is set to the PhoneNumberTextField.text property the partialFormatter.formatPartial() function is called from the property setter. This function will format the text and add the ')' character again into the phone number. From the user perspective it looks like nothing happened. We fixed this issue by changing the range which is provided as parameter for the PhoneNumberTextField.textField(: shouldChangeCharactersIn:, replacementString:) function. The range is changed so that, it contain also the number before the ')' character.
Here is the code for out fix which we added to the PhoneNumberTextField.textField(: shouldChangeCharactersIn:, replacementString:) function:
open func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// This allows for the case when a user autocompletes a phone number:
if range == NSRange(location: 0, length: 0) && string.isBlank {
return true
}
guard let text = text else {
return false
}
// allow delegate to intervene
guard self._delegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true else {
return false
}
guard self.isPartialFormatterEnabled else {
return true
}
var range = range
let textAsNSString = text as NSString
// If the user tries to delete the space or bracket characters, then those will be deleted, but when the number will be formatted, the space/bracket will be again inserted. We need to change the rage to include also the first number before the space/bracket character.
if string.isEmpty, range.length == 1, let textFieldText = textField.text, range.location > 0 {
var index = textFieldText.index(textFieldText.startIndex, offsetBy: range.location)
var char = textFieldText[index]
if char == " " {
let newIndex = textFieldText[..<index].lastIndex(where: { !$0.isWhitespace }) ?? textFieldText.startIndex
let newLocation = textFieldText.distance(from: textFieldText.startIndex, to: newIndex)
range = NSRange(location: max(0, newLocation), length: range.location - newLocation)
index = textFieldText.index(textFieldText.startIndex, offsetBy: range.location)
char = textFieldText[index]
}
if char == "(" || char == ")" {
let newIndex = textFieldText[..<index].lastIndex(where: { !$0.isWhitespace }) ?? textFieldText.startIndex
let newLocation = textFieldText.distance(from: textFieldText.startIndex, to: newIndex)
range = NSRange(location: max(0, newLocation), length: range.location - newLocation)
}
}
let changedRange = textAsNSString.substring(with: range) as NSString
let modifiedTextField = textAsNSString.replacingCharacters(in: range, with: string)
let filteredCharacters = modifiedTextField.filter {
String($0).rangeOfCharacter(from: (textField as! PhoneNumberTextField).nonNumericSet) == nil
}
let rawNumberString = String(filteredCharacters)
let formattedNationalNumber = self.partialFormatter.formatPartial(rawNumberString as String)
var selectedTextRange: NSRange?
let nonNumericRange = (changedRange.rangeOfCharacter(from: self.nonNumericSet).location != NSNotFound)
if range.length == 1, string.isEmpty, nonNumericRange {
selectedTextRange = self.selectionRangeForNumberReplacement(textField: textField, formattedText: modifiedTextField)
textField.text = modifiedTextField
} else {
selectedTextRange = self.selectionRangeForNumberReplacement(textField: textField, formattedText: formattedNationalNumber)
textField.text = formattedNationalNumber
}
sendActions(for: .editingChanged)
if let selectedTextRange = selectedTextRange, let selectionRangePosition = textField.position(from: beginningOfDocument, offset: selectedTextRange.location) {
let selectionRange = textField.textRange(from: selectionRangePosition, to: selectionRangePosition)
textField.selectedTextRange = selectionRange
}
// we change the default region to be the one most recently typed
// but only when the withFlag is true as to not confuse the user who don't see the flag
if withFlag == true
{
let region = self.partialFormatter.getCountryCallingCode(from: textField.text ?? "")
self._defaultRegion = region ?? PhoneNumberKit.defaultRegionCode()
self.partialFormatter.defaultRegion = region ?? PhoneNumberKit.defaultRegionCode()
self.updateFlag()
self.updatePlaceholder()
}
return false
}
@dencijan this issue might be fixed with #695
Can you check with the latest version 3.7.0?
@bguidolim sorry for late response but it looks that the issue is still not fixed.
I pulled latest sources from master (3.7.4), I started the AsYouType example project and the issue can be still reproduced.
I'll check it, but it can take from 2 to 3 weeks since I don't have access to my computer currently.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hi, I tested it again today with latest sources from master branch. It is still reproducible with latest version 3.7.6. Just start the AsYouType example project.
enter phone number +1 (206) 333-4444 move cursor behind the ')' character try to delete the ')' character The character is not removed and cursor stays on same position.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.