motion-turbo-ios 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +48 -0
- data/lib/motion-turbo-ios.rb +15 -0
- data/lib/turbo/logging.rb +25 -0
- data/lib/turbo/path_configuration/path_configuration.rb +55 -0
- data/lib/turbo/path_configuration/path_configuration_decoder.rb +25 -0
- data/lib/turbo/path_configuration/path_configuration_loader.rb +62 -0
- data/lib/turbo/path_configuration/path_rule.rb +34 -0
- data/lib/turbo/session/navigation_delegate_methods.rb +43 -0
- data/lib/turbo/session/session.rb +184 -0
- data/lib/turbo/session/session_delegate_methods.rb +30 -0
- data/lib/turbo/session/visit_delegate_methods.rb +67 -0
- data/lib/turbo/session/visitable_delegate_methods.rb +51 -0
- data/lib/turbo/session/web_view_delegate_methods.rb +46 -0
- data/lib/turbo/turbo_error.rb +30 -0
- data/lib/turbo/visit/cold_boot_visit.rb +109 -0
- data/lib/turbo/visit/javascript_visit.rb +107 -0
- data/lib/turbo/visit/visit.rb +91 -0
- data/lib/turbo/visit/visit_options.rb +36 -0
- data/lib/turbo/visit/visit_proposal.rb +13 -0
- data/lib/turbo/visit/visit_response.rb +29 -0
- data/lib/turbo/visitable/visitable.rb +58 -0
- data/lib/turbo/visitable/visitable_view.rb +20 -0
- data/lib/turbo/visitable/visitable_view_controller.rb +71 -0
- data/lib/turbo/visitable_view/activity_indicator.rb +36 -0
- data/lib/turbo/visitable_view/constraints.rb +14 -0
- data/lib/turbo/visitable_view/refresh_control.rb +61 -0
- data/lib/turbo/visitable_view/screenshots.rb +56 -0
- data/lib/turbo/visitable_view/scroll_view.rb +21 -0
- data/lib/turbo/visitable_view/web_view.rb +28 -0
- data/lib/turbo/web_view/script_message.rb +77 -0
- data/lib/turbo/web_view/script_message_handler.rb +16 -0
- data/lib/turbo/web_view/web_view_bridge.rb +154 -0
- metadata +90 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module Turbo
|
2
|
+
class VisitableView < UIView
|
3
|
+
module RefreshControl
|
4
|
+
def refreshControl
|
5
|
+
@refreshControl ||= begin
|
6
|
+
refreshControl = UIRefreshControl.alloc.init
|
7
|
+
refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEventValueChanged)
|
8
|
+
refreshControl
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def allowsPullToRefresh
|
13
|
+
return @allowsPullToRefresh if defined?(@allowsPullToRefresh)
|
14
|
+
@allowsPullToRefresh = true
|
15
|
+
end
|
16
|
+
|
17
|
+
def allowsPullToRefresh=(allowsPullToRefresh)
|
18
|
+
@allowsPullToRefresh = allowsPullToRefresh
|
19
|
+
if allowsPullToRefresh
|
20
|
+
installRefreshControl
|
21
|
+
else
|
22
|
+
removeRefreshControl
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def isRefreshing
|
27
|
+
refreshControl.refreshing?
|
28
|
+
end
|
29
|
+
|
30
|
+
def refresh(sender)
|
31
|
+
visitable.visitableViewDidRequestRefresh if visitable
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def installRefreshControl
|
37
|
+
scrollView = webView.scrollView if webView
|
38
|
+
return unless scrollView && allowsPullToRefresh
|
39
|
+
# TODO
|
40
|
+
#if !targetEnvironment(macCatalyst)
|
41
|
+
scrollView.addSubview(refreshControl)
|
42
|
+
|
43
|
+
# Infer refresh control's default height from its frame, if given.
|
44
|
+
# Otherwise fallback to 60 (the default height).
|
45
|
+
refreshControlHeight = CGRectGetHeight(refreshControl.frame) > 0 ? CGRectGetHeight(refreshControl.frame) : 60
|
46
|
+
NSLayoutConstraint.activateConstraints([
|
47
|
+
refreshControl.centerXAnchor.constraintEqualToAnchor(centerXAnchor),
|
48
|
+
refreshControl.topAnchor.constraintEqualToAnchor(safeAreaLayoutGuide.topAnchor),
|
49
|
+
refreshControl.heightAnchor.constraintEqualToConstant(refreshControlHeight)
|
50
|
+
])
|
51
|
+
#endif
|
52
|
+
end
|
53
|
+
|
54
|
+
def removeRefreshControl
|
55
|
+
refreshControl.endRefreshing
|
56
|
+
#refreshControl.removeFromSuperview
|
57
|
+
webView.scrollView.refreshControl = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Turbo
|
2
|
+
class VisitableView < UIView
|
3
|
+
module Screenshots
|
4
|
+
def screenshotContainerView
|
5
|
+
@screenshotContainerView ||= begin
|
6
|
+
view = UIView.alloc.initWithFrame(CGRectZero)
|
7
|
+
view.translatesAutoresizingMaskIntoConstraints = false
|
8
|
+
view.backgroundColor = backgroundColor
|
9
|
+
view
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :screenshotView
|
14
|
+
|
15
|
+
def isShowingScreenshot
|
16
|
+
screenshotContainerView.superview != nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def updateScreenshot
|
20
|
+
return unless webView
|
21
|
+
return if isShowingScreenshot
|
22
|
+
screenshot = webView.snapshotViewAfterScreenUpdates(false)
|
23
|
+
return unless screenshot
|
24
|
+
|
25
|
+
screenshotView.removeFromSuperview if screenshotView
|
26
|
+
screenshot.translatesAutoresizingMaskIntoConstraints = false
|
27
|
+
screenshotContainerView.addSubview(screenshot)
|
28
|
+
|
29
|
+
NSLayoutConstraint.activateConstraints([
|
30
|
+
screenshot.centerXAnchor.constraintEqualToAnchor(screenshotContainerView.centerXAnchor),
|
31
|
+
screenshot.topAnchor.constraintEqualToAnchor(screenshotContainerView.topAnchor),
|
32
|
+
screenshot.widthAnchor.constraintEqualToConstant(screenshot.bounds.size.width),
|
33
|
+
screenshot.heightAnchor.constraintEqualToConstant(screenshot.bounds.size.height)
|
34
|
+
])
|
35
|
+
@screenshotView = screenshot
|
36
|
+
end
|
37
|
+
|
38
|
+
def showScreenshot
|
39
|
+
if !isShowingScreenshot && !isRefreshing
|
40
|
+
addSubview(screenshotContainerView)
|
41
|
+
addFillConstraintsForSubview(screenshotContainerView)
|
42
|
+
showOrHideWebView
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def hideScreenshot
|
47
|
+
screenshotContainerView.removeFromSuperview
|
48
|
+
showOrHideWebView
|
49
|
+
end
|
50
|
+
|
51
|
+
def clearScreenshot
|
52
|
+
screenshotView.removeFromSuperview if screenshotView
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Turbo
|
2
|
+
class VisitableView < UIView
|
3
|
+
module ScrollView
|
4
|
+
private
|
5
|
+
|
6
|
+
def hiddenScrollView
|
7
|
+
@hiddenScrollView ||= begin
|
8
|
+
scrollView = UIScrollView.alloc.initWithFrame(CGRectZero)
|
9
|
+
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
10
|
+
scrollView.scrollsToTop = false
|
11
|
+
scrollView
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def installHiddenScrollView
|
16
|
+
insertSubview(hiddenScrollView, atIndex: 0)
|
17
|
+
addFillConstraintsForSubview(hiddenScrollView)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Turbo
|
2
|
+
class VisitableView < UIView
|
3
|
+
module WebView
|
4
|
+
attr_reader :webView, :visitable
|
5
|
+
|
6
|
+
def activateWebView(webView, forVisitable: visitable)
|
7
|
+
@webView = webView
|
8
|
+
@visitable = visitable
|
9
|
+
#addSubview(webView)
|
10
|
+
insertSubview(webView, atIndex: 0)
|
11
|
+
addFillConstraintsForSubview(webView)
|
12
|
+
installRefreshControl
|
13
|
+
showOrHideWebView
|
14
|
+
end
|
15
|
+
|
16
|
+
def deactivateWebView
|
17
|
+
removeRefreshControl
|
18
|
+
webView.removeFromSuperview if webView
|
19
|
+
@webView = nil
|
20
|
+
@visitable = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def showOrHideWebView
|
24
|
+
webView.hidden = isShowingScreenshot if webView
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Turbo
|
2
|
+
class ScriptMessage
|
3
|
+
NAMES = {
|
4
|
+
page_loaded: "pageLoaded",
|
5
|
+
page_load_failed: "pageLoadFailed",
|
6
|
+
error_raised: "errorRaised",
|
7
|
+
visit_proposed: "visitProposed",
|
8
|
+
visit_started: "visitStarted",
|
9
|
+
visit_request_started: "visitRequestStarted",
|
10
|
+
visit_request_completed: "visitRequestCompleted",
|
11
|
+
visit_request_failed: "visitRequestFailed",
|
12
|
+
visit_request_finished: "visitRequestFinished",
|
13
|
+
visit_rendered: "visitRendered",
|
14
|
+
visit_completed: "visitCompleted",
|
15
|
+
form_submission_started: "formSubmissionStarted",
|
16
|
+
form_submission_finished: "formSubmissionFinished",
|
17
|
+
page_invalidated: "pageInvalidated",
|
18
|
+
log: "log"
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.parse(message)
|
22
|
+
body = message.body
|
23
|
+
return unless body
|
24
|
+
|
25
|
+
rawName = body["name"]
|
26
|
+
return unless rawName
|
27
|
+
|
28
|
+
name = NAMES.key(rawName)
|
29
|
+
return unless name
|
30
|
+
|
31
|
+
data = body["data"]
|
32
|
+
return unless data
|
33
|
+
|
34
|
+
return new(name, data)
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :name, :data
|
38
|
+
|
39
|
+
def initialize(name, data)
|
40
|
+
@name = name
|
41
|
+
@data = data
|
42
|
+
end
|
43
|
+
|
44
|
+
def identifier
|
45
|
+
identifier = data["identifier"]
|
46
|
+
identifier if identifier.is_a?(String)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Milliseconds since unix epoch as provided by JavaScript Date.now()
|
50
|
+
def timestamp
|
51
|
+
#data["timestamp"] as? TimeInterval ?? 0
|
52
|
+
timestamp = data["timestamp"]
|
53
|
+
timestamp.to_i || 0
|
54
|
+
end
|
55
|
+
|
56
|
+
def date
|
57
|
+
NSDate.alloc.initWithTimeIntervalSince1970(timestamp / 1000.0)
|
58
|
+
end
|
59
|
+
|
60
|
+
def restorationIdentifier
|
61
|
+
restorationIdentifier = data["restorationIdentifier"]
|
62
|
+
restorationIdentifier if restorationIdentifier.is_a?(String)
|
63
|
+
end
|
64
|
+
|
65
|
+
def location
|
66
|
+
NSURL.alloc.initWithString(data["location"]) if data["location"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def options
|
70
|
+
if options = data["options"]
|
71
|
+
VisitOptions.alloc.initFromHash(options)
|
72
|
+
else
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Turbo
|
2
|
+
# This class prevents retain cycle caused by WKUserContentController
|
3
|
+
class ScriptMessageHandler
|
4
|
+
|
5
|
+
attr_accessor :delegate
|
6
|
+
|
7
|
+
def initWithDelegate(delegate)
|
8
|
+
self.delegate = delegate
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
def userContentController(userContentController, didReceiveScriptMessage: message)
|
13
|
+
delegate.scriptMessageHandlerDidReceiveMessage(message) if delegate
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Turbo
|
2
|
+
# The WebViewBridge is an internal class used for bi-directional communication
|
3
|
+
# with the web view/JavaScript
|
4
|
+
class WebViewBridge
|
5
|
+
attr_accessor :webView, :delegate, :pageLoadDelegate, :visitDelegate#, :navigationDelegate
|
6
|
+
def initWithWebView(webView)
|
7
|
+
@webView = webView
|
8
|
+
setup
|
9
|
+
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def setup
|
16
|
+
messageHandlerName = "turbo"
|
17
|
+
webView.configuration.userContentController.addUserScript(userScript)
|
18
|
+
scriptMessageHandler = ScriptMessageHandler.alloc.initWithDelegate(self)
|
19
|
+
webView.configuration.userContentController.addScriptMessageHandler(scriptMessageHandler, name: messageHandlerName)
|
20
|
+
end
|
21
|
+
|
22
|
+
def userScript
|
23
|
+
url = self.class.bundle.URLForResource("turbo", withExtension: "js")
|
24
|
+
source = NSString.stringWithContentsOfURL(url, encoding: NSUTF8StringEncoding, error: nil)
|
25
|
+
WKUserScript.alloc.initWithSource(source, injectionTime: WKUserScriptInjectionTimeAtDocumentEnd, forMainFrameOnly: true)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.bundle
|
29
|
+
@bundle ||= NSBundle.bundleForClass(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
public
|
33
|
+
|
34
|
+
def visitLocation(location, withOptions: options, restorationIdentifier: restorationIdentifier)
|
35
|
+
raise unless options.is_a? Turbo::VisitOptions
|
36
|
+
callJavaScriptFunction("window.turboNative.visitLocationWithOptionsAndRestorationIdentifier",
|
37
|
+
withArguments: [
|
38
|
+
location.absoluteString,
|
39
|
+
options.encode,
|
40
|
+
restorationIdentifier]
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def clearSnapshotCache
|
45
|
+
callJavaScriptFunction("window.turboNative.clearSnapshotCache", withArguments: [])
|
46
|
+
end
|
47
|
+
|
48
|
+
def cancelVisitWithIdentifier(identifier)
|
49
|
+
callJavaScriptFunction("window.turboNative.cancelVisitWithIdentifier", withArguments: [identifier])
|
50
|
+
end
|
51
|
+
|
52
|
+
# JavaScript Evaluation
|
53
|
+
|
54
|
+
def callJavaScriptFunction(functionExpression, withArguments: arguments)
|
55
|
+
callJavaScriptFunction(functionExpression, withArguments: arguments, completionHandler: nil)
|
56
|
+
end
|
57
|
+
|
58
|
+
def callJavaScriptFunction(functionExpression, withArguments: arguments, completionHandler: completionHandler)
|
59
|
+
script = scriptForCallingJavaScriptFunction(functionExpression, withArguments: arguments)
|
60
|
+
unless script
|
61
|
+
NSLog("Error encoding arguments for JavaScript function `%@'", functionExpression)
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
debugLog("[Bridge] → #{functionExpression} #{arguments}")
|
66
|
+
|
67
|
+
webView.evaluateJavaScript(script, completionHandler: -> (result, error) {
|
68
|
+
debugLog("[Bridge] = #{functionExpression} evaluation complete")
|
69
|
+
|
70
|
+
if result
|
71
|
+
if error = result["error"]
|
72
|
+
stack = result["stack"]
|
73
|
+
NSLog("Error evaluating JavaScript function `%@': %@\n%@", functionExpression, error, stack)
|
74
|
+
else
|
75
|
+
completionHandler.call(result["value"]) if completionHandler
|
76
|
+
end
|
77
|
+
elsif error
|
78
|
+
delegate.webView(self, didFailJavaScriptEvaluationWithError: error) if delegate
|
79
|
+
end
|
80
|
+
})
|
81
|
+
end
|
82
|
+
|
83
|
+
def scriptForCallingJavaScriptFunction(functionExpression, withArguments: arguments)
|
84
|
+
encodedArguments = encodeJavaScriptArguments(arguments)
|
85
|
+
return unless encodedArguments
|
86
|
+
|
87
|
+
script = "(function(result) {\n" +
|
88
|
+
" try {\n" +
|
89
|
+
" result.value = " + functionExpression + "(" + encodedArguments + ")\n" +
|
90
|
+
" } catch (error) {\n" +
|
91
|
+
" result.error = error.toString()\n" +
|
92
|
+
" result.stack = error.stack\n" +
|
93
|
+
" }\n" +
|
94
|
+
" return result\n" +
|
95
|
+
"})({})"
|
96
|
+
return script
|
97
|
+
end
|
98
|
+
|
99
|
+
def encodeJavaScriptArguments(arguments)
|
100
|
+
arguments = arguments.map {|v| v.nil? ? NSNull.alloc.init() : v }
|
101
|
+
|
102
|
+
data = NSJSONSerialization.dataWithJSONObject(arguments, options: 0, error: nil)
|
103
|
+
if data
|
104
|
+
dataString = NSString.alloc.initWithData(data, encoding: NSUTF8StringEncoding)
|
105
|
+
return dataString[1..-2]
|
106
|
+
end
|
107
|
+
return nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def scriptMessageHandlerDidReceiveMessage(message)
|
111
|
+
message = ScriptMessage.parse(message)
|
112
|
+
return unless message
|
113
|
+
|
114
|
+
if message.name.to_sym != :log
|
115
|
+
debugLog("[Bridge] ← #{message.name} #{message.data}")
|
116
|
+
end
|
117
|
+
|
118
|
+
case message.name.to_sym
|
119
|
+
when :page_loaded
|
120
|
+
pageLoadDelegate.webView(self, didLoadPageWithRestorationIdentifier: message.restorationIdentifier) if pageLoadDelegate
|
121
|
+
when :page_load_failed
|
122
|
+
delegate.webView(self, didFailInitialPageLoadWithError: TurboError.pageLoadFailure) if delegate
|
123
|
+
when :form_submission_started
|
124
|
+
delegate.webView(self, didStartFormSubmissionToLocation: message.location) if delegate
|
125
|
+
when :form_submission_finished
|
126
|
+
delegate.webView(self, didFinishFormSubmissionToLocation: message.location) if delegate
|
127
|
+
when :page_invalidated
|
128
|
+
delegate.webViewDidInvalidatePage(self) if delegate
|
129
|
+
when :visit_proposed
|
130
|
+
delegate.webView(self, didProposeVisitToLocation: message.location, withOptions: message.options) if delegate
|
131
|
+
when :visit_started
|
132
|
+
visitDelegate.webView(self, didStartVisitWithIdentifier: message.identifier, hasCachedSnapshot: message.data["hasCachedSnapshot"]) if visitDelegate
|
133
|
+
when :visit_request_started
|
134
|
+
visitDelegate.webView(self, didStartRequestForVisitWithIdentifier: message.identifier, date: message.date) if visitDelegate
|
135
|
+
when :visit_request_completed
|
136
|
+
visitDelegate.webView(self, didCompleteRequestForVisitWithIdentifier: message.identifier) if visitDelegate
|
137
|
+
when :visit_request_failed
|
138
|
+
visitDelegate.webView(self, didFailRequestForVisitWithIdentifier: message.identifier, statusCode: message.data["statusCode"]) if visitDelegate
|
139
|
+
when :visit_request_finished
|
140
|
+
visitDelegate.webView(self, didFinishRequestForVisitWithIdentifier: message.identifier, date: message.date) if visitDelegate
|
141
|
+
when :visit_rendered
|
142
|
+
visitDelegate.webView(self, didRenderForVisitWithIdentifier: message.identifier) if visitDelegate
|
143
|
+
when :visit_completed
|
144
|
+
visitDelegate.webView(self, didCompleteVisitWithIdentifier: message.identifier, restorationIdentifier: message.restorationIdentifier) if visitDelegate
|
145
|
+
when :error_raised
|
146
|
+
error = message.data["error"] || "<unknown error>"
|
147
|
+
debugLog("JavaScript error: #{error}")
|
148
|
+
when :log
|
149
|
+
msg = message.data["message"]
|
150
|
+
debugLog("[Bridge] ← log: #{msg}") if msg.is_a?(String)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motion-turbo-ios
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Havens
|
8
|
+
- Petrik de Heus
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2023-06-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
description: Turbo for RubyMotion apps
|
29
|
+
email:
|
30
|
+
- email@andrewhavens.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- README.md
|
36
|
+
- lib/motion-turbo-ios.rb
|
37
|
+
- lib/turbo/logging.rb
|
38
|
+
- lib/turbo/path_configuration/path_configuration.rb
|
39
|
+
- lib/turbo/path_configuration/path_configuration_decoder.rb
|
40
|
+
- lib/turbo/path_configuration/path_configuration_loader.rb
|
41
|
+
- lib/turbo/path_configuration/path_rule.rb
|
42
|
+
- lib/turbo/session/navigation_delegate_methods.rb
|
43
|
+
- lib/turbo/session/session.rb
|
44
|
+
- lib/turbo/session/session_delegate_methods.rb
|
45
|
+
- lib/turbo/session/visit_delegate_methods.rb
|
46
|
+
- lib/turbo/session/visitable_delegate_methods.rb
|
47
|
+
- lib/turbo/session/web_view_delegate_methods.rb
|
48
|
+
- lib/turbo/turbo_error.rb
|
49
|
+
- lib/turbo/visit/cold_boot_visit.rb
|
50
|
+
- lib/turbo/visit/javascript_visit.rb
|
51
|
+
- lib/turbo/visit/visit.rb
|
52
|
+
- lib/turbo/visit/visit_options.rb
|
53
|
+
- lib/turbo/visit/visit_proposal.rb
|
54
|
+
- lib/turbo/visit/visit_response.rb
|
55
|
+
- lib/turbo/visitable/visitable.rb
|
56
|
+
- lib/turbo/visitable/visitable_view.rb
|
57
|
+
- lib/turbo/visitable/visitable_view_controller.rb
|
58
|
+
- lib/turbo/visitable_view/activity_indicator.rb
|
59
|
+
- lib/turbo/visitable_view/constraints.rb
|
60
|
+
- lib/turbo/visitable_view/refresh_control.rb
|
61
|
+
- lib/turbo/visitable_view/screenshots.rb
|
62
|
+
- lib/turbo/visitable_view/scroll_view.rb
|
63
|
+
- lib/turbo/visitable_view/web_view.rb
|
64
|
+
- lib/turbo/web_view/script_message.rb
|
65
|
+
- lib/turbo/web_view/script_message_handler.rb
|
66
|
+
- lib/turbo/web_view/web_view_bridge.rb
|
67
|
+
homepage: https://github.com/p8/motion-turbo-ios
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.1.6
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Turbo for RubyMotion apps
|
90
|
+
test_files: []
|