Commit 92bfca28 by Orkhan Alikhanov

Added ErrorTextFieldValidator

parent 5cbae5db
...@@ -180,6 +180,7 @@ ...@@ -180,6 +180,7 @@
9DF352421FED20C900B2A11B /* BaseIconLayerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF352411FED20C900B2A11B /* BaseIconLayerButton.swift */; }; 9DF352421FED20C900B2A11B /* BaseIconLayerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF352411FED20C900B2A11B /* BaseIconLayerButton.swift */; };
9DF352441FED20ED00B2A11B /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF352431FED20ED00B2A11B /* RadioButton.swift */; }; 9DF352441FED20ED00B2A11B /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF352431FED20ED00B2A11B /* RadioButton.swift */; };
9DF352461FED210000B2A11B /* CheckButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF352451FED210000B2A11B /* CheckButton.swift */; }; 9DF352461FED210000B2A11B /* CheckButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF352451FED210000B2A11B /* CheckButton.swift */; };
9DF58CEE20C098C60098968D /* ErrorTextFieldValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF58CED20C098C60098968D /* ErrorTextFieldValidator.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
...@@ -297,6 +298,7 @@ ...@@ -297,6 +298,7 @@
9DF352411FED20C900B2A11B /* BaseIconLayerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseIconLayerButton.swift; sourceTree = "<group>"; }; 9DF352411FED20C900B2A11B /* BaseIconLayerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseIconLayerButton.swift; sourceTree = "<group>"; };
9DF352431FED20ED00B2A11B /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; }; 9DF352431FED20ED00B2A11B /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
9DF352451FED210000B2A11B /* CheckButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckButton.swift; sourceTree = "<group>"; }; 9DF352451FED210000B2A11B /* CheckButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckButton.swift; sourceTree = "<group>"; };
9DF58CED20C098C60098968D /* ErrorTextFieldValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorTextFieldValidator.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
...@@ -315,6 +317,7 @@ ...@@ -315,6 +317,7 @@
96BCB79E1CB40DC500C806FE /* TextView.swift */, 96BCB79E1CB40DC500C806FE /* TextView.swift */,
96BCB79C1CB40DC500C806FE /* TextField.swift */, 96BCB79C1CB40DC500C806FE /* TextField.swift */,
961F18E71CD93E3E008927C5 /* ErrorTextField.swift */, 961F18E71CD93E3E008927C5 /* ErrorTextField.swift */,
9DF58CED20C098C60098968D /* ErrorTextFieldValidator.swift */,
); );
name = Text; name = Text;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -1005,6 +1008,7 @@ ...@@ -1005,6 +1008,7 @@
965E80CE1DD4C50600D61E4B /* FABButton.swift in Sources */, 965E80CE1DD4C50600D61E4B /* FABButton.swift in Sources */,
965E80CF1DD4C50600D61E4B /* FlatButton.swift in Sources */, 965E80CF1DD4C50600D61E4B /* FlatButton.swift in Sources */,
965E80D01DD4C50600D61E4B /* RaisedButton.swift in Sources */, 965E80D01DD4C50600D61E4B /* RaisedButton.swift in Sources */,
9DF58CEE20C098C60098968D /* ErrorTextFieldValidator.swift in Sources */,
96A183631E0C6CE200083C30 /* FABMenu.swift in Sources */, 96A183631E0C6CE200083C30 /* FABMenu.swift in Sources */,
965E80D11DD4C50600D61E4B /* IconButton.swift in Sources */, 965E80D11DD4C50600D61E4B /* IconButton.swift in Sources */,
965E80D21DD4C50600D61E4B /* Color.swift in Sources */, 965E80D21DD4C50600D61E4B /* Color.swift in Sources */,
......
//
// ErrorTextFieldValidator.swift
// Material
//
// Created by Orkhan Alikhanov on 30/05/2018.
// Copyright © 2018 CosmicMind, Inc. All rights reserved.
//
import UIKit
import Motion
open class ErrorTextFieldValidator: NSObject {
public typealias ValidationClosure = (String) -> Bool
open var closures: [(code: ValidationClosure, msg: String)] = []
open weak var textField: ErrorTextField?
open var autoValidationType: AutoValidationType = .default
open var autoValidateOnlyIfErrorIsShownOnce = true
open var isErrorShownOnce = false
public init(textField: ErrorTextField) {
self.textField = textField
super.init()
textField.addTarget(self, action: #selector(checkIfErrorHasGone), for: .editingChanged)
}
@objc
private func checkIfErrorHasGone() {
guard let textField = textField else { return }
if autoValidateOnlyIfErrorIsShownOnce && !isErrorShownOnce { return }
switch autoValidationType {
case .none: break
case .custom(let closure):
closure(textField)
case .default:
_ = textField.isValid() // will hide if needed
}
}
open func isValid(deferred: Bool) -> Bool {
guard let textField = textField else { return false }
if !deferred { textField.isErrorRevealed = false }
for block in closures {
if !block.code(textField.text ?? "") {
if !deferred {
textField.error = block.msg
textField.isErrorRevealed = true
isErrorShownOnce = true
}
return false
}
}
return true
}
@discardableResult
open func validate(msg: String, when code: @escaping ValidationClosure) -> Self {
closures.append((code, msg))
return self
}
public enum AutoValidationType {
case none
case `default`
case custom((ErrorTextField) -> Void)
}
}
private var AssociatedInstanceKey: UInt8 = 0
extension ErrorTextField {
open var validator: ErrorTextFieldValidator {
get {
return AssociatedObject.get(base: self, key: &AssociatedInstanceKey) {
return ErrorTextFieldValidator(textField: self)
}
}
set(value) {
AssociatedObject.set(base: self, key: &AssociatedInstanceKey, value: value)
}
}
open func isValid(deferred: Bool = false) -> Bool {
return validator.isValid(deferred: deferred)
}
}
public extension ErrorTextFieldValidator {
@discardableResult
func email(msg: String) -> Self {
return regex(msg: msg, pattern: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}")
}
@discardableResult
func username(msg: String) -> Self {
return regex(msg: msg, pattern: "^[a-zA-Z0-9]+([_\\s\\-\\.\\']?[a-zA-Z0-9])*$")
}
@discardableResult
func regex(msg: String, pattern: String) -> Self {
return validate(msg: msg) {
let pred = NSPredicate(format: "SELF MATCHES %@", pattern)
return pred.evaluate(with: $0)
}
}
@discardableResult
func min(length: Int, msg: String, trimmingSet: CharacterSet? = .whitespacesAndNewlines) -> Self {
let trimmingSet = trimmingSet ?? .init()
return validate(msg: msg) {
$0.trimmingCharacters(in: trimmingSet).count >= length
}
}
@discardableResult
func notEmpty(msg: String, trimmingSet: CharacterSet? = .whitespacesAndNewlines) -> Self {
let trimmingSet = trimmingSet ?? .init()
return validate(msg: msg) {
$0.trimmingCharacters(in: trimmingSet).isEmpty == false
}
}
@discardableResult
func noWhitespaces(msg: String) -> Self {
return validate(msg: msg) {
$0.rangeOfCharacter(from: .whitespaces) == nil
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment