ProMotion-XLForm 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +227 -0
- data/lib/ProMotion-XLForm.rb +22 -0
- data/lib/ProMotion/XLForm/cells/xl_form_image_selector_cell.rb +227 -0
- data/lib/ProMotion/XLForm/value_transformer.rb +18 -0
- data/lib/ProMotion/XLForm/xl_form.rb +232 -0
- data/lib/ProMotion/XLForm/xl_form_class_methods.rb +11 -0
- data/lib/ProMotion/XLForm/xl_form_module.rb +9 -0
- data/lib/ProMotion/XLForm/xl_form_patch.rb +29 -0
- data/lib/ProMotion/XLForm/xl_form_screen.rb +168 -0
- data/lib/ProMotion/XLForm/xl_form_view_controller.rb +54 -0
- data/lib/ProMotion/XLForm/xl_sub_form_screen.rb +43 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b72f5d70e733afcd851aff9900f8b13b19fbed0b
|
4
|
+
data.tar.gz: 2b63d7b46c59924fb9839f45e2f358a135f34028
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 341ac2b44c3f2f74cf667351d087d6ee239ef4237fe5fb690c8dd4736ff941c23f164fb8c095e367230155c42b728ef36775b2a44fb9b3b757425da8ee92407f
|
7
|
+
data.tar.gz: 63926ccbdea5af6926c5f75de41415d6eae24b797421f29c7e4aafe508d34628bf859532ea49aa02572994b08423816d35e33c1398017570e6ab6aa9d8a9d1c0
|
data/README.md
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
# ProMotion-XLForm
|
2
|
+
|
3
|
+
ProMotion-XLForm provides a PM::XLFormScreen for [ProMotion](https://github.com/clearsightstudio/ProMotion) powered by the CocoaPod [XLForm](https://github.com/xmartlabs/XLForm).
|
4
|
+
|
5
|
+
## Warning
|
6
|
+
This gem is currently in very early-stage. Use it at your own risk :)
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'ProMotion-form'
|
12
|
+
```
|
13
|
+
|
14
|
+
Then:
|
15
|
+
|
16
|
+
```sh-session
|
17
|
+
$ bundle
|
18
|
+
$ rake pod:install
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
`PM::XLFormScreen` include `PM::ScreenModule` so you'll have all ProMotion methods available.
|
24
|
+
|
25
|
+
To create a form, create a new `PM::XLFormScreen` and implement `form_data`.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class TestFormScreen < PM::XLFormScreen
|
29
|
+
def form_data
|
30
|
+
[
|
31
|
+
{
|
32
|
+
title: 'Account information',
|
33
|
+
cells: [
|
34
|
+
{
|
35
|
+
title: 'Email',
|
36
|
+
name: :email,
|
37
|
+
type: :email,
|
38
|
+
placeholder: 'Enter your email',
|
39
|
+
required: true
|
40
|
+
},
|
41
|
+
{
|
42
|
+
title: 'Name',
|
43
|
+
name: :name,
|
44
|
+
type: :text,
|
45
|
+
value: 'Default value'
|
46
|
+
},
|
47
|
+
{
|
48
|
+
title: 'Sex',
|
49
|
+
name: :sex,
|
50
|
+
type: :selector_push,
|
51
|
+
options: {
|
52
|
+
male: 'Male',
|
53
|
+
female: 'Female',
|
54
|
+
other: 'Other'
|
55
|
+
}
|
56
|
+
]
|
57
|
+
}
|
58
|
+
]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
## Available types
|
64
|
+
* :text
|
65
|
+
* :name
|
66
|
+
* :url
|
67
|
+
* :email
|
68
|
+
* :password
|
69
|
+
* :number
|
70
|
+
* :phone
|
71
|
+
* :twitter
|
72
|
+
* :account
|
73
|
+
* :integer
|
74
|
+
* :decimal
|
75
|
+
* :textview
|
76
|
+
* :selector_push
|
77
|
+
* :selector_popover
|
78
|
+
* :selector_action_sheet
|
79
|
+
* :selector_alert_view
|
80
|
+
* :selector_picker_view
|
81
|
+
* :selector_picker_view_inline
|
82
|
+
* :multiple_selector
|
83
|
+
* :multiple_selector_popover
|
84
|
+
* :selector_left_right
|
85
|
+
* :selector_segmented_control
|
86
|
+
* :date_inline
|
87
|
+
* :datetime_inline
|
88
|
+
* :time_inline
|
89
|
+
* :countdown_timer_inline
|
90
|
+
* :date
|
91
|
+
* :datetime
|
92
|
+
* :time
|
93
|
+
* :countdown_timer
|
94
|
+
* :datepicker
|
95
|
+
* :picker
|
96
|
+
* :slider
|
97
|
+
* :check
|
98
|
+
* :switch
|
99
|
+
* :button
|
100
|
+
* :info
|
101
|
+
* :step_counter
|
102
|
+
* :image
|
103
|
+
|
104
|
+
### Class options
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
class TestFormScreen < PM::XLFormScreen
|
108
|
+
|
109
|
+
form_options required: :asterisks, # add an asterisk to required fields
|
110
|
+
on_save: :'save_form:', # will be called when you touch save
|
111
|
+
on_cancel: :cancel_form # will be called when you touch cancel
|
112
|
+
|
113
|
+
def save_form(values)
|
114
|
+
mp values
|
115
|
+
end
|
116
|
+
|
117
|
+
def cancel_form
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
### Getting values
|
123
|
+
|
124
|
+
You can get the values of your form with `values`. You can also get validation errors with `validation_errors` and check if the form is valid with `valid?`
|
125
|
+
|
126
|
+
### Events
|
127
|
+
|
128
|
+
`on_change`, `on_add` and `on_remove` are available for cells, `on_add` and `on_remove` are available for sections.
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
{
|
132
|
+
title: 'Sex',
|
133
|
+
name: :sex,
|
134
|
+
type: :selector_push,
|
135
|
+
options: {
|
136
|
+
male: 'Male',
|
137
|
+
female: 'Female',
|
138
|
+
other: 'Other'
|
139
|
+
},
|
140
|
+
on_change: lambda do |old_value, new_value|
|
141
|
+
puts "Changed from #{old_value} to #{new_value}"
|
142
|
+
end
|
143
|
+
}
|
144
|
+
```
|
145
|
+
|
146
|
+
### Multivalued Sections (Insert, Delete, Reorder rows)
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
{
|
150
|
+
title: 'Multiple value',
|
151
|
+
name: :multi_values,
|
152
|
+
options: [:insert, :delete, :reorder],
|
153
|
+
cells: [
|
154
|
+
{
|
155
|
+
title: 'Add a new tag',
|
156
|
+
name: :tag,
|
157
|
+
type: :text
|
158
|
+
}
|
159
|
+
]
|
160
|
+
}
|
161
|
+
```
|
162
|
+
|
163
|
+
### Custom Selectors
|
164
|
+
|
165
|
+
You can create a custom _subform_ with a few options
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
{
|
169
|
+
title: 'Custom',
|
170
|
+
name: :custom,
|
171
|
+
cells: [
|
172
|
+
{
|
173
|
+
title: 'Some text',
|
174
|
+
name: :some_text,
|
175
|
+
type: :text
|
176
|
+
},
|
177
|
+
{
|
178
|
+
title: 'Other text',
|
179
|
+
name: :some_other_text,
|
180
|
+
type: :text
|
181
|
+
}
|
182
|
+
]
|
183
|
+
}
|
184
|
+
```
|
185
|
+
|
186
|
+
By default, the cell will print a `Hash.inspect` of your _subcells_. You can change this by creating a valueTransformer and set `value_transformer:`.
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
{
|
190
|
+
title: 'Custom',
|
191
|
+
name: :custom,
|
192
|
+
value_transformer: MyValueTransformer
|
193
|
+
cells: []
|
194
|
+
}
|
195
|
+
|
196
|
+
class MyValueTransformer < PM::ValueTransformer
|
197
|
+
def transformedValue(value)
|
198
|
+
return nil if value.nil?
|
199
|
+
|
200
|
+
str = []
|
201
|
+
str << value['some_text'] if value['some_text']
|
202
|
+
str << value['some_other_text'] if value['some_other_text']
|
203
|
+
|
204
|
+
str.join(',')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
```
|
208
|
+
|
209
|
+
For a more advanced custom selector, you can set `view_controller_class:`. See [XLForm documentation](https://github.com/xmartlabs/XLForm/#custom-selectors---selector-row-with-a-custom-selector-view-controller) for more informations.
|
210
|
+
|
211
|
+
## Todo
|
212
|
+
- Validations
|
213
|
+
- Tests
|
214
|
+
- A lot of other things :)
|
215
|
+
|
216
|
+
## Contributing
|
217
|
+
|
218
|
+
1. Fork it
|
219
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
220
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
221
|
+
4. Make some specs pass
|
222
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
223
|
+
6. Create new Pull Request
|
224
|
+
|
225
|
+
## License
|
226
|
+
|
227
|
+
Released under the [MIT license](LICENSE).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
unless defined?(Motion::Project::Config)
|
3
|
+
raise "ProMotion-XLForm must be required within a RubyMotion project."
|
4
|
+
end
|
5
|
+
require 'motion-cocoapods'
|
6
|
+
|
7
|
+
Motion::Project::App.setup do |app|
|
8
|
+
lib_dir_path = File.dirname(File.expand_path(__FILE__))
|
9
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/cells/xl_form_image_selector_cell.rb")
|
10
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_form_class_methods.rb")
|
11
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_form_module.rb")
|
12
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_form_view_controller.rb")
|
13
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_form.rb")
|
14
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_form_screen.rb")
|
15
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_sub_form_screen.rb")
|
16
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/xl_form_patch.rb")
|
17
|
+
app.files << File.join(lib_dir_path, "ProMotion/XLForm/value_transformer.rb")
|
18
|
+
|
19
|
+
app.pods do
|
20
|
+
pod 'XLForm', '~> 3.0.0'
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
class XLFormImageSelectorCell < XLFormBaseCell
|
2
|
+
|
3
|
+
attr_accessor :imageview, :text_label
|
4
|
+
|
5
|
+
def configure
|
6
|
+
super
|
7
|
+
@image_height = 100.0
|
8
|
+
@image_width = 100.0
|
9
|
+
self.selectionStyle = UITableViewCellSelectionStyleNone
|
10
|
+
self.backgroundColor = UIColor.whiteColor
|
11
|
+
self.separatorInset = UIEdgeInsetsZero
|
12
|
+
|
13
|
+
self.contentView.addSubview(imageview)
|
14
|
+
self.contentView.addSubview(text_label)
|
15
|
+
text_label.addObserver(self, forKeyPath: "text", options: NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew, context: 0)
|
16
|
+
end
|
17
|
+
|
18
|
+
def update
|
19
|
+
text_label.text = self.rowDescriptor.title
|
20
|
+
imageview.image = self.rowDescriptor.value
|
21
|
+
|
22
|
+
text_label.setFont(UIFont.preferredFontForTextStyle(UIFontTextStyleBody))
|
23
|
+
text_label.sizeToFit
|
24
|
+
updateConstraints
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.formDescriptorCellHeightForRowDescriptor(_)
|
28
|
+
120.0
|
29
|
+
end
|
30
|
+
|
31
|
+
def formDescriptorCellDidSelectedWithFormController(controller)
|
32
|
+
if NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1
|
33
|
+
alert = UIAlertController.alertControllerWithTitle(self.rowDescriptor.selectorTitle,
|
34
|
+
message: nil,
|
35
|
+
preferredStyle: UIAlertControllerStyleActionSheet)
|
36
|
+
|
37
|
+
alert.addAction(UIAlertAction.actionWithTitle(NSLocalizedString("Choose From Library", nil),
|
38
|
+
style: UIAlertActionStyleDefault,
|
39
|
+
handler: lambda { |_|
|
40
|
+
self.formViewController.dismissViewControllerAnimated(true,
|
41
|
+
completion: -> {
|
42
|
+
open_picker(UIImagePickerControllerSourceTypePhotoLibrary)
|
43
|
+
})
|
44
|
+
}))
|
45
|
+
|
46
|
+
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceTypeCamera)
|
47
|
+
alert.addAction(UIAlertAction.actionWithTitle(NSLocalizedString("Take Photo", nil),
|
48
|
+
style: UIAlertActionStyleDefault,
|
49
|
+
handler: lambda { |_|
|
50
|
+
self.formViewController.dismissViewControllerAnimated(true,
|
51
|
+
completion: -> {
|
52
|
+
open_picker(UIImagePickerControllerSourceTypeCamera)
|
53
|
+
})
|
54
|
+
}))
|
55
|
+
end
|
56
|
+
if self.formViewController.presentedViewController
|
57
|
+
self.formViewController.dismissViewControllerAnimated(true,
|
58
|
+
completion: -> {
|
59
|
+
self.formViewController.presentViewController(alert, animated: true, completion: nil)
|
60
|
+
})
|
61
|
+
else
|
62
|
+
self.formViewController.presentViewController(alert, animated: true, completion: nil)
|
63
|
+
end
|
64
|
+
|
65
|
+
else
|
66
|
+
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceTypeCamera)
|
67
|
+
action_sheet = UIActionSheet.alloc.initWithTitle(self.rowDescriptor.selectorTitle,
|
68
|
+
delegate: self,
|
69
|
+
cancelButtonTitle: NSLocalizedString("Cancel", nil),
|
70
|
+
destructiveButtonTitle: nil,
|
71
|
+
otherButtonTitles: NSLocalizedString("Choose From Library", nil), NSLocalizedString("Take Photo", nil), nil)
|
72
|
+
else
|
73
|
+
action_sheet = UIActionSheet.alloc.initWithTitle(self.rowDescriptor.selectorTitle,
|
74
|
+
delegate: self,
|
75
|
+
cancelButtonTitle: NSLocalizedString("Cancel", nil),
|
76
|
+
destructiveButtonTitle: nil,
|
77
|
+
otherButtonTitles: NSLocalizedString("Choose From Library", nil), nil)
|
78
|
+
end
|
79
|
+
action_sheet.tag = self.tag
|
80
|
+
action_sheet.showInView(self.formViewController.view)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def updateConstraints
|
85
|
+
ui_components = { "image" => imageview, "text" => text_label }
|
86
|
+
|
87
|
+
self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-16-[text]", options: 0, metrics: 0, views: ui_components))
|
88
|
+
self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-6-[text]", options: 0, metrics: 0, views: ui_components))
|
89
|
+
|
90
|
+
self.contentView.addConstraint(NSLayoutConstraint.constraintWithItem(imageview,
|
91
|
+
attribute: NSLayoutAttributeTop,
|
92
|
+
relatedBy: NSLayoutRelationEqual,
|
93
|
+
toItem: self.contentView,
|
94
|
+
attribute: NSLayoutAttributeTop,
|
95
|
+
multiplier: 1.0,
|
96
|
+
constant: 10.0))
|
97
|
+
|
98
|
+
self.contentView.addConstraint(NSLayoutConstraint.constraintWithItem(imageview,
|
99
|
+
attribute: NSLayoutAttributeBottom,
|
100
|
+
relatedBy: NSLayoutRelationEqual,
|
101
|
+
toItem: self.contentView,
|
102
|
+
attribute: NSLayoutAttributeBottom,
|
103
|
+
multiplier: 1.0,
|
104
|
+
constant: -10.0))
|
105
|
+
|
106
|
+
self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[image(width)]", options: 0, metrics: { "width" => @image_width }, views: ui_components))
|
107
|
+
self.contentView.addConstraint(NSLayoutConstraint.constraintWithItem(imageview,
|
108
|
+
attribute: NSLayoutAttributeCenterX,
|
109
|
+
relatedBy: NSLayoutRelationEqual,
|
110
|
+
toItem: self.contentView,
|
111
|
+
attribute: NSLayoutAttributeCenterX,
|
112
|
+
multiplier: 1.0,
|
113
|
+
constant: 0.0))
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
# trick to force the status bar to be hidden when presenting the UIImagePickerViewController
|
118
|
+
def navigationController(_, willShowViewController: _, animated: _)
|
119
|
+
UIApplication.sharedApplication.setStatusBarHidden true
|
120
|
+
end
|
121
|
+
|
122
|
+
def setImageValue(image)
|
123
|
+
self.rowDescriptor.value = image
|
124
|
+
imageview.image = image
|
125
|
+
end
|
126
|
+
|
127
|
+
def observeValueForKeyPath(key_path, ofObject: object, change: change, context: _)
|
128
|
+
if object == text_label && key_path == "text"
|
129
|
+
if change[NSKeyValueChangeKindKey] == NSKeyValueChangeSetting
|
130
|
+
text_label.sizeToFit
|
131
|
+
frame = text_label.frame
|
132
|
+
frame.origin = [16, 4]
|
133
|
+
text_label.frame = frame
|
134
|
+
self.contentView.needsUpdateConstraints
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def dealloc
|
140
|
+
text_label.removeObserver(self, forKeyPath: "text")
|
141
|
+
end
|
142
|
+
|
143
|
+
# UIActionSheetDelegate
|
144
|
+
def actionSheet(action_sheet, clickedButtonAtIndex: button_index)
|
145
|
+
return if button_index == action_sheet.cancelButtonIndex
|
146
|
+
|
147
|
+
title = action_sheet.buttonTitleAtIndex(button_index)
|
148
|
+
|
149
|
+
case title
|
150
|
+
when NSLocalizedString("Choose From Library", nil)
|
151
|
+
open_picker(UIImagePickerControllerSourceTypePhotoLibrary)
|
152
|
+
when NSLocalizedString("Take Photo", nil)
|
153
|
+
open_picker(UIImagePickerControllerSourceTypeCamera)
|
154
|
+
else
|
155
|
+
return
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def open_picker(source)
|
160
|
+
image_picker = UIImagePickerController.alloc.init
|
161
|
+
image_picker.delegate = self
|
162
|
+
image_picker.allowsEditing = true
|
163
|
+
image_picker.sourceType = source
|
164
|
+
|
165
|
+
if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad
|
166
|
+
if @popover_controller && @popover_controller.isPopoverVisible
|
167
|
+
@popover_controller.dismissPopoverAnimated(true)
|
168
|
+
end
|
169
|
+
@popover_controller = UIPopoverController.alloc.initWithContentViewController(image_picker)
|
170
|
+
Dispatch::Queue.main.async do
|
171
|
+
@popover_controller.presentPopoverFromRect(self.contentView.frame,
|
172
|
+
inView: self.formViewController.view,
|
173
|
+
permittedArrowDirections: UIPopoverArrowDirectionAny,
|
174
|
+
animated: true)
|
175
|
+
end
|
176
|
+
else
|
177
|
+
if self.formViewController.presentedViewController
|
178
|
+
self.formViewController.dismissViewControllerAnimated(true,
|
179
|
+
completion: -> {
|
180
|
+
self.formViewController.presentViewController(image_picker,
|
181
|
+
animated: true,
|
182
|
+
completion: nil)
|
183
|
+
})
|
184
|
+
else
|
185
|
+
self.formViewController.presentViewController(image_picker,
|
186
|
+
animated: true,
|
187
|
+
completion: nil)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# UIImagePickerControllerDelegate
|
193
|
+
def imagePickerController(_, didFinishPickingMediaWithInfo: info)
|
194
|
+
editedImage = info[UIImagePickerControllerEditedImage]
|
195
|
+
originalImage = info[UIImagePickerControllerOriginalImage]
|
196
|
+
if editedImage
|
197
|
+
imageToUse = editedImage
|
198
|
+
else
|
199
|
+
imageToUse = originalImage
|
200
|
+
end
|
201
|
+
setImageValue(imageToUse)
|
202
|
+
|
203
|
+
if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad
|
204
|
+
if @popover_controller and @popover_controller.isPopoverVisible
|
205
|
+
@popover_controller.dismissPopoverAnimated(true)
|
206
|
+
end
|
207
|
+
else
|
208
|
+
self.formViewController.dismissViewControllerAnimated(true, completion: nil)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Properties
|
213
|
+
def imageview
|
214
|
+
return @imageview if @imageview
|
215
|
+
|
216
|
+
@imageview = UIImageView.autolayoutView
|
217
|
+
@imageview.layer.masksToBounds = true
|
218
|
+
@imageview.contentMode = UIViewContentModeScaleAspectFit
|
219
|
+
@imageview
|
220
|
+
end
|
221
|
+
|
222
|
+
def text_label
|
223
|
+
return @text_label if @text_label
|
224
|
+
@text_label = UILabel.autolayoutView
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ProMotion
|
2
|
+
class ValueTransformer
|
3
|
+
def self.transformedValueClass
|
4
|
+
NSString
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.allowsReverseTransformation
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def transformedValue(value)
|
12
|
+
return nil if value.nil?
|
13
|
+
|
14
|
+
# best effort
|
15
|
+
value.inspect
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
module ProMotion
|
2
|
+
class XLForm
|
3
|
+
|
4
|
+
attr_reader :form_data
|
5
|
+
|
6
|
+
def initialize(form_data, opts={})
|
7
|
+
@form_data = form_data
|
8
|
+
@title = opts[:title] || ''
|
9
|
+
@required = opts[:required]
|
10
|
+
end
|
11
|
+
|
12
|
+
def build
|
13
|
+
form = XLFormDescriptor.formDescriptorWithTitle(@title)
|
14
|
+
form.addAsteriskToRequiredRowsTitle = (@required == :asterisks)
|
15
|
+
|
16
|
+
form_data.each do |section_data|
|
17
|
+
title = section_data[:title]
|
18
|
+
|
19
|
+
options = parse_section_options(section_data[:options])
|
20
|
+
insert_mode = section_insert_mode(section_data[:insert_mode])
|
21
|
+
|
22
|
+
section = XLFormSectionDescriptor.formSectionWithTitle(title, sectionOptions: options, sectionInsertMode: insert_mode)
|
23
|
+
if options.nonzero?
|
24
|
+
tag = section_data[:name]
|
25
|
+
mp("MutliValued section with no :name option", force_color: :red) unless tag
|
26
|
+
if tag.respond_to? :to_s
|
27
|
+
tag = tag.to_s
|
28
|
+
end
|
29
|
+
section.multivaluedTag = tag
|
30
|
+
end
|
31
|
+
section.footerTitle = section_data[:footer] if section_data[:footer]
|
32
|
+
|
33
|
+
add_proc section, :on_add, section_data[:on_add] if section_data[:on_add]
|
34
|
+
add_proc section, :on_remove, section_data[:on_remove] if section_data[:on_remove]
|
35
|
+
|
36
|
+
form.addFormSection(section)
|
37
|
+
|
38
|
+
section_data[:cells].each do |cell_data|
|
39
|
+
tag = cell_data[:name]
|
40
|
+
mp("Cell with no :name option", force_color: :red) unless tag
|
41
|
+
if tag.respond_to? :to_s
|
42
|
+
tag = tag.to_s
|
43
|
+
end
|
44
|
+
title = cell_data[:title]
|
45
|
+
type = cell_data[:type]
|
46
|
+
if type.nil? and cell_data[:cells]
|
47
|
+
type = :selector_push
|
48
|
+
end
|
49
|
+
|
50
|
+
cell = XLFormRowDescriptor.formRowDescriptorWithTag(tag, rowType: row_type(type), title: title)
|
51
|
+
|
52
|
+
cell.required = cell_data[:required]
|
53
|
+
|
54
|
+
properties = cell_data[:properties] || {}
|
55
|
+
|
56
|
+
# placeholder
|
57
|
+
cell.cellConfigAtConfigure.setObject(cell_data[:placeholder], forKey: "textField.placeholder") if cell_data[:placeholder]
|
58
|
+
|
59
|
+
# slider
|
60
|
+
if cell_data[:type] == :slider
|
61
|
+
min = properties[:min]
|
62
|
+
max = properties[:max]
|
63
|
+
step = properties[:step]
|
64
|
+
cell.cellConfigAtConfigure.setObject(min, forKey: "slider.minimumValue") if min
|
65
|
+
cell.cellConfigAtConfigure.setObject(max, forKey: "slider.maximumValue") if max
|
66
|
+
cell.cellConfigAtConfigure.setObject(step, forKey: "steps") if step
|
67
|
+
end
|
68
|
+
|
69
|
+
# dates
|
70
|
+
if [:date_inline, :datetime_inline, :time_inline, :date, :datetime, :time, :datepicker].include? cell_data[:type]
|
71
|
+
min = properties[:min]
|
72
|
+
max = properties[:max]
|
73
|
+
cell.cellConfigAtConfigure.setObject(min, forKey: "minimumDate") if min
|
74
|
+
cell.cellConfigAtConfigure.setObject(max, forKey: "maximumDate") if max
|
75
|
+
end
|
76
|
+
|
77
|
+
cell_class = cell_data[:cell_class]
|
78
|
+
|
79
|
+
# image
|
80
|
+
if cell_data[:type] == :image
|
81
|
+
cell_class = XLFormImageSelectorCell if cell_class.nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
cell.cellClass = cell_class if cell_class
|
85
|
+
|
86
|
+
# subcells
|
87
|
+
if cell_data[:cells]
|
88
|
+
cell.action.viewControllerClass = ProMotion::XLSubFormScreen
|
89
|
+
cell.action.cells = cell_data[:cells]
|
90
|
+
cell.valueTransformer = ProMotion::ValueTransformer
|
91
|
+
end
|
92
|
+
|
93
|
+
# also accept default XLForm viewControllerClass
|
94
|
+
cell.action.viewControllerClass = cell_data[:view_controller_class] if cell_data[:view_controller_class]
|
95
|
+
cell.valueTransformer = cell_data[:value_transformer] if cell_data[:value_transformer]
|
96
|
+
|
97
|
+
# callbacks
|
98
|
+
add_proc cell, :on_change, cell_data[:on_change] if cell_data[:on_change]
|
99
|
+
add_proc cell, :on_add, cell_data[:on_add] if cell_data[:on_add]
|
100
|
+
add_proc cell, :on_remove, cell_data[:on_remove] if cell_data[:on_remove]
|
101
|
+
|
102
|
+
cell.selectorTitle = cell_data[:selector_title] if cell_data[:selector_title]
|
103
|
+
options = parse_options(cell_data[:options])
|
104
|
+
cell.selectorOptions = options
|
105
|
+
|
106
|
+
value = cell_data[:value]
|
107
|
+
if value and options
|
108
|
+
options.each do |opt|
|
109
|
+
if opt.formValue == value
|
110
|
+
value = opt
|
111
|
+
break
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
cell.value = value if value
|
117
|
+
|
118
|
+
cell.disabled = !cell_data[:enabled] if cell_data[:enabled]
|
119
|
+
|
120
|
+
section.addFormRow(cell)
|
121
|
+
|
122
|
+
# multi sections
|
123
|
+
if section.multivaluedTag
|
124
|
+
cell.action.required = @required
|
125
|
+
section.multivaluedRowTemplate = cell.copy
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
form
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_callback(row, event)
|
134
|
+
return if @blocks.nil? or @blocks[row].nil? or @blocks[row][event].nil?
|
135
|
+
|
136
|
+
@blocks[row][event]
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def add_proc(tag, event, block)
|
142
|
+
@blocks ||= {}
|
143
|
+
@blocks[tag] ||= {}
|
144
|
+
@blocks[tag][event] = block.respond_to?('weak!') ? block.weak! : block
|
145
|
+
end
|
146
|
+
|
147
|
+
def parse_options(options)
|
148
|
+
return nil if options.nil? or options.empty?
|
149
|
+
|
150
|
+
options.map do |key, text|
|
151
|
+
val = key
|
152
|
+
if val.is_a? Symbol
|
153
|
+
val = val.to_s
|
154
|
+
end
|
155
|
+
XLFormOptionsObject.formOptionsObjectWithValue(val, displayText: text)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def parse_section_options(options)
|
160
|
+
return section_options(:none) if options.nil?
|
161
|
+
|
162
|
+
opts = section_options(:none)
|
163
|
+
options.each do |opt|
|
164
|
+
opts |= section_options(opt)
|
165
|
+
end
|
166
|
+
|
167
|
+
opts
|
168
|
+
end
|
169
|
+
|
170
|
+
def section_insert_mode(symbol)
|
171
|
+
{
|
172
|
+
last_row: XLFormSectionInsertModeLastRow,
|
173
|
+
button: XLFormSectionInsertModeButton
|
174
|
+
}[symbol] || symbol || XLFormSectionInsertModeLastRow
|
175
|
+
end
|
176
|
+
|
177
|
+
def section_options(symbol)
|
178
|
+
{
|
179
|
+
none: XLFormSectionOptionNone,
|
180
|
+
insert: XLFormSectionOptionCanInsert,
|
181
|
+
delete: XLFormSectionOptionCanDelete,
|
182
|
+
reorder: XLFormSectionOptionCanReorder
|
183
|
+
}[symbol] || symbol || XLFormSectionOptionNone
|
184
|
+
end
|
185
|
+
|
186
|
+
def row_type(symbol)
|
187
|
+
{
|
188
|
+
text: XLFormRowDescriptorTypeText,
|
189
|
+
name: XLFormRowDescriptorTypeName,
|
190
|
+
url: XLFormRowDescriptorTypeURL,
|
191
|
+
email: XLFormRowDescriptorTypeEmail,
|
192
|
+
password: XLFormRowDescriptorTypePassword,
|
193
|
+
number: XLFormRowDescriptorTypeNumber,
|
194
|
+
phone: XLFormRowDescriptorTypePhone,
|
195
|
+
twitter: XLFormRowDescriptorTypeTwitter,
|
196
|
+
account: XLFormRowDescriptorTypeAccount,
|
197
|
+
integer: XLFormRowDescriptorTypeInteger,
|
198
|
+
decimal: XLFormRowDescriptorTypeDecimal,
|
199
|
+
textview: XLFormRowDescriptorTypeTextView,
|
200
|
+
selector_push: XLFormRowDescriptorTypeSelectorPush,
|
201
|
+
selector_popover: XLFormRowDescriptorTypeSelectorPopover,
|
202
|
+
selector_action_sheet: XLFormRowDescriptorTypeSelectorActionSheet,
|
203
|
+
selector_alert_view: XLFormRowDescriptorTypeSelectorAlertView,
|
204
|
+
selector_picker_view: XLFormRowDescriptorTypeSelectorPickerView,
|
205
|
+
selector_picker_view_inline: XLFormRowDescriptorTypeSelectorPickerViewInline,
|
206
|
+
multiple_selector: XLFormRowDescriptorTypeMultipleSelector,
|
207
|
+
multiple_selector_popover: XLFormRowDescriptorTypeMultipleSelectorPopover,
|
208
|
+
selector_left_right: XLFormRowDescriptorTypeSelectorLeftRight,
|
209
|
+
selector_segmented_control: XLFormRowDescriptorTypeSelectorSegmentedControl,
|
210
|
+
date_inline: XLFormRowDescriptorTypeDateInline,
|
211
|
+
datetime_inline: XLFormRowDescriptorTypeDateTimeInline,
|
212
|
+
time_inline: XLFormRowDescriptorTypeTimeInline,
|
213
|
+
countdown_timer_inline: XLFormRowDescriptorTypeCountDownTimerInline,
|
214
|
+
date: XLFormRowDescriptorTypeDate,
|
215
|
+
datetime: XLFormRowDescriptorTypeDateTime,
|
216
|
+
time: XLFormRowDescriptorTypeTime,
|
217
|
+
countdown_timer: XLFormRowDescriptorTypeCountDownTimer,
|
218
|
+
datepicker: XLFormRowDescriptorTypeDatePicker,
|
219
|
+
picker: XLFormRowDescriptorTypePicker,
|
220
|
+
slider: XLFormRowDescriptorTypeSlider,
|
221
|
+
check: XLFormRowDescriptorTypeBooleanCheck,
|
222
|
+
switch: XLFormRowDescriptorTypeBooleanSwitch,
|
223
|
+
button: XLFormRowDescriptorTypeButton,
|
224
|
+
info: XLFormRowDescriptorTypeInfo,
|
225
|
+
step_counter: XLFormRowDescriptorTypeStepCounter,
|
226
|
+
image: 'XLFormRowDescriptorTypeImage'
|
227
|
+
}[symbol] || symbol
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Monkey patch
|
2
|
+
class XLFormAction
|
3
|
+
|
4
|
+
attr_accessor :cells
|
5
|
+
attr_accessor :required
|
6
|
+
|
7
|
+
alias :old_copyWithZone :copyWithZone
|
8
|
+
|
9
|
+
def copyWithZone(zone)
|
10
|
+
action_copy = old_copyWithZone(zone)
|
11
|
+
|
12
|
+
action_copy.cells = self.cells.copy
|
13
|
+
action_copy.required = self.required
|
14
|
+
action_copy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class XLFormRowDescriptor
|
19
|
+
|
20
|
+
alias :old_copyWithZone :copyWithZone
|
21
|
+
|
22
|
+
def copyWithZone(zone)
|
23
|
+
row_descriptor_copy = old_copyWithZone(zone)
|
24
|
+
|
25
|
+
row_descriptor_copy.valueTransformer = self.valueTransformer
|
26
|
+
row_descriptor_copy
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module ProMotion
|
2
|
+
class XLFormScreen < XlFormViewController
|
3
|
+
include ProMotion::ScreenModule
|
4
|
+
include ProMotion::XLFormModule
|
5
|
+
|
6
|
+
attr_reader :form_object
|
7
|
+
|
8
|
+
def viewDidLoad
|
9
|
+
super
|
10
|
+
update_form_data
|
11
|
+
|
12
|
+
form_options = self.class.get_form_options
|
13
|
+
|
14
|
+
if form_options[:on_cancel]
|
15
|
+
on_cancel = form_options[:on_cancel]
|
16
|
+
title = NSLocalizedString('Cancel', nil)
|
17
|
+
item = :cancel
|
18
|
+
if on_cancel.is_a? Hash
|
19
|
+
title = on_cancel[:title] if on_cancel[:title]
|
20
|
+
item = on_cancel[:item] if on_cancel[:item]
|
21
|
+
end
|
22
|
+
|
23
|
+
set_nav_bar_button :left, {
|
24
|
+
system_item: item,
|
25
|
+
title: title,
|
26
|
+
action: 'on_cancel:'
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
if form_options[:on_save]
|
31
|
+
on_cancel = form_options[:on_save]
|
32
|
+
title = NSLocalizedString('Save', nil)
|
33
|
+
item = :save
|
34
|
+
if on_cancel.is_a? Hash
|
35
|
+
title = on_cancel[:title] if on_cancel[:title]
|
36
|
+
item = on_cancel[:item] if on_cancel[:item]
|
37
|
+
end
|
38
|
+
|
39
|
+
set_nav_bar_button :right, {
|
40
|
+
system_item: item,
|
41
|
+
title: title,
|
42
|
+
action: 'on_save:'
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def form_data
|
48
|
+
PM.logger.info "You need to implement a `form_data` method in #{self.class.to_s}."
|
49
|
+
[]
|
50
|
+
end
|
51
|
+
|
52
|
+
def update_form_data
|
53
|
+
form_options = self.class.get_form_options
|
54
|
+
title = self.class.title
|
55
|
+
required = form_options[:required]
|
56
|
+
|
57
|
+
@form_builder = PM::XLForm.new(self.form_data,
|
58
|
+
{
|
59
|
+
title: title,
|
60
|
+
required: required
|
61
|
+
})
|
62
|
+
@form_object = @form_builder.build
|
63
|
+
self.form = @form_object
|
64
|
+
end
|
65
|
+
|
66
|
+
def values
|
67
|
+
values = {}
|
68
|
+
formValues.each do |key, value|
|
69
|
+
if value.is_a? XLFormOptionsObject
|
70
|
+
value = value.formValue
|
71
|
+
end
|
72
|
+
values[key] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
values
|
76
|
+
end
|
77
|
+
|
78
|
+
def valid?
|
79
|
+
validation_errors.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
alias :validation_errors :formValidationErrors
|
83
|
+
|
84
|
+
def display_errors
|
85
|
+
return if valid?
|
86
|
+
|
87
|
+
errors = validation_errors.map do |error|
|
88
|
+
error.localizedDescription
|
89
|
+
end
|
90
|
+
|
91
|
+
if NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1
|
92
|
+
alert = UIAlertController.alertControllerWithTitle(NSLocalizedString('Error', nil),
|
93
|
+
message: errors.join(', '),
|
94
|
+
preferredStyle: UIAlertControllerStyleAlert)
|
95
|
+
action = UIAlertAction.actionWithTitle(NSLocalizedString('OK', nil),
|
96
|
+
style: UIAlertActionStyleDefault,
|
97
|
+
handler: nil)
|
98
|
+
alert.addAction(action)
|
99
|
+
presentViewController(alert, animated: true, completion: nil)
|
100
|
+
else
|
101
|
+
alert = UIAlertView.new
|
102
|
+
alert.title = NSLocalizedString('Error', nil)
|
103
|
+
alert.message = errors.join(', ')
|
104
|
+
alert.show
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
def on_cancel(_)
|
110
|
+
form_options = self.class.get_form_options
|
111
|
+
if form_options[:on_cancel]
|
112
|
+
on_cancel = form_options[:on_cancel]
|
113
|
+
if on_cancel.is_a? Hash
|
114
|
+
on_cancel = on_cancel[:action]
|
115
|
+
end
|
116
|
+
try on_cancel
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def on_save(_)
|
121
|
+
unless valid?
|
122
|
+
display_errors
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
form_options = self.class.get_form_options
|
127
|
+
if form_options[:on_save]
|
128
|
+
on_save = form_options[:on_save]
|
129
|
+
if on_save.is_a? Hash
|
130
|
+
on_save = on_save[:action]
|
131
|
+
end
|
132
|
+
try on_save, values
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
## XLFormDescriptorDelegate
|
137
|
+
def formSectionHasBeenAdded(section, atIndex: _)
|
138
|
+
super
|
139
|
+
callback = @form_builder.get_callback(section, :on_add)
|
140
|
+
callback.call if callback
|
141
|
+
end
|
142
|
+
|
143
|
+
def formSectionHasBeenRemoved(section, atIndex: _)
|
144
|
+
super
|
145
|
+
callback = @form_builder.get_callback(section, :on_remove)
|
146
|
+
callback.call if callback
|
147
|
+
end
|
148
|
+
|
149
|
+
def formRowHasBeenAdded(row, atIndexPath: _)
|
150
|
+
super
|
151
|
+
callback = @form_builder.get_callback(row, :on_add)
|
152
|
+
callback.call if callback
|
153
|
+
end
|
154
|
+
|
155
|
+
def formRowHasBeenRemoved(row, atIndexPath: _)
|
156
|
+
super
|
157
|
+
callback = @form_builder.get_callback(row, :on_remove)
|
158
|
+
callback.call if callback
|
159
|
+
end
|
160
|
+
|
161
|
+
def formRowDescriptorValueHasChanged(row, oldValue: old_value, newValue: new_value)
|
162
|
+
super
|
163
|
+
callback = @form_builder.get_callback(row, :on_change)
|
164
|
+
callback.call(old_value, new_value) if callback
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ProMotion
|
2
|
+
class XlFormViewController < XLFormViewController
|
3
|
+
def self.new(args = {})
|
4
|
+
s = self.alloc.init
|
5
|
+
s.screen_init(args) if s.respond_to?(:screen_init)
|
6
|
+
s
|
7
|
+
end
|
8
|
+
|
9
|
+
def loadView
|
10
|
+
self.respond_to?(:load_view) ? self.load_view : super
|
11
|
+
end
|
12
|
+
|
13
|
+
def viewDidLoad
|
14
|
+
super
|
15
|
+
self.view_did_load if self.respond_to?(:view_did_load)
|
16
|
+
end
|
17
|
+
|
18
|
+
def viewWillAppear(animated)
|
19
|
+
super
|
20
|
+
self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
|
21
|
+
end
|
22
|
+
|
23
|
+
def viewDidAppear(animated)
|
24
|
+
super
|
25
|
+
self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
|
26
|
+
end
|
27
|
+
|
28
|
+
def viewWillDisappear(animated)
|
29
|
+
self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def viewDidDisappear(animated)
|
34
|
+
self.view_did_disappear(animated) if self.respond_to?("view_did_disappear:")
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def shouldAutorotateToInterfaceOrientation(orientation)
|
39
|
+
self.should_rotate(orientation)
|
40
|
+
end
|
41
|
+
|
42
|
+
def shouldAutorotate
|
43
|
+
self.should_autorotate
|
44
|
+
end
|
45
|
+
|
46
|
+
def willRotateToInterfaceOrientation(orientation, duration:duration)
|
47
|
+
self.will_rotate(orientation, duration)
|
48
|
+
end
|
49
|
+
|
50
|
+
def didRotateFromInterfaceOrientation(orientation)
|
51
|
+
self.on_rotate
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ProMotion
|
2
|
+
class XLSubFormScreen < XLFormScreen
|
3
|
+
attr_accessor :rowDescriptor
|
4
|
+
|
5
|
+
def form_data
|
6
|
+
[
|
7
|
+
{
|
8
|
+
title: rowDescriptor.title,
|
9
|
+
cells: rowDescriptor.action.cells.map do |cell|
|
10
|
+
tag = cell[:name]
|
11
|
+
if tag.respond_to? :to_s
|
12
|
+
tag = tag.to_s
|
13
|
+
end
|
14
|
+
if rowDescriptor and rowDescriptor.value and rowDescriptor.value[tag]
|
15
|
+
cell.merge({ value: rowDescriptor.value[tag] })
|
16
|
+
else
|
17
|
+
cell
|
18
|
+
end
|
19
|
+
end
|
20
|
+
}
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_form_data
|
25
|
+
title = rowDescriptor.title
|
26
|
+
required = rowDescriptor.action.required
|
27
|
+
|
28
|
+
@form_builder = PM::XLForm.new(self.form_data,
|
29
|
+
{
|
30
|
+
title: title,
|
31
|
+
required: required
|
32
|
+
})
|
33
|
+
@form_object = @form_builder.build
|
34
|
+
self.form = @form_object
|
35
|
+
end
|
36
|
+
|
37
|
+
## XLFormDescriptorDelegate
|
38
|
+
def formRowDescriptorValueHasChanged(row, oldValue: old_value, newValue: new_value)
|
39
|
+
super
|
40
|
+
rowDescriptor.value = values
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ProMotion-XLForm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benjamin Michotte
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ProMotion
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: motion-cocoapods
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: motion-redgreen
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Adds XLForm screen support to ProMotion.
|
70
|
+
email:
|
71
|
+
- bmichotte@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- README.md
|
77
|
+
- lib/ProMotion-XLForm.rb
|
78
|
+
- lib/ProMotion/XLForm/cells/xl_form_image_selector_cell.rb
|
79
|
+
- lib/ProMotion/XLForm/value_transformer.rb
|
80
|
+
- lib/ProMotion/XLForm/xl_form.rb
|
81
|
+
- lib/ProMotion/XLForm/xl_form_class_methods.rb
|
82
|
+
- lib/ProMotion/XLForm/xl_form_module.rb
|
83
|
+
- lib/ProMotion/XLForm/xl_form_patch.rb
|
84
|
+
- lib/ProMotion/XLForm/xl_form_screen.rb
|
85
|
+
- lib/ProMotion/XLForm/xl_form_view_controller.rb
|
86
|
+
- lib/ProMotion/XLForm/xl_sub_form_screen.rb
|
87
|
+
homepage: https://github.com/bmichotte/ProMotion-XLForm
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.3
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Adds PM::XLFormScreen support to ProMotion, similar to ProMotion-form.
|
111
|
+
test_files: []
|