turbo-native-initializer 0.0.14 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d89f212990b6d8acf8b1f37073d8b892b7f043bdf4a19d11997fabf620ba4ca1
4
- data.tar.gz: d2b4ea5ee37d49c0d3eb23d4bb56894407a3ff5d535058ac21c54292439eae45
3
+ metadata.gz: a6841be700aef23b3f08578ca5600a2b04f749b0759b78524b9eeee25b401761
4
+ data.tar.gz: 150fcb0fdb292a111db55d614684162201e46fef74df2dd0d5e3bb07d1e631eb
5
5
  SHA512:
6
- metadata.gz: 3002e6b664dd0c92f04c2535707e8008a5c38e6d61e129bf3d376aa586bf2906228323a6947910b7a9d107dbcc2e33403ee1a2de508d444d97d37cea54fa1434
7
- data.tar.gz: 6884c3e84fef8d9462387a1ba5c787befe6b79053378bf6d21c5e65f68a3d31f117abf94a9eb0fb671581317968c17a3727247598b657b1171bf149316dbe00c
6
+ metadata.gz: 94495c27a497d66a322a394b5d0892d38ffd4b6db121dff707598864283efe3afd48ed50ab4f31ff08e60f64171ec2e7c2803131939e4aea202a1499e9d3bf31
7
+ data.tar.gz: dc44d0613e6e02f30de088a3f329297c8fd38e310e56c921a55d913c199862f6d44dfe468ff206bd0381dfedde8daf1def0acb41eef353b1dd93643421850b01
@@ -2,11 +2,11 @@
2
2
  "settings": {},
3
3
  "rules": [
4
4
  { "patterns": [".*"], "properties": { "uri": "turbo://fragment/web", "pull_to_refresh_enabled": true } },
5
- { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh" } },
6
5
  { "patterns": ["/recede_historical_location"], "properties": { "presentation": "pop" } },
7
6
  { "patterns": ["/resume_historical_location"], "properties": { "presentation": "none" } },
8
- { "patterns": ["^/$"], "properties": { "uri": "turbo://fragment/web/home", "presentation": "replace_all" } },
7
+ { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh" } },
9
8
  { "patterns": ["/new$", "/edit$", "/signin$", "/strada-form$"], "properties": { "context": "modal", "uri": "turbo://fragment/web/modal", "pull_to_refresh_enabled": false } },
9
+ { "patterns": ["^/$"], "properties": { "uri": "turbo://fragment/web/home", "presentation": "replace_all" } },
10
10
  { "patterns": ["/numbers$"], "properties": { "uri": "turbo://fragment/numbers", "title": "Numbers" } }
11
11
  ]
12
12
  }
@@ -2,11 +2,11 @@
2
2
  "settings": {},
3
3
  "rules": [
4
4
  { "patterns": [".*"], "properties": { "uri": "turbo://fragment/web", "pull_to_refresh_enabled": true } },
5
- { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh" } },
6
5
  { "patterns": ["/recede_historical_location"], "properties": { "presentation": "pop" } },
7
6
  { "patterns": ["/resume_historical_location"], "properties": { "presentation": "none" } },
8
- { "patterns": ["^/$"], "properties": { "uri": "turbo://fragment/web/home", "presentation": "replace_all" } },
7
+ { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh" } },
9
8
  { "patterns": ["/new$", "/edit$", "/signin$", "/strada-form$"], "properties": { "context": "modal", "uri": "turbo://fragment/web/modal", "pull_to_refresh_enabled": false } },
9
+ { "patterns": ["^/$"], "properties": { "uri": "turbo://fragment/web/home", "presentation": "replace_all" } },
10
10
  { "patterns": ["/numbers$"], "properties": { "uri": "turbo://fragment/numbers", "title": "Numbers" } }
11
11
  ]
12
12
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "settings": {},
3
3
  "rules": [
4
- { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh", "visitable": false } },
5
- { "patterns": ["/recede_historical_location"], "properties": { "presentation": "pop", "visitable": false } },
4
+ { "patterns": ["/recede_historical_location"], "properties": { "presentation": "back", "visitable": false } },
6
5
  { "patterns": ["/resume_historical_location"], "properties": { "presentation": "none", "visitable": false } },
6
+ { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh", "visitable": false } },
7
+ { "patterns": ["/new$", "/edit$", "/signin$", "/strada-form$"], "properties": { "presentation": "modal", "pull-to-refresh-enabled": false } },
7
8
  { "patterns": ["^/$"], "properties": { "presentation": "replace-all" } },
8
- { "patterns": ["/new$", "/edit$", "/signin$", "/strada-form$"], "properties": { "presentation": "modal" } },
9
9
  { "patterns": ["/numbers$"], "properties": { "view-controller": "numbers" } }
10
10
  ]
11
11
  }
@@ -22,9 +22,14 @@ class TurboNavigationController : UINavigationController {
22
22
  }
23
23
 
24
24
  // - Create view controller appropriate for url/properties
25
- // - Navigate to that with the correct presentation
26
25
  let viewController = makeViewController(for: url, properties: properties)
27
- navigate(to: viewController, action: options.action, properties: properties)
26
+
27
+ // - Navigate to that with the correct presentation
28
+ if session.topmostVisitable?.visitableURL == url {
29
+ navigate(to: viewController, action: .replace, properties: properties)
30
+ } else {
31
+ navigate(to: viewController, action: options.action, properties: properties)
32
+ }
28
33
 
29
34
  // Initiate the visit with Turbo
30
35
  if isVisitable(properties) {
@@ -43,8 +48,8 @@ extension TurboNavigationController {
43
48
  return properties["presentation"] as? String == "modal"
44
49
  }
45
50
 
46
- private func isPop(_ properties: PathProperties) -> Bool {
47
- return properties["presentation"] as? String == "pop"
51
+ private func isBack(_ properties: PathProperties) -> Bool {
52
+ return properties["presentation"] as? String == "back"
48
53
  }
49
54
 
50
55
  private func isRefresh(_ properties: PathProperties) -> Bool {
@@ -71,6 +76,14 @@ extension TurboNavigationController {
71
76
  return properties["visitable"] as? Bool ?? true
72
77
  }
73
78
 
79
+ private func isPullToRefreshEnabled(_ properties: PathProperties) -> Bool {
80
+ return properties["pull-to-refresh-enabled"] as? Bool ?? true
81
+ }
82
+
83
+ private func title(from properties: PathProperties) -> String? {
84
+ return properties["title"] as? String
85
+ }
86
+
74
87
  private func noticeMessage(from url: URL) -> String? {
75
88
  URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first(where: { $0.name == "notice" })?.value
76
89
  }
@@ -90,13 +103,16 @@ extension TurboNavigationController {
90
103
  }
91
104
  }
92
105
 
93
- return TurboWebViewController(url: url)
106
+ let viewController = TurboWebViewController(url: url)
107
+ viewController.pullToRefreshEnabled = isPullToRefreshEnabled(properties)
108
+ viewController.title = title(from: properties)
109
+ return viewController
94
110
  }
95
111
 
96
112
  private func navigate(to viewController: UIViewController, action: VisitAction, properties: PathProperties = [:]) {
97
113
  if isModal(properties) {
98
114
  present(UINavigationController(rootViewController: viewController), animated: true)
99
- } else if isPop(properties) {
115
+ } else if isBack(properties) {
100
116
  popViewController(animated: true)
101
117
  } else if isRefresh(properties) {
102
118
  session.reload()
@@ -5,6 +5,8 @@ import WebKit
5
5
 
6
6
  final class TurboWebViewController: VisitableViewController, ErrorPresenter, BridgeDestination {
7
7
 
8
+ var pullToRefreshEnabled = true
9
+
8
10
  private lazy var bridgeDelegate: BridgeDelegate = {
9
11
  BridgeDelegate(location: visitableURL.absoluteString, destination: self, componentTypes: BridgeComponent.allTypes)
10
12
  }()
@@ -20,6 +22,8 @@ final class TurboWebViewController: VisitableViewController, ErrorPresenter, Bri
20
22
 
21
23
  navigationItem.backButtonTitle = "Back"
22
24
 
25
+ visitableView.allowsPullToRefresh = pullToRefreshEnabled
26
+
23
27
  if presentingViewController != nil {
24
28
  navigationItem.leftBarButtonItem = dismissModalButton
25
29
  }
@@ -49,6 +53,10 @@ final class TurboWebViewController: VisitableViewController, ErrorPresenter, Bri
49
53
 
50
54
  // MARK: Visitable
51
55
 
56
+ override func visitableDidRender() {
57
+ title = title ?? visitableView.webView?.title
58
+ }
59
+
52
60
  override func visitableDidActivateWebView(_ webView: WKWebView) {
53
61
  bridgeDelegate.webViewDidBecomeActive(webView)
54
62
  }
@@ -14,9 +14,7 @@ final class SceneDelegate: UIResponder {
14
14
  // MARK: - Setup
15
15
 
16
16
  private func configureRootViewController() {
17
- guard let window = window else { fatalError() }
18
-
19
- navigationController = window.rootViewController as? TurboNavigationController
17
+ navigationController = window!.rootViewController as? TurboNavigationController
20
18
  navigationController.session = session
21
19
  navigationController.modalSession = modalSession
22
20
  }
@@ -68,6 +66,14 @@ extension SceneDelegate: SessionDelegate {
68
66
  navigationController.route(url: proposal.url, options: proposal.options, properties: proposal.properties)
69
67
  }
70
68
 
69
+ func session(_ session: Session, openExternalURL url: URL) {
70
+ if url.host == rootURL.host, !url.pathExtension.isEmpty {
71
+ navigationController.present(SFSafariViewController(url: url), animated: true)
72
+ } else {
73
+ UIApplication.shared.open(url)
74
+ }
75
+ }
76
+
71
77
  func session(_ session: Session, didFailRequestForVisitable visitable: Visitable, error: Error) {
72
78
  if let turboError = error as? TurboError, case let .http(statusCode) = turboError, statusCode == 401 {
73
79
  promptForAuthentication()
@@ -78,58 +84,22 @@ extension SceneDelegate: SessionDelegate {
78
84
  }
79
85
  }
80
86
 
81
- // When a form submission completes in the modal session, we need to
82
- // manually clear the snapshot cache in the default session, since we
83
- // don't want potentially stale cached snapshots to be used
84
87
  func sessionDidFinishFormSubmission(_ session: Session) {
85
88
  if (session == modalSession) {
86
89
  self.session.clearSnapshotCache()
87
90
  }
88
91
  }
89
92
 
90
- func sessionDidLoadWebView(_ session: Session) {
91
- session.webView.navigationDelegate = self
92
- }
93
-
94
93
  func sessionWebViewProcessDidTerminate(_ session: Session) {
95
94
  session.reload()
96
95
  }
97
96
  }
98
97
 
99
- extension SceneDelegate: WKNavigationDelegate {
100
- func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
101
- if navigationAction.navigationType == .linkActivated {
102
- // Any link that's not on the same domain as the Turbo root url will go through here
103
- // Other links on the domain, but that have an extension that is non-html will also go here
104
- // You can decide how to handle those, by default if you're not the navigationDelegate
105
- // the Session will open them in the default browser
106
-
107
- let url = navigationAction.request.url!
108
-
109
- // For this demo, we'll load files from our domain in a SafariViewController so you
110
- // don't need to leave the app. You might expand this in your app
111
- // to open all audio/video/images in a native media viewer
112
- if url.host == rootURL.host, !url.pathExtension.isEmpty {
113
- let safariViewController = SFSafariViewController(url: url)
114
- navigationController.present(safariViewController, animated: true)
115
- } else {
116
- UIApplication.shared.open(url)
117
- }
118
-
119
- decisionHandler(.cancel)
120
- } else {
121
- decisionHandler(.allow)
122
- }
123
- }
124
- }
125
-
126
98
  extension SceneDelegate: WKUIDelegate {
127
99
  func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
128
100
  let confirm = UIAlertController(title: nil, message: message, preferredStyle: .alert)
129
101
  confirm.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in completionHandler(false) })
130
102
  confirm.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(true) })
131
-
132
- // JavaScript alerts in Turbo Native
133
103
  navigationController.present(confirm, animated: true)
134
104
  }
135
105
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "settings": {},
3
3
  "rules": [
4
- { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh", "visitable": false } },
5
- { "patterns": ["/recede_historical_location"], "properties": { "presentation": "pop", "visitable": false } },
4
+ { "patterns": ["/recede_historical_location"], "properties": { "presentation": "back", "visitable": false } },
6
5
  { "patterns": ["/resume_historical_location"], "properties": { "presentation": "none", "visitable": false } },
6
+ { "patterns": ["/refresh_historical_location"], "properties": { "presentation": "refresh", "visitable": false } },
7
+ { "patterns": ["/new$", "/edit$", "/signin$", "/strada-form$"], "properties": { "presentation": "modal", "pull-to-refresh-enabled": false } },
7
8
  { "patterns": ["^/$"], "properties": { "presentation": "replace-all" } },
8
- { "patterns": ["/new$", "/edit$", "/signin$", "/strada-form$"], "properties": { "presentation": "modal" } },
9
9
  { "patterns": ["/numbers$"], "properties": { "view-controller": "numbers" } }
10
10
  ]
11
11
  }
@@ -22,9 +22,14 @@ class TurboNavigationController : UINavigationController {
22
22
  }
23
23
 
24
24
  // - Create view controller appropriate for url/properties
25
- // - Navigate to that with the correct presentation
26
25
  let viewController = makeViewController(for: url, properties: properties)
27
- navigate(to: viewController, action: options.action, properties: properties)
26
+
27
+ // - Navigate to that with the correct presentation
28
+ if session.topmostVisitable?.visitableURL == url {
29
+ navigate(to: viewController, action: .replace, properties: properties)
30
+ } else {
31
+ navigate(to: viewController, action: options.action, properties: properties)
32
+ }
28
33
 
29
34
  // Initiate the visit with Turbo
30
35
  if isVisitable(properties) {
@@ -43,8 +48,8 @@ extension TurboNavigationController {
43
48
  return properties["presentation"] as? String == "modal"
44
49
  }
45
50
 
46
- private func isPop(_ properties: PathProperties) -> Bool {
47
- return properties["presentation"] as? String == "pop"
51
+ private func isBack(_ properties: PathProperties) -> Bool {
52
+ return properties["presentation"] as? String == "back"
48
53
  }
49
54
 
50
55
  private func isRefresh(_ properties: PathProperties) -> Bool {
@@ -71,6 +76,14 @@ extension TurboNavigationController {
71
76
  return properties["visitable"] as? Bool ?? true
72
77
  }
73
78
 
79
+ private func isPullToRefreshEnabled(_ properties: PathProperties) -> Bool {
80
+ return properties["pull-to-refresh-enabled"] as? Bool ?? true
81
+ }
82
+
83
+ private func title(from properties: PathProperties) -> String? {
84
+ return properties["title"] as? String
85
+ }
86
+
74
87
  private func noticeMessage(from url: URL) -> String? {
75
88
  URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first(where: { $0.name == "notice" })?.value
76
89
  }
@@ -90,13 +103,16 @@ extension TurboNavigationController {
90
103
  }
91
104
  }
92
105
 
93
- return TurboWebViewController(url: url)
106
+ let viewController = TurboWebViewController(url: url)
107
+ viewController.pullToRefreshEnabled = isPullToRefreshEnabled(properties)
108
+ viewController.title = title(from: properties)
109
+ return viewController
94
110
  }
95
111
 
96
112
  private func navigate(to viewController: UIViewController, action: VisitAction, properties: PathProperties = [:]) {
97
113
  if isModal(properties) {
98
114
  present(UINavigationController(rootViewController: viewController), animated: true)
99
- } else if isPop(properties) {
115
+ } else if isBack(properties) {
100
116
  popViewController(animated: true)
101
117
  } else if isRefresh(properties) {
102
118
  session.reload()
@@ -5,6 +5,8 @@ import WebKit
5
5
 
6
6
  final class TurboWebViewController: VisitableViewController, ErrorPresenter, BridgeDestination {
7
7
 
8
+ var pullToRefreshEnabled = true
9
+
8
10
  private lazy var bridgeDelegate: BridgeDelegate = {
9
11
  BridgeDelegate(location: visitableURL.absoluteString, destination: self, componentTypes: BridgeComponent.allTypes)
10
12
  }()
@@ -20,6 +22,8 @@ final class TurboWebViewController: VisitableViewController, ErrorPresenter, Bri
20
22
 
21
23
  navigationItem.backButtonTitle = "Back"
22
24
 
25
+ visitableView.allowsPullToRefresh = pullToRefreshEnabled
26
+
23
27
  if presentingViewController != nil {
24
28
  navigationItem.leftBarButtonItem = dismissModalButton
25
29
  }
@@ -49,6 +53,10 @@ final class TurboWebViewController: VisitableViewController, ErrorPresenter, Bri
49
53
 
50
54
  // MARK: Visitable
51
55
 
56
+ override func visitableDidRender() {
57
+ title = title ?? visitableView.webView?.title
58
+ }
59
+
52
60
  override func visitableDidActivateWebView(_ webView: WKWebView) {
53
61
  bridgeDelegate.webViewDidBecomeActive(webView)
54
62
  }
@@ -14,14 +14,8 @@ final class SceneDelegate: UIResponder {
14
14
  private let rootURL2 = <%= name %>.homeURL2
15
15
 
16
16
  private var tabBarController: UITabBarController!
17
-
18
- private lazy var navigationController1 = {
19
- tabBarController.viewControllers![0] as! TurboNavigationController
20
- }()
21
-
22
- private lazy var navigationController2 = {
23
- tabBarController.viewControllers![1] as! TurboNavigationController
24
- }()
17
+ private var navigationController1: TurboNavigationController!
18
+ private var navigationController2: TurboNavigationController!
25
19
 
26
20
  private func navigationController() -> TurboNavigationController {
27
21
  tabBarController.selectedViewController as! TurboNavigationController
@@ -30,13 +24,13 @@ final class SceneDelegate: UIResponder {
30
24
  // MARK: - Setup
31
25
 
32
26
  private func configureRootViewController() {
33
- guard let window = window else { fatalError() }
34
-
35
- tabBarController = window.rootViewController as? UITabBarController
27
+ tabBarController = window!.rootViewController as? UITabBarController
36
28
 
29
+ navigationController1 = tabBarController.viewControllers![0] as? TurboNavigationController
37
30
  navigationController1.session = session1
38
31
  navigationController1.modalSession = modalSession
39
32
 
33
+ navigationController2 = tabBarController.viewControllers![1] as? TurboNavigationController
40
34
  navigationController2.session = session2
41
35
  navigationController2.modalSession = modalSession
42
36
  }
@@ -88,6 +82,14 @@ extension SceneDelegate: SessionDelegate {
88
82
  navigationController().route(url: proposal.url, options: proposal.options, properties: proposal.properties)
89
83
  }
90
84
 
85
+ func session(_ session: Session, openExternalURL url: URL) {
86
+ if url.host == baseURL.host, !url.pathExtension.isEmpty {
87
+ navigationController().present(SFSafariViewController(url: url), animated: true)
88
+ } else {
89
+ UIApplication.shared.open(url)
90
+ }
91
+ }
92
+
91
93
  func session(_ session: Session, didFailRequestForVisitable visitable: Visitable, error: Error) {
92
94
  if let errorPresenter = visitable as? ErrorPresenter {
93
95
  errorPresenter.presentError(error) { session.reload() }
@@ -96,58 +98,22 @@ extension SceneDelegate: SessionDelegate {
96
98
  }
97
99
  }
98
100
 
99
- // When a form submission completes in the modal session, we need to
100
- // manually clear the snapshot cache in the default session, since we
101
- // don't want potentially stale cached snapshots to be used
102
101
  func sessionDidFinishFormSubmission(_ session: Session) {
103
102
  if (session == modalSession) {
104
103
  self.session().clearSnapshotCache()
105
104
  }
106
105
  }
107
106
 
108
- func sessionDidLoadWebView(_ session: Session) {
109
- session.webView.navigationDelegate = self
110
- }
111
-
112
107
  func sessionWebViewProcessDidTerminate(_ session: Session) {
113
108
  session.reload()
114
109
  }
115
110
  }
116
111
 
117
- extension SceneDelegate: WKNavigationDelegate {
118
- func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
119
- if navigationAction.navigationType == .linkActivated {
120
- // Any link that's not on the same domain as the Turbo root url will go through here
121
- // Other links on the domain, but that have an extension that is non-html will also go here
122
- // You can decide how to handle those, by default if you're not the navigationDelegate
123
- // the Session will open them in the default browser
124
-
125
- let url = navigationAction.request.url!
126
-
127
- // For this demo, we'll load files from our domain in a SafariViewController so you
128
- // don't need to leave the app. You might expand this in your app
129
- // to open all audio/video/images in a native media viewer
130
- if url.host == baseURL.host, !url.pathExtension.isEmpty {
131
- let safariViewController = SFSafariViewController(url: url)
132
- navigationController().present(safariViewController, animated: true)
133
- } else {
134
- UIApplication.shared.open(url)
135
- }
136
-
137
- decisionHandler(.cancel)
138
- } else {
139
- decisionHandler(.allow)
140
- }
141
- }
142
- }
143
-
144
112
  extension SceneDelegate: WKUIDelegate {
145
113
  func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
146
114
  let confirm = UIAlertController(title: nil, message: message, preferredStyle: .alert)
147
115
  confirm.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in completionHandler(false) })
148
- confirm.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(true) })
149
-
150
- // JavaScript alerts in Turbo Native
116
+ confirm.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(true) })
151
117
  navigationController().present(confirm, animated: true)
152
118
  }
153
119
  }
@@ -1,3 +1,3 @@
1
1
  module TurboNativeInitializer
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.16"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo-native-initializer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nixon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-30 00:00:00.000000000 Z
11
+ date: 2023-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor