motion-form 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 09ef894ca746f523ff535a24fc6a087cea8a81d2
4
- data.tar.gz: e9f23285416fc9fcdc676952c90fbcd3aa438a5e
3
+ metadata.gz: c793153ac5710719c85021fde056751ffe3e2396
4
+ data.tar.gz: 031ba7b22c0c0a3a0ef0161d6e258b35fb1e491b
5
5
  SHA512:
6
- metadata.gz: f0971e202bc441add4a481064d56bdb29b2e971fcc79b1b5374ba40fd20250829d66dc1444965c94f81b14d20b06538ddf8a054bee95de96fef35236b72b8711
7
- data.tar.gz: d12f57fe38dadab75f55d55f2e1d35b9ba9adae4d37649d92cf3a4cae71068512e656e7922271d11cbe158ef1fe301d6fdbd9ac4b9ed7615eabaa4122a5ae1cc
6
+ metadata.gz: 238174d7a0399ad62ec129e827b171ed326f091adf3e48ec9d8b88d06aa2709d171de2088c79a64d418b2aadb14ef1c5cea5ba70f53c98f1c26b34aba9d039bf
7
+ data.tar.gz: 1958358b9767a1e39532443c316fb13714978704ed765a227bb15294eeb0885535d661a2b768898d96b85c80856b8c7c8f82e61889963052831fbe22e08e7b1d
data/lib/motion-form.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require 'bubble-wrap/core'
2
2
  require 'motion-require'
3
3
 
4
- Motion::Require.all(Dir.glob(File.expand_path('../project/**/*.rb', __FILE__)))
4
+ unless defined?(Motion::Project::Config)
5
+ raise 'This file must be required within a RubyMotion project Rakefile.'
6
+ end
5
7
 
8
+ Motion::Require.all(Dir.glob(File.expand_path('../project/**/*.rb', __FILE__)))
@@ -1,6 +1,6 @@
1
1
  motion_require './text_field_cell'
2
2
 
3
- class ButtonCell < TextFieldCell
3
+ class ButtonCell < TextInputCell
4
4
  IDENTIFIER = 'ButtonCell'
5
5
 
6
6
  class << self
@@ -6,9 +6,11 @@ class TextFieldCell < BaseCell
6
6
 
7
7
  def initWithStyle(style, reuseIdentifier: reuse_identifier)
8
8
  super.tap do |cell|
9
- cell.observe('ButtonCallbackWillFire', 'resign_textfield:')
10
- cell.observe('FormWillValidate', 'resign_textfield:')
11
- cell.observe('FormWillRender', 'resign_textfield:')
9
+ cell.observe('ButtonCallbackWillFire', 'resign_text_view:')
10
+ cell.observe('FormWillValidate', 'resign_text_view:')
11
+ cell.observe('FormWillRender', 'resign_text_view:')
12
+
13
+ cell.setup_constraints
12
14
  end
13
15
  end
14
16
 
@@ -18,69 +20,89 @@ class TextFieldCell < BaseCell
18
20
  end
19
21
  end
20
22
 
21
- def resign_textfield(notification)
22
- text_field.resignFirstResponder if text_field.isFirstResponder
23
+ def setup_constraints
24
+ Motion::Layout.new do |layout|
25
+ layout.view contentView
26
+ layout.subviews 'text_view' => text_view
27
+ layout.horizontal '|[text_view]|'
28
+ layout.vertical '|[text_view]|'
29
+ end
30
+ end
31
+
32
+ def resign_text_view(notification)
33
+ text_view.resignFirstResponder if text_view.isFirstResponder
23
34
  end
24
35
 
25
36
  def label=(label)
26
- text_field.placeholder = label
27
37
  end
28
38
 
29
39
  def secure=(secure)
30
- text_field.secureTextEntry = secure
31
40
  end
32
41
 
33
42
  def icon=(icon)
34
43
  left_view.name = icon
35
44
  end
36
45
 
37
- def text_field
38
- @text_field ||= UITextField.alloc.init.tap do |field|
39
- field.autocorrectionType = UITextAutocorrectionTypeNo
40
- field.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
41
- field.backgroundColor = UIColor.clearColor
42
- field.clearButtonMode = UITextFieldViewModeWhileEditing
43
- field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter
44
- field.leftView = left_view
45
- field.leftViewMode = UITextFieldViewModeAlways
46
- field.textColor = UIColor.grayColor
47
-
48
- field.delegate = self
46
+ def text_view
47
+ @text_view ||= SZTextView.alloc.init.tap do |text_view|
48
+ text_view.font = UIFont.fontWithName('HelveticaNeue-Light', size: 14.0)
49
+ text_view.placeholder = 'Write a short bio'
50
+ text_view.delegate = self
49
51
  end
50
52
  end
53
+ alias_method :text_field, :text_view
51
54
 
52
55
  def left_view
53
56
  @left_view ||= IconView.alloc.init
54
57
  end
55
58
 
56
59
  def value
57
- text_field.text
60
+ text_view.text
58
61
  end
59
62
 
60
63
  def value=(value)
61
- text_field.text = value
64
+ text_view.text = value
62
65
  end
63
66
 
64
- def layoutSubviews
65
- text_field.frame = [[10, 0], [300, 43]]
66
- left_view.frame = [[0, 0], [36, 43]]
67
- end
68
-
69
- def textFieldDidBeginEditing(text_field)
67
+ def textViewDidBeginEditing(text_view)
70
68
  post('FormCellDidBeginEditing', notification_payload)
71
69
  end
72
70
 
73
- def textFieldDidEndEditing(text_field)
71
+ def textViewDidEndEditing(text_view)
74
72
  post('FormCellDidEndEditing', notification_payload)
75
73
  end
76
74
 
77
- def textFieldShouldReturn(text_field)
78
- text_field.resignFirstResponder
75
+ def textFieldShouldReturn(text_view)
76
+ text_view.resignFirstResponder
79
77
 
80
78
  true
81
79
  end
82
80
 
81
+ def textView(text_view, shouldChangeTextInRange: range, replacementText: text)
82
+ if text == "\n"
83
+ text_view.resignFirstResponder
84
+
85
+ false
86
+ else
87
+ true
88
+ end
89
+ end
90
+
91
+ def textViewDidChange(text_view)
92
+ line = text_view.caretRectForPosition(text_view.selectedTextRange.start)
93
+ overflow = line.origin.y + line.size.height - (text_view.contentOffset.y + text_view.bounds.size.height - text_view.contentInset.bottom - text_view.contentInset.top )
94
+
95
+ if overflow > 0
96
+ offset = text_view.contentOffset
97
+ offset.y += overflow + 7
98
+
99
+ UIView.animateWithDuration(0.2, animations: -> {
100
+ text_view.setContentOffset(offset)
101
+ })
102
+ end
103
+ end
104
+
83
105
  def notification_payload
84
- { key: key, value: value, text_field: text_field }
106
+ { key: key, value: value, text_field: text_view }
85
107
  end
86
108
  end
@@ -0,0 +1,86 @@
1
+ motion_require './base_cell'
2
+ motion_require '../views/icon_view'
3
+
4
+ class TextInputCell < BaseCell
5
+ IDENTIFIER = 'TextInputCell'
6
+
7
+ def initWithStyle(style, reuseIdentifier: reuse_identifier)
8
+ super.tap do |cell|
9
+ cell.observe('ButtonCallbackWillFire', 'resign_textfield:')
10
+ cell.observe('FormWillValidate', 'resign_textfield:')
11
+ cell.observe('FormWillRender', 'resign_textfield:')
12
+ end
13
+ end
14
+
15
+ class << self
16
+ def has_value?
17
+ true
18
+ end
19
+ end
20
+
21
+ def resign_textfield(notification)
22
+ text_field.resignFirstResponder if text_field.isFirstResponder
23
+ end
24
+
25
+ def label=(label)
26
+ text_field.placeholder = label
27
+ end
28
+
29
+ def secure=(secure)
30
+ text_field.secureTextEntry = secure
31
+ end
32
+
33
+ def icon=(icon)
34
+ left_view.name = icon
35
+ end
36
+
37
+ def text_field
38
+ @text_field ||= UITextField.alloc.init.tap do |field|
39
+ field.autocorrectionType = UITextAutocorrectionTypeNo
40
+ field.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
41
+ field.backgroundColor = UIColor.clearColor
42
+ field.clearButtonMode = UITextFieldViewModeWhileEditing
43
+ field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter
44
+ field.leftView = left_view
45
+ field.leftViewMode = UITextFieldViewModeAlways
46
+ field.textColor = UIColor.grayColor
47
+
48
+ field.delegate = self
49
+ end
50
+ end
51
+
52
+ def left_view
53
+ @left_view ||= IconView.alloc.init
54
+ end
55
+
56
+ def value
57
+ text_field.text
58
+ end
59
+
60
+ def value=(value)
61
+ text_field.text = value
62
+ end
63
+
64
+ def layoutSubviews
65
+ text_field.frame = [[10, 0], [300, 43]]
66
+ left_view.frame = [[0, 0], [36, 43]]
67
+ end
68
+
69
+ def textFieldDidBeginEditing(text_field)
70
+ post('FormCellDidBeginEditing', notification_payload)
71
+ end
72
+
73
+ def textFieldDidEndEditing(text_field)
74
+ post('FormCellDidEndEditing', notification_payload)
75
+ end
76
+
77
+ def textFieldShouldReturn(text_field)
78
+ text_field.resignFirstResponder
79
+
80
+ true
81
+ end
82
+
83
+ def notification_payload
84
+ { key: key, value: value, text_field: text_field }
85
+ end
86
+ end
@@ -0,0 +1,22 @@
1
+ module MotionForm
2
+ module FontIconMapper
3
+ class << self
4
+ def call(icon)
5
+ unicode(icon).hex.chr(Encoding::UTF_8)
6
+ end
7
+
8
+ def unicode(icon)
9
+ mappings[icon] || ''
10
+ end
11
+
12
+ def mappings
13
+ @mappings ||= begin
14
+ path = NSBundle.mainBundle.pathForResource('icons', ofType:'json')
15
+ data = NSData.dataWithContentsOfFile(path)
16
+
17
+ NSJSONSerialization.JSONObjectWithData(data, options: 0, error: nil)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -13,11 +13,24 @@ module MotionForm
13
13
  f.dataSource = self
14
14
  f.delegate = self
15
15
 
16
+ f.addGestureRecognizer(tap_recognizer)
17
+
16
18
  @keyboard_avoiding_delegate = Motion::KeyboardAvoiding.new(f)
19
+
17
20
  listen
18
21
  end
19
22
  end
20
23
 
24
+ def tap_recognizer
25
+ @tap_recognizer ||= UITapGestureRecognizer.alloc.init.tap do |recognizer|
26
+ recognizer.addTarget(self, action: 'tapped:')
27
+ end
28
+ end
29
+
30
+ def tapped(recognizer)
31
+ endEditing(true)
32
+ end
33
+
21
34
  def listen
22
35
  observers << notification_center.addObserver(self, selector: 'did_begin_editing:', name: 'FormCellDidBeginEditing', object: nil)
23
36
  observers << notification_center.addObserver(self, selector: 'did_end_editing:', name: 'FormCellDidEndEditing', object: nil)
@@ -78,6 +91,13 @@ module MotionForm
78
91
  row = section.rows[index_path.row]
79
92
  end
80
93
 
94
+ def tableView(table_view, heightForRowAtIndexPath: index_path)
95
+ section = sections[index_path.section]
96
+ row = section.rows[index_path.row]
97
+
98
+ row.respondsToSelector('height') ? row.height : 44
99
+ end
100
+
81
101
  def tableView(table_view, viewForHeaderInSection: section)
82
102
  unless sections[section].title.blank?
83
103
  SectionHeaderView.alloc.initWithFrame([[0, 0], [size.width, 44.0]]).tap do |header|
@@ -105,7 +125,7 @@ module MotionForm
105
125
  def valid?
106
126
  notification_center.postNotificationName('FormWillValidate', object: self, userInfo: nil)
107
127
 
108
- rows.select { |row| row.is_a? TextFieldRow }.all? { |row| row.valid? }
128
+ rows.select { |row| row.is_a? TextInputRow }.all? { |row| row.valid? }
109
129
  end
110
130
 
111
131
  def tableView(table_view, cellForRowAtIndexPath: index_path)
@@ -42,7 +42,7 @@ module MotionForm
42
42
  end
43
43
 
44
44
  def included_cells
45
- [TextFieldCell, ButtonCell]
45
+ [TextInputCell, TextFieldCell, ButtonCell]
46
46
  end
47
47
 
48
48
  def section_header_font
@@ -54,7 +54,7 @@ module MotionForm
54
54
  end
55
55
 
56
56
  def icon_mapper
57
- @icon_mapper || -> (icon_name) { icon_name }
57
+ @icon_mapper || FontIconMapper
58
58
  end
59
59
 
60
60
  def section_header_color
@@ -1,7 +1,7 @@
1
1
  motion_require '../cells/button_cell'
2
2
  motion_require './text_field_row'
3
3
 
4
- class ButtonRow < TextFieldRow
4
+ class ButtonRow < TextInputRow
5
5
  attr_reader :on_tap_callback, :accessory
6
6
 
7
7
  def initialize(key, options)
@@ -1,70 +1,12 @@
1
1
  motion_require './base_row'
2
2
  motion_require '../cells/text_field_cell'
3
3
 
4
- class TextFieldRow < BaseRow
5
- EMAIL_REGEX = /^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/
6
- URL_REGEX = /https?:\/\/[\S]+/
7
-
8
- attr_accessor :value
9
-
10
- def initialize(key, options)
11
- super
12
-
13
- setup_validation
14
-
15
- listen
16
- end
17
-
18
- def setup_validation
19
- if options[:required]
20
- validation_rules << lambda { |value| value && value != '' }
21
- end
22
-
23
- if options[:email]
24
- validation_rules << lambda { |value| value && value[EMAIL_REGEX] }
25
- end
26
-
27
- if options[:url]
28
- validation_rules << lambda { |value| value && value[URL_REGEX] }
29
- end
30
-
31
- if options[:format] && options[:format].is_a?(Regexp)
32
- validation_rules << lambda { |value| value && value[options[:format]] }
33
- end
34
-
35
- if options[:validate_with] && options[:validate_with].is_a?(Proc)
36
- validation_rules << options[:validate_with]
37
- end
38
- end
39
-
40
- def valid?
41
- validation_rules.all? { |rule| rule.call(value) }
42
- end
43
-
44
- def validation_rules
45
- @validation_rules ||= []
46
- end
47
-
48
- def listen
49
- observe('FormCellDidEndEditing', 'did_end_editing:')
50
- end
51
-
52
- def did_end_editing(notification)
53
- self.value = notification.userInfo[:value] if notification.userInfo[:key] == key
54
- end
55
-
56
- def textFieldDidEndEditing(text_field)
57
- self.value = text_field.text
58
- end
59
-
60
- def update_cell(cell)
61
- super
62
-
63
- cell.secure = options[:secure]
64
- cell.value = options[:value]
65
- end
66
-
4
+ class TextFieldRow < TextInputRow
67
5
  def cell_type
68
6
  TextFieldCell
69
7
  end
8
+
9
+ def height
10
+ 100
11
+ end
70
12
  end
@@ -0,0 +1,70 @@
1
+ motion_require './base_row'
2
+ motion_require '../cells/text_input_cell'
3
+
4
+ class TextInputRow < BaseRow
5
+ EMAIL_REGEX = /^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/
6
+ URL_REGEX = /https?:\/\/[\S]+/
7
+
8
+ attr_accessor :value
9
+
10
+ def initialize(key, options)
11
+ super
12
+
13
+ setup_validation
14
+
15
+ listen
16
+ end
17
+
18
+ def setup_validation
19
+ if options[:required]
20
+ validation_rules << lambda { |value| value && value != '' }
21
+ end
22
+
23
+ if options[:email]
24
+ validation_rules << lambda { |value| value && value[EMAIL_REGEX] }
25
+ end
26
+
27
+ if options[:url]
28
+ validation_rules << lambda { |value| value && value[URL_REGEX] }
29
+ end
30
+
31
+ if options[:format] && options[:format].is_a?(Regexp)
32
+ validation_rules << lambda { |value| value && value[options[:format]] }
33
+ end
34
+
35
+ if options[:validate_with] && options[:validate_with].is_a?(Proc)
36
+ validation_rules << options[:validate_with]
37
+ end
38
+ end
39
+
40
+ def valid?
41
+ validation_rules.all? { |rule| rule.call(value) }
42
+ end
43
+
44
+ def validation_rules
45
+ @validation_rules ||= []
46
+ end
47
+
48
+ def listen
49
+ observe('FormCellDidEndEditing', 'did_end_editing:')
50
+ end
51
+
52
+ def did_end_editing(notification)
53
+ self.value = notification.userInfo[:value] if notification.userInfo[:key] == key
54
+ end
55
+
56
+ def textFieldDidEndEditing(text_field)
57
+ self.value = text_field.text
58
+ end
59
+
60
+ def update_cell(cell)
61
+ super
62
+
63
+ cell.secure = options[:secure]
64
+ cell.value = options[:value]
65
+ end
66
+
67
+ def cell_type
68
+ TextInputCell
69
+ end
70
+ end
@@ -10,6 +10,10 @@ class MotionForm
10
10
  end
11
11
 
12
12
  def input(key, options = {})
13
+ rows << TextInputRow.new(key, options)
14
+ end
15
+
16
+ def text(key, options = {})
13
17
  rows << TextFieldRow.new(key, options)
14
18
  end
15
19
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Devon Blandin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-31 00:00:00.000000000 Z
11
+ date: 2014-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: motion-keyboard-avoiding
@@ -38,6 +38,48 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.0.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: cocoapods
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.27.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.27.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: motion-cocoapods
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.7
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.7
69
+ - !ruby/object:Gem::Dependency
70
+ name: motion-layout
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.1
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: rake
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -64,12 +106,15 @@ files:
64
106
  - lib/project/cells/base_cell.rb
65
107
  - lib/project/cells/button_cell.rb
66
108
  - lib/project/cells/text_field_cell.rb
109
+ - lib/project/cells/text_input_cell.rb
67
110
  - lib/project/controllers/form_controller.rb
111
+ - lib/project/font_icon_mapper.rb
68
112
  - lib/project/form/base.rb
69
113
  - lib/project/motion-form.rb
70
114
  - lib/project/rows/base_row.rb
71
115
  - lib/project/rows/button_row.rb
72
116
  - lib/project/rows/text_field_row.rb
117
+ - lib/project/rows/text_input_row.rb
73
118
  - lib/project/section/section.rb
74
119
  - lib/project/string.rb
75
120
  - lib/project/views/icon_view.rb
@@ -95,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
140
  version: '0'
96
141
  requirements: []
97
142
  rubyforge_project:
98
- rubygems_version: 2.1.1
143
+ rubygems_version: 2.1.3
99
144
  signing_key:
100
145
  specification_version: 4
101
146
  summary: Simple DSL for RubyMotion form creation