diff --git a/README.md b/README.md
index ff37d6b..f690c41 100644
--- a/README.md
+++ b/README.md
@@ -146,6 +146,9 @@ class SSNVRule: RegexRule {
}
```
+## Documentation
+Checkout the docs here.
+
Credits
-------
diff --git a/SwiftValidator.podspec b/SwiftValidator.podspec
index 4e31e32..d5dff3e 100644
--- a/SwiftValidator.podspec
+++ b/SwiftValidator.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SwiftValidator"
- s.version = "3.0.1"
+ s.version = "3.0.3"
s.summary = "A UITextField Validation library for Swift"
s.homepage = "https://github.com/jpotts18/SwiftValidator"
s.screenshots = "https://raw.githubusercontent.com/jpotts18/SwiftValidator/master/swift-validator-v2.gif"
@@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.social_media_url = "http://twitter.com/jpotts18"
s.platform = :ios
s.ios.deployment_target = '8.0'
- s.source = { :git => "https://github.com/jpotts18/SwiftValidator.git", :tag => "3.0.1" }
+ s.source = { :git => "https://github.com/jpotts18/SwiftValidator.git", :tag => "3.0.3" }
s.source_files = "SwiftValidator/**/*.swift"
s.exclude_files = "Validator/AppDelegate.swift"
s.frameworks = ['Foundation', 'UIKit']
diff --git a/SwiftValidator/Core/ValidationDelegate.swift b/SwiftValidator/Core/ValidationDelegate.swift
index 7e70372..65185b2 100644
--- a/SwiftValidator/Core/ValidationDelegate.swift
+++ b/SwiftValidator/Core/ValidationDelegate.swift
@@ -16,10 +16,19 @@ import UIKit
This method will be called on delegate object when validation is successful.
- returns: No return value.
*/
- func validationSuccessful()
+ optional func validationSuccessful()
/**
This method will be called on delegate object when validation fails.
- returns: No return value.
*/
- func validationFailed(errors: [UITextField:ValidationError])
+ optional func validationFailed(errors: [UITextField:ValidationError])
+ /// This method is called as soon a validation starts. Should be used to do things like disable buttons, textfields once validation is started.
+ func willValidate()
+ /// This method is called just before validator's fields are validated. Should return true if validation is to be continued. Should return
+ /// false if validation should not run.
+ func shouldValidate() -> Bool
+ /// This method is called after validator's fields have been validated.
+ func didValidate()
+ /// This method is called after when validation does not run because preconditions have not been met.
+ func failedBeforeValidation()
}
diff --git a/SwiftValidator/Core/Validator.swift b/SwiftValidator/Core/Validator.swift
index a600b2d..5398ea9 100644
--- a/SwiftValidator/Core/Validator.swift
+++ b/SwiftValidator/Core/Validator.swift
@@ -18,6 +18,7 @@ public class Validator {
/// Dictionary to hold fields (and accompanying errors) that were unsuccessfully validated.
public var errors = [UITextField:ValidationError]()
/// Variable that holds success closure to display positive status of field.
+ public var delegate: ValidationDelegate?
private var successStyleTransform:((validationRule:ValidationRule)->Void)?
/// Variable that holds error closure to display negative status of field.
private var errorStyleTransform:((validationError:ValidationError)->Void)?
@@ -62,6 +63,7 @@ public class Validator {
- returns: No return value.
*/
public func validateField(textField: UITextField, callback: (error:ValidationError?) -> Void){
+ // perhaps delegate should be set on validator object instead of being passed as a parameter
if let fieldRule = validations[textField] {
if let error = fieldRule.validateField() {
errors[textField] = error
@@ -111,10 +113,11 @@ public class Validator {
- parameter textfield: field that is to be validated.
- parameter errorLabel: A UILabel that holds error label data
- parameter rules: A Rule array that holds different rules that apply to said textField.
+ - paramteter sanitizers: A Sanitizer array that allows for custom cleaning of textField text.
- returns: No return value
*/
- public func registerField(textField:UITextField, errorLabel:UILabel, rules:[Rule]) {
- validations[textField] = ValidationRule(textField: textField, rules:rules, errorLabel:errorLabel)
+ public func registerField(textField:UITextField, errorLabel:UILabel, rules:[Rule], sanitizers: [Sanitizer]? = nil) {
+ validations[textField] = ValidationRule(textField: textField, rules:rules, errorLabel:errorLabel, sanitizers: sanitizers)
}
/**
@@ -133,18 +136,30 @@ public class Validator {
- returns: No return value.
*/
- public func validate(delegate:ValidationDelegate) {
+ public func validate() {
+ // If preconditions are not met, then automatically fail validation
+ if delegate!.shouldValidate() == false {
+ delegate!.failedBeforeValidation()
+ return
+ }
+
+ // Validation is a go so modify view controller accordingly (disable subviews)
+ delegate!.willValidate()
+ // We've made it this far, so preconditions must've been satisfied
self.validateAllFields()
if errors.isEmpty {
- delegate.validationSuccessful()
+ // call success method if it's implemented
+ if delegate!.validationSuccessful?() != nil {}
} else {
- delegate.validationFailed(errors)
+ // call failure method if it's implemented
+ if delegate!.validationFailed?(errors) != nil {}
}
-
+ // validation did run so update view controller (re-enable buttons and such)
+ delegate!.didValidate()
}
-
+
/**
This method validates all fields in validator and sets any errors to errors parameter of callback.
diff --git a/SwiftValidator/Rules/Sanitizer.swift b/SwiftValidator/Rules/Sanitizer.swift
new file mode 100644
index 0000000..b572260
--- /dev/null
+++ b/SwiftValidator/Rules/Sanitizer.swift
@@ -0,0 +1,13 @@
+//
+// Preparator.swift
+// Validator
+//
+// Created by David Patterson on 2/22/16.
+// Copyright © 2016 jpotts18. All rights reserved.
+//
+
+import Foundation
+
+public protocol Sanitizer {
+ func sanitize(textField: UITextField)
+}
\ No newline at end of file
diff --git a/SwiftValidator/Rules/Sanitizers.swift b/SwiftValidator/Rules/Sanitizers.swift
new file mode 100644
index 0000000..f08f8ad
--- /dev/null
+++ b/SwiftValidator/Rules/Sanitizers.swift
@@ -0,0 +1,16 @@
+//
+// Sanitizers.swift
+// Validator
+//
+// Created by David Patterson on 2/22/16.
+// Copyright © 2016 jpotts18. All rights reserved.
+//
+
+import Foundation
+
+public class TrimLeadingAndTrailingSpacesSanitizer: Sanitizer {
+ public init() {}
+ public func sanitize(textField: UITextField) {
+ textField.text = textField.text?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
+ }
+}
\ No newline at end of file
diff --git a/SwiftValidator/Rules/ValidationRule.swift b/SwiftValidator/Rules/ValidationRule.swift
index 4e5a316..feb8b8b 100644
--- a/SwiftValidator/Rules/ValidationRule.swift
+++ b/SwiftValidator/Rules/ValidationRule.swift
@@ -11,7 +11,7 @@ import UIKit
/**
`ValidationRule` is a class that creates an object which holds validation info of a text field.
*/
-public class ValidationRule {
+public class ValidationRule : NSObject {
/// the text field of the field
public var textField:UITextField
/// the errorLabel of the field
@@ -19,6 +19,8 @@ public class ValidationRule {
/// the rules of the field
public var rules:[Rule] = []
+ public var sanitizers: [Sanitizer]?
+
/**
Initializes `ValidationRule` instance with text field, rules, and errorLabel.
@@ -27,10 +29,11 @@ public class ValidationRule {
- parameter rules: array of Rule objects, which text field will be validated against.
- returns: An initialized `ValidationRule` object, or nil if an object could not be created for some reason that would not result in an exception.
*/
- public init(textField: UITextField, rules:[Rule], errorLabel:UILabel?){
+ public init(textField: UITextField, rules:[Rule], errorLabel:UILabel?, sanitizers: [Sanitizer]? = nil){
self.textField = textField
self.errorLabel = errorLabel
self.rules = rules
+ self.sanitizers = sanitizers
}
/**
@@ -38,6 +41,15 @@ public class ValidationRule {
- returns: `ValidationError` object if at least one error is found. Nil is returned if there are no validation errors.
*/
public func validateField() -> ValidationError? {
+ // make any preparations if there are any
+ if let sanitizers = sanitizers {
+ print("called sanitizer")
+ for sanitizer in sanitizers {
+ sanitizer.sanitize(self.textField)
+ }
+ }
+
+ // check against prepare rules before validation
return rules.filter{ !$0.validate(self.textField.text ?? "") }
.map{ rule -> ValidationError in return ValidationError(textField: self.textField, errorLabel:self.errorLabel, error: rule.errorMessage()) }.first
}
diff --git a/Validator.xcodeproj/project.pbxproj b/Validator.xcodeproj/project.pbxproj
index ff3feb4..0e810ac 100644
--- a/Validator.xcodeproj/project.pbxproj
+++ b/Validator.xcodeproj/project.pbxproj
@@ -12,7 +12,9 @@
62D1AE221A1E6D4400E4DFF8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 62D1AE201A1E6D4400E4DFF8 /* Main.storyboard */; };
62D1AE241A1E6D4400E4DFF8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 62D1AE231A1E6D4400E4DFF8 /* Images.xcassets */; };
62D1AE271A1E6D4400E4DFF8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62D1AE251A1E6D4400E4DFF8 /* LaunchScreen.xib */; };
+ C19BA8941C7B97CB004743FF /* Sanitizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19BA8931C7B97CA004743FF /* Sanitizer.swift */; };
C1AB099F1C712025003C7155 /* ValidationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1AB099D1C712025003C7155 /* ValidationDelegate.swift */; };
+ C1B7C0FD1C7BF6A200BA7174 /* Sanitizers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7C0FC1C7BF6A200BA7174 /* Sanitizers.swift */; };
FB465CB81B9884F400398388 /* SwiftValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = FB465CB71B9884F400398388 /* SwiftValidator.h */; settings = {ATTRIBUTES = (Public, ); }; };
FB465CBE1B9884F400398388 /* SwiftValidator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB465CB31B9884F400398388 /* SwiftValidator.framework */; };
FB465CC71B9884F400398388 /* SwiftValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB465CC61B9884F400398388 /* SwiftValidatorTests.swift */; };
@@ -92,7 +94,9 @@
62D1AE261A1E6D4400E4DFF8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
62D1AE2C1A1E6D4500E4DFF8 /* ValidatorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ValidatorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
62D1AE311A1E6D4500E4DFF8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ C19BA8931C7B97CA004743FF /* Sanitizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sanitizer.swift; sourceTree = ""; };
C1AB099D1C712025003C7155 /* ValidationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationDelegate.swift; sourceTree = ""; };
+ C1B7C0FC1C7BF6A200BA7174 /* Sanitizers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sanitizers.swift; sourceTree = ""; };
FB465CB31B9884F400398388 /* SwiftValidator.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftValidator.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FB465CB61B9884F400398388 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
FB465CB71B9884F400398388 /* SwiftValidator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftValidator.h; sourceTree = ""; };
@@ -262,6 +266,8 @@
FB465CEE1B9889EA00398388 /* ValidationRule.swift */,
FB465CEF1B9889EA00398388 /* ZipCodeRule.swift */,
62C1821C1C6312F5003788E7 /* ExactLengthRule.swift */,
+ C19BA8931C7B97CA004743FF /* Sanitizer.swift */,
+ C1B7C0FC1C7BF6A200BA7174 /* Sanitizers.swift */,
);
path = Rules;
sourceTree = "";
@@ -473,6 +479,7 @@
FB465CF91B9889EA00398388 /* PasswordRule.swift in Sources */,
FB465CFD1B9889EA00398388 /* Rule.swift in Sources */,
FB465CFA1B9889EA00398388 /* PhoneNumberRule.swift in Sources */,
+ C1B7C0FD1C7BF6A200BA7174 /* Sanitizers.swift in Sources */,
FB465CF51B9889EA00398388 /* FloatRule.swift in Sources */,
FB465D011B9889EA00398388 /* Validator.swift in Sources */,
FB465CFE1B9889EA00398388 /* ValidationRule.swift in Sources */,
@@ -481,6 +488,7 @@
FB465CFC1B9889EA00398388 /* RequiredRule.swift in Sources */,
FB465CFB1B9889EA00398388 /* RegexRule.swift in Sources */,
FB465CF81B9889EA00398388 /* MinLengthRule.swift in Sources */,
+ C19BA8941C7B97CB004743FF /* Sanitizer.swift in Sources */,
C1AB099F1C712025003C7155 /* ValidationDelegate.swift in Sources */,
FB465CF71B9889EA00398388 /* MaxLengthRule.swift in Sources */,
62C1821D1C6312F5003788E7 /* ExactLengthRule.swift in Sources */,
diff --git a/Validator/Base.lproj/Main.storyboard b/Validator/Base.lproj/Main.storyboard
index 8efcb7e..6b4ba52 100644
--- a/Validator/Base.lproj/Main.storyboard
+++ b/Validator/Base.lproj/Main.storyboard
@@ -19,6 +19,12 @@
+
@@ -402,6 +411,7 @@
+
diff --git a/Validator/ViewController.swift b/Validator/ViewController.swift
index f273e1a..a78a982 100644
--- a/Validator/ViewController.swift
+++ b/Validator/ViewController.swift
@@ -25,6 +25,7 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate
@IBOutlet weak var phoneNumberErrorLabel: UILabel!
@IBOutlet weak var zipcodeErrorLabel: UILabel!
@IBOutlet weak var emailConfirmErrorLabel: UILabel!
+ @IBOutlet weak var agreementStatus: UISwitch!
let validator = Validator()
@@ -34,7 +35,6 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "hideKeyboard"))
validator.styleTransformers(success:{ (validationRule) -> Void in
- print("here")
// clear error label
validationRule.errorLabel?.hidden = true
validationRule.errorLabel?.text = ""
@@ -42,27 +42,32 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate
validationRule.textField.layer.borderWidth = 0.5
}, error:{ (validationError) -> Void in
- print("error")
validationError.errorLabel?.hidden = false
validationError.errorLabel?.text = validationError.errorMessage
validationError.textField.layer.borderColor = UIColor.redColor().CGColor
validationError.textField.layer.borderWidth = 1.0
})
- validator.registerField(fullNameTextField, errorLabel: fullNameErrorLabel , rules: [RequiredRule(), FullNameRule()])
+ validator.registerField(fullNameTextField, errorLabel: fullNameErrorLabel , rules: [RequiredRule(), FullNameRule()], sanitizers: [TrimLeadingAndTrailingSpacesSanitizer()])
validator.registerField(emailTextField, errorLabel: emailErrorLabel, rules: [RequiredRule(), EmailRule()])
validator.registerField(emailConfirmTextField, errorLabel: emailConfirmErrorLabel, rules: [RequiredRule(), ConfirmationRule(confirmField: emailTextField)])
validator.registerField(phoneNumberTextField, errorLabel: phoneNumberErrorLabel, rules: [RequiredRule(), MinLengthRule(length: 9)])
validator.registerField(zipcodeTextField, errorLabel: zipcodeErrorLabel, rules: [RequiredRule(), ZipCodeRule()])
+ // Set validator delegate
+ validator.delegate = self
}
@IBAction func submitTapped(sender: AnyObject) {
print("Validating...")
- validator.validate(self)
+ validator.validate()
}
// MARK: ValidationDelegate Methods
+ func willValidate() {
+ print("Prepare validator for validation")
+ }
+
func validationSuccessful() {
print("Validation Success!")
let alert = UIAlertController(title: "Success", message: "You are validated!", preferredStyle: UIAlertControllerStyle.Alert)
@@ -71,10 +76,30 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate
self.presentViewController(alert, animated: true, completion: nil)
}
+
func validationFailed(errors:[UITextField:ValidationError]) {
print("Validation FAILED!")
}
+ func shouldValidate() -> Bool {
+ // Allow user to check that any preconditions are met before validation
+ // Good place to validate things other than UITextField
+ if !agreementStatus.on {
+ return false
+ }
+ return true
+ }
+
+ func failedBeforeValidation() {
+ // perform any style transformations
+ print("validation failed before running")
+ }
+
+ func didValidate() {
+ // perform custom post validation
+ print("validationDidRun called")
+ }
+
func hideKeyboard(){
self.view.endEditing(true)
}
@@ -91,5 +116,4 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate
}
return true
}
-
}
\ No newline at end of file