ProMotion-XLForm 0.0.7 → 0.0.8

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.
@@ -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