Repository: jessesquires/PresenterKit Branch: main Commit: 77d4e2cb6b12 Files: 72 Total size: 430.7 KB Directory structure: gitextract_myk_b_mt/ ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── ci.yml │ ├── danger.yml │ ├── pod-lint.yml │ └── spm.yml ├── .gitignore ├── .swiftlint.yml ├── CHANGELOG.md ├── Dangerfile ├── Example/ │ ├── ExampleApp/ │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── ic_dismiss.imageset/ │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── MainViewController.swift │ │ └── RedViewController.swift │ ├── ExampleApp.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata/ │ │ ├── IDETemplateMacros.plist │ │ └── xcschemes/ │ │ └── ExampleApp.xcscheme │ └── ExampleAppUITests/ │ ├── ExampleAppUITests.swift │ └── Info.plist ├── Gemfile ├── Guides/ │ └── Getting Started.md ├── LICENSE ├── Package.swift ├── PresenterKit.podspec ├── PresenterKit.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata/ │ ├── IDETemplateMacros.plist │ └── xcschemes/ │ └── PresenterKit.xcscheme ├── README.md ├── Sources/ │ ├── DismissButtonConfig.swift │ ├── HalfModalPresentationController.swift │ ├── Info.plist │ ├── PresentationType.swift │ ├── UINavigationController+Extensions.swift │ └── UIViewController+Extensions.swift ├── Tests/ │ ├── Info.plist │ └── PresenterKitTests.swift ├── docs/ │ ├── Classes.html │ ├── Enums/ │ │ ├── NavigationStyle.html │ │ └── PresentationType.html │ ├── Enums.html │ ├── Extensions/ │ │ ├── UIBarButtonItem.html │ │ ├── UINavigationController.html │ │ └── UIViewController.html │ ├── Extensions.html │ ├── Guides.html │ ├── Structs/ │ │ ├── DismissButtonConfig/ │ │ │ ├── Content.html │ │ │ ├── Location.html │ │ │ └── Style.html │ │ ├── DismissButtonConfig.html │ │ ├── PopoverConfig/ │ │ │ └── Source.html │ │ └── PopoverConfig.html │ ├── Structs.html │ ├── css/ │ │ ├── highlight.css │ │ └── jazzy.css │ ├── getting-started.html │ ├── index.html │ ├── js/ │ │ ├── jazzy.js │ │ ├── jazzy.search.js │ │ └── typeahead.jquery.js │ ├── search.json │ └── undocumented.json └── scripts/ ├── build_docs.zsh └── lint.zsh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/dependabot.yml ================================================ # Documentation for all configuration options: # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "bundler" directory: "/" schedule: interval: "weekly" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: - master - develop pull_request: branches: - master - develop env: # https://github.com/actions/virtual-environments/tree/main/images/macos DEVELOPER_DIR: /Applications/Xcode_12.3.app/Contents/Developer IOS_SDK: iphonesimulator14.3 PROJECT: PresenterKit.xcodeproj SCHEME: PresenterKit EXAMPLE_PROJECT: Example/ExampleApp.xcodeproj EXAMPLE_SCHEME: ExampleApp IOS_DEST: "OS=14.3,name=iPhone 12 Mini" jobs: job-main: name: Build and Test runs-on: macOS-latest steps: - name: git checkout uses: actions/checkout@v2 - name: xcode version run: xcodebuild -version -sdk - name: list simulators run: | xcrun simctl delete unavailable xcrun simctl list - name: unit tests run: | set -o pipefail xcodebuild clean test \ -project "$PROJECT" \ -scheme "$SCHEME" \ -sdk "$IOS_SDK" \ -destination "$IOS_DEST" \ ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO | xcpretty -c - name: ui tests run: | set -o pipefail xcodebuild clean test \ -project "$EXAMPLE_PROJECT" \ -scheme "$EXAMPLE_SCHEME" \ -sdk "$IOS_SDK" \ -destination "$IOS_DEST" \ ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO | xcpretty -c ================================================ FILE: .github/workflows/danger.yml ================================================ name: Danger on: pull_request env: # https://github.com/actions/virtual-environments/tree/main/images/macos DEVELOPER_DIR: /Applications/Xcode_12.3.app/Contents/Developer jobs: job-danger: name: Review, Lint, Verify runs-on: macOS-latest steps: - name: git checkout uses: actions/checkout@v2 - name: ruby versions run: | ruby --version gem --version bundler --version - name: cache gems uses: actions/cache@v2 with: path: vendor/bundle key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }} restore-keys: | ${{ runner.os }}-gem- - name: bundle install run: | bundle config path vendor/bundle bundle install --without=documentation --jobs 4 --retry 3 echo "/Users/runner/Library/Python/2.7/bin" >> $GITHUB_PATH - name: jazzy docs run: bundle exec jazzy --output docs/ - name: danger env: DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} run: bundle exec danger ================================================ FILE: .github/workflows/pod-lint.yml ================================================ name: CocoaPods Lint on: push: branches: - master - develop pull_request: branches: - master - develop env: # https://github.com/actions/virtual-environments/tree/main/images/macos DEVELOPER_DIR: /Applications/Xcode_12.3.app/Contents/Developer jobs: job-pod-lint: name: Pod Lint runs-on: macOS-latest steps: - name: git checkout uses: actions/checkout@v2 - name: ruby versions run: | ruby --version gem --version bundler --version - name: cache gems uses: actions/cache@v2 with: path: vendor/bundle key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }} restore-keys: | ${{ runner.os }}-gem- - name: bundle install run: | bundle config path vendor/bundle bundle install --without=documentation --jobs 4 --retry 3 - name: pod lint run: bundle exec pod lib lint --allow-warnings ================================================ FILE: .github/workflows/spm.yml ================================================ name: SwiftPM Integration on: push: branches: - master - develop pull_request: branches: - master - develop env: # https://github.com/actions/virtual-environments/tree/main/images/macos DEVELOPER_DIR: /Applications/Xcode_12.3.app/Contents/Developer IOS_SDK: iphonesimulator14.3 IOS_DEST: "OS=14.3,name=iPhone 12 Mini" SCHEME: PresenterKit jobs: job-build: name: SwiftPM Build runs-on: macOS-latest steps: - name: git checkout uses: actions/checkout@v2 - name: xcode version run: xcodebuild -version -sdk - name: list simulators run: | xcrun simctl delete unavailable xcrun simctl list - name: generate xcodeproj run: swift package generate-xcodeproj - name: Build run: | set -o pipefail xcodebuild clean build -scheme "$SCHEME" -sdk "$IOS_SDK" -destination "$IOS_DEST" | xcpretty -c ================================================ FILE: .gitignore ================================================ .DS_Store # swiftpm .swiftpm .build # docs docs/docsets/ # Xcode ## Build generated build/ DerivedData/ ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata/ ## Other *.moved-aside *.xcuserstate ## Obj-C/Swift specific *.hmap *.ipa *.dSYM.zip *.dSYM # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # # Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md fastlane/report.xml fastlane/Preview.html fastlane/screenshots fastlane/test_output # Code Injection # # After new code Injection tools there's a generated folder /iOSInjectionProject # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ ================================================ FILE: .swiftlint.yml ================================================ excluded: - Pods - docs - build - scripts disabled_rules: # metrics - nesting # lint - notification_center_detachment - weak_delegate # idiomatic - force_cast - type_name # style - identifier_name opt_in_rules: # performance - empty_count - first_where - sorted_first_last - contains_over_first_not_nil - last_where - reduce_into - contains_over_filter_count - contains_over_filter_is_empty - empty_collection_literal - type_contents_order # idiomatic - fatal_error_message - xctfail_message - discouraged_object_literal - discouraged_optional_boolean - discouraged_optional_collection - for_where - function_default_parameter_at_end - legacy_random - no_extension_access_modifier - redundant_type_annotation - static_operator - toggle_bool - unavailable_function - no_space_in_method_call # style - attributes - number_separator - operator_usage_whitespace - sorted_imports - vertical_parameter_alignment_on_call - void_return - closure_spacing - empty_enum_arguments - implicit_return - modifier_order - multiline_arguments - multiline_parameters - trailing_closure - unneeded_parentheses_in_closure_argument - vertical_whitespace_between_cases # lint - overridden_super_call - yoda_condition - anyobject_protocol - array_init - empty_xctest_method - identical_operands - prohibited_super_call - unused_import - unused_capture_list - duplicate_enum_cases - legacy_multiple - unused_declaration line_length: 200 file_length: 600 type_body_length: 500 function_body_length: 250 cyclomatic_complexity: 15 type_contents_order: order: - associated_type - type_alias - case - subtype - type_property - ib_outlet - ib_inspectable - instance_property - initializer - deinitializer - subscript - type_method - view_life_cycle_method - ib_action - other_method ================================================ FILE: CHANGELOG.md ================================================ # CHANGELOG The changelog for `PresenterKit`. Also see the [releases](https://github.com/jessesquires/PresenterKit/releases) on GitHub. -------------------------------------- NEXT ---- - TBA 6.1.1 ----- This release closes the [6.1.1 milestone](https://github.com/jessesquires/PresenterKit/milestone/10?closed=1). - Upgraded to Xcode 12 and Swift 5.3 6.1.0 ----- This release closes the [6.1.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/9?closed=1). ### New - Added a new custom presentation controller, `HalfModalPresentationController` - Support for Swift Package Manager ### Changed - Upgrade to Swift 5.2 - Update to Xcode 11.4 - Upgrade SwiftLint - Switch to GH Actions 6.0.0 ----- This release closes the [6.0.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/8?closed=1). ### Breaking - iOS 11 minimum deployment target (Dropped iOS 10) - Renamed `present()` function to `presentController()` to avoid ambiguous naming with UIKit ### Changed - Swift 5.1 - Xcode 11 - Upgrade Swiftlint to 0.35.0, add new rules - Update Travis CI 5.1.0 ----- This release closes the [5.1.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/7?closed=1). - Upgrade to Swift 4.2 - Xcode 10.1 - Upgrade Swiftlint to 0.27.0 5.0.0 ----- This release closes the [5.0.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/6?closed=1). ### Breaking - Swift 4.1 - iOS 10 minimum deployment target (Dropped iOS 9) - Xcode 9.4 - Upgrade Swiftlint to 0.26.0 - Renamed `dismiss()` function to `dismissController()` to avoid ambiguous naming with UIKit (#41) ### Fixed - Respect transition context `.isCancelled` when pushing on a navigation stack (#38) ### New - Add new `pop()` method extension on `UINavigationController` that accepts a `completion` parameter. Similar to existing `push()` method (#40) - Added `completion` parameter to `dismiss()` method extension on `UIViewController` (#41) 4.0.0 ----- This release closes the [4.0.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/4?closed=1). ### Breaking changes - Converted to Swift 4 - iOS 9 minimum deployment target - `public struct PopoverConfig` was changed to accommodate custom frame so it can be used as anchor for the popover. ([#27](https://github.com/jessesquires/PresenterKit/pull/27), [#26](https://github.com/jessesquires/PresenterKit/issues/26), [@psartzetakis](https://github.com/psartzetakis)) - `PopoverConfig.Source.view(_)` was changed to `PopoverConfig.Source.view(container: frame:)` - `public struct DismissButtonConfig` was changed to accommodate custom images in bar button items. ([#24](https://github.com/jessesquires/PresenterKit/pull/24), [#22](https://github.com/jessesquires/PresenterKit/issues/22), [@psartzetakis](https://github.com/psartzetakis)) - `DismissButtonConfig.text` was renamed to `DismissButtonConfig.content` - `public enum DismissButtonConfig.Text` was renamed to `public enum DismissButtonConfig.Content` and it now has 3 cases: `.systemItem`, `.text`, `.image` - `DismissButtonConfig.init(location: style: text:)` was renamed to `DismissButtonConfig.init(location: style: content:)` ### New - Added support for `completion` closure parameter on `present(..)` method. ([#21](https://github.com/jessesquires/PresenterKit/pull/21), [@Sumolari](https://github.com/Sumolari)) 3.0.0 ----- This release closes the [3.0.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/3?closed=1). **Swift 3.0 now required.** ### Changes - `presentViewController(_:, type:, animated:)` was renamed to `present(_:, type:, animated:)` ### New - Added a `.none` case to `PresentationType` which uses UIKit defaults. Use this when presenting system controllers like `UIAlertController`. ### Bug fixes - Fixed bug in `withStyles()` where modal presentation/transition styles might not be applied correctly ([#14](https://github.com/jessesquires/PresenterKit/issues/14)). 2.0.0 ----- This release closes the [2.0.0 milestone](https://github.com/jessesquires/PresenterKit/milestone/2?closed=1). **Swift 2.3 now required.** 1.0.0 ----- Initial release 🎉 ================================================ FILE: Dangerfile ================================================ # ----------------------------------------------------------------------------- # Changed library files, but didn't add/update tests # ----------------------------------------------------------------------------- all_changed_files = (git.added_files + git.modified_files + git.deleted_files) has_source_changes = !all_changed_files.grep(/Sources/).empty? has_test_changes = !all_changed_files.grep(/Tests/).empty? if has_source_changes && !has_test_changes warn("Library files were updated without test coverage. Please update or add tests, if possible!") end # ----------------------------------------------------------------------------- # Pull request is too large to review # ----------------------------------------------------------------------------- if git.lines_of_code > 600 warn("This is a large pull request! Can you break it up into multiple smaller ones instead?") end # ----------------------------------------------------------------------------- # All pull requests need a description # ----------------------------------------------------------------------------- if github.pr_body.length < 25 fail("Please provide a detailed summary in the pull request description.") end # ----------------------------------------------------------------------------- # All pull requests should be submitted to dev/develop branch # ----------------------------------------------------------------------------- if github.branch_for_base != "dev" && github.branch_for_base != "develop" warn("Pull requests should be submitted to the dev branch only.") end # ----------------------------------------------------------------------------- # CHANGELOG entries are required for changes to library files # ----------------------------------------------------------------------------- no_changelog_entry = !git.modified_files.include?("CHANGELOG.md") if has_source_changes && no_changelog_entry warn("There is no CHANGELOG entry. Do you need to add one?") end # ----------------------------------------------------------------------------- # Milestones are required for all PRs to track what's included in each release # ----------------------------------------------------------------------------- has_milestone = github.pr_json["milestone"] != nil warn('All pull requests should have a milestone.', sticky: false) unless has_milestone # ----------------------------------------------------------------------------- # Docs are regenerated when releasing # ----------------------------------------------------------------------------- has_doc_changes = !git.modified_files.grep(/docs\//).empty? if has_doc_changes fail("Documentation cannot be edited directly.") message(%(Docs are automatically regenerated when creating new releases using [Jazzy](https://github.com/realm/jazzy). If you want to update docs, please update the doc comments or markdown files directly.)) end # ----------------------------------------------------------------------------- # Verify correct `pod install` and `bundle install` # ----------------------------------------------------------------------------- def files_changed_as_set(files) changed_files = files.select { |file| git.modified_files.include? file } not_changed_files = files.select { |file| !changed_files.include? file } all_files_changed = not_changed_files.empty? no_files_changed = changed_files.empty? return all_files_changed || no_files_changed end # Verify proper pod install. # If Podfile has been modified, so must the lock files. did_update_podfile = git.modified_files.include?("Podfile") pod_files = ["Podfile", "Podfile.lock", "Pods/Manifest.lock"] if did_update_podfile && !files_changed_as_set(pod_files) fail("CocoaPods error: #{pod_files} should all be changed at the same time. Run `pod install` and commit the changes to fix.") end # Prevent editing `Pods/` source directly. # If Pods has changed, then Podfile.lock must have changed too. has_modified_pods = !(git.added_files + git.modified_files + git.deleted_files).grep(/Pods/).empty? did_update_podlock = git.modified_files.include?("Podfile.lock") if has_modified_pods && !did_update_podlock fail("It looks like you are modifying CocoaPods source in `Pods/`. 3rd-party dependencies should not be edited. To update or change pods, please update the `Podfile` and run `pod install`.") end # Verify proper bundle install. # If Gemfile has been modified, so must the lock file. did_update_gemfile = git.modified_files.include?("Gemfile") gem_files = ["Gemfile", "Gemfile.lock"] if did_update_gemfile && !files_changed_as_set(gem_files) fail("Bundler error: #{gem_files} should all be changed at the same time. Run `bundle install` and commit the changes to fix.") end # ----------------------------------------------------------------------------- # Lint all changed markdown files # ----------------------------------------------------------------------------- markdown_files = (git.added_files + git.modified_files).grep(%r{.*\.md/}) unless markdown_files.empty? # Run proselint to check prose and check spelling prose.language = "en-us" prose.ignore_acronyms = true prose.ignore_numbers = true prose.ignored_words = ["jessesquires", "swiftpm", "iOS", "macOS", "watchOS", "tvOS", "Xcode", "PresenterKit" ] prose.lint_files markdown_files prose.check_spelling markdown_files end # ----------------------------------------------------------------------------- # Run SwiftLint # ----------------------------------------------------------------------------- swiftlint.verbose = true swiftlint.config_file = './.swiftlint.yml' swiftlint.lint_files(inline_mode: true, fail_on_error: true) # ----------------------------------------------------------------------------- # Jazzy docs - check for new, undocumented symbols # ----------------------------------------------------------------------------- jazzy.check fail: :all ================================================ FILE: Example/ExampleApp/AppDelegate.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import UIKit @UIApplicationMain final class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application( _ application: UIApplication, // swiftlint:disable:next discouraged_optional_collection willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { true } } ================================================ FILE: Example/ExampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/ExampleApp/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/ExampleApp/Assets.xcassets/ic_dismiss.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "dismiss@1x.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "dismiss@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "dismiss@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/ExampleApp/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Example/ExampleApp/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Example/ExampleApp/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Example/ExampleApp/MainViewController.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import PresenterKit import UIKit enum Options: Int { case push case modal case show case showDetail case popover case halfModal } final class MainViewController: UITableViewController, UIViewControllerTransitioningDelegate, UIPopoverPresentationControllerDelegate { @IBAction func didTapPopoverButton(_ sender: UIBarButtonItem) { let vc = RedViewController() let config = PopoverConfig(source: .barButtonItem(sender), delegate: self) presentController(vc, type: .popover(config)) { print("Completed") } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { defer { tableView.deselectRow(at: indexPath, animated: true) } let animated = true switch indexPath.section { case Options.push.rawValue: let vc = RedViewController() presentController(vc, type: .push, animated: animated) { print("Completed") } case Options.modal.rawValue: let image = UIImage(named: "ic_dismiss")! let dismissConfig = DismissButtonConfig(location: .left, style: .plain, content: .image(image)) let vc = RedViewController(dismissConfig: dismissConfig) presentController(vc, type: .modal(.withNavigation, .fullScreen, .coverVertical), animated: animated) { print("Completed") } case Options.show.rawValue: let vc = RedViewController() presentController(vc, type: .show, animated: animated) case Options.showDetail.rawValue: let vc = RedViewController() presentController(vc, type: .showDetail(.withNavigation), animated: animated) case Options.popover.rawValue: let cell = tableView.cellForRow(at: indexPath)!.contentView let config = PopoverConfig(source: .view(container: cell, frame: nil), delegate: self) let vc = RedViewController() presentController(vc, type: .popover(config), animated: animated) { print("Completed") } case Options.halfModal.rawValue: let vc = RedViewController() vc.modalTransitionStyle = .coverVertical presentController(vc, type: .custom(self), animated: animated) { print("Completed") } default: fatalError("invalid index path: \(indexPath)") } } // MARK: UIViewControllerTransitioningDelegate func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { HalfModalPresentationController(presentedViewController: presented, presenting: presenting) } // MARK: UIPopoverPresentationControllerDelegate func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle { .none } } ================================================ FILE: Example/ExampleApp/RedViewController.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import PresenterKit import UIKit final class RedViewController: UITableViewController { let cellId = "cell" var dismissConfig: DismissButtonConfig? init(dismissConfig: DismissButtonConfig? = nil) { self.dismissConfig = dismissConfig super.init(style: .grouped) } @available(*, unavailable) required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } override func viewDidLoad() { super.viewDidLoad() title = "Red View" tableView.backgroundColor = UIColor(red: 1.0, green: 0.493_3, blue: 0.474, alpha: 1.0) tableView.allowsSelection = false tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId) let config = dismissConfig ?? DismissButtonConfig() addDismissButtonIfNeeded(config: config) } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 10 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) cell.textLabel?.text = "cell \((indexPath as NSIndexPath).row)" cell.textLabel?.textColor = .red return cell } override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { "Section title" } override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { "Footer title" } } ================================================ FILE: Example/ExampleApp.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 882550121C5472B700CE6D8D /* RedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882550111C5472B700CE6D8D /* RedViewController.swift */; }; 887E572B1C4DBC9B00684C85 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887E572A1C4DBC9B00684C85 /* AppDelegate.swift */; }; 887E572D1C4DBC9B00684C85 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887E572C1C4DBC9B00684C85 /* MainViewController.swift */; }; 887E57301C4DBC9B00684C85 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 887E572E1C4DBC9B00684C85 /* Main.storyboard */; }; 887E57321C4DBC9B00684C85 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 887E57311C4DBC9B00684C85 /* Assets.xcassets */; }; 887E57351C4DBC9B00684C85 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 887E57331C4DBC9B00684C85 /* LaunchScreen.storyboard */; }; 887E574B1C4DBC9B00684C85 /* ExampleAppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887E574A1C4DBC9B00684C85 /* ExampleAppUITests.swift */; }; 887E57701C4DC07400684C85 /* PresenterKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887E57671C4DC03B00684C85 /* PresenterKit.framework */; }; 887E57711C4DC07400684C85 /* PresenterKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 887E57671C4DC03B00684C85 /* PresenterKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 887E57471C4DBC9B00684C85 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 887E571F1C4DBC9B00684C85 /* Project object */; proxyType = 1; remoteGlobalIDString = 887E57261C4DBC9B00684C85; remoteInfo = ExampleApp; }; 887E57661C4DC03B00684C85 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 887E57611C4DC03B00684C85 /* PresenterKit.xcodeproj */; proxyType = 2; remoteGlobalIDString = 88B1CF571C3F762700D1348C; remoteInfo = PresenterKit; }; 887E57681C4DC03B00684C85 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 887E57611C4DC03B00684C85 /* PresenterKit.xcodeproj */; proxyType = 2; remoteGlobalIDString = 88B1CF611C3F762800D1348C; remoteInfo = PresenterKitTests; }; 887E57721C4DC07500684C85 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 887E57611C4DC03B00684C85 /* PresenterKit.xcodeproj */; proxyType = 1; remoteGlobalIDString = 88B1CF561C3F762700D1348C; remoteInfo = PresenterKit; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 887E57741C4DC07500684C85 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 887E57711C4DC07400684C85 /* PresenterKit.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 882550111C5472B700CE6D8D /* RedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedViewController.swift; sourceTree = ""; }; 887E57271C4DBC9B00684C85 /* ExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 887E572A1C4DBC9B00684C85 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 887E572C1C4DBC9B00684C85 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 887E572F1C4DBC9B00684C85 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 887E57311C4DBC9B00684C85 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 887E57341C4DBC9B00684C85 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 887E57361C4DBC9B00684C85 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 887E57461C4DBC9B00684C85 /* ExampleAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 887E574A1C4DBC9B00684C85 /* ExampleAppUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleAppUITests.swift; sourceTree = ""; }; 887E574C1C4DBC9B00684C85 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 887E57611C4DC03B00684C85 /* PresenterKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = PresenterKit.xcodeproj; path = ../PresenterKit.xcodeproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 887E57241C4DBC9B00684C85 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 887E57701C4DC07400684C85 /* PresenterKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 887E57431C4DBC9B00684C85 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 887E571E1C4DBC9B00684C85 = { isa = PBXGroup; children = ( 887E57611C4DC03B00684C85 /* PresenterKit.xcodeproj */, 887E57291C4DBC9B00684C85 /* ExampleApp */, 887E57491C4DBC9B00684C85 /* ExampleAppUITests */, 887E57281C4DBC9B00684C85 /* Products */, ); sourceTree = ""; }; 887E57281C4DBC9B00684C85 /* Products */ = { isa = PBXGroup; children = ( 887E57271C4DBC9B00684C85 /* ExampleApp.app */, 887E57461C4DBC9B00684C85 /* ExampleAppUITests.xctest */, ); name = Products; sourceTree = ""; }; 887E57291C4DBC9B00684C85 /* ExampleApp */ = { isa = PBXGroup; children = ( 887E572A1C4DBC9B00684C85 /* AppDelegate.swift */, 887E57311C4DBC9B00684C85 /* Assets.xcassets */, 887E57361C4DBC9B00684C85 /* Info.plist */, 887E57331C4DBC9B00684C85 /* LaunchScreen.storyboard */, 887E572E1C4DBC9B00684C85 /* Main.storyboard */, 887E572C1C4DBC9B00684C85 /* MainViewController.swift */, 882550111C5472B700CE6D8D /* RedViewController.swift */, ); path = ExampleApp; sourceTree = ""; }; 887E57491C4DBC9B00684C85 /* ExampleAppUITests */ = { isa = PBXGroup; children = ( 887E574A1C4DBC9B00684C85 /* ExampleAppUITests.swift */, 887E574C1C4DBC9B00684C85 /* Info.plist */, ); path = ExampleAppUITests; sourceTree = ""; }; 887E57621C4DC03B00684C85 /* Products */ = { isa = PBXGroup; children = ( 887E57671C4DC03B00684C85 /* PresenterKit.framework */, 887E57691C4DC03B00684C85 /* PresenterKitTests.xctest */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 887E57261C4DBC9B00684C85 /* ExampleApp */ = { isa = PBXNativeTarget; buildConfigurationList = 887E574F1C4DBC9B00684C85 /* Build configuration list for PBXNativeTarget "ExampleApp" */; buildPhases = ( 887E57231C4DBC9B00684C85 /* Sources */, 887E57241C4DBC9B00684C85 /* Frameworks */, 887E57251C4DBC9B00684C85 /* Resources */, 887E57741C4DC07500684C85 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( 887E57731C4DC07500684C85 /* PBXTargetDependency */, ); name = ExampleApp; productName = ExampleApp; productReference = 887E57271C4DBC9B00684C85 /* ExampleApp.app */; productType = "com.apple.product-type.application"; }; 887E57451C4DBC9B00684C85 /* ExampleAppUITests */ = { isa = PBXNativeTarget; buildConfigurationList = 887E57551C4DBC9B00684C85 /* Build configuration list for PBXNativeTarget "ExampleAppUITests" */; buildPhases = ( 887E57421C4DBC9B00684C85 /* Sources */, 887E57431C4DBC9B00684C85 /* Frameworks */, 887E57441C4DBC9B00684C85 /* Resources */, ); buildRules = ( ); dependencies = ( 887E57481C4DBC9B00684C85 /* PBXTargetDependency */, ); name = ExampleAppUITests; productName = ExampleAppUITests; productReference = 887E57461C4DBC9B00684C85 /* ExampleAppUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 887E571F1C4DBC9B00684C85 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 1200; ORGANIZATIONNAME = "Hexed Bits"; TargetAttributes = { 887E57261C4DBC9B00684C85 = { CreatedOnToolsVersion = 7.2; DevelopmentTeamName = "Jesse Squires"; LastSwiftMigration = 0800; ProvisioningStyle = Manual; }; 887E57451C4DBC9B00684C85 = { CreatedOnToolsVersion = 7.2; LastSwiftMigration = 0800; ProvisioningStyle = Manual; TestTargetID = 887E57261C4DBC9B00684C85; }; }; }; buildConfigurationList = 887E57221C4DBC9B00684C85 /* Build configuration list for PBXProject "ExampleApp" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 887E571E1C4DBC9B00684C85; productRefGroup = 887E57281C4DBC9B00684C85 /* Products */; projectDirPath = ""; projectReferences = ( { ProductGroup = 887E57621C4DC03B00684C85 /* Products */; ProjectRef = 887E57611C4DC03B00684C85 /* PresenterKit.xcodeproj */; }, ); projectRoot = ""; targets = ( 887E57261C4DBC9B00684C85 /* ExampleApp */, 887E57451C4DBC9B00684C85 /* ExampleAppUITests */, ); }; /* End PBXProject section */ /* Begin PBXReferenceProxy section */ 887E57671C4DC03B00684C85 /* PresenterKit.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = PresenterKit.framework; remoteRef = 887E57661C4DC03B00684C85 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; 887E57691C4DC03B00684C85 /* PresenterKitTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = PresenterKitTests.xctest; remoteRef = 887E57681C4DC03B00684C85 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ 887E57251C4DBC9B00684C85 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 887E57351C4DBC9B00684C85 /* LaunchScreen.storyboard in Resources */, 887E57321C4DBC9B00684C85 /* Assets.xcassets in Resources */, 887E57301C4DBC9B00684C85 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 887E57441C4DBC9B00684C85 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 887E57231C4DBC9B00684C85 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 887E572D1C4DBC9B00684C85 /* MainViewController.swift in Sources */, 882550121C5472B700CE6D8D /* RedViewController.swift in Sources */, 887E572B1C4DBC9B00684C85 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 887E57421C4DBC9B00684C85 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 887E574B1C4DBC9B00684C85 /* ExampleAppUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 887E57481C4DBC9B00684C85 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 887E57261C4DBC9B00684C85 /* ExampleApp */; targetProxy = 887E57471C4DBC9B00684C85 /* PBXContainerItemProxy */; }; 887E57731C4DC07500684C85 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = PresenterKit; targetProxy = 887E57721C4DC07500684C85 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 887E572E1C4DBC9B00684C85 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 887E572F1C4DBC9B00684C85 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 887E57331C4DBC9B00684C85 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 887E57341C4DBC9B00684C85 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 887E574D1C4DBC9B00684C85 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 887E574E1C4DBC9B00684C85 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 887E57501C4DBC9B00684C85 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ExampleApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; 887E57511C4DBC9B00684C85 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ExampleApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; 887E57561C4DBC9B00684C85 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ExampleAppUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleAppUITests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; TEST_TARGET_NAME = ExampleApp; USES_XCTRUNNER = YES; }; name = Debug; }; 887E57571C4DBC9B00684C85 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ExampleAppUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleAppUITests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TEST_TARGET_NAME = ExampleApp; USES_XCTRUNNER = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 887E57221C4DBC9B00684C85 /* Build configuration list for PBXProject "ExampleApp" */ = { isa = XCConfigurationList; buildConfigurations = ( 887E574D1C4DBC9B00684C85 /* Debug */, 887E574E1C4DBC9B00684C85 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 887E574F1C4DBC9B00684C85 /* Build configuration list for PBXNativeTarget "ExampleApp" */ = { isa = XCConfigurationList; buildConfigurations = ( 887E57501C4DBC9B00684C85 /* Debug */, 887E57511C4DBC9B00684C85 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 887E57551C4DBC9B00684C85 /* Build configuration list for PBXNativeTarget "ExampleAppUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 887E57561C4DBC9B00684C85 /* Debug */, 887E57571C4DBC9B00684C85 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 887E571F1C4DBC9B00684C85 /* Project object */; } ================================================ FILE: Example/ExampleApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/ExampleApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/ExampleApp.xcodeproj/xcshareddata/IDETemplateMacros.plist ================================================ FILEHEADER // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // ================================================ FILE: Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ExampleApp.xcscheme ================================================ ================================================ FILE: Example/ExampleAppUITests/ExampleAppUITests.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import UIKit import XCTest final class ExampleAppUITests: XCTestCase { override func setUp() { super.setUp() continueAfterFailure = false XCUIApplication().launch() } func test_popover() { let app = XCUIApplication() app.navigationBars["PresenterKit"].buttons["Popover"].tap() app.otherElements["PopoverDismissRegion"].tap() } func test_push() { let app = XCUIApplication() app.tables.staticTexts["Push"].tap() app.navigationBars["Red View"].buttons["PresenterKit"].tap() } func test_modal() { let app = XCUIApplication() app.tables.staticTexts["Modal"].tap() app.navigationBars["Red View"].children(matching: .button).element.tap() } func test_show() { let app = XCUIApplication() app.tables.staticTexts["Show"].tap() app.navigationBars["Red View"].buttons["PresenterKit"].tap() } func test_showDetail() { let app = XCUIApplication() app.tables.staticTexts["ShowDetail"].tap() app.navigationBars["Red View"].buttons["Cancel"].tap() } func test_popoverFromView() { let app = XCUIApplication() app.tables.staticTexts["PopoverFromView"].tap() app.otherElements["PopoverDismissRegion"].tap() } func test_halfModal() { let app = XCUIApplication() app.tables.staticTexts["Custom (\"Half Modal\")"].tap() app.children(matching: .window).element(boundBy: 0).children(matching: .other).element(boundBy: 1).tap() } } ================================================ FILE: Example/ExampleAppUITests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' gem 'cocoapods', '~> 1.11' # ------------ # Danger Setup # ------------ gem 'danger' # github gem 'danger-auto_label' # general gem 'danger-todoist' gem 'danger-prose' # xcode, ios, macos gem 'danger-swiftlint' gem 'danger-jazzy' gem 'jazzy' gem 'danger-duplicate_localizable_strings' gem 'danger-missed_localizable_strings' # fixes for github security vulnerability warnings gem "rubyzip", ">= 1.3.0" gem "excon", ">= 0.71.0" ================================================ FILE: Guides/Getting Started.md ================================================ # Getting Started This guide provides a brief overview for how to get started using `PresenterKit`. ```swift import PresenterKit ``` - Watch [the talk](https://realm.io/news/slug-jesse-squires-swifty-view-controller-presenters/) - Read the [blog post](http://www.jessesquires.com/swifty-presenters/) - Run the [example project](https://github.com/jessesquires/PresenterKit/tree/develop/Example) ## Presenting a view controller modally ```swift let vc = MyViewController() presentController(vc, type: .modal(.withNavigation, .formSheet, .coverVertical)) ``` ## Pushing a view controller ```swift let vc = MyViewController() presentController(vc, type: .push) ``` ## Presenting as a popover ```swift let vc = MyViewController() let config = PopoverConfig(source: .barButtonItem(item), delegate: self) presentController(vc, type: .popover(config)) ``` ## Dismissing a view controller ```swift dismissController() ``` ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016-present Jesse Squires Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.3 // The swift-tools-version declares the minimum version // of Swift required to build this package. // ---------------------------------------------------- // // Created by Jesse Squires // https://www.jessesquires.com // // Documentation // https://jessesquires.github.io/PresenterKit // // GitHub // https://github.com/jessesquires/PresenterKit // // Copyright © 2020-present Jesse Squires // import PackageDescription let package = Package( name: "PresenterKit", platforms: [ .iOS(.v11) ], products: [ .library( name: "PresenterKit", targets: ["PresenterKit"]) ], targets: [ .target( name: "PresenterKit", path: "Sources", exclude: ["Info.plist"]), .testTarget(name: "PresenterKitTests", dependencies: ["PresenterKit"], path: "Tests", exclude: ["Info.plist"]) ], swiftLanguageVersions: [.v5] ) ================================================ FILE: PresenterKit.podspec ================================================ Pod::Spec.new do |s| s.name = 'PresenterKit' s.version = '6.1.3' s.license = 'MIT' s.summary = 'Custom presenters and better view controller presentation for iOS' s.homepage = 'https://github.com/jessesquires/PresenterKit' s.documentation_url = 'https://jessesquires.github.io/PresenterKit' s.social_media_url = 'https://twitter.com/jesse_squires' s.author = 'Jesse Squires' s.source = { :git => 'https://github.com/jessesquires/PresenterKit.git', :tag => s.version } s.source_files = 'Sources/*.swift' s.swift_version = '5.3' s.ios.deployment_target = '11.0' s.requires_arc = true s.deprecated = true end ================================================ FILE: PresenterKit.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 13C26AD71DFD2C99004CC79D /* UINavigationController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C26AD61DFD2C99004CC79D /* UINavigationController+Extensions.swift */; }; 8876470E1C56FB2D002048E2 /* DismissButtonConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8876470D1C56FB2D002048E2 /* DismissButtonConfig.swift */; }; 887647181C59E423002048E2 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887647171C59E423002048E2 /* UIViewController+Extensions.swift */; }; 8889115B244B89CC00CB3137 /* HalfModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8889115A244B89CB00CB3137 /* HalfModalPresentationController.swift */; }; 889CC4181C4345BD00CD2DBD /* PresentationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 889CC4171C4345BD00CD2DBD /* PresentationType.swift */; }; 88B1CF621C3F762800D1348C /* PresenterKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88B1CF571C3F762700D1348C /* PresenterKit.framework */; }; 88B1CF7B1C3F767000D1348C /* PresenterKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B1CF761C3F766C00D1348C /* PresenterKitTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 88B1CF631C3F762800D1348C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 88B1CF4E1C3F762700D1348C /* Project object */; proxyType = 1; remoteGlobalIDString = 88B1CF561C3F762700D1348C; remoteInfo = PresenterKit; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 13C26AD61DFD2C99004CC79D /* UINavigationController+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extensions.swift"; sourceTree = ""; }; 8876470D1C56FB2D002048E2 /* DismissButtonConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DismissButtonConfig.swift; sourceTree = ""; }; 887647171C59E423002048E2 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; 8889115A244B89CB00CB3137 /* HalfModalPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HalfModalPresentationController.swift; sourceTree = ""; }; 889CC4171C4345BD00CD2DBD /* PresentationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationType.swift; sourceTree = ""; }; 88B1CF571C3F762700D1348C /* PresenterKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PresenterKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 88B1CF611C3F762800D1348C /* PresenterKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PresenterKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 88B1CF721C3F766C00D1348C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 88B1CF751C3F766C00D1348C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 88B1CF761C3F766C00D1348C /* PresenterKitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenterKitTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 88B1CF531C3F762700D1348C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 88B1CF5E1C3F762800D1348C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 88B1CF621C3F762800D1348C /* PresenterKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 88B1CF4D1C3F762700D1348C = { isa = PBXGroup; children = ( 88B1CF711C3F766C00D1348C /* Sources */, 88B1CF741C3F766C00D1348C /* Tests */, 88B1CF581C3F762700D1348C /* Products */, ); sourceTree = ""; }; 88B1CF581C3F762700D1348C /* Products */ = { isa = PBXGroup; children = ( 88B1CF571C3F762700D1348C /* PresenterKit.framework */, 88B1CF611C3F762800D1348C /* PresenterKitTests.xctest */, ); name = Products; sourceTree = ""; }; 88B1CF711C3F766C00D1348C /* Sources */ = { isa = PBXGroup; children = ( 8876470D1C56FB2D002048E2 /* DismissButtonConfig.swift */, 8889115A244B89CB00CB3137 /* HalfModalPresentationController.swift */, 88B1CF721C3F766C00D1348C /* Info.plist */, 889CC4171C4345BD00CD2DBD /* PresentationType.swift */, 13C26AD61DFD2C99004CC79D /* UINavigationController+Extensions.swift */, 887647171C59E423002048E2 /* UIViewController+Extensions.swift */, ); path = Sources; sourceTree = ""; }; 88B1CF741C3F766C00D1348C /* Tests */ = { isa = PBXGroup; children = ( 88B1CF751C3F766C00D1348C /* Info.plist */, 88B1CF761C3F766C00D1348C /* PresenterKitTests.swift */, ); path = Tests; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 88B1CF541C3F762700D1348C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 88B1CF561C3F762700D1348C /* PresenterKit */ = { isa = PBXNativeTarget; buildConfigurationList = 88B1CF6B1C3F762800D1348C /* Build configuration list for PBXNativeTarget "PresenterKit" */; buildPhases = ( 88B1CF521C3F762700D1348C /* Sources */, 88B1CF531C3F762700D1348C /* Frameworks */, 88B1CF541C3F762700D1348C /* Headers */, 88B1CF551C3F762700D1348C /* Resources */, 8822155B20051A240008AA5C /* SwiftLint */, ); buildRules = ( ); dependencies = ( ); name = PresenterKit; productName = PresenterKit; productReference = 88B1CF571C3F762700D1348C /* PresenterKit.framework */; productType = "com.apple.product-type.framework"; }; 88B1CF601C3F762800D1348C /* PresenterKitTests */ = { isa = PBXNativeTarget; buildConfigurationList = 88B1CF6E1C3F762800D1348C /* Build configuration list for PBXNativeTarget "PresenterKitTests" */; buildPhases = ( 88B1CF5D1C3F762800D1348C /* Sources */, 88B1CF5E1C3F762800D1348C /* Frameworks */, 88B1CF5F1C3F762800D1348C /* Resources */, ); buildRules = ( ); dependencies = ( 88B1CF641C3F762800D1348C /* PBXTargetDependency */, ); name = PresenterKitTests; productName = PresenterKitTests; productReference = 88B1CF611C3F762800D1348C /* PresenterKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 88B1CF4E1C3F762700D1348C /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 1200; ORGANIZATIONNAME = "Hexed Bits"; TargetAttributes = { 88B1CF561C3F762700D1348C = { CreatedOnToolsVersion = 7.2; DevelopmentTeam = 5VRJU68BZ5; DevelopmentTeamName = "Jesse Squires"; LastSwiftMigration = 0900; }; 88B1CF601C3F762800D1348C = { CreatedOnToolsVersion = 7.2; DevelopmentTeamName = "Jesse Squires"; LastSwiftMigration = 0900; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 88B1CF511C3F762700D1348C /* Build configuration list for PBXProject "PresenterKit" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 88B1CF4D1C3F762700D1348C; productRefGroup = 88B1CF581C3F762700D1348C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 88B1CF561C3F762700D1348C /* PresenterKit */, 88B1CF601C3F762800D1348C /* PresenterKitTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 88B1CF551C3F762700D1348C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 88B1CF5F1C3F762800D1348C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 8822155B20051A240008AA5C /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = SwiftLint; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/zsh; shellScript = "\"${SRCROOT}/scripts/lint.zsh\"\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 88B1CF521C3F762700D1348C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8876470E1C56FB2D002048E2 /* DismissButtonConfig.swift in Sources */, 887647181C59E423002048E2 /* UIViewController+Extensions.swift in Sources */, 8889115B244B89CC00CB3137 /* HalfModalPresentationController.swift in Sources */, 889CC4181C4345BD00CD2DBD /* PresentationType.swift in Sources */, 13C26AD71DFD2C99004CC79D /* UINavigationController+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 88B1CF5D1C3F762800D1348C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 88B1CF7B1C3F767000D1348C /* PresenterKitTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 88B1CF641C3F762800D1348C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 88B1CF561C3F762700D1348C /* PresenterKit */; targetProxy = 88B1CF631C3F762800D1348C /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 88B1CF691C3F762800D1348C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 88B1CF6A1C3F762800D1348C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 88B1CF6C1C3F762800D1348C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MARKETING_VERSION = 6.1.1; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.PresenterKit; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 88B1CF6D1C3F762800D1348C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MARKETING_VERSION = 6.1.1; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.PresenterKit; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; 88B1CF6F1C3F762800D1348C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.PresenterKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; 88B1CF701C3F762800D1348C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.PresenterKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 88B1CF511C3F762700D1348C /* Build configuration list for PBXProject "PresenterKit" */ = { isa = XCConfigurationList; buildConfigurations = ( 88B1CF691C3F762800D1348C /* Debug */, 88B1CF6A1C3F762800D1348C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 88B1CF6B1C3F762800D1348C /* Build configuration list for PBXNativeTarget "PresenterKit" */ = { isa = XCConfigurationList; buildConfigurations = ( 88B1CF6C1C3F762800D1348C /* Debug */, 88B1CF6D1C3F762800D1348C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 88B1CF6E1C3F762800D1348C /* Build configuration list for PBXNativeTarget "PresenterKitTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 88B1CF6F1C3F762800D1348C /* Debug */, 88B1CF701C3F762800D1348C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 88B1CF4E1C3F762700D1348C /* Project object */; } ================================================ FILE: PresenterKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: PresenterKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: PresenterKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded ================================================ FILE: PresenterKit.xcodeproj/xcshareddata/IDETemplateMacros.plist ================================================ FILEHEADER // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // ================================================ FILE: PresenterKit.xcodeproj/xcshareddata/xcschemes/PresenterKit.xcscheme ================================================ ================================================ FILE: README.md ================================================ # PresenterKit [![Actions Status](https://github.com/jessesquires/PresenterKit/workflows/CI/badge.svg)](https://github.com/jessesquires/PresenterKit/actions) *Custom presenters and better view controller presentation for iOS* ## Requirements * Xcode 12.0+ * Swift 5.3+ * iOS 11.0+ * [SwiftLint](https://github.com/realm/SwiftLint) ## Installation #### [CocoaPods](https://cocoapods.org) ````ruby pod 'PresenterKit', '~> 6.1.0' # develop branch pod 'PresenterKit', :git => 'https://github.com/jessesquires/PresenterKit.git', :branch => 'develop' ```` ### [Swift Package Manager](https://swift.org/package-manager/) Add `PresenterKit` to the `dependencies` value of your `Package.swift`. ```swift dependencies: [ .package(url: "https://github.com/jessesquires/PresenterKit.git", from: "6.1.0") ] ``` Alternatively, you can add the package [directly via Xcode](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app). ## Documentation You can read the [documentation here](https://jessesquires.github.io/PresenterKit). Generated with [jazzy](https://github.com/realm/jazzy). Hosted by [GitHub Pages](https://pages.github.com). ## Contributing Interested in making contributions to this project? Please review the guides below. - [Contributing Guidelines](https://github.com/jessesquires/.github/blob/master/CONTRIBUTING.md) - [Code of Conduct](https://github.com/jessesquires/.github/blob/master/CODE_OF_CONDUCT.md) - [Support and Help](https://github.com/jessesquires/.github/blob/master/SUPPORT.md) - [Security Policy](https://github.com/jessesquires/.github/blob/master/SECURITY.md) Also, consider [sponsoring this project](https://www.jessesquires.com/sponsor/) or [buying my apps](https://www.hexedbits.com)! ✌️ ## Credits Created and maintained by [**@jesse_squires**](https://twitter.com/jesse_squires). ## License Released under the MIT License. See `LICENSE` for details. > **Copyright © 2016-present Jesse Squires.** ================================================ FILE: Sources/DismissButtonConfig.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import UIKit /** A configuration for `UIBarButtonItem`. Use this configuration to create dismissal/cancel buttons for modally presented view controllers. */ public struct DismissButtonConfig { /// Specifies a bar button's location in a navigation bar. public enum Location { /// The left side of the navigation bar. case left /// The right side of the navigation bar. case right } /// Specifies a bar button's item style. public enum Style { /// Use bold text, `.Done` style. case bold /// Use regular text, `.Plain` style. case plain } /// Specifies the content (title or image) for the bar button. public enum Content { /// Specifies a `UIBarButtonSystemItem`. case systemItem(UIBarButtonItem.SystemItem) /// Specifies custom text for the bar button. case text(String) /// Specifies a custom image for the bar button. case image(UIImage) } /// The location for the bar button. /// The default is `.left`. public let location: Location /// The style for the bar button. /// The default is `.plain`. public let style: Style /// The content for the bar button. /// The default is `.plain`. public let content: Content /** Initializes a new configuration instance. - parameter location: The location for the bar button. The default is `.left`. - parameter style: The style for the bar button. The default is `.plain`. - parameter content: The content for the bar button. The default is `.systemItem(.cancel)`. - returns: A new configuration instance. */ public init(location: Location = .left, style: Style = .plain, content: Content = .systemItem(.cancel)) { self.location = location self.style = style self.content = content } } extension UIBarButtonItem { /** Initializes a new bar button item using the specified configuration. - parameter config: The configuration for the item. - parameter target: The object that receives the action message. - parameter action: The action to send to target when this item is selected. - returns: A new bar button item instance. */ public convenience init(config: DismissButtonConfig, target: AnyObject?, action: Selector) { switch config.content { case .text(let title): self.init(title: title, style: config.style.itemStyle, target: target, action: action) case .image(let image): self.init(image: image, style: config.style.itemStyle, target: target, action: action) case .systemItem(let systemItem): self.init(barButtonSystemItem: systemItem, target: target, action: action) } self.style = config.style.itemStyle } } extension DismissButtonConfig.Style { var itemStyle: UIBarButtonItem.Style { switch self { case .bold: return .done case .plain: return .plain } } } extension DismissButtonConfig.Content { var systemItem: UIBarButtonItem.SystemItem? { switch self { case .systemItem(let item): return item default: return nil } } var image: UIImage? { switch self { case .image(let image): return image default: return nil } } var title: String? { switch self { case .text(let str): return str default: return nil } } } ================================================ FILE: Sources/HalfModalPresentationController.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // // swiftlint:disable type_contents_order import UIKit /// A modal presentation controller that presents the presented view controller modally, /// covering the bottom half of the presenting view controller. This presentation controller /// displays a transparent dimmed, tappable view over the top half of the presenting view controller. public final class HalfModalPresentationController: UIPresentationController { private lazy var dimmingView: UIView = { let view = UIView() view.backgroundColor = UIColor.black.withAlphaComponent(0.5) view.alpha = 0.0 let tap = UITapGestureRecognizer(target: self, action: #selector(Self.dimmingViewTapped(_:))) view.addGestureRecognizer(tap) return view }() /// :nodoc: override public init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { super.init(presentedViewController: presentedViewController, presenting: presentingViewController) } /// :nodoc: override public func presentationTransitionWillBegin() { self.dimmingView.frame = containerView!.bounds self.dimmingView.alpha = 0.0 self.containerView?.insertSubview(self.dimmingView, at: 0) let animations = { self.dimmingView.alpha = 1.0 } if let transitionCoordinator = self.presentingViewController.transitionCoordinator { transitionCoordinator.animate(alongsideTransition: { _ in animations() }, completion: nil) } else { animations() } } /// :nodoc: override public func dismissalTransitionWillBegin() { let animations = { self.dimmingView.alpha = 0.0 } if let transitionCoordinator = presentingViewController.transitionCoordinator { transitionCoordinator.animate(alongsideTransition: { _ in animations() }, completion: nil) } else { animations() } } /// :nodoc: override public var adaptivePresentationStyle: UIModalPresentationStyle { .none } /// :nodoc: override public var shouldPresentInFullscreen: Bool { true } /// :nodoc: override public func size( forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize { CGSize(width: parentSize.width, height: round(parentSize.height / 2.0)) } /// :nodoc: override public func containerViewWillLayoutSubviews() { self.dimmingView.frame = self.containerView!.bounds self.presentedView?.frame = self.frameOfPresentedViewInContainerView } /// :nodoc: override public var frameOfPresentedViewInContainerView: CGRect { let size = self.size(forChildContentContainer: presentedViewController, withParentContainerSize: containerView!.bounds.size) let origin = CGPoint(x: 0.0, y: self.containerView!.frame.maxY / 2) return CGRect(origin: origin, size: size) } // MARK: Private @objc private func dimmingViewTapped(_ tap: UITapGestureRecognizer) { self.presentingViewController.dismiss(animated: true, completion: nil) } } // swiftlint:enable type_contents_order ================================================ FILE: Sources/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Sources/PresentationType.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import UIKit /** Specifies the navigation style for a view controller. */ public enum NavigationStyle { /// Do not embed a view controller in a `UINavigationController`. case none /// Embed view controller in a `UINavigationController`. case withNavigation } /** A configuration for `UIPopoverPresentationController`. */ public struct PopoverConfig { /** Describes the source view from which the popover is showing. */ public enum Source { /// Specifies that the popover should display from a `UIBarButtonItem` instance. case barButtonItem(UIBarButtonItem) /// Specifies that the popover should display from a `UIView` instance and be anchored on the specific `frame`. /// If the `frame` is `nil` then the provided view's frame will be used as the anchor frame. case view(container: UIView, frame: CGRect?) } /// The source view for the popover. let source: Source /// The arrow direction of the popover. /// The default is `.any`. let arrowDirection: UIPopoverArrowDirection /// The delegate object for the popover presentation controller, or `nil`. /// The default is `nil`. let delegate: UIPopoverPresentationControllerDelegate? /** Initializes and returns a new `PopoverConfig` object. - parameter source: The source for the popoever. - parameter arrowDirection: The arrow direction for the popover. The default is `.any`. - parameter delegate: The delegate for the popover. The default is `nil`. - returns: A new `PopoverConfig` object. */ public init(source: Source, arrowDirection: UIPopoverArrowDirection = .any, delegate: UIPopoverPresentationControllerDelegate? = nil) { self.source = source self.arrowDirection = arrowDirection self.delegate = delegate } } /** Describes the type of presentation for a view controller. */ public enum PresentationType { /// A modal presentation type with the specified navigation, presentation, and transition styles. case modal(NavigationStyle, UIModalPresentationStyle, UIModalTransitionStyle) /// A popover presentation type with the specified configuration. case popover(PopoverConfig) /// A push presentation type. case push /// A "show" presentation type. This is an adaptive presentation that usually corresponds to `.Push`. case show /// A "show detail" presentation type. This is an adaptive presentation that usually corresponds to `.Modal`. case showDetail(NavigationStyle) /// A custom presentation style that uses the specified delegate. case custom(UIViewControllerTransitioningDelegate) /// No presentation type specified, use UIKit defaults. Use this when presenting system controllers, like `UIAlertController`. case none } ================================================ FILE: Sources/UINavigationController+Extensions.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import UIKit extension UINavigationController { /** Pushes the given view controller and calls the given closure upon completion. - parameter viewController: The view controller to push onto the stack. - parameter animated: Specify `true` to animate the transition or `false` if you do not want the transition to be animated. - parameter completion: The closure to be called upon completion. */ public func push(_ viewController: UIViewController, animated: Bool = true, completion: (() -> Void)? = nil) { self.pushViewController(viewController, animated: animated) self._handle(animated: animated, completion: completion) } /** Pops the top view controller and calls the given closure upon completion. - parameter animated: Specify `true` to animate the transition or `false` if you do not want the transition to be animated. - parameter completion: The closure to be called upon completion. */ public func pop(animated: Bool = true, completion: (() -> Void)? = nil) { self.popViewController(animated: animated) self._handle(animated: animated, completion: completion) } private func _handle(animated: Bool, completion: (() -> Void)?) { guard let completion = completion else { return } guard animated, let coordinator = self.transitionCoordinator else { completion() return } coordinator.animate(alongsideTransition: nil) { context in guard !context.isCancelled else { return } completion() } } } ================================================ FILE: Sources/UIViewController+Extensions.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // import UIKit // MARK: - Styles extension UIViewController { /** Wraps the receiving view controller in a navigation controller. The receiver is set as the `rootViewController` of the navigation controller. - returns: The navigation controller that contains the receiver as the `rootViewController`. */ @discardableResult public func withNavigation() -> UINavigationController { UINavigationController(rootViewController: self) } /** Applies the specified modal presentation style to the view controller. - parameter presentation: A modal presentation style. - returns: The view controller after applying the style. */ @discardableResult public func withPresentation(_ presentation: UIModalPresentationStyle) -> Self { self.modalPresentationStyle = presentation return self } /** Applies the specified modal transition style to the view controller. - parameter transition: A modal transition style. - returns: The view controller after applying the style. */ @discardableResult public func withTransition(_ transition: UIModalTransitionStyle) -> Self { self.modalTransitionStyle = transition return self } /** Applies the specified navigation style to the view controller. - parameter navigationStyle: A navigation style. - returns: The view controller after applying the style. - note: If `navigationStyle` is `.withNavigation`, then calling this method is equivalent to calling `withNavigation()`. If `navigationStyle` is `.none`, then calling this method does nothing. */ @discardableResult public func withNavigationStyle(_ navigationStyle: NavigationStyle) -> UIViewController { switch navigationStyle { case .none: return self case .withNavigation: return self.withNavigation() } } /** Applies the specified navigation style to the view controller. - parameter navigation: A navigation style. - parameter presentation: A modal presentation style. - parameter transition: A modal transition style. - returns: The view controller after applying the style. */ @discardableResult public func withStyles(navigation: NavigationStyle, presentation: UIModalPresentationStyle, transition: UIModalTransitionStyle) -> UIViewController { // apple styles to self, then to navigation controller self.withPresentation(presentation).withTransition(transition) return self.withNavigationStyle(navigation).withPresentation(presentation).withTransition(transition) } } // MARK: - Presentation extension UIViewController { /** Presents a view controller using the specified presentation type. - parameter viewController: The view controller to display over the current view controller. - parameter type: The presentation type to use. - parameter animated: Pass `true` to animate the presentation, `false` otherwise. - parameter completion: The closure to be called. - warning: The `completion` parameter is ignored for `show` and `showDetail` presentation types. */ public func presentController(_ controller: UIViewController, type: PresentationType, animated: Bool = true, completion: (() -> Void)? = nil) { switch type { case .modal(let n, let p, let t): let vc = controller.withStyles(navigation: n, presentation: p, transition: t) self.present(vc, animated: animated, completion: completion) case .popover(let c): controller.withStyles(navigation: .none, presentation: .popover, transition: .crossDissolve) let popoverController = controller.popoverPresentationController popoverController?.delegate = c.delegate popoverController?.permittedArrowDirections = c.arrowDirection switch c.source { case .barButtonItem(let item): popoverController?.barButtonItem = item case .view(let container, let frame): popoverController?.sourceView = container popoverController?.sourceRect = frame ?? container.bounds } self.present(controller, animated: animated, completion: completion) case .push: if let nav = self as? UINavigationController { nav.push(controller, animated: animated, completion: completion) } else { self.navigationController!.push(controller, animated: animated, completion: completion) } case .show: assert(completion == nil, "Completion closure parameter is ignored for `.show`") self.show(controller, sender: self) case .showDetail(let navigation): assert(completion == nil, "Completion closure parameter is ignored for `.showDetail`") self.showDetailViewController(controller.withNavigationStyle(navigation), sender: self) case .custom(let delegate): controller.modalPresentationStyle = .custom controller.transitioningDelegate = delegate self.present(controller, animated: animated, completion: completion) case .none: self.present(controller, animated: animated, completion: completion) } } } // MARK: - Dismissal extension UIViewController { private var needsDismissButton: Bool { self.isModallyPresented } private var isModallyPresented: Bool { (self.hasPresentingController && !self.hasNavigationController) || (self.hasPresentingController && self.hasNavigationController && self.isNavigationRootViewController) } private var hasPresentingController: Bool { self.presentingViewController != nil } private var hasNavigationController: Bool { self.navigationController != nil } private var isNavigationRootViewController: Bool { self.navigationController?.viewControllers.first == self } /** Dismisses the receiving view controller. - parameter animated: Pass `true` to animate the presentation, `false` otherwise. - parameter completion: The closure to be called upon completion. */ public func dismissController(animated: Bool = true, completion: (() -> Void)? = nil) { if self.isModallyPresented { assert(presentingViewController != nil) self.presentingViewController?.dismiss(animated: animated, completion: completion) } else { assert(navigationController != nil) _ = self.navigationController?.pop(animated: animated, completion: completion) } } /** Adds a dismiss button having the provided configuration, if needed. - parameter config: The configuration to apply to the dismiss button. - note: This method does nothing if the view controller is not presented modally. */ public func addDismissButtonIfNeeded(config: DismissButtonConfig = DismissButtonConfig()) { guard self.needsDismissButton else { return } self.addDismissButton(config: config) } /** Adds a dismiss button having the provided configuration. - parameter config: The configuration to apply to the dismiss button. - note: The view controller must have a non-nil `navigationItem`. */ public func addDismissButton(config: DismissButtonConfig = DismissButtonConfig()) { let button = UIBarButtonItem(config: config, target: self, action: #selector(Self._didTapDismissButton(_:))) switch config.location { case .left: self.navigationItem.leftBarButtonItem = button case .right: self.navigationItem.rightBarButtonItem = button } } @objc private func _didTapDismissButton(_ sender: UIBarButtonItem) { self.dismissController() } } ================================================ FILE: Tests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Tests/PresenterKitTests.swift ================================================ // // Created by Jesse Squires // https://www.jessesquires.com // // // Documentation // https://jessesquires.github.io/PresenterKit // // // GitHub // https://github.com/jessesquires/PresenterKit // // // License // Copyright © 2016-Present Jesse Squires // Released under an MIT license: https://opensource.org/licenses/MIT // @testable import PresenterKit import UIKit import XCTest final class PresenterKitTests: XCTestCase { func test_thatBarButtonItem_initializesWith_dismissConfig_default() { let config = DismissButtonConfig() XCTAssertEqual(config.location, DismissButtonConfig.Location.left) XCTAssertEqual(config.style.itemStyle, UIBarButtonItem.Style.plain) XCTAssertEqual(config.content.systemItem, UIBarButtonItem.SystemItem.cancel) XCTAssertNil(config.content.title) let action = #selector(tapAction(sender:)) let item = UIBarButtonItem(config: config, target: self, action: action) XCTAssertEqual(item.style, config.style.itemStyle) XCTAssertTrue(item.target === self) XCTAssertEqual(item.action, action) } func test_thatBarButtonItem_initializesWith_dismissConfig_leftBoldCancel() { let config = DismissButtonConfig(location: .left, style: .bold, content: .systemItem(.done)) XCTAssertEqual(config.location, DismissButtonConfig.Location.left) XCTAssertEqual(config.style.itemStyle, UIBarButtonItem.Style.done) XCTAssertEqual(config.content.systemItem, UIBarButtonItem.SystemItem.done) XCTAssertNil(config.content.title) let action = #selector(tapAction(sender:)) let item = UIBarButtonItem(config: config, target: self, action: action) XCTAssertEqual(item.style, config.style.itemStyle) XCTAssertTrue(item.target === self) XCTAssertEqual(item.action, action) } func test_thatBarButtonItem_initializesWith_dismissConfig_rightPlainCustomText() { let config = DismissButtonConfig(location: .right, style: .plain, content: .text("title")) XCTAssertEqual(config.location, DismissButtonConfig.Location.right) XCTAssertEqual(config.style.itemStyle, UIBarButtonItem.Style.plain) XCTAssertEqual(config.content.title, "title") XCTAssertNil(config.content.systemItem) let action = #selector(tapAction(sender:)) let item = UIBarButtonItem(config: config, target: self, action: action) XCTAssertEqual(item.style, config.style.itemStyle) XCTAssertTrue(item.target === self) XCTAssertEqual(item.action, action) } func test_thatBarButtonItem_initializesWith_dismissConfig_leftImage() { let image = UIImage() let config = DismissButtonConfig(location: .left, style: .plain, content: .image(image)) XCTAssertEqual(config.location, DismissButtonConfig.Location.left) XCTAssertEqual(config.style.itemStyle, UIBarButtonItem.Style.plain) XCTAssertEqual(config.content.image, image) XCTAssertNil(config.content.systemItem) let action = #selector(tapAction(sender:)) let item = UIBarButtonItem(config: config, target: self, action: action) XCTAssertEqual(item.style, config.style.itemStyle) XCTAssertTrue(item.target === self) XCTAssertEqual(item.action, action) } func test_thatViewController_appliesStyle_withNavigation() { let controller = UIViewController() let nav = controller.withNavigationStyle(.withNavigation) as! UINavigationController XCTAssertEqual(controller, nav.topViewController) } func test_thatViewController_appliesStyle_withNavigation_none() { let controller = UIViewController() let other = controller.withNavigationStyle(.none) XCTAssertEqual(controller, other) } func test_thatViewController_appliesStyle_withPresentation() { let controller = UIViewController() let other = controller.withPresentation(.formSheet) XCTAssertEqual(controller, other) XCTAssertEqual(controller.modalPresentationStyle, UIModalPresentationStyle.formSheet) XCTAssertEqual(other.modalPresentationStyle, UIModalPresentationStyle.formSheet) let controller2 = UIViewController() let other2 = controller2.withPresentation(.pageSheet) XCTAssertEqual(controller2, other2) XCTAssertEqual(controller2.modalPresentationStyle, UIModalPresentationStyle.pageSheet) XCTAssertEqual(other2.modalPresentationStyle, UIModalPresentationStyle.pageSheet) let controller3 = UIViewController() let other3 = controller3.withPresentation(.custom) XCTAssertEqual(controller3, other3) XCTAssertEqual(controller3.modalPresentationStyle, UIModalPresentationStyle.custom) XCTAssertEqual(other3.modalPresentationStyle, UIModalPresentationStyle.custom) } func test_thatViewController_appliesStyle_withTransition() { let controller = UIViewController() let other = controller.withTransition(.coverVertical) XCTAssertEqual(controller, other) XCTAssertEqual(controller.modalTransitionStyle, UIModalTransitionStyle.coverVertical) XCTAssertEqual(other.modalTransitionStyle, UIModalTransitionStyle.coverVertical) let controller2 = UIViewController() let other2 = controller2.withTransition(.crossDissolve) XCTAssertEqual(controller2, other2) XCTAssertEqual(controller2.modalTransitionStyle, UIModalTransitionStyle.crossDissolve) XCTAssertEqual(other2.modalTransitionStyle, UIModalTransitionStyle.crossDissolve) let controller3 = UIViewController() let other3 = controller3.withTransition(.flipHorizontal) XCTAssertEqual(controller3, other3) XCTAssertEqual(controller3.modalTransitionStyle, UIModalTransitionStyle.flipHorizontal) XCTAssertEqual(other3.modalTransitionStyle, UIModalTransitionStyle.flipHorizontal) } func test_thatViewController_appliesStyles_withStyles() { let controller = UIViewController() let other = controller.withStyles(navigation: .withNavigation, presentation: .overCurrentContext, transition: .partialCurl) as! UINavigationController XCTAssertEqual(controller, other.topViewController) XCTAssertEqual(controller.modalPresentationStyle, UIModalPresentationStyle.overCurrentContext) XCTAssertEqual(controller.modalTransitionStyle, UIModalTransitionStyle.partialCurl) XCTAssertEqual(other.modalPresentationStyle, UIModalPresentationStyle.overCurrentContext) XCTAssertEqual(other.modalTransitionStyle, UIModalTransitionStyle.partialCurl) let controller2 = UIViewController() let other2 = controller2.withStyles(navigation: .none, presentation: .none, transition: .coverVertical) XCTAssertEqual(controller2, other2) XCTAssertEqual(controller2.modalPresentationStyle, UIModalPresentationStyle.none) XCTAssertEqual(controller2.modalTransitionStyle, UIModalTransitionStyle.coverVertical) let controller3 = UIViewController() let other3 = controller3.withStyles(navigation: .withNavigation, presentation: .formSheet, transition: .coverVertical) as! UINavigationController XCTAssertEqual(controller3, other3.topViewController) XCTAssertEqual(controller3.modalPresentationStyle, UIModalPresentationStyle.formSheet) XCTAssertEqual(controller3.modalTransitionStyle, UIModalTransitionStyle.coverVertical) XCTAssertEqual(other3.modalPresentationStyle, UIModalPresentationStyle.formSheet) XCTAssertEqual(other3.modalTransitionStyle, UIModalTransitionStyle.coverVertical) } func test_thatViewController_presentsViewController_withPresentationType_push() { let firstController = UINavigationController() let secondController = UIViewController() let expectPush = expectation(description: "completion block called") firstController.presentController(secondController, type: .push, animated: false) { expectPush.fulfill() } XCTAssertNotNil(secondController.navigationController) XCTAssertNotNil(secondController.navigationItem) XCTAssertEqual(firstController.topViewController, secondController) secondController.addDismissButtonIfNeeded() XCTAssertNil(secondController.navigationItem.leftBarButtonItem) XCTAssertNil(secondController.navigationItem.rightBarButtonItem) let expectPop = expectation(description: "completion block called") secondController.dismissController(animated: false) { expectPop.fulfill() } XCTAssertEqual(firstController.topViewController, secondController) waitForExpectations(timeout: 5) } func test_thatViewController_presentsViewController_withPresentationType_push_embedded() { let firstController = UIViewController() let navController = UINavigationController(rootViewController: firstController) XCTAssertEqual(navController.topViewController, firstController) let secondController = UIViewController() firstController.presentController(secondController, type: .push, animated: false) XCTAssertNotNil(secondController.navigationController) XCTAssertNotNil(secondController.navigationItem) XCTAssertEqual(navController.topViewController, secondController) secondController.addDismissButtonIfNeeded() XCTAssertNil(secondController.navigationItem.leftBarButtonItem) XCTAssertNil(secondController.navigationItem.rightBarButtonItem) secondController.dismissController(animated: false) XCTAssertEqual(navController.topViewController, firstController) } func test_thatViewController_presentsViewController_withPresentationType_show() { let firstController = UINavigationController() let secondController = UIViewController() firstController.presentController(secondController, type: .show, animated: false) XCTAssertNotNil(secondController.navigationController) XCTAssertNotNil(secondController.navigationItem) XCTAssertEqual(firstController.topViewController, secondController) secondController.addDismissButtonIfNeeded() XCTAssertNil(secondController.navigationItem.leftBarButtonItem) XCTAssertNil(secondController.navigationItem.rightBarButtonItem) } // MARK: Helpers func tapAction(sender: UIBarButtonItem) { } } ================================================ FILE: docs/Classes.html ================================================ Classes Reference

Classes

The following classes are available globally.

  • A modal presentation controller that presents the presented view controller modally, covering the bottom half of the presenting view controller. This presentation controller displays a transparent dimmed, tappable view over the top half of the presenting view controller.

    Declaration

    Swift

    public final class HalfModalPresentationController : UIPresentationController
================================================ FILE: docs/Enums/NavigationStyle.html ================================================ NavigationStyle Enumeration Reference

NavigationStyle

public enum NavigationStyle

Specifies the navigation style for a view controller.

  • Do not embed a view controller in a UINavigationController.

    Declaration

    Swift

    case none
  • Embed view controller in a UINavigationController.

    Declaration

    Swift

    case withNavigation
================================================ FILE: docs/Enums/PresentationType.html ================================================ PresentationType Enumeration Reference

PresentationType

public enum PresentationType

Describes the type of presentation for a view controller.

  • A modal presentation type with the specified navigation, presentation, and transition styles.

    Declaration

    Swift

    case modal(NavigationStyle, UIModalPresentationStyle, UIModalTransitionStyle)
  • A popover presentation type with the specified configuration.

    Declaration

    Swift

    case popover(PopoverConfig)
  • A push presentation type.

    Declaration

    Swift

    case push
  • A “show” presentation type. This is an adaptive presentation that usually corresponds to .Push.

    Declaration

    Swift

    case show
  • A “show detail” presentation type. This is an adaptive presentation that usually corresponds to .Modal.

    Declaration

    Swift

    case showDetail(NavigationStyle)
  • A custom presentation style that uses the specified delegate.

    Declaration

    Swift

    case custom(UIViewControllerTransitioningDelegate)
  • No presentation type specified, use UIKit defaults. Use this when presenting system controllers, like UIAlertController.

    Declaration

    Swift

    case none
================================================ FILE: docs/Enums.html ================================================ Enumerations Reference

Enumerations

The following enumerations are available globally.

  • Specifies the navigation style for a view controller.

    See more

    Declaration

    Swift

    public enum NavigationStyle
  • Describes the type of presentation for a view controller.

    See more

    Declaration

    Swift

    public enum PresentationType
================================================ FILE: docs/Extensions/UIBarButtonItem.html ================================================ UIBarButtonItem Extension Reference

UIBarButtonItem

extension UIBarButtonItem
  • Initializes a new bar button item using the specified configuration.

    Declaration

    Swift

    public convenience init(config: DismissButtonConfig, target: AnyObject?, action: Selector)

    Parameters

    config

    The configuration for the item.

    target

    The object that receives the action message.

    action

    The action to send to target when this item is selected.

    Return Value

    A new bar button item instance.

================================================ FILE: docs/Extensions/UINavigationController.html ================================================ UINavigationController Extension Reference

UINavigationController

extension UINavigationController
  • Pushes the given view controller and calls the given closure upon completion.

    Declaration

    Swift

    public func push(_ viewController: UIViewController,
                     animated: Bool = true,
                     completion: (() -> Void)? = nil)

    Parameters

    viewController

    The view controller to push onto the stack.

    animated

    Specify true to animate the transition or false if you do not want the transition to be animated.

    completion

    The closure to be called upon completion.

  • Pops the top view controller and calls the given closure upon completion.

    Declaration

    Swift

    public func pop(animated: Bool = true,
                    completion: (() -> Void)? = nil)

    Parameters

    animated

    Specify true to animate the transition or false if you do not want the transition to be animated.

    completion

    The closure to be called upon completion.

================================================ FILE: docs/Extensions/UIViewController.html ================================================ UIViewController Extension Reference

UIViewController

extension UIViewController
  • Wraps the receiving view controller in a navigation controller. The receiver is set as the rootViewController of the navigation controller.

    Declaration

    Swift

    @discardableResult
    public func withNavigation() -> UINavigationController

    Return Value

    The navigation controller that contains the receiver as the rootViewController.

  • Applies the specified modal presentation style to the view controller.

    Declaration

    Swift

    @discardableResult
    public func withPresentation(_ presentation: UIModalPresentationStyle) -> Self

    Parameters

    presentation

    A modal presentation style.

    Return Value

    The view controller after applying the style.

  • Applies the specified modal transition style to the view controller.

    Declaration

    Swift

    @discardableResult
    public func withTransition(_ transition: UIModalTransitionStyle) -> Self

    Parameters

    transition

    A modal transition style.

    Return Value

    The view controller after applying the style.

  • Applies the specified navigation style to the view controller.

    Note

    If navigationStyle is .withNavigation, then calling this method is equivalent to calling withNavigation(). If navigationStyle is .none, then calling this method does nothing.

    Declaration

    Swift

    @discardableResult
    public func withNavigationStyle(_ navigationStyle: NavigationStyle) -> UIViewController

    Parameters

    navigationStyle

    A navigation style.

    Return Value

    The view controller after applying the style.

  • Applies the specified navigation style to the view controller.

    Declaration

    Swift

    @discardableResult
    public func withStyles(navigation: NavigationStyle,
                           presentation: UIModalPresentationStyle,
                           transition: UIModalTransitionStyle) -> UIViewController

    Parameters

    navigation

    A navigation style.

    presentation

    A modal presentation style.

    transition

    A modal transition style.

    Return Value

    The view controller after applying the style.

Presentation

  • Presents a view controller using the specified presentation type.

    Warning

    The completion parameter is ignored for show and showDetail presentation types.

    Declaration

    Swift

    public func presentController(_ controller: UIViewController,
                                  type: PresentationType,
                                  animated: Bool = true,
                                  completion: (() -> Void)? = nil)

    Parameters

    viewController

    The view controller to display over the current view controller.

    type

    The presentation type to use.

    animated

    Pass true to animate the presentation, false otherwise.

    completion

    The closure to be called.

Dismissal

  • Dismisses the receiving view controller.

    Declaration

    Swift

    public func dismissController(animated: Bool = true, completion: (() -> Void)? = nil)

    Parameters

    animated

    Pass true to animate the presentation, false otherwise.

    completion

    The closure to be called upon completion.

  • Adds a dismiss button having the provided configuration, if needed.

    Note

    This method does nothing if the view controller is not presented modally.

    Declaration

    Swift

    public func addDismissButtonIfNeeded(config: DismissButtonConfig = DismissButtonConfig())

    Parameters

    config

    The configuration to apply to the dismiss button.

  • Adds a dismiss button having the provided configuration.

    Note

    The view controller must have a non-nil navigationItem.

    Declaration

    Swift

    public func addDismissButton(config: DismissButtonConfig = DismissButtonConfig())

    Parameters

    config

    The configuration to apply to the dismiss button.

================================================ FILE: docs/Extensions.html ================================================ Extensions Reference
================================================ FILE: docs/Guides.html ================================================ Guides Reference
================================================ FILE: docs/Structs/DismissButtonConfig/Content.html ================================================ Content Enumeration Reference

Content

public enum Content

Specifies the content (title or image) for the bar button.

  • Specifies a UIBarButtonSystemItem.

    Declaration

    Swift

    case systemItem(UIBarButtonItem.SystemItem)
  • Specifies custom text for the bar button.

    Declaration

    Swift

    case text(String)
  • Specifies a custom image for the bar button.

    Declaration

    Swift

    case image(UIImage)
================================================ FILE: docs/Structs/DismissButtonConfig/Location.html ================================================ Location Enumeration Reference

Location

public enum Location

Specifies a bar button’s location in a navigation bar.

  • The left side of the navigation bar.

    Declaration

    Swift

    case left
  • The right side of the navigation bar.

    Declaration

    Swift

    case right
================================================ FILE: docs/Structs/DismissButtonConfig/Style.html ================================================ Style Enumeration Reference

Style

public enum Style

Specifies a bar button’s item style.

  • Use bold text, .Done style.

    Declaration

    Swift

    case bold
  • Use regular text, .Plain style.

    Declaration

    Swift

    case plain
================================================ FILE: docs/Structs/DismissButtonConfig.html ================================================ DismissButtonConfig Structure Reference

DismissButtonConfig

public struct DismissButtonConfig

A configuration for UIBarButtonItem. Use this configuration to create dismissal/cancel buttons for modally presented view controllers.

  • Specifies a bar button’s location in a navigation bar.

    See more

    Declaration

    Swift

    public enum Location
  • Specifies a bar button’s item style.

    See more

    Declaration

    Swift

    public enum Style
  • Specifies the content (title or image) for the bar button.

    See more

    Declaration

    Swift

    public enum Content
  • The location for the bar button. The default is .left.

    Declaration

    Swift

    public let location: Location
  • The style for the bar button. The default is .plain.

    Declaration

    Swift

    public let style: Style
  • The content for the bar button. The default is .plain.

    Declaration

    Swift

    public let content: Content
  • Initializes a new configuration instance.

    Declaration

    Swift

    public init(location: Location = .left, style: Style = .plain, content: Content = .systemItem(.cancel))

    Parameters

    location

    The location for the bar button. The default is .left.

    style

    The style for the bar button. The default is .plain.

    content

    The content for the bar button. The default is .systemItem(.cancel).

    Return Value

    A new configuration instance.

================================================ FILE: docs/Structs/PopoverConfig/Source.html ================================================ Source Enumeration Reference

Source

public enum Source

Describes the source view from which the popover is showing.

  • Specifies that the popover should display from a UIBarButtonItem instance.

    Declaration

    Swift

    case barButtonItem(UIBarButtonItem)
  • Specifies that the popover should display from a UIView instance and be anchored on the specific frame. If the frame is nil then the provided view’s frame will be used as the anchor frame.

    Declaration

    Swift

    case view(container: UIView, frame: CGRect?)
================================================ FILE: docs/Structs/PopoverConfig.html ================================================ PopoverConfig Structure Reference

PopoverConfig

public struct PopoverConfig

A configuration for UIPopoverPresentationController.

  • Describes the source view from which the popover is showing.

    See more

    Declaration

    Swift

    public enum Source
  • Initializes and returns a new PopoverConfig object.

    Declaration

    Swift

    public init(source: Source,
                arrowDirection: UIPopoverArrowDirection = .any,
                delegate: UIPopoverPresentationControllerDelegate? = nil)

    Parameters

    source

    The source for the popoever.

    arrowDirection

    The arrow direction for the popover. The default is .any.

    delegate

    The delegate for the popover. The default is nil.

    Return Value

    A new PopoverConfig object.

================================================ FILE: docs/Structs.html ================================================ Structures Reference

Structures

The following structures are available globally.

  • A configuration for UIBarButtonItem. Use this configuration to create dismissal/cancel buttons for modally presented view controllers.

    See more

    Declaration

    Swift

    public struct DismissButtonConfig
  • A configuration for UIPopoverPresentationController.

    See more

    Declaration

    Swift

    public struct PopoverConfig
================================================ FILE: docs/css/highlight.css ================================================ /* Credit to https://gist.github.com/wataru420/2048287 */ .highlight { /* Comment */ /* Error */ /* Keyword */ /* Operator */ /* Comment.Multiline */ /* Comment.Preproc */ /* Comment.Single */ /* Comment.Special */ /* Generic.Deleted */ /* Generic.Deleted.Specific */ /* Generic.Emph */ /* Generic.Error */ /* Generic.Heading */ /* Generic.Inserted */ /* Generic.Inserted.Specific */ /* Generic.Output */ /* Generic.Prompt */ /* Generic.Strong */ /* Generic.Subheading */ /* Generic.Traceback */ /* Keyword.Constant */ /* Keyword.Declaration */ /* Keyword.Pseudo */ /* Keyword.Reserved */ /* Keyword.Type */ /* Literal.Number */ /* Literal.String */ /* Name.Attribute */ /* Name.Builtin */ /* Name.Class */ /* Name.Constant */ /* Name.Entity */ /* Name.Exception */ /* Name.Function */ /* Name.Namespace */ /* Name.Tag */ /* Name.Variable */ /* Operator.Word */ /* Text.Whitespace */ /* Literal.Number.Float */ /* Literal.Number.Hex */ /* Literal.Number.Integer */ /* Literal.Number.Oct */ /* Literal.String.Backtick */ /* Literal.String.Char */ /* Literal.String.Doc */ /* Literal.String.Double */ /* Literal.String.Escape */ /* Literal.String.Heredoc */ /* Literal.String.Interpol */ /* Literal.String.Other */ /* Literal.String.Regex */ /* Literal.String.Single */ /* Literal.String.Symbol */ /* Name.Builtin.Pseudo */ /* Name.Variable.Class */ /* Name.Variable.Global */ /* Name.Variable.Instance */ /* Literal.Number.Integer.Long */ } .highlight .c { color: #999988; font-style: italic; } .highlight .err { color: #a61717; background-color: #e3d2d2; } .highlight .k { color: #000000; font-weight: bold; } .highlight .o { color: #000000; font-weight: bold; } .highlight .cm { color: #999988; font-style: italic; } .highlight .cp { color: #999999; font-weight: bold; } .highlight .c1 { color: #999988; font-style: italic; } .highlight .cs { color: #999999; font-weight: bold; font-style: italic; } .highlight .gd { color: #000000; background-color: #ffdddd; } .highlight .gd .x { color: #000000; background-color: #ffaaaa; } .highlight .ge { color: #000000; font-style: italic; } .highlight .gr { color: #aa0000; } .highlight .gh { color: #999999; } .highlight .gi { color: #000000; background-color: #ddffdd; } .highlight .gi .x { color: #000000; background-color: #aaffaa; } .highlight .go { color: #888888; } .highlight .gp { color: #555555; } .highlight .gs { font-weight: bold; } .highlight .gu { color: #aaaaaa; } .highlight .gt { color: #aa0000; } .highlight .kc { color: #000000; font-weight: bold; } .highlight .kd { color: #000000; font-weight: bold; } .highlight .kp { color: #000000; font-weight: bold; } .highlight .kr { color: #000000; font-weight: bold; } .highlight .kt { color: #445588; } .highlight .m { color: #009999; } .highlight .s { color: #d14; } .highlight .na { color: #008080; } .highlight .nb { color: #0086B3; } .highlight .nc { color: #445588; font-weight: bold; } .highlight .no { color: #008080; } .highlight .ni { color: #800080; } .highlight .ne { color: #990000; font-weight: bold; } .highlight .nf { color: #990000; } .highlight .nn { color: #555555; } .highlight .nt { color: #000080; } .highlight .nv { color: #008080; } .highlight .ow { color: #000000; font-weight: bold; } .highlight .w { color: #bbbbbb; } .highlight .mf { color: #009999; } .highlight .mh { color: #009999; } .highlight .mi { color: #009999; } .highlight .mo { color: #009999; } .highlight .sb { color: #d14; } .highlight .sc { color: #d14; } .highlight .sd { color: #d14; } .highlight .s2 { color: #d14; } .highlight .se { color: #d14; } .highlight .sh { color: #d14; } .highlight .si { color: #d14; } .highlight .sx { color: #d14; } .highlight .sr { color: #009926; } .highlight .s1 { color: #d14; } .highlight .ss { color: #990073; } .highlight .bp { color: #999999; } .highlight .vc { color: #008080; } .highlight .vg { color: #008080; } .highlight .vi { color: #008080; } .highlight .il { color: #009999; } ================================================ FILE: docs/css/jazzy.css ================================================ html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { background: transparent; border: 0; margin: 0; outline: 0; padding: 0; vertical-align: baseline; } body { background-color: #f2f2f2; font-family: Helvetica, freesans, Arial, sans-serif; font-size: 14px; -webkit-font-smoothing: subpixel-antialiased; word-wrap: break-word; } h1, h2, h3 { margin-top: 0.8em; margin-bottom: 0.3em; font-weight: 100; color: black; } h1 { font-size: 2.5em; } h2 { font-size: 2em; border-bottom: 1px solid #e2e2e2; } h4 { font-size: 13px; line-height: 1.5; margin-top: 21px; } h5 { font-size: 1.1em; } h6 { font-size: 1.1em; color: #777; } .section-name { color: gray; display: block; font-family: Helvetica; font-size: 22px; font-weight: 100; margin-bottom: 15px; } pre, code { font: 0.95em Menlo, monospace; color: #777; word-wrap: normal; } p code, li code { background-color: #eee; padding: 2px 4px; border-radius: 4px; } pre > code { padding: 0; } a { color: #0088cc; text-decoration: none; } a code { color: inherit; } ul { padding-left: 15px; } li { line-height: 1.8em; } img { max-width: 100%; } blockquote { margin-left: 0; padding: 0 10px; border-left: 4px solid #ccc; } .content-wrapper { margin: 0 auto; width: 980px; } header { font-size: 0.85em; line-height: 32px; background-color: #414141; position: fixed; width: 100%; z-index: 3; } header img { padding-right: 6px; vertical-align: -4px; height: 16px; } header a { color: #fff; } header p { float: left; color: #999; } header .header-right { float: right; margin-left: 16px; } #breadcrumbs { background-color: #f2f2f2; height: 21px; padding-top: 17px; position: fixed; width: 100%; z-index: 2; margin-top: 32px; } #breadcrumbs #carat { height: 10px; margin: 0 5px; } .sidebar { background-color: #f9f9f9; border: 1px solid #e2e2e2; overflow-y: auto; overflow-x: hidden; position: fixed; top: 70px; bottom: 0; width: 230px; word-wrap: normal; } .nav-groups { list-style-type: none; background: #fff; padding-left: 0; } .nav-group-name { border-bottom: 1px solid #e2e2e2; font-size: 1.1em; font-weight: 100; padding: 15px 0 15px 20px; } .nav-group-name > a { color: #333; } .nav-group-tasks { margin-top: 5px; } .nav-group-task { font-size: 0.9em; list-style-type: none; white-space: nowrap; } .nav-group-task a { color: #888; } .main-content { background-color: #fff; border: 1px solid #e2e2e2; margin-left: 246px; position: absolute; overflow: hidden; padding-bottom: 20px; top: 70px; width: 734px; } .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { margin-bottom: 1em; } .main-content p { line-height: 1.8em; } .main-content section .section:first-child { margin-top: 0; padding-top: 0; } .main-content section .task-group-section .task-group:first-of-type { padding-top: 10px; } .main-content section .task-group-section .task-group:first-of-type .section-name { padding-top: 15px; } .main-content section .heading:before { content: ""; display: block; padding-top: 70px; margin: -70px 0 0; } .main-content .section-name p { margin-bottom: inherit; line-height: inherit; } .main-content .section-name code { background-color: inherit; padding: inherit; color: inherit; } .section { padding: 0 25px; } .highlight { background-color: #eee; padding: 10px 12px; border: 1px solid #e2e2e2; border-radius: 4px; overflow-x: auto; } .declaration .highlight { overflow-x: initial; padding: 0 40px 40px 0; margin-bottom: -25px; background-color: transparent; border: none; } .section-name { margin: 0; margin-left: 18px; } .task-group-section { margin-top: 10px; padding-left: 6px; border-top: 1px solid #e2e2e2; } .task-group { padding-top: 0px; } .task-name-container a[name]:before { content: ""; display: block; padding-top: 70px; margin: -70px 0 0; } .section-name-container { position: relative; display: inline-block; } .section-name-container .section-name-link { position: absolute; top: 0; left: 0; bottom: 0; right: 0; margin-bottom: 0; } .section-name-container .section-name { position: relative; pointer-events: none; z-index: 1; } .section-name-container .section-name a { pointer-events: auto; } .item { padding-top: 8px; width: 100%; list-style-type: none; } .item a[name]:before { content: ""; display: block; padding-top: 70px; margin: -70px 0 0; } .item code { background-color: transparent; padding: 0; } .item .token, .item .direct-link { display: inline-block; text-indent: -20px; padding-left: 3px; margin-left: 35px; font-size: 11.9px; transition: all 300ms; } .item .token-open { margin-left: 20px; } .item .discouraged { text-decoration: line-through; } .item .declaration-note { font-size: .85em; color: gray; font-style: italic; } .pointer-container { border-bottom: 1px solid #e2e2e2; left: -23px; padding-bottom: 13px; position: relative; width: 110%; } .pointer { background: #f9f9f9; border-left: 1px solid #e2e2e2; border-top: 1px solid #e2e2e2; height: 12px; left: 21px; top: -7px; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -o-transform: rotate(45deg); transform: rotate(45deg); position: absolute; width: 12px; } .height-container { display: none; left: -25px; padding: 0 25px; position: relative; width: 100%; overflow: hidden; } .height-container .section { background: #f9f9f9; border-bottom: 1px solid #e2e2e2; left: -25px; position: relative; width: 100%; padding-top: 10px; padding-bottom: 5px; } .aside, .language { padding: 6px 12px; margin: 12px 0; border-left: 5px solid #dddddd; overflow-y: hidden; } .aside .aside-title, .language .aside-title { font-size: 9px; letter-spacing: 2px; text-transform: uppercase; padding-bottom: 0; margin: 0; color: #aaa; -webkit-user-select: none; } .aside p:last-child, .language p:last-child { margin-bottom: 0; } .language { border-left: 5px solid #cde9f4; } .language .aside-title { color: #4b8afb; } .aside-warning, .aside-deprecated, .aside-unavailable { border-left: 5px solid #ff6666; } .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { color: #ff0000; } .graybox { border-collapse: collapse; width: 100%; } .graybox p { margin: 0; word-break: break-word; min-width: 50px; } .graybox td { border: 1px solid #e2e2e2; padding: 5px 25px 5px 10px; vertical-align: middle; } .graybox tr td:first-of-type { text-align: right; padding: 7px; vertical-align: top; word-break: normal; width: 40px; } .slightly-smaller { font-size: 0.9em; } #footer { position: relative; top: 10px; bottom: 0px; margin-left: 25px; } #footer p { margin: 0; color: #aaa; font-size: 0.8em; } html.dash header, html.dash #breadcrumbs, html.dash .sidebar { display: none; } html.dash .main-content { width: 980px; margin-left: 0; border: none; width: 100%; top: 0; padding-bottom: 0; } html.dash .height-container { display: block; } html.dash .item .token { margin-left: 0; } html.dash .content-wrapper { width: auto; } html.dash #footer { position: static; } form[role=search] { float: right; } form[role=search] input { font: Helvetica, freesans, Arial, sans-serif; margin-top: 6px; font-size: 13px; line-height: 20px; padding: 0px 10px; border: none; border-radius: 1em; } .loading form[role=search] input { background: white url(../img/spinner.gif) center right 4px no-repeat; } form[role=search] .tt-menu { margin: 0; min-width: 300px; background: #fff; color: #333; border: 1px solid #e2e2e2; z-index: 4; } form[role=search] .tt-highlight { font-weight: bold; } form[role=search] .tt-suggestion { font: Helvetica, freesans, Arial, sans-serif; font-size: 14px; padding: 0 8px; } form[role=search] .tt-suggestion span { display: table-cell; white-space: nowrap; } form[role=search] .tt-suggestion .doc-parent-name { width: 100%; text-align: right; font-weight: normal; font-size: 0.9em; padding-left: 16px; } form[role=search] .tt-suggestion:hover, form[role=search] .tt-suggestion.tt-cursor { cursor: pointer; background-color: #4183c4; color: #fff; } form[role=search] .tt-suggestion:hover .doc-parent-name, form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { color: #fff; } ================================================ FILE: docs/getting-started.html ================================================ Getting Started Reference

Getting Started

This guide provides a brief overview for how to get started using PresenterKit.

import PresenterKit

Presenting a view controller modally

let vc = MyViewController()
presentController(vc, type: .modal(.withNavigation, .formSheet, .coverVertical))

Pushing a view controller

let vc = MyViewController()
presentController(vc, type: .push)

Presenting as a popover

let vc = MyViewController()
let config = PopoverConfig(source: .barButtonItem(item), delegate: self)
presentController(vc, type: .popover(config))

Dismissing a view controller

dismissController()
================================================ FILE: docs/index.html ================================================ PresenterKit Reference

PresenterKit Actions Status

Custom presenters and better view controller presentation for iOS

Requirements

Installation

CocoaPods

pod 'PresenterKit', '~> 6.1.0'

# develop branch
pod 'PresenterKit', :git => 'https://github.com/jessesquires/PresenterKit.git', :branch => 'develop'

Swift Package Manager

Add PresenterKit to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/jessesquires/PresenterKit.git", from: "6.1.0")
]

Alternatively, you can add the package directly via Xcode.

Documentation

You can read the documentation here. Generated with jazzy. Hosted by GitHub Pages.

Contributing

Interested in making contributions to this project? Please review the guides below.

Also, consider sponsoring this project or buying my apps! ✌️

Credits

Created and maintained by @jesse_squires.

License

Released under the MIT License. See LICENSE for details.

Copyright © 2016-present Jesse Squires.

================================================ FILE: docs/js/jazzy.js ================================================ window.jazzy = {'docset': false} if (typeof window.dash != 'undefined') { document.documentElement.className += ' dash' window.jazzy.docset = true } if (navigator.userAgent.match(/xcode/i)) { document.documentElement.className += ' xcode' window.jazzy.docset = true } function toggleItem($link, $content) { var animationDuration = 300; $link.toggleClass('token-open'); $content.slideToggle(animationDuration); } function itemLinkToContent($link) { return $link.parent().parent().next(); } // On doc load + hash-change, open any targetted item function openCurrentItemIfClosed() { if (window.jazzy.docset) { return; } var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); $content = itemLinkToContent($link); if ($content.is(':hidden')) { toggleItem($link, $content); } } $(openCurrentItemIfClosed); $(window).on('hashchange', openCurrentItemIfClosed); // On item link ('token') click, toggle its discussion $('.token').on('click', function(event) { if (window.jazzy.docset) { return; } var $link = $(this); toggleItem($link, itemLinkToContent($link)); // Keeps the document from jumping to the hash. var href = $link.attr('href'); if (history.pushState) { history.pushState({}, '', href); } else { location.hash = href; } event.preventDefault(); }); // Clicks on links to the current, closed, item need to open the item $("a:not('.token')").on('click', function() { if (location == this.href) { openCurrentItemIfClosed(); } }); // KaTeX rendering if ("katex" in window) { $($('.math').each( (_, element) => { katex.render(element.textContent, element, { displayMode: $(element).hasClass('m-block'), throwOnError: false, trust: true }); })) } ================================================ FILE: docs/js/jazzy.search.js ================================================ $(function(){ var $typeahead = $('[data-typeahead]'); var $form = $typeahead.parents('form'); var searchURL = $form.attr('action'); function displayTemplate(result) { return result.name; } function suggestionTemplate(result) { var t = '
'; t += '' + result.name + ''; if (result.parent_name) { t += '' + result.parent_name + ''; } t += '
'; return t; } $typeahead.one('focus', function() { $form.addClass('loading'); $.getJSON(searchURL).then(function(searchData) { const searchIndex = lunr(function() { this.ref('url'); this.field('name'); this.field('abstract'); for (const [url, doc] of Object.entries(searchData)) { this.add({url: url, name: doc.name, abstract: doc.abstract}); } }); $typeahead.typeahead( { highlight: true, minLength: 3, autoselect: true }, { limit: 10, display: displayTemplate, templates: { suggestion: suggestionTemplate }, source: function(query, sync) { const lcSearch = query.toLowerCase(); const results = searchIndex.query(function(q) { q.term(lcSearch, { boost: 100 }); q.term(lcSearch, { boost: 10, wildcard: lunr.Query.wildcard.TRAILING }); }).map(function(result) { var doc = searchData[result.ref]; doc.url = result.ref; return doc; }); sync(results); } } ); $form.removeClass('loading'); $typeahead.trigger('focus'); }); }); var baseURL = searchURL.slice(0, -"search.json".length); $typeahead.on('typeahead:select', function(e, result) { window.location = baseURL + result.url; }); }); ================================================ FILE: docs/js/typeahead.jquery.js ================================================ /*! * typeahead.js 1.3.1 * https://github.com/corejavascript/typeahead.js * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT */ (function(root, factory) { if (typeof define === "function" && define.amd) { define([ "jquery" ], function(a0) { return factory(a0); }); } else if (typeof module === "object" && module.exports) { module.exports = factory(require("jquery")); } else { factory(root["jQuery"]); } })(this, function($) { var _ = function() { "use strict"; return { isMsie: function() { return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; }, isBlankString: function(str) { return !str || /^\s*$/.test(str); }, escapeRegExChars: function(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }, isString: function(obj) { return typeof obj === "string"; }, isNumber: function(obj) { return typeof obj === "number"; }, isArray: $.isArray, isFunction: $.isFunction, isObject: $.isPlainObject, isUndefined: function(obj) { return typeof obj === "undefined"; }, isElement: function(obj) { return !!(obj && obj.nodeType === 1); }, isJQuery: function(obj) { return obj instanceof $; }, toStr: function toStr(s) { return _.isUndefined(s) || s === null ? "" : s + ""; }, bind: $.proxy, each: function(collection, cb) { $.each(collection, reverseArgs); function reverseArgs(index, value) { return cb(value, index); } }, map: $.map, filter: $.grep, every: function(obj, test) { var result = true; if (!obj) { return result; } $.each(obj, function(key, val) { if (!(result = test.call(null, val, key, obj))) { return false; } }); return !!result; }, some: function(obj, test) { var result = false; if (!obj) { return result; } $.each(obj, function(key, val) { if (result = test.call(null, val, key, obj)) { return false; } }); return !!result; }, mixin: $.extend, identity: function(x) { return x; }, clone: function(obj) { return $.extend(true, {}, obj); }, getIdGenerator: function() { var counter = 0; return function() { return counter++; }; }, templatify: function templatify(obj) { return $.isFunction(obj) ? obj : template; function template() { return String(obj); } }, defer: function(fn) { setTimeout(fn, 0); }, debounce: function(func, wait, immediate) { var timeout, result; return function() { var context = this, args = arguments, later, callNow; later = function() { timeout = null; if (!immediate) { result = func.apply(context, args); } }; callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); } return result; }; }, throttle: function(func, wait) { var context, args, timeout, result, previous, later; previous = 0; later = function() { previous = new Date(); timeout = null; result = func.apply(context, args); }; return function() { var now = new Date(), remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); } else if (!timeout) { timeout = setTimeout(later, remaining); } return result; }; }, stringify: function(val) { return _.isString(val) ? val : JSON.stringify(val); }, guid: function() { function _p8(s) { var p = (Math.random().toString(16) + "000000000").substr(2, 8); return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; } return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); }, noop: function() {} }; }(); var WWW = function() { "use strict"; var defaultClassNames = { wrapper: "twitter-typeahead", input: "tt-input", hint: "tt-hint", menu: "tt-menu", dataset: "tt-dataset", suggestion: "tt-suggestion", selectable: "tt-selectable", empty: "tt-empty", open: "tt-open", cursor: "tt-cursor", highlight: "tt-highlight" }; return build; function build(o) { var www, classes; classes = _.mixin({}, defaultClassNames, o); www = { css: buildCss(), classes: classes, html: buildHtml(classes), selectors: buildSelectors(classes) }; return { css: www.css, html: www.html, classes: www.classes, selectors: www.selectors, mixin: function(o) { _.mixin(o, www); } }; } function buildHtml(c) { return { wrapper: '', menu: '
' }; } function buildSelectors(classes) { var selectors = {}; _.each(classes, function(v, k) { selectors[k] = "." + v; }); return selectors; } function buildCss() { var css = { wrapper: { position: "relative", display: "inline-block" }, hint: { position: "absolute", top: "0", left: "0", borderColor: "transparent", boxShadow: "none", opacity: "1" }, input: { position: "relative", verticalAlign: "top", backgroundColor: "transparent" }, inputWithNoHint: { position: "relative", verticalAlign: "top" }, menu: { position: "absolute", top: "100%", left: "0", zIndex: "100", display: "none" }, ltr: { left: "0", right: "auto" }, rtl: { left: "auto", right: " 0" } }; if (_.isMsie()) { _.mixin(css.input, { backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" }); } return css; } }(); var EventBus = function() { "use strict"; var namespace, deprecationMap; namespace = "typeahead:"; deprecationMap = { render: "rendered", cursorchange: "cursorchanged", select: "selected", autocomplete: "autocompleted" }; function EventBus(o) { if (!o || !o.el) { $.error("EventBus initialized without el"); } this.$el = $(o.el); } _.mixin(EventBus.prototype, { _trigger: function(type, args) { var $e = $.Event(namespace + type); this.$el.trigger.call(this.$el, $e, args || []); return $e; }, before: function(type) { var args, $e; args = [].slice.call(arguments, 1); $e = this._trigger("before" + type, args); return $e.isDefaultPrevented(); }, trigger: function(type) { var deprecatedType; this._trigger(type, [].slice.call(arguments, 1)); if (deprecatedType = deprecationMap[type]) { this._trigger(deprecatedType, [].slice.call(arguments, 1)); } } }); return EventBus; }(); var EventEmitter = function() { "use strict"; var splitter = /\s+/, nextTick = getNextTick(); return { onSync: onSync, onAsync: onAsync, off: off, trigger: trigger }; function on(method, types, cb, context) { var type; if (!cb) { return this; } types = types.split(splitter); cb = context ? bindContext(cb, context) : cb; this._callbacks = this._callbacks || {}; while (type = types.shift()) { this._callbacks[type] = this._callbacks[type] || { sync: [], async: [] }; this._callbacks[type][method].push(cb); } return this; } function onAsync(types, cb, context) { return on.call(this, "async", types, cb, context); } function onSync(types, cb, context) { return on.call(this, "sync", types, cb, context); } function off(types) { var type; if (!this._callbacks) { return this; } types = types.split(splitter); while (type = types.shift()) { delete this._callbacks[type]; } return this; } function trigger(types) { var type, callbacks, args, syncFlush, asyncFlush; if (!this._callbacks) { return this; } types = types.split(splitter); args = [].slice.call(arguments, 1); while ((type = types.shift()) && (callbacks = this._callbacks[type])) { syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); syncFlush() && nextTick(asyncFlush); } return this; } function getFlush(callbacks, context, args) { return flush; function flush() { var cancelled; for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { cancelled = callbacks[i].apply(context, args) === false; } return !cancelled; } } function getNextTick() { var nextTickFn; if (window.setImmediate) { nextTickFn = function nextTickSetImmediate(fn) { setImmediate(function() { fn(); }); }; } else { nextTickFn = function nextTickSetTimeout(fn) { setTimeout(function() { fn(); }, 0); }; } return nextTickFn; } function bindContext(fn, context) { return fn.bind ? fn.bind(context) : function() { fn.apply(context, [].slice.call(arguments, 0)); }; } }(); var highlight = function(doc) { "use strict"; var defaults = { node: null, pattern: null, tagName: "strong", className: null, wordsOnly: false, caseSensitive: false, diacriticInsensitive: false }; var accented = { A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" }; return function hightlight(o) { var regex; o = _.mixin({}, defaults, o); if (!o.node || !o.pattern) { return; } o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); traverse(o.node, hightlightTextNode); function hightlightTextNode(textNode) { var match, patternNode, wrapperNode; if (match = regex.exec(textNode.data)) { wrapperNode = doc.createElement(o.tagName); o.className && (wrapperNode.className = o.className); patternNode = textNode.splitText(match.index); patternNode.splitText(match[0].length); wrapperNode.appendChild(patternNode.cloneNode(true)); textNode.parentNode.replaceChild(wrapperNode, patternNode); } return !!match; } function traverse(el, hightlightTextNode) { var childNode, TEXT_NODE_TYPE = 3; for (var i = 0; i < el.childNodes.length; i++) { childNode = el.childNodes[i]; if (childNode.nodeType === TEXT_NODE_TYPE) { i += hightlightTextNode(childNode) ? 1 : 0; } else { traverse(childNode, hightlightTextNode); } } } }; function accent_replacer(chr) { return accented[chr.toUpperCase()] || chr; } function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { var escapedPatterns = [], regexStr; for (var i = 0, len = patterns.length; i < len; i++) { var escapedWord = _.escapeRegExChars(patterns[i]); if (diacriticInsensitive) { escapedWord = escapedWord.replace(/\S/g, accent_replacer); } escapedPatterns.push(escapedWord); } regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); } }(window.document); var Input = function() { "use strict"; var specialKeyCodeMap; specialKeyCodeMap = { 9: "tab", 27: "esc", 37: "left", 39: "right", 13: "enter", 38: "up", 40: "down" }; function Input(o, www) { var id; o = o || {}; if (!o.input) { $.error("input is missing"); } www.mixin(this); this.$hint = $(o.hint); this.$input = $(o.input); this.$menu = $(o.menu); id = this.$input.attr("id") || _.guid(); this.$menu.attr("id", id + "_listbox"); this.$hint.attr({ "aria-hidden": true }); this.$input.attr({ "aria-owns": id + "_listbox", role: "combobox", "aria-autocomplete": "list", "aria-expanded": false }); this.query = this.$input.val(); this.queryWhenFocused = this.hasFocus() ? this.query : null; this.$overflowHelper = buildOverflowHelper(this.$input); this._checkLanguageDirection(); if (this.$hint.length === 0) { this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; } this.onSync("cursorchange", this._updateDescendent); } Input.normalizeQuery = function(str) { return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); }; _.mixin(Input.prototype, EventEmitter, { _onBlur: function onBlur() { this.resetInputValue(); this.trigger("blurred"); }, _onFocus: function onFocus() { this.queryWhenFocused = this.query; this.trigger("focused"); }, _onKeydown: function onKeydown($e) { var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; this._managePreventDefault(keyName, $e); if (keyName && this._shouldTrigger(keyName, $e)) { this.trigger(keyName + "Keyed", $e); } }, _onInput: function onInput() { this._setQuery(this.getInputValue()); this.clearHintIfInvalid(); this._checkLanguageDirection(); }, _managePreventDefault: function managePreventDefault(keyName, $e) { var preventDefault; switch (keyName) { case "up": case "down": preventDefault = !withModifier($e); break; default: preventDefault = false; } preventDefault && $e.preventDefault(); }, _shouldTrigger: function shouldTrigger(keyName, $e) { var trigger; switch (keyName) { case "tab": trigger = !withModifier($e); break; default: trigger = true; } return trigger; }, _checkLanguageDirection: function checkLanguageDirection() { var dir = (this.$input.css("direction") || "ltr").toLowerCase(); if (this.dir !== dir) { this.dir = dir; this.$hint.attr("dir", dir); this.trigger("langDirChanged", dir); } }, _setQuery: function setQuery(val, silent) { var areEquivalent, hasDifferentWhitespace; areEquivalent = areQueriesEquivalent(val, this.query); hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; this.query = val; if (!silent && !areEquivalent) { this.trigger("queryChanged", this.query); } else if (!silent && hasDifferentWhitespace) { this.trigger("whitespaceChanged", this.query); } }, _updateDescendent: function updateDescendent(event, id) { this.$input.attr("aria-activedescendant", id); }, bind: function() { var that = this, onBlur, onFocus, onKeydown, onInput; onBlur = _.bind(this._onBlur, this); onFocus = _.bind(this._onFocus, this); onKeydown = _.bind(this._onKeydown, this); onInput = _.bind(this._onInput, this); this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); if (!_.isMsie() || _.isMsie() > 9) { this.$input.on("input.tt", onInput); } else { this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { if (specialKeyCodeMap[$e.which || $e.keyCode]) { return; } _.defer(_.bind(that._onInput, that, $e)); }); } return this; }, focus: function focus() { this.$input.focus(); }, blur: function blur() { this.$input.blur(); }, getLangDir: function getLangDir() { return this.dir; }, getQuery: function getQuery() { return this.query || ""; }, setQuery: function setQuery(val, silent) { this.setInputValue(val); this._setQuery(val, silent); }, hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { return this.query !== this.queryWhenFocused; }, getInputValue: function getInputValue() { return this.$input.val(); }, setInputValue: function setInputValue(value) { this.$input.val(value); this.clearHintIfInvalid(); this._checkLanguageDirection(); }, resetInputValue: function resetInputValue() { this.setInputValue(this.query); }, getHint: function getHint() { return this.$hint.val(); }, setHint: function setHint(value) { this.$hint.val(value); }, clearHint: function clearHint() { this.setHint(""); }, clearHintIfInvalid: function clearHintIfInvalid() { var val, hint, valIsPrefixOfHint, isValid; val = this.getInputValue(); hint = this.getHint(); valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); !isValid && this.clearHint(); }, hasFocus: function hasFocus() { return this.$input.is(":focus"); }, hasOverflow: function hasOverflow() { var constraint = this.$input.width() - 2; this.$overflowHelper.text(this.getInputValue()); return this.$overflowHelper.width() >= constraint; }, isCursorAtEnd: function() { var valueLength, selectionStart, range; valueLength = this.$input.val().length; selectionStart = this.$input[0].selectionStart; if (_.isNumber(selectionStart)) { return selectionStart === valueLength; } else if (document.selection) { range = document.selection.createRange(); range.moveStart("character", -valueLength); return valueLength === range.text.length; } return true; }, destroy: function destroy() { this.$hint.off(".tt"); this.$input.off(".tt"); this.$overflowHelper.remove(); this.$hint = this.$input = this.$overflowHelper = $("
"); }, setAriaExpanded: function setAriaExpanded(value) { this.$input.attr("aria-expanded", value); } }); return Input; function buildOverflowHelper($input) { return $('').css({ position: "absolute", visibility: "hidden", whiteSpace: "pre", fontFamily: $input.css("font-family"), fontSize: $input.css("font-size"), fontStyle: $input.css("font-style"), fontVariant: $input.css("font-variant"), fontWeight: $input.css("font-weight"), wordSpacing: $input.css("word-spacing"), letterSpacing: $input.css("letter-spacing"), textIndent: $input.css("text-indent"), textRendering: $input.css("text-rendering"), textTransform: $input.css("text-transform") }).insertAfter($input); } function areQueriesEquivalent(a, b) { return Input.normalizeQuery(a) === Input.normalizeQuery(b); } function withModifier($e) { return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; } }(); var Dataset = function() { "use strict"; var keys, nameGenerator; keys = { dataset: "tt-selectable-dataset", val: "tt-selectable-display", obj: "tt-selectable-object" }; nameGenerator = _.getIdGenerator(); function Dataset(o, www) { o = o || {}; o.templates = o.templates || {}; o.templates.notFound = o.templates.notFound || o.templates.empty; if (!o.source) { $.error("missing source"); } if (!o.node) { $.error("missing node"); } if (o.name && !isValidName(o.name)) { $.error("invalid dataset name: " + o.name); } www.mixin(this); this.highlight = !!o.highlight; this.name = _.toStr(o.name || nameGenerator()); this.limit = o.limit || 5; this.displayFn = getDisplayFn(o.display || o.displayKey); this.templates = getTemplates(o.templates, this.displayFn); this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; this._resetLastSuggestion(); this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); } Dataset.extractData = function extractData(el) { var $el = $(el); if ($el.data(keys.obj)) { return { dataset: $el.data(keys.dataset) || "", val: $el.data(keys.val) || "", obj: $el.data(keys.obj) || null }; } return null; }; _.mixin(Dataset.prototype, EventEmitter, { _overwrite: function overwrite(query, suggestions) { suggestions = suggestions || []; if (suggestions.length) { this._renderSuggestions(query, suggestions); } else if (this.async && this.templates.pending) { this._renderPending(query); } else if (!this.async && this.templates.notFound) { this._renderNotFound(query); } else { this._empty(); } this.trigger("rendered", suggestions, false, this.name); }, _append: function append(query, suggestions) { suggestions = suggestions || []; if (suggestions.length && this.$lastSuggestion.length) { this._appendSuggestions(query, suggestions); } else if (suggestions.length) { this._renderSuggestions(query, suggestions); } else if (!this.$lastSuggestion.length && this.templates.notFound) { this._renderNotFound(query); } this.trigger("rendered", suggestions, true, this.name); }, _renderSuggestions: function renderSuggestions(query, suggestions) { var $fragment; $fragment = this._getSuggestionsFragment(query, suggestions); this.$lastSuggestion = $fragment.children().last(); this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); }, _appendSuggestions: function appendSuggestions(query, suggestions) { var $fragment, $lastSuggestion; $fragment = this._getSuggestionsFragment(query, suggestions); $lastSuggestion = $fragment.children().last(); this.$lastSuggestion.after($fragment); this.$lastSuggestion = $lastSuggestion; }, _renderPending: function renderPending(query) { var template = this.templates.pending; this._resetLastSuggestion(); template && this.$el.html(template({ query: query, dataset: this.name })); }, _renderNotFound: function renderNotFound(query) { var template = this.templates.notFound; this._resetLastSuggestion(); template && this.$el.html(template({ query: query, dataset: this.name })); }, _empty: function empty() { this.$el.empty(); this._resetLastSuggestion(); }, _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { var that = this, fragment; fragment = document.createDocumentFragment(); _.each(suggestions, function getSuggestionNode(suggestion) { var $el, context; context = that._injectQuery(query, suggestion); $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); fragment.appendChild($el[0]); }); this.highlight && highlight({ className: this.classes.highlight, node: fragment, pattern: query }); return $(fragment); }, _getFooter: function getFooter(query, suggestions) { return this.templates.footer ? this.templates.footer({ query: query, suggestions: suggestions, dataset: this.name }) : null; }, _getHeader: function getHeader(query, suggestions) { return this.templates.header ? this.templates.header({ query: query, suggestions: suggestions, dataset: this.name }) : null; }, _resetLastSuggestion: function resetLastSuggestion() { this.$lastSuggestion = $(); }, _injectQuery: function injectQuery(query, obj) { return _.isObject(obj) ? _.mixin({ _query: query }, obj) : obj; }, update: function update(query) { var that = this, canceled = false, syncCalled = false, rendered = 0; this.cancel(); this.cancel = function cancel() { canceled = true; that.cancel = $.noop; that.async && that.trigger("asyncCanceled", query, that.name); }; this.source(query, sync, async); !syncCalled && sync([]); function sync(suggestions) { if (syncCalled) { return; } syncCalled = true; suggestions = (suggestions || []).slice(0, that.limit); rendered = suggestions.length; that._overwrite(query, suggestions); if (rendered < that.limit && that.async) { that.trigger("asyncRequested", query, that.name); } } function async(suggestions) { suggestions = suggestions || []; if (!canceled && rendered < that.limit) { that.cancel = $.noop; var idx = Math.abs(rendered - that.limit); rendered += idx; that._append(query, suggestions.slice(0, idx)); that.async && that.trigger("asyncReceived", query, that.name); } } }, cancel: $.noop, clear: function clear() { this._empty(); this.cancel(); this.trigger("cleared"); }, isEmpty: function isEmpty() { return this.$el.is(":empty"); }, destroy: function destroy() { this.$el = $("
"); } }); return Dataset; function getDisplayFn(display) { display = display || _.stringify; return _.isFunction(display) ? display : displayFn; function displayFn(obj) { return obj[display]; } } function getTemplates(templates, displayFn) { return { notFound: templates.notFound && _.templatify(templates.notFound), pending: templates.pending && _.templatify(templates.pending), header: templates.header && _.templatify(templates.header), footer: templates.footer && _.templatify(templates.footer), suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate }; function userSuggestionTemplate(context) { var template = templates.suggestion; return $(template(context)).attr("id", _.guid()); } function suggestionTemplate(context) { return $('
').attr("id", _.guid()).text(displayFn(context)); } } function isValidName(str) { return /^[_a-zA-Z0-9-]+$/.test(str); } }(); var Menu = function() { "use strict"; function Menu(o, www) { var that = this; o = o || {}; if (!o.node) { $.error("node is required"); } www.mixin(this); this.$node = $(o.node); this.query = null; this.datasets = _.map(o.datasets, initializeDataset); function initializeDataset(oDataset) { var node = that.$node.find(oDataset.node).first(); oDataset.node = node.length ? node : $("
").appendTo(that.$node); return new Dataset(oDataset, www); } } _.mixin(Menu.prototype, EventEmitter, { _onSelectableClick: function onSelectableClick($e) { this.trigger("selectableClicked", $($e.currentTarget)); }, _onRendered: function onRendered(type, dataset, suggestions, async) { this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); this.trigger("datasetRendered", dataset, suggestions, async); }, _onCleared: function onCleared() { this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); this.trigger("datasetCleared"); }, _propagate: function propagate() { this.trigger.apply(this, arguments); }, _allDatasetsEmpty: function allDatasetsEmpty() { return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { var isEmpty = dataset.isEmpty(); this.$node.attr("aria-expanded", !isEmpty); return isEmpty; }, this)); }, _getSelectables: function getSelectables() { return this.$node.find(this.selectors.selectable); }, _removeCursor: function _removeCursor() { var $selectable = this.getActiveSelectable(); $selectable && $selectable.removeClass(this.classes.cursor); }, _ensureVisible: function ensureVisible($el) { var elTop, elBottom, nodeScrollTop, nodeHeight; elTop = $el.position().top; elBottom = elTop + $el.outerHeight(true); nodeScrollTop = this.$node.scrollTop(); nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); if (elTop < 0) { this.$node.scrollTop(nodeScrollTop + elTop); } else if (nodeHeight < elBottom) { this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); } }, bind: function() { var that = this, onSelectableClick; onSelectableClick = _.bind(this._onSelectableClick, this); this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); this.$node.on("mouseover", this.selectors.selectable, function() { that.setCursor($(this)); }); this.$node.on("mouseleave", function() { that._removeCursor(); }); _.each(this.datasets, function(dataset) { dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); }); return this; }, isOpen: function isOpen() { return this.$node.hasClass(this.classes.open); }, open: function open() { this.$node.scrollTop(0); this.$node.addClass(this.classes.open); }, close: function close() { this.$node.attr("aria-expanded", false); this.$node.removeClass(this.classes.open); this._removeCursor(); }, setLanguageDirection: function setLanguageDirection(dir) { this.$node.attr("dir", dir); }, selectableRelativeToCursor: function selectableRelativeToCursor(delta) { var $selectables, $oldCursor, oldIndex, newIndex; $oldCursor = this.getActiveSelectable(); $selectables = this._getSelectables(); oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; newIndex = oldIndex + delta; newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; return newIndex === -1 ? null : $selectables.eq(newIndex); }, setCursor: function setCursor($selectable) { this._removeCursor(); if ($selectable = $selectable && $selectable.first()) { $selectable.addClass(this.classes.cursor); this._ensureVisible($selectable); } }, getSelectableData: function getSelectableData($el) { return $el && $el.length ? Dataset.extractData($el) : null; }, getActiveSelectable: function getActiveSelectable() { var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); return $selectable.length ? $selectable : null; }, getTopSelectable: function getTopSelectable() { var $selectable = this._getSelectables().first(); return $selectable.length ? $selectable : null; }, update: function update(query) { var isValidUpdate = query !== this.query; if (isValidUpdate) { this.query = query; _.each(this.datasets, updateDataset); } return isValidUpdate; function updateDataset(dataset) { dataset.update(query); } }, empty: function empty() { _.each(this.datasets, clearDataset); this.query = null; this.$node.addClass(this.classes.empty); function clearDataset(dataset) { dataset.clear(); } }, destroy: function destroy() { this.$node.off(".tt"); this.$node = $("
"); _.each(this.datasets, destroyDataset); function destroyDataset(dataset) { dataset.destroy(); } } }); return Menu; }(); var Status = function() { "use strict"; function Status(options) { this.$el = $("", { role: "status", "aria-live": "polite" }).css({ position: "absolute", padding: "0", border: "0", height: "1px", width: "1px", "margin-bottom": "-1px", "margin-right": "-1px", overflow: "hidden", clip: "rect(0 0 0 0)", "white-space": "nowrap" }); options.$input.after(this.$el); _.each(options.menu.datasets, _.bind(function(dataset) { if (dataset.onSync) { dataset.onSync("rendered", _.bind(this.update, this)); dataset.onSync("cleared", _.bind(this.cleared, this)); } }, this)); } _.mixin(Status.prototype, { update: function update(event, suggestions) { var length = suggestions.length; var words; if (length === 1) { words = { result: "result", is: "is" }; } else { words = { result: "results", is: "are" }; } this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); }, cleared: function() { this.$el.text(""); } }); return Status; }(); var DefaultMenu = function() { "use strict"; var s = Menu.prototype; function DefaultMenu() { Menu.apply(this, [].slice.call(arguments, 0)); } _.mixin(DefaultMenu.prototype, Menu.prototype, { open: function open() { !this._allDatasetsEmpty() && this._show(); return s.open.apply(this, [].slice.call(arguments, 0)); }, close: function close() { this._hide(); return s.close.apply(this, [].slice.call(arguments, 0)); }, _onRendered: function onRendered() { if (this._allDatasetsEmpty()) { this._hide(); } else { this.isOpen() && this._show(); } return s._onRendered.apply(this, [].slice.call(arguments, 0)); }, _onCleared: function onCleared() { if (this._allDatasetsEmpty()) { this._hide(); } else { this.isOpen() && this._show(); } return s._onCleared.apply(this, [].slice.call(arguments, 0)); }, setLanguageDirection: function setLanguageDirection(dir) { this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); }, _hide: function hide() { this.$node.hide(); }, _show: function show() { this.$node.css("display", "block"); } }); return DefaultMenu; }(); var Typeahead = function() { "use strict"; function Typeahead(o, www) { var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; o = o || {}; if (!o.input) { $.error("missing input"); } if (!o.menu) { $.error("missing menu"); } if (!o.eventBus) { $.error("missing event bus"); } www.mixin(this); this.eventBus = o.eventBus; this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; this.input = o.input; this.menu = o.menu; this.enabled = true; this.autoselect = !!o.autoselect; this.active = false; this.input.hasFocus() && this.activate(); this.dir = this.input.getLangDir(); this._hacks(); this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); onFocused = c(this, "activate", "open", "_onFocused"); onBlurred = c(this, "deactivate", "_onBlurred"); onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); onEscKeyed = c(this, "isActive", "_onEscKeyed"); onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); } _.mixin(Typeahead.prototype, { _hacks: function hacks() { var $input, $menu; $input = this.input.$input || $("
"); $menu = this.menu.$node || $("
"); $input.on("blur.tt", function($e) { var active, isActive, hasActive; active = document.activeElement; isActive = $menu.is(active); hasActive = $menu.has(active).length > 0; if (_.isMsie() && (isActive || hasActive)) { $e.preventDefault(); $e.stopImmediatePropagation(); _.defer(function() { $input.focus(); }); } }); $menu.on("mousedown.tt", function($e) { $e.preventDefault(); }); }, _onSelectableClicked: function onSelectableClicked(type, $el) { this.select($el); }, _onDatasetCleared: function onDatasetCleared() { this._updateHint(); }, _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { this._updateHint(); if (this.autoselect) { var cursorClass = this.selectors.cursor.substr(1); this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); } this.eventBus.trigger("render", suggestions, async, dataset); }, _onAsyncRequested: function onAsyncRequested(type, dataset, query) { this.eventBus.trigger("asyncrequest", query, dataset); }, _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { this.eventBus.trigger("asynccancel", query, dataset); }, _onAsyncReceived: function onAsyncReceived(type, dataset, query) { this.eventBus.trigger("asyncreceive", query, dataset); }, _onFocused: function onFocused() { this._minLengthMet() && this.menu.update(this.input.getQuery()); }, _onBlurred: function onBlurred() { if (this.input.hasQueryChangedSinceLastFocus()) { this.eventBus.trigger("change", this.input.getQuery()); } }, _onEnterKeyed: function onEnterKeyed(type, $e) { var $selectable; if ($selectable = this.menu.getActiveSelectable()) { if (this.select($selectable)) { $e.preventDefault(); $e.stopPropagation(); } } else if (this.autoselect) { if (this.select(this.menu.getTopSelectable())) { $e.preventDefault(); $e.stopPropagation(); } } }, _onTabKeyed: function onTabKeyed(type, $e) { var $selectable; if ($selectable = this.menu.getActiveSelectable()) { this.select($selectable) && $e.preventDefault(); } else if (this.autoselect) { if ($selectable = this.menu.getTopSelectable()) { this.autocomplete($selectable) && $e.preventDefault(); } } }, _onEscKeyed: function onEscKeyed() { this.close(); }, _onUpKeyed: function onUpKeyed() { this.moveCursor(-1); }, _onDownKeyed: function onDownKeyed() { this.moveCursor(+1); }, _onLeftKeyed: function onLeftKeyed() { if (this.dir === "rtl" && this.input.isCursorAtEnd()) { this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); } }, _onRightKeyed: function onRightKeyed() { if (this.dir === "ltr" && this.input.isCursorAtEnd()) { this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); } }, _onQueryChanged: function onQueryChanged(e, query) { this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); }, _onWhitespaceChanged: function onWhitespaceChanged() { this._updateHint(); }, _onLangDirChanged: function onLangDirChanged(e, dir) { if (this.dir !== dir) { this.dir = dir; this.menu.setLanguageDirection(dir); } }, _openIfActive: function openIfActive() { this.isActive() && this.open(); }, _minLengthMet: function minLengthMet(query) { query = _.isString(query) ? query : this.input.getQuery() || ""; return query.length >= this.minLength; }, _updateHint: function updateHint() { var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; $selectable = this.menu.getTopSelectable(); data = this.menu.getSelectableData($selectable); val = this.input.getInputValue(); if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { query = Input.normalizeQuery(val); escapedQuery = _.escapeRegExChars(query); frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); match = frontMatchRegEx.exec(data.val); match && this.input.setHint(val + match[1]); } else { this.input.clearHint(); } }, isEnabled: function isEnabled() { return this.enabled; }, enable: function enable() { this.enabled = true; }, disable: function disable() { this.enabled = false; }, isActive: function isActive() { return this.active; }, activate: function activate() { if (this.isActive()) { return true; } else if (!this.isEnabled() || this.eventBus.before("active")) { return false; } else { this.active = true; this.eventBus.trigger("active"); return true; } }, deactivate: function deactivate() { if (!this.isActive()) { return true; } else if (this.eventBus.before("idle")) { return false; } else { this.active = false; this.close(); this.eventBus.trigger("idle"); return true; } }, isOpen: function isOpen() { return this.menu.isOpen(); }, open: function open() { if (!this.isOpen() && !this.eventBus.before("open")) { this.input.setAriaExpanded(true); this.menu.open(); this._updateHint(); this.eventBus.trigger("open"); } return this.isOpen(); }, close: function close() { if (this.isOpen() && !this.eventBus.before("close")) { this.input.setAriaExpanded(false); this.menu.close(); this.input.clearHint(); this.input.resetInputValue(); this.eventBus.trigger("close"); } return !this.isOpen(); }, setVal: function setVal(val) { this.input.setQuery(_.toStr(val)); }, getVal: function getVal() { return this.input.getQuery(); }, select: function select($selectable) { var data = this.menu.getSelectableData($selectable); if (data && !this.eventBus.before("select", data.obj, data.dataset)) { this.input.setQuery(data.val, true); this.eventBus.trigger("select", data.obj, data.dataset); this.close(); return true; } return false; }, autocomplete: function autocomplete($selectable) { var query, data, isValid; query = this.input.getQuery(); data = this.menu.getSelectableData($selectable); isValid = data && query !== data.val; if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { this.input.setQuery(data.val); this.eventBus.trigger("autocomplete", data.obj, data.dataset); return true; } return false; }, moveCursor: function moveCursor(delta) { var query, $candidate, data, suggestion, datasetName, cancelMove, id; query = this.input.getQuery(); $candidate = this.menu.selectableRelativeToCursor(delta); data = this.menu.getSelectableData($candidate); suggestion = data ? data.obj : null; datasetName = data ? data.dataset : null; id = $candidate ? $candidate.attr("id") : null; this.input.trigger("cursorchange", id); cancelMove = this._minLengthMet() && this.menu.update(query); if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { this.menu.setCursor($candidate); if (data) { if (typeof data.val === "string") { this.input.setInputValue(data.val); } } else { this.input.resetInputValue(); this._updateHint(); } this.eventBus.trigger("cursorchange", suggestion, datasetName); return true; } return false; }, destroy: function destroy() { this.input.destroy(); this.menu.destroy(); } }); return Typeahead; function c(ctx) { var methods = [].slice.call(arguments, 1); return function() { var args = [].slice.call(arguments); _.each(methods, function(method) { return ctx[method].apply(ctx, args); }); }; } }(); (function() { "use strict"; var old, keys, methods; old = $.fn.typeahead; keys = { www: "tt-www", attrs: "tt-attrs", typeahead: "tt-typeahead" }; methods = { initialize: function initialize(o, datasets) { var www; datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); o = o || {}; www = WWW(o.classNames); return this.each(attach); function attach() { var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; _.each(datasets, function(d) { d.highlight = !!o.highlight; }); $input = $(this); $wrapper = $(www.html.wrapper); $hint = $elOrNull(o.hint); $menu = $elOrNull(o.menu); defaultHint = o.hint !== false && !$hint; defaultMenu = o.menu !== false && !$menu; defaultHint && ($hint = buildHintFromInput($input, www)); defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); $hint && $hint.val(""); $input = prepInput($input, www); if (defaultHint || defaultMenu) { $wrapper.css(www.css.wrapper); $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); } MenuConstructor = defaultMenu ? DefaultMenu : Menu; eventBus = new EventBus({ el: $input }); input = new Input({ hint: $hint, input: $input, menu: $menu }, www); menu = new MenuConstructor({ node: $menu, datasets: datasets }, www); status = new Status({ $input: $input, menu: menu }); typeahead = new Typeahead({ input: input, menu: menu, eventBus: eventBus, minLength: o.minLength, autoselect: o.autoselect }, www); $input.data(keys.www, www); $input.data(keys.typeahead, typeahead); } }, isEnabled: function isEnabled() { var enabled; ttEach(this.first(), function(t) { enabled = t.isEnabled(); }); return enabled; }, enable: function enable() { ttEach(this, function(t) { t.enable(); }); return this; }, disable: function disable() { ttEach(this, function(t) { t.disable(); }); return this; }, isActive: function isActive() { var active; ttEach(this.first(), function(t) { active = t.isActive(); }); return active; }, activate: function activate() { ttEach(this, function(t) { t.activate(); }); return this; }, deactivate: function deactivate() { ttEach(this, function(t) { t.deactivate(); }); return this; }, isOpen: function isOpen() { var open; ttEach(this.first(), function(t) { open = t.isOpen(); }); return open; }, open: function open() { ttEach(this, function(t) { t.open(); }); return this; }, close: function close() { ttEach(this, function(t) { t.close(); }); return this; }, select: function select(el) { var success = false, $el = $(el); ttEach(this.first(), function(t) { success = t.select($el); }); return success; }, autocomplete: function autocomplete(el) { var success = false, $el = $(el); ttEach(this.first(), function(t) { success = t.autocomplete($el); }); return success; }, moveCursor: function moveCursoe(delta) { var success = false; ttEach(this.first(), function(t) { success = t.moveCursor(delta); }); return success; }, val: function val(newVal) { var query; if (!arguments.length) { ttEach(this.first(), function(t) { query = t.getVal(); }); return query; } else { ttEach(this, function(t) { t.setVal(_.toStr(newVal)); }); return this; } }, destroy: function destroy() { ttEach(this, function(typeahead, $input) { revert($input); typeahead.destroy(); }); return this; } }; $.fn.typeahead = function(method) { if (methods[method]) { return methods[method].apply(this, [].slice.call(arguments, 1)); } else { return methods.initialize.apply(this, arguments); } }; $.fn.typeahead.noConflict = function noConflict() { $.fn.typeahead = old; return this; }; function ttEach($els, fn) { $els.each(function() { var $input = $(this), typeahead; (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); }); } function buildHintFromInput($input, www) { return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ readonly: true, required: false }).removeAttr("id name placeholder").removeClass("required").attr({ spellcheck: "false", tabindex: -1 }); } function prepInput($input, www) { $input.data(keys.attrs, { dir: $input.attr("dir"), autocomplete: $input.attr("autocomplete"), spellcheck: $input.attr("spellcheck"), style: $input.attr("style") }); $input.addClass(www.classes.input).attr({ spellcheck: false }); try { !$input.attr("dir") && $input.attr("dir", "auto"); } catch (e) {} return $input; } function getBackgroundStyles($el) { return { backgroundAttachment: $el.css("background-attachment"), backgroundClip: $el.css("background-clip"), backgroundColor: $el.css("background-color"), backgroundImage: $el.css("background-image"), backgroundOrigin: $el.css("background-origin"), backgroundPosition: $el.css("background-position"), backgroundRepeat: $el.css("background-repeat"), backgroundSize: $el.css("background-size") }; } function revert($input) { var www, $wrapper; www = $input.data(keys.www); $wrapper = $input.parent().filter(www.selectors.wrapper); _.each($input.data(keys.attrs), function(val, key) { _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); }); $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); if ($wrapper.length) { $input.detach().insertAfter($wrapper); $wrapper.remove(); } } function $elOrNull(obj) { var isValid, $el; isValid = _.isJQuery(obj) || _.isElement(obj); $el = isValid ? $(obj).first() : []; return $el.length ? $el : null; } })(); }); ================================================ FILE: docs/search.json ================================================ {"Structs/PopoverConfig/Source.html#/s:12PresenterKit13PopoverConfigV6SourceO13barButtonItemyAESo05UIBargH0CcAEmF":{"name":"barButtonItem(_:)","abstract":"

Specifies that the popover should display from a UIBarButtonItem instance.

","parent_name":"Source"},"Structs/PopoverConfig/Source.html#/s:12PresenterKit13PopoverConfigV6SourceO4viewyAESo6UIViewC_So6CGRectVSgtcAEmF":{"name":"view(container:frame:)","abstract":"

Specifies that the popover should display from a UIView instance and be anchored on the specific frame.","parent_name":"Source"},"Structs/PopoverConfig/Source.html":{"name":"Source","abstract":"

Describes the source view from which the popover is showing.

","parent_name":"PopoverConfig"},"Structs/PopoverConfig.html#/s:12PresenterKit13PopoverConfigV6source14arrowDirection8delegateA2C6SourceO_So014UIPopoverArrowG0VSo0J30PresentationControllerDelegate_pSgtcfc":{"name":"init(source:arrowDirection:delegate:)","abstract":"

Initializes and returns a new PopoverConfig object.

","parent_name":"PopoverConfig"},"Structs/DismissButtonConfig/Content.html#/s:12PresenterKit19DismissButtonConfigV7ContentO10systemItemyAESo05UIBard6SystemH0VcAEmF":{"name":"systemItem(_:)","abstract":"

Specifies a UIBarButtonSystemItem.

","parent_name":"Content"},"Structs/DismissButtonConfig/Content.html#/s:12PresenterKit19DismissButtonConfigV7ContentO4textyAESScAEmF":{"name":"text(_:)","abstract":"

Specifies custom text for the bar button.

","parent_name":"Content"},"Structs/DismissButtonConfig/Content.html#/s:12PresenterKit19DismissButtonConfigV7ContentO5imageyAESo7UIImageCcAEmF":{"name":"image(_:)","abstract":"

Specifies a custom image for the bar button.

","parent_name":"Content"},"Structs/DismissButtonConfig/Style.html#/s:12PresenterKit19DismissButtonConfigV5StyleO4boldyA2EmF":{"name":"bold","abstract":"

Use bold text, .Done style.

","parent_name":"Style"},"Structs/DismissButtonConfig/Style.html#/s:12PresenterKit19DismissButtonConfigV5StyleO5plainyA2EmF":{"name":"plain","abstract":"

Use regular text, .Plain style.

","parent_name":"Style"},"Structs/DismissButtonConfig/Location.html#/s:12PresenterKit19DismissButtonConfigV8LocationO4leftyA2EmF":{"name":"left","abstract":"

The left side of the navigation bar.

","parent_name":"Location"},"Structs/DismissButtonConfig/Location.html#/s:12PresenterKit19DismissButtonConfigV8LocationO5rightyA2EmF":{"name":"right","abstract":"

The right side of the navigation bar.

","parent_name":"Location"},"Structs/DismissButtonConfig/Location.html":{"name":"Location","abstract":"

Specifies a bar button’s location in a navigation bar.

","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig/Style.html":{"name":"Style","abstract":"

Specifies a bar button’s item style.

","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig/Content.html":{"name":"Content","abstract":"

Specifies the content (title or image) for the bar button.

","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig.html#/s:12PresenterKit19DismissButtonConfigV8locationAC8LocationOvp":{"name":"location","abstract":"

The location for the bar button.","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig.html#/s:12PresenterKit19DismissButtonConfigV5styleAC5StyleOvp":{"name":"style","abstract":"

The style for the bar button.","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig.html#/s:12PresenterKit19DismissButtonConfigV7contentAC7ContentOvp":{"name":"content","abstract":"

The content for the bar button.","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig.html#/s:12PresenterKit19DismissButtonConfigV8location5style7contentA2C8LocationO_AC5StyleOAC7ContentOtcfc":{"name":"init(location:style:content:)","abstract":"

Initializes a new configuration instance.

","parent_name":"DismissButtonConfig"},"Structs/DismissButtonConfig.html":{"name":"DismissButtonConfig","abstract":"

A configuration for UIBarButtonItem."},"Structs/PopoverConfig.html":{"name":"PopoverConfig","abstract":"

A configuration for UIPopoverPresentationController.

"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE14withNavigationSo012UINavigationB0CyF":{"name":"withNavigation()","abstract":"

Wraps the receiving view controller in a navigation controller.","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE16withPresentationyABXDSo07UIModalF5StyleVF":{"name":"withPresentation(_:)","abstract":"

Applies the specified modal presentation style to the view controller.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE14withTransitionyABXDSo07UIModalF5StyleVF":{"name":"withTransition(_:)","abstract":"

Applies the specified modal transition style to the view controller.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE19withNavigationStyleyAbC0fG0OF":{"name":"withNavigationStyle(_:)","abstract":"

Applies the specified navigation style to the view controller.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE10withStyles10navigation12presentation10transitionAbC15NavigationStyleO_So019UIModalPresentationK0VSo0l10TransitionK0VtF":{"name":"withStyles(navigation:presentation:transition:)","abstract":"

Applies the specified navigation style to the view controller.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE07presentB0_4type8animated10completionyAB_AC16PresentationTypeOSbyycSgtF":{"name":"presentController(_:type:animated:completion:)","abstract":"

Presents a view controller using the specified presentation type.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE07dismissB08animated10completionySb_yycSgtF":{"name":"dismissController(animated:completion:)","abstract":"

Dismisses the receiving view controller.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE24addDismissButtonIfNeeded6configyAC0fG6ConfigV_tF":{"name":"addDismissButtonIfNeeded(config:)","abstract":"

Adds a dismiss button having the provided configuration, if needed.

","parent_name":"UIViewController"},"Extensions/UIViewController.html#/s:So16UIViewControllerC12PresenterKitE16addDismissButton6configyAC0fG6ConfigV_tF":{"name":"addDismissButton(config:)","abstract":"

Adds a dismiss button having the provided configuration.

","parent_name":"UIViewController"},"Extensions/UINavigationController.html#/s:So22UINavigationControllerC12PresenterKitE4push_8animated10completionySo06UIViewB0C_SbyycSgtF":{"name":"push(_:animated:completion:)","abstract":"

Pushes the given view controller and calls the given closure upon completion.

","parent_name":"UINavigationController"},"Extensions/UINavigationController.html#/s:So22UINavigationControllerC12PresenterKitE3pop8animated10completionySb_yycSgtF":{"name":"pop(animated:completion:)","abstract":"

Pops the top view controller and calls the given closure upon completion.

","parent_name":"UINavigationController"},"Extensions/UIBarButtonItem.html#/s:So15UIBarButtonItemC12PresenterKitE6config6target6actionAbC07DismissB6ConfigV_yXlSg10ObjectiveC8SelectorVtcfc":{"name":"init(config:target:action:)","abstract":"

Initializes a new bar button item using the specified configuration.

","parent_name":"UIBarButtonItem"},"Extensions/UIBarButtonItem.html":{"name":"UIBarButtonItem"},"Extensions/UINavigationController.html":{"name":"UINavigationController"},"Extensions/UIViewController.html":{"name":"UIViewController"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO5modalyAcA15NavigationStyleO_So07UIModalcG0VSo0h10TransitionG0VtcACmF":{"name":"modal(_:_:_:)","abstract":"

A modal presentation type with the specified navigation, presentation, and transition styles.

","parent_name":"PresentationType"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO7popoveryAcA13PopoverConfigVcACmF":{"name":"popover(_:)","abstract":"

A popover presentation type with the specified configuration.

","parent_name":"PresentationType"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO4pushyA2CmF":{"name":"push","abstract":"

A push presentation type.

","parent_name":"PresentationType"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO4showyA2CmF":{"name":"show","abstract":"

A “show” presentation type. This is an adaptive presentation that usually corresponds to .Push.

","parent_name":"PresentationType"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO10showDetailyAcA15NavigationStyleOcACmF":{"name":"showDetail(_:)","abstract":"

A “show detail” presentation type. This is an adaptive presentation that usually corresponds to .Modal.

","parent_name":"PresentationType"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO6customyACSo37UIViewControllerTransitioningDelegate_pcACmF":{"name":"custom(_:)","abstract":"

A custom presentation style that uses the specified delegate.

","parent_name":"PresentationType"},"Enums/PresentationType.html#/s:12PresenterKit16PresentationTypeO4noneyA2CmF":{"name":"none","abstract":"

No presentation type specified, use UIKit defaults. Use this when presenting system controllers, like UIAlertController.

","parent_name":"PresentationType"},"Enums/NavigationStyle.html#/s:12PresenterKit15NavigationStyleO4noneyA2CmF":{"name":"none","abstract":"

Do not embed a view controller in a UINavigationController.

","parent_name":"NavigationStyle"},"Enums/NavigationStyle.html#/s:12PresenterKit15NavigationStyleO04withC0yA2CmF":{"name":"withNavigation","abstract":"

Embed view controller in a UINavigationController.

","parent_name":"NavigationStyle"},"Enums/NavigationStyle.html":{"name":"NavigationStyle","abstract":"

Specifies the navigation style for a view controller.

"},"Enums/PresentationType.html":{"name":"PresentationType","abstract":"

Describes the type of presentation for a view controller.

"},"Classes.html#/c:@M@PresenterKit@objc(cs)HalfModalPresentationController":{"name":"HalfModalPresentationController","abstract":"

A modal presentation controller that presents the presented view controller modally,"},"getting-started.html":{"name":"Getting Started"},"Guides.html":{"name":"Guides","abstract":"

The following guides are available globally.

"},"Classes.html":{"name":"Classes","abstract":"

The following classes are available globally.

"},"Enums.html":{"name":"Enumerations","abstract":"

The following enumerations are available globally.

"},"Extensions.html":{"name":"Extensions","abstract":"

The following extensions are available globally.

"},"Structs.html":{"name":"Structures","abstract":"

The following structures are available globally.

"}} ================================================ FILE: docs/undocumented.json ================================================ { "warnings": [ ], "source_directory": "/Users/jsq/GitHub/PresenterKit" } ================================================ FILE: scripts/build_docs.zsh ================================================ #!/bin/zsh # Created by Jesse Squires # https://www.jessesquires.com # # Copyright © 2020-present Jesse Squires # # Docs by jazzy # https://github.com/realm/jazzy/releases/latest # ------------------------------ # Generates documentation using jazzy and checks for installation. VERSION="0.13.6" FOUND=$(jazzy --version) LINK="https://github.com/realm/jazzy" INSTALL="gem install jazzy" PROJECT="PresenterKit" if which jazzy >/dev/null; then jazzy \ --clean \ --author "Jesse Squires" \ --author_url "https://jessesquires.com" \ --github_url "https://github.com/jessesquires/$PROJECT" \ --module "$PROJECT" \ --source-directory . \ --readme "README.md" \ --documentation "Guides/*.md" \ --output docs/ else echo " Error: Jazzy not installed! Download: $LINK Install: $INSTALL " exit 1 fi if [ "$FOUND" != "jazzy version: $VERSION" ]; then echo " Warning: incorrect Jazzy installed! Please upgrade. Expected: $VERSION Found: $FOUND Download: $LINK Install: $INSTALL " fi exit ================================================ FILE: scripts/lint.zsh ================================================ #!/bin/zsh # Created by Jesse Squires # https://www.jessesquires.com # # Copyright © 2020-present Jesse Squires # # SwiftLint # https://github.com/realm/SwiftLint/releases/latest # ------------------------------ # Runs SwiftLint and checks for installation. VERSION="0.41.0" FOUND=$(swiftlint version) LINK="https://github.com/realm/SwiftLint" INSTALL="brew install swiftlint" if which swiftlint >/dev/null; then swiftlint lint --config ./.swiftlint.yml else echo " Error: SwiftLint not installed! Download: $LINK Install: $INSTALL " fi if [ $FOUND != $VERSION ]; then echo " Warning: incorrect SwiftLint installed! Please upgrade. Expected: $VERSION Found: $FOUND Download: $LINK Install: $INSTALL " fi exit