├── .gitignore ├── AutocompleteTextField.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── AutocompleteTextField.xcscheme ├── CODE_OF_CONDUCT.md ├── Example ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── DomainCompletionSource.swift ├── Info.plist ├── ViewController.swift └── topdomains.txt ├── LICENSE ├── README.md ├── Source ├── AutocompleteTextField.h ├── AutocompleteTextField.swift └── Info.plist └── Tests ├── AutocompleteTextFieldUITests.swift └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/ 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | xcuserdata 12 | *.xccheckout 13 | *.moved-aside 14 | DerivedData 15 | *.hmap 16 | *.ipa 17 | *.xcuserstate 18 | *.xcscmblueprint 19 | 20 | # OS X 21 | .DS_Store 22 | 23 | # Vim 24 | *~ 25 | .*.sw* 26 | 27 | # IDEA 28 | .idea 29 | 30 | # Python 31 | *.pyc 32 | 33 | Carthage 34 | -------------------------------------------------------------------------------- /AutocompleteTextField.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D31083431EAA7BF500ECF778 /* AutocompleteTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D31083351EAA7BF500ECF778 /* AutocompleteTextField.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | D31083531EAA7C3700ECF778 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31083521EAA7C3700ECF778 /* AppDelegate.swift */; }; 12 | D31083551EAA7C3700ECF778 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31083541EAA7C3700ECF778 /* ViewController.swift */; }; 13 | D31083581EAA7C3700ECF778 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D31083561EAA7C3700ECF778 /* Main.storyboard */; }; 14 | D310835A1EAA7C3700ECF778 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D31083591EAA7C3700ECF778 /* Assets.xcassets */; }; 15 | D310835D1EAA7C3700ECF778 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D310835B1EAA7C3700ECF778 /* LaunchScreen.storyboard */; }; 16 | D31083631EAA7CA200ECF778 /* AutocompleteTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31083621EAA7CA200ECF778 /* AutocompleteTextField.swift */; }; 17 | D31083641EAA86A500ECF778 /* AutocompleteTextField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D31083321EAA7BF500ECF778 /* AutocompleteTextField.framework */; }; 18 | D31083661EAA885C00ECF778 /* topdomains.txt in Resources */ = {isa = PBXBuildFile; fileRef = D31083651EAA885C00ECF778 /* topdomains.txt */; }; 19 | D310836A1EAA8B4A00ECF778 /* DomainCompletionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31083691EAA8B4A00ECF778 /* DomainCompletionSource.swift */; }; 20 | D37068731EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D37068721EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.swift */; }; 21 | D370687B1EAE69C6000D6BA7 /* AutocompleteTextField.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D31083321EAA7BF500ECF778 /* AutocompleteTextField.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | D37068751EAE68B2000D6BA7 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = D31083291EAA7BF500ECF778 /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = D310834F1EAA7C3600ECF778; 30 | remoteInfo = AutocompleteTextFieldExample; 31 | }; 32 | D370687C1EAE69C6000D6BA7 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = D31083291EAA7BF500ECF778 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = D31083311EAA7BF500ECF778; 37 | remoteInfo = AutocompleteTextField; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | D370687E1EAE69C6000D6BA7 /* Embed Frameworks */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = ""; 46 | dstSubfolderSpec = 10; 47 | files = ( 48 | D370687B1EAE69C6000D6BA7 /* AutocompleteTextField.framework in Embed Frameworks */, 49 | ); 50 | name = "Embed Frameworks"; 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXCopyFilesBuildPhase section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | D31083321EAA7BF500ECF778 /* AutocompleteTextField.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AutocompleteTextField.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | D31083351EAA7BF500ECF778 /* AutocompleteTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AutocompleteTextField.h; sourceTree = ""; }; 58 | D31083361EAA7BF500ECF778 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | D31083501EAA7C3600ECF778 /* AutocompleteTextFieldExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutocompleteTextFieldExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | D31083521EAA7C3700ECF778 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 61 | D31083541EAA7C3700ECF778 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 62 | D31083571EAA7C3700ECF778 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 63 | D31083591EAA7C3700ECF778 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 64 | D310835C1EAA7C3700ECF778 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 65 | D310835E1EAA7C3700ECF778 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | D31083621EAA7CA200ECF778 /* AutocompleteTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutocompleteTextField.swift; sourceTree = ""; }; 67 | D31083651EAA885C00ECF778 /* topdomains.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = topdomains.txt; sourceTree = ""; }; 68 | D31083691EAA8B4A00ECF778 /* DomainCompletionSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainCompletionSource.swift; sourceTree = ""; }; 69 | D37068701EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutocompleteTextFieldUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | D37068721EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteTextFieldUITests.swift; sourceTree = ""; }; 71 | D37068741EAE68B2000D6BA7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | D310832E1EAA7BF500ECF778 /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | D310834D1EAA7C3600ECF778 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | D31083641EAA86A500ECF778 /* AutocompleteTextField.framework in Frameworks */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | D370686D1EAE68B2000D6BA7 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | /* End PBXFrameworksBuildPhase section */ 98 | 99 | /* Begin PBXGroup section */ 100 | D31083281EAA7BF500ECF778 = { 101 | isa = PBXGroup; 102 | children = ( 103 | D31083341EAA7BF500ECF778 /* Source */, 104 | D31083511EAA7C3700ECF778 /* Example */, 105 | D37068711EAE68B2000D6BA7 /* Tests */, 106 | D31083331EAA7BF500ECF778 /* Products */, 107 | ); 108 | sourceTree = ""; 109 | }; 110 | D31083331EAA7BF500ECF778 /* Products */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | D31083321EAA7BF500ECF778 /* AutocompleteTextField.framework */, 114 | D31083501EAA7C3600ECF778 /* AutocompleteTextFieldExample.app */, 115 | D37068701EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.xctest */, 116 | ); 117 | name = Products; 118 | sourceTree = ""; 119 | }; 120 | D31083341EAA7BF500ECF778 /* Source */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | D31083351EAA7BF500ECF778 /* AutocompleteTextField.h */, 124 | D31083361EAA7BF500ECF778 /* Info.plist */, 125 | D31083621EAA7CA200ECF778 /* AutocompleteTextField.swift */, 126 | ); 127 | path = Source; 128 | sourceTree = ""; 129 | }; 130 | D31083511EAA7C3700ECF778 /* Example */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | D310835E1EAA7C3700ECF778 /* Info.plist */, 134 | D31083521EAA7C3700ECF778 /* AppDelegate.swift */, 135 | D31083691EAA8B4A00ECF778 /* DomainCompletionSource.swift */, 136 | D31083541EAA7C3700ECF778 /* ViewController.swift */, 137 | D31083651EAA885C00ECF778 /* topdomains.txt */, 138 | D31083591EAA7C3700ECF778 /* Assets.xcassets */, 139 | D310835B1EAA7C3700ECF778 /* LaunchScreen.storyboard */, 140 | D31083561EAA7C3700ECF778 /* Main.storyboard */, 141 | ); 142 | path = Example; 143 | sourceTree = ""; 144 | }; 145 | D37068711EAE68B2000D6BA7 /* Tests */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | D37068721EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.swift */, 149 | D37068741EAE68B2000D6BA7 /* Info.plist */, 150 | ); 151 | path = Tests; 152 | sourceTree = ""; 153 | }; 154 | /* End PBXGroup section */ 155 | 156 | /* Begin PBXHeadersBuildPhase section */ 157 | D310832F1EAA7BF500ECF778 /* Headers */ = { 158 | isa = PBXHeadersBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | D31083431EAA7BF500ECF778 /* AutocompleteTextField.h in Headers */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXHeadersBuildPhase section */ 166 | 167 | /* Begin PBXNativeTarget section */ 168 | D31083311EAA7BF500ECF778 /* AutocompleteTextField */ = { 169 | isa = PBXNativeTarget; 170 | buildConfigurationList = D31083461EAA7BF500ECF778 /* Build configuration list for PBXNativeTarget "AutocompleteTextField" */; 171 | buildPhases = ( 172 | D310832D1EAA7BF500ECF778 /* Sources */, 173 | D310832E1EAA7BF500ECF778 /* Frameworks */, 174 | D310832F1EAA7BF500ECF778 /* Headers */, 175 | D31083301EAA7BF500ECF778 /* Resources */, 176 | ); 177 | buildRules = ( 178 | ); 179 | dependencies = ( 180 | ); 181 | name = AutocompleteTextField; 182 | productName = AutocompleteTextField; 183 | productReference = D31083321EAA7BF500ECF778 /* AutocompleteTextField.framework */; 184 | productType = "com.apple.product-type.framework"; 185 | }; 186 | D310834F1EAA7C3600ECF778 /* AutocompleteTextFieldExample */ = { 187 | isa = PBXNativeTarget; 188 | buildConfigurationList = D310835F1EAA7C3700ECF778 /* Build configuration list for PBXNativeTarget "AutocompleteTextFieldExample" */; 189 | buildPhases = ( 190 | D310834C1EAA7C3600ECF778 /* Sources */, 191 | D310834D1EAA7C3600ECF778 /* Frameworks */, 192 | D310834E1EAA7C3600ECF778 /* Resources */, 193 | D370687E1EAE69C6000D6BA7 /* Embed Frameworks */, 194 | ); 195 | buildRules = ( 196 | ); 197 | dependencies = ( 198 | D370687D1EAE69C6000D6BA7 /* PBXTargetDependency */, 199 | ); 200 | name = AutocompleteTextFieldExample; 201 | productName = AutocompleteTextFieldExample; 202 | productReference = D31083501EAA7C3600ECF778 /* AutocompleteTextFieldExample.app */; 203 | productType = "com.apple.product-type.application"; 204 | }; 205 | D370686F1EAE68B2000D6BA7 /* AutocompleteTextFieldUITests */ = { 206 | isa = PBXNativeTarget; 207 | buildConfigurationList = D37068771EAE68B2000D6BA7 /* Build configuration list for PBXNativeTarget "AutocompleteTextFieldUITests" */; 208 | buildPhases = ( 209 | D370686C1EAE68B2000D6BA7 /* Sources */, 210 | D370686D1EAE68B2000D6BA7 /* Frameworks */, 211 | D370686E1EAE68B2000D6BA7 /* Resources */, 212 | ); 213 | buildRules = ( 214 | ); 215 | dependencies = ( 216 | D37068761EAE68B2000D6BA7 /* PBXTargetDependency */, 217 | ); 218 | name = AutocompleteTextFieldUITests; 219 | productName = AutocompleteTextFieldExampleUITests; 220 | productReference = D37068701EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.xctest */; 221 | productType = "com.apple.product-type.bundle.ui-testing"; 222 | }; 223 | /* End PBXNativeTarget section */ 224 | 225 | /* Begin PBXProject section */ 226 | D31083291EAA7BF500ECF778 /* Project object */ = { 227 | isa = PBXProject; 228 | attributes = { 229 | LastSwiftUpdateCheck = 0820; 230 | LastUpgradeCheck = 0820; 231 | ORGANIZATIONNAME = Mozilla; 232 | TargetAttributes = { 233 | D31083311EAA7BF500ECF778 = { 234 | CreatedOnToolsVersion = 8.2.1; 235 | DevelopmentTeam = 43AQ936H96; 236 | LastSwiftMigration = 0820; 237 | ProvisioningStyle = Automatic; 238 | }; 239 | D310834F1EAA7C3600ECF778 = { 240 | CreatedOnToolsVersion = 8.2.1; 241 | DevelopmentTeam = 43AQ936H96; 242 | ProvisioningStyle = Automatic; 243 | }; 244 | D370686F1EAE68B2000D6BA7 = { 245 | CreatedOnToolsVersion = 8.2.1; 246 | DevelopmentTeam = 43AQ936H96; 247 | ProvisioningStyle = Automatic; 248 | TestTargetID = D310834F1EAA7C3600ECF778; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = D310832C1EAA7BF500ECF778 /* Build configuration list for PBXProject "AutocompleteTextField" */; 253 | compatibilityVersion = "Xcode 3.2"; 254 | developmentRegion = English; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | English, 258 | en, 259 | Base, 260 | ); 261 | mainGroup = D31083281EAA7BF500ECF778; 262 | productRefGroup = D31083331EAA7BF500ECF778 /* Products */; 263 | projectDirPath = ""; 264 | projectRoot = ""; 265 | targets = ( 266 | D31083311EAA7BF500ECF778 /* AutocompleteTextField */, 267 | D310834F1EAA7C3600ECF778 /* AutocompleteTextFieldExample */, 268 | D370686F1EAE68B2000D6BA7 /* AutocompleteTextFieldUITests */, 269 | ); 270 | }; 271 | /* End PBXProject section */ 272 | 273 | /* Begin PBXResourcesBuildPhase section */ 274 | D31083301EAA7BF500ECF778 /* Resources */ = { 275 | isa = PBXResourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | D310834E1EAA7C3600ECF778 /* Resources */ = { 282 | isa = PBXResourcesBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | D310835D1EAA7C3700ECF778 /* LaunchScreen.storyboard in Resources */, 286 | D310835A1EAA7C3700ECF778 /* Assets.xcassets in Resources */, 287 | D31083661EAA885C00ECF778 /* topdomains.txt in Resources */, 288 | D31083581EAA7C3700ECF778 /* Main.storyboard in Resources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | D370686E1EAE68B2000D6BA7 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | /* End PBXResourcesBuildPhase section */ 300 | 301 | /* Begin PBXSourcesBuildPhase section */ 302 | D310832D1EAA7BF500ECF778 /* Sources */ = { 303 | isa = PBXSourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | D31083631EAA7CA200ECF778 /* AutocompleteTextField.swift in Sources */, 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | }; 310 | D310834C1EAA7C3600ECF778 /* Sources */ = { 311 | isa = PBXSourcesBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | D310836A1EAA8B4A00ECF778 /* DomainCompletionSource.swift in Sources */, 315 | D31083551EAA7C3700ECF778 /* ViewController.swift in Sources */, 316 | D31083531EAA7C3700ECF778 /* AppDelegate.swift in Sources */, 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | D370686C1EAE68B2000D6BA7 /* Sources */ = { 321 | isa = PBXSourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | D37068731EAE68B2000D6BA7 /* AutocompleteTextFieldUITests.swift in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | /* End PBXSourcesBuildPhase section */ 329 | 330 | /* Begin PBXTargetDependency section */ 331 | D37068761EAE68B2000D6BA7 /* PBXTargetDependency */ = { 332 | isa = PBXTargetDependency; 333 | target = D310834F1EAA7C3600ECF778 /* AutocompleteTextFieldExample */; 334 | targetProxy = D37068751EAE68B2000D6BA7 /* PBXContainerItemProxy */; 335 | }; 336 | D370687D1EAE69C6000D6BA7 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = D31083311EAA7BF500ECF778 /* AutocompleteTextField */; 339 | targetProxy = D370687C1EAE69C6000D6BA7 /* PBXContainerItemProxy */; 340 | }; 341 | /* End PBXTargetDependency section */ 342 | 343 | /* Begin PBXVariantGroup section */ 344 | D31083561EAA7C3700ECF778 /* Main.storyboard */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | D31083571EAA7C3700ECF778 /* Base */, 348 | ); 349 | name = Main.storyboard; 350 | sourceTree = ""; 351 | }; 352 | D310835B1EAA7C3700ECF778 /* LaunchScreen.storyboard */ = { 353 | isa = PBXVariantGroup; 354 | children = ( 355 | D310835C1EAA7C3700ECF778 /* Base */, 356 | ); 357 | name = LaunchScreen.storyboard; 358 | sourceTree = ""; 359 | }; 360 | /* End PBXVariantGroup section */ 361 | 362 | /* Begin XCBuildConfiguration section */ 363 | D31083441EAA7BF500ECF778 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ALWAYS_SEARCH_USER_PATHS = NO; 367 | CLANG_ANALYZER_NONNULL = YES; 368 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 369 | CLANG_CXX_LIBRARY = "libc++"; 370 | CLANG_ENABLE_MODULES = YES; 371 | CLANG_ENABLE_OBJC_ARC = YES; 372 | CLANG_WARN_BOOL_CONVERSION = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 375 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INFINITE_RECURSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 381 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 382 | CLANG_WARN_UNREACHABLE_CODE = YES; 383 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 384 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 385 | COPY_PHASE_STRIP = NO; 386 | CURRENT_PROJECT_VERSION = 1; 387 | DEBUG_INFORMATION_FORMAT = dwarf; 388 | ENABLE_STRICT_OBJC_MSGSEND = YES; 389 | ENABLE_TESTABILITY = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_DYNAMIC_NO_PIC = NO; 392 | GCC_NO_COMMON_BLOCKS = YES; 393 | GCC_OPTIMIZATION_LEVEL = 0; 394 | GCC_PREPROCESSOR_DEFINITIONS = ( 395 | "DEBUG=1", 396 | "$(inherited)", 397 | ); 398 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 399 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 400 | GCC_WARN_UNDECLARED_SELECTOR = YES; 401 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 402 | GCC_WARN_UNUSED_FUNCTION = YES; 403 | GCC_WARN_UNUSED_VARIABLE = YES; 404 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 405 | MTL_ENABLE_DEBUG_INFO = YES; 406 | ONLY_ACTIVE_ARCH = YES; 407 | SDKROOT = iphoneos; 408 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 409 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 410 | SWIFT_VERSION = 4.2; 411 | TARGETED_DEVICE_FAMILY = "1,2"; 412 | VERSIONING_SYSTEM = "apple-generic"; 413 | VERSION_INFO_PREFIX = ""; 414 | }; 415 | name = Debug; 416 | }; 417 | D31083451EAA7BF500ECF778 /* Release */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ALWAYS_SEARCH_USER_PATHS = NO; 421 | CLANG_ANALYZER_NONNULL = YES; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BOOL_CONVERSION = YES; 427 | CLANG_WARN_CONSTANT_CONVERSION = YES; 428 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 429 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 430 | CLANG_WARN_EMPTY_BODY = YES; 431 | CLANG_WARN_ENUM_CONVERSION = YES; 432 | CLANG_WARN_INFINITE_RECURSION = YES; 433 | CLANG_WARN_INT_CONVERSION = YES; 434 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = NO; 440 | CURRENT_PROJECT_VERSION = 1; 441 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 442 | ENABLE_NS_ASSERTIONS = NO; 443 | ENABLE_STRICT_OBJC_MSGSEND = YES; 444 | GCC_C_LANGUAGE_STANDARD = gnu99; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 447 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 448 | GCC_WARN_UNDECLARED_SELECTOR = YES; 449 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 450 | GCC_WARN_UNUSED_FUNCTION = YES; 451 | GCC_WARN_UNUSED_VARIABLE = YES; 452 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 453 | MTL_ENABLE_DEBUG_INFO = NO; 454 | SDKROOT = iphoneos; 455 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 456 | SWIFT_VERSION = 4.2; 457 | TARGETED_DEVICE_FAMILY = "1,2"; 458 | VALIDATE_PRODUCT = YES; 459 | VERSIONING_SYSTEM = "apple-generic"; 460 | VERSION_INFO_PREFIX = ""; 461 | }; 462 | name = Release; 463 | }; 464 | D31083471EAA7BF500ECF778 /* Debug */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | CLANG_ENABLE_MODULES = YES; 468 | CODE_SIGN_IDENTITY = ""; 469 | DEFINES_MODULE = YES; 470 | DEVELOPMENT_TEAM = 43AQ936H96; 471 | DYLIB_COMPATIBILITY_VERSION = 1; 472 | DYLIB_CURRENT_VERSION = 1; 473 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 474 | INFOPLIST_FILE = Source/Info.plist; 475 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 476 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 477 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 478 | PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.AutocompleteTextField; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | SKIP_INSTALL = YES; 481 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 482 | }; 483 | name = Debug; 484 | }; 485 | D31083481EAA7BF500ECF778 /* Release */ = { 486 | isa = XCBuildConfiguration; 487 | buildSettings = { 488 | CLANG_ENABLE_MODULES = YES; 489 | CODE_SIGN_IDENTITY = ""; 490 | DEFINES_MODULE = YES; 491 | DEVELOPMENT_TEAM = 43AQ936H96; 492 | DYLIB_COMPATIBILITY_VERSION = 1; 493 | DYLIB_CURRENT_VERSION = 1; 494 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 495 | INFOPLIST_FILE = Source/Info.plist; 496 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 497 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 498 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 499 | PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.AutocompleteTextField; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | SKIP_INSTALL = YES; 502 | }; 503 | name = Release; 504 | }; 505 | D31083601EAA7C3700ECF778 /* Debug */ = { 506 | isa = XCBuildConfiguration; 507 | buildSettings = { 508 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 509 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 510 | DEVELOPMENT_TEAM = 43AQ936H96; 511 | INFOPLIST_FILE = Example/Info.plist; 512 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 513 | PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.AutocompleteTextFieldExample; 514 | PRODUCT_NAME = "$(TARGET_NAME)"; 515 | }; 516 | name = Debug; 517 | }; 518 | D31083611EAA7C3700ECF778 /* Release */ = { 519 | isa = XCBuildConfiguration; 520 | buildSettings = { 521 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 522 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 523 | DEVELOPMENT_TEAM = 43AQ936H96; 524 | INFOPLIST_FILE = Example/Info.plist; 525 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 526 | PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.AutocompleteTextFieldExample; 527 | PRODUCT_NAME = "$(TARGET_NAME)"; 528 | }; 529 | name = Release; 530 | }; 531 | D37068781EAE68B2000D6BA7 /* Debug */ = { 532 | isa = XCBuildConfiguration; 533 | buildSettings = { 534 | DEVELOPMENT_TEAM = 43AQ936H96; 535 | INFOPLIST_FILE = Tests/Info.plist; 536 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 537 | PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.AutocompleteTextFieldUITests; 538 | PRODUCT_NAME = "$(TARGET_NAME)"; 539 | TEST_TARGET_NAME = AutocompleteTextFieldExample; 540 | }; 541 | name = Debug; 542 | }; 543 | D37068791EAE68B2000D6BA7 /* Release */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | DEVELOPMENT_TEAM = 43AQ936H96; 547 | INFOPLIST_FILE = Tests/Info.plist; 548 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 549 | PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.AutocompleteTextFieldUITests; 550 | PRODUCT_NAME = "$(TARGET_NAME)"; 551 | TEST_TARGET_NAME = AutocompleteTextFieldExample; 552 | }; 553 | name = Release; 554 | }; 555 | /* End XCBuildConfiguration section */ 556 | 557 | /* Begin XCConfigurationList section */ 558 | D310832C1EAA7BF500ECF778 /* Build configuration list for PBXProject "AutocompleteTextField" */ = { 559 | isa = XCConfigurationList; 560 | buildConfigurations = ( 561 | D31083441EAA7BF500ECF778 /* Debug */, 562 | D31083451EAA7BF500ECF778 /* Release */, 563 | ); 564 | defaultConfigurationIsVisible = 0; 565 | defaultConfigurationName = Release; 566 | }; 567 | D31083461EAA7BF500ECF778 /* Build configuration list for PBXNativeTarget "AutocompleteTextField" */ = { 568 | isa = XCConfigurationList; 569 | buildConfigurations = ( 570 | D31083471EAA7BF500ECF778 /* Debug */, 571 | D31083481EAA7BF500ECF778 /* Release */, 572 | ); 573 | defaultConfigurationIsVisible = 0; 574 | defaultConfigurationName = Release; 575 | }; 576 | D310835F1EAA7C3700ECF778 /* Build configuration list for PBXNativeTarget "AutocompleteTextFieldExample" */ = { 577 | isa = XCConfigurationList; 578 | buildConfigurations = ( 579 | D31083601EAA7C3700ECF778 /* Debug */, 580 | D31083611EAA7C3700ECF778 /* Release */, 581 | ); 582 | defaultConfigurationIsVisible = 0; 583 | defaultConfigurationName = Release; 584 | }; 585 | D37068771EAE68B2000D6BA7 /* Build configuration list for PBXNativeTarget "AutocompleteTextFieldUITests" */ = { 586 | isa = XCConfigurationList; 587 | buildConfigurations = ( 588 | D37068781EAE68B2000D6BA7 /* Debug */, 589 | D37068791EAE68B2000D6BA7 /* Release */, 590 | ); 591 | defaultConfigurationIsVisible = 0; 592 | defaultConfigurationName = Release; 593 | }; 594 | /* End XCConfigurationList section */ 595 | }; 596 | rootObject = D31083291EAA7BF500ECF778 /* Project object */; 597 | } 598 | -------------------------------------------------------------------------------- /AutocompleteTextField.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutocompleteTextField.xcodeproj/xcshareddata/xcschemes/AutocompleteTextField.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. 9 | 10 | 16 | -------------------------------------------------------------------------------- /Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | import UIKit 6 | 7 | @UIApplicationMain 8 | class AppDelegate: UIResponder, UIApplicationDelegate { 9 | 10 | var window: UIWindow? 11 | 12 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 13 | return true 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /Example/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 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/DomainCompletionSource.swift: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | import Foundation 6 | import AutocompleteTextField 7 | 8 | class DomainCompletionSource: AutocompleteTextFieldCompletionSource { 9 | private var topDomains: [String] = { 10 | let filePath = Bundle.main.path(forResource: "topdomains", ofType: "txt") 11 | return try! String(contentsOfFile: filePath!).components(separatedBy: "\n") 12 | }() 13 | 14 | func autocompleteTextFieldCompletionSource(_ autocompleteTextField: AutocompleteTextField, forText text: String) -> String? { 15 | guard !text.isEmpty else { return nil } 16 | 17 | for domain in self.topDomains { 18 | if let completion = self.completion(forDomain: domain, withText: text) { 19 | return completion 20 | } 21 | } 22 | 23 | return nil 24 | } 25 | private func completion(forDomain domain: String, withText text: String) -> String? { 26 | let domainWithDotPrefix: String = ".www.\(domain)" 27 | if let range = domainWithDotPrefix.range(of: ".\(text)", options: .caseInsensitive, range: nil, locale: nil) { 28 | // We don't actually want to match the top-level domain ("com", "org", etc.) by itself, so 29 | // so make sure the result includes at least one ".". 30 | let range = domainWithDotPrefix.index(range.lowerBound, offsetBy: 1) 31 | let matchedDomain: String = domainWithDotPrefix.substring(from: range) 32 | if matchedDomain.contains(".") { 33 | return matchedDomain + "/" 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 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 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | import UIKit 6 | import AutocompleteTextField 7 | 8 | class ViewController: UIViewController { 9 | let domainCompletionSource = DomainCompletionSource() 10 | 11 | override func viewDidLoad() { 12 | super.viewDidLoad() 13 | 14 | let textField = AutocompleteTextField() 15 | textField.layer.borderColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1).cgColor 16 | textField.layer.borderWidth = 0.5 17 | textField.keyboardType = .webSearch 18 | textField.autocapitalizationType = .none 19 | textField.autocorrectionType = .no 20 | textField.completionSource = domainCompletionSource 21 | textField.accessibilityLabel = "Domain" 22 | view.addSubview(textField) 23 | 24 | textField.translatesAutoresizingMaskIntoConstraints = false 25 | NSLayoutConstraint.activate([ 26 | textField.centerYAnchor.constraint(equalTo: view.centerYAnchor), 27 | textField.widthAnchor.constraint(equalTo: view.widthAnchor), 28 | ]) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Example/topdomains.txt: -------------------------------------------------------------------------------- 1 | google.com 2 | facebook.com 3 | amazon.com 4 | youtube.com 5 | yahoo.com 6 | ebay.com 7 | wikipedia.org 8 | twitter.com 9 | reddit.com 10 | go.com 11 | craigslist.org 12 | live.com 13 | netflix.com 14 | pinterest.com 15 | bing.com 16 | linkedin.com 17 | imgur.com 18 | espn.go.com 19 | walmart.com 20 | tumblr.com 21 | target.com 22 | paypal.com 23 | cnn.com 24 | chase.com 25 | instagram.com 26 | bestbuy.com 27 | blogspot.com 28 | nytimes.com 29 | msn.com 30 | imdb.com 31 | apple.com 32 | bankofamerica.com 33 | diply.com 34 | huffingtonpost.com 35 | yelp.com 36 | wellsfargo.com 37 | etsy.com 38 | weather.com 39 | wordpress.com 40 | buzzfeed.com 41 | zillow.com 42 | kohls.com 43 | aol.com 44 | homedepot.com 45 | foxnews.com 46 | microsoft.com 47 | comcast.net 48 | wikia.com 49 | groupon.com 50 | macys.com 51 | washingtonpost.com 52 | outbrain.com 53 | microsoftonline.com 54 | xfinity.com 55 | usps.com 56 | hulu.com 57 | americanexpress.com 58 | slickdeals.net 59 | pandora.com 60 | office.com 61 | cnet.com 62 | indeed.com 63 | capitalone.com 64 | nfl.com 65 | ups.com 66 | ask.com 67 | verizonwireless.com 68 | newegg.com 69 | usatoday.com 70 | forbes.com 71 | dailymail.co.uk 72 | dropbox.com 73 | att.com 74 | costco.com 75 | gfycat.com 76 | lowes.com 77 | gap.com 78 | about.com 79 | tripadvisor.com 80 | fedex.com 81 | baidu.com 82 | vice.com 83 | nordstrom.com 84 | adobe.com 85 | bbc.com 86 | twitch.tv 87 | allrecipes.com 88 | retailmenot.com 89 | stackoverflow.com 90 | citi.com 91 | sears.com 92 | jcpenney.com 93 | webmd.com 94 | ijreview.com 95 | nih.gov 96 | answers.com 97 | foodnetwork.com 98 | discovercard.com 99 | cbssports.com 100 | overstock.com 101 | businessinsider.com 102 | office365.com 103 | theguardian.com 104 | staples.com 105 | bleacherreport.com 106 | toysrus.com 107 | verizon.com 108 | github.com 109 | wayfair.com 110 | salesforce.com 111 | zulily.com 112 | wsj.com 113 | flickr.com 114 | goodreads.com 115 | realtor.com 116 | nbcnews.com 117 | ebates.com 118 | ancestry.com 119 | wunderground.com 120 | instructure.com 121 | people.com 122 | stackexchange.com 123 | drudgereport.com 124 | fidelity.com 125 | southwest.com 126 | deviantart.com 127 | thesaurus.com 128 | intuit.com 129 | woot.com 130 | pch.com 131 | soundcloud.com 132 | force.com 133 | samsclub.com 134 | ign.com 135 | qvc.com 136 | npr.org 137 | patch.com 138 | dell.com 139 | accuweather.com 140 | vimeo.com 141 | expedia.com 142 | trulia.com 143 | ca.gov 144 | swagbucks.com 145 | spotify.com 146 | bedbathandbeyond.com 147 | nypost.com 148 | aliexpress.com 149 | blackboard.com 150 | ticketmaster.com 151 | ikea.com 152 | feedly.com 153 | usaa.com 154 | tmz.com 155 | quora.com 156 | lifehacker.com 157 | kayak.com 158 | reference.com 159 | zappos.com 160 | gizmodo.com 161 | slate.com 162 | faithtap.com 163 | adp.com 164 | abcnews.go.com 165 | sephora.com 166 | cbs.com 167 | latimes.com 168 | shutterfly.com 169 | t-mobile.com 170 | littlethings.com 171 | glassdoor.com 172 | bloomberg.com 173 | cbsnews.com 174 | wikihow.com 175 | walgreens.com 176 | usbank.com 177 | blogger.com 178 | weebly.com 179 | gamestop.com 180 | food.com 181 | time.com 182 | kickstarter.com 183 | okcupid.com 184 | aa.com 185 | weather.gov 186 | nametests.com 187 | fandango.com 188 | engadget.com 189 | steamcommunity.com 190 | thekitchn.com 191 | nba.com 192 | mashable.com 193 | hp.com 194 | gamefaqs.com 195 | delta.com 196 | breitbart.com 197 | coupons.com 198 | eonline.com 199 | surveymonkey.com 200 | kmart.com 201 | barnesandnoble.com 202 | meetup.com 203 | bhphotovideo.com 204 | fanduel.com 205 | quizlet.com 206 | nydailynews.com 207 | sbnation.com 208 | nbcsports.com 209 | likes.com 210 | bbc.co.uk 211 | ew.com 212 | nike.com 213 | rottentomatoes.com 214 | steampowered.com 215 | reuters.com 216 | qq.com 217 | today.com 218 | mapquest.com 219 | audible.com 220 | priceline.com 221 | whitepages.com 222 | united.com 223 | myfitnesspal.com 224 | icloud.com 225 | forever21.com 226 | theatlantic.com 227 | microsoftstore.com 228 | theverge.com 229 | gawker.com 230 | houzz.com 231 | mayoclinic.org 232 | rei.com 233 | sfgate.com 234 | lifebuzz.com 235 | discover.com 236 | pnc.com 237 | pof.com 238 | iflscience.com 239 | popsugar.com 240 | creditkarma.com 241 | telegraph.co.uk 242 | airbnb.com 243 | buzzlie.com 244 | cnbc.com 245 | deadspin.com 246 | sina.com.cn 247 | legacy.com 248 | thedailybeast.com 249 | samsung.com 250 | nextdoor.com 251 | evite.com 252 | shopify.com 253 | yellowpages.com 254 | pcmag.com 255 | redfin.com 256 | emgn.com 257 | weibo.com 258 | alibaba.com 259 | cabelas.com 260 | battle.net 261 | foxsports.com 262 | taobao.com 263 | eventbrite.com 264 | victoriassecret.com 265 | theblaze.com 266 | dealnews.com 267 | cbslocal.com 268 | cvs.com 269 | dailymotion.com 270 | ecollege.com 271 | gofundme.com 272 | fitbit.com 273 | instructables.com 274 | godaddy.com 275 | babycenter.com 276 | squarespace.com 277 | llbean.com 278 | dickssportinggoods.com 279 | 6pm.com 280 | myway.com 281 | hsn.com 282 | wired.com 283 | officedepot.com 284 | ozztube.com 285 | usmagazine.com 286 | match.com 287 | cracked.com 288 | evernote.com 289 | box.com 290 | starbucks.com 291 | kbb.com 292 | mlb.com 293 | marriott.com 294 | si.com 295 | jezebel.com 296 | pbs.org 297 | consumerreports.org 298 | roblox.com 299 | urbandictionary.com 300 | kotaku.com 301 | xbox.com 302 | marketwatch.com 303 | refinery29.com 304 | wikimedia.org 305 | tvguide.com 306 | politico.com 307 | barclaycardus.com 308 | abc.go.com 309 | mint.com 310 | topix.com 311 | theblackfriday.com 312 | aarp.org 313 | hotnewhiphop.com 314 | yourdailydish.com 315 | sprint.com 316 | vox.com 317 | cafemom.com 318 | nbc.com 319 | dailykos.com 320 | azlyrics.com 321 | autotrader.com 322 | hilton.com 323 | irs.gov 324 | monster.com 325 | fatwallet.com 326 | mailchimp.com 327 | webex.com 328 | landsend.com 329 | wix.com 330 | usnews.com 331 | jcrew.com 332 | jet.com 333 | capitalone360.com 334 | sharepoint.com 335 | schwab.com 336 | ulta.com 337 | vistaprint.com 338 | rollingstone.com 339 | biblegateway.com 340 | gamespot.com 341 | io9.com 342 | opentable.com 343 | hm.com 344 | duckduckgo.com 345 | chron.com 346 | photobucket.com 347 | shareasale.com 348 | directv.com 349 | avg.com 350 | oracle.com 351 | hotels.com 352 | timewarnercable.com 353 | chicagotribune.com 354 | ehow.com 355 | primewire.ag 356 | abs-cbnnews.com 357 | salon.com 358 | greatergood.com 359 | epicurious.com 360 | fool.com 361 | patheos.com 362 | custhelp.com 363 | purdue.edu 364 | tickld.com 365 | frys.com 366 | indiatimes.com 367 | amazon.co.uk 368 | zendesk.com 369 | tigerdirect.com 370 | stubhub.com 371 | healthcare.gov 372 | archive.org 373 | qualtrics.com 374 | ravelry.com 375 | cars.com 376 | redbox.com 377 | jalopnik.com 378 | speedtest.net 379 | harvard.edu 380 | slideshare.net 381 | kinja.com 382 | nesn.com 383 | michaels.com 384 | mit.edu 385 | bodybuilding.com 386 | edmunds.com 387 | nhl.com 388 | zergnet.com 389 | terraclicks.com 390 | techcrunch.com 391 | regnok.com 392 | pogo.com 393 | backpage.com 394 | mozilla.org 395 | naver.com 396 | giphy.com 397 | bankrate.com 398 | msnbc.com 399 | digitaltrends.com 400 | fanfiction.net 401 | skype.com 402 | disney.go.com 403 | norton.com 404 | androidcentral.com 405 | tomshardware.com 406 | thefreedictionary.com 407 | liveleak.com 408 | 247sports.com 409 | merriam-webster.com 410 | wnd.com 411 | earthlink.net 412 | conservativetribune.com 413 | independent.co.uk 414 | drugs.com 415 | rotoworld.com 416 | nationalgeographic.com 417 | ae.com 418 | noaa.gov 419 | arstechnica.com 420 | thinkgeek.com 421 | stanford.edu 422 | bizjournals.com 423 | hootsuite.com 424 | genius.com 425 | goodhousekeeping.com 426 | vanguard.com 427 | ny.gov 428 | citibankonline.com 429 | booking.com 430 | mic.com 431 | orbitz.com 432 | dominos.com 433 | medium.com 434 | wow.com 435 | urbanoutfitters.com 436 | douban.com 437 | timeanddate.com 438 | draftkings.com 439 | livestrong.com 440 | livingsocial.com 441 | cox.net 442 | theonion.com 443 | marthastewart.com 444 | comenity.net 445 | worldlifestyle.com 446 | disney.com 447 | realsimple.com 448 | vrbo.com 449 | playstation.com 450 | potterybarn.com 451 | zazzle.com 452 | ksl.com 453 | tdbank.com 454 | sourceforge.net 455 | careerbuilder.com 456 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | 364 | 365 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutocompleteTextField 2 | An iOS text field that autocompletes text with the supplied list of words. 3 | 4 | ## Usage 5 | ```swift 6 | import AutocompleteTextField 7 | 8 | // First implement the completion source: 9 | extension ViewController: AutocompleteTextFieldCompletionSource { 10 | func autocompleteTextFieldCompletionSource(_ autocompleteTextField: AutocompleteTextField, forText text: String) -> String? { 11 | guard !text.isEmpty else { return nil } 12 | return domains.first { $0.hasPrefix(text) } 13 | } 14 | } 15 | 16 | class ViewController: UIViewController { 17 | let domains = ["mozilla.org", "google.com", "wikipedia.org"] 18 | 19 | override func viewDidLoad() { 20 | // Then create an AutocompleteTextField, attaching our source: 21 | let textField = AutocompleteTextField() 22 | textField.completionSource = self 23 | view.addSubview(textField) 24 | ... 25 | } 26 | } 27 | ``` 28 | 29 | To see this in action, run the example project! 30 | -------------------------------------------------------------------------------- /Source/AutocompleteTextField.h: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #import 6 | 7 | //! Project version number for AutocompleteTextField. 8 | FOUNDATION_EXPORT double AutocompleteTextFieldVersionNumber; 9 | 10 | //! Project version string for AutocompleteTextField. 11 | FOUNDATION_EXPORT const unsigned char AutocompleteTextFieldVersionString[]; 12 | -------------------------------------------------------------------------------- /Source/AutocompleteTextField.swift: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | import UIKit 6 | 7 | public protocol AutocompleteTextFieldCompletionSource: class { 8 | func autocompleteTextFieldCompletionSource(_ autocompleteTextField: AutocompleteTextField, forText text: String) -> String? 9 | } 10 | 11 | @objc public protocol AutocompleteTextFieldDelegate: class { 12 | @objc optional func autocompleteTextFieldShouldBeginEditing(_ autocompleteTextField: AutocompleteTextField) -> Bool 13 | @objc optional func autocompleteTextFieldShouldEndEditing(_ autocompleteTextField: AutocompleteTextField) -> Bool 14 | @objc optional func autocompleteTextFieldShouldReturn(_ autocompleteTextField: AutocompleteTextField) -> Bool 15 | @objc optional func autocompleteTextField(_ autocompleteTextField: AutocompleteTextField, didTextChange text: String) 16 | } 17 | 18 | open class AutocompleteTextField: UITextField, UITextFieldDelegate { 19 | public var highlightColor = UIColor(red: 0, green: 0.333, blue: 0.666, alpha: 0.2) 20 | 21 | public weak var completionSource: AutocompleteTextFieldCompletionSource? 22 | public weak var autocompleteDelegate: AutocompleteTextFieldDelegate? 23 | 24 | /// The range of the current completion, or nil if there is no active completion. 25 | private var completionRange: NSRange? 26 | 27 | // The last string used as a replacement in shouldChangeCharactersInRange. 28 | private var lastReplacement: String? 29 | 30 | public init() { 31 | super.init(frame: CGRect.zero) 32 | addTarget(self, action: #selector(textDidChange), for: .editingChanged) 33 | delegate = self 34 | } 35 | 36 | required public init?(coder aDecoder: NSCoder) { 37 | fatalError("init(coder:) has not been implemented") 38 | } 39 | 40 | override open var text: String? { 41 | didSet { 42 | applyCompletion() 43 | super.text = text 44 | } 45 | } 46 | 47 | public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 48 | lastReplacement = string 49 | return true 50 | } 51 | 52 | @objc private func textDidChange() { 53 | removeCompletion() 54 | 55 | // Try setting a completion if we're not deleting and we're typing at the end of the text field. 56 | let isAtEnd = selectedTextRange?.start == endOfDocument 57 | let textBeforeCompletion = text 58 | let isEmpty = lastReplacement?.isEmpty ?? true 59 | if !isEmpty, isAtEnd, markedTextRange == nil, 60 | let completion = completionSource?.autocompleteTextFieldCompletionSource(self, forText: text ?? "") { 61 | setCompletion(completion) 62 | } 63 | 64 | // Fire the delegate with the text the user typed (not including the completion). 65 | autocompleteDelegate?.autocompleteTextField?(self, didTextChange: textBeforeCompletion ?? "") 66 | } 67 | 68 | override open func deleteBackward() { 69 | lastReplacement = nil 70 | 71 | guard completionRange == nil else { 72 | // If we have an active completion, delete it without deleting any user-typed characters. 73 | removeCompletion() 74 | return 75 | } 76 | 77 | super.deleteBackward() 78 | } 79 | 80 | public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { 81 | return autocompleteDelegate?.autocompleteTextFieldShouldBeginEditing?(self) ?? true 82 | } 83 | 84 | public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { 85 | applyCompletion() 86 | return autocompleteDelegate?.autocompleteTextFieldShouldEndEditing?(self) ?? true 87 | } 88 | 89 | public func textFieldShouldReturn(_ textField: UITextField) -> Bool { 90 | return autocompleteDelegate?.autocompleteTextFieldShouldReturn?(self) ?? true 91 | } 92 | 93 | override open func touchesBegan(_ touches: Set, with event: UIEvent?) { 94 | applyCompletion() 95 | super.touchesBegan(touches, with: event) 96 | } 97 | 98 | override open func caretRect(for forPosition: UITextPosition) -> CGRect { 99 | return (completionRange != nil) ? CGRect.zero : super.caretRect(for: forPosition) 100 | } 101 | 102 | override open func setMarkedText(_ markedText: String?, selectedRange: NSRange) { 103 | removeCompletion() 104 | super.setMarkedText(markedText, selectedRange: selectedRange) 105 | } 106 | 107 | open func highlightAll() { 108 | let text = self.text 109 | self.text = nil 110 | setCompletion(text ?? "") 111 | selectedTextRange = textRange(from: beginningOfDocument, to: beginningOfDocument) 112 | } 113 | 114 | private func applyCompletion() { 115 | guard completionRange != nil else { return } 116 | 117 | completionRange = nil 118 | 119 | // Clear the current completion, then set the text without the attributed style. 120 | // The attributed string must have at least one character to clear the current style. 121 | let text = self.text ?? "" 122 | attributedText = NSAttributedString(string: " ") 123 | self.text = text 124 | 125 | // Move the cursor to the end of the completion. 126 | selectedTextRange = textRange(from: endOfDocument, to: endOfDocument) 127 | } 128 | 129 | private func removeCompletion() { 130 | guard let completionRange = completionRange else { return } 131 | 132 | applyCompletion() 133 | 134 | // Fixes: https://github.com/mozilla-mobile/focus-ios/issues/630 135 | // Prevents the hard crash when you select all and start a new query 136 | guard let count = text?.count, count > 1 else { return } 137 | 138 | text = (text as NSString?)?.replacingCharacters(in: completionRange, with: "") 139 | } 140 | 141 | private func setCompletion(_ completion: String) { 142 | let text = self.text ?? "" 143 | 144 | // Ignore this completion if it's empty or doesn't start with the current text. 145 | guard !completion.isEmpty, completion.lowercased().hasPrefix(text.lowercased()) else { return } 146 | 147 | // Add the completion suffix to the current text and highlight it. 148 | let completion = completion.substring(from: completion.index(completion.startIndex, offsetBy: text.characters.count)) 149 | let attributed = NSMutableAttributedString(string: text + completion) 150 | let range = NSMakeRange((text as NSString).length, (completion as NSString).length) 151 | attributed.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightColor, range: range) 152 | attributedText = attributed 153 | completionRange = range 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Source/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 | -------------------------------------------------------------------------------- /Tests/AutocompleteTextFieldUITests.swift: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | import XCTest 6 | 7 | class AutocompleteTextFieldUITests: XCTestCase { 8 | override func setUp() { 9 | super.setUp() 10 | 11 | continueAfterFailure = false 12 | XCUIApplication().launch() 13 | } 14 | 15 | override func tearDown() { 16 | super.tearDown() 17 | } 18 | 19 | func testExample() { 20 | let field = XCUIApplication().textFields["Domain"] 21 | field.tap() 22 | 23 | field.typeText("w") 24 | XCTAssertEqual(field.value! as! String, "www.google.com/") 25 | field.typeText(XCUIKeyboardKeyDelete) 26 | XCTAssertEqual(field.value! as! String, "w") 27 | field.typeText("ww.yah") 28 | XCTAssertEqual(field.value! as! String, "www.yahoo.com/") 29 | field.typeText(XCUIKeyboardKeyDelete) 30 | XCTAssertEqual(field.value! as! String, "www.yah") 31 | field.typeText(XCUIKeyboardKeyDelete) 32 | XCTAssertEqual(field.value! as! String, "www.ya") 33 | field.typeText(XCUIKeyboardKeyDelete) 34 | field.typeText(XCUIKeyboardKeyDelete) 35 | field.typeText(XCUIKeyboardKeyDelete) 36 | field.typeText(XCUIKeyboardKeyDelete) 37 | field.typeText(XCUIKeyboardKeyDelete) 38 | field.typeText(XCUIKeyboardKeyDelete) 39 | XCTAssertEqual(field.value! as! String, "") 40 | field.typeText("g") 41 | XCTAssertEqual(field.value! as! String, "google.com/") 42 | field.typeText("z") 43 | XCTAssertEqual(field.value! as! String, "gz") 44 | field.typeText(XCUIKeyboardKeyDelete) 45 | XCTAssertEqual(field.value! as! String, "g") 46 | field.typeText("o") 47 | XCTAssertEqual(field.value! as! String, "google.com/") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tests/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 | --------------------------------------------------------------------------------