formotion 1.2 → 1.3
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.
- data/CHANGELOG.md +18 -0
- data/Gemfile +2 -0
- data/Guardfile +7 -0
- data/LIST_OF_ROW_TYPES.md +37 -1
- data/NEW_ROW_TYPES.md +3 -3
- data/README.md +41 -1
- data/Rakefile +1 -0
- data/examples/KitchenSink/app/app_delegate.rb +7 -0
- data/lib/formotion.rb +7 -2
- data/lib/formotion/form/form.rb +48 -43
- data/lib/formotion/form/form_delegate.rb +2 -2
- data/lib/formotion/patch/ui_text_field.rb +1 -7
- data/lib/formotion/patch/ui_text_view.rb +0 -6
- data/lib/formotion/row/row.rb +26 -5
- data/lib/formotion/row_type/base.rb +16 -2
- data/lib/formotion/row_type/button.rb +1 -8
- data/lib/formotion/row_type/currency_row.rb +43 -0
- data/lib/formotion/row_type/date_row.rb +4 -3
- data/lib/formotion/row_type/image_row.rb +17 -10
- data/lib/formotion/row_type/phone_row.rb +1 -1
- data/lib/formotion/row_type/string_row.rb +8 -3
- data/lib/formotion/row_type/template_row.rb +55 -7
- data/lib/formotion/section/section.rb +5 -2
- data/lib/formotion/version.rb +1 -1
- data/spec/form/persist_spec.rb +39 -4
- data/spec/row_type/base_spec.rb +38 -0
- data/spec/row_type/currency_spec.rb +49 -0
- data/spec/row_type/date_spec.rb +6 -6
- data/spec/row_type/string_spec.rb +30 -1
- metadata +10 -4
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 1.3 - March 25, 2013
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
- Added `:currency` row type, which automatically presents an entered number into the current locale's format (i.e. "$4,003.45" or "€ 3.004,35")
|
6
|
+
|
7
|
+
- Added `on_delete` callback for when a `Row` is deleted
|
8
|
+
|
9
|
+
- Correctly handle `on_tap` for `Row` objects, regardless of whether or not they are `:button`s.
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
- Fixed a crash that occured when rapidly serializing a form.
|
14
|
+
|
15
|
+
- Template rows are now persisted correctly.
|
16
|
+
|
17
|
+
- `ImageRow`s which are disabled will not show the "plus" icon
|
18
|
+
|
1
19
|
## 1.2 - January 3, 2013
|
2
20
|
|
3
21
|
### Features
|
data/Gemfile
CHANGED
data/Guardfile
ADDED
data/LIST_OF_ROW_TYPES.md
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
[Email](#email)<br/>
|
5
5
|
[Phone](#phone)<br/>
|
6
6
|
[Number](#number)<br/>
|
7
|
+
[Currency](#currency)<br/>
|
7
8
|
[Date](#date)
|
8
9
|
|
9
10
|
**Other**<br/>
|
@@ -131,6 +132,21 @@ The `PhoneRow` is a string input row for a phone number and opens a `UIKeyboardT
|
|
131
132
|
The `NumberRow` is a string input row for a number and opens a `UIKeyboardTypeDecimalPad` keyboard when editing.
|
132
133
|
|
133
134
|
|
135
|
+
### <a name="currency"></a> Currency Row
|
136
|
+

|
137
|
+
|
138
|
+
```ruby
|
139
|
+
{
|
140
|
+
title: "Amount",
|
141
|
+
key: :amount,
|
142
|
+
placeholder: "0.00",
|
143
|
+
type: :currency
|
144
|
+
}
|
145
|
+
```
|
146
|
+
|
147
|
+
The `CurrentyRow` is a string input row with a number keyboard that restricts users to entering valid currency without tapping the decimal key on the keyboard.
|
148
|
+
|
149
|
+
|
134
150
|
### <a name="date"></a> Date row
|
135
151
|

|
136
152
|
|
@@ -156,6 +172,19 @@ You can pass one of following formats as property:
|
|
156
172
|
|
157
173
|
The `value` is a `NSDate.timeIntervalSince1970` as an integer.
|
158
174
|
|
175
|
+
Note that you can pass a `:picker_mode` argument to affect what kind of date picker is displayed:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
:time # UIDatePickerModeTime
|
179
|
+
:date_time # UIDatePickerModeDateAndTime
|
180
|
+
:countdown # UIDatePickerModeCountDownTimer
|
181
|
+
```
|
182
|
+
|
183
|
+
If none of these are specified, `UIDatePickerModeDate` is used.
|
184
|
+
|
185
|
+
Note: If you use `:date_time` or `:time` for the type, `:minute_interval` will be applied to the time picker if you specify a value for it.
|
186
|
+
the default is the Apple default of 1.
|
187
|
+
|
159
188
|
|
160
189
|
## Other
|
161
190
|
|
@@ -222,6 +251,13 @@ You can create a radio button style group by defining a section with `select_one
|
|
222
251
|
}
|
223
252
|
```
|
224
253
|
|
254
|
+
This would result in a form's `render` as:
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
{
|
258
|
+
account_type: :basic
|
259
|
+
}
|
260
|
+
```
|
225
261
|
|
226
262
|
### <a name="slider"></a> Slider row
|
227
263
|

|
@@ -397,4 +433,4 @@ The `BackRow` is used in subforms to go back to the parent form.
|
|
397
433
|
}
|
398
434
|
```
|
399
435
|
|
400
|
-
The `EditRow` is used to switch between edit and view mode. It's mainly used for the `TemplateRow`.
|
436
|
+
The `EditRow` is used to switch between edit and view mode. It's mainly used for the `TemplateRow`.
|
data/NEW_ROW_TYPES.md
CHANGED
@@ -53,8 +53,8 @@ module Formotion
|
|
53
53
|
class MyNewRow < Base
|
54
54
|
def build_cell(cell)
|
55
55
|
blue_box = UIView.alloc.initWithFrame [[10, 10], [30, 30]]
|
56
|
-
|
57
|
-
cell.addSubview
|
56
|
+
blue_box.backgroundColor = UIColor.blueColor
|
57
|
+
cell.addSubview blue_box
|
58
58
|
|
59
59
|
# return nil because no UITextField added.
|
60
60
|
nil
|
@@ -70,4 +70,4 @@ Your subclass can override these methods:
|
|
70
70
|
|
71
71
|
`#on_select(tableView, tableViewDelegate)` - Called when the row is tapped by the user.
|
72
72
|
|
73
|
-
`#cell_style` - The `UITableViewCellStyle` for the row type. By default is `UITableViewCellStyleSubtitle`
|
73
|
+
`#cell_style` - The `UITableViewCellStyle` for the row type. By default is `UITableViewCellStyleSubtitle`
|
data/README.md
CHANGED
@@ -116,6 +116,25 @@ To add your own, check [the guide to adding new row types](https://github.com/cl
|
|
116
116
|
|
117
117
|
`Formotion::Form`, `Formotion::Section`, and `Formotion::Row` all respond to a `::PROPERTIES` attribute. These are settable as an attribute (ie `section.title = 'title'`) or in the initialization hash (ie `{sections: [{title: 'title', ...}]}`). Check the comments in the 3 main files (`form.rb`, `section.rb`, and `row.rb` for details on what these do).
|
118
118
|
|
119
|
+
### Setting Initial Values
|
120
|
+
|
121
|
+
Forms, particularly edit forms, have default initial values. You can supply these in the `:value` attribute for a given row. So, for example:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
{
|
125
|
+
title: "Email",
|
126
|
+
key: :email,
|
127
|
+
placeholder: "me@mail.com",
|
128
|
+
type: :email,
|
129
|
+
auto_correction: :no,
|
130
|
+
auto_capitalization: :none,
|
131
|
+
value: 'zippity_dippity@doo.com'
|
132
|
+
}
|
133
|
+
```
|
134
|
+
|
135
|
+
Setting values for non-string types can be tricky, so you need to watch what the particular field expects. In particular, date types require
|
136
|
+
the number of seconds from the beginning of the epoch as a number.
|
137
|
+
|
119
138
|
### Retrieve
|
120
139
|
|
121
140
|
You have `form#submit`, `form#on_submit`, and `form#render` at your disposal. Here's an example:
|
@@ -175,7 +194,28 @@ Your form values and state are automatically persisted across application loads,
|
|
175
194
|
|
176
195
|
To reset the form, `persist` it and call `reset`, which restores it to the original state.
|
177
196
|
|
178
|
-
View the [Persistence Example](./
|
197
|
+
View the [Persistence Example](./examples/Persistence) to see it in action.
|
198
|
+
|
199
|
+
### Callbacks
|
200
|
+
|
201
|
+
`Row` objects support the following callbacks:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
row.on_tap do |row|
|
205
|
+
p "I'm tapped!"
|
206
|
+
end
|
207
|
+
|
208
|
+
row.on_delete do |row|
|
209
|
+
p "I'm called before the delete animation"
|
210
|
+
end
|
211
|
+
|
212
|
+
row.on_begin do |row|
|
213
|
+
p "I'm called when my text field begins editing"
|
214
|
+
end
|
215
|
+
|
216
|
+
row.on_enter do |row|
|
217
|
+
p "I'm called when the user taps the return key while typing in my text field"
|
218
|
+
end
|
179
219
|
|
180
220
|
## Forking
|
181
221
|
|
data/Rakefile
CHANGED
@@ -92,6 +92,13 @@ class AppDelegate
|
|
92
92
|
key: :date_short,
|
93
93
|
type: :date,
|
94
94
|
format: :short
|
95
|
+
}, {
|
96
|
+
title: "Date (Time)",
|
97
|
+
subtitle: "w/picker_mode => :time",
|
98
|
+
key: :date_time_short,
|
99
|
+
type: :date,
|
100
|
+
picker_mode: :time,
|
101
|
+
format: :short
|
95
102
|
}, {
|
96
103
|
title: "Slider",
|
97
104
|
key: :slider,
|
data/lib/formotion.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "formotion/version"
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "formotion/version"))
|
2
2
|
require 'bubble-wrap/core'
|
3
3
|
require 'bubble-wrap/camera'
|
4
4
|
|
@@ -17,6 +17,11 @@ BW.require File.expand_path('../formotion/**/*.rb', __FILE__) do
|
|
17
17
|
['date_row', 'email_row', 'number_row', 'phone_row'].each {|file|
|
18
18
|
file("lib/formotion/row_type/#{file}.rb").depends_on 'lib/formotion/row_type/string_row.rb'
|
19
19
|
}
|
20
|
+
|
21
|
+
['currency_row'].each {|file|
|
22
|
+
file("lib/formotion/row_type/#{file}.rb").depends_on 'lib/formotion/row_type/number_row.rb'
|
23
|
+
}
|
24
|
+
|
20
25
|
['submit_row', 'back_row'].each {|file|
|
21
26
|
file("lib/formotion/row_type/#{file}.rb").depends_on 'lib/formotion/row_type/button.rb'
|
22
27
|
}
|
@@ -25,4 +30,4 @@ BW.require File.expand_path('../formotion/**/*.rb', __FILE__) do
|
|
25
30
|
file("lib/formotion/#{file}").depends_on 'lib/formotion/base.rb'
|
26
31
|
}
|
27
32
|
file("lib/formotion/controller/form_controller.rb").depends_on 'lib/formotion/patch/ui_text_field.rb'
|
28
|
-
end
|
33
|
+
end
|
data/lib/formotion/form/form.rb
CHANGED
@@ -22,7 +22,8 @@ module Formotion
|
|
22
22
|
|
23
23
|
def self.persist(params = {})
|
24
24
|
form = new(params)
|
25
|
-
form.open
|
25
|
+
form.open
|
26
|
+
form.init_observer_for_save
|
26
27
|
form
|
27
28
|
end
|
28
29
|
|
@@ -65,8 +66,8 @@ module Formotion
|
|
65
66
|
# EX
|
66
67
|
# @form.create_section(:title => 'Section Title')
|
67
68
|
def create_section(hash = {})
|
69
|
+
hash = hash.merge({:form => self})
|
68
70
|
section = Formotion::Section.new(hash)
|
69
|
-
section.form = self
|
70
71
|
section.index = self.sections.count
|
71
72
|
self.sections << section
|
72
73
|
section
|
@@ -168,13 +169,12 @@ module Formotion
|
|
168
169
|
else
|
169
170
|
section.rows.each {|row|
|
170
171
|
next if row.button?
|
171
|
-
if row.
|
172
|
+
if row.templated?
|
172
173
|
# If this row is part of a template
|
173
174
|
# use the parent's key
|
174
|
-
kv[row.template_parent.key]
|
175
|
-
kv[row.template_parent.key] << row.value
|
175
|
+
kv[row.template_parent.key] = row.template_parent.value
|
176
176
|
else
|
177
|
-
kv[row.key] ||= row.
|
177
|
+
kv[row.key] ||= row.value_for_save_hash
|
178
178
|
end
|
179
179
|
}
|
180
180
|
end
|
@@ -200,7 +200,7 @@ module Formotion
|
|
200
200
|
# see if one of the select one value is used
|
201
201
|
unless (section.rows.map{ |r| r.key } & data.keys).empty?
|
202
202
|
section.rows.each { |row|
|
203
|
-
row.value = data.has_key?(row.key) ? true : nil
|
203
|
+
row.value = data.has_key?(row.key) ? true : nil
|
204
204
|
}
|
205
205
|
end
|
206
206
|
else
|
@@ -221,25 +221,20 @@ module Formotion
|
|
221
221
|
end
|
222
222
|
|
223
223
|
alias_method :fill_out, :values=
|
224
|
-
|
224
|
+
|
225
225
|
#########################
|
226
226
|
# Persisting Forms
|
227
227
|
|
228
228
|
# loads the given settings into the the form, and
|
229
229
|
# places observers to save on changes
|
230
|
-
|
231
|
-
|
230
|
+
|
231
|
+
def init_observer_for_save
|
232
|
+
@form_save_observer ||= lambda { |form|
|
232
233
|
form.sections.each_with_index do |section, s_index|
|
233
234
|
section.rows.each_with_index do |row, index|
|
234
|
-
temp_row = saved_form.sections[s_index].rows[index]
|
235
|
-
|
236
235
|
if row.subform?
|
237
|
-
@
|
238
|
-
|
239
|
-
@saved_subform = nil
|
240
|
-
else
|
241
|
-
row.value = temp_row.value
|
242
|
-
|
236
|
+
@form_save_observer.call(row.subform.to_form)
|
237
|
+
elsif !row.templated?
|
243
238
|
observe(row, "value") do |old_value, new_value|
|
244
239
|
self.save
|
245
240
|
end
|
@@ -248,41 +243,48 @@ module Formotion
|
|
248
243
|
end
|
249
244
|
}
|
250
245
|
|
251
|
-
|
252
|
-
@form_observer.call(self, Formotion::Form.new(saved_hash))
|
253
|
-
end
|
254
|
-
|
255
|
-
# places hash of values into application persistance
|
256
|
-
def save
|
257
|
-
App::Persistence[persist_key] = to_hash.to_archived_data
|
258
|
-
App::Persistence[original_persist_key] ||= self.to_hash.to_archived_data
|
246
|
+
@form_save_observer.call(self)
|
259
247
|
end
|
260
248
|
|
261
|
-
def
|
262
|
-
|
263
|
-
|
264
|
-
@form_resetter ||= lambda { |form, original_form|
|
249
|
+
def open
|
250
|
+
@form_observer ||= lambda { |form, saved_render|
|
265
251
|
form.sections.each_with_index do |section, s_index|
|
266
252
|
section.rows.each_with_index do |row, index|
|
267
|
-
|
253
|
+
next if row.templated?
|
254
|
+
saved_row_value = saved_render[row.key]
|
268
255
|
|
269
256
|
if row.subform?
|
270
|
-
|
271
|
-
|
257
|
+
@form_observer.call(row.subform.to_form, saved_row_value)
|
258
|
+
elsif row.type == :template
|
259
|
+
row.value = saved_row_value
|
260
|
+
row.object.update_template_rows
|
272
261
|
else
|
273
|
-
row.value =
|
262
|
+
row.value = saved_row_value
|
274
263
|
end
|
275
264
|
end
|
276
265
|
end
|
277
266
|
}
|
267
|
+
rendered_data = load_state
|
268
|
+
if rendered_data
|
269
|
+
@form_observer.call(self, rendered_data)
|
270
|
+
else
|
271
|
+
save
|
272
|
+
end
|
273
|
+
end
|
278
274
|
|
279
|
-
|
280
|
-
|
275
|
+
# places hash of values into application persistance
|
276
|
+
def save
|
277
|
+
App::Persistence[persist_key] = render
|
278
|
+
App::Persistence[original_persist_key] ||= render
|
279
|
+
end
|
281
280
|
|
282
|
-
|
281
|
+
def reset
|
282
|
+
App::Persistence[persist_key] = App::Persistence[original_persist_key]
|
283
|
+
open
|
283
284
|
end
|
284
285
|
|
285
286
|
private
|
287
|
+
|
286
288
|
def persist_key
|
287
289
|
"FORMOTION_#{self.persist_as}"
|
288
290
|
end
|
@@ -292,13 +294,16 @@ module Formotion
|
|
292
294
|
end
|
293
295
|
|
294
296
|
def load_state
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
297
|
+
state = App::Persistence[persist_key]
|
298
|
+
# support old archived format
|
299
|
+
if state.respond_to? :unarchive
|
300
|
+
begin
|
301
|
+
form = Formotion::Form.new(state.unarchive)
|
302
|
+
state = form.render
|
303
|
+
p "Old archived data found: #{state}"
|
304
|
+
end
|
299
305
|
end
|
300
|
-
|
301
|
-
state ||= self.to_hash
|
306
|
+
state
|
302
307
|
end
|
303
308
|
|
304
309
|
def each_row(&block)
|
@@ -18,7 +18,7 @@ module Formotion
|
|
18
18
|
def controller=(controller)
|
19
19
|
@controller = controller
|
20
20
|
@controller.title = self.title
|
21
|
-
self.table = controller.
|
21
|
+
self.table = @controller.tableView
|
22
22
|
end
|
23
23
|
|
24
24
|
def table=(table_view)
|
@@ -104,4 +104,4 @@ module Formotion
|
|
104
104
|
row.object.indentWhileEditing?
|
105
105
|
end
|
106
106
|
end
|
107
|
-
end
|
107
|
+
end
|
@@ -15,12 +15,6 @@
|
|
15
15
|
# end
|
16
16
|
|
17
17
|
class UITextField
|
18
|
-
attr_accessor :menu_options_enabled
|
19
|
-
|
20
|
-
def canPerformAction(action, withSender:sender)
|
21
|
-
self.menu_options_enabled
|
22
|
-
end
|
23
|
-
|
24
18
|
# block takes argument textField; should return true/false
|
25
19
|
def should_begin?(&block)
|
26
20
|
add_delegate_method do
|
@@ -155,4 +149,4 @@ class UITextField_Delegate
|
|
155
149
|
end
|
156
150
|
true
|
157
151
|
end
|
158
|
-
end
|
152
|
+
end
|
@@ -15,12 +15,6 @@
|
|
15
15
|
# end
|
16
16
|
|
17
17
|
class UITextView
|
18
|
-
attr_accessor :menu_options_enabled
|
19
|
-
|
20
|
-
def canPerformAction(action, withSender:sender)
|
21
|
-
self.menu_options_enabled.nil? ? true : self.menu_options_enabled
|
22
|
-
end
|
23
|
-
|
24
18
|
# block takes argument textView; should return true/false
|
25
19
|
def should_begin?(&block)
|
26
20
|
add_delegate_method do
|
data/lib/formotion/row/row.rb
CHANGED
@@ -82,7 +82,10 @@ module Formotion
|
|
82
82
|
# When a row is deleted, actually remove the row from UI
|
83
83
|
# instead of just nil'ing the value.
|
84
84
|
# DEFAULT is false EXCEPT for template-generated rows
|
85
|
-
:remove_on_delete
|
85
|
+
:remove_on_delete,
|
86
|
+
# In a date/time or time picker, the minute interval can
|
87
|
+
# be set. That allows picking by every 15 minutes, etc.
|
88
|
+
:minute_interval
|
86
89
|
]
|
87
90
|
PROPERTIES.each {|prop|
|
88
91
|
attr_accessor prop
|
@@ -118,12 +121,15 @@ module Formotion
|
|
118
121
|
# callback for what happens when the user
|
119
122
|
# taps a ButtonRow
|
120
123
|
attr_accessor :on_tap_callback
|
124
|
+
# callback for when a row is tapped
|
125
|
+
attr_accessor :on_delete_callback
|
121
126
|
|
122
127
|
# RowType object
|
123
128
|
attr_accessor :object
|
124
129
|
|
125
130
|
# Owning template row, if applicable
|
126
131
|
attr_accessor :template_parent
|
132
|
+
attr_accessor :template_children
|
127
133
|
|
128
134
|
def initialize(params = {})
|
129
135
|
super
|
@@ -131,20 +137,27 @@ module Formotion
|
|
131
137
|
BOOLEAN_PROPERTIES.each { |prop|
|
132
138
|
Formotion::Conditions.assert_nil_or_boolean(self.send(prop))
|
133
139
|
}
|
140
|
+
@template_children = []
|
134
141
|
end
|
135
142
|
|
136
143
|
# called after section and index have been assigned
|
137
144
|
def after_create
|
138
|
-
if self.type == :template
|
139
|
-
self.
|
140
|
-
new_row = self.object.build_new_row({:value => value})
|
141
|
-
end
|
145
|
+
if self.type == :template
|
146
|
+
self.object.update_template_rows
|
142
147
|
end
|
143
148
|
end
|
144
149
|
|
145
150
|
#########################
|
146
151
|
# pseudo-properties
|
147
152
|
|
153
|
+
def value_for_save_hash
|
154
|
+
if self.object.respond_to? :value_for_save_hash
|
155
|
+
self.object.value_for_save_hash
|
156
|
+
else
|
157
|
+
self.value
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
148
161
|
def index_path
|
149
162
|
NSIndexPath.indexPathForRow(self.index, inSection:self.section.index)
|
150
163
|
end
|
@@ -184,6 +197,10 @@ module Formotion
|
|
184
197
|
self.type.to_s == "subform"
|
185
198
|
end
|
186
199
|
|
200
|
+
def templated?
|
201
|
+
!!self.template_parent
|
202
|
+
end
|
203
|
+
|
187
204
|
#########################
|
188
205
|
# getter overrides
|
189
206
|
def items
|
@@ -273,6 +290,10 @@ module Formotion
|
|
273
290
|
self.on_tap_callback = block
|
274
291
|
end
|
275
292
|
|
293
|
+
def on_delete(&block)
|
294
|
+
self.on_delete_callback = block
|
295
|
+
end
|
296
|
+
|
276
297
|
#########################
|
277
298
|
# Methods for making cells
|
278
299
|
# Called in UITableViewDataSource methods
|
@@ -57,15 +57,26 @@ module Formotion
|
|
57
57
|
# method gets triggered when tableView(tableView, didSelectRowAtIndexPath:indexPath)
|
58
58
|
# in UITableViewDelegate is executed
|
59
59
|
def on_select(tableView, tableViewDelegate)
|
60
|
-
#
|
60
|
+
# row class should call super and proceed if false is return (not handled here)
|
61
|
+
if row.on_tap_callback
|
62
|
+
# Not all row types will want to define on_tap, but call it if so
|
63
|
+
row.on_tap_callback.call(self.row)
|
64
|
+
true
|
65
|
+
else
|
66
|
+
false
|
67
|
+
end
|
61
68
|
end
|
62
69
|
|
63
70
|
# called when the delete editing style was triggered tableView:commitEditingStyle:forRowAtIndexPath:
|
64
71
|
def on_delete(tableView, tableViewDelegate)
|
72
|
+
if row.on_delete_callback
|
73
|
+
row.on_delete_callback.call(self.row)
|
74
|
+
end
|
65
75
|
if row.remove_on_delete?
|
66
76
|
row.section.rows.delete_at(row.index)
|
67
77
|
row.section.refresh_row_indexes
|
68
78
|
delete_row
|
79
|
+
after_delete
|
69
80
|
else
|
70
81
|
row.value = nil
|
71
82
|
self.tableView.reloadData
|
@@ -78,6 +89,9 @@ module Formotion
|
|
78
89
|
tableView.endUpdates
|
79
90
|
end
|
80
91
|
|
92
|
+
def after_delete
|
93
|
+
end
|
94
|
+
|
81
95
|
def break_with_semaphore(&block)
|
82
96
|
return if @semaphore
|
83
97
|
with_semaphore(&block)
|
@@ -90,4 +104,4 @@ module Formotion
|
|
90
104
|
end
|
91
105
|
end
|
92
106
|
end
|
93
|
-
end
|
107
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Formotion
|
2
|
+
module RowType
|
3
|
+
class CurrencyRow < NumberRow
|
4
|
+
def on_change(text_field)
|
5
|
+
break_with_semaphore do
|
6
|
+
edited_text = text_field.text
|
7
|
+
entered_digits = edited_text.gsub %r{\D+}, ''
|
8
|
+
decimal_num = 0.0
|
9
|
+
|
10
|
+
if !entered_digits.empty?
|
11
|
+
decimal_num = entered_digits.to_i * (10 ** currency_scale.to_i)
|
12
|
+
decimal_num = decimal_num.to_f
|
13
|
+
end
|
14
|
+
|
15
|
+
row.value = decimal_num
|
16
|
+
text_field.text = row_value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def row_value
|
21
|
+
number_formatter.stringFromNumber super.to_f
|
22
|
+
end
|
23
|
+
|
24
|
+
def value_for_save_hash
|
25
|
+
number_formatter.numberFromString(row_value)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def number_formatter
|
30
|
+
@number_formatter ||= begin
|
31
|
+
formatter = NSNumberFormatter.alloc.init
|
32
|
+
formatter.numberStyle = NSNumberFormatterCurrencyStyle
|
33
|
+
formatter.locale = NSLocale.currentLocale
|
34
|
+
formatter
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def currency_scale
|
39
|
+
@currency_scale ||= number_formatter.maximumFractionDigits * -1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -12,7 +12,7 @@ module Formotion
|
|
12
12
|
def date_value
|
13
13
|
value = self.row.value
|
14
14
|
if value.is_a? Numeric
|
15
|
-
|
15
|
+
Time.at value
|
16
16
|
else
|
17
17
|
nil
|
18
18
|
end
|
@@ -43,13 +43,14 @@ module Formotion
|
|
43
43
|
picker = UIDatePicker.alloc.initWithFrame(CGRectZero)
|
44
44
|
picker.datePickerMode = self.picker_mode
|
45
45
|
picker.hidden = false
|
46
|
-
picker.date = self.date_value ||
|
46
|
+
picker.date = self.date_value || Time.now
|
47
|
+
picker.minuteInterval = self.row.minute_interval if self.row.minute_interval
|
47
48
|
|
48
49
|
picker.when(UIControlEventValueChanged) do
|
49
50
|
if self.row.picker_mode == :countdown
|
50
51
|
self.row.value = @picker.countDownDuration
|
51
52
|
else
|
52
|
-
self.row.value = @picker.date.
|
53
|
+
self.row.value = Time.at(@picker.date).to_i
|
53
54
|
end
|
54
55
|
update
|
55
56
|
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
module Formotion
|
2
2
|
module RowType
|
3
3
|
class ImageRow < Base
|
4
|
+
TAKE = BW.localized_string("Take", nil)
|
5
|
+
DELETE = BW.localized_string("Delete", nil)
|
6
|
+
CHOOSE = BW.localized_string("Choose", nil)
|
7
|
+
CANCEL = BW.localized_string("Cancel", nil)
|
8
|
+
|
4
9
|
include BW::KVO
|
5
10
|
|
6
11
|
IMAGE_VIEW_TAG=1100
|
7
12
|
|
8
13
|
def build_cell(cell)
|
9
|
-
|
14
|
+
# only show the "plus" when editable
|
15
|
+
add_plus_accessory(cell) if row.editable?
|
10
16
|
|
11
17
|
observe(self.row, "value") do |old_value, new_value|
|
12
18
|
@image_view.image = new_value
|
@@ -15,7 +21,8 @@ module Formotion
|
|
15
21
|
cell.accessoryView = cell.editingAccessoryView = nil
|
16
22
|
else
|
17
23
|
self.row.row_height = 44
|
18
|
-
|
24
|
+
# only show the "plus" when editable
|
25
|
+
add_plus_accessory(cell) if row.editable?
|
19
26
|
end
|
20
27
|
row.form.reload_data
|
21
28
|
end
|
@@ -51,10 +58,10 @@ module Formotion
|
|
51
58
|
@action_sheet = UIActionSheet.alloc.init
|
52
59
|
@action_sheet.delegate = self
|
53
60
|
|
54
|
-
@action_sheet.destructiveButtonIndex = (@action_sheet.addButtonWithTitle
|
55
|
-
@action_sheet.addButtonWithTitle
|
56
|
-
@action_sheet.addButtonWithTitle
|
57
|
-
@action_sheet.cancelButtonIndex = (@action_sheet.addButtonWithTitle
|
61
|
+
@action_sheet.destructiveButtonIndex = (@action_sheet.addButtonWithTitle DELETE) if row.value
|
62
|
+
@action_sheet.addButtonWithTitle TAKE if BW::Device.camera.front? or BW::Device.camera.rear?
|
63
|
+
@action_sheet.addButtonWithTitle CHOOSE
|
64
|
+
@action_sheet.cancelButtonIndex = (@action_sheet.addButtonWithTitle CANCEL)
|
58
65
|
|
59
66
|
@action_sheet.showInView @image_view
|
60
67
|
end
|
@@ -68,11 +75,11 @@ module Formotion
|
|
68
75
|
end
|
69
76
|
|
70
77
|
case actionSheet.buttonTitleAtIndex(index)
|
71
|
-
when
|
78
|
+
when TAKE
|
72
79
|
source = :camera
|
73
|
-
when
|
80
|
+
when CHOOSE
|
74
81
|
source = :photo_library
|
75
|
-
when
|
82
|
+
when CANCEL
|
76
83
|
else
|
77
84
|
p "Unrecognized button title #{actionSheet.buttonTitleAtIndex(index)}"
|
78
85
|
end
|
@@ -99,4 +106,4 @@ module Formotion
|
|
99
106
|
end
|
100
107
|
end
|
101
108
|
end
|
102
|
-
end
|
109
|
+
end
|
@@ -128,16 +128,21 @@ module Formotion
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def on_select(tableView, tableViewDelegate)
|
131
|
+
super or _on_select(tableView, tableViewDelegate)
|
132
|
+
end
|
133
|
+
|
134
|
+
def _on_select(tableView, tableViewDelegate)
|
131
135
|
if !row.editable?
|
132
136
|
return
|
137
|
+
else
|
138
|
+
row.text_field.becomeFirstResponder
|
133
139
|
end
|
134
|
-
row.text_field.becomeFirstResponder
|
135
140
|
end
|
136
141
|
|
137
142
|
# Used when row.value changes
|
138
143
|
def update_text_field(new_value)
|
139
|
-
self.row.text_field.text =
|
144
|
+
self.row.text_field.text = row_value
|
140
145
|
end
|
141
146
|
end
|
142
147
|
end
|
143
|
-
end
|
148
|
+
end
|
@@ -14,6 +14,7 @@
|
|
14
14
|
module Formotion
|
15
15
|
module RowType
|
16
16
|
class TemplateRow < Base
|
17
|
+
include BubbleWrap::KVO
|
17
18
|
|
18
19
|
def cellEditingStyle
|
19
20
|
UITableViewCellEditingStyleInsert
|
@@ -33,7 +34,6 @@ module Formotion
|
|
33
34
|
button
|
34
35
|
end
|
35
36
|
cell.accessoryView = @add_button
|
36
|
-
|
37
37
|
nil
|
38
38
|
end
|
39
39
|
|
@@ -42,7 +42,6 @@ module Formotion
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def on_insert(tableView, tableViewDelegate)
|
45
|
-
@template_index = row.section.rows.count
|
46
45
|
new_row = build_new_row
|
47
46
|
move_row_in_list(new_row)
|
48
47
|
insert_row(new_row)
|
@@ -51,27 +50,76 @@ module Formotion
|
|
51
50
|
def build_new_row(options = {})
|
52
51
|
# build row
|
53
52
|
new_row = row.section.create_row(row.template.merge(options))
|
53
|
+
new_row.object.instance_eval do
|
54
|
+
def after_delete
|
55
|
+
template_value = row.template_parent.value
|
56
|
+
template_value.delete_at(row.index)
|
57
|
+
row.template_parent.value = template_value
|
58
|
+
end
|
59
|
+
end
|
54
60
|
new_row.remove_on_delete = true
|
55
|
-
new_row.template_parent =
|
61
|
+
new_row.template_parent = row
|
62
|
+
row.template_children ||= []
|
63
|
+
row.template_children << new_row
|
64
|
+
observe(new_row, "value") do |old_value, new_value|
|
65
|
+
template_value = row.value.dup
|
66
|
+
template_value[new_row.index] = new_row.value
|
67
|
+
row.value = template_value
|
68
|
+
end
|
56
69
|
new_row
|
57
70
|
end
|
58
71
|
|
59
72
|
def move_row_in_list(new_row)
|
60
73
|
# move to top
|
61
74
|
row.section.rows.pop
|
62
|
-
row.section.rows.insert(
|
75
|
+
row.section.rows.insert(row.template_children.count - 1, new_row)
|
63
76
|
|
64
77
|
# reset indexes
|
65
78
|
row.section.refresh_row_indexes
|
66
79
|
end
|
67
80
|
|
68
|
-
def insert_row(
|
69
|
-
|
81
|
+
def insert_row(template_row, with_animation = true)
|
82
|
+
animation = with_animation ? UITableViewRowAnimationBottom : UITableViewRowAnimationNone
|
83
|
+
index_path = NSIndexPath.indexPathForRow(template_row.index, inSection:row.section.index)
|
84
|
+
tableView.beginUpdates
|
85
|
+
tableView.insertRowsAtIndexPaths [index_path], withRowAnimation:animation
|
86
|
+
tableView.endUpdates
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_row(template_row, with_animation = true)
|
90
|
+
animation = with_animation ? UITableViewRowAnimationTop : UITableViewRowAnimationNone
|
91
|
+
index_path = NSIndexPath.indexPathForRow(template_row.index, inSection:row.section.index)
|
70
92
|
tableView.beginUpdates
|
71
|
-
tableView.
|
93
|
+
tableView.deleteRowsAtIndexPaths [index_path], withRowAnimation:animation
|
72
94
|
tableView.endUpdates
|
73
95
|
end
|
74
96
|
|
97
|
+
def update_template_rows
|
98
|
+
row.value ||= []
|
99
|
+
if row.value.count > row.template_children.count
|
100
|
+
row.value[row.template_children.count..-1].each do |value|
|
101
|
+
new_row = build_new_row({:value => value})
|
102
|
+
move_row_in_list(new_row)
|
103
|
+
insert_row(new_row) if tableView
|
104
|
+
end
|
105
|
+
elsif row.value.count < row.template_children.count
|
106
|
+
row.template_children[row.value.count..-1].each do |row_to_delete|
|
107
|
+
row.section.rows.delete(row_to_delete)
|
108
|
+
row.template_children.delete(row_to_delete)
|
109
|
+
row.section.refresh_row_indexes
|
110
|
+
delete_row(row_to_delete) if tableView
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
row.value.dup.each_with_index do |new_value, index|
|
115
|
+
template_child = row.template_children[index]
|
116
|
+
old_value = template_child.value
|
117
|
+
if old_value != new_value
|
118
|
+
template_child.value = new_value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
75
123
|
end
|
76
124
|
end
|
77
125
|
end
|
@@ -29,7 +29,7 @@ module Formotion
|
|
29
29
|
|
30
30
|
def initialize(params = {})
|
31
31
|
super
|
32
|
-
|
32
|
+
self.form = params[:form]
|
33
33
|
Formotion::Conditions.assert_nil_or_boolean(self.select_one)
|
34
34
|
|
35
35
|
rows = params[:rows] || params["rows"]
|
@@ -112,7 +112,10 @@ module Formotion
|
|
112
112
|
# Retreiving data
|
113
113
|
def to_hash
|
114
114
|
h = super
|
115
|
-
h[:rows] =
|
115
|
+
h[:rows] = []
|
116
|
+
self.rows.each do |row|
|
117
|
+
h[:rows] << row.to_hash if row.template_parent.nil?
|
118
|
+
end
|
116
119
|
h
|
117
120
|
end
|
118
121
|
end
|
data/lib/formotion/version.rb
CHANGED
data/spec/form/persist_spec.rb
CHANGED
@@ -19,8 +19,8 @@ describe "Form Persisting" do
|
|
19
19
|
r = f.sections[0].rows[0]
|
20
20
|
r.value = "new value"
|
21
21
|
|
22
|
-
saved =
|
23
|
-
saved
|
22
|
+
saved = f.send(:load_state)
|
23
|
+
saved["first"] == r.value
|
24
24
|
|
25
25
|
f.reset
|
26
26
|
r.value.should == "initial value"
|
@@ -57,10 +57,45 @@ describe "Form Persisting" do
|
|
57
57
|
r = f.sections[0].rows[0].subform.to_form.sections[0].rows[0]
|
58
58
|
r.value = "new value"
|
59
59
|
|
60
|
-
saved =
|
61
|
-
saved
|
60
|
+
saved = f.send(:load_state)
|
61
|
+
saved[:subform]["second"].should == r.value
|
62
62
|
|
63
63
|
f.reset
|
64
64
|
r.value.should == "initial value"
|
65
65
|
end
|
66
|
+
|
67
|
+
it "works with templates" do
|
68
|
+
key = "test_#{rand(255)}"
|
69
|
+
App::Persistence["FORMOTION_#{key}"] = nil
|
70
|
+
App::Persistence["FORMOTION_#{key}_ORIGINAL"] = nil
|
71
|
+
hash = {
|
72
|
+
persist_as: key,
|
73
|
+
sections: [
|
74
|
+
rows: [{
|
75
|
+
title: "Add nickname",
|
76
|
+
key: :nicknames,
|
77
|
+
type: :template,
|
78
|
+
value: ['Nici', 'Sam'],
|
79
|
+
template: {
|
80
|
+
title: 'Nickname',
|
81
|
+
type: :string,
|
82
|
+
placeholder: 'Enter here',
|
83
|
+
indented: true,
|
84
|
+
deletable: true
|
85
|
+
}
|
86
|
+
}]
|
87
|
+
]
|
88
|
+
}
|
89
|
+
f = Formotion::Form.persist(hash)
|
90
|
+
f.render.should == { :nicknames => ['Nici', 'Sam'] }
|
91
|
+
|
92
|
+
r = f.sections[0].rows[0]
|
93
|
+
r.value = "Sandra"
|
94
|
+
|
95
|
+
saved = f.send(:load_state)
|
96
|
+
saved[:nicknames].should == ["Sandra", "Sam"]
|
97
|
+
|
98
|
+
f.reset
|
99
|
+
r.value.should == "Nici"
|
100
|
+
end
|
66
101
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Formotion
|
2
|
+
module RowType
|
3
|
+
class DummyRow < Base
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "Base Row Type" do
|
9
|
+
|
10
|
+
describe '#on_select' do
|
11
|
+
tests_row :dummy
|
12
|
+
|
13
|
+
it "should return false if callback is not defined" do
|
14
|
+
@row.object.on_select(nil, nil).should == false
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'when on_tap_callback is set' do
|
18
|
+
tests_row :dummy do |row|
|
19
|
+
row.on_tap { |row| @called = true }
|
20
|
+
end
|
21
|
+
|
22
|
+
before do
|
23
|
+
@called = false
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return true" do
|
27
|
+
@row.object.on_select(nil, nil).should == true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should call the callback" do
|
31
|
+
@row.object.on_select(nil, nil)
|
32
|
+
@called.should == true
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
describe "Number Row" do
|
2
|
+
tests_row :currency
|
3
|
+
|
4
|
+
def set_formatter_locale(locale)
|
5
|
+
formatter = NSNumberFormatter.alloc.init
|
6
|
+
formatter.numberStyle = NSNumberFormatterCurrencyStyle
|
7
|
+
formatter.locale = NSLocale.alloc.initWithLocaleIdentifier(locale)
|
8
|
+
@row.object.instance_variable_set("@number_formatter", formatter)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should initialize with correct settings" do
|
12
|
+
cell = @row.make_cell
|
13
|
+
@row.object.class.should == Formotion::RowType::CurrencyRow
|
14
|
+
set_formatter_locale("en_US")
|
15
|
+
@row.value.should == 0.0
|
16
|
+
@row.object.row_value.should == "$0.00"
|
17
|
+
@row.value_for_save_hash.should == 0.0
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should work when row#value is changed" do
|
21
|
+
cell = @row.make_cell
|
22
|
+
set_formatter_locale("en_US")
|
23
|
+
@row.value = 4.35
|
24
|
+
@row.text_field.text.should == "$4.35"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should work when text_field#text is changed" do
|
28
|
+
cell = @row.make_cell
|
29
|
+
set_formatter_locale("en_US")
|
30
|
+
@row.text_field.setText("$100.45")
|
31
|
+
@row.text_field.delegate.on_change(@row.text_field)
|
32
|
+
@row.value.should == 100.45
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should work with different locale" do
|
36
|
+
cell = @row.make_cell
|
37
|
+
set_formatter_locale("it_IT")
|
38
|
+
@row.value = 3004.35
|
39
|
+
@row.text_field.text.should == "€ 3.004,35"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should work with different locale and setting text_field#text" do
|
43
|
+
cell = @row.make_cell
|
44
|
+
set_formatter_locale("it_IT")
|
45
|
+
@row.text_field.setText("€ 3.100,35")
|
46
|
+
@row.text_field.delegate.on_change(@row.text_field)
|
47
|
+
@row.value.should == 3100.35
|
48
|
+
end
|
49
|
+
end
|
data/spec/row_type/date_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
MILLENIUM =
|
1
|
+
MILLENIUM = 946684772 # Time.at(MILLENIUM) => 1999-12-31 18:59:32 -0500
|
2
2
|
TIME_ZONE = NSTimeZone.timeZoneWithName "Europe/Paris"
|
3
3
|
|
4
4
|
describe "Date Row" do
|
@@ -34,7 +34,7 @@ describe "Date Row" do
|
|
34
34
|
it "should update value when date is picked" do
|
35
35
|
cell = @row.make_cell
|
36
36
|
|
37
|
-
@row.object.picker.date =
|
37
|
+
@row.object.picker.date = Time.at MILLENIUM
|
38
38
|
@row.object.picker.trigger UIControlEventValueChanged
|
39
39
|
|
40
40
|
@row.value.should == MILLENIUM
|
@@ -63,16 +63,16 @@ describe "Date Row" do
|
|
63
63
|
# Modes
|
64
64
|
{
|
65
65
|
:date => '1/1/00',
|
66
|
-
:time => '12:
|
67
|
-
:date_time => '1/1/00, 12:
|
68
|
-
:countdown => '00:
|
66
|
+
:time => '12:59 AM',
|
67
|
+
:date_time => '1/1/00, 12:59 AM',
|
68
|
+
:countdown => '00:59'
|
69
69
|
}.each do |mode, expected_output|
|
70
70
|
|
71
71
|
it "should display chosen mode #{mode} date/time format #{expected_output}" do
|
72
72
|
@row.format = :short
|
73
73
|
@row.picker_mode = mode
|
74
74
|
cell = @row.make_cell
|
75
|
-
@row.object.picker.date =
|
75
|
+
@row.object.picker.date = Time.at MILLENIUM
|
76
76
|
@row.object.picker.trigger UIControlEventValueChanged
|
77
77
|
|
78
78
|
@row.text_field.text.should == expected_output
|
@@ -53,4 +53,33 @@ describe "String Row Type" do
|
|
53
53
|
cell = @row.make_cell
|
54
54
|
@row.text_field.keyboardType.should == UIKeyboardTypeDefault
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
|
+
describe "on_select" do
|
58
|
+
|
59
|
+
it "should call _on_select" do
|
60
|
+
@row.object.instance_variable_set("@called_on_select", false)
|
61
|
+
def (@row.object)._on_select(a, b); @called_on_select = true end
|
62
|
+
@row.object.on_select(nil, nil)
|
63
|
+
@row.object.instance_variable_get("@called_on_select").should == true
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "when on_tap callback is set" do
|
67
|
+
tests_row :string do |row|
|
68
|
+
@on_tap_called = false
|
69
|
+
row.on_tap { |row| @on_tap_called = true }
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return true" do
|
73
|
+
@row.object.on_select(nil, nil).should == true
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should call the callback" do
|
77
|
+
@row.object.on_select(nil, nil)
|
78
|
+
@on_tap_called.should == true
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: formotion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bubble-wrap
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- CHANGELOG.md
|
55
55
|
- Formotion.gemspec
|
56
56
|
- Gemfile
|
57
|
+
- Guardfile
|
57
58
|
- LICENSE
|
58
59
|
- LIST_OF_ROW_TYPES.md
|
59
60
|
- NEW_ROW_TYPES.md
|
@@ -125,6 +126,7 @@ files:
|
|
125
126
|
- lib/formotion/row_type/base.rb
|
126
127
|
- lib/formotion/row_type/button.rb
|
127
128
|
- lib/formotion/row_type/check_row.rb
|
129
|
+
- lib/formotion/row_type/currency_row.rb
|
128
130
|
- lib/formotion/row_type/date_row.rb
|
129
131
|
- lib/formotion/row_type/edit_row.rb
|
130
132
|
- lib/formotion/row_type/email_row.rb
|
@@ -166,7 +168,9 @@ files:
|
|
166
168
|
- spec/helpers/row_test_helpers.rb
|
167
169
|
- spec/row_spec.rb
|
168
170
|
- spec/row_type/back_spec.rb
|
171
|
+
- spec/row_type/base_spec.rb
|
169
172
|
- spec/row_type/check_spec.rb
|
173
|
+
- spec/row_type/currency_spec.rb
|
170
174
|
- spec/row_type/date_spec.rb
|
171
175
|
- spec/row_type/email_spec.rb
|
172
176
|
- spec/row_type/image_spec.rb
|
@@ -198,7 +202,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
202
|
version: '0'
|
199
203
|
segments:
|
200
204
|
- 0
|
201
|
-
hash:
|
205
|
+
hash: -3419813869520045411
|
202
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
207
|
none: false
|
204
208
|
requirements:
|
@@ -207,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
211
|
version: '0'
|
208
212
|
segments:
|
209
213
|
- 0
|
210
|
-
hash:
|
214
|
+
hash: -3419813869520045411
|
211
215
|
requirements: []
|
212
216
|
rubyforge_project:
|
213
217
|
rubygems_version: 1.8.23
|
@@ -236,7 +240,9 @@ test_files:
|
|
236
240
|
- spec/helpers/row_test_helpers.rb
|
237
241
|
- spec/row_spec.rb
|
238
242
|
- spec/row_type/back_spec.rb
|
243
|
+
- spec/row_type/base_spec.rb
|
239
244
|
- spec/row_type/check_spec.rb
|
245
|
+
- spec/row_type/currency_spec.rb
|
240
246
|
- spec/row_type/date_spec.rb
|
241
247
|
- spec/row_type/email_spec.rb
|
242
248
|
- spec/row_type/image_spec.rb
|