motion-hybrid 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -21
- data/Rakefile +9 -0
- data/lib/motion-hybrid.rb +1 -1
- data/lib/motion-hybrid/concerns/basic_routes.rb +0 -6
- data/lib/motion-hybrid/concerns/bridgeable.rb +71 -67
- data/lib/motion-hybrid/concerns/navigatable.rb +52 -43
- data/lib/motion-hybrid/concerns/presentable.rb +6 -6
- data/lib/motion-hybrid/concerns/releasable.rb +10 -5
- data/lib/motion-hybrid/concerns/updatable.rb +24 -23
- data/lib/motion-hybrid/models/bridge.rb +12 -12
- data/lib/motion-hybrid/models/request.rb +4 -0
- data/lib/motion-hybrid/models/router.rb +8 -4
- data/lib/motion-hybrid/version.rb +1 -1
- data/lib/motion-hybrid/views/toast.rb +68 -19
- data/lib/resources/jquery.motion-hybrid.coffee +10 -7
- data/lib/resources/jquery.motion-hybrid.js +16 -11
- data/resources/web/index_2.html +4 -0
- data/spec/{basic_routes_spec.rb → functional/basic_routes_spec.rb} +0 -0
- data/spec/unit/navigatable_spec.rb +30 -0
- data/vendor/Podfile.lock +11 -7
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce0fa09ca4db9ca8ede81070958c19283aa176e4
|
4
|
+
data.tar.gz: 3e7355cc44d889739486a886afb825c9e9012ad3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7d1d0c32961c63d908145a849a69a51dcec120ff4933c227a83cf879fdf2a803614562a81f931988b60e8eacf95c4f189fec5c3963827abfbe771375d6a88ed
|
7
|
+
data.tar.gz: 6e0b1e0dd7f1108c25966fd1256687e00c69399f88971625348c3e2cc9ba1cddd9481fba99206a5c512c5a79c3e9d0d10cbbc242b18f6d9f907818060961312c
|
data/README.md
CHANGED
@@ -35,7 +35,7 @@ Instantiate a screen and set the initial path:
|
|
35
35
|
# app/app_delegate.rb
|
36
36
|
class AppDelegate < PM::Delegate
|
37
37
|
def on_load(app, options)
|
38
|
-
open BaseScreen.new(nav_bar: true, path: '/balvig'
|
38
|
+
open BaseScreen.new(nav_bar: true, path: '/balvig')
|
39
39
|
end
|
40
40
|
end
|
41
41
|
```
|
@@ -75,7 +75,25 @@ Links with anchor `#self` will open the new url within the current view without
|
|
75
75
|
|
76
76
|
### Non-GET requests
|
77
77
|
|
78
|
-
Any non-GET requests (form posts etc) will display the result within the current view and also automatically refresh all
|
78
|
+
Any non-GET requests (form posts etc) will display the result within the current view and also automatically refresh all parent views so that pages are up to date.
|
79
|
+
|
80
|
+
## Custom routes
|
81
|
+
|
82
|
+
Sometimes you will want to trigger native iOS functionality from the web views, this is done by intercepting URLs that you can handle using the routing api, so you can do things like:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class BaseScreen < MotionHybrid::Screen
|
86
|
+
# pops up in-app email composer when clicking mailto: links
|
87
|
+
route /^mailto:/ do
|
88
|
+
BW::Mail.compose(to: 'bob@example.com', subject: 'In app emailing', message: 'Hi!', animated: true)
|
89
|
+
end
|
90
|
+
|
91
|
+
# ask for push nofitication permisions when user hits '/setup' url
|
92
|
+
route '/setup' do
|
93
|
+
App.delegate.register_for_push_notifications :badge, :sound, :alert
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
79
97
|
|
80
98
|
## The Bridge
|
81
99
|
|
@@ -106,22 +124,3 @@ All markup is contained within a div with id `motion-hybrid-bridge`
|
|
106
124
|
### Navbar items
|
107
125
|
|
108
126
|
TBA
|
109
|
-
|
110
|
-
## Custom routes
|
111
|
-
|
112
|
-
Sometimes you will want to trigger native iOS functionality from the web views, this is done by intercepting URLs that you can handle using the routing api, so you can do things like:
|
113
|
-
|
114
|
-
```ruby
|
115
|
-
class BaseScreen < MotionHybrid::Screen
|
116
|
-
# pops up in-app email composer when clicking mailto: links
|
117
|
-
route /^mailto:/ do
|
118
|
-
BW::Mail.compose(to: 'bob@example.com', subject: 'In app emailing', message: 'Hi!', animated: true)
|
119
|
-
end
|
120
|
-
|
121
|
-
# ask for push nofitication permisions when user hits '/setup' url
|
122
|
-
route '/setup' do
|
123
|
-
App.delegate.register_for_push_notifications :badge, :sound, :alert
|
124
|
-
end
|
125
|
-
end
|
126
|
-
```
|
127
|
-
|
data/Rakefile
CHANGED
@@ -9,3 +9,12 @@ Motion::Project::App.setup do |app|
|
|
9
9
|
app.name = 'motion-hybrid test'
|
10
10
|
app.version = '1.0'
|
11
11
|
end
|
12
|
+
|
13
|
+
namespace :spec do
|
14
|
+
task :unit do
|
15
|
+
App.config.spec_mode = true
|
16
|
+
spec_files = App.config.spec_files - Dir.glob('./spec/functional/**/*.rb')
|
17
|
+
App.config.instance_variable_set("@spec_files", spec_files)
|
18
|
+
Rake::Task["simulator"].invoke
|
19
|
+
end
|
20
|
+
end
|
data/lib/motion-hybrid.rb
CHANGED
@@ -11,7 +11,7 @@ Motion::Require.all(Dir.glob(File.expand_path('../motion-hybrid/**/*.rb', __FILE
|
|
11
11
|
Motion::Project::App.setup do |app|
|
12
12
|
app.resources_dirs << File.join(File.dirname(__FILE__), 'resources')
|
13
13
|
app.pods do
|
14
|
-
pod 'CRToast', '
|
14
|
+
pod 'CRToast', git: 'git@github.com:cruffenach/CRToast.git'
|
15
15
|
pod 'FontAwesomeKit'
|
16
16
|
pod 'MBProgressHUD'
|
17
17
|
pod 'SpinKit'
|
@@ -4,12 +4,6 @@ module MotionHybrid
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
|
7
|
-
# Trigger dom-loaded events
|
8
|
-
route 'motionhybrid://ready' do
|
9
|
-
dom_loaded
|
10
|
-
true
|
11
|
-
end
|
12
|
-
|
13
7
|
# All clicked GET-links are pushed
|
14
8
|
route /.*/ do |request|
|
15
9
|
push(request.url) if request.http_method == 'GET' && request.type == UIWebViewNavigationTypeLinkClicked
|
@@ -3,95 +3,99 @@ module MotionHybrid
|
|
3
3
|
|
4
4
|
def on_appear
|
5
5
|
super
|
6
|
-
|
7
|
-
|
8
|
-
else
|
9
|
-
@transition_finished = true
|
10
|
-
end
|
6
|
+
@appeared = true
|
7
|
+
set_titles if dom_loaded?
|
11
8
|
refresher.endRefreshing if refresher #avoids stuck animation
|
12
9
|
end
|
13
10
|
|
14
11
|
private
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
def load_bridge
|
14
|
+
self.bridge = Bridge.new(self)
|
15
|
+
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def dom_loaded
|
18
|
+
PM.logger.debug "#{self} dom_loaded"
|
19
|
+
set_titles if appeared?
|
20
|
+
set_buttons
|
21
|
+
set_refresher
|
22
|
+
render_flash
|
23
|
+
@dom_loaded = true
|
24
|
+
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
set_refresher
|
28
|
-
render_flash
|
29
|
-
end
|
26
|
+
def dom_loaded?
|
27
|
+
!!@dom_loaded
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def appeared?
|
31
|
+
!!@appeared
|
32
|
+
end
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
def set_titles
|
35
|
+
if bridge.subtitle.present?
|
36
|
+
self.navigationItem.titleView = MultiLineHeader.new(bridge.title, bridge.subtitle)
|
37
|
+
else
|
38
|
+
self.title = bridge.title
|
39
|
+
self.navigationItem.titleView = nil
|
40
|
+
end
|
40
41
|
end
|
41
|
-
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
def set_buttons
|
44
|
+
if bridge.nav_bar_buttons
|
45
|
+
set_button :left, bridge.nav_bar_buttons.left
|
46
|
+
set_button :right, bridge.nav_bar_buttons.right
|
47
|
+
else
|
48
|
+
PM.logger.debug 'No buttons found'
|
49
|
+
end
|
50
|
+
end
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
def set_button(side, button)
|
53
|
+
return unless button
|
54
|
+
return if button.if && !send(button.if)
|
55
|
+
label = button.icon ? Icon.new(button.icon, 20) : button.label
|
56
|
+
send "set_nav_bar_#{side}_button", label, action: "on_nav_bar_#{side}_button_click"
|
57
|
+
end
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
def on_nav_bar_button_click(side)
|
60
|
+
button = bridge.nav_bar_buttons.send(side)
|
61
|
+
if button.options.any?
|
62
|
+
UIActionSheet.alert nil, buttons: button.options do |pressed, index|
|
63
|
+
index = remap_index(index, button.options)
|
64
|
+
bridge.click_child(button.id, index)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
bridge.click(button.id)
|
60
68
|
end
|
61
|
-
else
|
62
|
-
bridge.click(button.id)
|
63
69
|
end
|
64
|
-
end
|
65
70
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
# iOS button order and actual order of buttons on screen are not the same
|
72
|
+
def remap_index(index, options)
|
73
|
+
if index == options.length - 1
|
74
|
+
0
|
75
|
+
else
|
76
|
+
index + 1
|
77
|
+
end
|
72
78
|
end
|
73
|
-
end
|
74
|
-
|
75
79
|
|
76
|
-
|
77
|
-
|
78
|
-
|
80
|
+
def on_nav_bar_left_button_click
|
81
|
+
on_nav_bar_button_click(:left)
|
82
|
+
end
|
79
83
|
|
80
|
-
|
81
|
-
|
82
|
-
|
84
|
+
def on_nav_bar_right_button_click
|
85
|
+
on_nav_bar_button_click(:right)
|
86
|
+
end
|
83
87
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
88
|
+
def set_refresher
|
89
|
+
if bridge.refreshable && !refresher
|
90
|
+
self.refresher = UIRefreshControl.alloc.init
|
91
|
+
refresher.addTarget(self, action: 'reload', forControlEvents: UIControlEventValueChanged)
|
92
|
+
webview.scrollView.addSubview(refresher)
|
93
|
+
end
|
89
94
|
end
|
90
|
-
end
|
91
95
|
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
def render_flash
|
97
|
+
Flash.new(bridge.flash.title, subtitle: bridge.flash.subtitle).show if bridge.flash
|
98
|
+
end
|
95
99
|
|
96
100
|
end
|
97
101
|
end
|
@@ -34,14 +34,15 @@ module MotionHybrid
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def load_started
|
37
|
+
@dom_loaded = false
|
37
38
|
start_transitions
|
38
39
|
end
|
39
40
|
|
40
41
|
def load_finished
|
41
42
|
@url = current_url
|
42
|
-
load_bridge
|
43
|
-
reload_dependents if needs_reload?
|
44
43
|
stop_transitions
|
44
|
+
load_bridge unless external_page?
|
45
|
+
reload_dependents if needs_reload?
|
45
46
|
end
|
46
47
|
|
47
48
|
def load_failed(error)
|
@@ -53,12 +54,13 @@ module MotionHybrid
|
|
53
54
|
end
|
54
55
|
|
55
56
|
def reset!
|
57
|
+
dismissModalViewControllerAnimated(false)
|
56
58
|
return_to_root
|
57
59
|
load_initial_url
|
58
60
|
end
|
59
61
|
|
60
62
|
def return_to_root
|
61
|
-
|
63
|
+
close to_screen: :root, animated: false if nav_bar?
|
62
64
|
end
|
63
65
|
|
64
66
|
def on_request(nsurlrequest, type)
|
@@ -66,6 +68,7 @@ module MotionHybrid
|
|
66
68
|
end
|
67
69
|
|
68
70
|
def navigate(new_path)
|
71
|
+
new_path = self.class.path_for(new_path)
|
69
72
|
return if path == new_path
|
70
73
|
process_request Request.new(self.class.request_for(new_path), UIWebViewNavigationTypeLinkClicked)
|
71
74
|
end
|
@@ -79,57 +82,63 @@ module MotionHybrid
|
|
79
82
|
|
80
83
|
private
|
81
84
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
if router.process(request)
|
86
|
-
false
|
87
|
-
else
|
88
|
-
PM.logger.info("#{self} #{request.http_method} #{request.url}")
|
89
|
-
true
|
85
|
+
def external_page?
|
86
|
+
!url.include?(self.class.root_url)
|
90
87
|
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def push(url, options = {})
|
94
|
-
view_options = options.slice!(:hide_tab_bar)
|
95
|
-
options[:modal] = view_options[:modal]
|
96
|
-
view_options.reverse_merge!(url: url, modal: modal?, transition_style: transition_style)
|
97
|
-
new_view = self.class.new(view_options)
|
98
|
-
open(new_view, options)
|
99
|
-
new_view
|
100
|
-
end
|
101
88
|
|
102
|
-
|
103
|
-
|
104
|
-
|
89
|
+
def process_request(request)
|
90
|
+
return dom_loaded && false if request.url == 'motionhybrid://ready'
|
91
|
+
@needs_reload = true if request.http_method != 'GET'
|
105
92
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
93
|
+
if router.process(request)
|
94
|
+
PM.logger.info("#{self} #{request} <intercept>")
|
95
|
+
false
|
96
|
+
else
|
97
|
+
PM.logger.info("#{self} #{request} <load>")
|
98
|
+
true
|
99
|
+
end
|
100
|
+
end
|
113
101
|
|
114
|
-
|
115
|
-
|
116
|
-
|
102
|
+
def push(url, options = {})
|
103
|
+
screen = options.delete(:screen) || self.class
|
104
|
+
view_options = options.slice!(:hide_tab_bar)
|
105
|
+
options[:modal] = view_options[:modal]
|
106
|
+
view_options.reverse_merge!(url: url, modal: modal?)
|
107
|
+
new_view = screen.new(view_options)
|
108
|
+
open(new_view, options)
|
109
|
+
new_view
|
117
110
|
end
|
118
111
|
|
119
|
-
def
|
120
|
-
|
112
|
+
def load_initial_url
|
113
|
+
self.path = self.class.path_for(@initial_url)
|
121
114
|
end
|
122
115
|
|
123
|
-
def
|
124
|
-
|
125
|
-
NSURL.URLWithString(url).path
|
116
|
+
def router
|
117
|
+
@router ||= Router.new(self)
|
126
118
|
end
|
127
119
|
|
128
|
-
|
129
|
-
|
130
|
-
|
120
|
+
module ClassMethods
|
121
|
+
def url_for(path)
|
122
|
+
"#{root_url}#{path}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def request_for(path)
|
126
|
+
NSURLRequest.requestWithURL NSURL.URLWithString(url_for(path))
|
127
|
+
end
|
128
|
+
|
129
|
+
def path_for(url)
|
130
|
+
return if url.blank?
|
131
|
+
nsurl = NSURL.URLWithString(url)
|
132
|
+
url = url.sub("#{nsurl.scheme}://#{nsurl.host}", '')
|
133
|
+
url = url.sub(":#{nsurl.port}", '') if nsurl.port
|
134
|
+
url
|
135
|
+
end
|
136
|
+
|
137
|
+
def route(*patterns, &block)
|
138
|
+
patterns.each do |pattern|
|
139
|
+
self.routes = [Route.new(pattern, &block)] + routes
|
140
|
+
end
|
131
141
|
end
|
132
142
|
end
|
133
|
-
end
|
134
143
|
end
|
135
144
|
end
|
@@ -7,13 +7,13 @@ module MotionHybrid
|
|
7
7
|
|
8
8
|
private
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
def presenter_url
|
11
|
+
presenter.url.sub(/\?.+/, '').sub(/#.+/, '')
|
12
|
+
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def presenter
|
15
|
+
navigationController.viewControllers.first.parent_screen if navigationController
|
16
|
+
end
|
17
17
|
|
18
18
|
end
|
19
19
|
end
|
@@ -1,16 +1,21 @@
|
|
1
1
|
module MotionHybrid
|
2
2
|
module Releasable
|
3
3
|
|
4
|
-
def
|
5
|
-
@should_release =
|
4
|
+
def will_disappear
|
5
|
+
@should_release = nav_bar? && !navigationController.viewControllers.include?(self)
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
if @should_release
|
8
|
+
def on_disappear
|
9
|
+
release_from_memory if @should_release
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def release_from_memory
|
15
|
+
PM.logger.debug "Releasing #{self}"
|
10
16
|
webview.removeFromSuperview
|
11
17
|
webview.release
|
12
18
|
end
|
13
|
-
end
|
14
19
|
|
15
20
|
end
|
16
21
|
end
|
@@ -1,38 +1,39 @@
|
|
1
1
|
module MotionHybrid
|
2
2
|
module Updatable
|
3
3
|
|
4
|
-
|
4
|
+
def reload!
|
5
|
+
stop
|
6
|
+
stop_transitions
|
7
|
+
reload
|
8
|
+
end
|
5
9
|
|
6
10
|
def reload_dependents
|
7
11
|
@needs_reload = false
|
8
|
-
dependents.map(&:
|
9
|
-
dependents.map(&:reload)
|
12
|
+
dependents.map(&:reload!)
|
10
13
|
end
|
11
14
|
|
12
|
-
|
13
|
-
def dependents
|
14
|
-
#dependents = all_views - [self]
|
15
|
-
#dependents = dependents | parent_screens
|
16
|
-
#dependents
|
17
|
-
parent_screens
|
18
|
-
end
|
15
|
+
private
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def dependents
|
18
|
+
parent_screens
|
19
|
+
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
def all_views
|
22
|
+
app_delegate.window.rootViewController.viewControllers.map(&:viewControllers).flatten
|
23
|
+
end
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
25
|
+
def needs_reload?
|
26
|
+
@needs_reload
|
27
|
+
end
|
28
|
+
|
29
|
+
def parent_screens
|
30
|
+
parent_screens = []
|
31
|
+
screen = self
|
32
|
+
while screen = screen.parent_screen
|
33
|
+
parent_screens << screen
|
34
|
+
end
|
35
|
+
parent_screens
|
33
36
|
end
|
34
|
-
parent_screens
|
35
|
-
end
|
36
37
|
|
37
38
|
end
|
38
39
|
end
|
@@ -18,21 +18,21 @@ module MotionHybrid
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def bridge_hash
|
22
|
+
@bridge_hash ||= Dish BW::JSON.parse(bridge_json)
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def bridge_json
|
26
|
+
js_api('getParams()').presence || '{}'
|
27
|
+
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
def method_missing(method)
|
30
|
+
bridge_hash.send(method)
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
def js_api(command)
|
34
|
+
@screen.evaluate("MotionHybrid.#{command};").to_s
|
35
|
+
end
|
36
36
|
|
37
37
|
end
|
38
38
|
end
|
@@ -7,15 +7,19 @@ module MotionHybrid
|
|
7
7
|
|
8
8
|
def process(request)
|
9
9
|
routes.find do |route|
|
10
|
-
route.matches?(request) && @screen.instance_exec(request, &route.block)
|
10
|
+
route.matches?(request) && @screen.instance_exec(request, external?(request), &route.block)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def external?(request)
|
17
|
+
!request.url.include?(@screen.root_url)
|
18
|
+
end
|
19
|
+
|
20
|
+
def routes
|
21
|
+
@screen.class.routes
|
22
|
+
end
|
19
23
|
|
20
24
|
end
|
21
25
|
end
|
@@ -1,24 +1,73 @@
|
|
1
1
|
module MotionHybrid
|
2
|
+
CRToastManager.setDefaultOptions(
|
3
|
+
KCRToastAnimationOutDirectionKey => CRToastAnimationDirectionTop,
|
4
|
+
KCRToastTextAlignmentKey => NSTextAlignmentLeft,
|
5
|
+
KCRToastSubtitleTextAlignmentKey => NSTextAlignmentLeft,
|
6
|
+
KCRToastNotificationTypeKey => CRToastTypeNavigationBar,
|
7
|
+
KCRToastSubtitleFontKey => UIFont.systemFontOfSize(14)
|
8
|
+
)
|
9
|
+
|
2
10
|
class Toast
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(title,
|
6
|
-
options =
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
attr_reader :title, :options, :responders
|
12
|
+
|
13
|
+
def initialize(title, options = {})
|
14
|
+
@title, @options = title, options
|
15
|
+
@responders = [CRToastInteractionResponder.interactionResponderWithInteractionType(CRToastInteractionTypeSwipeUp, automaticallyDismiss: true, block: nil)]
|
16
|
+
end
|
17
|
+
|
18
|
+
def show(&block)
|
19
|
+
responders << CRToastInteractionResponder.interactionResponderWithInteractionType(CRToastInteractionTypeTapOnce, automaticallyDismiss: true, block: -> (i) { block.call }) if block_given?
|
20
|
+
CRToastManager.showNotificationWithOptions(kcr_options, completionBlock: nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
def text_color
|
24
|
+
'#333'.to_color
|
25
|
+
end
|
26
|
+
|
27
|
+
def background_color
|
28
|
+
'#ffffff'.to_color
|
29
|
+
end
|
30
|
+
|
31
|
+
def image
|
32
|
+
if options[:image_url]
|
33
|
+
image_data = NSData.dataWithContentsOfURL(NSURL.URLWithString(options[:image_url]))
|
34
|
+
retinafy UIImage.imageWithData(image_data)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def retinafy(image)
|
41
|
+
UIImage.imageWithCGImage(image.CGImage, scale: 2, orientation: image.imageOrientation)
|
42
|
+
end
|
43
|
+
|
44
|
+
def kcr_options
|
45
|
+
{
|
46
|
+
KCRToastTextKey => title,
|
47
|
+
KCRToastSubtitleTextKey => options[:subtitle].presence,
|
48
|
+
KCRToastTextColorKey => text_color,
|
49
|
+
KCRToastBackgroundColorKey => background_color,
|
50
|
+
KCRToastSubtitleTextColorKey => text_color,
|
51
|
+
KCRToastImageKey => image,
|
52
|
+
KCRToastFontKey => options[:subtitle].present? ? UIFont.boldSystemFontOfSize(13) : UIFont.systemFontOfSize(18),
|
53
|
+
KCRToastTimeIntervalKey => options[:subtitle].present? ? 5 : nil,
|
54
|
+
KCRToastInteractionRespondersKey => responders
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Flash < Toast
|
60
|
+
def text_color
|
61
|
+
'#3c763d'.to_color
|
62
|
+
end
|
63
|
+
|
64
|
+
def background_color
|
65
|
+
'#dff0d8'.to_color
|
66
|
+
end
|
67
|
+
|
68
|
+
def image
|
69
|
+
Icon.new(:check, 20, color: text_color)
|
22
70
|
end
|
23
71
|
end
|
72
|
+
|
24
73
|
end
|
@@ -17,14 +17,17 @@ class window.MotionHybrid
|
|
17
17
|
{ title: flash.find('h3').text() || flash.text().trim(), subtitle: flash.find('p').text() } if flash.length
|
18
18
|
|
19
19
|
parseButton = (button) ->
|
20
|
-
{ id: button.attr('id'), options: button.children().map(-> this.innerText).get(), icon: button.data('icon') } if button.length
|
20
|
+
{ id: button.attr('id'), options: button.children().map(-> this.innerText).get(), icon: button.data('icon'), if: button.data('if'), label: button.text().trim() } if button.length
|
21
21
|
|
22
22
|
@clicked: (target, childIndex) ->
|
23
23
|
target = $("##{target}")
|
24
|
-
target = target.children() if childIndex
|
25
|
-
target.
|
24
|
+
target = target.children().eq(childIndex) if childIndex
|
25
|
+
window.location = target.attr('href') # want to simulate real click but target.get(0).click() sometimes needs to be fired twice to work..?
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
@waitForJqueryAndDom: ->
|
28
|
+
if window.$
|
29
|
+
jQuery -> document.location.href = 'motionhybrid://ready'
|
30
|
+
else
|
31
|
+
setTimeout MotionHybrid.waitForJqueryAndDom, 100
|
32
|
+
|
33
|
+
MotionHybrid.waitForJqueryAndDom()
|
@@ -32,11 +32,12 @@
|
|
32
32
|
if (button.length) {
|
33
33
|
return {
|
34
34
|
id: button.attr('id'),
|
35
|
-
link: button.attr('href'),
|
36
35
|
options: button.children().map(function() {
|
37
36
|
return this.innerText;
|
38
37
|
}).get(),
|
39
|
-
icon: button.data('icon')
|
38
|
+
icon: button.data('icon'),
|
39
|
+
"if": button.data('if'),
|
40
|
+
label: button.text().trim()
|
40
41
|
};
|
41
42
|
}
|
42
43
|
};
|
@@ -44,21 +45,25 @@
|
|
44
45
|
MotionHybrid.clicked = function(target, childIndex) {
|
45
46
|
target = $("#" + target);
|
46
47
|
if (childIndex) {
|
47
|
-
target = target.children();
|
48
|
+
target = target.children().eq(childIndex);
|
49
|
+
}
|
50
|
+
return window.location = target.attr('href');
|
51
|
+
};
|
52
|
+
|
53
|
+
MotionHybrid.waitForJqueryAndDom = function() {
|
54
|
+
if (window.$) {
|
55
|
+
return jQuery(function() {
|
56
|
+
return document.location.href = 'motionhybrid://ready';
|
57
|
+
});
|
58
|
+
} else {
|
59
|
+
return setTimeout(MotionHybrid.waitForJqueryAndDom, 100);
|
48
60
|
}
|
49
|
-
return target.get(childIndex || 0).click();
|
50
61
|
};
|
51
62
|
|
52
63
|
return MotionHybrid;
|
53
64
|
|
54
65
|
})();
|
55
66
|
|
56
|
-
|
57
|
-
document.location.href = 'motionhybrid://ready';
|
58
|
-
} else {
|
59
|
-
jQuery(function() {
|
60
|
-
return document.location.href = 'motionhybrid://ready';
|
61
|
-
});
|
62
|
-
}
|
67
|
+
MotionHybrid.waitForJqueryAndDom();
|
63
68
|
|
64
69
|
}).call(this);
|
data/resources/web/index_2.html
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
<body>
|
14
14
|
<div id="motion_hybrid_bridge">
|
15
15
|
<h1>Page 2</h1>
|
16
|
+
<h2>Yes it is</h2>
|
16
17
|
<div id="nav_bar_right_button" data-icon='trash-o'>
|
17
18
|
<a href="#">Cancel</a>
|
18
19
|
<a href="#">Delete</a>
|
@@ -22,6 +23,9 @@
|
|
22
23
|
|
23
24
|
<div class="content-padded">
|
24
25
|
This is page 2
|
26
|
+
<form action="index.html" method="post" accept-charset="utf-8">
|
27
|
+
<input type="submit" name="Post" />
|
28
|
+
</form>
|
25
29
|
</div>
|
26
30
|
</body>
|
27
31
|
</html>
|
File without changes
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module MotionHybrid
|
2
|
+
describe Navigatable do
|
3
|
+
describe '.path_for' do
|
4
|
+
it "should parse path correctly for localhost" do
|
5
|
+
MotionHybrid::Screen.path_for('http://localhost:3000/chats').should == '/chats'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.route' do
|
10
|
+
class MyScreen < Screen
|
11
|
+
attr_accessor :external
|
12
|
+
route /.*/ do |request, external|
|
13
|
+
self.external = external
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "determines whether request is external or not" do
|
18
|
+
MyScreen.root_url = 'http://mysite.com'
|
19
|
+
screen = MyScreen.new
|
20
|
+
internal_request = NSURLRequest.requestWithURL NSURL.URLWithString('http://mysite.com/users/')
|
21
|
+
external_request = NSURLRequest.requestWithURL NSURL.URLWithString('http://theirsite.com/users/')
|
22
|
+
|
23
|
+
screen.on_request(internal_request, UIWebViewNavigationTypeLinkClicked)
|
24
|
+
screen.external.should == false
|
25
|
+
screen.on_request(external_request, UIWebViewNavigationTypeLinkClicked)
|
26
|
+
screen.external.should == true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/vendor/Podfile.lock
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
PODS:
|
2
|
-
- CRToast (0.0.
|
2
|
+
- CRToast (0.0.7)
|
3
3
|
- FontAwesomeKit (2.1.5):
|
4
4
|
- FontAwesomeKit/Core
|
5
5
|
- FontAwesomeKit/FontAwesome
|
@@ -19,15 +19,19 @@ PODS:
|
|
19
19
|
- SpinKit (1.0.1)
|
20
20
|
|
21
21
|
DEPENDENCIES:
|
22
|
-
- CRToast (
|
22
|
+
- CRToast (from `git@github.com:cruffenach/CRToast.git`)
|
23
23
|
- FontAwesomeKit
|
24
24
|
- MBProgressHUD
|
25
25
|
- SpinKit
|
26
26
|
|
27
|
+
EXTERNAL SOURCES:
|
28
|
+
CRToast:
|
29
|
+
:git: git@github.com:cruffenach/CRToast.git
|
30
|
+
|
27
31
|
SPEC CHECKSUMS:
|
28
|
-
CRToast:
|
29
|
-
FontAwesomeKit:
|
30
|
-
MBProgressHUD:
|
31
|
-
SpinKit:
|
32
|
+
CRToast: da11d94a05b1351a87bb26cbf8f25e80ed2e7115
|
33
|
+
FontAwesomeKit: 2e37bec52edbb8f8044a487734ba63eb320a2665
|
34
|
+
MBProgressHUD: c356980b0cd097f19acec959b49dca5eb8ec31be
|
35
|
+
SpinKit: 563a00196a87d789b16e3592265f0dfa9c3fb9db
|
32
36
|
|
33
|
-
COCOAPODS: 0.
|
37
|
+
COCOAPODS: 0.33.1
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion-hybrid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Balvig
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bubble-wrap
|
@@ -212,7 +212,8 @@ files:
|
|
212
212
|
- resources/web/ratchet-theme-ios.css
|
213
213
|
- resources/web/ratchet.css
|
214
214
|
- resources/web/refreshable.html
|
215
|
-
- spec/basic_routes_spec.rb
|
215
|
+
- spec/functional/basic_routes_spec.rb
|
216
|
+
- spec/unit/navigatable_spec.rb
|
216
217
|
- vendor/Podfile.lock
|
217
218
|
homepage: https://github.com/balvig/motion-hybrid
|
218
219
|
licenses:
|
@@ -239,4 +240,5 @@ signing_key:
|
|
239
240
|
specification_version: 4
|
240
241
|
summary: RubyMotion framework for easily making hybrid webview-centric iOS apps
|
241
242
|
test_files:
|
242
|
-
- spec/basic_routes_spec.rb
|
243
|
+
- spec/functional/basic_routes_spec.rb
|
244
|
+
- spec/unit/navigatable_spec.rb
|