formotion 1.6 → 1.7

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +0 -3
  4. data/Gemfile +4 -1
  5. data/LIST_OF_ROW_TYPES.md +58 -6
  6. data/Rakefile +6 -2
  7. data/app/app_delegate.rb +6 -0
  8. data/examples/KitchenSink/Gemfile +2 -1
  9. data/examples/KitchenSink/Rakefile +9 -4
  10. data/examples/KitchenSink/app/app_delegate.rb +20 -5
  11. data/examples/KitchenSink/resources/arrow-up.png +0 -0
  12. data/examples/KitchenSink/resources/arrow-up@2x.png +0 -0
  13. data/examples/KitchenSink/resources/email.png +0 -0
  14. data/examples/KitchenSink/resources/email@2x.png +0 -0
  15. data/examples/Persistence/app/app_delegate.rb +2 -0
  16. data/examples/Persistence/app/controller.rb +66 -0
  17. data/lib/formotion/controller/form_controller.rb +1 -1
  18. data/lib/formotion/form/form.rb +14 -5
  19. data/lib/formotion/model/formable.rb +8 -6
  20. data/lib/formotion/patch/ui_text_field.rb +15 -1
  21. data/lib/formotion/row/row.rb +19 -3
  22. data/lib/formotion/row/row_cell_builder.rb +48 -2
  23. data/lib/formotion/row_type/button.rb +2 -2
  24. data/lib/formotion/row_type/date_row.rb +8 -1
  25. data/lib/formotion/row_type/image_row.rb +2 -2
  26. data/lib/formotion/row_type/map_row.rb +60 -23
  27. data/lib/formotion/row_type/object_row.rb +2 -2
  28. data/lib/formotion/row_type/picker_row.rb +32 -0
  29. data/lib/formotion/row_type/string_row.rb +5 -2
  30. data/lib/formotion/row_type/web_link_row.rb +48 -0
  31. data/lib/formotion/version.rb +1 -1
  32. data/resources/camera.png +0 -0
  33. data/resources/camera@2x.png +0 -0
  34. data/spec/functional/map_row_spec.rb +151 -4
  35. data/spec/functional/web_link_row_spec.rb +35 -0
  36. data/spec/row_spec.rb +109 -1
  37. data/spec/row_type/web_link_spec.rb +23 -0
  38. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3407c939ef975c1f7e97164c26689e0110507891
4
- data.tar.gz: 996472e335ea5b2be05e62fccc4499402e21b6a0
3
+ metadata.gz: 71061dad41a80a78a4e7b26faa6fb78d284beaee
4
+ data.tar.gz: 4d6462cfe38e455077bf4736376beb84ef1ba46a
5
5
  SHA512:
6
- metadata.gz: ac0469bebf08738e7ec88465b6b72fce94625f02b65eb5815f85650a5671046266f90beee6100f6cf16d8849ebcd6100eb58f9c74d23ac2b669238de29a233c5
7
- data.tar.gz: e16aeb3fbd30d8407bb19b7bd102b04b90274c2f1540056d110371bfbab3a4709ee0afb33838267ebf4b214b16a2772b0b6e460471e8fd808903d10e37cc6948
6
+ metadata.gz: 0217c216bf843420d86d38f2ef6120af5f4057d68328cae4bb28aa65d0628aeb78a8c5af21eeef22fa90a944713fae98f2827b21dc1750dc11400947b83ea4e9
7
+ data.tar.gz: 116b36b2b66855546e79d7033fcf1473926c8d3085e049c14ff8b803a8e7e737768decb49b29ffff9ebc6144e4ed5510da27afc542f309524deec2e9a185600c
data/.gitignore CHANGED
@@ -8,4 +8,5 @@ resources/*.storyboardc
8
8
  .bundle
9
9
  Gemfile.lock
10
10
  pkg/*
11
- .rvmrc
11
+ .rvmrc
12
+ vendor
data/.travis.yml CHANGED
@@ -1,6 +1,3 @@
1
1
  language: objective-c
2
- before_install:
3
- - rvm install ruby-1.9.3-p429
4
- - rvm use 1.9.3
5
2
  install: bundle install
6
3
  script: bundle exec rake spec:units
data/Gemfile CHANGED
@@ -3,5 +3,8 @@ source 'https://rubygems.org'
3
3
  gem 'guard-motion'
4
4
  gem 'rb-fsevent'
5
5
 
6
+ gem "motion-cocoapods"
7
+ gem "cocoapods"
8
+
6
9
  # Specify your gem's dependencies in motion-settings.gemspec
7
- gemspec
10
+ gemspec
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: :map_view,
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,3 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'formotion', path: '../..'
3
+ gem 'formotion', path: '../..'
4
+ gem 'motion-cocoapods'
@@ -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
- require 'rubygems'
6
- require 'bundler'
7
- Bundler.require :default
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",
@@ -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
 
@@ -49,7 +49,7 @@ module Formotion
49
49
  # Setting @form.controller assigns
50
50
  # @form as the datasource and delegate
51
51
  # and reloads the data.
52
- @form.controller = self
52
+ @form.controller = WeakRef.new(self)
53
53
  end
54
54
 
55
55
  def viewWillAppear(animated)
@@ -267,19 +267,26 @@ module Formotion
267
267
  end
268
268
 
269
269
  def open
270
- @form_observer ||= lambda { |form, saved_render|
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
- App::Persistence[persist_key] = render
298
- App::Persistence[original_persist_key] ||= render
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 to_form
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
- form_hash = {
66
+ return {
67
67
  title: self.class.form_title || self.class.to_s.capitalize,
68
68
  sections: [{
69
- rows: rows
70
- }]
69
+ rows: rows
70
+ }]
71
71
  }
72
+ end
72
73
 
73
- form = Formotion::Form.new(form_hash)
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