ProMotion-XLForm 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,343 +1,86 @@
1
1
  module ProMotion
2
2
  class XLForm
3
3
 
4
+ include ProMotion::XLFormHelper
5
+ include ProMotion::XLFormCellBuilder
6
+ include ProMotion::XLFormSectionBuilder
7
+
4
8
  attr_reader :form_data
5
9
 
6
10
  def initialize(form_data, opts={})
7
11
  @form_data = form_data
8
- @title = opts[:title] || ''
9
- @required = opts[:required]
12
+ @title = opts[:title] || ''
13
+ @required = opts[:required]
10
14
  end
11
15
 
12
16
  def build
13
- form = XLFormDescriptor.formDescriptorWithTitle(@title)
17
+ form = XLFormDescriptor.formDescriptorWithTitle(@title)
14
18
  form.addAsteriskToRequiredRowsTitle = (@required == :asterisks)
15
19
 
16
20
  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
-
21
+ section = create_section(section_data)
36
22
  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
- # step_counter
60
- if cell_data[:type] == :step_counter
61
- min = properties[:min]
62
- max = properties[:max]
63
- step = properties[:step]
64
-
65
- cell.cellConfigAtConfigure.setObject(true, forKey: "stepControl.wraps")
66
- cell.cellConfigAtConfigure.setObject(min, forKey: "stepControl.minimumValue") if min
67
- cell.cellConfigAtConfigure.setObject(max, forKey: "stepControl.maximumValue") if max
68
- cell.cellConfigAtConfigure.setObject(step, forKey: "stepControl.maximumValue") if step
69
- end
70
-
71
- # slider
72
- if cell_data[:type] == :slider
73
- min = properties[:min]
74
- max = properties[:max]
75
- step = properties[:step]
76
- cell.cellConfigAtConfigure.setObject(min, forKey: "slider.minimumValue") if min
77
- cell.cellConfigAtConfigure.setObject(max, forKey: "slider.maximumValue") if max
78
- cell.cellConfigAtConfigure.setObject(step, forKey: "steps") if step
79
- end
80
-
81
- # dates
82
- if [:date_inline, :datetime_inline, :time_inline, :date, :datetime, :time, :datepicker].include? cell_data[:type]
83
- min = properties[:min]
84
- max = properties[:max]
85
- cell.cellConfigAtConfigure.setObject(min, forKey: "minimumDate") if min
86
- cell.cellConfigAtConfigure.setObject(max, forKey: "maximumDate") if max
87
- end
88
-
89
- cell_class = cell_data[:cell_class]
90
-
91
- # image
92
- if cell_data[:type] == :image
93
- cell_class = XLFormImageSelectorCell if cell_class.nil?
94
- elsif cell_data[:type] == :color
95
- cell_class = XLFormColorSelectorCell if cell_class.nil?
96
- end
97
-
98
- cell.cellClass = cell_class if cell_class
99
-
100
- # subcells
101
- if cell_data[:cells]
102
- cell.action.viewControllerClass = ProMotion::XLSubFormScreen
103
- cell.action.cells = cell_data[:cells]
104
- cell.valueTransformer = ProMotion::ValueTransformer
105
- end
106
-
107
- # also accept default XLForm viewControllerClass
108
- cell.action.viewControllerClass = cell_data[:view_controller_class] if cell_data[:view_controller_class]
109
- cell.valueTransformer = cell_data[:value_transformer] if cell_data[:value_transformer]
110
-
111
- # callbacks
112
- add_proc cell, :on_change, cell_data[:on_change] if cell_data[:on_change]
113
- add_proc cell, :on_add, cell_data[:on_add] if cell_data[:on_add]
114
- add_proc cell, :on_remove, cell_data[:on_remove] if cell_data[:on_remove]
115
-
116
- cell.selectorTitle = cell_data[:selector_title] if cell_data[:selector_title]
117
- cell.options = cell_data[:options]
118
-
119
- cell.disabled = !cell_data.fetch(:enabled, true)
120
-
121
- # row visible
122
- if cell_data[:hidden]
123
- predicate = cell_data[:hidden]
124
- if predicate.is_a?(Hash)
125
- tag = predicate[:name]
126
- operand = case predicate[:is]
127
- when :equal
128
- '=='
129
- when :not_equal
130
- '!='
131
- when :contains
132
- 'contains'
133
- when :not_contains
134
- 'not contains'
135
- else
136
- predicate[:is]
137
- end
138
- value = predicate[:value]
139
- else
140
- match = /(:?[a-zA-Z_]+)\s+(==|!=|contains|not contains)\s+(.*)/.match(predicate)
141
- if match and match.length == 4
142
- # todo better than ignore ?
143
- tag = match[1]
144
- operand = match[2]
145
- value = match[3]
146
- if value =~ /"(.*)"/
147
- value = value[1, value.length - 2]
148
- end
149
- end
150
- end
151
-
152
- if tag and operand
153
- if tag.is_a?(Symbol)
154
- tag = tag.to_s
155
- elsif tag.start_with?(':')
156
- tag[0] = ''
157
- end
158
- value = case value
159
- when 'true', :true, true
160
- 0
161
- when 'false', :false, false
162
- 1
163
- when String
164
- "\"#{value}\""
165
- else
166
- value
167
- end
168
-
169
- if operand == 'contains'
170
- cell.hidden = "$#{tag} contains[c] #{value}"
171
- elsif operand == 'not contains'
172
- cell.hidden = "not($#{tag} contains[c] #{value})"
173
- else
174
- cell.hidden = "$#{tag} #{operand} #{value}"
175
- end
176
- else
177
- mp "#{cell_data[:visible]} can not be parsed", force_color: :red
178
- end
179
- end
180
-
181
- # validators
182
- if cell_data[:validators]
183
- validators = cell_data[:validators]
184
- validators.each do |key, value|
185
- validator = case key
186
- when :email
187
- XLFormValidator.emailValidator
188
- when :regex
189
- regex = value[:regex]
190
- if regex.is_a?(String)
191
- XLFormRegexValidator.formRegexValidatorWithMsg(value[:message], regex: regex)
192
- elsif regex.is_a?(Regexp)
193
- ProMotion::RegexValidator.validator(value[:message], regex)
194
- else
195
- mp "Invalid regex : #{regex.inspect}. Please provides a Regexp or a String", force_color: :red
196
- nil
197
- end
198
- when :url
199
- ProMotion::UrlValidator.validator
200
- else
201
- if value.is_a?(ProMotion::Validator) or value.respond_to?(:isValid)
202
- value
203
- else
204
- mp "Invalid validator : #{key}", force_color: :red
205
- nil
206
- end
207
- end
208
-
209
- if validator
210
- cell.addValidator(validator)
211
- end
212
- end
213
- end
214
-
215
- # customization
216
- appearance = cell_data[:appearance]
217
- if appearance
218
- cell.cellConfig["textLabel.font"] = appearance[:font] if appearance[:font]
219
- cell.cellConfig["textLabel.textColor"] = appearance[:color] if appearance[:color]
220
- cell.cellConfig["detailTextLabel.font"] = appearance[:detail_font] if appearance[:detail_font]
221
- cell.cellConfig["detailTextLabel.textColor"] = appearance[:detail_color] if appearance[:detail_color]
222
- cell.cellConfig["backgroundColor"] = appearance[:background_color] if appearance[:background_color]
223
-
224
- appearance.delete_if {|k,v| k.is_a?(Symbol)}.each do |k,v|
225
- cell.cellConfig[k] = v
226
- end
227
- end
228
-
229
- value = cell_data[:value]
230
- if value and cell.selectorOptions
231
- cell.selectorOptions.each do |opt|
232
- if opt.formValue == value
233
- value = opt
234
- break
235
- end
236
- end
237
- end
238
-
239
- if value === true or value === false
240
- value = value ? 1 : 0
241
- end
242
-
243
- cell.value = value
244
-
245
- section.addFormRow(cell)
246
-
247
- # multi sections
248
- if section.multivaluedTag
249
- cell.action.required = @required
250
- section.multivaluedRowTemplate = cell.copy
251
- end
252
- end
253
23
  end
254
24
 
255
25
  form
256
26
  end
257
27
 
258
- def get_callback(row, event)
259
- return if @blocks.nil? or @blocks[row].nil? or @blocks[row][event].nil?
28
+ def get_callback(descriptor, event)
29
+ tag = descriptor.respond_to?(:multivaluedTag) ? descriptor.multivaluedTag : descriptor.tag
30
+ return if @blocks.nil? || @blocks[tag].nil? || @blocks[tag][event].nil?
260
31
 
261
- @blocks[row][event]
32
+ @blocks[tag][event]
262
33
  end
263
34
 
264
35
  private
265
-
266
36
  def add_proc(tag, event, block)
267
- @blocks ||= {}
268
- @blocks[tag] ||= {}
37
+ @blocks ||= {}
38
+ @blocks[tag] ||= {}
269
39
  @blocks[tag][event] = block.respond_to?('weak!') ? block.weak! : block
270
40
  end
271
41
 
272
- def parse_section_options(options)
273
- return section_options(:none) if options.nil?
274
-
275
- opts = section_options(:none)
276
- options.each do |opt|
277
- opts |= section_options(opt)
278
- end
279
-
280
- opts
281
- end
282
-
283
- def section_insert_mode(symbol)
284
- {
285
- last_row: XLFormSectionInsertModeLastRow,
286
- button: XLFormSectionInsertModeButton
287
- }[symbol] || symbol || XLFormSectionInsertModeLastRow
288
- end
289
-
290
- def section_options(symbol)
291
- {
292
- none: XLFormSectionOptionNone,
293
- insert: XLFormSectionOptionCanInsert,
294
- delete: XLFormSectionOptionCanDelete,
295
- reorder: XLFormSectionOptionCanReorder
296
- }[symbol] || symbol || XLFormSectionOptionNone
297
- end
298
-
299
42
  def row_type(symbol)
300
43
  {
301
- text: XLFormRowDescriptorTypeText,
302
- name: XLFormRowDescriptorTypeName,
303
- url: XLFormRowDescriptorTypeURL,
304
- email: XLFormRowDescriptorTypeEmail,
305
- password: XLFormRowDescriptorTypePassword,
306
- number: XLFormRowDescriptorTypeNumber,
307
- phone: XLFormRowDescriptorTypePhone,
308
- twitter: XLFormRowDescriptorTypeTwitter,
309
- account: XLFormRowDescriptorTypeAccount,
310
- integer: XLFormRowDescriptorTypeInteger,
311
- decimal: XLFormRowDescriptorTypeDecimal,
312
- textview: XLFormRowDescriptorTypeTextView,
313
- selector_push: XLFormRowDescriptorTypeSelectorPush,
314
- selector_popover: XLFormRowDescriptorTypeSelectorPopover,
315
- selector_action_sheet: XLFormRowDescriptorTypeSelectorActionSheet,
316
- selector_alert_view: XLFormRowDescriptorTypeSelectorAlertView,
317
- selector_picker_view: XLFormRowDescriptorTypeSelectorPickerView,
318
- selector_picker_view_inline: XLFormRowDescriptorTypeSelectorPickerViewInline,
319
- multiple_selector: XLFormRowDescriptorTypeMultipleSelector,
320
- multiple_selector_popover: XLFormRowDescriptorTypeMultipleSelectorPopover,
321
- selector_left_right: XLFormRowDescriptorTypeSelectorLeftRight,
322
- selector_segmented_control: XLFormRowDescriptorTypeSelectorSegmentedControl,
323
- date_inline: XLFormRowDescriptorTypeDateInline,
324
- datetime_inline: XLFormRowDescriptorTypeDateTimeInline,
325
- time_inline: XLFormRowDescriptorTypeTimeInline,
326
- countdown_timer_inline: XLFormRowDescriptorTypeCountDownTimerInline,
327
- date: XLFormRowDescriptorTypeDate,
328
- datetime: XLFormRowDescriptorTypeDateTime,
329
- time: XLFormRowDescriptorTypeTime,
330
- countdown_timer: XLFormRowDescriptorTypeCountDownTimer,
331
- datepicker: XLFormRowDescriptorTypeDatePicker,
332
- picker: XLFormRowDescriptorTypePicker,
333
- slider: XLFormRowDescriptorTypeSlider,
334
- check: XLFormRowDescriptorTypeBooleanCheck,
335
- switch: XLFormRowDescriptorTypeBooleanSwitch,
336
- button: XLFormRowDescriptorTypeButton,
337
- info: XLFormRowDescriptorTypeInfo,
338
- step_counter: XLFormRowDescriptorTypeStepCounter,
339
- image: 'XLFormRowDescriptorTypeImage',
340
- color: 'XLFormRowDescriptorTypeColor',
44
+ text: XLFormRowDescriptorTypeText,
45
+ name: XLFormRowDescriptorTypeName,
46
+ url: XLFormRowDescriptorTypeURL,
47
+ email: XLFormRowDescriptorTypeEmail,
48
+ password: XLFormRowDescriptorTypePassword,
49
+ number: XLFormRowDescriptorTypeNumber,
50
+ phone: XLFormRowDescriptorTypePhone,
51
+ twitter: XLFormRowDescriptorTypeTwitter,
52
+ account: XLFormRowDescriptorTypeAccount,
53
+ integer: XLFormRowDescriptorTypeInteger,
54
+ decimal: XLFormRowDescriptorTypeDecimal,
55
+ textview: XLFormRowDescriptorTypeTextView,
56
+ selector_push: XLFormRowDescriptorTypeSelectorPush,
57
+ selector_popover: XLFormRowDescriptorTypeSelectorPopover,
58
+ selector_action_sheet: XLFormRowDescriptorTypeSelectorActionSheet,
59
+ selector_alert_view: XLFormRowDescriptorTypeSelectorAlertView,
60
+ selector_picker_view: XLFormRowDescriptorTypeSelectorPickerView,
61
+ selector_picker_view_inline: XLFormRowDescriptorTypeSelectorPickerViewInline,
62
+ multiple_selector: XLFormRowDescriptorTypeMultipleSelector,
63
+ multiple_selector_popover: XLFormRowDescriptorTypeMultipleSelectorPopover,
64
+ selector_left_right: XLFormRowDescriptorTypeSelectorLeftRight,
65
+ selector_segmented_control: XLFormRowDescriptorTypeSelectorSegmentedControl,
66
+ date_inline: XLFormRowDescriptorTypeDateInline,
67
+ datetime_inline: XLFormRowDescriptorTypeDateTimeInline,
68
+ time_inline: XLFormRowDescriptorTypeTimeInline,
69
+ countdown_timer_inline: XLFormRowDescriptorTypeCountDownTimerInline,
70
+ date: XLFormRowDescriptorTypeDate,
71
+ datetime: XLFormRowDescriptorTypeDateTime,
72
+ time: XLFormRowDescriptorTypeTime,
73
+ countdown_timer: XLFormRowDescriptorTypeCountDownTimer,
74
+ datepicker: XLFormRowDescriptorTypeDatePicker,
75
+ picker: XLFormRowDescriptorTypePicker,
76
+ slider: XLFormRowDescriptorTypeSlider,
77
+ check: XLFormRowDescriptorTypeBooleanCheck,
78
+ switch: XLFormRowDescriptorTypeBooleanSwitch,
79
+ button: XLFormRowDescriptorTypeButton,
80
+ info: XLFormRowDescriptorTypeInfo,
81
+ step_counter: XLFormRowDescriptorTypeStepCounter,
82
+ image: 'XLFormRowDescriptorTypeImage',
83
+ color: 'XLFormRowDescriptorTypeColor',
341
84
  }[symbol] || symbol
342
85
  end
343
86
 
@@ -0,0 +1,182 @@
1
+ module ProMotion
2
+ module XLFormCellBuilder
3
+
4
+ def create_cell(cell_data)
5
+ tag = cell_data[:name]
6
+ mp("Cell with no :name option", force_color: :red) unless tag
7
+ if tag.respond_to? :to_s
8
+ tag = tag.to_s
9
+ end
10
+ title = cell_data[:title]
11
+ type = cell_data[:type]
12
+ if type.nil? && cell_data[:cells]
13
+ type = :selector_push
14
+ end
15
+
16
+ cell = XLFormRowDescriptor.formRowDescriptorWithTag(tag, rowType: row_type(type), title: title)
17
+ cell.cell_data = cell_data
18
+
19
+ cell.required = cell_data[:required]
20
+
21
+ properties = cell_data[:properties] || {}
22
+
23
+ # placeholder
24
+ if cell_data[:placeholder]
25
+ if type == :textview
26
+ cell.cellConfigAtConfigure.setObject(cell_data[:placeholder], forKey: "textView.placeholder")
27
+ else
28
+ cell.cellConfigAtConfigure.setObject(cell_data[:placeholder], forKey: "textField.placeholder")
29
+ end
30
+ end
31
+
32
+ # step_counter
33
+ if cell_data[:type] == :step_counter
34
+ min = properties[:min]
35
+ max = properties[:max]
36
+ step = properties[:step]
37
+
38
+ cell.cellConfigAtConfigure.setObject(true, forKey: "stepControl.wraps")
39
+ cell.cellConfigAtConfigure.setObject(min, forKey: "stepControl.minimumValue") if min
40
+ cell.cellConfigAtConfigure.setObject(max, forKey: "stepControl.maximumValue") if max
41
+ cell.cellConfigAtConfigure.setObject(step, forKey: "stepControl.maximumValue") if step
42
+ end
43
+
44
+ # slider
45
+ if cell_data[:type] == :slider
46
+ min = properties[:min]
47
+ max = properties[:max]
48
+ step = properties[:step]
49
+ cell.cellConfigAtConfigure.setObject(min, forKey: "slider.minimumValue") if min
50
+ cell.cellConfigAtConfigure.setObject(max, forKey: "slider.maximumValue") if max
51
+ cell.cellConfigAtConfigure.setObject(step, forKey: "steps") if step
52
+ end
53
+
54
+ # dates
55
+ if [:date_inline, :datetime_inline, :time_inline, :date, :datetime, :time, :datepicker].include? cell_data[:type]
56
+ min = properties[:min]
57
+ max = properties[:max]
58
+ cell.cellConfigAtConfigure.setObject(min, forKey: "minimumDate") if min
59
+ cell.cellConfigAtConfigure.setObject(max, forKey: "maximumDate") if max
60
+ end
61
+
62
+ cell_class = cell_data[:cell_class]
63
+
64
+ # image
65
+ if cell_data[:type] == :image
66
+ cell_class = XLFormImageSelectorCell if cell_class.nil?
67
+ elsif cell_data[:type] == :color
68
+ cell_class = XLFormColorSelectorCell if cell_class.nil?
69
+ end
70
+
71
+ cell.cellClass = cell_class if cell_class
72
+
73
+ # subcells
74
+ if cell_data[:cells]
75
+ cell.action.viewControllerClass = ProMotion::XLSubFormScreen
76
+ cell.action.cells = cell_data[:cells]
77
+ cell.valueTransformer = ProMotion::ValueTransformer
78
+ end
79
+
80
+ # also accept default XLForm viewControllerClass
81
+ cell.action.viewControllerClass = cell_data[:view_controller_class] if cell_data[:view_controller_class]
82
+ cell.valueTransformer = cell_data[:value_transformer] if cell_data[:value_transformer]
83
+
84
+ # callbacks
85
+ add_proc tag, :on_change, cell_data[:on_change] if cell_data[:on_change]
86
+ add_proc tag, :on_add, cell_data[:on_add] if cell_data[:on_add]
87
+ add_proc tag, :on_remove, cell_data[:on_remove] if cell_data[:on_remove]
88
+
89
+ # button clicks
90
+ if cell_data[:type] == :button && cell_data[:on_click]
91
+ cell.action.formBlock = -> (cell) {
92
+ action = cell_data[:on_click]
93
+ case action.arity
94
+ when 0
95
+ action.call
96
+ when 1
97
+ action.call(cell)
98
+ else
99
+ mp(":on_click take 0 or 1 argument", force_color: :red)
100
+ end
101
+ }
102
+ end
103
+
104
+ cell.selectorTitle = cell_data[:selector_title] if cell_data[:selector_title]
105
+ cell.options = cell_data[:options]
106
+
107
+ cell.disabled = !cell_data.fetch(:enabled, true)
108
+
109
+ # row visible
110
+ if cell_data.has_key?(:hidden)
111
+ configure_hidden(cell, cell_data[:hidden])
112
+ end
113
+
114
+ # validators
115
+ if cell_data[:validators]
116
+ validators = cell_data[:validators]
117
+ validators.each do |key, value|
118
+ validator = case key
119
+ when :email
120
+ XLFormValidator.emailValidator
121
+ when :regex
122
+ regex = value[:regex]
123
+ if regex.is_a?(String)
124
+ XLFormRegexValidator.formRegexValidatorWithMsg(value[:message], regex: regex)
125
+ elsif regex.is_a?(Regexp)
126
+ ProMotion::RegexValidator.validator(value[:message], regex)
127
+ else
128
+ mp "Invalid regex : #{regex.inspect}. Please provides a Regexp or a String", force_color: :red
129
+ nil
130
+ end
131
+ when :url
132
+ ProMotion::UrlValidator.validator
133
+ else
134
+ if value.is_a?(ProMotion::Validator) || value.respond_to?(:isValid)
135
+ value
136
+ else
137
+ mp "Invalid validator : #{key}", force_color: :red
138
+ nil
139
+ end
140
+ end
141
+
142
+ if validator
143
+ cell.addValidator(validator)
144
+ end
145
+ end
146
+ end
147
+
148
+ # customization
149
+ appearance = cell_data[:appearance]
150
+ if appearance
151
+ cell.cellConfig["textLabel.font"] = appearance[:font] if appearance[:font]
152
+ cell.cellConfig["textLabel.textColor"] = appearance[:color] if appearance[:color]
153
+ cell.cellConfig["detailTextLabel.font"] = appearance[:detail_font] if appearance[:detail_font]
154
+ cell.cellConfig["detailTextLabel.textColor"] = appearance[:detail_color] if appearance[:detail_color]
155
+ cell.cellConfig["backgroundColor"] = appearance[:background_color] if appearance[:background_color]
156
+
157
+ appearance.delete_if { |k, v| k.is_a?(Symbol) }.each do |k, v|
158
+ cell.cellConfig[k] = v
159
+ end
160
+ end
161
+
162
+ value = cell_data[:value]
163
+ if value && cell.selectorOptions
164
+ cell.selectorOptions.each do |opt|
165
+ if opt.formValue == value
166
+ value = opt
167
+ break
168
+ end
169
+ end
170
+ end
171
+
172
+ if value === true || value === false
173
+ value = value ? 1 : 0
174
+ end
175
+
176
+ cell.value = value
177
+
178
+ cell
179
+ end
180
+
181
+ end
182
+ end