formotion 1.6 → 1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +0 -3
- data/Gemfile +4 -1
- data/LIST_OF_ROW_TYPES.md +58 -6
- data/Rakefile +6 -2
- data/app/app_delegate.rb +6 -0
- data/examples/KitchenSink/Gemfile +2 -1
- data/examples/KitchenSink/Rakefile +9 -4
- data/examples/KitchenSink/app/app_delegate.rb +20 -5
- data/examples/KitchenSink/resources/arrow-up.png +0 -0
- data/examples/KitchenSink/resources/arrow-up@2x.png +0 -0
- data/examples/KitchenSink/resources/email.png +0 -0
- data/examples/KitchenSink/resources/email@2x.png +0 -0
- data/examples/Persistence/app/app_delegate.rb +2 -0
- data/examples/Persistence/app/controller.rb +66 -0
- data/lib/formotion/controller/form_controller.rb +1 -1
- data/lib/formotion/form/form.rb +14 -5
- data/lib/formotion/model/formable.rb +8 -6
- data/lib/formotion/patch/ui_text_field.rb +15 -1
- data/lib/formotion/row/row.rb +19 -3
- data/lib/formotion/row/row_cell_builder.rb +48 -2
- data/lib/formotion/row_type/button.rb +2 -2
- data/lib/formotion/row_type/date_row.rb +8 -1
- data/lib/formotion/row_type/image_row.rb +2 -2
- data/lib/formotion/row_type/map_row.rb +60 -23
- data/lib/formotion/row_type/object_row.rb +2 -2
- data/lib/formotion/row_type/picker_row.rb +32 -0
- data/lib/formotion/row_type/string_row.rb +5 -2
- data/lib/formotion/row_type/web_link_row.rb +48 -0
- data/lib/formotion/version.rb +1 -1
- data/resources/camera.png +0 -0
- data/resources/camera@2x.png +0 -0
- data/spec/functional/map_row_spec.rb +151 -4
- data/spec/functional/web_link_row_spec.rb +35 -0
- data/spec/row_spec.rb +109 -1
- data/spec/row_type/web_link_spec.rb +23 -0
- metadata +13 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71061dad41a80a78a4e7b26faa6fb78d284beaee
|
4
|
+
data.tar.gz: 4d6462cfe38e455077bf4736376beb84ef1ba46a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0217c216bf843420d86d38f2ef6120af5f4057d68328cae4bb28aa65d0628aeb78a8c5af21eeef22fa90a944713fae98f2827b21dc1750dc11400947b83ea4e9
|
7
|
+
data.tar.gz: 116b36b2b66855546e79d7033fcf1473926c8d3085e049c14ff8b803a8e7e737768decb49b29ffff9ebc6144e4ed5510da27afc542f309524deec2e9a185600c
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/LIST_OF_ROW_TYPES.md
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
[Subform](#subform)<br/>
|
20
20
|
[Template](#template)<br/>
|
21
21
|
[MapView](#mapview)<br/>
|
22
|
+
[WebLink](#weblink)<br/>
|
22
23
|
[WebView](#webview)<br/>
|
23
24
|
[PagedImage](#pagedimage)<br/>
|
24
25
|
[Tags](#tags)<br/>
|
@@ -38,6 +39,8 @@ All row types accept following properties:
|
|
38
39
|
value: 'Some Value', # The initial value passed to the row
|
39
40
|
title: 'Title', # Title of the row
|
40
41
|
subtitle: 'Subtitle', # Subtitle of the row
|
42
|
+
image: nil, # Image for the cell's imageView. Accepts a string, UIImage, URL string, or NSURL
|
43
|
+
image_placeholder: nil # Used only when you are loading remote images. Accpets a string or UIImage
|
41
44
|
type: :string, # The type of row (string, phone, switch, etc)
|
42
45
|
row_height: 100 # Height of the row
|
43
46
|
}
|
@@ -70,11 +73,12 @@ All character based row types accept following properties:
|
|
70
73
|
type: :string,
|
71
74
|
placeholder: 'James Bond',
|
72
75
|
auto_correction: :no,
|
73
|
-
auto_capitalization: :none
|
76
|
+
auto_capitalization: :none,
|
77
|
+
input_accessory: :done
|
74
78
|
}
|
75
79
|
```
|
76
80
|
|
77
|
-
The `StringRow` is a simple text input row and opens a `UIKeyboardTypeDefault` keyboard when editing.
|
81
|
+
The `StringRow` is a simple text input row and opens a `UIKeyboardTypeDefault` keyboard when editing. `input_accessory` can be nil or `:done`, and shows a toolbar with a done button above the keyboard.
|
78
82
|
|
79
83
|
|
80
84
|
### <a name="text"></a> Text row
|
@@ -355,7 +359,8 @@ The `SliderRow` takes a ruby range as `range` property that defines the min and
|
|
355
359
|
key: :pick,
|
356
360
|
type: :picker,
|
357
361
|
items: ["Ruby", "Motion", "Rocks"],
|
358
|
-
value: "Motion"
|
362
|
+
value: "Motion",
|
363
|
+
input_accessory: :done
|
359
364
|
}
|
360
365
|
```
|
361
366
|
|
@@ -432,13 +437,60 @@ Use a `:display_key` to show the value of the subform in the row:
|
|
432
437
|
```ruby
|
433
438
|
{
|
434
439
|
title: "Map",
|
435
|
-
type: :
|
436
|
-
value: coordinates, # of type CLLocationCoordinate2D
|
440
|
+
type: :map,
|
441
|
+
value: coordinates, # of type CLLocationCoordinate2D, CLCircularRegion, or a Hash of options
|
437
442
|
row_height: 200 # for better viewing
|
438
443
|
}
|
439
444
|
```
|
440
445
|
|
441
|
-
Shows a map with a pin at the coordinates from value.
|
446
|
+
Shows a map with a pin at the coordinates from value. If you pass a `CLLocationCoordinate2D` or `CLCircularRegion`, a pin will be placed at the coordinates. You can pass a hash of options like this:
|
447
|
+
|
448
|
+
```ruby
|
449
|
+
{
|
450
|
+
title: "Map",
|
451
|
+
type: :map,
|
452
|
+
value: {
|
453
|
+
coord: coordinates,
|
454
|
+
enabled: true, # Whether the user can interact with the map.
|
455
|
+
type: MKMapTypeStandard, # The type of map to show. See MKMapType documentation.
|
456
|
+
animated: true, # Whether setting the region should animate. This property also applies to annotation titles.
|
457
|
+
pin: {
|
458
|
+
coord: coordinates, # Must be a CLLocationCoordinate2D
|
459
|
+
title: nil, # Title of the annotation
|
460
|
+
subtitle: nil # Subtitle of the annotation
|
461
|
+
}
|
462
|
+
}
|
463
|
+
row_height: 200 # for better viewing
|
464
|
+
}
|
465
|
+
```
|
466
|
+
|
467
|
+
If you pass `pin: nil` the map will not display an annotation. Annotations with titles will automatically pop open the annotation. _Note: If you set a title on an annotation it will automatically invalidate `enabled:false` and the map will be interactable._
|
468
|
+
|
469
|
+
### <a name="weblink"></a> WebLink row
|
470
|
+
```ruby
|
471
|
+
{
|
472
|
+
title: "My Awesome Site",
|
473
|
+
type: :web_link,
|
474
|
+
value: "http://www.myawesomesite.com" # URL to be opened. Can also be an NSURL
|
475
|
+
}
|
476
|
+
```
|
477
|
+
|
478
|
+
You can also allow the user to confirm leaving your app:
|
479
|
+
```ruby
|
480
|
+
{
|
481
|
+
title: "My Awesome Site",
|
482
|
+
type: :web_link,
|
483
|
+
warn: true,
|
484
|
+
# or pass a hash to :warn.
|
485
|
+
# Here are the default values (Bubblewrap alert options):
|
486
|
+
# warn: {
|
487
|
+
# title: "Leaving #{App.name}",
|
488
|
+
# message: "This action will leave #{App.name} and open Safari.",
|
489
|
+
# buttons: ["Cancel", "OK"]
|
490
|
+
# }
|
491
|
+
value: "http://www.myawesomesite.com", # URL to be opened
|
492
|
+
}
|
493
|
+
```
|
442
494
|
|
443
495
|
|
444
496
|
### <a name="webview"></a> WebView row
|
data/Rakefile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
$:.unshift("/Library/RubyMotion/lib")
|
2
|
-
require 'motion/project'
|
2
|
+
require 'motion/project/template/ios'
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "bundler/setup"
|
5
|
-
|
5
|
+
Bundler.require
|
6
6
|
$:.unshift("./lib/")
|
7
7
|
require './lib/formotion'
|
8
8
|
require 'guard/motion'
|
@@ -10,6 +10,10 @@ require 'guard/motion'
|
|
10
10
|
Motion::Project::App.setup do |app|
|
11
11
|
# Use `rake config' to see complete project settings.
|
12
12
|
app.name = 'Formotion'
|
13
|
+
|
14
|
+
app.pods do
|
15
|
+
pod 'JMImageCache'
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
namespace :spec do
|
data/app/app_delegate.rb
CHANGED
@@ -11,6 +11,7 @@ class AppDelegate
|
|
11
11
|
title: "Photo",
|
12
12
|
key: :photo,
|
13
13
|
type: :image,
|
14
|
+
image: "camera",
|
14
15
|
deletable: true
|
15
16
|
},{
|
16
17
|
title: "Picker",
|
@@ -31,6 +32,11 @@ class AppDelegate
|
|
31
32
|
placeholder: "required",
|
32
33
|
type: :string,
|
33
34
|
secure: true
|
35
|
+
}, {
|
36
|
+
title: "Remote Loaded Image",
|
37
|
+
type: :static,
|
38
|
+
image: "http://placekitten.com/80/80?t=#{Time.now.to_i}",
|
39
|
+
image_placeholder: "camera"
|
34
40
|
}, {
|
35
41
|
title: "Password",
|
36
42
|
subtitle: "Confirmation",
|
@@ -1,12 +1,17 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
$:.unshift("/Library/RubyMotion/lib")
|
3
|
-
require 'motion/project'
|
3
|
+
require 'motion/project/template/ios'
|
4
4
|
|
5
|
-
|
6
|
-
require 'bundler'
|
7
|
-
Bundler.require
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
Bundler.require
|
8
|
+
rescue LoadError
|
9
|
+
end
|
8
10
|
|
9
11
|
Motion::Project::App.setup do |app|
|
10
12
|
# Use `rake config' to see complete project settings.
|
11
13
|
app.name = 'KitchenSink'
|
14
|
+
app.pods do
|
15
|
+
pod 'SDWebImage'
|
16
|
+
end
|
12
17
|
end
|
@@ -14,15 +14,28 @@ class AppDelegate
|
|
14
14
|
title: "Email",
|
15
15
|
key: :email,
|
16
16
|
placeholder: "me@mail.com",
|
17
|
+
image: "email",
|
17
18
|
type: :email,
|
18
19
|
auto_correction: :no,
|
19
|
-
auto_capitalization: :none
|
20
|
+
auto_capitalization: :none,
|
21
|
+
input_accessory: :done
|
22
|
+
}, {
|
23
|
+
title: "Image Accessory",
|
24
|
+
subtitle: "You can add an image to any row type",
|
25
|
+
image: "arrow-up",
|
26
|
+
type: :static
|
27
|
+
}, {
|
28
|
+
title: "Image from URL",
|
29
|
+
subtitle: "Or from a URL!",
|
30
|
+
image: "http://placekitten.com/80/80?t=#{Time.now.to_i}",
|
31
|
+
type: :static
|
20
32
|
}, {
|
21
33
|
title: "Gender",
|
22
34
|
key: :gender,
|
23
35
|
type: :picker,
|
24
|
-
items: [['Female', 'f'], ['Male', 'm']],
|
25
|
-
value: 'm'
|
36
|
+
items: [['Female', 'f'],['fds', 'df'],['fddfsfds', 'f3'],['fdfafds', 'f33'], ['Male', 'm']],
|
37
|
+
value: 'm',
|
38
|
+
input_accessory: :done
|
26
39
|
}, {
|
27
40
|
title: "Password",
|
28
41
|
key: :password,
|
@@ -35,14 +48,16 @@ class AppDelegate
|
|
35
48
|
placeholder: "555-555-5555",
|
36
49
|
type: :phone,
|
37
50
|
auto_correction: :no,
|
38
|
-
auto_capitalization: :none
|
51
|
+
auto_capitalization: :none,
|
52
|
+
input_accessory: :done
|
39
53
|
}, {
|
40
54
|
title: "Number",
|
41
55
|
key: :number,
|
42
56
|
placeholder: "12345",
|
43
57
|
type: :number,
|
44
58
|
auto_correction: :no,
|
45
|
-
auto_capitalization: :none
|
59
|
+
auto_capitalization: :none,
|
60
|
+
input_accessory: :done
|
46
61
|
}, {
|
47
62
|
title: "Subtitle",
|
48
63
|
subtitle: "Confirmation",
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -6,6 +6,8 @@ class AppDelegate
|
|
6
6
|
|
7
7
|
@view_controller.navigationItem.leftBarButtonItem = UIBarButtonItem.alloc.initWithTitle("Render", style: UIBarButtonItemStyleBordered, target:self, action:'reset_form')
|
8
8
|
|
9
|
+
@view_controller.navigationItem.rightBarButtonItem = UIBarButtonItem.alloc.initWithTitle("Save", style: UIBarButtonItemStyleBordered, target:self, action:'submit')
|
10
|
+
|
9
11
|
@navigation_controller = UINavigationController.alloc.initWithRootViewController(@view_controller)
|
10
12
|
|
11
13
|
@window.rootViewController = @navigation_controller
|
@@ -4,6 +4,41 @@ class AccountSettingsController < Formotion::FormController
|
|
4
4
|
API_SERVER = "hello_world"
|
5
5
|
API_KEY = "123123secret"
|
6
6
|
|
7
|
+
SPECIAL_OPTIONS_HASH = {
|
8
|
+
title: "Special options",
|
9
|
+
sections: [{
|
10
|
+
rows: [{
|
11
|
+
title: "Phone Number",
|
12
|
+
value: "555-555-5555",
|
13
|
+
type: "phone",
|
14
|
+
key: "phone"
|
15
|
+
}, {
|
16
|
+
title: "Address",
|
17
|
+
value: "90210",
|
18
|
+
type: "string",
|
19
|
+
key: "address"
|
20
|
+
}]
|
21
|
+
}]
|
22
|
+
}
|
23
|
+
|
24
|
+
DISPLAY_KEY_HASH = {
|
25
|
+
title: "Alert Sounds",
|
26
|
+
sections: [{
|
27
|
+
key: :sound,
|
28
|
+
select_one: true,
|
29
|
+
rows: [{
|
30
|
+
title: "Beeps",
|
31
|
+
key: :Beeps,
|
32
|
+
value: true,
|
33
|
+
type: :check
|
34
|
+
},{
|
35
|
+
title: "Boops",
|
36
|
+
key: :Boops,
|
37
|
+
type: :check
|
38
|
+
}]
|
39
|
+
}]
|
40
|
+
}
|
41
|
+
|
7
42
|
SETTINGS_HASH = {
|
8
43
|
title: "Application",
|
9
44
|
persist_as: PERSIST_AS,
|
@@ -24,6 +59,37 @@ class AccountSettingsController < Formotion::FormController
|
|
24
59
|
auto_correction: :no,
|
25
60
|
auto_capitalization: :none
|
26
61
|
}]
|
62
|
+
}, {
|
63
|
+
rows: [{
|
64
|
+
title: "Name",
|
65
|
+
type: :string,
|
66
|
+
key: :name,
|
67
|
+
value: "Clay",
|
68
|
+
auto_correction: :no,
|
69
|
+
auto_capitalization: :none
|
70
|
+
}, {
|
71
|
+
title: "Password",
|
72
|
+
value: "Secret",
|
73
|
+
type: :string,
|
74
|
+
key: :password,
|
75
|
+
secure: false,
|
76
|
+
auto_correction: :no,
|
77
|
+
auto_capitalization: :none
|
78
|
+
}]
|
79
|
+
}, {
|
80
|
+
title: "w/ Subforms",
|
81
|
+
rows: [{
|
82
|
+
title: "Special Options",
|
83
|
+
type: :subform,
|
84
|
+
key: :special_options,
|
85
|
+
subform: SPECIAL_OPTIONS_HASH
|
86
|
+
}, {
|
87
|
+
title: "w/ Display Key",
|
88
|
+
type: :subform,
|
89
|
+
key: :alert_sound,
|
90
|
+
display_key: :sound,
|
91
|
+
subform: DISPLAY_KEY_HASH
|
92
|
+
}]
|
27
93
|
}]
|
28
94
|
}
|
29
95
|
|
data/lib/formotion/form/form.rb
CHANGED
@@ -267,19 +267,26 @@ module Formotion
|
|
267
267
|
end
|
268
268
|
|
269
269
|
def open
|
270
|
-
@form_observer ||=
|
270
|
+
@form_observer ||= ->(form, saved_render, uses_display_key = false) {
|
271
|
+
no_saved_render = saved_render.nil?
|
272
|
+
saved_render ||= {}
|
273
|
+
|
271
274
|
form.sections.each_with_index do |section, s_index|
|
272
275
|
section.rows.each_with_index do |row, index|
|
273
276
|
next if row.templated?
|
274
277
|
saved_row_value = saved_render[row.key]
|
275
278
|
|
279
|
+
if uses_display_key && section.select_one && saved_render.include?(section.key.to_s)
|
280
|
+
saved_row_value = row.key.to_s == saved_render[section.key.to_s].to_s
|
281
|
+
end
|
282
|
+
|
276
283
|
if row.subform?
|
277
|
-
@form_observer.call(row.subform.to_form, saved_row_value)
|
284
|
+
@form_observer.call(row.subform.to_form, saved_row_value, !!row.display_key)
|
278
285
|
elsif row.type == :template
|
279
286
|
row.value = saved_row_value
|
280
287
|
row.object.update_template_rows
|
281
288
|
else
|
282
|
-
row.value = saved_row_value
|
289
|
+
row.value = saved_row_value if !no_saved_render
|
283
290
|
end
|
284
291
|
end
|
285
292
|
end
|
@@ -294,8 +301,10 @@ module Formotion
|
|
294
301
|
|
295
302
|
# places hash of values into application persistance
|
296
303
|
def save
|
297
|
-
|
298
|
-
|
304
|
+
rendered = render
|
305
|
+
recursive_delete_nil(rendered)
|
306
|
+
App::Persistence[persist_key] = rendered
|
307
|
+
App::Persistence[original_persist_key] ||= rendered
|
299
308
|
end
|
300
309
|
|
301
310
|
def reset
|
@@ -54,7 +54,7 @@ module Formotion
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# Creates a Formotion::Form out of the model
|
57
|
-
def
|
57
|
+
def to_form_hash
|
58
58
|
rows = self.class.form_properties.collect { |options|
|
59
59
|
{
|
60
60
|
title: options[:property].capitalize,
|
@@ -63,14 +63,16 @@ module Formotion
|
|
63
63
|
value: self.send(options[:property])
|
64
64
|
}.merge(options)
|
65
65
|
}
|
66
|
-
|
66
|
+
return {
|
67
67
|
title: self.class.form_title || self.class.to_s.capitalize,
|
68
68
|
sections: [{
|
69
|
-
|
70
|
-
|
69
|
+
rows: rows
|
70
|
+
}]
|
71
71
|
}
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
+
def to_form
|
75
|
+
form = Formotion::Form.new(to_form_hash)
|
74
76
|
form.on_submit do
|
75
77
|
self.on_submit
|
76
78
|
end
|
@@ -96,4 +98,4 @@ module Formotion
|
|
96
98
|
p "need to implement on_submit in your Formable model #{self.class.to_s}"
|
97
99
|
end
|
98
100
|
end
|
99
|
-
end
|
101
|
+
end
|