|
|
|
//
|
|
|
|
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
@objc class TextFieldHelper: NSObject {
|
|
|
|
|
|
|
|
// Used to implement the UITextFieldDelegate method: `textField:shouldChangeCharactersInRange:replacementString`
|
|
|
|
// Takes advantage of Swift's superior unicode handling to append partial pasted text without splitting multi-byte characters.
|
|
|
|
class func textField(_ textField: UITextField, shouldChangeCharactersInRange editingRange: NSRange, replacementString: String, byteLimit: UInt) -> Bool {
|
|
|
|
|
|
|
|
let byteLength = { (string: String) -> UInt in
|
|
|
|
return UInt(string.utf8.count)
|
|
|
|
}
|
|
|
|
|
|
|
|
let existingString = textField.text ?? ""
|
|
|
|
|
|
|
|
// Given an NSRange, we need to interact with the NS flavor of substring
|
|
|
|
let removedString = (existingString as NSString).substring(with: editingRange)
|
|
|
|
|
|
|
|
let lengthOfRemainingExistingString = byteLength(existingString) - byteLength(removedString)
|
|
|
|
|
|
|
|
let newLength = lengthOfRemainingExistingString + byteLength(replacementString)
|
|
|
|
|
|
|
|
if (newLength <= byteLimit) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't allow any change if inserting a single char is already over the limit (typically this means typing)
|
|
|
|
if (replacementString.count < 2) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// However if pasting, accept as much of the string as possible.
|
|
|
|
let availableSpace = byteLimit - lengthOfRemainingExistingString
|
|
|
|
|
|
|
|
var acceptableSubstring = ""
|
|
|
|
|
|
|
|
for (_, char) in replacementString.characters.enumerated() {
|
|
|
|
var maybeAcceptableSubstring = acceptableSubstring
|
|
|
|
maybeAcceptableSubstring.append(char)
|
|
|
|
if (byteLength(maybeAcceptableSubstring) <= availableSpace) {
|
|
|
|
acceptableSubstring = maybeAcceptableSubstring
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
textField.text = (existingString as NSString).replacingCharacters(in: editingRange, with:acceptableSubstring)
|
|
|
|
|
|
|
|
// We've already handled any valid editing manually, so prevent further changes.
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|