├── .gitignore
├── FTCTextEntryFormatting-prefix.pch
├── FTCTextEntryFormatting.podspec
├── FTCTextEntryFormatting.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ └── FTCTextEntryFormatting.xcscheme
├── FTCTextEntryFormattingDemo
├── FTCTextEntryFormattingDemo.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── FTCTextEntryFormattingDemo
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Bridging-Header.h
│ ├── Data
│ └── FormattingExampleItem.swift
│ ├── Info.plist
│ ├── PrefixHeader.pch
│ └── Screens
│ ├── EntryViewController.swift
│ └── ViewController.swift
├── Info.plist
├── LICENSE
├── README.md
├── Src
├── Core
│ ├── FTCTextEntry.h
│ ├── FTCTextEntryFormatCoordinator.h
│ ├── FTCTextEntryFormatCoordinator.m
│ ├── FTCTextEntryFormatCoordinatorHelper.h
│ ├── FTCTextEntryFormatCoordinatorHelper.m
│ ├── FTCTextEntryFormattingConfig.h
│ ├── FTCTextEntryFormattingConfig.m
│ ├── Formatting
│ │ ├── FTCNoFormattingFormatter.h
│ │ ├── FTCNoFormattingFormatter.m
│ │ ├── FTCTextEntryFormatter.h
│ │ ├── MaskFormatter
│ │ │ ├── FTCMaskFormatter.h
│ │ │ ├── FTCMaskFormatter.m
│ │ │ ├── FTCMaskFormatterConfig.h
│ │ │ ├── FTCMaskFormatterGenericConfig.h
│ │ │ └── FTCMaskFormatterGenericConfig.m
│ │ └── PostfixFormatter
│ │ │ ├── FTCPostfixFormatter.h
│ │ │ └── FTCPostfixFormatter.m
│ └── InputFiltering
│ │ ├── DigitsValueFilter
│ │ ├── FTCDigitsValueFilter.h
│ │ └── FTCDigitsValueFilter.m
│ │ ├── FTCFilteredString.h
│ │ ├── FTCFilteredString.m
│ │ ├── FTCNoFilteringFilter.h
│ │ ├── FTCNoFilteringFilter.m
│ │ ├── FTCTextEntryEditingInputFilter.h
│ │ ├── FTCTextEntryNotEditingInputFilter.h
│ │ ├── LimitedLengthInputFilter
│ │ ├── FTCLimitedLengthInputFilter.h
│ │ └── FTCLimitedLengthInputFilter.m
│ │ └── ToUpperCaseInputFilter
│ │ ├── FTCToUpperCaseInputFilter.h
│ │ └── FTCToUpperCaseInputFilter.m
├── FTCTextEntryFormatting.h
├── FTCTextEntryFormattingConfigFactory.h
├── FTCTextEntryFormattingConfigFactory.m
├── FTCTextFieldFormatCoordinator.h
├── FTCTextFieldFormatCoordinator.m
├── FTCTextInputUtils.h
├── FTCTextInputUtils.m
├── Money
│ ├── FTCIntegralMoneyAmountEntryEditingInputFilter.h
│ ├── FTCIntegralMoneyAmountEntryEditingInputFilter.m
│ ├── FTCIntegralMoneyAmountEntryNotEditingInputFilter.h
│ ├── FTCIntegralMoneyAmountEntryNotEditingInputFilter.m
│ ├── FTCMoneyEntryEditingFormatter.h
│ ├── FTCMoneyEntryEditingFormatter.m
│ ├── FTCMoneyEntryEditingInputFilter.h
│ ├── FTCMoneyEntryEditingInputFilter.m
│ ├── FTCMoneyEntryFormatUtils.h
│ ├── FTCMoneyEntryFormatUtils.m
│ ├── FTCMoneyEntryNotEditingFormatter.h
│ ├── FTCMoneyEntryNotEditingFormatter.m
│ ├── FTCMoneyEntryNotEditingInputFilter.h
│ └── FTCMoneyEntryNotEditingInputFilter.m
└── Tools
│ ├── FTCTextEntryFormattingStringUtils.h
│ ├── FTCTextEntryFormattingStringUtils.m
│ ├── NSString+FTCTextEntryFormatting.h
│ └── NSString+FTCTextEntryFormatting.m
└── UnitTests
├── FormatCoordinator
└── FormatCoordinatorTestCase.m
├── Formatters
├── FTCMaskFormatter
│ └── FTCMaskFormatterTestCase.m
└── FTCPostfixFormatter
│ ├── FTCPostfixFormatterTestCaseWithEmptyPostfix.m
│ ├── FTCPostfixFormatterTestCaseWithNilPostfix.m
│ └── FTCPostfixFormatterTestCaseWithNotEmptyPostfix.m
├── Info.plist
└── InputFilter
├── FTCDigitsInputFilterTestCase.m
└── FTCDigitsInputFilterTestCaseWithZeroMaxLength.m
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # AppCode
3 | .idea
4 |
5 | # Xcode
6 | #
7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8 |
9 | ## Build generated
10 | build/
11 | DerivedData/
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata/
23 | FTCTextEntryFormatting.xcscmblueprint
24 |
25 | ## Other
26 | *.moved-aside
27 | *.xcuserstate
28 |
29 | ## Obj-C/Swift specific
30 | *.hmap
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 |
35 | ## Playgrounds
36 | timeline.xctimeline
37 | playground.xcworkspace
38 |
39 | # Swift Package Manager
40 | #
41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
42 | # Packages/
43 | .build/
44 |
45 | # CocoaPods
46 | #
47 | # We recommend against adding the Pods directory to your .gitignore. However
48 | # you should judge for yourself, the pros and cons are mentioned at:
49 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
50 | #
51 | # Pods/
52 |
53 | # Carthage
54 | #
55 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
56 | # Carthage/Checkouts
57 |
58 | Carthage/Build
59 |
60 | # fastlane
61 | #
62 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
63 | # screenshots whenever they are needed.
64 | # For more information about the recommended setup visit:
65 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
66 |
67 | fastlane/report.xml
68 | fastlane/Preview.html
69 | fastlane/screenshots
70 | fastlane/test_output
71 |
--------------------------------------------------------------------------------
/FTCTextEntryFormatting-prefix.pch:
--------------------------------------------------------------------------------
1 | @import Foundation;
2 |
--------------------------------------------------------------------------------
/FTCTextEntryFormatting.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 |
3 | spec.name = 'FTCTextEntryFormatting'
4 | spec.version = '1.0.5'
5 | spec.license = { :type => 'FTC' }
6 | spec.homepage = 'https://github.com/cft-dev/FTCTextEntryFormatting'
7 | spec.authors = { 'Denis Morozov' => 'd.morozov@ftc.ru' }
8 | spec.summary = 'Text Entry Formatting.'
9 | spec.source = { :git => 'https://github.com/cft-dev/FTCTextEntryFormatting.git', :tag => '1.0.5' }
10 |
11 | spec.prefix_header_contents = '@import Foundation;'
12 | spec.source_files = 'Src/**/*.{h,m}'
13 | spec.private_header_files = 'Src/Categories/*.h', 'Src/Tools/*.h'
14 |
15 | spec.requires_arc = true
16 |
17 | spec.ios.deployment_target = '8.0'
18 |
19 | spec.test_spec 'UnitTests' do |test_spec|
20 | test_spec.source_files = 'UnitTests/**/*.{h,m}'
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/FTCTextEntryFormatting.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FTCTextEntryFormatting.xcodeproj/xcshareddata/xcschemes/FTCTextEntryFormatting.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
69 |
70 |
76 |
77 |
78 |
79 |
80 |
81 |
87 |
88 |
94 |
95 |
96 |
97 |
99 |
100 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | import UIKit
22 |
23 | @UIApplicationMain
24 | class AppDelegate: UIResponder, UIApplicationDelegate {
25 |
26 | var window: UIWindow?
27 |
28 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
29 | {
30 | return true
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/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 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/Base.lproj/Main.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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/Bridging-Header.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #ifndef Bridging_Header_h
22 | #define Bridging_Header_h
23 |
24 | #import "FTCTextEntryFormatting.h"
25 |
26 | #endif /* Bridging_Header_h */
27 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/Data/FormattingExampleItem.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | struct FormattingExampleItem
22 | {
23 | let text: String
24 | let detailText: String?
25 | let config: FTCTextEntryFormattingConfig
26 | let keyboard: UIKeyboardType
27 | }
28 |
29 | extension FormattingExampleItem
30 | {
31 | static func makeItems() -> [FormattingExampleItem]
32 | {
33 |
34 | return [
35 | self.makeCellPhoneItem(),
36 | self.makeMoneyItem(),
37 | self.makeCreditCardPANItem(),
38 | self.makeDriverLicenseModernItem(),
39 | self.makeDriverLicenseOutdatedItem(),
40 | ]
41 | }
42 |
43 | static func makeCellPhoneItem() -> FormattingExampleItem
44 | {
45 | let config = FTCTextEntryFormattingConfigFactory.mobilePhoneConfig(with: "+7 (___) ___ __ __", maskChar: "_")
46 |
47 | return FormattingExampleItem(text: "Cell phone",
48 | detailText: nil,
49 | config: config,
50 | keyboard: .phonePad)
51 | }
52 |
53 | static func makeMoneyItem() -> FormattingExampleItem
54 | {
55 | let config = FTCTextEntryFormattingConfigFactory.moneyConfig(with: nil, onlyIntegral: false)
56 |
57 | return FormattingExampleItem(text: "Money",
58 | detailText: nil,
59 | config: config,
60 | keyboard: .decimalPad)
61 | }
62 |
63 | static func makeCreditCardPANItem() -> FormattingExampleItem
64 | {
65 | let maskConfig = FTCMaskFormatterGenericConfig(mask: "XXXX XXXX XXXX XXXX XXX", maskCharacter: "X")
66 | maskConfig.tailMode = .cut
67 |
68 | let maskFormatter = FTCMaskFormatter(config: maskConfig)
69 | let inputFilter = FTCDigitsValueFilter(maxLength: maskConfig.countMaskCharacters)
70 |
71 | let config = FTCTextEntryFormattingConfig(formatter: maskFormatter, inputFilter: inputFilter)
72 |
73 | return FormattingExampleItem(text: "Credit Card PAN",
74 | detailText: nil,
75 | config: config,
76 | keyboard: .numberPad)
77 | }
78 |
79 | static func makeDriverLicenseModernItem() -> FormattingExampleItem
80 | {
81 | let maskConfig = FTCMaskFormatterGenericConfig(mask: "__ __ ______", maskCharacter: "_")
82 | maskConfig.tailMode = .none
83 |
84 | let maskFormatter = FTCMaskFormatter(config: maskConfig)
85 | let inputFilter = FTCDigitsValueFilter(maxLength: maskConfig.countMaskCharacters)
86 |
87 | let config = FTCTextEntryFormattingConfig(formatter: maskFormatter, inputFilter: inputFilter)
88 |
89 | return FormattingExampleItem(text: "Driver's license",
90 | detailText: "modern",
91 | config: config,
92 | keyboard: .numberPad)
93 | }
94 |
95 | static func makeDriverLicenseOutdatedItem() -> FormattingExampleItem
96 | {
97 | let maskConfig = FTCMaskFormatterGenericConfig(mask: "__ __ № ______", maskCharacter: "_")
98 | maskConfig.tailMode = .none
99 |
100 | let maskFormatter = FTCMaskFormatter(config: maskConfig)
101 | let inputFilter = FTCToUpperCaseInputFilter()
102 |
103 | let config = FTCTextEntryFormattingConfig(formatter: maskFormatter, inputFilter: inputFilter)
104 |
105 | return FormattingExampleItem(text: "Driver's license",
106 | detailText: "outdated",
107 | config: config,
108 | keyboard: .default)
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/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 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/PrefixHeader.pch:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #ifndef PrefixHeader_pch
22 | #define PrefixHeader_pch
23 |
24 | @import Foundation;
25 |
26 | #endif /* PrefixHeader_pch */
27 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/Screens/EntryViewController.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | import UIKit
22 |
23 | class EntryViewController: UIViewController
24 | {
25 | @IBOutlet var textField: UITextField!
26 |
27 | var textFieldFormatCoordinator: FTCTextFieldFormatCoordinator!
28 |
29 | var formattingConfig: FTCTextEntryFormattingConfig!
30 | var keyboard: UIKeyboardType = .default
31 |
32 | override func viewDidLoad()
33 | {
34 | super.viewDidLoad()
35 |
36 | self.textField.keyboardType = self.keyboard
37 |
38 | self.textFieldFormatCoordinator = FTCTextFieldFormatCoordinator(textField: self.textField)
39 |
40 | self.textFieldFormatCoordinator.apply(formattingConfig: self.formattingConfig)
41 |
42 | self.textFieldFormatCoordinator.didChangeValueHandler = { [unowned self] in
43 | print("rawValue: \(self.textFieldFormatCoordinator.rawValue ?? "nil")")
44 | print("formattedValue: \(self.textFieldFormatCoordinator.formattedValue)")
45 | }
46 | }
47 |
48 | @IBAction func close(_ sender: Any)
49 | {
50 | self.dismiss(animated: true, completion: nil)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/FTCTextEntryFormattingDemo/FTCTextEntryFormattingDemo/Screens/ViewController.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | import UIKit
22 |
23 | class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
24 | {
25 | @IBOutlet var tableView: UITableView!
26 |
27 | let formattingExampleItems: [FormattingExampleItem] = FormattingExampleItem.makeItems()
28 |
29 | override func viewDidLoad()
30 | {
31 | super.viewDidLoad()
32 | }
33 |
34 | public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
35 | {
36 | return self.formattingExampleItems.count
37 | }
38 |
39 | public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
40 | {
41 | let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
42 |
43 | cell.textLabel?.text = formattingExampleItems[indexPath.row].text
44 | cell.detailTextLabel?.text = formattingExampleItems[indexPath.row].detailText
45 |
46 | return cell
47 | }
48 |
49 | public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
50 | {
51 | tableView.deselectRow(at: indexPath, animated: true)
52 |
53 | if let vc = self.storyboard?.instantiateViewController(withIdentifier: "EntryViewController") as? EntryViewController
54 | {
55 | vc.formattingConfig = formattingExampleItems[indexPath.row].config
56 | vc.keyboard = formattingExampleItems[indexPath.row].keyboard
57 |
58 | self.present(vc, animated: true, completion: nil)
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/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 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 CFT
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Overview
2 |
3 | **FTCTextEntryFormatting** is a component for formatting input data in realtime.
4 |
5 | ### Installation
6 |
7 | ```ruby
8 | pod 'FTCTextEntryFormatting', :git => 'https://github.com/cft-dev/FTCTextEntryFormatting.git', :tag => '1.0.5'
9 | ```
10 |
11 | ### Standalone usage
12 |
13 | Example for cell phone. See Demo project for more details.
14 |
15 | ```swift
16 | import FTCTextEntryFormatting
17 |
18 | class EntryViewController: UIViewController
19 | {
20 | @IBOutlet var textField: UITextField!
21 |
22 | // required strong stored
23 | var textFieldFormatCoordinator: FTCTextFieldFormatCoordinator!
24 |
25 | override func viewDidLoad()
26 | {
27 | super.viewDidLoad()
28 |
29 | self.textFieldFormatCoordinator = FTCTextFieldFormatCoordinator(textField: self.textField)
30 |
31 | let formattingConfig = FTCTextEntryFormattingConfigFactory.mobilePhoneConfig(with: "+7 (___) ___-__-__",
32 | maskChar: "_")
33 | self.textFieldFormatCoordinator.apply(formattingConfig: formattingConfig)
34 | }
35 | }
36 | ```
37 |
38 | ### Custom usage
39 |
40 | 1. Create adopter of FTCTextEntryEditingInputFilter
41 |
42 | ```swift
43 | import FTCTextEntryFormatting
44 |
45 | class CustomEditingInputFilter : NSObject, FTCTextEntryEditingInputFilter
46 | {
47 | func replaceSubstring(in originalString: String, at range: NSRange, with replacement: String) -> FTCFilteredString
48 | {
49 | ...
50 | }
51 | }
52 | ```
53 |
54 | 2. Create adopter of FTCTextEntryFormatter
55 |
56 | ```swift
57 | class CustomFormatter : NSObject, FTCTextEntryFormatter
58 | {
59 | func raw(fromFormatted formattedValue: String?) -> String
60 | {
61 | ...
62 | }
63 |
64 | func formatted(fromRaw rawValue: String?) -> String
65 | {
66 | ...
67 | }
68 |
69 | func rangeInFormattedValue(for rangeInRawValue: NSRange, inRawValue rawValue: String?) -> NSRange
70 | {
71 | ...
72 | }
73 |
74 | func rangeInRawValue(for rangeInFormattedValue: NSRange, inFormattedValue formattedValue: String?) -> NSRange
75 | {
76 | ...
77 | }
78 | }
79 | ```
80 |
81 | 3. Create adopter of FTCTextEntryNotEditingInputFilter
82 |
83 | ```swift
84 | class CustomNotEditingInputFilter : NSObject, FTCTextEntryNotEditingInputFilter
85 | {
86 | func filterString(_ string: String) -> String
87 | {
88 | ...
89 | }
90 | }
91 | ```
92 |
93 | 4. Use it
94 |
95 | ```swift
96 | class EntryViewController: UIViewController
97 | {
98 | @IBOutlet var textField: UITextField!
99 |
100 | // required strong stored
101 | var textFieldFormatCoordinator: FTCTextFieldFormatCoordinator!
102 |
103 | override func viewDidLoad()
104 | {
105 | super.viewDidLoad()
106 |
107 | self.textFieldFormatCoordinator = FTCTextFieldFormatCoordinator(textField: self.textField)
108 |
109 | let formattingConfig = FTCTextEntryFormattingConfig()
110 | formattingConfig.editingInputFilter = CustomEditingInputFilter()
111 | formattingConfig.editingFormatter = CustomFormatter()
112 | formattingConfig.notEditingInputFilter = CustomNotEditingInputFilter()
113 | formattingConfig.notEditingFormatter = CustomFormatter()
114 |
115 | self.textFieldFormatCoordinator.apply(formattingConfig: formattingConfig)
116 | }
117 | }
118 | ```
119 |
120 | ### Generic input filters
121 |
122 | FTCDigitsValueFilter – Allows only digits symbols.
123 |
124 | FTCNoFilteringFilter – Allows any symbol.
125 |
126 | FTCLimitedLengthInputFilter – Allows any symbol. Constraining input by length.
127 |
128 | FTCToUpperCaseInputFilter – Allows any symbol. Turns case to upper.
129 |
130 | ### License
131 | MIT
132 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntry.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @protocol FTCTextEntry;
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @protocol FTCTextEntry
26 |
27 | @property (nonatomic, strong, nullable) NSString *text;
28 |
29 | @property (nonatomic, assign) NSRange selectedTextRange;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntryFormatCoordinator.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @class FTCTextEntryFormattingConfig;
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCTextEntryFormatCoordinator : NSObject
26 |
27 | @property (nonatomic, strong, nullable) NSString *rawValue;
28 | @property (nonatomic, readonly) NSString *formattedValue;
29 |
30 | @property (nonatomic, assign) NSRange currentSelectionRangeInFormattedValue;
31 |
32 | - (instancetype)init;
33 |
34 | - (void)userReplacedInFormattedValueSubstringAtRange:(NSRange)range withString:(NSString *)replacement;
35 |
36 | - (void)beginEditing;
37 | - (void)endEditing;
38 |
39 | - (BOOL)isEditing;
40 |
41 | - (void)applyConfig:(FTCTextEntryFormattingConfig *)config;
42 |
43 | @end
44 |
45 | NS_ASSUME_NONNULL_END
46 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntryFormatCoordinator.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatCoordinator.h"
22 | #import "FTCTextEntryFormatter.h"
23 | #import "FTCFilteredString.h"
24 | #import "FTCTextEntryEditingInputFilter.h"
25 | #import "FTCTextEntryNotEditingInputFilter.h"
26 | #import "FTCTextEntryFormattingConfig.h"
27 |
28 | @implementation FTCTextEntryFormatCoordinator
29 | {
30 | BOOL isEditing;
31 |
32 | NSRange currentSelectionRangeInRawValue;
33 |
34 | id editingFormatter;
35 | id editingInputFilter;
36 |
37 | id notEditingFormatter;
38 | id notEditingInputFilter;
39 | }
40 |
41 | - (instancetype)init
42 | {
43 | self = [super init];
44 |
45 | [self applyDefaultConfig];
46 |
47 | self.rawValue = @"";
48 |
49 | return self;
50 | }
51 |
52 | - (void)applyDefaultConfig
53 | {
54 | FTCTextEntryFormattingConfig *defaultConfig = [[FTCTextEntryFormattingConfig alloc] init];
55 | [self applyConfig:defaultConfig];
56 | }
57 |
58 | - (void)userReplacedInFormattedValueSubstringAtRange:(NSRange)range withString:(NSString *)replacement
59 | {
60 | assert( nil != replacement );
61 | assert( isEditing );
62 | assert( (nil != editingFormatter) && "'editingFormatter' must not be nil here." );
63 |
64 | NSRange replacementRangeInRawValue = [editingFormatter rangeInRawValueForRange:range inFormattedValue:_formattedValue];
65 |
66 | assert( (nil != _rawValue) || (nil == _rawValue && (replacementRangeInRawValue.location + replacementRangeInRawValue.length == 0)) );
67 |
68 | //фикс так как voice input добавляет пробел и не вызывает replacement
69 | replacementRangeInRawValue.location = MIN(_rawValue.length, replacementRangeInRawValue.location);
70 |
71 | FTCFilteredString *filteredRawString = [editingInputFilter replaceSubstringInString:(nil != _rawValue ? _rawValue : @"")
72 | atRange:replacementRangeInRawValue
73 | withString:replacement];
74 |
75 | assert( nil != filteredRawString.string );
76 |
77 | _rawValue = filteredRawString.string;
78 | [self doFormatValue];
79 |
80 | const NSRange filteredRange = filteredRawString.range;
81 | const NSUInteger lastInsertedCharacterLocation = filteredRange.location + filteredRange.length;
82 | currentSelectionRangeInRawValue = NSMakeRange(lastInsertedCharacterLocation, 0);
83 | _currentSelectionRangeInFormattedValue = [editingFormatter rangeInFormattedValueForRange:currentSelectionRangeInRawValue inRawValue:_rawValue];
84 | }
85 |
86 | - (void)beginEditing
87 | {
88 | assert( NO == isEditing );
89 | assert( (nil != editingFormatter) && "'editingFormatter' must not be nil here." );
90 |
91 | isEditing = YES;
92 |
93 | [self doFormatValue];
94 | [self moveCaretToTheEndOfRawValue];
95 | }
96 |
97 | - (void)moveCaretToTheEndOfRawValue
98 | {
99 | currentSelectionRangeInRawValue = NSMakeRange(_rawValue.length, 0);
100 |
101 | id currentFormatter = isEditing ? editingFormatter : notEditingFormatter;
102 | assert( (nil != currentFormatter) && "'currentFormatter' must not be nil here." );
103 |
104 | _currentSelectionRangeInFormattedValue = [currentFormatter rangeInFormattedValueForRange:currentSelectionRangeInRawValue inRawValue:_rawValue];
105 | }
106 |
107 | - (void)endEditing
108 | {
109 | assert( isEditing );
110 |
111 | isEditing = NO;
112 |
113 | _rawValue = [self filterValue:_rawValue];
114 |
115 | [self doFormatValue];
116 | }
117 |
118 | - (void)doFormatValue
119 | {
120 | id currentFormatter = isEditing ? editingFormatter : notEditingFormatter;
121 | assert( (nil != currentFormatter) && "'currentFormatter' must not be nil here." );
122 |
123 | _formattedValue = [currentFormatter formattedFromRaw:(nil != _rawValue ? _rawValue : @"")];
124 | }
125 |
126 | - (BOOL)isEditing
127 | {
128 | return isEditing;
129 | }
130 |
131 | - (void)setRawValue:(NSString *)rawValue
132 | {
133 | assert( NO == isEditing );
134 |
135 | [self doSetRawValue:rawValue];
136 | }
137 |
138 | - (void)applyConfig:(FTCTextEntryFormattingConfig *)config
139 | {
140 | assert( (nil != config) && "Argument 'config' must not be nil." );
141 | assert( (nil != config.editingFormatter) && "'config.editingFormatter' must not be nil here." );
142 | assert( (nil != config.editingInputFilter) && "'config.editingInputFilter' must not be nil here." );
143 | assert( (nil != config.notEditingFormatter) && "'config.notEditingFormatter' must not be nil here." );
144 | assert( (nil != config.notEditingInputFilter) && "'config.notEditingInputFilter' must not be nil here." );
145 |
146 | editingFormatter = config.editingFormatter;
147 | editingInputFilter = config.editingInputFilter;
148 |
149 | notEditingFormatter = config.notEditingFormatter;
150 | notEditingInputFilter = config.notEditingInputFilter;
151 |
152 | [self doSetRawValue:_rawValue];
153 | }
154 |
155 | - (void)doSetRawValue:(nullable NSString *)rawValue
156 | {
157 | _rawValue = [self filterValue:rawValue];
158 |
159 | [self doFormatValue];
160 | [self moveCaretToTheEndOfRawValue];
161 | }
162 |
163 | - (nullable NSString *)filterValue:(nullable NSString *)value
164 | {
165 | assert( (nil != notEditingInputFilter) && "'notEditingInputFilter' must not be nil here." );
166 |
167 | if( nil == value )
168 | {
169 | return value;
170 | }
171 |
172 | return [notEditingInputFilter filterString:value];
173 | }
174 |
175 | @end
176 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntryFormatCoordinatorHelper.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @class FTCTextEntryFormattingConfig;
22 | @protocol FTCTextEntry;
23 |
24 | NS_ASSUME_NONNULL_BEGIN
25 |
26 | @interface FTCTextEntryFormatCoordinatorHelper : NSObject
27 |
28 | @property (nonatomic, nullable, copy) void (^didChangeValueHandler)(void);
29 |
30 | @property (nonatomic, nullable, copy) NSString *rawValue;
31 |
32 | @property (nonatomic, readonly) NSString *formattedValue;
33 |
34 | - (instancetype)initWithUI:(id)textEntryUI;
35 |
36 | - (void)beginEditing;
37 | - (void)changeCharactersInRange:(NSRange)range replacement:(NSString *)replacement;
38 | - (void)endEditing;
39 |
40 | - (void)applyFormattingConfig:(FTCTextEntryFormattingConfig *)config NS_SWIFT_NAME( apply(formattingConfig:) );
41 |
42 | @end
43 |
44 | NS_ASSUME_NONNULL_END
45 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntryFormatCoordinatorHelper.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatCoordinatorHelper.h"
22 | #import "FTCTextEntryFormatCoordinator.h"
23 | #import "FTCTextEntryFormattingConfig.h"
24 | #import "FTCTextEntry.h"
25 |
26 | @interface FTCTextEntryFormatCoordinatorHelper ()
27 |
28 | @end
29 |
30 | @implementation FTCTextEntryFormatCoordinatorHelper
31 | {
32 | id __weak entryUI;
33 |
34 | FTCTextEntryFormatCoordinator *formatCoordinator;
35 |
36 | FTCTextEntryFormattingConfig *currentConfig;
37 | }
38 |
39 | - (instancetype)initWithUI:(id)anEntryUI
40 | {
41 | assert( nil != anEntryUI );
42 |
43 | self = [super init];
44 |
45 | entryUI = anEntryUI;
46 | formatCoordinator = [[FTCTextEntryFormatCoordinator alloc] init];
47 |
48 | return self;
49 | }
50 |
51 | - (NSString *)rawValue
52 | {
53 | return formatCoordinator.rawValue;
54 | }
55 |
56 | - (void)setRawValue:(NSString *)rawValue
57 | {
58 | BOOL shouldBecomeFirstResponder = NO;
59 | if( [formatCoordinator isEditing] )
60 | {
61 | shouldBecomeFirstResponder = YES;
62 | [formatCoordinator endEditing];
63 | }
64 | assert( NO == [formatCoordinator isEditing] );
65 |
66 | formatCoordinator.rawValue = [rawValue copy];
67 | entryUI.text = formatCoordinator.formattedValue;
68 |
69 | if( shouldBecomeFirstResponder )
70 | {
71 | [formatCoordinator beginEditing];
72 | }
73 | }
74 |
75 | - (NSString *)formattedValue
76 | {
77 | return formatCoordinator.formattedValue;
78 | }
79 |
80 | - (void)beginEditing
81 | {
82 | [self handleValueChange:^(FTCTextEntryFormatCoordinator *coordinator, id entry)
83 | {
84 | [coordinator beginEditing];
85 | entry.text = coordinator.formattedValue;
86 | entry.selectedTextRange = coordinator.currentSelectionRangeInFormattedValue;
87 | }];
88 | }
89 |
90 | - (void)changeCharactersInRange:(NSRange)range replacement:(NSString *)replacement
91 | {
92 | [self handleValueChange:^(FTCTextEntryFormatCoordinator *coordinator, id entry)
93 | {
94 | [coordinator userReplacedInFormattedValueSubstringAtRange:range withString:replacement];
95 | entry.text = coordinator.formattedValue;
96 | entry.selectedTextRange = coordinator.currentSelectionRangeInFormattedValue;
97 | }];
98 | }
99 |
100 | - (void)endEditing
101 | {
102 | [self handleValueChange:^(FTCTextEntryFormatCoordinator *coordinator, id entry)
103 | {
104 | [coordinator endEditing];
105 | entry.text = coordinator.formattedValue;
106 | }];
107 | }
108 |
109 | - (void)handleValueChange:(void(^)(FTCTextEntryFormatCoordinator *coordinator, id entry))valueChange
110 | {
111 | NSString *initialValue = formatCoordinator.rawValue;
112 |
113 | if( NULL != valueChange )
114 | {
115 | valueChange(formatCoordinator, entryUI);
116 | }
117 |
118 | if( NULL == _didChangeValueHandler )
119 | {
120 | return;
121 | }
122 |
123 | BOOL valueIsReallyChanged;
124 | if( (nil == initialValue) && (nil == formatCoordinator.rawValue) )
125 | {
126 | valueIsReallyChanged = NO;
127 | }
128 | else
129 | {
130 | valueIsReallyChanged = (NO == [initialValue isEqualToString:formatCoordinator.rawValue]);
131 | }
132 |
133 | if( valueIsReallyChanged )
134 | {
135 | _didChangeValueHandler();
136 | }
137 | }
138 |
139 | - (void)applyFormattingConfig:(FTCTextEntryFormattingConfig *)config
140 | {
141 | assert( nil != config );
142 |
143 | [formatCoordinator applyConfig:config];
144 |
145 | NSRange currentRange = entryUI.selectedTextRange;
146 | if( (NSNotFound != currentRange.location) && (0 != currentRange.location) && [config isEqualToConfig:currentConfig] )
147 | {
148 | formatCoordinator.currentSelectionRangeInFormattedValue = currentRange;
149 | }
150 |
151 | entryUI.text = formatCoordinator.formattedValue;
152 |
153 | entryUI.selectedTextRange = formatCoordinator.currentSelectionRangeInFormattedValue;
154 |
155 | currentConfig = config;
156 | }
157 |
158 | @end
159 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntryFormattingConfig.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @protocol FTCTextEntryFormatter;
22 | @protocol FTCTextEntryEditingInputFilter;
23 | @protocol FTCTextEntryNotEditingInputFilter;
24 |
25 | NS_ASSUME_NONNULL_BEGIN
26 |
27 | @interface FTCTextEntryFormattingConfig : NSObject
28 |
29 | @property (nonatomic, strong) id editingFormatter;
30 | @property (nonatomic, strong) id editingInputFilter;
31 |
32 | @property (nonatomic, strong) id notEditingFormatter;
33 | @property (nonatomic, strong) id notEditingInputFilter;
34 |
35 | - (BOOL)isEqualToConfig:(FTCTextEntryFormattingConfig *)config;
36 |
37 | - (instancetype)init NS_DESIGNATED_INITIALIZER;
38 |
39 | - (instancetype)initWithFormatter:(id)formatter
40 | inputFilter:(id)inputFilter;
41 |
42 | @end
43 |
44 | NS_ASSUME_NONNULL_END
45 |
--------------------------------------------------------------------------------
/Src/Core/FTCTextEntryFormattingConfig.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormattingConfig.h"
22 | #import "FTCNoFormattingFormatter.h"
23 | #import "FTCNoFilteringFilter.h"
24 |
25 | @implementation FTCTextEntryFormattingConfig
26 |
27 | - (instancetype)init
28 | {
29 | self = [super init];
30 |
31 | _editingFormatter = [[FTCNoFormattingFormatter alloc] init];
32 | _editingInputFilter = [[FTCNoFilteringFilter alloc] init];
33 |
34 | _notEditingFormatter = [[FTCNoFormattingFormatter alloc] init];
35 | _notEditingInputFilter = [[FTCNoFilteringFilter alloc] init];
36 |
37 | return self;
38 | }
39 |
40 | - (instancetype)initWithFormatter:(id)formatter
41 | inputFilter:(id)inputFilter
42 | {
43 | self = [self init];
44 |
45 | _editingFormatter = formatter;
46 | _editingInputFilter = inputFilter;
47 |
48 | _notEditingFormatter = formatter;
49 | _notEditingInputFilter = inputFilter;
50 |
51 | return self;
52 | }
53 |
54 | - (void)setEditingFormatter:(id)editingFormatter
55 | {
56 | assert( (nil != editingFormatter) && "Argument 'editingFormatter' must not be nil." );
57 |
58 | _editingFormatter = editingFormatter;
59 | }
60 |
61 | - (void)setEditingInputFilter:(id)editingInputFilter
62 | {
63 | assert( (nil != editingInputFilter) && "Argument 'editingInputFilter' must not be nil." );
64 |
65 | _editingInputFilter = editingInputFilter;
66 | }
67 |
68 | - (void)setNotEditingFormatter:(id)notEditingFormatter
69 | {
70 | assert( (nil != notEditingFormatter) && "Argument 'notEditingFormatter' must not be nil." );
71 |
72 | _notEditingFormatter = notEditingFormatter;
73 | }
74 |
75 | - (void)setNotEditingInputFilter:(id)notEditingInputFilter
76 | {
77 | assert( (nil != notEditingInputFilter) && "Argument 'notEditingInputFilter' must not be nil." );
78 |
79 | _notEditingInputFilter = notEditingInputFilter;
80 | }
81 |
82 | - (BOOL)isEqualToConfig:(FTCTextEntryFormattingConfig *)config
83 | {
84 | if( nil == config )
85 | {
86 | return NO;
87 | }
88 |
89 | BOOL editingFormatterEquality = [self.editingFormatter isEqual:config.editingFormatter];
90 | BOOL editingInputFormatterEquality = [self.editingInputFilter isEqual:config.editingInputFilter];
91 | BOOL notEditingFormatterEquality = [self.notEditingFormatter isEqual:config.notEditingFormatter];
92 | BOOL notEditingInputFormatterEquality = [self.notEditingInputFilter isEqual:config.notEditingInputFilter];
93 |
94 | return editingFormatterEquality && editingInputFormatterEquality && notEditingFormatterEquality && notEditingInputFormatterEquality;
95 | }
96 |
97 | @end
98 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/FTCNoFormattingFormatter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCNoFormattingFormatter : NSObject
26 |
27 | - (instancetype)init;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/FTCNoFormattingFormatter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCNoFormattingFormatter.h"
22 |
23 | @implementation FTCNoFormattingFormatter
24 |
25 | - (instancetype)init
26 | {
27 | self = [super init];
28 |
29 | return self;
30 | }
31 |
32 | - (NSString *)rawFromFormatted:(NSString *)formattedValue
33 | {
34 | return formattedValue;
35 | }
36 |
37 | - (NSString *)formattedFromRaw:(NSString *)rawValue
38 | {
39 | return rawValue;
40 | }
41 |
42 | - (NSRange)rangeInFormattedValueForRange:(NSRange)rangeInRawValue inRawValue:(NSString *)rawValue
43 | {
44 | return rangeInRawValue;
45 | }
46 |
47 | - (NSRange)rangeInRawValueForRange:(NSRange)rangeInFormattedValue inFormattedValue:(NSString *)formattedValue
48 | {
49 | return rangeInFormattedValue;
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/FTCTextEntryFormatter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | @protocol FTCTextEntryFormatter
24 |
25 | - (NSString *)rawFromFormatted:(nullable NSString *)formattedValue;
26 | - (NSString *)formattedFromRaw:(nullable NSString *)rawValue;
27 |
28 | - (NSRange)rangeInFormattedValueForRange:(NSRange)rangeInRawValue inRawValue:(nullable NSString *)rawValue;
29 | - (NSRange)rangeInRawValueForRange:(NSRange)rangeInFormattedValue inFormattedValue:(nullable NSString *)formattedValue;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/MaskFormatter/FTCMaskFormatter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatter.h"
22 |
23 | @protocol FTCMaskFormatterConfig;
24 |
25 | NS_ASSUME_NONNULL_BEGIN
26 |
27 | @interface FTCMaskFormatter : NSObject
28 |
29 | - (instancetype)initWithConfig:(id)config NS_DESIGNATED_INITIALIZER;
30 |
31 | - (instancetype)init NS_UNAVAILABLE;
32 |
33 | @end
34 |
35 | NS_ASSUME_NONNULL_END
36 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/MaskFormatter/FTCMaskFormatter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMaskFormatter.h"
22 | #import "FTCMaskFormatterConfig.h"
23 | #import "FTCTextEntryFormattingStringUtils.h"
24 |
25 | @implementation FTCMaskFormatter
26 | {
27 | id config;
28 | }
29 |
30 | - (instancetype)initWithConfig:(id)aConfig
31 | {
32 | assert( nil != aConfig );
33 |
34 | self = [super init];
35 |
36 | config = aConfig;
37 |
38 | return self;
39 | }
40 |
41 | - (NSString *)rawFromFormatted:(NSString *)formattedValue
42 | {
43 | return [self rawValueStringFromFormattedString:formattedValue
44 | inFormattedRange:NSMakeRange(0, formattedValue.length)];
45 | }
46 |
47 | - (NSString *)formattedFromRaw:(NSString *)rawValue
48 | {
49 | NSString * const mask = config.mask;
50 |
51 | if( (FTCMaskFormatterConfigTailModeCutAndForceHead == config.tailMode) && (rawValue.length == 0) )
52 | {
53 | NSString *maskCharacterString = [FTCTextEntryFormattingStringUtils stringWithCharacter:config.maskCharacter];
54 | return [config.mask substringToIndex:[config.mask rangeOfString:maskCharacterString].location];
55 | }
56 |
57 | NSMutableString *formattedValue = [[NSMutableString alloc] initWithCapacity:mask.length];
58 |
59 | for( NSUInteger indexInFormat = 0, indexInRawValue = 0; indexInFormat < mask.length; ++indexInFormat )
60 | {
61 | if( ((FTCMaskFormatterConfigTailModeCutAndForceHead == config.tailMode) || (FTCMaskFormatterConfigTailModeCut == config.tailMode))
62 | && indexInRawValue == rawValue.length )
63 | {
64 | break;
65 | }
66 |
67 | if( config.maskCharacter != [mask characterAtIndex:indexInFormat] || indexInRawValue >= rawValue.length )
68 | {
69 | unichar c = [mask characterAtIndex:indexInFormat];
70 | [formattedValue appendString:[FTCTextEntryFormattingStringUtils stringWithCharacter:c]];
71 | }
72 | else
73 | {
74 | unichar c = [rawValue characterAtIndex:indexInRawValue++];
75 | [formattedValue appendString:[FTCTextEntryFormattingStringUtils stringWithCharacter:c]];
76 | }
77 | }
78 |
79 | return [formattedValue copy];
80 | }
81 |
82 | - (NSRange)rangeInFormattedValueForRange:(NSRange)rangeInRawValue inRawValue:(NSString *)rawValue
83 | {
84 | assert( (rawValue.length >= rangeInRawValue.location + rangeInRawValue.length) && "Argument 'rangeInRawValue' is out of bounds of 'rawValue'" );
85 |
86 | if( 0 == rangeInRawValue.location )
87 | {
88 | /*
89 | * Если начало, то ставим каретку спереди первого raw-символа
90 | */
91 | NSUInteger numberOfFirstRawSymbolInRange = 1;
92 | NSUInteger numberOfLastRawSymbolInRange = rangeInRawValue.length + 1;
93 |
94 | NSUInteger position = [self positionOfRawSymbolInFormattedValue:numberOfFirstRawSymbolInRange];
95 | NSUInteger positionLast = [self positionOfRawSymbolInFormattedValue:numberOfLastRawSymbolInRange];
96 |
97 | return NSMakeRange(position, positionLast - position);
98 | }
99 | else
100 | {
101 | /*
102 | * Если не начало, то ставим каретку позади предыдущего raw-символа
103 | */
104 | NSUInteger numberOfFirstRawSymbolInRange = rangeInRawValue.location;
105 | NSUInteger numberOfLastRawSymbolInRange = (rangeInRawValue.location + rangeInRawValue.length);
106 |
107 | NSUInteger position = [self positionOfRawSymbolInFormattedValue:numberOfFirstRawSymbolInRange] + 1;
108 | NSUInteger positionLast = [self positionOfRawSymbolInFormattedValue:numberOfLastRawSymbolInRange] + 1;
109 |
110 | return NSMakeRange(position, positionLast - position);
111 | }
112 | }
113 |
114 | - (NSRange)rangeInRawValueForRange:(NSRange)rangeInFormattedValue
115 | inFormattedValue:(NSString *)formattedValue
116 | {
117 | NSUInteger symbolsToLocation = [self countOfRawSymbolsInFormattedString:formattedValue
118 | inRange:NSMakeRange(0, rangeInFormattedValue.location)];
119 |
120 | NSUInteger symbolsInRange = [self countOfRawSymbolsInFormattedString:formattedValue
121 | inRange:rangeInFormattedValue];
122 |
123 | return NSMakeRange(symbolsToLocation, symbolsInRange);
124 | }
125 |
126 | - (NSUInteger)positionOfRawSymbolInFormattedValue:(const NSUInteger)rawNumber
127 | {
128 | NSUInteger position = 0;
129 |
130 | NSUInteger currentPosition = 0;
131 |
132 | for( NSUInteger i = 0; i < config.mask.length; ++i )
133 | {
134 | if( config.maskCharacter != [config.mask characterAtIndex:i] )
135 | {
136 | continue;
137 | }
138 |
139 | ++currentPosition;
140 |
141 | position = i;
142 |
143 | if( rawNumber == currentPosition )
144 | {
145 | break;
146 | }
147 | }
148 |
149 | return position;
150 | }
151 |
152 | - (nonnull NSString *)rawValueStringFromFormattedString:(nullable NSString *const)formattedString
153 | inFormattedRange:(const NSRange)range
154 | {
155 | NSString * const mask = config.mask;
156 |
157 | NSMutableString *rawString = [[NSMutableString alloc] init];
158 |
159 | for( NSUInteger i = range.location; (i < range.location + range.length) && (i < formattedString.length); ++i )
160 | {
161 | if ( config.maskCharacter == [mask characterAtIndex:i] && config.maskCharacter != [formattedString characterAtIndex:i] )
162 | {
163 | unichar c = [formattedString characterAtIndex:i];
164 | [rawString appendString:[FTCTextEntryFormattingStringUtils stringWithCharacter:c]];
165 | }
166 | }
167 |
168 | return [rawString copy];
169 | }
170 |
171 | - (NSUInteger)countOfRawSymbolsInFormattedString:(nullable NSString *const)formattedString
172 | inRange:(const NSRange)range
173 | {
174 | NSString *rawString = [self rawValueStringFromFormattedString:formattedString
175 | inFormattedRange:range];
176 | return rawString.length;
177 | }
178 |
179 | - (instancetype)init
180 | {
181 | assert( false && "Won't happen" );
182 | return nil;
183 | }
184 |
185 | @end
186 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/MaskFormatter/FTCMaskFormatterConfig.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | typedef NS_ENUM(NSInteger, FTCMaskFormatterConfigTailMode)
24 | {
25 | FTCMaskFormatterConfigTailModeNone = 0,
26 | FTCMaskFormatterConfigTailModeCut,
27 | FTCMaskFormatterConfigTailModeCutAndForceHead
28 | };
29 |
30 | @protocol FTCMaskFormatterConfig
31 |
32 | @property (nonatomic, readonly) NSString *mask;
33 | @property (nonatomic, readonly) unichar maskCharacter;
34 | @property (nonatomic, readonly) NSUInteger countMaskCharacters;
35 | @property (nonatomic, readonly) FTCMaskFormatterConfigTailMode tailMode;
36 |
37 | @end
38 |
39 | NS_ASSUME_NONNULL_END
40 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/MaskFormatter/FTCMaskFormatterGenericConfig.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMaskFormatterConfig.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCMaskFormatterGenericConfig : NSObject
26 |
27 | @property (nonatomic, readwrite) FTCMaskFormatterConfigTailMode tailMode; // default FTCMaskFormatterConfigTailModeNone
28 |
29 | - (instancetype)initWithMask:(NSString *)mask maskCharacter:(NSString *)maskCharacter NS_DESIGNATED_INITIALIZER;
30 |
31 | - (instancetype)init NS_UNAVAILABLE;
32 |
33 | @end
34 |
35 | NS_ASSUME_NONNULL_END
36 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/MaskFormatter/FTCMaskFormatterGenericConfig.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMaskFormatterGenericConfig.h"
22 |
23 | @implementation FTCMaskFormatterGenericConfig
24 |
25 | @synthesize mask = _mask;
26 | @synthesize maskCharacter = _maskCharacter;
27 | @synthesize countMaskCharacters = _countMaskCharacters;
28 |
29 | - (instancetype)initWithMask:(NSString *)mask maskCharacter:(NSString *)maskCharacter
30 | {
31 | assert( nil != mask );
32 | assert( maskCharacter.length == 1 );
33 |
34 | self = [super init];
35 |
36 | _mask = mask;
37 | _maskCharacter = [maskCharacter characterAtIndex:0];
38 | _tailMode = FTCMaskFormatterConfigTailModeNone;
39 |
40 | NSUInteger countMaskCharacters = 0;
41 | for( NSUInteger i = 0; i < _mask.length; ++i )
42 | {
43 | if( [_mask characterAtIndex:i] == _maskCharacter )
44 | {
45 | ++countMaskCharacters;
46 | }
47 | }
48 |
49 | _countMaskCharacters = countMaskCharacters;
50 |
51 | return self;
52 | }
53 |
54 | - (instancetype)init
55 | {
56 | assert( false && "Won't happen" );
57 | return nil;
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/PostfixFormatter/FTCPostfixFormatter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCPostfixFormatter : NSObject
26 |
27 | @property (nonatomic, nullable, readonly) NSString *postfix;
28 |
29 | - (instancetype)initWithPostfix:(nullable NSString *)postfix;
30 |
31 | - (instancetype)init NS_UNAVAILABLE;
32 |
33 | @end
34 |
35 | NS_ASSUME_NONNULL_END
36 |
--------------------------------------------------------------------------------
/Src/Core/Formatting/PostfixFormatter/FTCPostfixFormatter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCPostfixFormatter.h"
22 |
23 | @implementation FTCPostfixFormatter
24 |
25 | - (instancetype)init
26 | {
27 | assert(false && "Won't happen");
28 | return nil;
29 | }
30 |
31 | - (instancetype)initWithPostfix:(NSString *)postfix
32 | {
33 | self = [super init];
34 |
35 | _postfix = postfix;
36 |
37 | return self;
38 | }
39 |
40 | - (NSString *)rawFromFormatted:(NSString *)formattedValue
41 | {
42 | if( NO == [self canShowPostfix] )
43 | {
44 | return formattedValue;
45 | }
46 |
47 | NSString *result = formattedValue;
48 |
49 | if(result.length >= _postfix.length)
50 | {
51 | NSString *const possiblePostfix = [result substringFromIndex:result.length - _postfix.length];
52 |
53 | if([possiblePostfix isEqualToString:_postfix])
54 | {
55 | result = [result substringToIndex:result.length - _postfix.length];
56 | }
57 | }
58 |
59 | return result;
60 | }
61 |
62 | - (NSString *)formattedFromRaw:(NSString *)rawValue
63 | {
64 | NSString *result = (rawValue != nil ? rawValue : @"");
65 |
66 | if( NO == [self canShowPostfix] )
67 | {
68 | return result;
69 | }
70 |
71 | return [result stringByAppendingString:_postfix];
72 | }
73 |
74 | - (NSRange)rangeInFormattedValueForRange:(NSRange)rangeInRawValue inRawValue:(NSString *)rawValue
75 | {
76 | assert( (rawValue.length >= rangeInRawValue.location + rangeInRawValue.length) && "Argument 'rangeInRawValue' is out of bounds of 'rawValue'" );
77 |
78 | return rangeInRawValue;
79 | }
80 |
81 | - (NSRange)rangeInRawValueForRange:(NSRange)rangeInFormattedValue inFormattedValue:(NSString *)formattedValue
82 | {
83 | assert( (formattedValue.length >= rangeInFormattedValue.location + rangeInFormattedValue.length) && "Argument 'rangeInFormattedValue' is out of bounds of 'formattedValue'" );
84 |
85 | NSRange rawRange = rangeInFormattedValue;
86 |
87 | if( [self canShowPostfix] )
88 | {
89 | NSRange postfixRange = [formattedValue rangeOfString:_postfix];
90 | if( NSNotFound != postfixRange.location )
91 | {
92 | if( rawRange.location > postfixRange.location )
93 | {
94 | rawRange.location = postfixRange.location;
95 | }
96 |
97 | if( (rawRange.location + rawRange.length) > postfixRange.location )
98 | {
99 | NSInteger exceedingLength = (rawRange.location + rawRange.length) - postfixRange.location;
100 |
101 | rawRange.length = rawRange.length - exceedingLength;
102 | }
103 | }
104 | }
105 |
106 | return rawRange;
107 | }
108 |
109 | - (BOOL)canShowPostfix
110 | {
111 | if( nil == _postfix || 0 == _postfix.length )
112 | {
113 | return NO;
114 | }
115 |
116 | return YES;
117 | }
118 |
119 | @end
120 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/DigitsValueFilter/FTCDigitsValueFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryEditingInputFilter.h"
22 | #import "FTCTextEntryNotEditingInputFilter.h"
23 |
24 | NS_ASSUME_NONNULL_BEGIN
25 |
26 | @interface FTCDigitsValueFilter : NSObject
27 |
28 | @property (nonatomic, readonly) NSUInteger maxLength;
29 |
30 | - (instancetype)initWithMaxLength:(NSUInteger)length;//set '0' for infinite length
31 |
32 | - (instancetype)init NS_UNAVAILABLE;
33 |
34 | @end
35 |
36 | NS_ASSUME_NONNULL_END
37 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/DigitsValueFilter/FTCDigitsValueFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCDigitsValueFilter.h"
22 | #import "FTCFilteredString.h"
23 | #import "FTCTextEntryFormattingStringUtils.h"
24 |
25 | @implementation FTCDigitsValueFilter
26 |
27 | - (instancetype)initWithMaxLength:(NSUInteger)aLength
28 | {
29 | self = [super init];
30 |
31 | _maxLength = aLength;
32 |
33 | return self;
34 | }
35 |
36 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement shouldTrim:(BOOL)shouldTrim
37 | {
38 | assert( (nil != originalString) && "Argument 'originalString' must not be nil." );
39 | assert( (nil != replacement) && "Argument 'replacement' must not be nil." );
40 |
41 | NSString *filteredReplacement = [FTCTextEntryFormattingStringUtils stringWithDecimalDigitsFromString:replacement];
42 |
43 | NSString *filteredString = [originalString stringByReplacingCharactersInRange:range withString:filteredReplacement];
44 |
45 | if( shouldTrim && (filteredString.length > _maxLength) && (0 != _maxLength) )
46 | {
47 | filteredString = [filteredString substringToIndex:_maxLength];
48 | }
49 |
50 | if( 0 == _maxLength || filteredString.length <= _maxLength )
51 | {
52 | return [[FTCFilteredString alloc] initWithString:filteredString range:NSMakeRange(range.location, filteredReplacement.length)];
53 | }
54 | else
55 | {
56 | return [[FTCFilteredString alloc] initWithString:originalString range:NSMakeRange(range.location, 0)];
57 | }
58 | }
59 |
60 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement
61 | {
62 | return [self replaceSubstringInString:originalString atRange:range withString:replacement shouldTrim:NO];
63 | }
64 |
65 | - (NSString *)filterString:(NSString *)string
66 | {
67 | assert( nil != string );
68 |
69 | return [self replaceSubstringInString:@"" atRange:NSMakeRange(0, 0) withString:string shouldTrim:YES].string;
70 | }
71 |
72 | - (instancetype)init
73 | {
74 | assert( NO );
75 | return nil;
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/FTCFilteredString.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | @interface FTCFilteredString : NSObject
24 |
25 | @property (nonatomic, readonly) NSString *string;
26 | @property (nonatomic, readonly) NSRange range;
27 |
28 | - (instancetype)initWithString:(NSString *)string range:(NSRange)range;
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/FTCFilteredString.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCFilteredString.h"
22 |
23 | @implementation FTCFilteredString
24 |
25 | - (instancetype)initWithString:(NSString *)string range:(NSRange)range
26 | {
27 | self = [super init];
28 |
29 | _string = string;
30 | _range = range;
31 |
32 | return self;
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/FTCNoFilteringFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryEditingInputFilter.h"
22 | #import "FTCTextEntryNotEditingInputFilter.h"
23 |
24 | NS_ASSUME_NONNULL_BEGIN
25 |
26 | @interface FTCNoFilteringFilter : NSObject
27 |
28 | - (instancetype)init;
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/FTCNoFilteringFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCNoFilteringFilter.h"
22 | #import "FTCFilteredString.h"
23 |
24 | @implementation FTCNoFilteringFilter
25 |
26 | - (instancetype)init
27 | {
28 | self = [super init];
29 |
30 | return self;
31 | }
32 |
33 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement
34 | {
35 | assert( (nil != originalString) && "Argument 'originalString' must not be nil." );
36 | assert( (nil != replacement) && "Argument 'replacement' must not be nil." );
37 |
38 | NSString *resultString = [originalString stringByReplacingCharactersInRange:range withString:replacement];
39 | const NSRange resultRange = NSMakeRange(range.location, replacement.length);
40 |
41 | return [[FTCFilteredString alloc] initWithString:resultString range:resultRange];
42 | }
43 |
44 | - (NSString *)filterString:(NSString *)string
45 | {
46 | return string;
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/FTCTextEntryEditingInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @class FTCFilteredString;
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @protocol FTCTextEntryEditingInputFilter
26 |
27 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString
28 | atRange:(NSRange)range
29 | withString:(NSString *)replacement;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/FTCTextEntryNotEditingInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import Foundation;
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @protocol FTCTextEntryNotEditingInputFilter
26 |
27 | - (NSString *)filterString:(NSString *)string;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/LimitedLengthInputFilter/FTCLimitedLengthInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryEditingInputFilter.h"
22 | #import "FTCTextEntryNotEditingInputFilter.h"
23 |
24 | NS_ASSUME_NONNULL_BEGIN
25 |
26 | @interface FTCLimitedLengthInputFilter : NSObject
27 |
28 | - (instancetype)initWithMaximumLength:(NSUInteger)maximumLength NS_DESIGNATED_INITIALIZER;
29 | - (instancetype)init NS_UNAVAILABLE;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/LimitedLengthInputFilter/FTCLimitedLengthInputFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCLimitedLengthInputFilter.h"
22 | #import "FTCFilteredString.h"
23 |
24 | @implementation FTCLimitedLengthInputFilter
25 | {
26 | NSUInteger maxLength;
27 | }
28 |
29 | - (instancetype)init
30 | {
31 | assert( false && "Won't happen" );
32 | return nil;
33 | }
34 |
35 | - (instancetype)initWithMaximumLength:(NSUInteger)maximumLength
36 | {
37 | self = [super init];
38 |
39 | maxLength = maximumLength;
40 |
41 | return self;
42 | }
43 |
44 | - (NSString *)trimmedString:(NSString *)string
45 | {
46 | assert( nil != string && "String must not be nil" );
47 |
48 | if( string.length > maxLength )
49 | {
50 | return [string substringToIndex:maxLength];
51 | }
52 |
53 | return string;
54 | }
55 |
56 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement
57 | {
58 | assert( (nil != originalString) && "Argument 'originalString' must not be nil." );
59 | assert( (nil != replacement) && "Argument 'replacement' must not be nil." );
60 |
61 | NSString *replacedString = [originalString stringByReplacingCharactersInRange:range withString:replacement];;
62 |
63 | if( replacedString.length <= maxLength )
64 | {
65 | NSRange resultRange = NSMakeRange(range.location, replacement.length);
66 | return [[FTCFilteredString alloc] initWithString:replacedString range:resultRange];
67 | }
68 |
69 | NSString *trimmedString = [self trimmedString:originalString];
70 |
71 | return [[FTCFilteredString alloc] initWithString:trimmedString range:NSMakeRange(range.location, 0)];
72 | }
73 |
74 | - (NSString *)filterString:(NSString *)string
75 | {
76 | assert( nil != string );
77 |
78 | return [self trimmedString:string];
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/ToUpperCaseInputFilter/FTCToUpperCaseInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryEditingInputFilter.h"
22 | #import "FTCTextEntryNotEditingInputFilter.h"
23 |
24 | NS_ASSUME_NONNULL_BEGIN
25 |
26 | @interface FTCToUpperCaseInputFilter : NSObject
27 |
28 | - (instancetype)init;
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/Src/Core/InputFiltering/ToUpperCaseInputFilter/FTCToUpperCaseInputFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCToUpperCaseInputFilter.h"
22 | #import "FTCFilteredString.h"
23 |
24 | @implementation FTCToUpperCaseInputFilter
25 |
26 | - (instancetype)init
27 | {
28 | self = [super init];
29 |
30 | return self;
31 | }
32 |
33 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement
34 | {
35 | assert( (nil != originalString) && "Argument 'originalString' must not be nil." );
36 | assert( (nil != replacement) && "Argument 'replacement' must not be nil." );
37 |
38 | NSString * const upperCaseReplacement = [replacement uppercaseString];
39 |
40 | NSString * const resultString = [originalString stringByReplacingCharactersInRange:range withString:upperCaseReplacement];
41 | const NSRange resultRange = NSMakeRange(range.location, upperCaseReplacement.length);
42 |
43 | return [[FTCFilteredString alloc] initWithString:resultString range:resultRange];
44 | }
45 |
46 | - (NSString *)filterString:(NSString *)string
47 | {
48 | assert( nil != string );
49 |
50 | return [string uppercaseString];
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/Src/FTCTextEntryFormatting.h:
--------------------------------------------------------------------------------
1 | #import "FTCMoneyEntryNotEditingInputFilter.h"
2 | #import "FTCMoneyEntryNotEditingFormatter.h"
3 | #import "FTCFilteredString.h"
4 | #import "FTCMoneyEntryFormatUtils.h"
5 | #import "FTCTextEntry.h"
6 | #import "FTCMaskFormatterGenericConfig.h"
7 | #import "FTCLimitedLengthInputFilter.h"
8 | #import "FTCMoneyEntryEditingFormatter.h"
9 | #import "FTCMaskFormatter.h"
10 | #import "FTCMoneyEntryEditingInputFilter.h"
11 | #import "FTCMaskFormatterConfig.h"
12 | #import "FTCIntegralMoneyAmountEntryNotEditingInputFilter.h"
13 | #import "FTCNoFilteringFilter.h"
14 | #import "FTCTextEntryFormattingConfig.h"
15 | #import "FTCTextEntryFormattingConfigFactory.h"
16 | #import "FTCTextEntryNotEditingInputFilter.h"
17 | #import "FTCTextInputUtils.h"
18 | #import "FTCDigitsValueFilter.h"
19 | #import "FTCNoFormattingFormatter.h"
20 | #import "FTCTextEntryEditingInputFilter.h"
21 | #import "FTCTextEntryFormatCoordinatorHelper.h"
22 | #import "FTCIntegralMoneyAmountEntryEditingInputFilter.h"
23 | #import "FTCTextEntryFormatCoordinator.h"
24 | #import "FTCTextEntryFormatting.h"
25 | #import "FTCTextEntryFormatter.h"
26 | #import "FTCPostfixFormatter.h"
27 | #import "FTCToUpperCaseInputFilter.h"
28 | #import "FTCTextFieldFormatCoordinator.h"
29 |
--------------------------------------------------------------------------------
/Src/FTCTextEntryFormattingConfigFactory.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatting.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @class FTCTextEntryFormattingConfig;
26 |
27 | @interface FTCTextEntryFormattingConfigFactory : NSObject
28 |
29 | + (FTCTextEntryFormattingConfig *)mobilePhoneConfigWithMask:(NSString *)mask
30 | maskChar:(NSString *)maskChar NS_SWIFT_NAME( mobilePhoneConfig(with:maskChar:) );
31 | + (FTCTextEntryFormattingConfig *)mobilePhoneConfigWithMask:(NSString *)mask
32 | maskChar:(NSString *)maskChar
33 | tailMode:(FTCMaskFormatterConfigTailMode)tailMode NS_SWIFT_NAME( mobilePhoneConfig(with:maskChar:tailMode:) );
34 |
35 | + (FTCTextEntryFormattingConfig *)moneyConfigWithCurrency:(nullable NSString *)currency
36 | onlyIntegral:(BOOL)onlyIntegral NS_SWIFT_NAME( moneyConfig(with:onlyIntegral:) );
37 |
38 | - (instancetype)init NS_UNAVAILABLE;
39 |
40 | @end
41 |
42 | NS_ASSUME_NONNULL_END
43 |
--------------------------------------------------------------------------------
/Src/FTCTextEntryFormattingConfigFactory.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormattingConfigFactory.h"
22 | #import "FTCTextEntryFormattingConfig.h"
23 | #import "FTCMaskFormatterGenericConfig.h"
24 | #import "FTCMaskFormatter.h"
25 | #import "FTCDigitsValueFilter.h"
26 | #import "FTCMoneyEntryNotEditingFormatter.h"
27 | #import "FTCMoneyEntryEditingFormatter.h"
28 | #import "FTCMoneyEntryNotEditingInputFilter.h"
29 | #import "FTCMoneyEntryEditingInputFilter.h"
30 | #import "FTCIntegralMoneyAmountEntryNotEditingInputFilter.h"
31 | #import "FTCIntegralMoneyAmountEntryEditingInputFilter.h"
32 |
33 | @implementation FTCTextEntryFormattingConfigFactory
34 |
35 | + (FTCTextEntryFormattingConfig *)mobilePhoneConfigWithMask:(NSString *)mask maskChar:(NSString *)maskChar
36 | {
37 | return [self mobilePhoneConfigWithMask:mask maskChar:maskChar tailMode:FTCMaskFormatterConfigTailModeNone];
38 | }
39 |
40 | + (FTCTextEntryFormattingConfig *)mobilePhoneConfigWithMask:(NSString *)mask maskChar:(NSString *)maskChar tailMode:(FTCMaskFormatterConfigTailMode)tailMode
41 | {
42 | __auto_type maskConfig = [[FTCMaskFormatterGenericConfig alloc] initWithMask:mask maskCharacter:maskChar];
43 | maskConfig.tailMode = tailMode;
44 |
45 | __auto_type maskFormatter = [[FTCMaskFormatter alloc] initWithConfig:maskConfig];
46 | __auto_type inputFilter = [[FTCDigitsValueFilter alloc] initWithMaxLength:maskConfig.countMaskCharacters];
47 |
48 | __auto_type formattingConfig = [[FTCTextEntryFormattingConfig alloc] init];
49 |
50 | formattingConfig.editingInputFilter = inputFilter;
51 | formattingConfig.editingFormatter = maskFormatter;
52 | formattingConfig.notEditingInputFilter = inputFilter;
53 | formattingConfig.notEditingFormatter = maskFormatter;
54 |
55 | return formattingConfig;
56 | }
57 |
58 | + (FTCTextEntryFormattingConfig *)moneyConfigWithCurrency:(nullable NSString *)currency onlyIntegral:(BOOL)onlyIntegral
59 | {
60 | __auto_type formattingConfig = [[FTCTextEntryFormattingConfig alloc] init];
61 |
62 | formattingConfig.notEditingFormatter = [[FTCMoneyEntryNotEditingFormatter alloc] initWithCurrency:currency];
63 | formattingConfig.editingFormatter = [[FTCMoneyEntryEditingFormatter alloc] initWithCurrency:currency];
64 |
65 | if( onlyIntegral )
66 | {
67 | formattingConfig.notEditingInputFilter = [[FTCIntegralMoneyAmountEntryNotEditingInputFilter alloc] init];
68 | formattingConfig.editingInputFilter = [[FTCIntegralMoneyAmountEntryEditingInputFilter alloc] init];
69 | }
70 | else
71 | {
72 | formattingConfig.notEditingInputFilter = [[FTCMoneyEntryNotEditingInputFilter alloc] init];
73 | formattingConfig.editingInputFilter = [[FTCMoneyEntryEditingInputFilter alloc] init];
74 | }
75 |
76 | return formattingConfig;
77 | }
78 |
79 | - (instancetype)init
80 | {
81 | assert( NO );
82 | return nil;
83 | }
84 |
85 | @end
86 |
--------------------------------------------------------------------------------
/Src/FTCTextFieldFormatCoordinator.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import UIKit;
22 |
23 | @class FTCTextEntryFormattingConfig;
24 |
25 | NS_ASSUME_NONNULL_BEGIN
26 |
27 | @interface FTCTextFieldFormatCoordinator : NSObject
28 |
29 | @property (nonatomic, weak) id textFieldDelegate;
30 |
31 | @property (nonatomic, nullable, copy) void (^didChangeValueHandler)(void);
32 | @property (nonatomic, nullable, copy) NSString *rawValue;
33 | @property (nonatomic, readonly) NSString *formattedValue;
34 |
35 | /*!
36 | * Устанавливает delegate у textField. Используйте поле textFieldDelegate если необходим delegate.
37 | * Если textField уже имеет delegate, то он будет установлен в поле textFieldDelegate.
38 | **/
39 | - (instancetype)initWithTextField:(UITextField *)textField;
40 |
41 | - (void)applyFormattingConfig:(FTCTextEntryFormattingConfig *)config NS_SWIFT_NAME( apply(formattingConfig:) );
42 |
43 | - (instancetype)init NS_UNAVAILABLE;
44 |
45 | @end
46 |
47 | NS_ASSUME_NONNULL_END
48 |
--------------------------------------------------------------------------------
/Src/FTCTextFieldFormatCoordinator.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextFieldFormatCoordinator.h"
22 | #import "FTCTextEntry.h"
23 | #import "FTCTextInputUtils.h"
24 | #import "FTCTextEntryFormatCoordinatorHelper.h"
25 | #import "FTCTextEntryFormattingConfig.h"
26 |
27 | @interface FTCTextFieldFormatCoordinator()
28 | {
29 | UITextField * __weak textField;
30 |
31 | FTCTextEntryFormatCoordinatorHelper *formatCoordinatorHelper;
32 | }
33 |
34 | @end
35 |
36 | @implementation FTCTextFieldFormatCoordinator
37 |
38 | - (instancetype)initWithTextField:(UITextField *)aTextField
39 | {
40 | assert(aTextField != nil);
41 |
42 | self = [super init];
43 |
44 | textField = aTextField;
45 |
46 | _textFieldDelegate = textField.delegate;
47 | textField.delegate = self;
48 |
49 | formatCoordinatorHelper = [[FTCTextEntryFormatCoordinatorHelper alloc] initWithUI:self];
50 |
51 | return self;
52 | }
53 |
54 | // MARK: Public
55 |
56 | - (void)setDidChangeValueHandler:(void (^)(void))didChangeValueHandler
57 | {
58 | [formatCoordinatorHelper setDidChangeValueHandler: didChangeValueHandler];
59 | }
60 |
61 | - (void (^)(void))didChangeValueHandler
62 | {
63 | return [formatCoordinatorHelper didChangeValueHandler];
64 | }
65 |
66 | - (void)setRawValue:(NSString *)rawValue
67 | {
68 | [formatCoordinatorHelper setRawValue:rawValue];
69 | }
70 |
71 | - (NSString *)rawValue
72 | {
73 | return [formatCoordinatorHelper rawValue];
74 | }
75 |
76 | - (NSString *)formattedValue
77 | {
78 | return formatCoordinatorHelper.formattedValue;
79 | }
80 |
81 | - (void)applyFormattingConfig:(FTCTextEntryFormattingConfig *)config
82 | {
83 | [formatCoordinatorHelper applyFormattingConfig:config];
84 | }
85 |
86 | // MARK: FTCTextEntry
87 |
88 | - (NSString *)text
89 | {
90 | return textField.text;
91 | }
92 |
93 | - (void)setText:(NSString *)text
94 | {
95 | textField.text = text;
96 | }
97 |
98 | - (NSRange)selectedTextRange
99 | {
100 | return [FTCTextInputUtils selectedRangeInTextInput:textField];
101 | }
102 |
103 | - (void)setSelectedTextRange:(NSRange)selectedTextRange
104 | {
105 | [FTCTextInputUtils selectTextInTextInput:textField atRange:selectedTextRange];
106 | }
107 |
108 | // MARK: UITextFieldDelegate
109 |
110 | - (void)textFieldDidBeginEditing:(UITextField *)aTextField
111 | {
112 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldDidBeginEditing:)])
113 | {
114 | [self.textFieldDelegate textFieldDidBeginEditing:textField];
115 | }
116 |
117 | [formatCoordinatorHelper beginEditing];
118 | }
119 |
120 | - (void)textFieldDidEndEditing:(UITextField *)aTextField
121 | {
122 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldDidEndEditing:)])
123 | {
124 | [self.textFieldDelegate textFieldDidEndEditing:textField];
125 | }
126 |
127 | [formatCoordinatorHelper endEditing];
128 | }
129 |
130 | - (void)textFieldDidEndEditing:(UITextField *)aTextField reason:(UITextFieldDidEndEditingReason)reason NS_AVAILABLE_IOS(10_0)
131 | {
132 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldDidEndEditing:reason:)])
133 | {
134 | return [self.textFieldDelegate textFieldDidEndEditing:textField reason:reason];
135 | }
136 | else if ([self.textFieldDelegate respondsToSelector:@selector(textFieldDidEndEditing:)])
137 | {
138 | [self.textFieldDelegate textFieldDidEndEditing:textField];
139 | }
140 |
141 | [formatCoordinatorHelper endEditing];
142 | }
143 |
144 | - (BOOL)textField:(UITextField *)aTextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
145 | {
146 | BOOL shouldChange = YES;
147 |
148 | if ([self.textFieldDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)])
149 | {
150 | shouldChange = [self.textFieldDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
151 | }
152 |
153 | if (shouldChange)
154 | {
155 | [formatCoordinatorHelper changeCharactersInRange:range replacement:string];
156 | }
157 |
158 | return NO;
159 | }
160 |
161 | - (BOOL)textFieldShouldBeginEditing:(UITextField *)aTextField
162 | {
163 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldShouldBeginEditing:)])
164 | {
165 | return [self.textFieldDelegate textFieldShouldBeginEditing:textField];
166 | }
167 | return YES;
168 | }
169 |
170 | - (BOOL)textFieldShouldEndEditing:(UITextField *)aTextField
171 | {
172 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldShouldEndEditing:)])
173 | {
174 | return [self.textFieldDelegate textFieldShouldEndEditing:textField];
175 | }
176 | return YES;
177 | }
178 |
179 | - (BOOL)textFieldShouldClear:(UITextField *)aTextField
180 | {
181 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldShouldClear:)])
182 | {
183 | return [self.textFieldDelegate textFieldShouldClear:textField];
184 | }
185 | return YES;
186 | }
187 |
188 | - (BOOL)textFieldShouldReturn:(UITextField *)aTextField
189 | {
190 | if ([self.textFieldDelegate respondsToSelector:@selector(textFieldShouldReturn:)])
191 | {
192 | return [self.textFieldDelegate textFieldShouldReturn:textField];
193 | }
194 | return YES;
195 | }
196 |
197 | // MARK: Unavailable init
198 |
199 | - (instancetype)init
200 | {
201 | assert(NO);
202 | return nil;
203 | }
204 |
205 | @end
206 |
--------------------------------------------------------------------------------
/Src/FTCTextInputUtils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import UIKit;
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCTextInputUtils : NSObject
26 |
27 | + (void)selectTextInTextInput:(id)textInput atRange:(NSRange)selectionRange NS_SWIFT_NAME( selectText(in:at:) );
28 | + (void)selectTextInTextInput:(id)textInput fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex NS_SWIFT_NAME( selectText(in:from:to:) );
29 |
30 | + (void)moveCursorInTextInput:(id)textInput toPosition:(NSUInteger)position NS_SWIFT_NAME( moveCursor(in:to:) );
31 |
32 | + (NSRange)selectedRangeInTextInput:(id)textInput NS_SWIFT_NAME( selectedRange(in:) );
33 |
34 | - (instancetype)init NS_UNAVAILABLE;
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
--------------------------------------------------------------------------------
/Src/FTCTextInputUtils.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextInputUtils.h"
22 |
23 | @implementation FTCTextInputUtils
24 |
25 | + (void)selectTextInTextInput:(id)textInput atRange:(NSRange)selectionRange
26 | {
27 | assert( nil != textInput );
28 |
29 | const NSUInteger selectionStart = selectionRange.location;
30 | const NSUInteger selectionEnd = selectionRange.location + selectionRange.length;
31 | [FTCTextInputUtils selectTextInTextInput:textInput fromIndex:selectionStart toIndex:selectionEnd];
32 | }
33 |
34 | + (void)selectTextInTextInput:(id)textInput fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
35 | {
36 | assert( nil != textInput );
37 | assert( fromIndex <= toIndex && "'fromIndex' or 'toIndex' is out of bounds." );
38 |
39 | UITextPosition *fromPosition = [textInput positionFromPosition:[textInput beginningOfDocument] offset:fromIndex];
40 | UITextPosition *toPosition = [textInput positionFromPosition:[textInput beginningOfDocument] offset:toIndex];
41 | UITextRange *selectionRange = [textInput textRangeFromPosition:fromPosition toPosition:toPosition];
42 | [textInput setSelectedTextRange:selectionRange];
43 | }
44 |
45 | + (void)moveCursorInTextInput:(id)textInput toPosition:(NSUInteger)position
46 | {
47 | assert( nil != textInput );
48 |
49 | [self selectTextInTextInput:textInput fromIndex:position toIndex:position];
50 | }
51 |
52 | + (NSRange)selectedRangeInTextInput:(id)textInput
53 | {
54 | UITextPosition *beginning = textInput.beginningOfDocument;
55 |
56 | UITextRange *selectedRange = textInput.selectedTextRange;
57 | UITextPosition *selectionStart = selectedRange.start;
58 | UITextPosition *selectionEnd = selectedRange.end;
59 |
60 | const NSInteger location = [textInput offsetFromPosition:beginning toPosition:selectionStart];
61 | const NSInteger length = [textInput offsetFromPosition:selectionStart toPosition:selectionEnd];
62 |
63 | assert( location >= 0 );
64 | assert( length >= 0 );
65 |
66 | return NSMakeRange((NSUInteger)location, (NSUInteger)length);
67 | }
68 |
69 | - (instancetype)init
70 | {
71 | assert( false && "Won't happen." );
72 | return nil;
73 | }
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/Src/Money/FTCIntegralMoneyAmountEntryEditingInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryEditingInputFilter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCIntegralMoneyAmountEntryEditingInputFilter : NSObject
26 |
27 | - (instancetype)init;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/Src/Money/FTCIntegralMoneyAmountEntryEditingInputFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCIntegralMoneyAmountEntryEditingInputFilter.h"
22 | #import "FTCTextEntryFormattingStringUtils.h"
23 | #import "FTCFilteredString.h"
24 | #import "FTCMoneyEntryFormatUtils.h"
25 |
26 | @implementation FTCIntegralMoneyAmountEntryEditingInputFilter
27 |
28 | - (instancetype)init
29 | {
30 | self = [super init];
31 |
32 | return self;
33 | }
34 |
35 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement
36 | {
37 | assert( (nil != originalString) && "Argument 'originalString' must not be nil." );
38 | assert( (nil != replacement) && "Argument 'replacement' must not be nil." );
39 |
40 | NSString *filteredReplacement = [FTCMoneyEntryFormatUtils removeFractionalPartFromString:replacement];
41 | filteredReplacement = [FTCTextEntryFormattingStringUtils removeCharactersOfSet:[FTCIntegralMoneyAmountEntryEditingInputFilter notAllowedCharacters] fromString:filteredReplacement];
42 |
43 | NSRange filteredReplacementRange = range;
44 | filteredReplacementRange.length = filteredReplacement.length;
45 |
46 | NSString *replacedString = [originalString stringByReplacingCharactersInRange:range withString:filteredReplacement];
47 |
48 | return [[FTCFilteredString alloc] initWithString:replacedString range:filteredReplacementRange];
49 | }
50 |
51 | + (NSCharacterSet *)notAllowedCharacters
52 | {
53 | static NSCharacterSet *notAllowedCharacters;
54 |
55 | static dispatch_once_t predicate;
56 | dispatch_once(&predicate, ^
57 | {
58 | NSCharacterSet *numericCharSet = [NSCharacterSet decimalDigitCharacterSet];
59 |
60 | notAllowedCharacters = [numericCharSet invertedSet];
61 | });
62 |
63 | return notAllowedCharacters;
64 | }
65 |
66 | - (BOOL)isEqual:(id)object
67 | {
68 | return ( (self == object) || [object isMemberOfClass:self.class] );
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/Src/Money/FTCIntegralMoneyAmountEntryNotEditingInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryNotEditingInputFilter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCIntegralMoneyAmountEntryNotEditingInputFilter : NSObject
26 |
27 | - (instancetype)init;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/Src/Money/FTCIntegralMoneyAmountEntryNotEditingInputFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCIntegralMoneyAmountEntryNotEditingInputFilter.h"
22 | #import "FTCMoneyEntryFormatUtils.h"
23 |
24 | @implementation FTCIntegralMoneyAmountEntryNotEditingInputFilter
25 |
26 | - (instancetype)init
27 | {
28 | self = [super init];
29 |
30 | return self;
31 | }
32 |
33 | - (NSString *)filterString:(NSString *)string
34 | {
35 | assert( nil != string );
36 |
37 | if( 0 == string.length )
38 | {
39 | return [FTCMoneyEntryFormatUtils emptyString];
40 | }
41 |
42 | string = [FTCMoneyEntryFormatUtils removeFractionalPartFromString:string];
43 | string = [FTCMoneyEntryFormatUtils trimZeroHeadFromString:string];
44 | string = [FTCMoneyEntryFormatUtils removeNonMoneyEntryCharactersFromString:string];
45 |
46 | return string;
47 | }
48 |
49 | - (BOOL)isEqual:(id)object
50 | {
51 | return ( (self == object) || [object isMemberOfClass:self.class] );
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryEditingFormatter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCMoneyEntryEditingFormatter : NSObject
26 |
27 | - (instancetype)init NS_UNAVAILABLE;
28 |
29 | - (instancetype)initWithCurrency:(nullable NSString *)aCurrency;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryEditingFormatter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMoneyEntryEditingFormatter.h"
22 | #import "FTCPostfixFormatter.h"
23 |
24 | @implementation FTCMoneyEntryEditingFormatter
25 | {
26 | FTCPostfixFormatter *postfixFormatter;
27 | NSString *currency;
28 | }
29 |
30 | - (instancetype)init
31 | {
32 | assert(NO && "Won't happen");
33 | return nil;
34 | }
35 |
36 | - (instancetype)initWithCurrency:(NSString *)aCurrency
37 | {
38 | self = [super init];
39 |
40 | currency = aCurrency;
41 |
42 | NSString *amountPostfix = @"";
43 | if( nil != aCurrency )
44 | {
45 | amountPostfix = [NSString stringWithFormat:@" %@", currency];
46 | }
47 | postfixFormatter = [[FTCPostfixFormatter alloc] initWithPostfix:amountPostfix];
48 |
49 | return self;
50 | }
51 |
52 | - (NSString *)rawFromFormatted:(NSString *)formattedValue
53 | {
54 | return [postfixFormatter rawFromFormatted:formattedValue];
55 | }
56 |
57 | - (NSString *)formattedFromRaw:(NSString *)rawValue
58 | {
59 | assert( nil != rawValue );
60 | return [postfixFormatter formattedFromRaw:rawValue];
61 | }
62 |
63 | - (NSRange)rangeInFormattedValueForRange:(NSRange)rangeInRawValue inRawValue:(NSString *)rawValue
64 | {
65 | return [postfixFormatter rangeInFormattedValueForRange:rangeInRawValue inRawValue:rawValue];
66 | }
67 |
68 | - (NSRange)rangeInRawValueForRange:(NSRange)rangeInFormattedValue inFormattedValue:(NSString *)formattedValue
69 | {
70 | return [postfixFormatter rangeInRawValueForRange:rangeInFormattedValue inFormattedValue:formattedValue];
71 | }
72 |
73 | - (BOOL)isEqual:(id)object
74 | {
75 | if( nil == object )
76 | {
77 | return NO;
78 | }
79 |
80 | if( self == object )
81 | {
82 | return YES;
83 | }
84 |
85 | if( NO == [object isMemberOfClass:self.class] )
86 | {
87 | return NO;
88 | }
89 |
90 | return [self isEqualToFormatter:object];
91 | }
92 |
93 | - (BOOL)isEqualToFormatter:(FTCMoneyEntryEditingFormatter *)formatter
94 | {
95 | if( nil == currency )
96 | {
97 | return (nil == formatter->currency);
98 | }
99 | return [currency isEqualToString:formatter->currency];
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryEditingInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryEditingInputFilter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCMoneyEntryEditingInputFilter : NSObject
26 |
27 | - (instancetype)init;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryEditingInputFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMoneyEntryEditingInputFilter.h"
22 | #import "FTCFilteredString.h"
23 | #import "FTCTextEntryFormattingStringUtils.h"
24 | #import "FTCMoneyEntryFormatUtils.h"
25 |
26 | static const int MAX_FRACTIONAL_DIGITS = 2;
27 |
28 | @implementation FTCMoneyEntryEditingInputFilter
29 |
30 | - (instancetype)init
31 | {
32 | self = [super init];
33 |
34 | return self;
35 | }
36 |
37 | - (FTCFilteredString *)replaceSubstringInString:(NSString *)originalString atRange:(NSRange)range withString:(NSString *)replacement
38 | {
39 | assert( nil != originalString );
40 | assert( nil != replacement );
41 |
42 | NSString *filteredReplacement = [FTCMoneyEntryFormatUtils removeNonMoneyEntryCharactersFromString:replacement];
43 |
44 | const NSUInteger originalStringSeparatorLocation = [originalString rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]].location;
45 |
46 | if(NSNotFound != originalStringSeparatorLocation)
47 | {
48 | filteredReplacement = [FTCTextEntryFormattingStringUtils removeCharactersOfSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet] fromString:filteredReplacement];
49 | }
50 | else
51 | {
52 | filteredReplacement = [self filterExtraSeparatorsFromString:filteredReplacement];
53 | }
54 |
55 | NSRange filteredReplacementRange = range;
56 | filteredReplacementRange.length = filteredReplacement.length;
57 |
58 | NSString *replacedString = [originalString stringByReplacingCharactersInRange:range withString:filteredReplacement];
59 |
60 | if( [self shouldUseReplacementResult:replacedString] )
61 | {
62 | return [[FTCFilteredString alloc] initWithString:replacedString range:filteredReplacementRange];
63 | }
64 |
65 | return [[FTCFilteredString alloc] initWithString:originalString range:NSMakeRange(filteredReplacementRange.location, 0)];
66 | }
67 |
68 | - (BOOL)shouldUseReplacementResult:(nonnull NSString *)replacementResult
69 | {
70 | const NSUInteger separatorLocation = [replacementResult rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]].location;
71 |
72 | if( NSNotFound != separatorLocation )
73 | {
74 | NSString *fractionalPart = [FTCMoneyEntryFormatUtils removeIntegralPartFromString:replacementResult];
75 | if ( fractionalPart.length > MAX_FRACTIONAL_DIGITS )
76 | {
77 | return NO;
78 | }
79 | }
80 |
81 | return YES;
82 | }
83 |
84 | - (NSString *)filterExtraSeparatorsFromString:(NSString * const)string
85 | {
86 | NSString *result = string;
87 |
88 | const NSUInteger separatorLocation = [result rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]].location;
89 |
90 | if(NSNotFound != separatorLocation)
91 | {
92 | NSString *singleSeparator = [result substringWithRange:NSMakeRange(separatorLocation, 1)];
93 |
94 | result = [FTCTextEntryFormattingStringUtils removeCharactersOfSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet] fromString:result];
95 | result = [result stringByReplacingCharactersInRange:NSMakeRange(separatorLocation, 0) withString:singleSeparator];
96 | }
97 |
98 | return result;
99 | }
100 |
101 | - (BOOL)isEqual:(id)object
102 | {
103 | return ( (self == object) || [object isMemberOfClass:self.class] );
104 | }
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryFormatUtils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | @interface FTCMoneyEntryFormatUtils : NSObject
24 |
25 | + (NSString *)trimZeroHeadFromString:(NSString *const)string;
26 | + (NSString *)removeNonMoneyEntryCharactersFromString:(NSString *const)string;
27 | + (NSString *)removeFractionalPartFromString:(NSString *)string;
28 | + (NSString *)removeIntegralPartFromString:(NSString *)string;
29 |
30 | + (NSString *)emptyString;
31 | + (NSString *)zeroString;
32 |
33 | + (NSCharacterSet *)decimalSeparatorsCharacterSet;
34 | + (NSString *)preferredDecimalSeparator;
35 |
36 | - (instancetype)init NS_UNAVAILABLE;
37 |
38 | @end
39 |
40 | NS_ASSUME_NONNULL_END
41 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryFormatUtils.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMoneyEntryFormatUtils.h"
22 | #import "FTCTextEntryFormattingStringUtils.h"
23 |
24 | static NSString * const EMPTY_STRING = @"";
25 | static NSString * const ZERO_STRING = @"0";
26 | static NSString * const DECIMAL_SEPARATORS = @".,";
27 |
28 | @implementation FTCMoneyEntryFormatUtils
29 |
30 | + (NSString *)trimZeroHeadFromString:(NSString * const)string
31 | {
32 | const NSUInteger zeroHeadLength = [FTCMoneyEntryFormatUtils zeroHeadRangeForString:string].length;
33 |
34 | return [string substringFromIndex:zeroHeadLength];
35 | }
36 |
37 | + (NSRange)zeroHeadRangeForString:(nonnull NSString * const)string
38 | {
39 | NSRange zeroHeadRange = NSMakeRange(NSNotFound, 0);
40 |
41 | if( 0 == string.length )
42 | {
43 | return zeroHeadRange;
44 | }
45 |
46 | NSString *substring = nil;
47 | for(NSUInteger i = 0; i < string.length; i++)
48 | {
49 | substring = [string substringWithRange:NSMakeRange(i, 1)];
50 | if( [ZERO_STRING isEqualToString:substring] )
51 | {
52 | zeroHeadRange.length++;
53 | zeroHeadRange.location = 0;
54 | }
55 | else
56 | {
57 | break;
58 | }
59 | }
60 |
61 | // Обрабатываем случаи @"00", @"00.1", чтобы после триминга иметь @"0", @"0.1" соответственно, иначе
62 | // если этого не делать, то после триминга будем иметь @"", @".1" соответственно.
63 | if( zeroHeadRange.length > 0 )
64 | {
65 | BOOL reachedDecimalSeparator = (substring != nil && 0 != [self.decimalSeparators rangeOfString:substring].length);
66 | BOOL reachedEndOfString = (string.length == zeroHeadRange.length);
67 |
68 | if( reachedDecimalSeparator || reachedEndOfString )
69 | {
70 | zeroHeadRange.length--;
71 | }
72 | }
73 |
74 | return zeroHeadRange;
75 | }
76 |
77 | + (NSString *)removeNonMoneyEntryCharactersFromString:(NSString * const)string
78 | {
79 | return [FTCTextEntryFormattingStringUtils removeCharactersOfSet:[FTCMoneyEntryFormatUtils nonMoneyEntryCharacters] fromString:string];
80 | }
81 |
82 | + (nonnull NSCharacterSet *)nonMoneyEntryCharacters
83 | {
84 | static NSCharacterSet *notAllowedCharacters;
85 |
86 | static dispatch_once_t predicate;
87 | dispatch_once(&predicate, ^
88 | {
89 | NSMutableCharacterSet *numericCharSet = [NSMutableCharacterSet decimalDigitCharacterSet];
90 | [numericCharSet addCharactersInString:DECIMAL_SEPARATORS];
91 |
92 | notAllowedCharacters = [numericCharSet invertedSet];
93 | });
94 |
95 | return notAllowedCharacters;
96 | }
97 |
98 | + (NSString *)removeFractionalPartFromString:(NSString *)string
99 | {
100 | const NSUInteger separatorLocation = [string rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]].location;
101 |
102 | if(NSNotFound != separatorLocation)
103 | {
104 | string = [string substringToIndex:separatorLocation];
105 | }
106 |
107 | return string;
108 | }
109 |
110 | + (NSString *)removeIntegralPartFromString:(NSString *)string
111 | {
112 | const NSUInteger separatorLocation = [string rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]].location;
113 |
114 | if(NSNotFound != separatorLocation)
115 | {
116 | string = [string substringFromIndex:separatorLocation + 1];
117 | }
118 |
119 | return string;
120 | }
121 |
122 | + (NSString *)emptyString
123 | {
124 | return EMPTY_STRING;
125 | }
126 |
127 | + (NSString *)zeroString
128 | {
129 | return ZERO_STRING;
130 | }
131 |
132 | + (NSString *)decimalSeparators
133 | {
134 | return DECIMAL_SEPARATORS;
135 | }
136 |
137 | + (NSCharacterSet *)decimalSeparatorsCharacterSet
138 | {
139 | static NSCharacterSet *separatingCharSet;
140 |
141 | static dispatch_once_t predicate;
142 | dispatch_once(&predicate, ^
143 | {
144 | separatingCharSet = [NSCharacterSet characterSetWithCharactersInString:[FTCMoneyEntryFormatUtils decimalSeparators]];
145 | });
146 |
147 | return separatingCharSet;
148 | }
149 |
150 | + (NSString *)preferredDecimalSeparator
151 | {
152 | static NSString *decimalSeparator;
153 |
154 | static dispatch_once_t predicate;
155 | dispatch_once(&predicate, ^
156 | {
157 | NSLocale *russianLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"ru_RU"];
158 | decimalSeparator = [russianLocale objectForKey:NSLocaleDecimalSeparator];
159 | });
160 |
161 | return decimalSeparator;
162 | }
163 |
164 | - (instancetype)init
165 | {
166 | assert( NO );
167 | return nil;
168 | }
169 |
170 | @end
171 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryNotEditingFormatter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormatter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCMoneyEntryNotEditingFormatter : NSObject
26 |
27 | - (instancetype)init NS_UNAVAILABLE;
28 |
29 | - (instancetype)initWithCurrency:(nullable NSString *)currency;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryNotEditingFormatter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMoneyEntryNotEditingFormatter.h"
22 | #import "FTCPostfixFormatter.h"
23 |
24 | @implementation FTCMoneyEntryNotEditingFormatter
25 | {
26 | FTCPostfixFormatter *postfixFormatter;
27 |
28 | NSString *currency;
29 | }
30 |
31 | - (instancetype)init
32 | {
33 | assert(NO && "Won't happen");
34 | return nil;
35 | }
36 |
37 | - (instancetype)initWithCurrency:(NSString *)aCurrency
38 | {
39 | self = [super init];
40 |
41 | currency = aCurrency;
42 |
43 | NSString *amountPostfix = @"";
44 | if( nil != currency )
45 | {
46 | amountPostfix = [NSString stringWithFormat:@" %@", currency];
47 | }
48 | postfixFormatter = [[FTCPostfixFormatter alloc] initWithPostfix:amountPostfix];
49 |
50 | return self;
51 | }
52 |
53 | - (NSString *)rawFromFormatted:(NSString *)formattedValue
54 | {
55 | if( NO == [self canShowPostfixForString:formattedValue] )
56 | {
57 | return formattedValue;
58 | }
59 |
60 | return [postfixFormatter rawFromFormatted:formattedValue];
61 | }
62 |
63 | - (NSString *)formattedFromRaw:(NSString *)rawValue
64 | {
65 | if( NO == [self canShowPostfixForString:rawValue] )
66 | {
67 | return (rawValue != nil ? rawValue : @"");
68 | }
69 |
70 | return [postfixFormatter formattedFromRaw:rawValue];
71 | }
72 |
73 | - (NSRange)rangeInFormattedValueForRange:(NSRange)rangeInRawValue inRawValue:(NSString *)rawValue
74 | {
75 | return [postfixFormatter rangeInFormattedValueForRange:rangeInRawValue inRawValue:rawValue];
76 | }
77 |
78 | - (NSRange)rangeInRawValueForRange:(NSRange)rangeInFormattedValue inFormattedValue:(NSString *)formattedValue
79 | {
80 | if( [self canShowPostfixForString:formattedValue] )
81 | {
82 | return [postfixFormatter rangeInRawValueForRange:rangeInFormattedValue inFormattedValue:formattedValue];
83 | }
84 |
85 | return rangeInFormattedValue;
86 | }
87 |
88 | - (BOOL)canShowPostfixForString:(nullable NSString *)string
89 | {
90 | if(0 == string.length)
91 | {
92 | return NO;
93 | }
94 |
95 | return YES;
96 | }
97 |
98 | - (BOOL)isEqual:(id)object
99 | {
100 | if( nil == object )
101 | {
102 | return NO;
103 | }
104 |
105 | if( self == object )
106 | {
107 | return YES;
108 | }
109 |
110 | if( NO == [object isMemberOfClass:self.class] )
111 | {
112 | return NO;
113 | }
114 |
115 | return [self isEqualToFormatter:object];
116 | }
117 |
118 | - (BOOL)isEqualToFormatter:(FTCMoneyEntryNotEditingFormatter *)object
119 | {
120 | if( nil == currency )
121 | {
122 | return (nil == object->currency);
123 | }
124 | return [currency isEqualToString:object->currency];
125 | }
126 |
127 | @end
128 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryNotEditingInputFilter.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryNotEditingInputFilter.h"
22 |
23 | NS_ASSUME_NONNULL_BEGIN
24 |
25 | @interface FTCMoneyEntryNotEditingInputFilter : NSObject
26 |
27 | - (instancetype)init;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/Src/Money/FTCMoneyEntryNotEditingInputFilter.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCMoneyEntryNotEditingInputFilter.h"
22 | #import "FTCMoneyEntryFormatUtils.h"
23 |
24 | static const NSInteger PREFERRED_NUMBER_OF_FRACTIONAL_DIGITS = 2;
25 |
26 | @implementation FTCMoneyEntryNotEditingInputFilter
27 |
28 | - (instancetype)init
29 | {
30 | self = [super init];
31 |
32 | return self;
33 | }
34 |
35 | - (NSString *)filterString:(NSString *)string
36 | {
37 | assert( nil != string );
38 |
39 | if( 0 == string.length )
40 | {
41 | return [FTCMoneyEntryFormatUtils emptyString];
42 | }
43 |
44 | NSString *result = [FTCMoneyEntryFormatUtils removeNonMoneyEntryCharactersFromString:string];
45 | result = [FTCMoneyEntryFormatUtils trimZeroHeadFromString:result];
46 | result = [self trimZeroTailFromString:result];
47 | result = [self trimEndingSeparatorInString:result];
48 |
49 | if( 0 == result.length )
50 | {
51 | result = [FTCMoneyEntryFormatUtils zeroString];
52 | }
53 |
54 | result = [self fixNotExistingIntegerPartInString:result];
55 | result = [self appendMissingZeroInFractionalPartToString:result];
56 |
57 | return result;
58 | }
59 |
60 | - (NSString *)trimZeroTailFromString:(NSString * const)string
61 | {
62 | NSString *result = string;
63 |
64 | const NSUInteger separatorLocation = [string rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]].location;
65 |
66 | if(NSNotFound != separatorLocation)
67 | {
68 | const NSUInteger zeroTailLocation = [self zeroTailRangeForString:result].location;
69 |
70 | if(NSNotFound != zeroTailLocation)
71 | {
72 | result = [result substringToIndex:zeroTailLocation];
73 | }
74 | }
75 |
76 | return result;
77 | }
78 |
79 | - (NSString *)trimEndingSeparatorInString:(NSString * const)string
80 | {
81 | NSString *result = string;
82 |
83 | if(0 < result.length)
84 | {
85 | const NSRange trimmedStringSeparatorRange = [result rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]];
86 |
87 | if(NSNotFound != trimmedStringSeparatorRange.location)
88 | {
89 | if (result.length == trimmedStringSeparatorRange.location + 1)
90 | {
91 | result = [result substringToIndex:trimmedStringSeparatorRange.location];
92 | }
93 | }
94 | }
95 |
96 | return result;
97 | }
98 |
99 | - (NSString *)fixNotExistingIntegerPartInString:(NSString * const)string
100 | {
101 | NSString *result = string;
102 |
103 | if(0 < result.length)
104 | {
105 | const NSRange trimmedStringSeparatorRange = [result rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]];
106 |
107 | if(0 == trimmedStringSeparatorRange.location)
108 | {
109 | result = [[FTCMoneyEntryFormatUtils zeroString] stringByAppendingString:result];
110 | }
111 | }
112 |
113 | return result;
114 | }
115 |
116 | - (NSString *)appendMissingZeroInFractionalPartToString:(NSString * const)string
117 | {
118 | NSString *result = string;
119 |
120 | NSRange separatorRange = [string rangeOfCharacterFromSet:[FTCMoneyEntryFormatUtils decimalSeparatorsCharacterSet]];
121 |
122 | if( NSNotFound != separatorRange.location )
123 | {
124 | const NSInteger numberOfFractionalDigits = string.length - (separatorRange.location + separatorRange.length);
125 | const NSInteger fractionalDigitsToAdd = PREFERRED_NUMBER_OF_FRACTIONAL_DIGITS - numberOfFractionalDigits;
126 |
127 | if( fractionalDigitsToAdd > 0 )
128 | {
129 | for( NSInteger index = 0; index < fractionalDigitsToAdd; index++ )
130 | {
131 | result = [result stringByAppendingString:[FTCMoneyEntryFormatUtils zeroString]];
132 | }
133 | }
134 | }
135 | else
136 | {
137 | NSString *separator = [FTCMoneyEntryFormatUtils preferredDecimalSeparator];
138 | NSString *zeroString = [FTCMoneyEntryFormatUtils zeroString];
139 | NSString *zeroTail = [zeroString stringByAppendingString:zeroString];
140 | NSString *tail = [separator stringByAppendingString:zeroTail];
141 | result = [result stringByAppendingString:tail];
142 | }
143 |
144 | return result;
145 | }
146 |
147 | - (NSRange)zeroTailRangeForString:(NSString * const)string
148 | {
149 | NSRange zeroHeadRange = NSMakeRange(NSNotFound, 0);
150 |
151 | if( 0 == string.length )
152 | {
153 | return zeroHeadRange;
154 | }
155 |
156 | for(NSInteger i = string.length - 1; i >= 0; i--)
157 | {
158 | NSString *substring = [string substringWithRange:NSMakeRange((NSUInteger)i, 1)];
159 |
160 | if( [[FTCMoneyEntryFormatUtils zeroString] isEqualToString:substring] )
161 | {
162 | zeroHeadRange.length++;
163 | zeroHeadRange.location = (NSUInteger)i;
164 | }
165 | else
166 | {
167 | break;
168 | }
169 | }
170 |
171 | return zeroHeadRange;
172 | }
173 |
174 | - (BOOL)isEqual:(id)object
175 | {
176 | return ( (self == object) || [object isMemberOfClass:self.class] );
177 | }
178 |
179 | @end
180 |
--------------------------------------------------------------------------------
/Src/Tools/FTCTextEntryFormattingStringUtils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | @interface FTCTextEntryFormattingStringUtils : NSObject
24 |
25 | + (NSString *)removeCharactersOfSet:(NSCharacterSet *)characterSet fromString:(NSString *)string;
26 | + (nullable NSString *)stringWithDecimalDigitsFromString:(nullable NSString *)string;
27 |
28 | + (NSString *)stringWithCharacter:(unichar)character;
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/Src/Tools/FTCTextEntryFormattingStringUtils.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "FTCTextEntryFormattingStringUtils.h"
22 |
23 | @implementation FTCTextEntryFormattingStringUtils
24 |
25 | + (NSString *)joinStringsFromArray:(NSArray *)arrayToJoinStringsFrom
26 | {
27 | #if defined(DEBUG)
28 | for( id obj in arrayToJoinStringsFrom )
29 | {
30 | assert( [obj isKindOfClass:[NSString class]] && "'obj' is of unexpected class." );
31 | }
32 | #endif // defined(DEBUG)
33 |
34 | return [arrayToJoinStringsFrom componentsJoinedByString:@""];
35 | }
36 |
37 | + (NSString *)removeCharactersOfSet:(NSCharacterSet *)characterSet fromString:(NSString *)string
38 | {
39 | return [self joinStringsFromArray:[string componentsSeparatedByCharactersInSet:characterSet]];
40 | }
41 |
42 | + (NSString *)stringWithDecimalDigitsFromString:(NSString *)string
43 | {
44 | if (nil == string || 0 == [string length])
45 | {
46 | return string;
47 | }
48 |
49 | NSCharacterSet *bannedCharacters = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
50 | NSString *normalString = [self removeCharactersOfSet:bannedCharacters fromString:string];
51 | return normalString;
52 | }
53 |
54 | + (NSString *)stringWithCharacter:(unichar)character
55 | {
56 | return [NSString stringWithCharacters:&character length:1];
57 | }
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/Src/Tools/NSString+FTCTextEntryFormatting.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @interface NSString (FTCTextEntryFormatting)
22 |
23 | - (BOOL)textEntryFormatting_isEmpty;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/Src/Tools/NSString+FTCTextEntryFormatting.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #import "NSString+FTCTextEntryFormatting.h"
22 |
23 | @implementation NSString (FTCTextEntryFormatting)
24 |
25 | - (BOOL)textEntryFormatting_isEmpty
26 | {
27 | return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0;
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/UnitTests/FormatCoordinator/FormatCoordinatorTestCase.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 | @interface FormattingCoordinatorTestCase : XCTestCase
25 | @end
26 |
27 | @implementation FormattingCoordinatorTestCase
28 | {
29 | FTCTextEntryFormatCoordinator *coordinator;
30 | }
31 |
32 | - (void)setUp
33 | {
34 | [super setUp];
35 |
36 | coordinator = [[FTCTextEntryFormatCoordinator alloc] init];
37 | }
38 |
39 | - (void)tearDown
40 | {
41 | [super tearDown];
42 | }
43 |
44 | - (void)test_set_nil_rawValue
45 | {
46 | coordinator.rawValue = nil;
47 |
48 | XCTAssert( nil == coordinator.rawValue );
49 | }
50 |
51 | - (void)test_set_empty_rawValue
52 | {
53 | [self checkRawValueAfterSetRawValue:@""];
54 | }
55 |
56 | - (void)test_set_not_empty_rawValue
57 | {
58 | [self checkRawValueAfterSetRawValue:@"value"];
59 | }
60 |
61 | - (void)test_formattedValue_for_nil_rawValue
62 | {
63 | [self checkFormattedValue:@"" afterSetRawValue:nil];
64 | }
65 |
66 | - (void)test_empty_formattedValue
67 | {
68 | [self checkFormattedValue:@"" afterSetRawValue:@""];
69 | }
70 |
71 | - (void)test_not_empty_formattedValue
72 | {
73 | [self checkFormattedValue:@"value" afterSetRawValue:@"value"];
74 | }
75 |
76 | - (void)test_append_data_to_nil_rawValue
77 | {
78 | NSString *replacement = @"value";
79 | NSString *etalonRawValue = @"value";
80 |
81 | coordinator.rawValue = nil;
82 |
83 | [coordinator beginEditing];
84 |
85 | [coordinator userReplacedInFormattedValueSubstringAtRange:NSMakeRange(0, 0) withString:replacement];
86 |
87 | [coordinator endEditing];
88 |
89 | XCTAssertEqualObjects(etalonRawValue, coordinator.rawValue);
90 | }
91 |
92 | - (void)test_insert_to_rawValue
93 | {
94 | [self checkRawValue:@"1value2"
95 | replaceInRawValue:@"12"
96 | atRange:NSMakeRange(1, 0)
97 | withReplacement:@"value"];
98 | }
99 |
100 | - (void)test_replace_in_rawValue
101 | {
102 | [self checkRawValue:@"1aaaa2"
103 | replaceInRawValue:@"1value2"
104 | atRange:NSMakeRange(1, 5)
105 | withReplacement:@"aaaa"];
106 | }
107 |
108 | - (void)test_remove_in_rawValue
109 | {
110 | [self checkRawValue:@"12"
111 | replaceInRawValue:@"1value2"
112 | atRange:NSMakeRange(1, 5)
113 | withReplacement:@""];
114 | }
115 |
116 | - (void)test_insert_to_formattedValue
117 | {
118 | [self checkFormattedValue:@"1value2"
119 | replaceInRawValue:@"12"
120 | atRange:NSMakeRange(1, 0)
121 | withReplacement:@"value"];
122 | }
123 |
124 | - (void)test_replace_in_formattedValue
125 | {
126 | [self checkFormattedValue:@"1aaaa2"
127 | replaceInRawValue:@"1value2"
128 | atRange:NSMakeRange(1, 5)
129 | withReplacement:@"aaaa"];
130 | }
131 |
132 | - (void)test_remove_in_formattedValue
133 | {
134 | [self checkFormattedValue:@"12"
135 | replaceInRawValue:@"1value2"
136 | atRange:NSMakeRange(1, 5)
137 | withReplacement:@""];
138 | }
139 |
140 | - (void)test_selection
141 | {
142 | NSString *rawValue = @"1value2";
143 | NSRange range = NSMakeRange(1, 5);
144 | NSString *replacement = @"aaaa";
145 | NSRange etalonSelection = NSMakeRange(5, 0);
146 |
147 | [self doReplaceInRawValue:rawValue atRange:range withReplacement:replacement];
148 |
149 | XCTAssert( NSEqualRanges(etalonSelection, coordinator.currentSelectionRangeInFormattedValue) );
150 | }
151 |
152 | // MARK: Helpers
153 |
154 | - (void)checkRawValueAfterSetRawValue:(NSString *)rawValue
155 | {
156 | coordinator.rawValue = rawValue;
157 |
158 | XCTAssertEqualObjects(rawValue, coordinator.rawValue);
159 | }
160 |
161 | - (void)checkFormattedValue:(NSString *)etalonFormattedValue afterSetRawValue:(NSString *)rawValue
162 | {
163 | coordinator.rawValue = rawValue;
164 |
165 | XCTAssertEqualObjects(etalonFormattedValue, coordinator.formattedValue);
166 | }
167 |
168 | - (void)checkRawValue:(NSString *)etalonRawValue
169 | replaceInRawValue:(NSString *)rawValue
170 | atRange:(NSRange)range
171 | withReplacement:(NSString *)replacement
172 | {
173 | [self doReplaceInRawValue:rawValue atRange:range withReplacement:replacement];
174 |
175 | XCTAssertEqualObjects(etalonRawValue, coordinator.rawValue,
176 | @"\n resultRawValue: '%@'\n etalonRawValue: '%@'\n rawValue: '%@'\n range: '%@'\n replacement: '%@'",
177 | coordinator.rawValue, etalonRawValue, rawValue, NSStringFromRange(range), replacement);
178 | }
179 |
180 | - (void)checkFormattedValue:(NSString *)etalonFormattedValue
181 | replaceInRawValue:(NSString *)rawValue
182 | atRange:(NSRange)range
183 | withReplacement:(NSString *)replacement
184 | {
185 | [self doReplaceInRawValue:rawValue atRange:range withReplacement:replacement];
186 |
187 | XCTAssertEqualObjects(etalonFormattedValue, coordinator.formattedValue,
188 | @"\n formattedValue: '%@'\n etalonFormattedValue: '%@'\n rawValue: '%@'\n range: '%@'\n replacement: '%@'",
189 | coordinator.formattedValue, etalonFormattedValue, rawValue, NSStringFromRange(range), replacement);
190 | }
191 |
192 | - (void)doReplaceInRawValue:(NSString *)rawValue atRange:(NSRange)range withReplacement:(NSString *)replacement
193 | {
194 | coordinator.rawValue = rawValue;
195 |
196 | [coordinator beginEditing];
197 |
198 | [coordinator userReplacedInFormattedValueSubstringAtRange:range withString:replacement];
199 |
200 | [coordinator endEditing];
201 | }
202 |
203 | @end
204 |
--------------------------------------------------------------------------------
/UnitTests/Formatters/FTCMaskFormatter/FTCMaskFormatterTestCase.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 | @interface FTCMaskFormatterTestCase : XCTestCase
25 | {
26 | FTCMaskFormatter *formatterWithCutTail;
27 | FTCMaskFormatter *formatterWithoutCutTail;
28 | }
29 |
30 | @end
31 |
32 | @implementation FTCMaskFormatterTestCase
33 |
34 | - (void)setUp
35 | {
36 | [super setUp];
37 |
38 | FTCMaskFormatterGenericConfig *configWithCutTail = [[FTCMaskFormatterGenericConfig alloc] initWithMask:@"_ _ _ _ _" maskCharacter:@"_"];
39 | configWithCutTail.tailMode = FTCMaskFormatterConfigTailModeCut;
40 |
41 | formatterWithCutTail = [[FTCMaskFormatter alloc] initWithConfig:configWithCutTail];
42 |
43 | FTCMaskFormatterGenericConfig *configWithoutCutTail = [[FTCMaskFormatterGenericConfig alloc] initWithMask:@"_ _ _ _ _" maskCharacter:@"_"];
44 | configWithoutCutTail.tailMode = FTCMaskFormatterConfigTailModeNone;
45 |
46 | formatterWithoutCutTail = [[FTCMaskFormatter alloc] initWithConfig:configWithoutCutTail];
47 | }
48 |
49 | - (void)test_raw_from_formatted
50 | {
51 | XCTAssertEqualObjects([formatterWithCutTail rawFromFormatted:@""], @"");
52 | XCTAssertEqualObjects([formatterWithCutTail rawFromFormatted:@"1 2 3"], @"123");
53 |
54 | XCTAssertEqualObjects([formatterWithoutCutTail rawFromFormatted:@""], @"");
55 | XCTAssertEqualObjects([formatterWithoutCutTail rawFromFormatted:@"1 2 3"], @"123");
56 | }
57 |
58 | - (void)test_formatted_from_raw
59 | {
60 | XCTAssertEqualObjects([formatterWithCutTail formattedFromRaw:@""], @"");
61 | XCTAssertEqualObjects([formatterWithCutTail formattedFromRaw:@"123"], @"1 2 3");
62 |
63 | XCTAssertEqualObjects([formatterWithoutCutTail formattedFromRaw:@""], @"_ _ _ _ _");
64 | XCTAssertEqualObjects([formatterWithoutCutTail formattedFromRaw:@"123"], @"1 2 3 _ _");
65 | }
66 |
67 | - (void)test_rangeInFormattedValueForRange_inRawValue
68 | {
69 | NSRange rangeInFormatted;
70 |
71 |
72 | rangeInFormatted = [formatterWithCutTail rangeInFormattedValueForRange:NSMakeRange(0, 3) inRawValue:@"123"];
73 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(0, 6)));
74 |
75 | rangeInFormatted = [formatterWithCutTail rangeInFormattedValueForRange:NSMakeRange(1, 2) inRawValue:@"123"];
76 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(1, 4)));
77 |
78 |
79 | rangeInFormatted = [formatterWithoutCutTail rangeInFormattedValueForRange:NSMakeRange(0, 3) inRawValue:@"123"];
80 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(0, 6)));
81 |
82 | rangeInFormatted = [formatterWithoutCutTail rangeInFormattedValueForRange:NSMakeRange(1, 2) inRawValue:@"123"];
83 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(1, 4)));
84 | }
85 |
86 | - (void)test_rangeInRawValueForRange_inFormattedValue
87 | {
88 | NSRange rangeInRaw;
89 |
90 |
91 | rangeInRaw = [formatterWithCutTail rangeInRawValueForRange:NSMakeRange(0, 3) inFormattedValue:@"1 2 3"];
92 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(0, 2)));
93 |
94 | rangeInRaw = [formatterWithCutTail rangeInRawValueForRange:NSMakeRange(1, 2) inFormattedValue:@"1 2 3"];
95 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(1, 1)));
96 |
97 |
98 | rangeInRaw = [formatterWithoutCutTail rangeInRawValueForRange:NSMakeRange(0, 3) inFormattedValue:@"1 2 3 _ _"];
99 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(0, 2)));
100 |
101 | rangeInRaw = [formatterWithoutCutTail rangeInRawValueForRange:NSMakeRange(1, 2) inFormattedValue:@"1 2 3 _ _"];
102 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(1, 1)));
103 | }
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/UnitTests/Formatters/FTCPostfixFormatter/FTCPostfixFormatterTestCaseWithEmptyPostfix.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 | @interface FTCPostfixFormatterTestCaseWithEmptyPostfix : XCTestCase
25 | {
26 | FTCPostfixFormatter *formatter;
27 | }
28 |
29 | @end
30 |
31 | @implementation FTCPostfixFormatterTestCaseWithEmptyPostfix
32 |
33 | - (void)setUp
34 | {
35 | [super setUp];
36 |
37 | formatter = [[FTCPostfixFormatter alloc] initWithPostfix:@""];
38 | }
39 |
40 | - (void)test_raw_from_formatted
41 | {
42 | XCTAssertEqualObjects([formatter rawFromFormatted:@""], @"");
43 | XCTAssertEqualObjects([formatter rawFromFormatted:@"123"], @"123");
44 | }
45 |
46 | - (void)test_formatted_from_raw
47 | {
48 | XCTAssertEqualObjects([formatter formattedFromRaw:@""], @"");
49 | XCTAssertEqualObjects([formatter formattedFromRaw:@"123"], @"123");
50 | }
51 |
52 | - (void)test_rangeInFormattedValueForRange_inRawValue
53 | {
54 | NSRange rangeInFormatted;
55 |
56 | rangeInFormatted = [formatter rangeInFormattedValueForRange:NSMakeRange(0, 3) inRawValue:@"123"];
57 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(0, 3)));
58 |
59 | rangeInFormatted = [formatter rangeInFormattedValueForRange:NSMakeRange(1, 2) inRawValue:@"123"];
60 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(1, 2)));
61 | }
62 |
63 | - (void)test_rangeInRawValueForRange_inFormattedValue
64 | {
65 | NSRange rangeInRaw;
66 |
67 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(0, 3) inFormattedValue:@"123"];
68 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(0, 3)));
69 |
70 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(1, 2) inFormattedValue:@"123"];
71 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(1, 2)));
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/UnitTests/Formatters/FTCPostfixFormatter/FTCPostfixFormatterTestCaseWithNilPostfix.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 | @interface FTCPostfixFormatterTestCaseWithNilPostfix : XCTestCase
25 | {
26 | FTCPostfixFormatter *formatter;
27 | }
28 |
29 | @end
30 |
31 | @implementation FTCPostfixFormatterTestCaseWithNilPostfix
32 |
33 | - (void)setUp
34 | {
35 | [super setUp];
36 |
37 | formatter = [[FTCPostfixFormatter alloc] initWithPostfix:@""];
38 | }
39 |
40 | - (void)test_raw_from_formatted
41 | {
42 | XCTAssertEqualObjects([formatter rawFromFormatted:@""], @"");
43 | XCTAssertEqualObjects([formatter rawFromFormatted:@"123"], @"123");
44 | }
45 |
46 | - (void)test_formatted_from_raw
47 | {
48 | XCTAssertEqualObjects([formatter formattedFromRaw:@""], @"");
49 | XCTAssertEqualObjects([formatter formattedFromRaw:@"123"], @"123");
50 | }
51 |
52 | - (void)test_rangeInFormattedValueForRange_inRawValue
53 | {
54 | NSRange rangeInFormatted;
55 |
56 | rangeInFormatted = [formatter rangeInFormattedValueForRange:NSMakeRange(0, 3) inRawValue:@"123"];
57 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(0, 3)));
58 |
59 | rangeInFormatted = [formatter rangeInFormattedValueForRange:NSMakeRange(1, 2) inRawValue:@"123"];
60 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(1, 2)));
61 | }
62 |
63 | - (void)test_rangeInRawValueForRange_inFormattedValue
64 | {
65 | NSRange rangeInRaw;
66 |
67 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(0, 3) inFormattedValue:@"123"];
68 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(0, 3)));
69 |
70 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(1, 2) inFormattedValue:@"123"];
71 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(1, 2)));
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/UnitTests/Formatters/FTCPostfixFormatter/FTCPostfixFormatterTestCaseWithNotEmptyPostfix.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 | @interface FTCPostfixFormatterTestCaseWithNotEmptyPostfix : XCTestCase
25 | {
26 | FTCPostfixFormatter *formatter;
27 | }
28 |
29 | @end
30 |
31 | @implementation FTCPostfixFormatterTestCaseWithNotEmptyPostfix
32 |
33 | - (void)setUp
34 | {
35 | [super setUp];
36 |
37 | formatter = [[FTCPostfixFormatter alloc] initWithPostfix:@" rub"];
38 | }
39 |
40 | - (void)test_raw_from_formatted
41 | {
42 | XCTAssertEqualObjects([formatter rawFromFormatted:@" rub"], @"");
43 | XCTAssertEqualObjects([formatter rawFromFormatted:@"123 rub"], @"123");
44 | }
45 |
46 | - (void)test_formatted_from_raw
47 | {
48 | XCTAssertEqualObjects([formatter formattedFromRaw:@""], @" rub");
49 | XCTAssertEqualObjects([formatter formattedFromRaw:@"123"], @"123 rub");
50 | }
51 |
52 | - (void)test_rangeInFormattedValueForRange_inRawValue
53 | {
54 | NSRange rangeInFormatted;
55 |
56 | rangeInFormatted = [formatter rangeInFormattedValueForRange:NSMakeRange(0, 3) inRawValue:@"123"];
57 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(0, 3)));
58 |
59 | rangeInFormatted = [formatter rangeInFormattedValueForRange:NSMakeRange(1, 2) inRawValue:@"123"];
60 | XCTAssertTrue(NSEqualRanges(rangeInFormatted, NSMakeRange(1, 2)));
61 | }
62 |
63 | - (void)test_rangeInRawValueForRange_inFormattedValue
64 | {
65 | NSRange rangeInRaw;
66 |
67 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(0, 3) inFormattedValue:@"123 rub"];
68 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(0, 3)));
69 |
70 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(1, 2) inFormattedValue:@"123 rub"];
71 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(1, 2)));
72 |
73 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(2, 3) inFormattedValue:@"123 rub"];
74 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(2, 1)));
75 |
76 | rangeInRaw = [formatter rangeInRawValueForRange:NSMakeRange(4, 1) inFormattedValue:@"123 rub"];
77 | XCTAssertTrue(NSEqualRanges(rangeInRaw, NSMakeRange(3, 0)));
78 | }
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/UnitTests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/UnitTests/InputFilter/FTCDigitsInputFilterTestCase.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 | static const NSUInteger MAX_LENGTH = 5;
25 |
26 | @interface FTCDigitsInputFilterTestCase : XCTestCase
27 | @end
28 |
29 | @implementation FTCDigitsInputFilterTestCase
30 | {
31 | FTCDigitsValueFilter *filter;
32 | }
33 |
34 | - (void)setUp
35 | {
36 | [super setUp];
37 |
38 | filter = [[FTCDigitsValueFilter alloc] initWithMaxLength:MAX_LENGTH];
39 | }
40 |
41 | - (void)test_filter_should_trim_empty_string
42 | {
43 | NSString *string = @"";
44 | NSString *filteredString = [filter filterString:string];
45 | XCTAssertEqual(filteredString.length, 0);
46 | }
47 |
48 | - (void)test_filter_trim_string_case
49 | {
50 | NSString *string = @"123456";
51 | NSString *filteredString = [filter filterString:string];
52 | XCTAssertEqual(filteredString.length, MAX_LENGTH);
53 | }
54 |
55 | - (void)test_filter_empty_string
56 | {
57 | NSString *string = @"";
58 | NSString *filteredString = [filter filterString:string];
59 |
60 | XCTAssertEqualObjects(string, filteredString);
61 | }
62 |
63 | - (void)test_filter_non_empty_digits_only_string
64 | {
65 | NSString *string = @"233223";
66 | NSString *etalon = @"23322";
67 | NSString *filteredString = [filter filterString:string];
68 |
69 | XCTAssertEqualObjects(etalon, filteredString);
70 | }
71 |
72 | - (void)test_filter_non_empty_string
73 | {
74 | NSString *string = @"asdsdf33223dd";
75 | NSString *etalon = @"33223";
76 | NSString *filteredString = [filter filterString:string];
77 |
78 | XCTAssertEqualObjects(etalon, filteredString);
79 | XCTAssertEqual(filteredString.length, MAX_LENGTH);
80 | }
81 |
82 | - (void)test_filter_digits_string_with_comma_delemiter
83 | {
84 | NSString *string = @"332,23";
85 | NSString *etalon = @"33223";
86 | NSString *filteredString = [filter filterString:string];
87 |
88 | XCTAssertEqualObjects(etalon, filteredString);
89 | XCTAssertEqual(filteredString.length, MAX_LENGTH);
90 | }
91 |
92 | @end
93 |
--------------------------------------------------------------------------------
/UnitTests/InputFilter/FTCDigitsInputFilterTestCaseWithZeroMaxLength.m:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 CFT
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | @import XCTest;
22 | @import FTCTextEntryFormatting;
23 |
24 |
25 | @interface FTCDigitsInputFilterTestCaseWithZeroMaxLength : XCTestCase
26 | @end
27 |
28 | @implementation FTCDigitsInputFilterTestCaseWithZeroMaxLength
29 | {
30 | FTCDigitsValueFilter *filter;
31 | }
32 |
33 | - (void)setUp
34 | {
35 | [super setUp];
36 |
37 | filter = [[FTCDigitsValueFilter alloc] initWithMaxLength:0];
38 | }
39 |
40 | - (void)test_filter_empty_string
41 | {
42 | NSString *string = @"";
43 | NSString *filteredString = [filter filterString:string];
44 |
45 | XCTAssertEqualObjects(string, filteredString);
46 | }
47 |
48 | - (void)test_filter_non_empty_digits_only_string
49 | {
50 | NSString *string = @"233223";
51 | NSString *filteredString = [filter filterString:string];
52 |
53 | XCTAssertEqualObjects(string, filteredString);
54 | }
55 |
56 | - (void)test_filter_non_empty_string
57 | {
58 | NSString *string = @"asdsdf33223dd";
59 | NSString *etalon = @"33223";
60 | NSString *filteredString = [filter filterString:string];
61 |
62 | XCTAssertEqualObjects(etalon, filteredString);
63 | }
64 |
65 | - (void)test_filter_digits_string_with_comma_delemiter
66 | {
67 | NSString *string = @"332,23";
68 | NSString *etalon = @"33223";
69 | NSString *filteredString = [filter filterString:string];
70 |
71 | XCTAssertEqualObjects(etalon, filteredString);
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------