├── .gitignore
├── Example
├── .idea
│ ├── Example.iml
│ ├── modules.xml
│ ├── workspace.xml
│ └── xcode.xml
├── Example.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── Example
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── ic_turtle.imageset
│ │ ├── Contents.json
│ │ ├── ic_turtle.png
│ │ ├── ic_turtle@2x.png
│ │ └── ic_turtle@3x.png
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Cells
│ ├── ButtonCell.h
│ ├── ButtonCell.m
│ ├── MultiTextCell.h
│ ├── MultiTextCell.m
│ ├── SegmentedCell.h
│ ├── SegmentedCell.m
│ ├── SliderCell.h
│ ├── SliderCell.m
│ ├── StepperCell.h
│ ├── StepperCell.m
│ ├── SwitchCell.h
│ ├── SwitchCell.m
│ ├── TextCell.h
│ └── TextCell.m
│ ├── Info.plist
│ ├── ViewController.h
│ ├── ViewController.m
│ ├── form.json
│ └── main.m
├── LICENSE
├── PureForm.podspec
├── PureForm
├── Categories
│ ├── NSString+PureForm.h
│ ├── NSString+PureForm.m
│ ├── PFInputView+Validation.h
│ ├── PFInputView+Validation.m
│ ├── PFValidator+FailureReason.h
│ ├── PFValidator+FailureReason.m
│ ├── UIColor+PureForm.h
│ ├── UIColor+PureForm.m
│ ├── UISlider+PureForm.h
│ ├── UISlider+PureForm.m
│ ├── UITableViewCell+PureForm.h
│ ├── UITableViewCell+PureForm.m
│ ├── UIView+PureForm.h
│ └── UIView+PureForm.m
├── Common
│ ├── PFConstants.h
│ ├── PFEnums.h
│ ├── PFEnums.m
│ ├── PFMacros.h
│ └── PFProtocols.h
├── Delegates
│ ├── PFFormDelegate.h
│ ├── PFInputViewDelegate.h
│ ├── PFInputViewDelegate.m
│ └── PFViewDelegate.h
├── Models
│ ├── PFError.h
│ ├── PFError.m
│ ├── PFInputView.h
│ ├── PFInputView.m
│ ├── PFModel.h
│ ├── PFModel.m
│ ├── PFSettings.h
│ ├── PFSettings.m
│ ├── PFValidator.h
│ └── PFValidator.m
├── PFFormController.h
├── PFFormController.m
├── PFJSONSerialization.h
├── PFJSONSerialization.m
├── PFTableViewDataSource.h
├── PFTableViewDataSource.m
└── PureForm.h
├── README.md
└── Screenshots
├── centered_text.png
├── clean_form.png
├── filled_form.png
└── filled_form_error.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | # Pods/
37 |
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 |
43 | Carthage/Build
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
51 |
52 | fastlane/report.xml
53 | fastlane/screenshots
54 |
55 | #Code Injection
56 | #
57 | # After new code Injection tools there's a generated folder /iOSInjectionProject
58 | # https://github.com/johnno1962/injectionforxcode
59 |
60 | iOSInjectionProject/
61 |
--------------------------------------------------------------------------------
/Example/.idea/Example.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Example/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/.idea/xcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 495379E0E7B8260F290BF8BC /* form.json in Resources */ = {isa = PBXBuildFile; fileRef = 49537A582DA49F05CD69AAA0 /* form.json */; };
11 | E920F5AA1D6B189200F98334 /* UISlider+PureForm.m in Sources */ = {isa = PBXBuildFile; fileRef = E920F5A91D6B189200F98334 /* UISlider+PureForm.m */; };
12 | E920F5B01D6BB3B900F98334 /* UIColor+PureForm.m in Sources */ = {isa = PBXBuildFile; fileRef = E920F5AF1D6BB3B900F98334 /* UIColor+PureForm.m */; };
13 | E92B23DE1D6E261A001FDC7F /* PFError.m in Sources */ = {isa = PBXBuildFile; fileRef = E92B23D91D6E261A001FDC7F /* PFError.m */; };
14 | E92B23DF1D6E261A001FDC7F /* PFModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E92B23DB1D6E261A001FDC7F /* PFModel.m */; };
15 | E92B23E01D6E261A001FDC7F /* PFSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = E92B23DD1D6E261A001FDC7F /* PFSettings.m */; };
16 | E92B23E31D6E2630001FDC7F /* PFInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = E92B23E21D6E2630001FDC7F /* PFInputView.m */; };
17 | E92B23E61D6E2641001FDC7F /* PFValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = E92B23E51D6E2641001FDC7F /* PFValidator.m */; };
18 | E959E1D41D687D3800D5461B /* SwitchCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E959E1D31D687D3800D5461B /* SwitchCell.m */; };
19 | E959E1D71D68A09D00D5461B /* StepperCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E959E1D61D68A09D00D5461B /* StepperCell.m */; };
20 | E959E1DA1D68F01200D5461B /* SliderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E959E1D91D68F01200D5461B /* SliderCell.m */; };
21 | E965BDE81D5F36E400D05E14 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BDE71D5F36E400D05E14 /* main.m */; };
22 | E965BDEB1D5F36E400D05E14 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BDEA1D5F36E400D05E14 /* AppDelegate.m */; };
23 | E965BDEE1D5F36E400D05E14 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BDED1D5F36E400D05E14 /* ViewController.m */; };
24 | E965BDF11D5F36E400D05E14 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E965BDEF1D5F36E400D05E14 /* Main.storyboard */; };
25 | E965BDF31D5F36E400D05E14 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E965BDF21D5F36E400D05E14 /* Assets.xcassets */; };
26 | E965BDF61D5F36E400D05E14 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E965BDF41D5F36E400D05E14 /* LaunchScreen.storyboard */; };
27 | E965BE011D5F46B200D05E14 /* PFJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE001D5F46B200D05E14 /* PFJSONSerialization.m */; };
28 | E965BE041D5F4DE400D05E14 /* PFFormController.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE031D5F4DE400D05E14 /* PFFormController.m */; };
29 | E965BE121D5F652300D05E14 /* NSString+PureForm.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE111D5F652300D05E14 /* NSString+PureForm.m */; };
30 | E965BE211D608A3700D05E14 /* PFEnums.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE1F1D608A3700D05E14 /* PFEnums.m */; };
31 | E965BE261D608E4A00D05E14 /* PFTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE251D608E4A00D05E14 /* PFTableViewDataSource.m */; };
32 | E965BE2A1D60963600D05E14 /* TextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE291D60963600D05E14 /* TextCell.m */; };
33 | E965BE331D62417F00D05E14 /* UITableViewCell+PureForm.m in Sources */ = {isa = PBXBuildFile; fileRef = E965BE321D62417F00D05E14 /* UITableViewCell+PureForm.m */; };
34 | E981C5B81D635B28001C25EF /* PFInputViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E981C5B71D635B28001C25EF /* PFInputViewDelegate.m */; };
35 | E981C5BB1D6370BC001C25EF /* PFInputView+Validation.m in Sources */ = {isa = PBXBuildFile; fileRef = E981C5BA1D6370BC001C25EF /* PFInputView+Validation.m */; };
36 | E981C5BE1D648737001C25EF /* PFValidator+FailureReason.m in Sources */ = {isa = PBXBuildFile; fileRef = E981C5BD1D648737001C25EF /* PFValidator+FailureReason.m */; };
37 | E981C5C11D649782001C25EF /* ButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E981C5C01D649782001C25EF /* ButtonCell.m */; };
38 | E981C5C41D64CFD1001C25EF /* UIView+PureForm.m in Sources */ = {isa = PBXBuildFile; fileRef = E981C5C31D64CFD1001C25EF /* UIView+PureForm.m */; };
39 | E981C5CA1D6600DC001C25EF /* MultiTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E981C5C91D6600DC001C25EF /* MultiTextCell.m */; };
40 | E9F2FEDF1D672A8100657744 /* SegmentedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E9F2FEDE1D672A8100657744 /* SegmentedCell.m */; };
41 | /* End PBXBuildFile section */
42 |
43 | /* Begin PBXFileReference section */
44 | 49537A582DA49F05CD69AAA0 /* form.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = form.json; sourceTree = ""; };
45 | E920F5A81D6B189200F98334 /* UISlider+PureForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UISlider+PureForm.h"; sourceTree = ""; };
46 | E920F5A91D6B189200F98334 /* UISlider+PureForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UISlider+PureForm.m"; sourceTree = ""; };
47 | E920F5AB1D6B486500F98334 /* PureForm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PureForm.h; sourceTree = ""; };
48 | E920F5AE1D6BB3B900F98334 /* UIColor+PureForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+PureForm.h"; sourceTree = ""; };
49 | E920F5AF1D6BB3B900F98334 /* UIColor+PureForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+PureForm.m"; sourceTree = ""; };
50 | E92B23D81D6E261A001FDC7F /* PFError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFError.h; sourceTree = ""; };
51 | E92B23D91D6E261A001FDC7F /* PFError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFError.m; sourceTree = ""; };
52 | E92B23DA1D6E261A001FDC7F /* PFModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFModel.h; sourceTree = ""; };
53 | E92B23DB1D6E261A001FDC7F /* PFModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFModel.m; sourceTree = ""; };
54 | E92B23DC1D6E261A001FDC7F /* PFSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFSettings.h; sourceTree = ""; };
55 | E92B23DD1D6E261A001FDC7F /* PFSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFSettings.m; sourceTree = ""; };
56 | E92B23E11D6E2630001FDC7F /* PFInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFInputView.h; sourceTree = ""; };
57 | E92B23E21D6E2630001FDC7F /* PFInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFInputView.m; sourceTree = ""; };
58 | E92B23E41D6E2641001FDC7F /* PFValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFValidator.h; sourceTree = ""; };
59 | E92B23E51D6E2641001FDC7F /* PFValidator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFValidator.m; sourceTree = ""; };
60 | E959E1D11D68651900D5461B /* PFProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFProtocols.h; sourceTree = ""; };
61 | E959E1D21D687D3800D5461B /* SwitchCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwitchCell.h; sourceTree = ""; };
62 | E959E1D31D687D3800D5461B /* SwitchCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwitchCell.m; sourceTree = ""; };
63 | E959E1D51D68A09D00D5461B /* StepperCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StepperCell.h; sourceTree = ""; };
64 | E959E1D61D68A09D00D5461B /* StepperCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StepperCell.m; sourceTree = ""; };
65 | E959E1D81D68F01200D5461B /* SliderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SliderCell.h; sourceTree = ""; };
66 | E959E1D91D68F01200D5461B /* SliderCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SliderCell.m; sourceTree = ""; };
67 | E965BDE31D5F36E400D05E14 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
68 | E965BDE71D5F36E400D05E14 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
69 | E965BDE91D5F36E400D05E14 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
70 | E965BDEA1D5F36E400D05E14 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
71 | E965BDEC1D5F36E400D05E14 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
72 | E965BDED1D5F36E400D05E14 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
73 | E965BDF01D5F36E400D05E14 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
74 | E965BDF21D5F36E400D05E14 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
75 | E965BDF51D5F36E400D05E14 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
76 | E965BDF71D5F36E400D05E14 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
77 | E965BDFF1D5F46B200D05E14 /* PFJSONSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFJSONSerialization.h; sourceTree = ""; };
78 | E965BE001D5F46B200D05E14 /* PFJSONSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFJSONSerialization.m; sourceTree = ""; };
79 | E965BE021D5F4DE400D05E14 /* PFFormController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFFormController.h; sourceTree = ""; };
80 | E965BE031D5F4DE400D05E14 /* PFFormController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFFormController.m; sourceTree = ""; };
81 | E965BE101D5F652300D05E14 /* NSString+PureForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+PureForm.h"; sourceTree = ""; };
82 | E965BE111D5F652300D05E14 /* NSString+PureForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+PureForm.m"; sourceTree = ""; };
83 | E965BE1D1D608A3700D05E14 /* PFConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFConstants.h; sourceTree = ""; };
84 | E965BE1E1D608A3700D05E14 /* PFEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFEnums.h; sourceTree = ""; };
85 | E965BE1F1D608A3700D05E14 /* PFEnums.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFEnums.m; sourceTree = ""; };
86 | E965BE201D608A3700D05E14 /* PFMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFMacros.h; sourceTree = ""; };
87 | E965BE231D608BAA00D05E14 /* PFFormDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFFormDelegate.h; sourceTree = ""; };
88 | E965BE241D608E4A00D05E14 /* PFTableViewDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFTableViewDataSource.h; sourceTree = ""; };
89 | E965BE251D608E4A00D05E14 /* PFTableViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFTableViewDataSource.m; sourceTree = ""; };
90 | E965BE281D60963600D05E14 /* TextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextCell.h; sourceTree = ""; };
91 | E965BE291D60963600D05E14 /* TextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextCell.m; sourceTree = ""; };
92 | E965BE311D62417F00D05E14 /* UITableViewCell+PureForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableViewCell+PureForm.h"; sourceTree = ""; };
93 | E965BE321D62417F00D05E14 /* UITableViewCell+PureForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableViewCell+PureForm.m"; sourceTree = ""; };
94 | E981C5B71D635B28001C25EF /* PFInputViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFInputViewDelegate.m; sourceTree = ""; };
95 | E981C5B91D6370BC001C25EF /* PFInputView+Validation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PFInputView+Validation.h"; sourceTree = ""; };
96 | E981C5BA1D6370BC001C25EF /* PFInputView+Validation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PFInputView+Validation.m"; sourceTree = ""; };
97 | E981C5BC1D648737001C25EF /* PFValidator+FailureReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PFValidator+FailureReason.h"; sourceTree = ""; };
98 | E981C5BD1D648737001C25EF /* PFValidator+FailureReason.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PFValidator+FailureReason.m"; sourceTree = ""; };
99 | E981C5BF1D649782001C25EF /* ButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButtonCell.h; sourceTree = ""; };
100 | E981C5C01D649782001C25EF /* ButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ButtonCell.m; sourceTree = ""; };
101 | E981C5C21D64CFD1001C25EF /* UIView+PureForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+PureForm.h"; sourceTree = ""; };
102 | E981C5C31D64CFD1001C25EF /* UIView+PureForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+PureForm.m"; sourceTree = ""; };
103 | E981C5C81D6600DC001C25EF /* MultiTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultiTextCell.h; sourceTree = ""; };
104 | E981C5C91D6600DC001C25EF /* MultiTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultiTextCell.m; sourceTree = ""; };
105 | E9F2FEDD1D672A8100657744 /* SegmentedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SegmentedCell.h; sourceTree = ""; };
106 | E9F2FEDE1D672A8100657744 /* SegmentedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SegmentedCell.m; sourceTree = ""; };
107 | E9F2FEE11D6739E900657744 /* PFInputViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PFInputViewDelegate.h; sourceTree = ""; };
108 | E9F2FEE21D673A1000657744 /* PFViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFViewDelegate.h; sourceTree = ""; };
109 | /* End PBXFileReference section */
110 |
111 | /* Begin PBXFrameworksBuildPhase section */
112 | E965BDE01D5F36E400D05E14 /* Frameworks */ = {
113 | isa = PBXFrameworksBuildPhase;
114 | buildActionMask = 2147483647;
115 | files = (
116 | );
117 | runOnlyForDeploymentPostprocessing = 0;
118 | };
119 | /* End PBXFrameworksBuildPhase section */
120 |
121 | /* Begin PBXGroup section */
122 | E92B23D71D6E261A001FDC7F /* Models */ = {
123 | isa = PBXGroup;
124 | children = (
125 | E92B23D81D6E261A001FDC7F /* PFError.h */,
126 | E92B23D91D6E261A001FDC7F /* PFError.m */,
127 | E92B23DA1D6E261A001FDC7F /* PFModel.h */,
128 | E92B23DB1D6E261A001FDC7F /* PFModel.m */,
129 | E92B23DC1D6E261A001FDC7F /* PFSettings.h */,
130 | E92B23DD1D6E261A001FDC7F /* PFSettings.m */,
131 | E92B23E11D6E2630001FDC7F /* PFInputView.h */,
132 | E92B23E21D6E2630001FDC7F /* PFInputView.m */,
133 | E92B23E41D6E2641001FDC7F /* PFValidator.h */,
134 | E92B23E51D6E2641001FDC7F /* PFValidator.m */,
135 | );
136 | path = Models;
137 | sourceTree = "";
138 | };
139 | E965BDDA1D5F36E400D05E14 = {
140 | isa = PBXGroup;
141 | children = (
142 | E965BDFE1D5F380100D05E14 /* PureForm */,
143 | E965BDE51D5F36E400D05E14 /* Example */,
144 | E965BDE41D5F36E400D05E14 /* Products */,
145 | );
146 | sourceTree = "";
147 | };
148 | E965BDE41D5F36E400D05E14 /* Products */ = {
149 | isa = PBXGroup;
150 | children = (
151 | E965BDE31D5F36E400D05E14 /* Example.app */,
152 | );
153 | name = Products;
154 | sourceTree = "";
155 | };
156 | E965BDE51D5F36E400D05E14 /* Example */ = {
157 | isa = PBXGroup;
158 | children = (
159 | E965BE271D60961C00D05E14 /* Cells */,
160 | E965BDE91D5F36E400D05E14 /* AppDelegate.h */,
161 | E965BDEA1D5F36E400D05E14 /* AppDelegate.m */,
162 | E965BDEC1D5F36E400D05E14 /* ViewController.h */,
163 | E965BDED1D5F36E400D05E14 /* ViewController.m */,
164 | E965BDEF1D5F36E400D05E14 /* Main.storyboard */,
165 | E965BDF21D5F36E400D05E14 /* Assets.xcassets */,
166 | E965BDF41D5F36E400D05E14 /* LaunchScreen.storyboard */,
167 | E965BDF71D5F36E400D05E14 /* Info.plist */,
168 | E965BDE61D5F36E400D05E14 /* Supporting Files */,
169 | 49537A582DA49F05CD69AAA0 /* form.json */,
170 | );
171 | path = Example;
172 | sourceTree = "";
173 | };
174 | E965BDE61D5F36E400D05E14 /* Supporting Files */ = {
175 | isa = PBXGroup;
176 | children = (
177 | E965BDE71D5F36E400D05E14 /* main.m */,
178 | );
179 | name = "Supporting Files";
180 | sourceTree = "";
181 | };
182 | E965BDFE1D5F380100D05E14 /* PureForm */ = {
183 | isa = PBXGroup;
184 | children = (
185 | E965BE0C1D5F614000D05E14 /* Categories */,
186 | E965BE1C1D608A3700D05E14 /* Common */,
187 | E965BE221D608A4800D05E14 /* Delegates */,
188 | E92B23D71D6E261A001FDC7F /* Models */,
189 | E965BDFF1D5F46B200D05E14 /* PFJSONSerialization.h */,
190 | E965BE001D5F46B200D05E14 /* PFJSONSerialization.m */,
191 | E965BE021D5F4DE400D05E14 /* PFFormController.h */,
192 | E965BE031D5F4DE400D05E14 /* PFFormController.m */,
193 | E965BE241D608E4A00D05E14 /* PFTableViewDataSource.h */,
194 | E965BE251D608E4A00D05E14 /* PFTableViewDataSource.m */,
195 | E920F5AB1D6B486500F98334 /* PureForm.h */,
196 | );
197 | name = PureForm;
198 | path = ../PureForm;
199 | sourceTree = "";
200 | };
201 | E965BE0C1D5F614000D05E14 /* Categories */ = {
202 | isa = PBXGroup;
203 | children = (
204 | E965BE101D5F652300D05E14 /* NSString+PureForm.h */,
205 | E965BE111D5F652300D05E14 /* NSString+PureForm.m */,
206 | E965BE311D62417F00D05E14 /* UITableViewCell+PureForm.h */,
207 | E965BE321D62417F00D05E14 /* UITableViewCell+PureForm.m */,
208 | E981C5B91D6370BC001C25EF /* PFInputView+Validation.h */,
209 | E981C5BA1D6370BC001C25EF /* PFInputView+Validation.m */,
210 | E981C5BC1D648737001C25EF /* PFValidator+FailureReason.h */,
211 | E981C5BD1D648737001C25EF /* PFValidator+FailureReason.m */,
212 | E981C5C21D64CFD1001C25EF /* UIView+PureForm.h */,
213 | E981C5C31D64CFD1001C25EF /* UIView+PureForm.m */,
214 | E920F5A81D6B189200F98334 /* UISlider+PureForm.h */,
215 | E920F5A91D6B189200F98334 /* UISlider+PureForm.m */,
216 | E920F5AE1D6BB3B900F98334 /* UIColor+PureForm.h */,
217 | E920F5AF1D6BB3B900F98334 /* UIColor+PureForm.m */,
218 | );
219 | path = Categories;
220 | sourceTree = "";
221 | };
222 | E965BE1C1D608A3700D05E14 /* Common */ = {
223 | isa = PBXGroup;
224 | children = (
225 | E965BE1D1D608A3700D05E14 /* PFConstants.h */,
226 | E965BE1E1D608A3700D05E14 /* PFEnums.h */,
227 | E965BE1F1D608A3700D05E14 /* PFEnums.m */,
228 | E965BE201D608A3700D05E14 /* PFMacros.h */,
229 | E959E1D11D68651900D5461B /* PFProtocols.h */,
230 | );
231 | path = Common;
232 | sourceTree = "";
233 | };
234 | E965BE221D608A4800D05E14 /* Delegates */ = {
235 | isa = PBXGroup;
236 | children = (
237 | E965BE231D608BAA00D05E14 /* PFFormDelegate.h */,
238 | E9F2FEE11D6739E900657744 /* PFInputViewDelegate.h */,
239 | E981C5B71D635B28001C25EF /* PFInputViewDelegate.m */,
240 | E9F2FEE21D673A1000657744 /* PFViewDelegate.h */,
241 | );
242 | path = Delegates;
243 | sourceTree = "";
244 | };
245 | E965BE271D60961C00D05E14 /* Cells */ = {
246 | isa = PBXGroup;
247 | children = (
248 | E965BE281D60963600D05E14 /* TextCell.h */,
249 | E965BE291D60963600D05E14 /* TextCell.m */,
250 | E981C5BF1D649782001C25EF /* ButtonCell.h */,
251 | E981C5C01D649782001C25EF /* ButtonCell.m */,
252 | E981C5C81D6600DC001C25EF /* MultiTextCell.h */,
253 | E981C5C91D6600DC001C25EF /* MultiTextCell.m */,
254 | E9F2FEDD1D672A8100657744 /* SegmentedCell.h */,
255 | E9F2FEDE1D672A8100657744 /* SegmentedCell.m */,
256 | E959E1D21D687D3800D5461B /* SwitchCell.h */,
257 | E959E1D31D687D3800D5461B /* SwitchCell.m */,
258 | E959E1D51D68A09D00D5461B /* StepperCell.h */,
259 | E959E1D61D68A09D00D5461B /* StepperCell.m */,
260 | E959E1D81D68F01200D5461B /* SliderCell.h */,
261 | E959E1D91D68F01200D5461B /* SliderCell.m */,
262 | );
263 | path = Cells;
264 | sourceTree = "";
265 | };
266 | /* End PBXGroup section */
267 |
268 | /* Begin PBXNativeTarget section */
269 | E965BDE21D5F36E400D05E14 /* Example */ = {
270 | isa = PBXNativeTarget;
271 | buildConfigurationList = E965BDFA1D5F36E400D05E14 /* Build configuration list for PBXNativeTarget "Example" */;
272 | buildPhases = (
273 | E965BDDF1D5F36E400D05E14 /* Sources */,
274 | E965BDE01D5F36E400D05E14 /* Frameworks */,
275 | E965BDE11D5F36E400D05E14 /* Resources */,
276 | );
277 | buildRules = (
278 | );
279 | dependencies = (
280 | );
281 | name = Example;
282 | productName = Example;
283 | productReference = E965BDE31D5F36E400D05E14 /* Example.app */;
284 | productType = "com.apple.product-type.application";
285 | };
286 | /* End PBXNativeTarget section */
287 |
288 | /* Begin PBXProject section */
289 | E965BDDB1D5F36E400D05E14 /* Project object */ = {
290 | isa = PBXProject;
291 | attributes = {
292 | LastUpgradeCheck = 0730;
293 | ORGANIZATIONNAME = "Puzyrev Pavel";
294 | TargetAttributes = {
295 | E965BDE21D5F36E400D05E14 = {
296 | CreatedOnToolsVersion = 7.3.1;
297 | DevelopmentTeam = 22BDH96YAS;
298 | };
299 | };
300 | };
301 | buildConfigurationList = E965BDDE1D5F36E400D05E14 /* Build configuration list for PBXProject "Example" */;
302 | compatibilityVersion = "Xcode 3.2";
303 | developmentRegion = English;
304 | hasScannedForEncodings = 0;
305 | knownRegions = (
306 | en,
307 | Base,
308 | );
309 | mainGroup = E965BDDA1D5F36E400D05E14;
310 | productRefGroup = E965BDE41D5F36E400D05E14 /* Products */;
311 | projectDirPath = "";
312 | projectRoot = "";
313 | targets = (
314 | E965BDE21D5F36E400D05E14 /* Example */,
315 | );
316 | };
317 | /* End PBXProject section */
318 |
319 | /* Begin PBXResourcesBuildPhase section */
320 | E965BDE11D5F36E400D05E14 /* Resources */ = {
321 | isa = PBXResourcesBuildPhase;
322 | buildActionMask = 2147483647;
323 | files = (
324 | E965BDF61D5F36E400D05E14 /* LaunchScreen.storyboard in Resources */,
325 | E965BDF31D5F36E400D05E14 /* Assets.xcassets in Resources */,
326 | E965BDF11D5F36E400D05E14 /* Main.storyboard in Resources */,
327 | 495379E0E7B8260F290BF8BC /* form.json in Resources */,
328 | );
329 | runOnlyForDeploymentPostprocessing = 0;
330 | };
331 | /* End PBXResourcesBuildPhase section */
332 |
333 | /* Begin PBXSourcesBuildPhase section */
334 | E965BDDF1D5F36E400D05E14 /* Sources */ = {
335 | isa = PBXSourcesBuildPhase;
336 | buildActionMask = 2147483647;
337 | files = (
338 | E965BE211D608A3700D05E14 /* PFEnums.m in Sources */,
339 | E981C5B81D635B28001C25EF /* PFInputViewDelegate.m in Sources */,
340 | E965BE331D62417F00D05E14 /* UITableViewCell+PureForm.m in Sources */,
341 | E959E1D41D687D3800D5461B /* SwitchCell.m in Sources */,
342 | E981C5CA1D6600DC001C25EF /* MultiTextCell.m in Sources */,
343 | E92B23E31D6E2630001FDC7F /* PFInputView.m in Sources */,
344 | E965BE2A1D60963600D05E14 /* TextCell.m in Sources */,
345 | E92B23E61D6E2641001FDC7F /* PFValidator.m in Sources */,
346 | E965BE041D5F4DE400D05E14 /* PFFormController.m in Sources */,
347 | E9F2FEDF1D672A8100657744 /* SegmentedCell.m in Sources */,
348 | E965BE121D5F652300D05E14 /* NSString+PureForm.m in Sources */,
349 | E92B23DF1D6E261A001FDC7F /* PFModel.m in Sources */,
350 | E920F5AA1D6B189200F98334 /* UISlider+PureForm.m in Sources */,
351 | E965BE261D608E4A00D05E14 /* PFTableViewDataSource.m in Sources */,
352 | E92B23E01D6E261A001FDC7F /* PFSettings.m in Sources */,
353 | E959E1DA1D68F01200D5461B /* SliderCell.m in Sources */,
354 | E920F5B01D6BB3B900F98334 /* UIColor+PureForm.m in Sources */,
355 | E965BDEE1D5F36E400D05E14 /* ViewController.m in Sources */,
356 | E965BDEB1D5F36E400D05E14 /* AppDelegate.m in Sources */,
357 | E965BE011D5F46B200D05E14 /* PFJSONSerialization.m in Sources */,
358 | E965BDE81D5F36E400D05E14 /* main.m in Sources */,
359 | E92B23DE1D6E261A001FDC7F /* PFError.m in Sources */,
360 | E981C5BE1D648737001C25EF /* PFValidator+FailureReason.m in Sources */,
361 | E981C5C41D64CFD1001C25EF /* UIView+PureForm.m in Sources */,
362 | E981C5BB1D6370BC001C25EF /* PFInputView+Validation.m in Sources */,
363 | E981C5C11D649782001C25EF /* ButtonCell.m in Sources */,
364 | E959E1D71D68A09D00D5461B /* StepperCell.m in Sources */,
365 | );
366 | runOnlyForDeploymentPostprocessing = 0;
367 | };
368 | /* End PBXSourcesBuildPhase section */
369 |
370 | /* Begin PBXVariantGroup section */
371 | E965BDEF1D5F36E400D05E14 /* Main.storyboard */ = {
372 | isa = PBXVariantGroup;
373 | children = (
374 | E965BDF01D5F36E400D05E14 /* Base */,
375 | );
376 | name = Main.storyboard;
377 | sourceTree = "";
378 | };
379 | E965BDF41D5F36E400D05E14 /* LaunchScreen.storyboard */ = {
380 | isa = PBXVariantGroup;
381 | children = (
382 | E965BDF51D5F36E400D05E14 /* Base */,
383 | );
384 | name = LaunchScreen.storyboard;
385 | sourceTree = "";
386 | };
387 | /* End PBXVariantGroup section */
388 |
389 | /* Begin XCBuildConfiguration section */
390 | E965BDF81D5F36E400D05E14 /* Debug */ = {
391 | isa = XCBuildConfiguration;
392 | buildSettings = {
393 | ALWAYS_SEARCH_USER_PATHS = NO;
394 | CLANG_ANALYZER_NONNULL = YES;
395 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
396 | CLANG_CXX_LIBRARY = "libc++";
397 | CLANG_ENABLE_MODULES = YES;
398 | CLANG_ENABLE_OBJC_ARC = YES;
399 | CLANG_WARN_BOOL_CONVERSION = YES;
400 | CLANG_WARN_CONSTANT_CONVERSION = YES;
401 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
402 | CLANG_WARN_EMPTY_BODY = YES;
403 | CLANG_WARN_ENUM_CONVERSION = YES;
404 | CLANG_WARN_INT_CONVERSION = YES;
405 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
406 | CLANG_WARN_UNREACHABLE_CODE = YES;
407 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
408 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
409 | COPY_PHASE_STRIP = NO;
410 | DEBUG_INFORMATION_FORMAT = dwarf;
411 | ENABLE_STRICT_OBJC_MSGSEND = YES;
412 | ENABLE_TESTABILITY = YES;
413 | GCC_C_LANGUAGE_STANDARD = gnu99;
414 | GCC_DYNAMIC_NO_PIC = NO;
415 | GCC_NO_COMMON_BLOCKS = YES;
416 | GCC_OPTIMIZATION_LEVEL = 0;
417 | GCC_PREPROCESSOR_DEFINITIONS = (
418 | "DEBUG=1",
419 | "$(inherited)",
420 | );
421 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
422 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
423 | GCC_WARN_UNDECLARED_SELECTOR = YES;
424 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
425 | GCC_WARN_UNUSED_FUNCTION = YES;
426 | GCC_WARN_UNUSED_VARIABLE = YES;
427 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
428 | MTL_ENABLE_DEBUG_INFO = YES;
429 | ONLY_ACTIVE_ARCH = YES;
430 | SDKROOT = iphoneos;
431 | };
432 | name = Debug;
433 | };
434 | E965BDF91D5F36E400D05E14 /* Release */ = {
435 | isa = XCBuildConfiguration;
436 | buildSettings = {
437 | ALWAYS_SEARCH_USER_PATHS = NO;
438 | CLANG_ANALYZER_NONNULL = YES;
439 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
440 | CLANG_CXX_LIBRARY = "libc++";
441 | CLANG_ENABLE_MODULES = YES;
442 | CLANG_ENABLE_OBJC_ARC = YES;
443 | CLANG_WARN_BOOL_CONVERSION = YES;
444 | CLANG_WARN_CONSTANT_CONVERSION = YES;
445 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
446 | CLANG_WARN_EMPTY_BODY = YES;
447 | CLANG_WARN_ENUM_CONVERSION = YES;
448 | CLANG_WARN_INT_CONVERSION = YES;
449 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
450 | CLANG_WARN_UNREACHABLE_CODE = YES;
451 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
452 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
453 | COPY_PHASE_STRIP = NO;
454 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
455 | ENABLE_NS_ASSERTIONS = NO;
456 | ENABLE_STRICT_OBJC_MSGSEND = YES;
457 | GCC_C_LANGUAGE_STANDARD = gnu99;
458 | GCC_NO_COMMON_BLOCKS = YES;
459 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
460 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
461 | GCC_WARN_UNDECLARED_SELECTOR = YES;
462 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
463 | GCC_WARN_UNUSED_FUNCTION = YES;
464 | GCC_WARN_UNUSED_VARIABLE = YES;
465 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
466 | MTL_ENABLE_DEBUG_INFO = NO;
467 | SDKROOT = iphoneos;
468 | VALIDATE_PRODUCT = YES;
469 | };
470 | name = Release;
471 | };
472 | E965BDFB1D5F36E400D05E14 /* Debug */ = {
473 | isa = XCBuildConfiguration;
474 | buildSettings = {
475 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
476 | DEVELOPMENT_TEAM = 22BDH96YAS;
477 | INFOPLIST_FILE = Example/Info.plist;
478 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
480 | PRODUCT_BUNDLE_IDENTIFIER = com.cannedapp.pureformexample;
481 | PRODUCT_NAME = "$(TARGET_NAME)";
482 | };
483 | name = Debug;
484 | };
485 | E965BDFC1D5F36E400D05E14 /* Release */ = {
486 | isa = XCBuildConfiguration;
487 | buildSettings = {
488 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
489 | DEVELOPMENT_TEAM = 22BDH96YAS;
490 | INFOPLIST_FILE = Example/Info.plist;
491 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
492 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
493 | PRODUCT_BUNDLE_IDENTIFIER = com.cannedapp.pureformexample;
494 | PRODUCT_NAME = "$(TARGET_NAME)";
495 | };
496 | name = Release;
497 | };
498 | /* End XCBuildConfiguration section */
499 |
500 | /* Begin XCConfigurationList section */
501 | E965BDDE1D5F36E400D05E14 /* Build configuration list for PBXProject "Example" */ = {
502 | isa = XCConfigurationList;
503 | buildConfigurations = (
504 | E965BDF81D5F36E400D05E14 /* Debug */,
505 | E965BDF91D5F36E400D05E14 /* Release */,
506 | );
507 | defaultConfigurationIsVisible = 0;
508 | defaultConfigurationName = Release;
509 | };
510 | E965BDFA1D5F36E400D05E14 /* Build configuration list for PBXNativeTarget "Example" */ = {
511 | isa = XCConfigurationList;
512 | buildConfigurations = (
513 | E965BDFB1D5F36E400D05E14 /* Debug */,
514 | E965BDFC1D5F36E400D05E14 /* Release */,
515 | );
516 | defaultConfigurationIsVisible = 0;
517 | defaultConfigurationName = Release;
518 | };
519 | /* End XCConfigurationList section */
520 | };
521 | rootObject = E965BDDB1D5F36E400D05E14 /* Project object */;
522 | }
523 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Example/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 13.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/Example/Example/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 13.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/ic_turtle.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ic_turtle.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "ic_turtle@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "ic_turtle@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/ic_turtle.imageset/ic_turtle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Example/Example/Assets.xcassets/ic_turtle.imageset/ic_turtle.png
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/ic_turtle.imageset/ic_turtle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Example/Example/Assets.xcassets/ic_turtle.imageset/ic_turtle@2x.png
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/ic_turtle.imageset/ic_turtle@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Example/Example/Assets.xcassets/ic_turtle.imageset/ic_turtle@3x.png
--------------------------------------------------------------------------------
/Example/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Example/Example/Cells/ButtonCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // ButtonCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 17.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ButtonCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Example/Example/Cells/ButtonCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // ButtonCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 17.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "ButtonCell.h"
10 |
11 | @implementation ButtonCell
12 |
13 | - (void)awakeFromNib {
14 | [super awakeFromNib];
15 | // Initialization code
16 | }
17 |
18 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
19 | [super setSelected:selected animated:animated];
20 |
21 | // Configure the view for the selected state
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Example/Example/Cells/MultiTextCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // MultiTextCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 18.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MultiTextCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 | @property (weak, nonatomic) IBOutlet UITextField *dayTextField;
15 | @property (weak, nonatomic) IBOutlet UITextField *monthTextField;
16 | @property (weak, nonatomic) IBOutlet UITextField *yearTextField;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/Example/Example/Cells/MultiTextCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // MultiTextCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 18.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "MultiTextCell.h"
10 |
11 | @implementation MultiTextCell
12 |
13 | - (void)awakeFromNib {
14 | [super awakeFromNib];
15 | // Initialization code
16 | }
17 |
18 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
19 | [super setSelected:selected animated:animated];
20 |
21 | // Configure the view for the selected state
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Example/Example/Cells/SegmentedCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SegmentedCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 19.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SegmentedCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UISegmentedControl *segmentedControl;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Example/Example/Cells/SegmentedCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SegmentedCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 19.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "SegmentedCell.h"
10 |
11 | @implementation SegmentedCell
12 |
13 | - (void)awakeFromNib {
14 | [super awakeFromNib];
15 | // Initialization code
16 | }
17 |
18 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
19 | [super setSelected:selected animated:animated];
20 |
21 | // Configure the view for the selected state
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Example/Example/Cells/SliderCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SliderCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 20.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SliderCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 | @property (weak, nonatomic) IBOutlet UISlider *sliderControl;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Example/Example/Cells/SliderCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SliderCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 20.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "SliderCell.h"
10 |
11 | @implementation SliderCell
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/Example/Cells/StepperCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // StepperCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 20.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface StepperCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 | @property (weak, nonatomic) IBOutlet UILabel *displayLabel;
15 | @property (weak, nonatomic) IBOutlet UIStepper *stepperControl;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Example/Example/Cells/StepperCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // StepperCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 20.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "StepperCell.h"
10 |
11 | @implementation StepperCell
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/Example/Cells/SwitchCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 20.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SwitchCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 | @property (weak, nonatomic) IBOutlet UISwitch *switchControl;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Example/Example/Cells/SwitchCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 20.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "SwitchCell.h"
10 |
11 | @implementation SwitchCell
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/Example/Cells/TextCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // TextCell.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 14.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TextCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 | @property (weak, nonatomic) IBOutlet UITextField *textField;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Example/Example/Cells/TextCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // TextCell.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 14.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "TextCell.h"
10 |
11 | @implementation TextCell
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 0.0.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Example/Example/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 13.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Example/Example/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 13.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | #import "PureForm.h"
12 |
13 | @interface ViewController ()
14 |
15 | @property(strong, nonatomic) PFFormController *formController;
16 | @property(weak, nonatomic) IBOutlet UITableView *tableView;
17 |
18 | @end
19 |
20 | @implementation ViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 |
25 | PFSettings *settings = [[PFSettings alloc] init];
26 | settings.keyboardTypeValidation = YES;
27 | settings.keyboardAvoiding = YES;
28 | settings.formDelegate = self;
29 | settings.tableViewDelegate = self;
30 |
31 | self.formController = [[PFFormController alloc] initWithTableView:self.tableView settings:settings];
32 | [self.formController makeFormWithJSONFile:@"form"];
33 | }
34 |
35 | #pragma mark - PFFormDelegate
36 |
37 | - (void)valueDidUpdate {
38 | NSLog(@"valueDidUpdate");
39 | }
40 |
41 | - (void)valueDidUpdateWithError:(PFError *)error {
42 | NSLog(@"valueDidUpdateWithError: - %@", error.reason);
43 | }
44 |
45 | - (void)validationDidEndSuccessfully {
46 | NSLog(@"validationDidEndSuccessfully");
47 |
48 | NSLog(@"%@", [self.formController allKeyValuePairs]);
49 | [self showAlertWithMessage:[NSString stringWithFormat:@"%@", [self.formController allKeyValuePairs]] error:NO];
50 | }
51 |
52 | - (void)validationDidFailWithErrors:(NSArray *)errors {
53 | NSLog(@"validationDidFailWithErrors: - \n%@", [PFError descriptionFromErrors:errors]);
54 |
55 | [self showAlertWithMessage:@"Some errors, check log." error:YES];
56 | }
57 |
58 | #pragma mark - UITableViewDelegate
59 |
60 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
61 | [tableView deselectRowAtIndexPath:indexPath animated:YES];
62 |
63 | if (indexPath.section == 3) {
64 | [self.formController validate];
65 | }
66 | }
67 |
68 | #pragma mark - Alerts
69 |
70 | - (void)showAlertWithMessage:(NSString *)message error:(BOOL)isError {
71 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:isError ? @"Error" : @"Yep"
72 | message:message
73 | preferredStyle:UIAlertControllerStyleAlert];
74 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
75 | style:UIAlertActionStyleCancel
76 | handler:nil];
77 | [alertController addAction:okAction];
78 |
79 | [self presentViewController:alertController animated:YES completion:nil];
80 | }
81 |
82 | @end
83 |
--------------------------------------------------------------------------------
/Example/Example/form.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "": {
4 | "textField?": {
5 | "placeholder": "Thomas",
6 | "": "name",
7 | "": {
8 | "required": true
9 | }
10 | },
11 | "titleLabel": {
12 | "text": "Name"
13 | }
14 | }
15 | },
16 | {
17 | "<= + =>": {
18 | "textField?": {
19 | "placeholder": "Bakker",
20 | "": "surname",
21 | "": {
22 | "required": true
23 | }
24 | },
25 | "titleLabel": {
26 | "text": "Surname"
27 | }
28 | }
29 | },
30 | {
31 | "": {
32 | "dayTextField?": {
33 | "placeholder": "01",
34 | "keyboardType": "UIKeyboardTypeNumberPad",
35 | "": "dob_day",
36 | "": {
37 | "min_length": 1,
38 | "max_length": 2
39 | }
40 | },
41 | "monthTextField?": {
42 | "placeholder": "11",
43 | "keyboardType": "UIKeyboardTypeNumberPad",
44 | "": "dob_month",
45 | "": {
46 | "min_length": 1,
47 | "max_length": 2
48 | }
49 | },
50 | "yearTextField?": {
51 | "placeholder": "1990",
52 | "keyboardType": "UIKeyboardTypeNumberPad",
53 | "": "dob_year",
54 | "": {
55 | "equal_length": 4
56 | }
57 | },
58 | "titleLabel": {
59 | "text": "Date of birth"
60 | }
61 | }
62 | },
63 | {
64 | "": {
65 | "segmentedControl?": {
66 | "sectionTitle0": "Male",
67 | "sectionTitle1": "Female",
68 | "tintColor": "#6F3F83",
69 | "": 0,
70 | "": "gender",
71 | "": {
72 | "required": true
73 | }
74 | }
75 | }
76 | },
77 | {
78 | "": 1
79 | },
80 | {
81 | "": {
82 | "textField?": {
83 | "placeholder": "Klundert",
84 | "": "city",
85 | "": {
86 | "required": true
87 | }
88 | },
89 | "titleLabel": {
90 | "text": "City"
91 | }
92 | }
93 | },
94 | {
95 | "<= + =>": {
96 | "textField?": {
97 | "placeholder": "Prins Willemstraat 1",
98 | "": "address",
99 | "": {
100 | "required": true
101 | }
102 | },
103 | "titleLabel": {
104 | "text": "Address"
105 | }
106 | }
107 | },
108 | {
109 | "<= + =>": {
110 | "textField?": {
111 | "placeholder": "+31 6 12345678",
112 | "keyboardType": "UIKeyboardTypePhonePad",
113 | "": "phone",
114 | "": {
115 | "required": true
116 | }
117 | },
118 | "titleLabel": {
119 | "text": "Phone"
120 | }
121 | }
122 | },
123 | {
124 | "<= + =>": {
125 | "textField?": {
126 | "placeholder": "thomas.bakker@domain.com",
127 | "keyboardType": "UIKeyboardTypeEmailAddress",
128 | "": "email",
129 | "": {
130 | "type": "email"
131 | }
132 | },
133 | "titleLabel": {
134 | "text": "Email"
135 | }
136 | }
137 | },
138 | {
139 | "": 2
140 | },
141 | {
142 | "": {
143 | "stepperControl?": {
144 | "stepValue": 1,
145 | "tintColor": "#6F3F83",
146 | "": "children_count",
147 | "": "displayLabel",
148 | "": "0"
149 | },
150 | "titleLabel": {
151 | "text": "Children"
152 | }
153 | }
154 | },
155 | {
156 | "": {
157 | "switchControl?": {
158 | "onTintColor": "#6F3F83",
159 | "": true,
160 | "": "driver_license"
161 | },
162 | "titleLabel": {
163 | "text": "Driver licence"
164 | }
165 | }
166 | },
167 | {
168 | "": {
169 | "sliderControl?": {
170 | "stepValue": 1,
171 | "minimumValue": 0,
172 | "maximumValue": 100,
173 | "minimumTrackTintColor": "#6F3F83",
174 | "": 50,
175 | "": "test"
176 | },
177 | "titleLabel": {
178 | "text": "Center it"
179 | }
180 | }
181 | },
182 | {
183 | "": 3
184 | },
185 | {
186 | "": {
187 | "titleLabel": {
188 | "text": "Accept",
189 | "textColor": "#6F3F83"
190 | }
191 | }
192 | },
193 | {
194 | "": 4
195 | },
196 | {
197 | "": {
198 | "imageView": {
199 | "image": "ic_turtle#6F3F83"
200 | },
201 | "textLabel": {
202 | "text": "Colored turtle :)"
203 | }
204 | }
205 | }
206 | ]
--------------------------------------------------------------------------------
/Example/Example/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 13.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Pavel Puzyrev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PureForm.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "PureForm"
3 | s.version = "0.0.2"
4 | s.summary = "Easy form creator based on JSON"
5 | s.homepage = "https://github.com/unboxme/PureForm"
6 | s.license = { :type => 'MIT', :file => 'LICENSE' }
7 | s.author = { "Pavel Puzyrev" => "cannedapp@yahoo.com" }
8 | s.platform = :ios, '8.0'
9 | s.source = { :git => "https://github.com/unboxme/PureForm.git", :tag => s.version.to_s }
10 |
11 | s.source_files = 'PureForm/**/*.{h,m}'
12 | s.public_header_files = 'PureForm/**/*.h'
13 |
14 | s.framework = 'Foundation'
15 | s.requires_arc = true
16 | end
17 |
--------------------------------------------------------------------------------
/PureForm/Categories/NSString+PureForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+PureForm.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | @interface NSString (PureForm)
27 |
28 | /**
29 | @return `YES` if the string is special PureForm key, otherwise `NO`.
30 | */
31 | - (BOOL)pf_isSpecialKey;
32 |
33 | /**
34 | @return `YES` if the string contains cell class and identifier, otherwise `NO`.
35 | */
36 | - (BOOL)pf_isCombinedKey;
37 |
38 | /**
39 | @return `YES` if the string has suffix, otherwise `NO`.
40 | */
41 | - (BOOL)pf_hasSuffix;
42 |
43 | /**
44 | @return `YES` if the string has localized suffix, otherwise `NO`.
45 | */
46 | - (BOOL)pf_hasLocalizedSuffix;
47 |
48 | /**
49 | @return `YES` if the string has form view suffix, otherwise `NO`.
50 | */
51 | - (BOOL)pf_hasFormViewSuffix;
52 |
53 | /**
54 | @return The cell class name.
55 | */
56 | - (NSString *)pf_cellClassName;
57 |
58 | /**
59 | @return The cell identifier.
60 | */
61 | - (NSString *)pf_cellIdentifier;
62 |
63 | /**
64 | @return The string without suffix.
65 | */
66 | - (NSString *)pf_suffixFreeString;
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/PureForm/Categories/NSString+PureForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+PureForm.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "NSString+PureForm.h"
25 | #import "PFConstants.h"
26 |
27 | @implementation NSString (PureForm)
28 |
29 | NSArray *availablePFSuffixes() {
30 | return @[PFSuffixFormView, PFSuffixForce, PFSuffixLocalized];
31 | };
32 |
33 | - (NSString *)pf_suffix {
34 | NSInteger suffixIndex = self.length - 1;
35 |
36 | if (suffixIndex < 1) {
37 | return nil;
38 | }
39 |
40 | return [self substringFromIndex:(NSUInteger) suffixIndex];
41 | }
42 |
43 | - (NSString *)pf_clearString {
44 | NSString *forbiddenChars = [NSString stringWithFormat:@"%@%@", PFSpecialCharBegin, PFSpecialCharEnd];
45 | NSCharacterSet *specialCharacterSet = [NSCharacterSet characterSetWithCharactersInString:forbiddenChars];
46 |
47 | NSString *string = self;
48 | string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
49 | string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
50 | string = [string stringByTrimmingCharactersInSet:specialCharacterSet];
51 |
52 | return string;
53 | }
54 |
55 | #pragma mark -
56 |
57 | - (BOOL)pf_isSpecialKey {
58 | if (self.length < 3) {
59 | return NO;
60 | }
61 |
62 | NSString *firstChar = [self substringToIndex:1];
63 | NSString *lastChar = [self substringFromIndex:self.length - 1];
64 |
65 | return [firstChar isEqualToString:PFSpecialCharBegin] && [lastChar isEqualToString:PFSpecialCharEnd];
66 | }
67 |
68 | - (BOOL)pf_isCombinedKey {
69 | return [[self pf_clearString] componentsSeparatedByString:PFSpecialCharPlus].count > 1;
70 | }
71 |
72 | - (BOOL)pf_hasSuffix {
73 | return [availablePFSuffixes() containsObject:[self pf_suffix]];
74 | }
75 |
76 | - (BOOL)pf_hasLocalizedSuffix {
77 | return [[self pf_suffix] isEqualToString:PFSuffixLocalized];
78 | }
79 |
80 | - (BOOL)pf_hasFormViewSuffix {
81 | return [[self pf_suffix] isEqualToString:PFSuffixFormView];
82 | }
83 |
84 | - (NSString *)pf_cellClassName {
85 | return [[self pf_clearString] componentsSeparatedByString:PFSpecialCharPlus].firstObject;
86 | }
87 |
88 | - (NSString *)pf_cellIdentifier {
89 | return [[self pf_clearString] componentsSeparatedByString:PFSpecialCharPlus].lastObject;
90 | }
91 |
92 | - (NSString *)pf_suffixFreeString {
93 | if (![self pf_hasSuffix]) {
94 | return self;
95 | }
96 |
97 | return [[self pf_clearString] substringToIndex:self.length - 1];
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/PureForm/Categories/PFInputView+Validation.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFInputView+Validation.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFInputView.h"
25 | #import "PFValidator.h"
26 | #import "PFModel.h"
27 |
28 | @interface PFInputView (Validation)
29 |
30 | /**
31 | @param value The value for validation.
32 | @param number The array of PFModel objects from the section.
33 | @param index The index of the first param.
34 | @param force Use `YES` for a quick validation. Only validators with `!` will be used.
35 | @return The failed validation PFValidator object.
36 | */
37 | - (PFValidator *)failedValidatorWithValue:(id)value sectionModels:(NSArray *)models modelIndex:(NSUInteger)index force:(BOOL)force;
38 |
39 | /**
40 | @param comparable The full `float` or `double`, wrapped into NSNumber value which will be corrected.
41 | @param number The `float` or `double` wrapped into NSNumber value without odd numbers.
42 | @return The double value without odd numbers.
43 | */
44 | + (double)doubleWithComparableNumber:(NSNumber *)comparable number:(NSNumber *)number;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/PureForm/Categories/PFInputView+Validation.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFInputView+Validation.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFInputView+Validation.h"
25 | #import "PFConstants.h"
26 |
27 | @implementation PFInputView (Validation)
28 |
29 | - (PFValidator *)failedValidatorWithValue:(id)value sectionModels:(NSArray *)models modelIndex:(NSUInteger)index force:(BOOL)force {
30 | for (PFValidator *validator in self.validators) {
31 | if (force && !validator.isForceValidation) {
32 | continue;
33 | }
34 |
35 | switch (validator.type) {
36 | case PFValidatorTypeEqual: {
37 | if (![value isEqual:validator.value]) {
38 | return validator;
39 | }
40 |
41 | break;
42 | }
43 | case PFValidatorTypeEqualNext: {
44 | if (index >= models.count - 1) {
45 | break;
46 | }
47 |
48 | NSArray *nextInputViews = models[index + 1].inputViews;
49 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isFormView == YES"];
50 | NSArray *results = [nextInputViews filteredArrayUsingPredicate:predicate];
51 |
52 | if (results.count == 0) {
53 | break;
54 | }
55 |
56 | if (![results.firstObject.value isEqual:value]) {
57 | return validator;
58 | }
59 |
60 | break;
61 | }
62 | case PFValidatorTypeEqualPrevious: {
63 | if (index == 0) {
64 | break;
65 | }
66 |
67 | NSArray *nextInputViews = models[index - 1].inputViews;
68 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isFormView == YES"];
69 | NSArray *results = [nextInputViews filteredArrayUsingPredicate:predicate];
70 |
71 | if (results.count == 0) {
72 | break;
73 | }
74 |
75 | if (![results.firstObject.value isEqual:value]) {
76 | return validator;
77 | }
78 |
79 | break;
80 | }
81 | case PFValidatorTypeEqualLength: {
82 | if (!value && [validator.value integerValue] > 0) {
83 | return validator;
84 | }
85 |
86 | if ([value isKindOfClass:[NSString class]]) {
87 | NSString *string = value;
88 | if (string.length != [validator.value integerValue]) {
89 | return validator;
90 | }
91 | }
92 |
93 | break;
94 | }
95 | case PFValidatorTypeMinLength: {
96 | if (!value && [validator.value integerValue] > 0) {
97 | return validator;
98 | }
99 |
100 | if ([value isKindOfClass:[NSString class]]) {
101 | NSString *string = value;
102 | if (string.length < [validator.value integerValue]) {
103 | return validator;
104 | }
105 | }
106 |
107 | break;
108 | }
109 | case PFValidatorTypeMaxLength: {
110 | if ([value isKindOfClass:[NSString class]]) {
111 | NSString *string = value;
112 | if (string.length > [validator.value integerValue]) {
113 | return validator;
114 | }
115 | }
116 |
117 | break;
118 | }
119 | case PFValidatorTypeMinValue: {
120 | if ([value isKindOfClass:[NSNumber class]]) {
121 | if ([PFInputView doubleWithComparableNumber:value number:validator.value] < [validator.value doubleValue]) {
122 | return validator;
123 | }
124 | }
125 |
126 | break;
127 | }
128 | case PFValidatorTypeMaxValue: {
129 | if ([value isKindOfClass:[NSNumber class]]) {
130 | if ([PFInputView doubleWithComparableNumber:value number:validator.value] > [validator.value doubleValue]) {
131 | return validator;
132 | }
133 | }
134 |
135 | break;
136 | }
137 | case PFValidatorTypeRequired: {
138 | if (!value) {
139 | return validator;
140 | }
141 |
142 | if ([value isKindOfClass:[NSString class]]) {
143 | NSString *string = value;
144 | if ([string isEqualToString:@""]) {
145 | return validator;
146 | }
147 | }
148 |
149 | break;
150 | }
151 | case PFValidatorTypeFormType:
152 | case PFValidatorTypeCustom: {
153 | if (![value isKindOfClass:[NSString class]] || ![validator.value isKindOfClass:[NSString class]]) {
154 | return validator;
155 | }
156 |
157 | NSString *regexString;
158 | if ([validator.value isEqualToString:PFValidationTypeEmailKey]) {
159 | regexString = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
160 | } else if ([validator.value isEqualToString:PFValidationTypeNameKey]) {
161 | regexString = @"^[a-z]([-']?[a-z]+)*( [a-z]([-']?[a-z]+)*)+$";
162 | } else {
163 | regexString = validator.value;
164 | }
165 |
166 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexString];
167 | if (![predicate evaluateWithObject:value]) {
168 | return validator;
169 | }
170 |
171 | break;
172 | }
173 | case PFValidatorTypeUnknown: {
174 | break;
175 | }
176 | }
177 | }
178 |
179 | return nil;
180 | }
181 |
182 | + (double)doubleWithComparableNumber:(NSNumber *)comparable number:(NSNumber *)number {
183 | NSString *fraction = [[NSString stringWithFormat:@"%@", number]
184 | componentsSeparatedByCharactersInSet:[NSCharacterSet punctuationCharacterSet]].lastObject;
185 | NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
186 | [formatter setRoundingMode:NSNumberFormatterRoundHalfUp];
187 | [formatter setMaximumFractionDigits:fraction.length];
188 |
189 | return [[formatter stringFromNumber:comparable] doubleValue];
190 | }
191 |
192 | @end
193 |
--------------------------------------------------------------------------------
/PureForm/Categories/PFValidator+FailureReason.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFValidator+FailureReason.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFValidator.h"
25 |
26 | @interface PFValidator (FailureReason)
27 |
28 | /**
29 | @param failureReasons The user dictionary of custom validation failure reasons.
30 | @return The failure reason string for current validator.
31 | */
32 | - (NSString *)failureReasonWithUserReasons:(NSDictionary *)failureReasons;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/PureForm/Categories/PFValidator+FailureReason.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFValidator+FailureReason.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFValidator+FailureReason.h"
25 | #import "PFSettings.h"
26 |
27 | @implementation PFValidator (FailureReason)
28 |
29 | - (NSString *)failureReasonWithUserReasons:(NSDictionary *)failureReasons {
30 | static NSDictionary *defaultReasons = nil;
31 | static NSArray *defaultReasonsArray = nil;
32 | static dispatch_once_t onceToken;
33 | dispatch_once(&onceToken, ^{
34 | defaultReasons = @{
35 | PFValidationEqualFailureKey : @"Value doesn't match expected one (%@)",
36 | PFValidationEqualNextFailureKey : @"Value doesn't match next one",
37 | PFValidationEqualPreviousFailureKey : @"Value doesn't match previous one",
38 | PFValidationEqualLengthFailureKey : @"Value length doesn't match expected one (%@)",
39 | PFValidationMinLengthFailureKey : @"String length is too short, than expected (%@)",
40 | PFValidationMaxLengthFailureKey : @"String length is too long, than expected (%@)",
41 | PFValidationMinValueFailureKey : @"Value is too small, than expected (%@)",
42 | PFValidationMaxValueFailureKey : @"Value is too big, than expected (%@)",
43 | PFValidationRequiredFailureKey : @"Value is required",
44 | PFValidationTypeFailureKey : @"Value doesn't match %@ format",
45 | PFValidationCustomFailureKey : @"Check value you entered",
46 | PFValidationUnknownFailureKey : @""
47 | };
48 |
49 | defaultReasonsArray = @[
50 | PFValidationEqualFailureKey,
51 | PFValidationEqualNextFailureKey,
52 | PFValidationEqualPreviousFailureKey,
53 | PFValidationEqualLengthFailureKey,
54 | PFValidationMinLengthFailureKey,
55 | PFValidationMaxLengthFailureKey,
56 | PFValidationMinValueFailureKey,
57 | PFValidationMaxValueFailureKey,
58 | PFValidationRequiredFailureKey,
59 | PFValidationTypeFailureKey,
60 | PFValidationCustomFailureKey,
61 | PFValidationUnknownFailureKey
62 | ];
63 | });
64 |
65 | NSString *value = [self.value isKindOfClass:[NSNumber class]] ? [self.value stringValue] : self.value;
66 | NSString *key = defaultReasonsArray[self.type];
67 | NSString *reason = [failureReasons.allKeys containsObject:key] ? failureReasons[key] : defaultReasons[key];
68 | reason = [reason stringByReplacingOccurrencesOfString:@"%@" withString:value];
69 |
70 | return reason;
71 | }
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/PureForm/Categories/UIColor+PureForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+PureForm.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | @interface UIColor (PureForm)
27 |
28 | /**
29 | @param The hex code string;
30 | @return The color object from hex.
31 | */
32 | + (UIColor *)pf_colorWithHexString:(NSString *)hexString;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/PureForm/Categories/UIColor+PureForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+PureForm.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 23.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "UIColor+PureForm.h"
10 | #import "PFConstants.h"
11 |
12 | @implementation UIColor (PureForm)
13 |
14 | + (UIColor *)pf_colorWithHexString:(NSString *)hexString {
15 | unsigned rgbValue = 0;
16 |
17 | NSScanner *scanner = [NSScanner scannerWithString:hexString];
18 | [scanner setScanLocation:[hexString containsString:PFSpecialCharHex] ? 1 : 0];
19 | [scanner scanHexInt:&rgbValue];
20 |
21 | return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.f
22 | green:((rgbValue & 0xFF00) >> 8) / 255.f
23 | blue:(rgbValue & 0xFF) / 255.f
24 | alpha:1.0];
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/PureForm/Categories/UISlider+PureForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // UISlider+PureForm.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | @interface UISlider (PureForm)
27 |
28 | /**
29 | The UIStepper-like step value.
30 | */
31 | @property(assign, nonatomic) CGFloat pf_stepValue;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/PureForm/Categories/UISlider+PureForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // UISlider+PureForm.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "UISlider+PureForm.h"
25 | #import
26 |
27 | static void *kStepValueRuntimePropertyKey = &kStepValueRuntimePropertyKey;
28 |
29 | @implementation UISlider (PureForm)
30 |
31 | - (CGFloat)pf_stepValue {
32 | return [objc_getAssociatedObject(self, kStepValueRuntimePropertyKey) floatValue];
33 | }
34 |
35 | - (void)setPf_stepValue:(CGFloat)pf_stepValue {
36 | objc_setAssociatedObject(self, kStepValueRuntimePropertyKey, @(pf_stepValue), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/PureForm/Categories/UITableViewCell+PureForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITableViewCell+PureForm.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | @interface UITableViewCell (PureForm)
27 |
28 | /**
29 | @param value The value which will be set.
30 | @param inputView The cell property name.
31 | */
32 | - (void)setValue:(id)value forPropertyName:(id)inputView;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/PureForm/Categories/UITableViewCell+PureForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITableViewCell+PureForm.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "UITableViewCell+PureForm.h"
25 | #import
26 | #import "PFEnums.h"
27 | #import "PFConstants.h"
28 | #import "PFProtocols.h"
29 | #import "UIView+PureForm.h"
30 | #import "PFInputView+Validation.h"
31 | #import "UISlider+PureForm.h"
32 | #import "UIColor+PureForm.h"
33 |
34 | @implementation UITableViewCell (PureForm)
35 |
36 | - (void)setValue:(id)value forPropertyName:(id)inputView {
37 | id inputViewObject = [self valueForKey:inputView];
38 |
39 | if ([inputViewObject respondsToSelector:@selector(text)]) {
40 | id dInputViewObject = inputViewObject;
41 | dInputViewObject.text = value;
42 | }
43 |
44 | if ([inputViewObject isKindOfClass:[UISegmentedControl class]]) {
45 | UISegmentedControl *segmentedControl = inputViewObject;
46 | segmentedControl.selectedSegmentIndex = [value integerValue];
47 | }
48 |
49 | if ([inputViewObject isKindOfClass:[UISwitch class]]) {
50 | UISwitch *switchControl = inputViewObject;
51 | switchControl.on = [value boolValue];
52 | }
53 |
54 | if ([inputViewObject isKindOfClass:[UIStepper class]]) {
55 | UIStepper *stepperControl = inputViewObject;
56 |
57 | double dValue = [PFInputView doubleWithComparableNumber:value number:@(stepperControl.stepValue)];
58 | stepperControl.value = dValue;
59 | stepperControl.pf_display.text = [NSString stringWithFormat:@"%@", @(dValue)];
60 | }
61 |
62 | if ([inputViewObject isKindOfClass:[UISlider class]]) {
63 | UISlider *sliderControl = inputViewObject;
64 |
65 | sliderControl.value = [value floatValue];
66 | sliderControl.pf_display.text = [value stringValue];
67 | }
68 | }
69 |
70 | - (void)setValue:(id)value forKeyPath:(NSString *)keyPath {
71 | NSString *propertyName = [keyPath componentsSeparatedByString:@"."].firstObject;
72 | NSString *paramName = [keyPath componentsSeparatedByString:@"."].lastObject;
73 | id view = [self valueForKey:propertyName];
74 |
75 | Class propertyClass = [[self valueForKeyPath:propertyName] class];
76 | Class paramClass = [self classOfPropertyNamed:paramName withOwnerClass:propertyClass];
77 |
78 | if (paramClass == [UIImage class]) {
79 | UIImage *image = [UIImage imageNamed:value];
80 | if ([value containsString:PFSpecialCharHex]) {
81 | NSArray *valueComponents = [value componentsSeparatedByString:PFSpecialCharHex];
82 | image = [UIImage imageNamed:valueComponents.firstObject];
83 | image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
84 | [view setTintColor:[UIColor pf_colorWithHexString:valueComponents.lastObject]];
85 | }
86 |
87 | [super setValue:image forKeyPath:keyPath];
88 |
89 | return;
90 | }
91 |
92 | if (paramClass == [UIColor class]) {
93 | [super setValue:[UIColor pf_colorWithHexString:value] forKeyPath:keyPath];
94 |
95 | return;
96 | }
97 |
98 | #pragma mark - UITextInputTraits
99 |
100 | //TODO: I'm not sure that it's a good solution, but it works, hm
101 | if ([view conformsToProtocol:@protocol(UITextInputTraits)]) {
102 | NSDictionary *specialInputTraitsCases = @{
103 | [NSString stringWithFormat:@"%@.autocapitalizationType", propertyName] : ^(UITextField *t, NSInteger v) {
104 | t.autocapitalizationType = (UITextAutocapitalizationType) v;
105 | },
106 | [NSString stringWithFormat:@"%@.autocorrectionType", propertyName] : ^(UITextField *t, NSInteger v) {
107 | t.autocorrectionType = (UITextAutocorrectionType) v;
108 | },
109 | [NSString stringWithFormat:@"%@.spellCheckingType", propertyName] : ^(UITextField *t, NSInteger v) {
110 | t.spellCheckingType = (UITextSpellCheckingType) v;
111 | },
112 | [NSString stringWithFormat:@"%@.keyboardType", propertyName] : ^(UITextField *t, NSInteger v) {
113 | t.keyboardType = (UIKeyboardType) v;
114 | },
115 | [NSString stringWithFormat:@"%@.keyboardAppearance", propertyName] : ^(UITextField *t, NSInteger v) {
116 | t.keyboardAppearance = (UIKeyboardAppearance) v;
117 | },
118 | [NSString stringWithFormat:@"%@.returnKeyType", propertyName] : ^(UITextField *t, NSInteger v) {
119 | t.returnKeyType = (UIReturnKeyType) v;
120 | }};
121 |
122 | NSDictionary *specialBoolCases = @{
123 | [NSString stringWithFormat:@"%@.enablesReturnKeyAutomatically", propertyName] : ^(UITextField *t, BOOL v) {
124 | t.enablesReturnKeyAutomatically = v;
125 | },
126 | [NSString stringWithFormat:@"%@.secureTextEntry", propertyName] : ^(UITextField *t, BOOL v) {
127 | t.secureTextEntry = v;
128 | }};
129 |
130 | if ([specialInputTraitsCases.allKeys containsObject:keyPath]) {
131 | void (^block)(UITextField *f, NSInteger v) = specialInputTraitsCases[keyPath];
132 | block(view, [PFEnums enumFromValue:value]);
133 |
134 | return;
135 | }
136 |
137 | if ([specialBoolCases.allKeys containsObject:keyPath]) {
138 | void (^block)(UITextField *f, BOOL v) = specialBoolCases[keyPath];
139 | block(view, [value boolValue]);
140 |
141 | return;
142 | }
143 | }
144 |
145 | #pragma mark - UISegmentedControl
146 |
147 | if ([view isKindOfClass:[UISegmentedControl class]]) {
148 | NSCharacterSet *notNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
149 | NSUInteger index = (NSUInteger) [[paramName stringByTrimmingCharactersInSet:notNumbers] integerValue];
150 |
151 | UISegmentedControl *segmentedControl = view;
152 |
153 | if ([paramName containsString:PFSegmentedControlSectionTitleKey]) {
154 | [segmentedControl removeSegmentAtIndex:index animated:NO];
155 | [segmentedControl insertSegmentWithTitle:value atIndex:index animated:NO];
156 |
157 | return;
158 | }
159 |
160 | if ([paramName containsString:PFSegmentedControlSectionImageKey]) {
161 | [segmentedControl removeSegmentAtIndex:index animated:NO];
162 | [segmentedControl insertSegmentWithImage:[UIImage imageNamed:value] atIndex:index animated:NO];
163 |
164 | return;
165 | }
166 | }
167 |
168 | if ([view isKindOfClass:[UISwitch class]]) {
169 | UISwitch *switchControl = view;
170 | switchControl.on = [value boolValue];
171 |
172 | return;
173 | }
174 |
175 | if ([view isKindOfClass:[UISlider class]] && [paramName isEqualToString:PFSliderControlStepValueKey]) {
176 | UISlider *sliderControl = view;
177 | sliderControl.pf_stepValue = [value floatValue];
178 |
179 | return;
180 | }
181 |
182 | [super setValue:value forKeyPath:keyPath];
183 | }
184 |
185 | - (Class)classOfPropertyNamed:(NSString *)propertyName withOwnerClass:(Class)ownerClass {
186 | if (ownerClass == NULL) {
187 | return NULL;
188 | }
189 |
190 | Class propertyClass = nil;
191 | objc_property_t property = class_getProperty(ownerClass, [propertyName UTF8String]);
192 |
193 | if (property == NULL) {
194 | return NULL;
195 | }
196 |
197 | NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
198 | NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@","];
199 |
200 | if (splitPropertyAttributes.count > 0) {
201 | NSString *encodeType = splitPropertyAttributes[0];
202 | NSArray *splitEncodeType = [encodeType componentsSeparatedByString:@"\""];
203 | NSString *className = splitEncodeType.count > 1 ? splitEncodeType[1] : nil;
204 | propertyClass = NSClassFromString(className);
205 | }
206 |
207 | return propertyClass;
208 | }
209 |
210 | @end
211 |
--------------------------------------------------------------------------------
/PureForm/Categories/UIView+PureForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+PureForm.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import "PFProtocols.h"
26 |
27 | @interface UIView (PureForm)
28 |
29 | /**
30 | The section index of the table view section where current view is.
31 | */
32 | @property(assign, nonatomic) NSUInteger pf_section;
33 |
34 | /**
35 | The row index of the table view row where current view is.
36 | */
37 | @property(assign, nonatomic) NSUInteger pf_index;
38 |
39 | /**
40 | The UIView-like tag.
41 | */
42 | @property(assign, nonatomic) NSUInteger pf_tag;
43 |
44 | /**
45 | The object with a `text` property, such as UILabel, UITextView, etc.
46 | */
47 | @property(strong, nonatomic) id pf_display;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/PureForm/Categories/UIView+PureForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+PureForm.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "UIView+PureForm.h"
25 | #import
26 |
27 | static void *kIndexRuntimePropertyKey = &kIndexRuntimePropertyKey;
28 | static void *kSectionRuntimePropertyKey = &kSectionRuntimePropertyKey;
29 | static void *kTagRuntimePropertyKey = &kTagRuntimePropertyKey;
30 | static void *kDisplayRuntimePropertyKey = &kDisplayRuntimePropertyKey;
31 |
32 | @implementation UIView (PureForm)
33 |
34 | - (NSUInteger)pf_section {
35 | return [objc_getAssociatedObject(self, kSectionRuntimePropertyKey) unsignedIntegerValue];
36 | }
37 |
38 | - (void)setPf_section:(NSUInteger)pf_section {
39 | objc_setAssociatedObject(self, kSectionRuntimePropertyKey, @(pf_section), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
40 | }
41 |
42 | - (NSUInteger)pf_index {
43 | return [objc_getAssociatedObject(self, kIndexRuntimePropertyKey) unsignedIntegerValue];
44 | }
45 |
46 | - (void)setPf_index:(NSUInteger)pf_index {
47 | objc_setAssociatedObject(self, kIndexRuntimePropertyKey, @(pf_index), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
48 | }
49 |
50 | - (NSUInteger)pf_tag {
51 | return [objc_getAssociatedObject(self, kTagRuntimePropertyKey) unsignedIntegerValue];
52 | }
53 |
54 | - (void)setPf_tag:(NSUInteger)pf_tag {
55 | objc_setAssociatedObject(self, kTagRuntimePropertyKey, @(pf_tag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
56 | }
57 |
58 | - (id )pf_display {
59 | return objc_getAssociatedObject(self, kDisplayRuntimePropertyKey);
60 | }
61 |
62 | - (void)setPf_display:(id )pf_display {
63 | objc_setAssociatedObject(self, kDisplayRuntimePropertyKey, pf_display, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
64 | }
65 |
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/PureForm/Common/PFConstants.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFConstants.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | #pragma mark - NSNotification
27 |
28 | static NSString *const PFDisplayLabelShouldChangeNotification = @"PFDisplayLabelShouldChangeNotification";
29 |
30 | #pragma mark - JSON Keys
31 |
32 | static NSString *const PFSectionKey = @"";
33 | static NSString *const PFValueKey = @"";
34 | static NSString *const PFKeyKey = @"";
35 | static NSString *const PFValidationKey = @"";
36 | static NSString *const PFDisplayKey = @"";
37 |
38 | static NSString *const PFValidationEqualKey = @"equal";
39 | static NSString *const PFValidationEqualNextKey = @"equal_next";
40 | static NSString *const PFValidationEqualPreviousKey = @"equal_previous";
41 | static NSString *const PFValidationEqualLengthKey = @"equal_length";
42 | static NSString *const PFValidationMinLengthKey = @"min_length";
43 | static NSString *const PFValidationMaxLengthKey = @"max_length";
44 | static NSString *const PFValidationMinValueKey = @"min_value";
45 | static NSString *const PFValidationMaxValueKey = @"max_value";
46 | static NSString *const PFValidationRequiredKey = @"required";
47 | static NSString *const PFValidationTypeKey = @"type";
48 | static NSString *const PFValidationCustomKey = @"custom";
49 |
50 | static NSString *const PFValidationTypeEmailKey = @"email";
51 | static NSString *const PFValidationTypeNameKey = @"full_name";
52 |
53 | #pragma mark - Special Chars
54 |
55 | static NSString *const PFSpecialCharBegin = @"<";
56 | static NSString *const PFSpecialCharEnd = @">";
57 | static NSString *const PFSpecialCharPlus = @"+";
58 | static NSString *const PFSpecialCharSame = @"=";
59 | static NSString *const PFSpecialCharHex = @"#";
60 |
61 | static NSString *const PFSuffixForce = @"!";
62 | static NSString *const PFSuffixFormView = @"?";
63 | static NSString *const PFSuffixLocalized = @"*";
64 |
65 | static NSString *const PFUnknownKey = @"unknown_key";
66 |
67 | #pragma mark - Available Chars
68 |
69 | static NSString *const PFPhonePadCharacters = @"+*#0123456789";
70 | static NSString *const PFNumberPadCharacters = @"0123456789";
71 | static NSString *const PFDecimalPadCharacters = @".,0123456789";
72 |
73 | #pragma mark - Custom Controls
74 |
75 | static NSString *const PFSegmentedControlSectionTitleKey = @"sectionTitle";
76 | static NSString *const PFSegmentedControlSectionImageKey = @"sectionImage";
77 | static NSString *const PFSliderControlStepValueKey = @"stepValue";
78 |
--------------------------------------------------------------------------------
/PureForm/Common/PFEnums.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFEnums.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | typedef NS_ENUM(NSUInteger, PFValidatorType) {
27 | PFValidatorTypeEqual,
28 | PFValidatorTypeEqualNext,
29 | PFValidatorTypeEqualPrevious,
30 | PFValidatorTypeEqualLength,
31 | PFValidatorTypeMinLength,
32 | PFValidatorTypeMaxLength,
33 | PFValidatorTypeMinValue,
34 | PFValidatorTypeMaxValue,
35 | PFValidatorTypeRequired,
36 | PFValidatorTypeFormType,
37 | PFValidatorTypeCustom,
38 | PFValidatorTypeUnknown
39 | };
40 |
41 | @interface PFEnums : NSObject
42 |
43 | /**
44 | @param string The string enum value.
45 | @return The enum value.
46 | */
47 | + (NSInteger)enumFromValue:(id)value;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/PureForm/Common/PFEnums.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFEnums.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFEnums.h"
25 |
26 | #import "NSString+PureForm.h"
27 | #import "PFConstants.h"
28 |
29 | @implementation PFEnums
30 |
31 | + (NSInteger)enumFromValue:(id)value {
32 | if ([value isKindOfClass:[NSNumber class]]) {
33 | return [value integerValue];
34 | }
35 |
36 | value = [value pf_suffixFreeString];
37 |
38 | NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"ANY SELF == %@", value];
39 | NSArray *results = [[self enumValues] filteredArrayUsingPredicate:searchPredicate];
40 |
41 | if (results.count > 0) {
42 | return (NSInteger) [results.firstObject indexOfObject:value];
43 | }
44 |
45 | return 0;
46 | }
47 |
48 | + (NSArray *)enumValues {
49 | static NSArray *enumValues = nil;
50 | static dispatch_once_t onceToken;
51 | dispatch_once(&onceToken, ^{
52 |
53 | #pragma mark - PureForm
54 |
55 | NSArray *PFValidationArray = @[
56 | PFValidationEqualKey,
57 | PFValidationEqualNextKey,
58 | PFValidationEqualPreviousKey,
59 | PFValidationEqualLengthKey,
60 | PFValidationMinLengthKey,
61 | PFValidationMaxLengthKey,
62 | PFValidationMinValueKey,
63 | PFValidationMaxValueKey,
64 | PFValidationRequiredKey,
65 | PFValidationTypeKey,
66 | PFValidationCustomKey,
67 | ];
68 |
69 | #pragma mark - UITextInputTraits
70 |
71 | NSArray *UITextAutocapitalizationTypeArray = @[
72 | @"UITextAutocapitalizationTypeNone",
73 | @"UITextAutocapitalizationTypeWords",
74 | @"UITextAutocapitalizationTypeSentences",
75 | @"UITextAutocapitalizationTypeAllCharacters"
76 | ];
77 |
78 | NSArray *UITextAutocorrectionTypeArray = @[
79 | @"UITextAutocorrectionTypeDefault",
80 | @"UITextAutocorrectionTypeNo",
81 | @"UITextAutocorrectionTypeYes"
82 | ];
83 |
84 | NSArray *UITextSpellCheckingTypeArray = @[
85 | @"UITextSpellCheckingTypeDefault",
86 | @"UITextSpellCheckingTypeNo",
87 | @"UITextSpellCheckingTypeYes"
88 | ];
89 |
90 | NSArray *UIKeyboardTypeArray = @[
91 | @"UIKeyboardTypeDefault",
92 | @"UIKeyboardTypeASCIICapable",
93 | @"UIKeyboardTypeNumbersAndPunctuation",
94 | @"UIKeyboardTypeURL",
95 | @"UIKeyboardTypeNumberPad",
96 | @"UIKeyboardTypePhonePad",
97 | @"UIKeyboardTypeNamePhonePad",
98 | @"UIKeyboardTypeEmailAddress",
99 | @"UIKeyboardTypeDecimalPad",
100 | @"UIKeyboardTypeTwitter",
101 | @"UIKeyboardTypeWebSearch",
102 | @"UIKeyboardTypeAlphabet"
103 | ];
104 |
105 | NSArray *UIKeyboardAppearanceArray = @[
106 | @"UIKeyboardAppearanceDefault",
107 | @"UIKeyboardAppearanceDark",
108 | @"UIKeyboardAppearanceLight",
109 | @"UIKeyboardAppearanceAlert"
110 | ];
111 |
112 | NSArray *UIReturnKeyTypeArray = @[
113 | @"UIReturnKeyDefault",
114 | @"UIReturnKeyGo",
115 | @"UIReturnKeyGoogle",
116 | @"UIReturnKeyJoin",
117 | @"UIReturnKeyNext",
118 | @"UIReturnKeyRoute",
119 | @"UIReturnKeySearch",
120 | @"UIReturnKeySend",
121 | @"UIReturnKeyYahoo",
122 | @"UIReturnKeyDone",
123 | @"UIReturnKeyEmergencyCall",
124 | @"UIReturnKeyContinue"
125 | ];
126 |
127 | #pragma mark - UITextField
128 |
129 | NSArray *UITextFieldViewModeArray = @[
130 | @"UITextFieldViewModeNever",
131 | @"UITextFieldViewModeWhileEditing",
132 | @"UITextFieldViewModeUnlessEditing",
133 | @"UITextFieldViewModeAlways"
134 | ];
135 |
136 | #pragma mark - Output
137 |
138 | enumValues = @[
139 | PFValidationArray,
140 | UITextAutocapitalizationTypeArray,
141 | UITextAutocorrectionTypeArray,
142 | UITextSpellCheckingTypeArray,
143 | UIKeyboardTypeArray,
144 | UIKeyboardAppearanceArray,
145 | UIReturnKeyTypeArray,
146 | UITextFieldViewModeArray
147 | ];
148 |
149 | });
150 |
151 | return enumValues;
152 | }
153 |
154 | @end
155 |
--------------------------------------------------------------------------------
/PureForm/Common/PFMacros.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFMacros.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #ifndef PFMacros_h
25 | #define PFMacros_h
26 |
27 | #ifdef DEBUG
28 | # define PFLog(format, ...) NSLog((@"PureForm: " format @", occurred in: %s [Line %d]"), ##__VA_ARGS__, __PRETTY_FUNCTION__, __LINE__)
29 | #else
30 | # define PFLog(...)
31 | #endif
32 |
33 | #endif /* PFMacros_h */
34 |
--------------------------------------------------------------------------------
/PureForm/Common/PFProtocols.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFProtocols.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | @protocol PFDelegate
27 |
28 | @required
29 | @property(weak, nonatomic) id delegate;
30 |
31 | @end
32 |
33 | @protocol PFText
34 |
35 | @required
36 | @property(copy, nonatomic) NSString *text;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/PureForm/Delegates/PFFormDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFFormDelegate.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import "PFModel.h"
26 | #import "PFError.h"
27 |
28 | @protocol PFFormDelegate
29 |
30 | @optional
31 | /**
32 | Called when a value was successfully updated.
33 | */
34 | - (void)valueDidUpdate;
35 |
36 | /**
37 | Called when a value was successfully updated.
38 | @param inputView The updated PFInputView object.
39 | */
40 | - (void)valueDidUpdateWithInputView:(PFInputView *)inputView;
41 |
42 | /**
43 | Called when a value was updated with a validation error.
44 | @param error The validation error.
45 | */
46 | - (void)valueDidUpdateWithError:(PFError *)error;
47 |
48 | /**
49 | Called when values successfully passed a validation.
50 | */
51 | - (void)validationDidEndSuccessfully;
52 |
53 | /**
54 | Called when values failed a validation.
55 | @param errors The array of validation errors.
56 | */
57 | - (void)validationDidFailWithErrors:(NSArray *)errors;
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/PureForm/Delegates/PFInputViewDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFInputViewDelegate.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 |
27 | @class PFModel;
28 | @class PFSettings;
29 |
30 | @interface PFInputViewDelegate : NSObject
31 |
32 | /**
33 | @return The instance of PFInputViewDelegate.
34 | */
35 | - (instancetype)initWithModels:(NSMutableArray *> *)models tableView:(UITableView *)tableView settings:(PFSettings *)settings;
36 |
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/PureForm/Delegates/PFInputViewDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFInputViewDelegate.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFInputViewDelegate.h"
25 |
26 | #import
27 | #import "PFModel.h"
28 | #import "UIView+PureForm.h"
29 | #import "PFSettings.h"
30 | #import "PFInputView+Validation.h"
31 | #import "PFValidator+FailureReason.h"
32 | #import "PFConstants.h"
33 | #import "UISlider+PureForm.h"
34 |
35 | #define PFFormDelegate self.settings.formDelegate
36 | #define PFTextFieldDelegate self.settings.textFieldDelegate
37 | #define PFSegmentedControlDelegate self.settings.segmentedControlDelegate
38 | #define PFSwitchControlDelegate self.settings.switchControlDelegate
39 | #define PFSliderControlDelegate self.settings.sliderControlDelegate
40 | #define PFStepperControlDelegate self.settings.stepperControlDelegate
41 |
42 | static void *PFCurrentInputViewPropertyKey = &PFCurrentInputViewPropertyKey;
43 | static void *PFOriginalInputViewPropertyKey = &PFOriginalInputViewPropertyKey;
44 |
45 | @interface PFInputViewDelegate ()
46 |
47 | @property(weak, nonatomic) PFSettings *settings;
48 | @property(weak, nonatomic) NSMutableArray *> *models;
49 |
50 | @property(strong, nonatomic) PFInputView *currentInputView;
51 | @property(strong, nonatomic) id originalValue;
52 | @property(strong, nonatomic) UITableView *tableView;
53 | @property(strong, nonatomic) NSValue *showedKeyboardFrame;
54 |
55 | @end
56 |
57 | @implementation PFInputViewDelegate
58 |
59 | - (PFInputView *)currentInputView {
60 | return objc_getAssociatedObject(self, PFCurrentInputViewPropertyKey);
61 | }
62 |
63 | - (void)setCurrentInputView:(PFInputView *)currentInputView {
64 | objc_setAssociatedObject(self, PFCurrentInputViewPropertyKey, currentInputView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
65 | }
66 |
67 | - (id)originalValue {
68 | return objc_getAssociatedObject(self, PFOriginalInputViewPropertyKey);
69 | }
70 |
71 | - (void)setOriginalValue:(id)originalValue {
72 | objc_setAssociatedObject(self, PFOriginalInputViewPropertyKey, originalValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
73 | }
74 |
75 | - (instancetype)initWithModels:(NSMutableArray *> *)models tableView:(UITableView *)tableView settings:(PFSettings *)settings {
76 | self = [super init];
77 |
78 | if (self) {
79 | _tableView = tableView;
80 | _settings = settings;
81 | _models = models;
82 |
83 | if (settings.isKeyboardAvoiding) {
84 | [[NSNotificationCenter defaultCenter] addObserver:self
85 | selector:@selector(keyboardWillShow:)
86 | name:UIKeyboardWillShowNotification
87 | object:nil];
88 | [[NSNotificationCenter defaultCenter] addObserver:self
89 | selector:@selector(keyboardWillHide:)
90 | name:UIKeyboardWillHideNotification
91 | object:nil];
92 | }
93 | }
94 |
95 | return self;
96 | }
97 |
98 | - (void)dealloc {
99 | [[NSNotificationCenter defaultCenter] removeObserver:self];
100 | }
101 |
102 | - (void)searchAndAssignCurrentInputViewByView:(UIView *)view {
103 | self.currentInputView = nil;
104 |
105 | for (NSArray *array in self.models) {
106 | NSPredicate *modelPredicate = [NSPredicate predicateWithFormat:@"ANY inputViews.view == %@", view];
107 | NSArray *results = [array filteredArrayUsingPredicate:modelPredicate];
108 |
109 | if (results.count > 0) {
110 | PFModel *model = results.firstObject;
111 | NSPredicate *inputViewPredicate = [NSPredicate predicateWithFormat:@"view == %@", view];
112 |
113 | self.currentInputView = [model.inputViews filteredArrayUsingPredicate:inputViewPredicate].firstObject;
114 | self.originalValue = self.currentInputView.value;
115 | }
116 | }
117 | }
118 |
119 | #pragma mark - PFSegmentedControlDelegate, PFSwitchControlDelegate, PFSliderControlDelegate, PFStepperControlDelegate
120 |
121 | - (void)sliderControlDidEndEditing:(id)controlView {
122 | UISlider *sliderControl = controlView;
123 | [self makeValidationWithSectionModels:nil modelIndex:0];
124 |
125 | if (PFSliderControlDelegate &&
126 | [PFSliderControlDelegate respondsToSelector:@selector(sliderControl:didChangeValue:)]) {
127 | [PFSliderControlDelegate sliderControl:sliderControl didChangeValue:sliderControl.value];
128 | }
129 | }
130 |
131 | - (void)controlViewDidChangeValue:(id)controlView {
132 | [self searchAndAssignCurrentInputViewByView:controlView];
133 |
134 | if ([controlView isKindOfClass:[UISegmentedControl class]]) {
135 | UISegmentedControl *segmentedControl = controlView;
136 | self.currentInputView.value = @(segmentedControl.selectedSegmentIndex);
137 | [self makeValidationWithSectionModels:nil modelIndex:0];
138 |
139 | if (PFSegmentedControlDelegate &&
140 | [PFSegmentedControlDelegate respondsToSelector:@selector(segmentedControl:didSelectItemAtIndex:)]) {
141 | [PFSegmentedControlDelegate segmentedControl:segmentedControl
142 | didSelectItemAtIndex:segmentedControl.selectedSegmentIndex];
143 | }
144 | }
145 |
146 | if ([controlView isKindOfClass:[UISwitch class]]) {
147 | UISwitch *switchControl = controlView;
148 | self.currentInputView.value = @(switchControl.isOn);
149 | [self makeValidationWithSectionModels:nil modelIndex:0];
150 |
151 | if (PFSwitchControlDelegate &&
152 | [PFSwitchControlDelegate respondsToSelector:@selector(switchControl:didChangeState:)]) {
153 | [PFSwitchControlDelegate switchControl:switchControl didChangeState:switchControl.isOn];
154 | }
155 | }
156 |
157 | if ([controlView isKindOfClass:[UIStepper class]]) {
158 | UIStepper *stepperControl = controlView;
159 | self.currentInputView.value = @(stepperControl.value);
160 | [self makeValidationWithSectionModels:nil modelIndex:0];
161 |
162 | [[NSNotificationCenter defaultCenter] postNotificationName:PFDisplayLabelShouldChangeNotification
163 | object:self.currentInputView];
164 |
165 | if (PFStepperControlDelegate &&
166 | [PFStepperControlDelegate respondsToSelector:@selector(stepperControl:didChangeValue:)]) {
167 | [PFStepperControlDelegate stepperControl:stepperControl didChangeValue:(CGFloat) stepperControl.value];
168 | }
169 | }
170 |
171 | if ([controlView isKindOfClass:[UISlider class]]) {
172 | UISlider *sliderControl = controlView;
173 | CGFloat step = sliderControl.pf_stepValue;
174 | self.currentInputView.value = @(round(sliderControl.value / step) * step);
175 |
176 | [[NSNotificationCenter defaultCenter] postNotificationName:PFDisplayLabelShouldChangeNotification
177 | object:self.currentInputView];
178 | }
179 | }
180 |
181 | #pragma mark - PFFormDelegate Methods Calls
182 |
183 | - (void)callValueDidUpdate {
184 | BOOL isDifferent = ![self.currentInputView.value isEqual:self.originalValue];
185 | if (!self.currentInputView.value && !self.originalValue) {
186 | isDifferent = NO;
187 | }
188 |
189 | if ([self.currentInputView.view isKindOfClass:[UISlider class]]) {
190 | isDifferent = YES;
191 | }
192 |
193 | if (PFFormDelegate && [PFFormDelegate respondsToSelector:@selector(valueDidUpdate)] && isDifferent) {
194 | [PFFormDelegate valueDidUpdate];
195 | }
196 |
197 | if (PFFormDelegate && [PFFormDelegate respondsToSelector:@selector(valueDidUpdateWithInputView:)] && isDifferent) {
198 | [PFFormDelegate valueDidUpdateWithInputView:self.currentInputView];
199 | }
200 | }
201 |
202 | - (void)callValueUpdateDidFailWithFailedValidator:(PFValidator *)validator {
203 | if (!PFFormDelegate) {
204 | return;
205 | }
206 |
207 | NSString *reason = [validator failureReasonWithUserReasons:self.settings.failureReasons];
208 |
209 | if ([PFFormDelegate respondsToSelector:@selector(valueDidUpdateWithError:)]) {
210 | PFError *error = [[PFError alloc] initWithView:self.currentInputView.view validator:validator reason:reason];
211 | [PFFormDelegate valueDidUpdateWithError:error];
212 | }
213 | }
214 |
215 | #pragma mark - Validation
216 |
217 | - (void)makeValidationWithSectionModels:(NSArray *)models modelIndex:(NSUInteger)index {
218 | PFValidator *failedValidator = [self.currentInputView failedValidatorWithValue:self.currentInputView.value
219 | sectionModels:models
220 | modelIndex:index
221 | force:YES];
222 | if (failedValidator) {
223 | [self callValueUpdateDidFailWithFailedValidator:failedValidator];
224 | return;
225 | } else {
226 | [self callValueDidUpdate];
227 | }
228 | }
229 |
230 | #pragma mark - UITextFieldDelegate
231 |
232 | - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
233 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textFieldShouldBeginEditing:)]) {
234 | return [PFTextFieldDelegate textFieldShouldBeginEditing:textField];
235 | }
236 |
237 | return YES;
238 | }
239 |
240 | - (void)textFieldDidBeginEditing:(UITextField *)textField {
241 | [self searchAndAssignCurrentInputViewByView:textField];
242 |
243 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
244 | [PFTextFieldDelegate textFieldDidBeginEditing:textField];
245 | }
246 | }
247 |
248 | - (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
249 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
250 | return [PFTextFieldDelegate textFieldShouldEndEditing:textField];
251 | }
252 |
253 | return YES;
254 | }
255 |
256 | - (void)textFieldDidEndEditing:(UITextField *)textField {
257 | [textField resignFirstResponder];
258 |
259 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textFieldDidEndEditing:)]) {
260 | [PFTextFieldDelegate textFieldDidEndEditing:textField];
261 | }
262 |
263 | self.currentInputView.value = [textField.text isEqualToString:@""] ? nil : textField.text;
264 |
265 | NSArray *models;
266 | NSUInteger index = 0;
267 | for (NSArray *array in self.models) {
268 | NSPredicate *modelPredicate = [NSPredicate predicateWithFormat:@"ANY inputViews == %@", self.currentInputView];
269 | NSArray *results = [array filteredArrayUsingPredicate:modelPredicate];
270 | if (results.count > 0) {
271 | models = array;
272 | index = [array indexOfObject:results.firstObject];
273 | }
274 | }
275 |
276 | [self makeValidationWithSectionModels:models modelIndex:index];
277 | }
278 |
279 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
280 | NSString *fullString = [textField.text stringByReplacingCharactersInRange:range withString:string];
281 | NSString *characterSetString;
282 |
283 | switch (textField.keyboardType) {
284 | case UIKeyboardTypePhonePad: {
285 | characterSetString = PFPhonePadCharacters;
286 | break;
287 | }
288 | case UIKeyboardTypeNumberPad: {
289 | characterSetString = PFNumberPadCharacters;
290 | break;
291 | }
292 | case UIKeyboardTypeDecimalPad: {
293 | characterSetString = PFDecimalPadCharacters;
294 | break;
295 | }
296 | default:
297 | break;
298 | }
299 |
300 | if (fullString.length > 0 && characterSetString && self.settings.isKeyboardTypeValidation) {
301 | NSCharacterSet *numberPadCharacters = [NSCharacterSet characterSetWithCharactersInString:characterSetString];
302 | if ([fullString rangeOfCharacterFromSet:[numberPadCharacters invertedSet]].location != NSNotFound) {
303 | string = nil;
304 | }
305 | }
306 |
307 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
308 | return [PFTextFieldDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
309 | }
310 |
311 | return string != nil;
312 | }
313 |
314 | - (BOOL)textFieldShouldClear:(UITextField *)textField {
315 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textFieldShouldClear:)]) {
316 | return [PFTextFieldDelegate textFieldShouldClear:textField];
317 | }
318 |
319 | return YES;
320 | }
321 |
322 | - (BOOL)textFieldShouldReturn:(UITextField *)textField {
323 | [textField resignFirstResponder];
324 |
325 | if (PFTextFieldDelegate && [PFTextFieldDelegate respondsToSelector:@selector(textFieldShouldReturn:)]) {
326 | return [PFTextFieldDelegate textFieldShouldReturn:textField];
327 | }
328 |
329 | return YES;
330 | }
331 |
332 | #pragma mark - Keyboard Avoiding
333 |
334 | - (void)keyboardWillHide:(NSNotification *)notification {
335 |
336 | CGRect viewFrame = self.tableView.frame;
337 | viewFrame.size.height += self.showedKeyboardFrame.CGRectValue.size.height;
338 |
339 | [UIView beginAnimations:nil context:NULL];
340 | [UIView setAnimationBeginsFromCurrentState:YES];
341 | [self.tableView setFrame:viewFrame];
342 | [UIView commitAnimations];
343 |
344 | self.showedKeyboardFrame = nil;
345 | }
346 |
347 | - (void)keyboardWillShow:(NSNotification *)notification {
348 | if (self.showedKeyboardFrame) {
349 | return;
350 | }
351 |
352 | CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
353 |
354 | CGRect viewFrame = self.tableView.frame;
355 | viewFrame.size.height -= keyboardFrame.size.height;
356 |
357 | [UIView beginAnimations:nil context:NULL];
358 | [UIView setAnimationBeginsFromCurrentState:YES];
359 | [self.tableView setFrame:viewFrame];
360 | [UIView commitAnimations];
361 |
362 | self.showedKeyboardFrame = [NSValue valueWithCGRect:keyboardFrame];
363 | }
364 |
365 | @end
366 |
--------------------------------------------------------------------------------
/PureForm/Delegates/PFViewDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFViewDelegate.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 |
27 | @protocol PFSegmentedControlDelegate
28 |
29 | @optional
30 | /**
31 | Called when a UISegmentedControl value was changed.
32 | @param segmentedControl The UISegmentedControl object.
33 | @param index The index of the selected item.
34 | */
35 | - (void)segmentedControl:(UISegmentedControl *)segmentedControl didSelectItemAtIndex:(NSInteger)index;
36 |
37 | @end
38 |
39 | @protocol PFSwitchControlDelegate
40 |
41 | @optional
42 | /**
43 | Called when a UISwitch value was changed.
44 | @param switchControl The UISwitch object.
45 | @param state The state of UISwitch object.
46 | */
47 | - (void)switchControl:(UISwitch *)switchControl didChangeState:(BOOL)state;
48 |
49 | @end
50 |
51 | @protocol PFSliderControlDelegate
52 |
53 | @optional
54 | /**
55 | Called when the user interaction with a UISlider object was ended.
56 | @param sliderControl The UISlider object.
57 | @param value The value of UISlider object.
58 | */
59 | - (void)sliderControl:(UISlider *)sliderControl didChangeValue:(CGFloat)value;
60 |
61 | @end
62 |
63 | @protocol PFStepperControlDelegate
64 |
65 | @optional
66 | /**
67 | Called when a UIStepper value was changed.
68 | @param stepperControl The UIStepper object.
69 | @param value The value of UIStepper object.
70 | */
71 | - (void)stepperControl:(UIStepper *)stepperControl didChangeValue:(CGFloat)value;
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/PureForm/Models/PFError.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFError.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 |
27 | @class PFInputView;
28 | @class PFValidator;
29 |
30 | @interface PFError : NSObject
31 |
32 | /**
33 | The error-associated UIView object.
34 | */
35 | @property(strong, nonatomic) UIView *view;
36 |
37 | /**
38 | The error-associated validator.
39 | */
40 | @property(assign, nonatomic) PFValidator *validator;
41 |
42 | /**
43 | The error reason.
44 | */
45 | @property(strong, nonatomic) NSString *reason;
46 |
47 | /**
48 | @return An instance of PFError.
49 | */
50 | - (instancetype)initWithView:(UIView *)view validator:(PFValidator *)validator reason:(NSString *)reason;
51 |
52 | /**
53 | @return The array of error reasons.
54 | @param The array of PFError objects.
55 | */
56 | + (NSArray *)descriptionFromErrors:(NSArray *)errors;
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/PureForm/Models/PFError.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFError.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFError.h"
25 | #import "PFModel.h"
26 | #import "UIView+PureForm.h"
27 |
28 | @implementation PFError
29 |
30 | - (instancetype)initWithView:(UIView *)view validator:(PFValidator *)validator reason:(NSString *)reason {
31 | self = [super init];
32 |
33 | if (self) {
34 | _view = view;
35 | _validator = validator;
36 | _reason = reason;
37 | }
38 |
39 | return self;
40 | }
41 |
42 | - (NSString *)description {
43 | return [NSString stringWithFormat:@"View: (row: %tu, section: %tu, tag: %tu), reason: %@",
44 | self.view.pf_index, self.view.pf_section, self.view.pf_tag, self.reason];
45 | }
46 |
47 | + (NSArray *)descriptionFromErrors:(NSArray *)errors {
48 | NSMutableArray *descriptions = [[NSMutableArray alloc] initWithCapacity:errors.count];
49 |
50 | for (PFError *error in errors) {
51 | [descriptions addObject:error.description];
52 | }
53 |
54 | return [NSArray arrayWithArray:descriptions];
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/PureForm/Models/PFInputView.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFInputView.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 24.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class PFValidator;
13 |
14 | @interface PFInputView : NSObject
15 |
16 | /**
17 | The real input view.
18 | */
19 | @property(strong, nonatomic) UIView *view;
20 |
21 | /**
22 | The current value.
23 | */
24 | @property(strong, nonatomic) id value;
25 |
26 | /**
27 | The key for creating an output dictionary.
28 | */
29 | @property(strong, nonatomic) NSString *key;
30 |
31 | /**
32 | The validators of the input view (`view`).
33 | */
34 | @property(strong, nonatomic) NSArray *validators;
35 |
36 | /**
37 | Indicates whether `view` is a form input view (use `?` to mark as an input view).
38 | */
39 | @property(assign, nonatomic, getter=isFormView) BOOL formView;
40 |
41 | ///---------------
42 | /// @name Specials
43 | ///---------------
44 |
45 | @property(strong, nonatomic) NSString *propertyName;
46 |
47 | @property(strong, nonatomic) NSString *displayPropertyName;
48 |
49 | @property(strong, nonatomic) NSDictionary *params;
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/PureForm/Models/PFInputView.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFInputView.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 24.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "PFInputView.h"
10 |
11 | @implementation PFInputView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/PureForm/Models/PFModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFModel.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 |
27 | @class PFInputView;
28 |
29 | @interface PFModel : NSObject
30 |
31 | /**
32 | The array of input views. It contains form views and simple views as well (ex. UILabel with cell title).
33 | */
34 | @property(strong, nonatomic) NSArray *inputViews;
35 |
36 | /**
37 | Just a custom data. You can associate with this model what you want using this property.
38 | */
39 | @property(strong, nonatomic) id userData;
40 |
41 | ///---------------
42 | /// @name Specials
43 | ///---------------
44 |
45 | @property(strong, nonatomic) NSString *cellClassName;
46 |
47 | @property(strong, nonatomic) NSString *cellIdentifier;
48 |
49 | @property(assign, nonatomic) NSUInteger sectionIndex;
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/PureForm/Models/PFModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFModel.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFModel.h"
25 |
26 | @implementation PFModel
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/PureForm/Models/PFSettings.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFSettings.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 | #import "PFViewDelegate.h"
27 | #import "PFFormDelegate.h"
28 |
29 | NS_ASSUME_NONNULL_BEGIN
30 |
31 | @interface PFSettings : NSObject
32 |
33 | /**
34 | Provides a real-time validation for approved characters by UIKeyboardType.
35 | `NO` by default.
36 | */
37 | @property(assign, nonatomic, getter=isKeyboardTypeValidation) BOOL keyboardTypeValidation;
38 |
39 | /**
40 | Provides an automatic keyboard avoiding.
41 | `NO` by default.
42 | */
43 | @property(assign, nonatomic, getter=isKeyboardAvoiding) BOOL keyboardAvoiding;
44 |
45 | /**
46 | The height for each cell in the table view.
47 | `nil` by default.
48 | */
49 | @property(strong, nonatomic, nullable) NSDictionary *failureReasons;
50 |
51 | /**
52 | The height for each cell in the table view.
53 | `PFCellHeightDefault` by default.
54 | */
55 | @property(assign, nonatomic) CGFloat cellHeight;
56 |
57 | ///----------------
58 | /// @name Delegates
59 | ///----------------
60 |
61 | @property(weak, nonatomic, nullable) id formDelegate;
62 |
63 | @property(weak, nonatomic, nullable) id tableViewDelegate;
64 |
65 | @property(weak, nonatomic, nullable) id textFieldDelegate;
66 |
67 | @property(weak, nonatomic, nullable) id segmentedControlDelegate;
68 |
69 | @property(weak, nonatomic, nullable) id switchControlDelegate;
70 |
71 | @property(weak, nonatomic, nullable) id sliderControlDelegate;
72 |
73 | @property(weak, nonatomic, nullable) id stepperControlDelegate;
74 |
75 | @end
76 |
77 | ///---------------------------
78 | /// @name Cell height contants
79 | ///---------------------------
80 |
81 | /**
82 | Similar to UITableViewAutomaticDimension.
83 | */
84 | FOUNDATION_EXPORT CGFloat const PFCellHeightAutomatic;
85 |
86 | /**
87 | Equals to storyboard params.
88 | */
89 | FOUNDATION_EXPORT CGFloat const PFCellHeightDefault;
90 |
91 | ///-------------------------------------
92 | /// @name Validation failure reason keys
93 | ///-------------------------------------
94 |
95 | /**
96 | When the value doesn't match the expected one.
97 | */
98 | FOUNDATION_EXPORT NSString *const PFValidationEqualFailureKey;
99 |
100 | /**
101 | When the value doesn't match the next one.
102 | */
103 | FOUNDATION_EXPORT NSString *const PFValidationEqualNextFailureKey;
104 |
105 | /**
106 | When the value doesn't match the previous one.
107 | */
108 | FOUNDATION_EXPORT NSString *const PFValidationEqualPreviousFailureKey;
109 |
110 | /**
111 | When the value length doesn't match expected one.
112 | */
113 | FOUNDATION_EXPORT NSString *const PFValidationEqualLengthFailureKey;
114 |
115 | /**
116 | When the value length is too short, than expected.
117 | */
118 | FOUNDATION_EXPORT NSString *const PFValidationMinLengthFailureKey;
119 |
120 | /**
121 | When the value length is too long, than expected.
122 | */
123 | FOUNDATION_EXPORT NSString *const PFValidationMaxLengthFailureKey;
124 |
125 | /**
126 | When the value length is too small, than expected.
127 | */
128 | FOUNDATION_EXPORT NSString *const PFValidationMinValueFailureKey;
129 |
130 | /**
131 | When the value length is too big, than expected.
132 | */
133 | FOUNDATION_EXPORT NSString *const PFValidationMaxValueFailureKey;
134 |
135 | /**
136 | When the value doesn't exist.
137 | */
138 | FOUNDATION_EXPORT NSString *const PFValidationRequiredFailureKey;
139 |
140 | /**
141 | When the value doesn't match special format.
142 | */
143 | FOUNDATION_EXPORT NSString *const PFValidationTypeFailureKey;
144 |
145 | /**
146 | When the value doesn't match regex format.
147 | */
148 | FOUNDATION_EXPORT NSString *const PFValidationCustomFailureKey;
149 |
150 | /**
151 | When uses unknown validator.
152 | */
153 | FOUNDATION_EXPORT NSString *const PFValidationUnknownFailureKey;
154 |
155 | NS_ASSUME_NONNULL_END
156 |
--------------------------------------------------------------------------------
/PureForm/Models/PFSettings.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFSettings.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFSettings.h"
25 |
26 | NSString *const PFValidationEqualFailureKey = @"PFValidationEqualFailure";
27 | NSString *const PFValidationEqualNextFailureKey = @"PFValidationEqualNextFailure";
28 | NSString *const PFValidationEqualPreviousFailureKey = @"PFValidationEqualPreviousFailure";
29 | NSString *const PFValidationEqualLengthFailureKey = @"PFValidationEqualLengthFailure";
30 | NSString *const PFValidationMinLengthFailureKey = @"PFValidationMinLengthFailure";
31 | NSString *const PFValidationMaxLengthFailureKey = @"PFValidationMaxLengthFailure";
32 | NSString *const PFValidationMinValueFailureKey = @"PFValidationMinValueFailure";
33 | NSString *const PFValidationMaxValueFailureKey = @"PFValidationMaxValueFailure";
34 | NSString *const PFValidationRequiredFailureKey = @"PFValidationRequiredFailure";
35 | NSString *const PFValidationTypeFailureKey = @"PFValidationTypeFailure";
36 | NSString *const PFValidationCustomFailureKey = @"PFValidationCustomFailure";
37 | NSString *const PFValidationUnknownFailureKey = @"PFValidationUnknownFailure";
38 |
39 | CGFloat const PFCellHeightAutomatic = -1.f;
40 | CGFloat const PFCellHeightDefault = -2.f;
41 |
42 | @implementation PFSettings
43 |
44 | - (instancetype)init {
45 | self = [super init];
46 |
47 | if (self) {
48 | _cellHeight = PFCellHeightDefault;
49 | }
50 |
51 | return self;
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/PureForm/Models/PFValidator.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFValidator.h
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 24.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "PFEnums.h"
11 |
12 | @interface PFValidator : NSObject
13 |
14 | /**
15 | The validator type.
16 | */
17 | @property(assign, nonatomic) PFValidatorType type;
18 |
19 | /**
20 | It contains validation rule (ex. regex, maximum value, etc).
21 | */
22 | @property(strong, nonatomic) id value;
23 |
24 | ///---------------
25 | /// @name Specials
26 | ///---------------
27 |
28 | @property(assign, nonatomic, getter=isForceValidation) BOOL forceValidation;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/PureForm/Models/PFValidator.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFValidator.m
3 | // Example
4 | //
5 | // Created by Puzyrev Pavel on 24.08.16.
6 | // Copyright © 2016 Puzyrev Pavel. All rights reserved.
7 | //
8 |
9 | #import "PFValidator.h"
10 |
11 | @implementation PFValidator
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/PureForm/PFFormController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFFormController.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 |
27 | @class PFSettings;
28 | @class PFInputView;
29 | @class PFModel;
30 |
31 | NS_ASSUME_NONNULL_BEGIN
32 |
33 | @interface PFFormController : NSObject
34 |
35 | /**
36 | @param tableView The user form table view.
37 | @return An instance of PFFormController.
38 | */
39 | - (instancetype)initWithTableView:(nonnull __kindof UITableView *)tableView settings:(nullable PFSettings *)settings;
40 |
41 | /**
42 | @param fileName The file name with JSON data.
43 | */
44 | - (void)makeFormWithJSONFile:(nullable NSString *)fileName;
45 |
46 | ///----------------------------------
47 | /// @name Validation & getting values
48 | ///----------------------------------
49 |
50 | /**
51 | @return `YES` if validation was successfully passed, otherwise `NO`.
52 | */
53 | - (BOOL)validate;
54 |
55 | /**
56 | @return The array of all form values at the moment.
57 | */
58 | - (NSArray *)allValues;
59 |
60 | /**
61 | Uses special keys such as , .
62 | @return The key-value pairs of all form values at the moment.
63 | */
64 | - (NSDictionary *)allKeyValuePairs;
65 |
66 | ///-----------------------------
67 | /// @name Getting views & models
68 | ///-----------------------------
69 |
70 | /**
71 | @param view The view which will be using for search.
72 | @return The model which contains `view` in one of the `inputViews` array.
73 | */
74 | - (nullable PFModel *)modelByView:(__kindof UIView *)view;
75 |
76 | /**
77 | @param indexPath The index path which will be using for search.
78 | @return The model which uses for displaying cell by the index path.
79 | */
80 | - (nullable PFModel *)modelByIndexPath:(NSIndexPath *)indexPath;
81 |
82 | /**
83 | @param view The view which will be using for search.
84 | @return The PFInputView object associated with the view.
85 | */
86 | - (nullable PFInputView *)inputViewByView:(__kindof UIView *)view;
87 |
88 | /**
89 | Use it if the cell has only one input view.
90 |
91 | @param indexPath The index path which will be using for search.
92 | @return The PFInputView object associated with the indexPath.
93 | */
94 | - (nullable PFInputView *)inputViewByIndexPath:(NSIndexPath *)indexPath;
95 |
96 | /**
97 | Use it if the cell has more than one input view.
98 |
99 | @param indexPath The index path which will be using for search.
100 | @param tag The tag for exact search.
101 | @return The PFInputView object associated with the indexPath.
102 | */
103 | - (nullable PFInputView *)inputViewByIndexPath:(NSIndexPath *)indexPath tag:(NSUInteger)tag;
104 |
105 | @end
106 |
107 | NS_ASSUME_NONNULL_END
108 |
--------------------------------------------------------------------------------
/PureForm/PFFormController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFFormController.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFFormController.h"
25 |
26 | #import "PFJSONSerialization.h"
27 | #import "PFSettings.h"
28 | #import "PFTableViewDataSource.h"
29 | #import "PFModel.h"
30 | #import "PFConstants.h"
31 | #import "PFInputView+Validation.h"
32 | #import "PFError.h"
33 | #import "PFValidator+FailureReason.h"
34 | #import "PFConstants.h"
35 | #import "UIView+PureForm.h"
36 |
37 | @interface PFFormController ()
38 |
39 | @property(strong, nonatomic) UITableView *tableView;
40 | @property(strong, nonatomic) PFSettings *settings;
41 | @property(strong, nonatomic) NSArray *models;
42 | @property(strong, nonatomic) PFTableViewDataSource *tableViewDataSource;
43 |
44 | @end
45 |
46 | @implementation PFFormController
47 |
48 | - (instancetype)initWithTableView:(UITableView *)tableView settings:(PFSettings *)settings {
49 | self = [super init];
50 |
51 | if (self) {
52 | _tableView = tableView;
53 | _settings = settings;
54 | }
55 |
56 | return self;
57 | }
58 |
59 | - (void)makeFormWithJSONFile:(NSString *)fileName {
60 | self.models = [PFJSONSerialization modelsFromFile:fileName];
61 |
62 | self.tableViewDataSource = [[PFTableViewDataSource alloc] initWithModels:self.models
63 | tableView:self.tableView
64 | settings:self.settings];
65 | self.tableView.dataSource = self.tableViewDataSource;
66 | self.tableView.delegate = self.settings.tableViewDelegate;
67 |
68 | CGFloat rowHeight = self.settings.cellHeight;
69 | if (rowHeight > PFCellHeightDefault) {
70 | self.tableView.rowHeight = rowHeight;
71 | self.tableView.estimatedRowHeight = rowHeight;
72 | }
73 | }
74 |
75 | - (NSArray *)inputFormViews {
76 | NSMutableArray *inputFormViews = [[NSMutableArray alloc] init];
77 |
78 | NSPredicate *formPredicate = [NSPredicate predicateWithFormat:@"ANY inputViews.isFormView == YES"];
79 |
80 | for (PFModel *model in [self.models filteredArrayUsingPredicate:formPredicate]) {
81 | NSPredicate *inputViewPredicate = [NSPredicate predicateWithFormat:@"isFormView == YES"];
82 | NSArray *results = [model.inputViews filteredArrayUsingPredicate:inputViewPredicate];
83 | [inputFormViews addObjectsFromArray:results];
84 | }
85 |
86 | return inputFormViews;
87 | }
88 |
89 | - (BOOL)validate {
90 | BOOL isValid = YES;
91 |
92 | NSMutableArray *errors = [[NSMutableArray alloc] init];
93 |
94 | for (PFInputView *inputView in [self inputFormViews]) {
95 | NSArray *sectionModels = self.tableViewDataSource.dataSource[inputView.view.pf_section];
96 | PFValidator *validator = [inputView failedValidatorWithValue:inputView.value
97 | sectionModels:sectionModels
98 | modelIndex:inputView.view.pf_index
99 | force:NO];
100 |
101 | if (validator) {
102 | NSString *reason = [validator failureReasonWithUserReasons:self.settings.failureReasons];
103 | PFError *error = [[PFError alloc] initWithView:inputView.view validator:validator reason:reason];
104 | [errors addObject:error];
105 | }
106 |
107 | if (isValid && validator) {
108 | isValid = NO;
109 | }
110 | }
111 |
112 | if (!isValid && self.settings.formDelegate &&
113 | [self.settings.formDelegate respondsToSelector:@selector(validationDidFailWithErrors:)]) {
114 | [self.settings.formDelegate validationDidFailWithErrors:[NSArray arrayWithArray:errors]];
115 | }
116 |
117 | if (isValid && [self.settings.formDelegate respondsToSelector:@selector(validationDidEndSuccessfully)]) {
118 | [self.settings.formDelegate validationDidEndSuccessfully];
119 | }
120 |
121 | return isValid;
122 | }
123 |
124 | - (NSArray *)allValues {
125 | NSMutableArray *values = [[NSMutableArray alloc] init];
126 |
127 | for (PFInputView *inputView in [self inputFormViews]) {
128 | if (inputView.value) {
129 | [values addObject:inputView.value];
130 | }
131 | }
132 |
133 | return values;
134 | }
135 |
136 | - (NSDictionary *)allKeyValuePairs {
137 | NSMutableDictionary *pairs = [[NSMutableDictionary alloc] init];
138 |
139 | NSUInteger emptyIndex = 0;
140 | for (PFInputView *inputView in [self inputFormViews]) {
141 | if (!inputView.value && !inputView.key) {
142 | continue;
143 | }
144 |
145 | NSString *key = inputView.key;
146 | NSString *value = inputView.value ?: @"";
147 |
148 | if (!inputView.key || [inputView.key isEqualToString:@""]) {
149 | key = [NSString stringWithFormat:@"%@_%tu", PFUnknownKey, emptyIndex];
150 | emptyIndex += 1;
151 | }
152 |
153 | pairs[key] = value;
154 | }
155 |
156 | return pairs;
157 | }
158 |
159 | - (PFModel *)modelByView:(__kindof UIView *)view {
160 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY inputViews.view == %@", view];
161 | NSArray *results = [self.models filteredArrayUsingPredicate:predicate];
162 |
163 | return results.count > 0 ? results.firstObject : nil;
164 | }
165 |
166 | - (PFModel *)modelByIndexPath:(NSIndexPath *)indexPath {
167 | NSPredicate *predicate = [NSPredicate predicateWithFormat:
168 | @"ANY inputViews.view.pf_index == %ld AND sectionIndex == %ld", indexPath.row, indexPath.section];
169 | NSArray *results = [self.models filteredArrayUsingPredicate:predicate];
170 |
171 | return results.count > 0 ? results.firstObject : nil;
172 | }
173 |
174 | - (PFInputView *)inputViewByView:(__kindof UIView *)view {
175 | PFModel *model = [self modelByView:view];
176 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"view == %@", view];
177 | NSArray *results = [model.inputViews filteredArrayUsingPredicate:predicate];
178 |
179 | return results.count > 0 ? results.firstObject : nil;
180 | }
181 |
182 | - (PFInputView *)inputViewByIndexPath:(NSIndexPath *)indexPath {
183 | return [self inputViewByIndexPath:indexPath tag:0];
184 | }
185 |
186 | - (PFInputView *)inputViewByIndexPath:(NSIndexPath *)indexPath tag:(NSUInteger)tag {
187 | PFModel *model = [self modelByIndexPath:indexPath];
188 | NSPredicate *predicate = [NSPredicate predicateWithFormat:
189 | @"view.pf_index == %ld AND view.pf_section == %ld AND view.pf_tag == %ld AND formView == YES",
190 | indexPath.row, indexPath.section, tag];
191 | NSArray *results = [model.inputViews filteredArrayUsingPredicate:predicate];
192 |
193 | return results.count > 0 ? results.firstObject : nil;
194 | }
195 |
196 | @end
197 |
--------------------------------------------------------------------------------
/PureForm/PFJSONSerialization.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFJSONSerialization.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | NS_ASSUME_NONNULL_BEGIN
27 |
28 | @interface PFJSONSerialization : NSObject
29 |
30 | /**
31 | @param fileName The name of JSON file.
32 | @return The array of PFModel objects.
33 | */
34 | + (nullable NSArray *)modelsFromFile:(NSString *)fileName;
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
--------------------------------------------------------------------------------
/PureForm/PFJSONSerialization.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFJSONSerialization.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFJSONSerialization.h"
25 | #import "NSString+PureForm.h"
26 | #import "PFModel.h"
27 | #import "PFConstants.h"
28 | #import "PFMacros.h"
29 | #import "PFInputView.h"
30 | #import "PFValidator.h"
31 |
32 | @implementation PFJSONSerialization
33 |
34 | + (NSArray *)modelsFromFile:(NSString *)fileName {
35 | NSError *error;
36 |
37 | NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"json"];
38 | NSString *string = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
39 |
40 | if (error) {
41 | PFLog(@"%@", error.localizedDescription);
42 | return nil;
43 | }
44 |
45 | NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
46 | NSArray *elements = [PFJSONSerialization PFModelWithData:data error:&error];
47 |
48 | if (error) {
49 | PFLog(@"%@", error.localizedDescription);
50 | return nil;
51 | }
52 |
53 | return elements;
54 | }
55 |
56 | + (NSArray *)PFModelWithData:(NSData *)data error:(NSError **)error {
57 | NSArray *elements = [NSJSONSerialization JSONObjectWithData:data options:0 error:error];
58 | NSMutableArray *models = [[NSMutableArray alloc] initWithCapacity:elements.count];
59 |
60 | NSUInteger sectionIndex = 0;
61 |
62 | for (NSDictionary *element in elements) {
63 | if (element.allKeys.count == 1 && [element.allKeys.firstObject isEqualToString:PFSectionKey]) {
64 | sectionIndex = [element.allValues.firstObject unsignedIntegerValue];
65 | continue;
66 | }
67 |
68 | PFModel *model = [[PFModel alloc] init];
69 | model.sectionIndex = sectionIndex;
70 |
71 | NSArray *level1Keys = element.allKeys;
72 |
73 | BOOL userDataIsMultiple = level1Keys.count > 2;
74 | NSMutableArray *userData = userDataIsMultiple ? [[NSMutableArray alloc] initWithCapacity:level1Keys.count - 1] : nil;
75 |
76 | NSDictionary *inputViewsDictionary;
77 | for (NSString *level1key in level1Keys) {
78 | if ([level1key pf_isCombinedKey]) {
79 |
80 | NSString *cellClassName = [level1key pf_cellClassName];
81 | NSString *cellIdentifier = [level1key pf_cellIdentifier];
82 |
83 | PFModel *previousModel = models.lastObject;
84 |
85 | model.cellClassName =
86 | [cellClassName isEqualToString:PFSpecialCharSame] ? previousModel.cellClassName : cellClassName;
87 | model.cellIdentifier =
88 | [cellIdentifier isEqualToString:PFSpecialCharSame] ? previousModel.cellIdentifier : cellIdentifier;
89 |
90 | inputViewsDictionary = element[level1key];
91 |
92 | continue;
93 | }
94 |
95 | [userData addObject:element[level1key]];
96 | }
97 |
98 | // Hm...
99 | NSArray *level2Keys = inputViewsDictionary.allKeys;
100 | NSMutableArray *inputViews = [[NSMutableArray alloc] initWithCapacity:level2Keys.count];
101 | for (NSString *level2key in level2Keys) {
102 | PFInputView *inputView = [[PFInputView alloc] init];
103 | inputView.propertyName = [level2key pf_hasFormViewSuffix] ? [level2key pf_suffixFreeString] : level2key;
104 | inputView.formView = [level2key pf_hasFormViewSuffix];
105 |
106 | NSDictionary *inputViewOptions = inputViewsDictionary[level2key];
107 | NSMutableDictionary *inputViewParams = [[NSMutableDictionary alloc] init];
108 |
109 | for (NSString *level3Key in inputViewOptions.allKeys) {
110 | id value = inputViewOptions[level3Key];
111 |
112 | if ([level3Key pf_isSpecialKey]) {
113 | if ([level3Key isEqualToString:PFValueKey]) {
114 | inputView.value = value;
115 | }
116 | if ([level3Key isEqualToString:PFKeyKey]) {
117 | inputView.key = value;
118 | }
119 | if ([level3Key isEqualToString:PFValidationKey]) {
120 | NSDictionary *options = value;
121 |
122 | NSArray *keys = options.allKeys;
123 | NSMutableArray *validators = [[NSMutableArray alloc] initWithCapacity:keys.count];
124 |
125 | for (NSString *key in keys) {
126 | PFValidator *validator = [[PFValidator alloc] init];
127 |
128 | validator.type = (PFValidatorType) [PFEnums enumFromValue:key];
129 | validator.forceValidation = [key pf_hasSuffix];
130 | validator.value = options[key];
131 |
132 | [validators addObject:validator];
133 | }
134 |
135 | inputView.validators = [NSArray arrayWithArray:validators];
136 | }
137 | if ([level3Key isEqualToString:PFDisplayKey]) {
138 | inputView.displayPropertyName = value;
139 | }
140 |
141 | continue;
142 | }
143 |
144 | NSString *saveKey = level3Key;
145 |
146 | if ([saveKey pf_hasLocalizedSuffix]) {
147 | value = NSLocalizedString(value,);
148 | saveKey = [saveKey pf_suffixFreeString];
149 | }
150 |
151 | inputViewParams[saveKey] = value;
152 | }
153 |
154 | inputView.params = [NSDictionary dictionaryWithDictionary:inputViewParams];
155 |
156 | [inputViews addObject:inputView];
157 | }
158 |
159 | model.inputViews = [NSArray arrayWithArray:inputViews];
160 |
161 | [models addObject:model];
162 | }
163 |
164 | return [NSArray arrayWithArray:models];
165 | }
166 |
167 | @end
168 |
--------------------------------------------------------------------------------
/PureForm/PFTableViewDataSource.h:
--------------------------------------------------------------------------------
1 | //
2 | // PFTableViewDataSource.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 | #import
26 |
27 | @class PFModel;
28 | @class PFSettings;
29 |
30 | @interface PFTableViewDataSource : NSObject
31 |
32 | /**
33 | The section-grouped data source for table view.
34 | */
35 | @property(strong, nonatomic, readonly) NSMutableArray *> *dataSource;
36 |
37 | /**
38 | @param elements The array of PFModel objects.
39 | @return The instance of PFTableViewDataSource.
40 | */
41 | - (instancetype)initWithModels:(NSArray *)models tableView:(UITableView *)tableView settings:(PFSettings *)settings;
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/PureForm/PFTableViewDataSource.m:
--------------------------------------------------------------------------------
1 | //
2 | // PFTableViewDataSource.m
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import "PFTableViewDataSource.h"
25 |
26 | #import "PFModel.h"
27 | #import "PFMacros.h"
28 | #import "UITableViewCell+PureForm.h"
29 | #import "PFInputViewDelegate.h"
30 | #import "PFSettings.h"
31 | #import "UIView+PureForm.h"
32 | #import "PFConstants.h"
33 | #import "PFInputView.h"
34 |
35 | @interface PFTableViewDataSource ()
36 |
37 | @property(strong, nonatomic, readwrite) NSMutableArray *> *dataSource;
38 | @property(strong, nonatomic) PFInputViewDelegate *inputViewDelegate;
39 | @property(strong, nonatomic) PFSettings *settings;
40 | @property(strong, nonatomic) UITableView *tableView;
41 |
42 | @end
43 |
44 | @implementation PFTableViewDataSource
45 |
46 | - (instancetype)initWithModels:(NSArray *)models tableView:(UITableView *)tableView settings:(PFSettings *)settings {
47 | self = [super init];
48 |
49 | if (self) {
50 | NSMutableArray *sections = [[NSMutableArray alloc] init];
51 | for (PFModel *model in models) {
52 | NSNumber *sectionIndex = @(model.sectionIndex);
53 | if (![sections containsObject:sectionIndex]) {
54 | [sections addObject:sectionIndex];
55 | }
56 | }
57 |
58 | // Safe for random selection of sections
59 | NSMutableArray *dataSource = [[NSMutableArray alloc] initWithCapacity:sections.count];
60 | for (NSUInteger i = 0; i < sections.count; i++) {
61 | [dataSource addObject:@0];
62 | }
63 |
64 | for (NSNumber *sectionIndex in sections) {
65 | NSPredicate *sectionPredicate = [NSPredicate predicateWithFormat:@"sectionIndex == %@", sectionIndex];
66 | NSArray *results = [models filteredArrayUsingPredicate:sectionPredicate];
67 | dataSource[[sectionIndex unsignedIntegerValue]] = results;
68 | }
69 |
70 | _settings = settings;
71 | _dataSource = dataSource;
72 | _tableView = tableView;
73 |
74 | [[NSNotificationCenter defaultCenter] addObserver:self
75 | selector:@selector(changeDisplayLabel:)
76 | name:PFDisplayLabelShouldChangeNotification
77 | object:nil];
78 | }
79 |
80 | return self;
81 | }
82 |
83 | - (void)dealloc {
84 | [[NSNotificationCenter defaultCenter] removeObserver:self];
85 | }
86 |
87 | - (void)changeDisplayLabel:(NSNotification *)notification {
88 | PFInputView *inputView = notification.object;
89 |
90 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:inputView.view.pf_index inSection:inputView.view.pf_section];
91 | UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
92 | [cell setValue:inputView.value forPropertyName:inputView.propertyName];
93 | }
94 |
95 | #pragma clang diagnostic push
96 | #pragma clang diagnostic ignored "-Wundeclared-selector"
97 |
98 | #pragma mark - UITableViewDataSource
99 |
100 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
101 | return self.dataSource[(NSUInteger) section].count;
102 | }
103 |
104 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
105 | return self.dataSource.count;
106 | }
107 |
108 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
109 | PFModel *model = self.dataSource[(NSUInteger) indexPath.section][(NSUInteger) indexPath.row];
110 |
111 | Class CellClass = NSClassFromString(model.cellClassName);
112 |
113 | __kindof UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:model.cellIdentifier];
114 | if (!cell) {
115 | cell = (__kindof UITableViewCell *) [[CellClass alloc] init];
116 | }
117 |
118 | NSUInteger tag = 0;
119 | for (PFInputView *inputView in model.inputViews) {
120 | if (inputView.isFormView) {
121 | __kindof UIView *view = [cell valueForKey:inputView.propertyName];
122 |
123 | view.pf_index = (NSUInteger) indexPath.row;
124 | view.pf_section = (NSUInteger) indexPath.section;
125 | view.pf_tag = tag;
126 | view.pf_display = inputView.displayPropertyName ? [cell valueForKey:inputView.displayPropertyName] : nil;
127 |
128 | inputView.view = view;
129 |
130 | tag += 1;
131 |
132 | [self assignDelegateToView:view];
133 | }
134 |
135 | for (NSString *paramKey in inputView.params.allKeys) {
136 | NSString *param = inputView.params[paramKey];
137 |
138 | @try {
139 | [cell setValue:param forKeyPath:[NSString stringWithFormat:@"%@.%@", inputView.propertyName, paramKey]];
140 | }
141 | @catch (NSException *exception) {
142 | @throw exception;
143 | UIView *view = inputView.view;
144 | PFLog(@"Unable to set '%@' to '%@' (row: %tu, section: %tu, tag: %tu)",
145 | paramKey, inputView.propertyName, view.pf_index, view.pf_section, view.pf_tag);
146 | }
147 | }
148 |
149 | if (inputView.value) {
150 | [cell setValue:inputView.value forPropertyName:inputView.propertyName];
151 | }
152 | }
153 |
154 | return cell;
155 | }
156 |
157 | #pragma mark - Delegates
158 |
159 | - (void)assignDelegateToView:(id)view {
160 | if (!self.inputViewDelegate) {
161 | self.inputViewDelegate = [[PFInputViewDelegate alloc] initWithModels:self.dataSource
162 | tableView:self.tableView
163 | settings:self.settings];
164 | }
165 |
166 | if ([view respondsToSelector:@selector(delegate)]) {
167 | id dView = view;
168 | dView.delegate = self.inputViewDelegate;
169 | } else {
170 | if ([view isKindOfClass:[UISlider class]]) {
171 | SEL action = @selector(sliderControlDidEndEditing:);
172 | [view addTarget:self.inputViewDelegate action:action forControlEvents:UIControlEventTouchUpInside];
173 | }
174 |
175 | SEL action = @selector(controlViewDidChangeValue:);
176 | [view addTarget:self.inputViewDelegate action:action forControlEvents:UIControlEventValueChanged];
177 | }
178 | }
179 |
180 | #pragma clang diagnostic pop
181 |
182 | @end
183 |
--------------------------------------------------------------------------------
/PureForm/PureForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // PureForm.h
3 | //
4 | // Copyright (c) 2016 Puzyrev Pavel
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 |
24 | #import
25 |
26 | #import "PFFormController.h"
27 | #import "PFFormDelegate.h"
28 | #import "PFSettings.h"
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PureForm — the easiest way to build form such as login, questionnaire and etc. screens from JSON file. PureForm provides parsing properties and special params into objects for further manipulation of them.
2 |
3 | ## Setup
4 |
5 | ### Manually
6 |
7 | Download the source files from the [PureForm subdirectory](https://github.com/unboxme/PureForm/tree/master/PureForm). Then just add source files to your Xcode project and import the `PureLayout.h` header.
8 |
9 | ### Cocoapods
10 |
11 | Add the pod PureForm to your Podfile:
12 |
13 | ```ruby
14 | platform :ios, '8.0'
15 |
16 | target 'YourProject' do
17 | pod 'PureForm'
18 | end
19 | ```
20 |
21 | Then, run the following command:
22 |
23 | ```terminal
24 | $ pod install
25 | ```
26 |
27 | ## Usage
28 |
29 | PureForm is clean and pretty easy to use in several steps:
30 |
31 | 1. Describe your form in a JSON file using `JSON Rules` paragraph below;
32 | 2. Create settings via `PFSettings` using `Settings` paragraph below:
33 |
34 | ```objc
35 | PFSettings *settings = [[PFSettings alloc] init];
36 | settings.keyboardTypeValidation = YES;
37 | settings.keyboardAvoiding = YES;
38 | settings.formDelegate = self;
39 | settings.tableViewDelegate = self;
40 |
41 | // etc.
42 | ```
43 | 3. Create a `PFFormController` instance with a `UITableView` and settings which were created at the previous step:
44 |
45 | ```objc
46 | self.formController = [[PFFormController alloc] initWithTableView:self.tableView settings:settings];
47 | ```
48 | 4. Just use a `makeFormWithJSONFile:` method to create and display your form from the JSON file from the first step:
49 |
50 | ```objc
51 | [self.formController makeFormWithJSONFile:@"form"];
52 | ```
53 |
54 | 5. That's it!
55 |
56 | ## Settings
57 |
58 | The [settings header](PureForm/Models/PFSettings.h) is fully documented. There are main params here you can set:
59 |
60 | * `keyboardTypeValidation`
61 | * `keyboardAvoiding`
62 | * `failureReasons`
63 | * `cellHeight`
64 |
65 | As well as delegates for `UIKit` controls:
66 |
67 | * `PFFormDelegate`
68 | * `UITableViewDelegate`
69 | * `UITextFieldDelegate`
70 | * `PFSegmentedControlDelegate`
71 | * `PFSwitchControlDelegate`
72 | * `PFSliderControlDelegate`
73 | * `PFStepperControlDelegate`
74 |
75 | ## JSON Rules
76 |
77 | Describe your custom cell in JSON just using property names and values for them. Of course, __reserved words__ and __special chars__ are used too. You can find reserved words and special chars in a [constants header](PureForm/Common/PFConstants.h).
78 |
79 | ### Basics
80 |
81 | * Pairs of class cell name or cell identifier and reserved words are segregated by `<` and `>`.
82 | * The base structure for 2 cells looks like __(pay attention on levels)__:
83 |
84 | ```
85 | [ /// 0 level
86 | {
87 | "": { // First cell
88 | property_name_1: { /// 1 level
89 | in_property_name_1.1: value, /// 2 level
90 | in_property_name_1.2: value
91 | },
92 | property_name_2: {
93 | in_property_name_2.1: value
94 | }
95 | }
96 | },
97 | {
98 | "": { // Second cell
99 | // Setup
100 | },
101 | {
102 | // etc.
103 | }
104 | ]
105 | ```
106 | __Note that JSON parsing supports only 2 levels of nesting yet.__
107 | * If a cell class name or a cell identifier equals to the previous one, you can simplify it using `=` like that:
108 |
109 | ```
110 | {
111 | "<= + =>": { // Any cell
112 | // Setup
113 | },
114 | ```
115 | * Usage of reserved words and special chars:
116 |
117 | | Reserved word | Level | Value
118 | |----------------------|---------|----------
119 | | `` | 0 | index of section
120 | | `` | 1 | current value
121 | | `` | 1 | save key for output dictionary
122 | | `` | 1 | array of validators
123 | | `` | 1 | property name to display value after change
124 | __All reserved words and special chars are optional.__
125 |
126 | | Char | Usage in | Example | Description
127 | |------------------|-----------|-------------|------
128 | | ? | property name | textField? | Shows that it's a form for validation — not just a view
129 | | ! | validator name | min_value! | Starts validation immediately after value change
130 | | * | property name | text* | Shows that this value is a key for `NSLocalizedString` macros
131 | | # | value | ic_turtle#6F3F83 or #6F3F83| Uses as it is or for hex coloring image by their name
132 | * Available validator keys for ``:
133 |
134 | | Validator | Value
135 | |-------------|----------
136 | | `equal` | string or number
137 | | `equal_next` | `true`
138 | | `equal_previous` | `true`
139 | | `equal_length` | number
140 | | `min_length` | number
141 | | `max_length` | number
142 | | `min_value` | number
143 | | `max_value` | number
144 | | `required` | `true`
145 | | `type` | `email` or `full_name`
146 | | `custom` | regex string
147 | __Validators are used in 2 level and they should be nested into ``.__
148 |
149 | * Enums are just numeric values in JSON. By the way there are some enums which are associated with string values:
150 | * `UIKeyboardType`
151 | * `UITextAutocapitalizationType`
152 | * `UITextAutocorrectionType`
153 | * `UITextSpellCheckingType`
154 | * `UIKeyboardAppearance`
155 | * `UIReturnKeyType`
156 | * `UITextFieldViewMode`
157 |
158 | ### Examples
159 |
160 | * Well, how it looks in a real example:
161 |
162 | ```json
163 | [
164 | {
165 | "": {
166 | "textField?": {
167 | "placeholder": "Huh, centered?",
168 | "textAlignment": 1
169 | }
170 | }
171 | }
172 | ]
173 | ```
174 |
175 |
176 |
177 |
178 |
179 | * Now let's make a login form with validators:
180 |
181 | ```json
182 | [
183 | {
184 | "": {
185 | "textField?": {
186 | "placeholder": "Login",
187 | "textAlignment": 1,
188 | "keyboardType": "UIKeyboardTypeEmailAddress",
189 | "": "login",
190 | "": {
191 | "type": "email"
192 | }
193 | }
194 | }
195 | },
196 | {
197 | "<= + =>": {
198 | "textField?": {
199 | "placeholder": "Password",
200 | "textAlignment": 1,
201 | "secureTextEntry": true,
202 | "": "password",
203 | "": {
204 | "min_length!": 6,
205 | "max_length!": 25
206 | }
207 | }
208 | }
209 | },
210 | {
211 | "": 1
212 | },
213 | {
214 | "": {
215 | "titleLabel": {
216 | "text": "Login",
217 | "textColor": "#6F3F83"
218 | }
219 | }
220 | }
221 | ]
222 | ```
223 |
224 |
225 |
226 |
227 |
228 | * It remains only to validate entered values and save they into the dictionary. Credentials from left form satisfies the validators and `[self.formController validate]` will return `YES`:
229 |
230 | ```objc
231 | if ([self.formController validate]) {
232 | NSDictionary *loginInfo = [self.formController allKeyValuePairs];
233 | // Send it to server
234 | }
235 | ```
236 |
237 |
238 |
239 |
240 |
241 |
242 | ## Notes
243 |
244 | * Example project files will open properly only in Xcode 8.
245 |
246 | ## TODO
247 |
248 | - [ ] Remove limit of nesting
249 | - [x] Keyboard avoiding (issue #2)
250 | - [ ] Targets for buttons
251 | - [ ] Support of UITextView
252 | - [ ] Wrapper for editing common properties
253 |
--------------------------------------------------------------------------------
/Screenshots/centered_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Screenshots/centered_text.png
--------------------------------------------------------------------------------
/Screenshots/clean_form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Screenshots/clean_form.png
--------------------------------------------------------------------------------
/Screenshots/filled_form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Screenshots/filled_form.png
--------------------------------------------------------------------------------
/Screenshots/filled_form_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unboxme/PureForm/84c77c143b4249c19e11d0728bcb23cd0adffb21/Screenshots/filled_form_error.png
--------------------------------------------------------------------------------