cck_forms 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -0
  3. data/README.md +1 -0
  4. data/Rakefile +40 -0
  5. data/lib/cck_forms/date_time.rb +58 -0
  6. data/lib/cck_forms/engine.rb +23 -0
  7. data/lib/cck_forms/form_builder_extensions.rb +18 -0
  8. data/lib/cck_forms/parameter_type_class/album.rb +100 -0
  9. data/lib/cck_forms/parameter_type_class/base.rb +275 -0
  10. data/lib/cck_forms/parameter_type_class/boolean.rb +24 -0
  11. data/lib/cck_forms/parameter_type_class/checkboxes.rb +202 -0
  12. data/lib/cck_forms/parameter_type_class/date.rb +35 -0
  13. data/lib/cck_forms/parameter_type_class/date_range.rb +53 -0
  14. data/lib/cck_forms/parameter_type_class/date_time.rb +76 -0
  15. data/lib/cck_forms/parameter_type_class/enum.rb +53 -0
  16. data/lib/cck_forms/parameter_type_class/file.rb +80 -0
  17. data/lib/cck_forms/parameter_type_class/float.rb +20 -0
  18. data/lib/cck_forms/parameter_type_class/image.rb +20 -0
  19. data/lib/cck_forms/parameter_type_class/integer.rb +77 -0
  20. data/lib/cck_forms/parameter_type_class/integer_range.rb +150 -0
  21. data/lib/cck_forms/parameter_type_class/map.rb +259 -0
  22. data/lib/cck_forms/parameter_type_class/phones.rb +204 -0
  23. data/lib/cck_forms/parameter_type_class/string.rb +13 -0
  24. data/lib/cck_forms/parameter_type_class/string_collection.rb +23 -0
  25. data/lib/cck_forms/parameter_type_class/text.rb +18 -0
  26. data/lib/cck_forms/parameter_type_class/time.rb +30 -0
  27. data/lib/cck_forms/parameter_type_class/work_hours.rb +369 -0
  28. data/lib/cck_forms/version.rb +3 -0
  29. data/lib/cck_forms.rb +4 -0
  30. data/vendor/assets/javascripts/cck_forms/jquery.workhours.js +399 -0
  31. data/vendor/assets/javascripts/cck_forms/map.js.coffee +322 -0
  32. metadata +116 -0
@@ -0,0 +1,202 @@
1
+ class CckForms::ParameterTypeClass::Checkboxes
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Галочки'
6
+ end
7
+
8
+ # {kazakh: '1', russian: '0', english: '1'} -> ['kazakh', 'english']
9
+ def mongoize
10
+ resulting_set = []
11
+
12
+ if value.is_a? Array
13
+ return value
14
+ elsif value.is_a?(String) || value.is_a?(Symbol)
15
+ return [value.to_s]
16
+ elsif !value.is_a?(Hash)
17
+ return []
18
+ end
19
+
20
+ value.each do |key, value|
21
+ resulting_set << key if value.to_s == '1'
22
+ end
23
+
24
+ resulting_set
25
+ end
26
+
27
+ # ['kazakh', 'english'] -> {'kazakh' => 1, 'russain' => 0, 'english' => 1}
28
+ # (такой формат нужен формам)
29
+ def self.demongoize_value(value, parameter_type_class=nil)
30
+ value.present? or return {}
31
+
32
+ valid_values = parameter_type_class.try!(:valid_values) || value.map { |x| [x, nil] }
33
+ valid_values.reduce({}) do |r, (key, _)|
34
+ r[key] = value.include?(key) ? '1' : '0'
35
+ r
36
+ end
37
+ end
38
+
39
+ # Перечислим все отмеченные элементы в строку.
40
+ # options[:block] - задает шаблон sprintf для каждого вхождения
41
+ # options[:only] - массив, оставить только эти ключи (можно передать одно, без массива)
42
+ # options[:except] - :only наоборот
43
+ # options[:glue] - используем его вместо ', ' для склейки значений
44
+ # options[:short] - по-возможности сокращать: если указаны все варианты, то вернется строка вида "выбрано все"
45
+ # - или "все, кроме xxx", если не выбран только xxx
46
+ def to_s(options = nil)
47
+ checked_keys, checked_elements = [], []
48
+ return '' if value.blank?
49
+
50
+ template = '%s'
51
+ if options
52
+ options = {block: options} unless options.is_a? Hash
53
+ template = options[:block] if options[:block]
54
+ else
55
+ options = {}
56
+ end
57
+
58
+ if value.respond_to? :each_pair
59
+ value.each_pair do |k, v|
60
+ include = v == '1' && (!options[:only] || options[:only] && options[:only] == k)
61
+ exclude = options[:except] && options[:except] == k
62
+ if include && !exclude
63
+ checked_elements << sprintf(template, valid_values[k])
64
+ checked_keys << k
65
+ end
66
+ end
67
+ elsif value.respond_to? :each
68
+ value.each do |k|
69
+ exclude = options[:except] && options[:except] == k
70
+ unless exclude
71
+ checked_elements << sprintf(template, valid_values[k])
72
+ checked_keys << k
73
+ end
74
+ end
75
+ end
76
+
77
+ glue = options[:glue] || ', '
78
+ if options[:short] && checked_keys
79
+ all_keys = valid_values.keys
80
+ unchecked_keys = all_keys - checked_keys
81
+ unchecked_num = unchecked_keys.count
82
+
83
+ param_title = cck_parameter ? " «#{cck_parameter.title}»" : ''
84
+
85
+ if unchecked_num == 0
86
+ return "Все значения#{param_title}"
87
+ elsif unchecked_num < checked_keys.count./(2).round
88
+ return "Все значения#{param_title}, кроме " + valid_values.values_at(*unchecked_keys).map { |x| sprintf(template, x) }.join(glue)
89
+ end
90
+ end
91
+
92
+ checked_elements.join glue
93
+ end
94
+
95
+ def search(selectable, field, query)
96
+ if query.respond_to? :each_pair
97
+ keys = []
98
+ query.each_pair do |key, value|
99
+ if value.present? && value != '0'
100
+ if key == 'any'
101
+ selectable = selectable.where(field.to_sym.ne => [])
102
+ else
103
+ keys << key
104
+ end
105
+ end
106
+ end
107
+ selectable = selectable.where(field.to_sym.all => keys) if keys.any?
108
+ else
109
+ selectable = selectable.where(field.to_s => query)
110
+ end
111
+
112
+ selectable
113
+ end
114
+
115
+ # Составим строку для map-reduce, чтобы emit вызывался на каждом отмеченном значении, например, в документе хранится:
116
+ #
117
+ # cck_params.city: ['almaty', 'astana']
118
+ #
119
+ # Мы вызовем emit('almaty', 1); emit('astana', 1).
120
+ def self.emit_map_reduce(field_name)
121
+ field_name = 'this.' + field_name
122
+ return "if(#{field_name} && #{field_name} instanceof Array) {
123
+ #{field_name}.forEach(function(key) {
124
+ emit(key, 1)
125
+ })
126
+ }"
127
+ end
128
+
129
+ # options[:block] - задает шаблон sprintf для каждого чекбокса (input, label)
130
+ # options[:map] - задает преобразование (ключ-значение) текстов в подписях, например, 'длинный текст' => 'кор. ткст'
131
+ # options[:data] - задает data-атрибуты для тэга label, по ключу из valid_values (capital: {almaty: 'yes', astana: 'no'})
132
+ # options[:as] - если :select, то показать не в виде чекбоксов, а в виде выпадайки
133
+ # options[:only] - только этот ключ (ключи)
134
+ def build_form(form_builder, options)
135
+ return '' unless valid_values.is_a?(Hash) || valid_values.is_a?(Array)
136
+
137
+ if options.is_a? Hash and options[:as] == :select
138
+ return build_select_form(form_builder, options.except(:for, :as))
139
+ end
140
+
141
+ options = {block: '<div class="form_check_box_block">%s %s</div>', map: {}}.merge(options)
142
+
143
+ set_value_in_hash options
144
+ val = options[:value]
145
+
146
+ result = ''
147
+ if valid_values.is_a? Array
148
+ method = :each_with_index
149
+ elsif valid_values.is_a? Hash
150
+ method = :each_pair
151
+ end
152
+
153
+ valid_values.send(method) do |k, v|
154
+ if !options[:only] || options[:only] == k || options[:only].try(:include?, k)
155
+ result += form_builder.fields_for :value do |ff|
156
+
157
+ begin
158
+ checked = ! val.try(:[], k).to_i.zero?
159
+ rescue
160
+ checked = false
161
+ end
162
+
163
+ v = options[:map][v] || v
164
+
165
+ # required не встраиваю, иначе пока я все чекбоксы не отмечу, не могу отправить форму
166
+ data = options[:data] ? extract_data_for_key(k, options[:data]) : nil
167
+ sprintf(options[:block], ff.check_box(k.to_sym, {checked: checked}, '1', options[:for] == :search ? nil : '0'), ff.label(k.to_sym, v, data: data)).html_safe
168
+ end
169
+ end
170
+ end
171
+
172
+ result
173
+ end
174
+
175
+
176
+
177
+ private
178
+
179
+ def build_select_form(form_builder, options)
180
+ set_value_in_hash options
181
+
182
+ values = valid_values_enum
183
+ if options[:only]
184
+ options[:only] = [options[:only]] unless options[:only].is_a? Array
185
+ values.select! { |o| o[1].in? options[:only] }
186
+ end
187
+
188
+ if options[:except]
189
+ options[:except] = [options[:except]] unless options[:except].is_a? Array
190
+ values.reject! { |o| o[1].in? options[:except] }
191
+ end
192
+
193
+ form_builder.select :value, values, {selected: options[:value], required: options[:required], include_blank: !options[:required]}, class: 'form-control'
194
+ end
195
+
196
+ def extract_data_for_key(request_key, data)
197
+ data.reduce({}) do |r, (key, values)|
198
+ r[key] = values[request_key] if values[request_key]
199
+ r
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,35 @@
1
+ class CckForms::ParameterTypeClass::Date
2
+ include CckForms::ParameterTypeClass::Base
3
+ include CckForms::DateTime
4
+
5
+ def self.name
6
+ 'Дата'
7
+ end
8
+
9
+ def build_form(form_builder, options)
10
+ set_value_in_hash options
11
+ self.class.build_date_form(form_builder, options)
12
+ end
13
+
14
+ def self.build_date_form(form_builder, options, type = '')
15
+ val = options[:value].is_a?(Hash) ? options[:value][type] : options[:value]
16
+ val = CckForms::ParameterTypeClass::Time::date_object_from_what_stored_in_database(val)
17
+ form_element_options, form_element_html = CckForms::ParameterTypeClass::Time::default_options_for_date_time_selectors(val)
18
+ form_element_html.merge!({required: options[:required]})
19
+ ('<div class="form-inline">%s</div>' % form_builder.fields_for(:value) { |datetime_builder| datetime_builder.date_select type, form_element_options, form_element_html}).html_safe
20
+ end
21
+
22
+ def to_s(options = nil)
23
+ if value.is_a? Time
24
+ the_value = {
25
+ '(1i)' => value.year,
26
+ '(2i)' => value.month,
27
+ '(3i)' => value.day,
28
+ }
29
+ end
30
+
31
+ the_value ||= value
32
+
33
+ "#{the_value.try(:[], '(3i)')}.#{the_value.try(:[], '(2i)')}.#{the_value.try(:[], '(1i)')}"
34
+ end
35
+ end
@@ -0,0 +1,53 @@
1
+ class CckForms::ParameterTypeClass::DateRange
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Диапазон между двумя датами'
6
+ end
7
+
8
+ def mongoize
9
+ value_from_form = value
10
+ return nil if value_from_form.blank?
11
+ db_representation = {}
12
+
13
+ %w(from till).each do |type|
14
+ type_hash = {}
15
+ %w((1i) (2i) (3i)).each do |field|
16
+ type_hash.merge!("#{field}" => value_from_form.try(:[], "#{type + field}"))
17
+ end
18
+ db_representation[type] = CckForms::ParameterTypeClass::Time::date_object_from_what_stored_in_database(type_hash)
19
+ end
20
+
21
+ db_representation
22
+ end
23
+
24
+ def build_form(form_builder, options)
25
+ result = []
26
+ set_value_in_hash options
27
+
28
+ [:from, :till].each do |type|
29
+ result << CckForms::ParameterTypeClass::Date.build_date_form(form_builder, options, type)
30
+ end
31
+
32
+ result.join.html_safe
33
+ end
34
+
35
+ def to_s
36
+ return '' unless value.present? && value.is_a?(Hash)
37
+ types = {}
38
+ [:from, :till].each { |type| types[type] = value[type].strftime('%d.%m.%Y') if value[type].is_a?(Time) }
39
+ from, till = types[:from], types[:till]
40
+
41
+ if from.blank?
42
+ "до #{till}"
43
+ elsif till.blank?
44
+ "от #{from}"
45
+ elsif from == till
46
+ from.to_s
47
+ else
48
+ [from, till].join(' - ')
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,76 @@
1
+ class CckForms::ParameterTypeClass::DateTime
2
+ include CckForms::ParameterTypeClass::Base
3
+ include CckForms::DateTime
4
+
5
+ def self.name
6
+ 'Дата и время'
7
+ end
8
+
9
+ def build_form(form_builder, options)
10
+ set_value_in_hash options
11
+ value = CckForms::ParameterTypeClass::Time::date_object_from_what_stored_in_database(options[:value])
12
+ form_element_options, form_element_html = CckForms::ParameterTypeClass::Time.default_options_for_date_time_selectors(value)
13
+ form_element_options.merge!({minute_step: 5})
14
+ form_element_html.merge!({required: options[:required]})
15
+ ('<div class="form-inline">%s</div>' % form_builder.fields_for(:value) { |datetime_builder| datetime_builder.datetime_select '', form_element_options, form_element_html})
16
+ end
17
+
18
+ # Формирует строковое представление даты и времени. Если options :символ, это эквивалентно options[:символ] = true,
19
+ # например:
20
+ #
21
+ # date_attr.to_s :only_date
22
+ # date_attr.to_s :only_date => true # эквивалентно
23
+ #
24
+ # Ключи options:
25
+ #
26
+ # year_obligatory - вывести год, по-умолчанию, он не показывается, если равен текущему
27
+ # only_date - только дату, без времени
28
+ # rus_date - дату по-русски, типа "2 июля"
29
+ #
30
+ # По-умолчанию, вернет строку вида "01.02.2012, 12:49". Если что-то сломалось, вернет пустую строку.
31
+ def to_s(options=nil)
32
+ value = if self.value.is_a? Time
33
+ {
34
+ '(1i)' => self.value.year,
35
+ '(2i)' => self.value.month,
36
+ '(3i)' => self.value.day,
37
+ '(4i)' => self.value.hour,
38
+ '(5i)' => self.value.min,
39
+ }
40
+ else
41
+ self.value
42
+ end
43
+
44
+ return '' unless value and
45
+ value.is_a?(Hash) and
46
+ value.try(:[], '(1i)').to_i > 0 and
47
+ value.try(:[], '(2i)').to_i > 0 and
48
+ value.try(:[], '(3i)').to_i > 0
49
+
50
+ options = {options => true} if options.is_a? Symbol
51
+ options = {} unless options.is_a? Hash
52
+
53
+ now = Date::today
54
+ date = DateTime.new value.try(:[], '(1i)').to_i, value.try(:[], '(2i)').to_i, value.try(:[], '(3i)').to_i, value.try(:[], '(4i)').to_i, value.try(:[], '(5i)').to_i
55
+ date = date.in_time_zone(Rails.application.config.time_zone)
56
+
57
+ need_year = options[:year_obligatory] || now.strftime('%Y') != date.strftime('%Y')
58
+
59
+ if options[:rus_date]
60
+ date_string = Russian::strftime(date, '%e %B' + (need_year ? ' %Y' : '')) # 2 июля
61
+ else
62
+ date_string = date.strftime('%d.%m' + (need_year ? '.%Y' : ''))
63
+ end
64
+
65
+ time_string = date.strftime '%H:%M'
66
+
67
+ if options[:only_date]
68
+ return date_string
69
+ else
70
+ return "#{date_string}, #{time_string}"
71
+ end
72
+
73
+ rescue
74
+ ''
75
+ end
76
+ end
@@ -0,0 +1,53 @@
1
+ class CckForms::ParameterTypeClass::Enum
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Значение из списка'
6
+ end
7
+
8
+ def mongoize
9
+ value.presence
10
+ end
11
+
12
+ def to_s(options = nil)
13
+ return '' if value.blank?
14
+ valid_values[value].to_s
15
+ end
16
+
17
+ def search(selectable, field, query)
18
+ if query.is_a? Hash
19
+ query = query.map { |k, v| v == '1' ? k : nil }.compact
20
+ end
21
+ query = [query] unless query.is_a? Array
22
+
23
+ if query.any?
24
+ selectable.where(field.to_sym.in => query)
25
+ else
26
+ selectable
27
+ end
28
+ end
29
+
30
+ def build_form(form_builder, options)
31
+
32
+ if options.is_a? Hash and options[:as] == 'checkboxes'
33
+ options = options.except(:for, :as)
34
+ checkboxes = CckForms::ParameterTypeClass::Checkboxes.new valid_values: self.valid_values, value: self.value
35
+ return checkboxes.build_form(form_builder, options)
36
+ end
37
+
38
+ set_value_in_hash options
39
+
40
+ values = valid_values_enum
41
+ if options[:only]
42
+ options[:only] = [options[:only]] unless options[:only].is_a? Array
43
+ values.select! { |o| o[1].in? options[:only] }
44
+ end
45
+
46
+ if options[:except]
47
+ options[:except] = [options[:except]] unless options[:except].is_a? Array
48
+ values.reject! { |o| o[1].in? options[:except] }
49
+ end
50
+
51
+ form_builder.select :value, values, {selected: options[:value], required: options[:required], include_blank: !options[:required]}, class: 'form-control '
52
+ end
53
+ end
@@ -0,0 +1,80 @@
1
+ class CckForms::ParameterTypeClass::File
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Файл'
6
+ end
7
+
8
+ def self.file_type
9
+ ::Neofiles::File
10
+ end
11
+
12
+ def file_type
13
+ self.class.file_type
14
+ end
15
+
16
+ # Если передан Neofiles::File, вернет его идентификатор, если строка - вернет ее, иначе - nil.
17
+ def mongoize
18
+ case value
19
+ when file_type then value.id
20
+ when ::String then value
21
+ end
22
+ end
23
+
24
+ # Попытаемся получить объект Neofiles::File по его идентификатору. Если не получилось, вернем nil.
25
+ def self.demongoize_value(value, parameter_type_class=nil)
26
+ file_type.find(value) unless value.blank?
27
+ rescue Mongoid::Errors::DocumentNotFound
28
+ nil
29
+ end
30
+
31
+ # Строит форму выбора и загрузки 1 картинки.
32
+ #
33
+ # Ставит ДИВ и делает аяксовый вызов метода file_compact контроллера Neofiles::AdminController.
34
+ #
35
+ # Ключи options:
36
+ #
37
+ # value - текущее значение (идентификатор или объект Neofiles::File)
38
+ #
39
+ def build_form(form_builder, options)
40
+ set_value_in_hash options
41
+ self.class.create_load_form helper: self,
42
+ file: options[:value].presence,
43
+ input_name: form_builder.object_name + '[value]',
44
+ widget_id: form_builder_name_to_id(form_builder, '[value]'),
45
+ with_desc: options[:with_desc]
46
+ end
47
+
48
+ def self.create_load_form(helper:, file:, input_name:, append_create: false, clean_remove: false, widget_id: nil, disabled: false, multiple: false, with_desc: false)
49
+ cont_id = 'container_' + (widget_id.presence || form_name_to_id(input_name))
50
+
51
+ # создаем временное поле, чтобы пока аяксовый ответ не вернется, мы могли все же отправить родительскую форму
52
+ # и не потерять при этом данные из поля
53
+ temp_field, remove_temp_field = '', ''
54
+ if file.present? && file.is_a?(String)
55
+ temp_id = "temp_file_field_#{file}"
56
+ temp_field = '<input id="' + temp_id + '" type="hidden" name="' + input_name + '" value="' + file + '">'
57
+ remove_temp_field = '$("#' + temp_id + '").remove();'
58
+ end
59
+
60
+ '<div id="' + cont_id + '"></div>
61
+ ' + temp_field + '
62
+
63
+ <script type="text/javascript">
64
+ $(function() {
65
+ $("#' + cont_id + '").load("' + helper.neofiles_file_compact_path(id: file, input_name: input_name, widget_id: widget_id, append_create: append_create ? '1' : nil, clean_remove: clean_remove ? '1' : nil, disabled: disabled ? '1' : nil, multiple: multiple ? '1' : nil, with_desc: with_desc ? '1' : nil) + '", null, function() {
66
+ $(this).children().unwrap();
67
+ ' + remove_temp_field + '
68
+ });
69
+ });
70
+ </script>'
71
+ end
72
+
73
+ def to_s
74
+ ''
75
+ end
76
+
77
+ def to_diff_value(options = {})
78
+ "Файл: #{self.value.try! :name}"
79
+ end
80
+ end
@@ -0,0 +1,20 @@
1
+ class CckForms::ParameterTypeClass::Float
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Дробное число'
6
+ end
7
+
8
+ def mongoize
9
+ value.to_f
10
+ end
11
+
12
+ def to_s(options = nil)
13
+ value.to_f != 0.0 ? value.to_f : ''
14
+ end
15
+
16
+ def build_form(form_builder, options)
17
+ set_value_in_hash options
18
+ form_builder.number_field :value, {class: 'form-control input-small'}.merge(options)
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class CckForms::ParameterTypeClass::Image < CckForms::ParameterTypeClass::File
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Картинка'
6
+ end
7
+
8
+ def self.file_type
9
+ ::Neofiles::Image
10
+ end
11
+
12
+ def file_type
13
+ self.class.file_type
14
+ end
15
+
16
+ def to_diff_value(options = {})
17
+ view_context = options[:view_context]
18
+ "<img style='width: 64px; height: 64px;' src='#{view_context.neofiles_image_path(id: value, format: '64x64', crop: 1)}'>".html_safe
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ class CckForms::ParameterTypeClass::Integer
2
+ include CckForms::ParameterTypeClass::Base
3
+
4
+ def self.name
5
+ 'Целое число'
6
+ end
7
+
8
+ def mongoize
9
+ value.to_i
10
+ end
11
+
12
+ def to_s(options = nil)
13
+ value.to_i != 0 ? value.to_i.to_s : ''
14
+ end
15
+
16
+ # '123' -> 123
17
+ # '100/' -> $gte: 100
18
+ # '100/150' -> $gte: 100, $lte: 150
19
+ # '/150' -> $lte: 150
20
+ #
21
+ # l: 100 -> $gte: 100
22
+ # l: 100, h: 150 -> $gte: 100, $lte: 150
23
+ # h: 150 -> $lte: 150
24
+ def search(selectable, field, query)
25
+ if query.is_a?(Hash) || query.to_s.include?('/')
26
+ low, high = query.is_a?(Hash) ? [query[:l] || query['l'], query[:h] || query['h']] : query.to_s.split('/')
27
+
28
+ if low.to_i > 0
29
+ selectable = selectable.gte(field => low.to_i)
30
+ end
31
+
32
+ if high.to_i > 0
33
+ selectable = selectable.lte(field => high.to_i)
34
+ end
35
+
36
+ selectable
37
+ else
38
+ selectable.where(field => query.to_i)
39
+ end
40
+ end
41
+
42
+ # Примеры options[:values] (работает, если передано options[:as] == :select и options[:for] == :search):
43
+ #
44
+ # диапазоны: [['не больше 10', '/10'], ['11-20', '11/20'], ['21-30', '21/30'], ['свыше 30', '31/']]
45
+ # перечисление: [['один', '1'], ['два', '2'], ['три', '3']]
46
+ # комбинирование: [['один', '1'], ['два', '2'], ['три и больше', '3/']]
47
+ def build_form(form_builder, options = {})
48
+ set_value_in_hash options
49
+
50
+ default_style = {class: 'form-control input-small'}
51
+
52
+ if options[:for] == :search
53
+ res = []
54
+ as = options[:as]
55
+ only = options[:only]
56
+ options = options.except :only, :for
57
+
58
+ if as == :select
59
+ res << form_builder.select(:value, [['', '']] + options[:values], options.merge(selected: options[:value]), class: 'form-control input-small')
60
+ else
61
+ value = options[:value].is_a?(Hash) ? options[:value].symbolize_keys : {}
62
+
63
+ if !only || only == :low
64
+ res << form_builder.text_field(:l, options.merge(index: 'value', value: value[:l]).reverse_merge(default_style))
65
+ end
66
+
67
+ if !only || only == :high
68
+ res << form_builder.text_field(:h, options.merge(index: 'value', value: value[:h]).reverse_merge(default_style))
69
+ end
70
+ end
71
+
72
+ res.join ' – '
73
+ else
74
+ form_builder.number_field :value, options.reverse_merge(default_style)
75
+ end
76
+ end
77
+ end