cck_forms 3.1.1 → 3.1.2
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.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/cck_forms/date_time.rb +1 -1
- data/lib/cck_forms/parameter_type_class/album.rb +0 -4
- data/lib/cck_forms/parameter_type_class/base.rb +1 -1
- data/lib/cck_forms/parameter_type_class/boolean.rb +2 -6
- data/lib/cck_forms/parameter_type_class/checkboxes.rb +3 -7
- data/lib/cck_forms/parameter_type_class/date.rb +1 -5
- data/lib/cck_forms/parameter_type_class/date_range.rb +2 -6
- data/lib/cck_forms/parameter_type_class/date_time.rb +0 -4
- data/lib/cck_forms/parameter_type_class/enum.rb +1 -5
- data/lib/cck_forms/parameter_type_class/file.rb +5 -8
- data/lib/cck_forms/parameter_type_class/float.rb +1 -5
- data/lib/cck_forms/parameter_type_class/image.rb +0 -5
- data/lib/cck_forms/parameter_type_class/integer.rb +1 -5
- data/lib/cck_forms/parameter_type_class/integer_range.rb +5 -9
- data/lib/cck_forms/parameter_type_class/map.rb +4 -23
- data/lib/cck_forms/parameter_type_class/phones.rb +4 -7
- data/lib/cck_forms/parameter_type_class/string.rb +0 -4
- data/lib/cck_forms/parameter_type_class/string_collection.rb +0 -4
- data/lib/cck_forms/parameter_type_class/text.rb +2 -6
- data/lib/cck_forms/parameter_type_class/time.rb +1 -5
- data/lib/cck_forms/parameter_type_class/watermarkless_album.rb +0 -4
- data/lib/cck_forms/parameter_type_class/watermarkless_image.rb +0 -4
- data/lib/cck_forms/parameter_type_class/work_hours.rb +18 -23
- data/lib/cck_forms/version.rb +1 -1
- data/vendor/assets/javascripts/cck_forms/jquery.workhours.js +57 -58
- data/vendor/assets/javascripts/cck_forms/map.js.coffee +3 -29
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8dceaa1bbafb95e971aa01a98f84e506330928e7
|
4
|
+
data.tar.gz: 99ae8648bafac7968f576b8f3e2c822c987691e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 035dc59ed36c8546d3c78ef4a0c9a1d50300943ba7b0c6c71e8afff7d10c1d99430b6580fdc26ebcee6224d241d293871d3b6d0c6bf8bc6c7e5b50a7c44c0de8
|
7
|
+
data.tar.gz: 377da4b610b5d1b961a835786cd6eb4b95aef62326ca5129527fe43e2ee7610415d5dba720d79e36103b53c9b3bc662eeeceb9ee823467063a05276df39bd603
|
data/README.md
CHANGED
@@ -210,6 +210,8 @@ Available field types
|
|
210
210
|
|
211
211
|
***WorkHours***: complex input to construct work schedule on a weekly basis.
|
212
212
|
|
213
|
+
***WatermarklessAlbum***, ***WatermarklessImage***: same as Album & Image, but do not place watermarks. For banners or
|
214
|
+
important sliders, for example.
|
213
215
|
|
214
216
|
Configuration
|
215
217
|
-------------
|
data/lib/cck_forms/date_time.rb
CHANGED
@@ -49,7 +49,7 @@ module CckForms::DateTime
|
|
49
49
|
[{default: date_in_time_zone, include_blank: false, with_css_classes: true}, {class: 'form-control'}]
|
50
50
|
end
|
51
51
|
|
52
|
-
def demongoize_value(value,
|
52
|
+
def demongoize_value(value, _parameter_type_class=nil)
|
53
53
|
date_object_from_what_stored_in_database value
|
54
54
|
end
|
55
55
|
end
|
@@ -4,10 +4,6 @@ class CckForms::ParameterTypeClass::Album
|
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
include CckForms::NeofilesDenormalize
|
6
6
|
|
7
|
-
def self.name
|
8
|
-
'Альбом'
|
9
|
-
end
|
10
|
-
|
11
7
|
# Converts input array of Neofiles::Image or IDs to array of hashes (denormalized image data) or IDs
|
12
8
|
def mongoize
|
13
9
|
the_value = value.is_a?(Hash) ? value['value'] : value
|
@@ -3,10 +3,6 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::Boolean
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Галочка (да/нет)'
|
8
|
-
end
|
9
|
-
|
10
6
|
# Is it true?
|
11
7
|
def value?
|
12
8
|
value.present? && value != '0'
|
@@ -18,8 +14,8 @@ class CckForms::ParameterTypeClass::Boolean
|
|
18
14
|
end
|
19
15
|
|
20
16
|
# 'yes/no' string
|
21
|
-
def to_s(
|
22
|
-
value? ? '
|
17
|
+
def to_s(_options = nil)
|
18
|
+
value? ? I18n.t('cck_forms.boolean.yes') : I18n.t('cck_forms.boolean.no')
|
23
19
|
end
|
24
20
|
|
25
21
|
# Checkbox HTML
|
@@ -3,10 +3,6 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::Checkboxes
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Галочки'
|
8
|
-
end
|
9
|
-
|
10
6
|
# {kazakh: '1', russian: '0', english: '1'} -> ['kazakh', 'english']
|
11
7
|
def mongoize
|
12
8
|
resulting_set = []
|
@@ -86,9 +82,9 @@ class CckForms::ParameterTypeClass::Checkboxes
|
|
86
82
|
param_title = cck_parameter ? " «#{cck_parameter.title}»" : ''
|
87
83
|
|
88
84
|
if unchecked_num == 0
|
89
|
-
return
|
85
|
+
return I18n.t('cck_forms.checkboxes.all_values', param_title: param_title)
|
90
86
|
elsif unchecked_num < checked_keys.count./(2).round
|
91
|
-
return
|
87
|
+
return I18n.t('cck_forms.checkboxes.all_values_except', param_title: param_title) + ' ' + valid_values.values_at(*unchecked_keys).map { |x| sprintf(template, x) }.join(glue)
|
92
88
|
end
|
93
89
|
end
|
94
90
|
|
@@ -173,7 +169,7 @@ class CckForms::ParameterTypeClass::Checkboxes
|
|
173
169
|
|
174
170
|
v = options[:map][v] || v
|
175
171
|
|
176
|
-
# required
|
172
|
+
# skip `required` since form will not be submitted unless a user checks all the checkboxes
|
177
173
|
data = options[:data] ? extract_data_for_key(k, options[:data]) : nil
|
178
174
|
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
|
179
175
|
end
|
@@ -4,10 +4,6 @@ class CckForms::ParameterTypeClass::Date
|
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
include CckForms::DateTime
|
6
6
|
|
7
|
-
def self.name
|
8
|
-
'Дата'
|
9
|
-
end
|
10
|
-
|
11
7
|
# Date SELECT
|
12
8
|
def build_form(form_builder, options)
|
13
9
|
set_value_in_hash options
|
@@ -24,7 +20,7 @@ class CckForms::ParameterTypeClass::Date
|
|
24
20
|
end
|
25
21
|
|
26
22
|
# "12.12.2012"
|
27
|
-
def to_s(
|
23
|
+
def to_s(_options = nil)
|
28
24
|
if value.is_a? Time
|
29
25
|
the_value = {
|
30
26
|
'(1i)' => value.year,
|
@@ -3,10 +3,6 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::DateRange
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Диапазон между двумя датами'
|
8
|
-
end
|
9
|
-
|
10
6
|
# Converts input hash of type {from: ..., till: ...} to MongoDB format
|
11
7
|
def mongoize
|
12
8
|
value_from_form = value
|
@@ -46,9 +42,9 @@ class CckForms::ParameterTypeClass::DateRange
|
|
46
42
|
from, till = types[:from], types[:till]
|
47
43
|
|
48
44
|
if from.blank?
|
49
|
-
|
45
|
+
[I18n.t('cck_forms.date_range.till'), till].join(' ')
|
50
46
|
elsif till.blank?
|
51
|
-
|
47
|
+
[I18n.t('cck_forms.date_range.from'), from].join(' ')
|
52
48
|
elsif from == till
|
53
49
|
from.to_s
|
54
50
|
else
|
@@ -3,16 +3,12 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::Enum
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Значение из списка'
|
8
|
-
end
|
9
|
-
|
10
6
|
def mongoize
|
11
7
|
value.presence
|
12
8
|
end
|
13
9
|
|
14
10
|
# Current string value from valid_values
|
15
|
-
def to_s(
|
11
|
+
def to_s(_options = nil)
|
16
12
|
return '' if value.blank?
|
17
13
|
valid_values[value].to_s
|
18
14
|
end
|
@@ -4,10 +4,6 @@ class CckForms::ParameterTypeClass::File
|
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
include CckForms::NeofilesDenormalize
|
6
6
|
|
7
|
-
def self.name
|
8
|
-
'Файл'
|
9
|
-
end
|
10
|
-
|
11
7
|
def self.file_type
|
12
8
|
::Neofiles::File
|
13
9
|
end
|
@@ -52,8 +48,9 @@ class CckForms::ParameterTypeClass::File
|
|
52
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)
|
53
49
|
cont_id = 'container_' + (widget_id.presence || form_name_to_id(input_name))
|
54
50
|
|
55
|
-
#
|
56
|
-
#
|
51
|
+
# create temporary hidden field to keep the value in form context until AJAX request is finished
|
52
|
+
# (otherwise submitting the form before that moment sends it without the file value which can lead to confusion
|
53
|
+
# and consequent data loss in a controller)
|
57
54
|
file_id = file.is_a?(file_type) ? file.id.to_s : file.to_s
|
58
55
|
temp_field, remove_temp_field = '', ''
|
59
56
|
if file_id.present?
|
@@ -89,12 +86,12 @@ class CckForms::ParameterTypeClass::File
|
|
89
86
|
end
|
90
87
|
|
91
88
|
# Returns empty string
|
92
|
-
def to_s
|
89
|
+
def to_s(_options = nil)
|
93
90
|
''
|
94
91
|
end
|
95
92
|
|
96
93
|
# Returns a file name
|
97
|
-
def to_diff_value(
|
94
|
+
def to_diff_value(_options = {})
|
98
95
|
value.try! :name
|
99
96
|
end
|
100
97
|
end
|
@@ -3,15 +3,11 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::Float
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Дробное число'
|
8
|
-
end
|
9
|
-
|
10
6
|
def mongoize
|
11
7
|
value.to_f
|
12
8
|
end
|
13
9
|
|
14
|
-
def to_s(
|
10
|
+
def to_s(_options = nil)
|
15
11
|
value.to_f != 0.0 ? value.to_f : ''
|
16
12
|
end
|
17
13
|
|
@@ -3,15 +3,11 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::Integer
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Целое число'
|
8
|
-
end
|
9
|
-
|
10
6
|
def mongoize
|
11
7
|
value.to_i
|
12
8
|
end
|
13
9
|
|
14
|
-
def to_s(
|
10
|
+
def to_s(_options = nil)
|
15
11
|
value.to_i != 0 ? value.to_i.to_s : ''
|
16
12
|
end
|
17
13
|
|
@@ -7,10 +7,6 @@
|
|
7
7
|
class CckForms::ParameterTypeClass::IntegerRange # Rover :)
|
8
8
|
include CckForms::ParameterTypeClass::Base
|
9
9
|
|
10
|
-
def self.name
|
11
|
-
'Диапазон между двумя целыми числами'
|
12
|
-
end
|
13
|
-
|
14
10
|
# {from: 500, to: 1000, ranges: {"300-600" => true, "601-900" => true, "901-1500" => false}}
|
15
11
|
def mongoize
|
16
12
|
value_from_form = value
|
@@ -74,9 +70,9 @@ class CckForms::ParameterTypeClass::IntegerRange # Rover :)
|
|
74
70
|
return '' if from.zero? && till.zero?
|
75
71
|
|
76
72
|
if from.zero?
|
77
|
-
|
73
|
+
[I18n.t('cck_forms.integer_range.till'), till].join(' ')
|
78
74
|
elsif till.zero?
|
79
|
-
|
75
|
+
[I18n.t('cck_forms.integer_range.from'), from].join(' ')
|
80
76
|
elsif from == till
|
81
77
|
from.to_s
|
82
78
|
else
|
@@ -145,16 +141,16 @@ class CckForms::ParameterTypeClass::IntegerRange # Rover :)
|
|
145
141
|
end
|
146
142
|
|
147
143
|
def default_integer_range_delimiter
|
148
|
-
|
144
|
+
'–'
|
149
145
|
end
|
150
146
|
|
151
147
|
def humanized_integer_ranges_for_select
|
152
148
|
@extra_options[:ranges].map do |range_string|
|
153
149
|
low, high = range_string.split(range_string_delimiter)
|
154
150
|
if low.to_i.to_s != low.to_s
|
155
|
-
option_text =
|
151
|
+
option_text = [I18n.t('cck_forms.integer_range.less_than'), high].join(' ')
|
156
152
|
elsif high.to_i.to_s != high.to_s
|
157
|
-
option_text =
|
153
|
+
option_text = [I18n.t('cck_forms.integer_range.more_than'), low].join(' ')
|
158
154
|
else
|
159
155
|
option_text = [low, high].join(default_integer_range_delimiter)
|
160
156
|
end
|
@@ -12,10 +12,6 @@ class CckForms::ParameterTypeClass::Map
|
|
12
12
|
|
13
13
|
mattr_accessor :google_maps_api_key
|
14
14
|
|
15
|
-
def self.name
|
16
|
-
'Точка на карте'
|
17
|
-
end
|
18
|
-
|
19
15
|
# In MongoDB: {latlon: [x, y], zoom: z}
|
20
16
|
#
|
21
17
|
# In application: {
|
@@ -23,7 +19,7 @@ class CckForms::ParameterTypeClass::Map
|
|
23
19
|
# longitude: y,
|
24
20
|
# zoom: z
|
25
21
|
# }
|
26
|
-
def self.demongoize_value(value,
|
22
|
+
def self.demongoize_value(value, _parameter_type_class=nil)
|
27
23
|
value = value.to_h
|
28
24
|
value.stringify_keys!
|
29
25
|
latlon = value['latlon'] || []
|
@@ -145,8 +141,6 @@ class CckForms::ParameterTypeClass::Map
|
|
145
141
|
#
|
146
142
|
# 1 click on a map places a point (writing to hidden fields). 1 click on a point removes it (emptying fields).
|
147
143
|
#
|
148
|
-
# TODO: remove listeners of "city" events, it's out of scope for this gem
|
149
|
-
#
|
150
144
|
# options:
|
151
145
|
#
|
152
146
|
# value - current point
|
@@ -180,21 +174,8 @@ class CckForms::ParameterTypeClass::Map
|
|
180
174
|
inputs << value_builder.hidden_field(:type, value: value['type'])
|
181
175
|
end
|
182
176
|
|
183
|
-
city_id = id.clone
|
184
|
-
city_id['map'] = 'city'
|
185
|
-
city_id += '_value'
|
186
|
-
|
187
|
-
cities_js = []
|
188
|
-
city_class = if defined?(KazakhstanCities::City) then KazakhstanCities::City elsif defined?(City) then City end
|
189
|
-
if city_class
|
190
|
-
city_class.all.each do |city|
|
191
|
-
cities_js.push [city.id, {lat: city.lat.to_f, lon: city.lon.to_f, zoom: city.zoom.to_i}]
|
192
|
-
end
|
193
|
-
end
|
194
|
-
cities_js = Hash[cities_js].to_json
|
195
|
-
|
196
177
|
allowed_maps = @@map_providers
|
197
|
-
map_names = {'google' => 'Google', 'yandex' => '
|
178
|
+
map_names = {'google' => 'Google', 'yandex' => 'Yandex'}
|
198
179
|
selected_map_type = value['type'].in?(allowed_maps) ? value['type'] : allowed_maps.first
|
199
180
|
|
200
181
|
switchers = []
|
@@ -242,7 +223,7 @@ class CckForms::ParameterTypeClass::Map
|
|
242
223
|
window.onload = loadMapScripts;
|
243
224
|
</script>
|
244
225
|
|
245
|
-
<div data-map-data-source data-options='#{options.to_json}' data-id="#{id}" data-
|
226
|
+
<div data-map-data-source data-options='#{options.to_json}' data-id="#{id}" data-allowed-maps='#{allowed_maps.to_json}' style="width: #{options[:width]}px; height: #{options[:height]}px">
|
246
227
|
#{map_html_containers.join}
|
247
228
|
</div>
|
248
229
|
|
@@ -252,7 +233,7 @@ class CckForms::ParameterTypeClass::Map
|
|
252
233
|
end
|
253
234
|
|
254
235
|
# Returns a 64x64 IMG with a marker (see #img_tag)
|
255
|
-
def to_diff_value(
|
236
|
+
def to_diff_value(_options = {})
|
256
237
|
demongoize_value!
|
257
238
|
img_tag(64, 64, marker_size: :small)
|
258
239
|
end
|
@@ -8,10 +8,6 @@ class CckForms::ParameterTypeClass::Phones
|
|
8
8
|
PREFIX = Rails.application.config.cck_forms.phones.prefix
|
9
9
|
NUMBER_PARTS_GLUE = Rails.application.config.cck_forms.phones.number_parts_glue
|
10
10
|
|
11
|
-
def self.name
|
12
|
-
'Телефоны'
|
13
|
-
end
|
14
|
-
|
15
11
|
# Filters input array for phone-like Hashes: prefix: ..., code: ..., number: ...
|
16
12
|
# Cleans them up and returns.
|
17
13
|
#
|
@@ -46,7 +42,7 @@ class CckForms::ParameterTypeClass::Phones
|
|
46
42
|
end
|
47
43
|
|
48
44
|
# Cleanup phone format
|
49
|
-
def self.demongoize_value(value,
|
45
|
+
def self.demongoize_value(value, _parameter_type_class=nil)
|
50
46
|
if value
|
51
47
|
value.map do |phone|
|
52
48
|
phone = phone.stringify_keys!
|
@@ -124,7 +120,7 @@ class CckForms::ParameterTypeClass::Phones
|
|
124
120
|
$phones.children("p:last").after($newPhone);
|
125
121
|
}
|
126
122
|
|
127
|
-
$phones.append('<a href="#" class="add_more"
|
123
|
+
$phones.append('<a href="#" class="add_more">#{I18n.t 'cck_forms.phones.add_more'}</a>');
|
128
124
|
$phones.children(".add_more").click(function() {
|
129
125
|
for(var i = 0; i < doTimes; ++ i) {
|
130
126
|
createPhone();
|
@@ -163,7 +159,8 @@ HTML
|
|
163
159
|
end
|
164
160
|
|
165
161
|
def to_s(options = {})
|
166
|
-
HTML::FullSanitizer
|
162
|
+
sanitizer = defined?(Rails::Html::FullSanitizer) ? Rails::Html::FullSanitizer : HTML::FullSanitizer
|
163
|
+
sanitizer.new.sanitize to_html(options)
|
167
164
|
end
|
168
165
|
|
169
166
|
|
@@ -3,19 +3,15 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::Text
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Текст'
|
8
|
-
end
|
9
|
-
|
10
6
|
# Builds a TEXTAREA
|
11
7
|
def build_form(form_builder, options)
|
12
8
|
set_value_in_hash options
|
13
9
|
form_builder.text_area :value, {cols: 50, rows: 5, class: 'form-control'}.merge(options)
|
14
10
|
end
|
15
11
|
|
16
|
-
#
|
12
|
+
# Wraps DIFF output to .wall (bootstrap-specific bounded block)
|
17
13
|
def to_diff_value(options = {})
|
18
|
-
to_html.presence.try do |html|
|
14
|
+
to_html(options).presence.try do |html|
|
19
15
|
"<div class='well well-small'>#{html}</div>".html_safe
|
20
16
|
end
|
21
17
|
end
|
@@ -4,10 +4,6 @@ class CckForms::ParameterTypeClass::Time
|
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
include CckForms::DateTime
|
6
6
|
|
7
|
-
def self.name
|
8
|
-
'Время'
|
9
|
-
end
|
10
|
-
|
11
7
|
# Time SELECT
|
12
8
|
def build_form(form_builder, options)
|
13
9
|
set_value_in_hash options
|
@@ -19,7 +15,7 @@ class CckForms::ParameterTypeClass::Time
|
|
19
15
|
end
|
20
16
|
|
21
17
|
# "19:34"
|
22
|
-
def to_s(
|
18
|
+
def to_s(_options = nil)
|
23
19
|
if value.is_a? Time
|
24
20
|
the_value = {
|
25
21
|
'(4i)' => value.hour,
|
@@ -1,10 +1,6 @@
|
|
1
1
|
# Album without watermark. A subclass of Album.
|
2
2
|
#
|
3
3
|
class CckForms::ParameterTypeClass::WatermarklessAlbum < CckForms::ParameterTypeClass::Album
|
4
|
-
def self.name
|
5
|
-
'Альбом без водяного знака'
|
6
|
-
end
|
7
|
-
|
8
4
|
def cck_image_type
|
9
5
|
CckForms::ParameterTypeClass::WatermarklessImage
|
10
6
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
# Image without watermark. A subclass of Image.
|
2
2
|
#
|
3
3
|
class CckForms::ParameterTypeClass::WatermarklessImage < CckForms::ParameterTypeClass::Image
|
4
|
-
def self.name
|
5
|
-
'Картинка без водяного знака'
|
6
|
-
end
|
7
|
-
|
8
4
|
def self.additional_file_attributes
|
9
5
|
{no_wm: '1'}
|
10
6
|
end
|
@@ -3,16 +3,11 @@
|
|
3
3
|
class CckForms::ParameterTypeClass::WorkHours
|
4
4
|
include CckForms::ParameterTypeClass::Base
|
5
5
|
|
6
|
-
def self.name
|
7
|
-
'Часы работы'
|
8
|
-
end
|
9
|
-
|
10
6
|
DAYS = %w{ mon tue wed thu fri sat sun }
|
11
|
-
DAYS_RU_SHORT = %w{ Пн Вт Ср Чт Пт Сб Вс }
|
12
7
|
|
13
|
-
# mon ->
|
14
|
-
def self.
|
15
|
-
|
8
|
+
# mon -> Mon
|
9
|
+
def self.day_to_short(day)
|
10
|
+
I18n.t "cck_forms.work_hours.day_short.#{day}"
|
16
11
|
end
|
17
12
|
|
18
13
|
# mon: {open_time: ..., open_24_hours: ...}, tue: {...}, ... -> MongoDB Hash
|
@@ -91,13 +86,13 @@ class CckForms::ParameterTypeClass::WorkHours
|
|
91
86
|
groups.each_pair do |hours_description, days|
|
92
87
|
if hours_description.present?
|
93
88
|
if days.length == 7
|
94
|
-
template = with_tags ?
|
89
|
+
template = with_tags ? %Q{<span class="workhours-group">%s, <span class="workhours-group-novac">#{I18n.t 'cck_forms.work_hours.no_vacations'}</span></span>} : "%s, #{I18n.t 'cck_forms.work_hours.no_vacations'}"
|
95
90
|
result << sprintf(template, hours_description)
|
96
91
|
else
|
97
92
|
if days == %w{ mon tue wed thu fri }
|
98
|
-
days_description = '
|
93
|
+
days_description = I18n.t 'cck_forms.work_hours.work_days'
|
99
94
|
elsif days == %w{ sat sun }
|
100
|
-
days_description =
|
95
|
+
days_description = I18n.t 'cck_forms.work_hours.sat_sun'
|
101
96
|
else
|
102
97
|
days_description = CckForms::ParameterTypeClass::WorkHours.grouped_days_string(days).mb_chars.downcase
|
103
98
|
end
|
@@ -110,7 +105,7 @@ class CckForms::ParameterTypeClass::WorkHours
|
|
110
105
|
result.join('; ').html_safe
|
111
106
|
end
|
112
107
|
|
113
|
-
def to_s(
|
108
|
+
def to_s(_options = nil)
|
114
109
|
to_html with_tags: false
|
115
110
|
end
|
116
111
|
|
@@ -127,7 +122,7 @@ class CckForms::ParameterTypeClass::WorkHours
|
|
127
122
|
groups << []
|
128
123
|
end
|
129
124
|
|
130
|
-
groups.last <<
|
125
|
+
groups.last << day_to_short(day)
|
131
126
|
prev_index = index
|
132
127
|
end
|
133
128
|
|
@@ -190,21 +185,21 @@ class CckForms::ParameterTypeClass::WorkHours
|
|
190
185
|
def to_s_without_day
|
191
186
|
result = ''
|
192
187
|
if open_24_hours
|
193
|
-
return '
|
188
|
+
return I18n.t 'cck_forms.work_hours.24h'
|
194
189
|
elsif time_present?(open_time) or time_present?(close_time)
|
195
190
|
ots, cts = time_to_s(open_time), time_to_s(close_time)
|
196
191
|
if ots and cts
|
197
192
|
result = sprintf('%s–%s', ots, cts)
|
198
193
|
elsif ots
|
199
|
-
result = sprintf('
|
194
|
+
result = sprintf("#{I18n.t 'cck_forms.work_hours.from'} %s", ots)
|
200
195
|
else
|
201
|
-
result = sprintf('
|
196
|
+
result = sprintf("#{I18n.t 'cck_forms.work_hours.till'} %s", cts)
|
202
197
|
end
|
203
198
|
end
|
204
199
|
|
205
200
|
if open_until_last_client
|
206
201
|
result += ' ' if result.present?
|
207
|
-
result +=
|
202
|
+
result += I18n.t 'cck_forms.work_hours.until_last_client'
|
208
203
|
end
|
209
204
|
|
210
205
|
result
|
@@ -223,16 +218,16 @@ class CckForms::ParameterTypeClass::WorkHours
|
|
223
218
|
|
224
219
|
if template
|
225
220
|
header = ['<ul class="nav nav-pills">']
|
226
|
-
CckForms::ParameterTypeClass::WorkHours::DAYS.each { |day| header << '<li><a href="#"><input name="' + form_builder.object_name + '[days]" type="checkbox" value="' + day + '" /> ' + CckForms::ParameterTypeClass::WorkHours.
|
221
|
+
CckForms::ParameterTypeClass::WorkHours::DAYS.each { |day| header << '<li><a href="#"><input name="' + form_builder.object_name + '[days]" type="checkbox" value="' + day + '" /> ' + CckForms::ParameterTypeClass::WorkHours.day_to_short(day) + '</a></li>' }
|
227
222
|
header = header.push('</ul>').join
|
228
223
|
else
|
229
|
-
header = sprintf '<strong>%s</strong>:%s', CckForms::ParameterTypeClass::WorkHours::
|
224
|
+
header = sprintf '<strong>%s</strong>:%s', CckForms::ParameterTypeClass::WorkHours::day_to_short(day), form_builder.hidden_field(:day)
|
230
225
|
end
|
231
226
|
|
232
227
|
open_until_last_client_html = unless options[:hide_open_until_last_client]
|
233
228
|
<<HTML
|
234
229
|
<div class="checkbox">
|
235
|
-
<label class="form_work_hours_option">#{
|
230
|
+
<label class="form_work_hours_option">#{form_builder.check_box :open_until_last_client} <nobr>#{I18n.t 'cck_forms.work_hours.until_last_client'}</nobr></label>
|
236
231
|
</div>
|
237
232
|
HTML
|
238
233
|
end
|
@@ -246,12 +241,12 @@ HTML
|
|
246
241
|
<table width="100%">
|
247
242
|
<tr>
|
248
243
|
<td width="60%" class="form-inline">
|
249
|
-
|
250
|
-
|
244
|
+
#{I18n.t 'cck_forms.work_hours.time_from'} #{open_time_form}
|
245
|
+
#{I18n.t 'cck_forms.work_hours.time_till'} #{close_time_form}
|
251
246
|
</td>
|
252
247
|
<td width="40%">
|
253
248
|
<div class="checkbox">
|
254
|
-
<label class="form_work_hours_option">#{
|
249
|
+
<label class="form_work_hours_option">#{form_builder.check_box :open_24_hours} #{I18n.t 'cck_forms.work_hours.24h'}</label>
|
255
250
|
</div>
|
256
251
|
#{open_until_last_client_html}
|
257
252
|
</td>
|
data/lib/cck_forms/version.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
$(function() {
|
2
2
|
|
3
3
|
/**
|
4
|
-
*
|
5
|
-
* При установке значения событи change не вызывается!
|
4
|
+
* Helper widget to set & obtain data from HTML of a single day or days group (almost identical)
|
6
5
|
*/
|
7
6
|
$.widget("cck.workhoursday", {
|
8
7
|
|
@@ -30,14 +29,14 @@ $(function() {
|
|
30
29
|
},
|
31
30
|
|
32
31
|
/**
|
33
|
-
*
|
32
|
+
* Day name (mod, tue)
|
34
33
|
*/
|
35
34
|
day: function() {
|
36
35
|
return this._$day.val();
|
37
36
|
},
|
38
37
|
|
39
38
|
/**
|
40
|
-
*
|
39
|
+
* Gets or sets "open 24 hours" checkbox state
|
41
40
|
*/
|
42
41
|
open24Hours: function(value) {
|
43
42
|
if(value !== undefined) {
|
@@ -48,7 +47,7 @@ $(function() {
|
|
48
47
|
},
|
49
48
|
|
50
49
|
/**
|
51
|
-
*
|
50
|
+
* Gets or sets "open until last client" checkbox state
|
52
51
|
*/
|
53
52
|
openUntilLastClient: function(value) {
|
54
53
|
if(value !== undefined) {
|
@@ -59,8 +58,7 @@ $(function() {
|
|
59
58
|
},
|
60
59
|
|
61
60
|
/**
|
62
|
-
*
|
63
|
-
* вернет null.
|
61
|
+
* Converts passed input values to string of form "20:35". If failed, or any of values is empty, returns null
|
64
62
|
*/
|
65
63
|
inputsToTime: function($hoursInput, $minutesInput) {
|
66
64
|
var h = $hoursInput.val() == '' ? null : $hoursInput.val() * 1;
|
@@ -74,7 +72,7 @@ $(function() {
|
|
74
72
|
},
|
75
73
|
|
76
74
|
/**
|
77
|
-
*
|
75
|
+
* Converts a hash of form {hours: 20, minutes: 5} into input values
|
78
76
|
*/
|
79
77
|
timeToInputs: function(value, $hoursInput, $minutesInput) {
|
80
78
|
if(value.hours !== undefined) {
|
@@ -87,7 +85,7 @@ $(function() {
|
|
87
85
|
},
|
88
86
|
|
89
87
|
/**
|
90
|
-
*
|
88
|
+
* Get (as a string) or set (from a hash) open time values
|
91
89
|
*/
|
92
90
|
openTime: function(value) {
|
93
91
|
if(value !== undefined) {
|
@@ -98,7 +96,7 @@ $(function() {
|
|
98
96
|
},
|
99
97
|
|
100
98
|
/**
|
101
|
-
*
|
99
|
+
* Get (as a string) or set (from a hash) close time values
|
102
100
|
*/
|
103
101
|
closeTime: function(value) {
|
104
102
|
if(value !== undefined) {
|
@@ -109,12 +107,15 @@ $(function() {
|
|
109
107
|
},
|
110
108
|
|
111
109
|
/**
|
112
|
-
*
|
110
|
+
* Returns true, if the day is empty, that is neither open/close times are set nor checkboxes are checked
|
113
111
|
*/
|
114
112
|
isEmpty: function() {
|
115
113
|
return !this.open24Hours() && !this.openUntilLastClient() && !this.openTime() && !this.closeTime();
|
116
114
|
},
|
117
115
|
|
116
|
+
/**
|
117
|
+
* If this object is equal to another
|
118
|
+
*/
|
118
119
|
equalTo: function($other) {
|
119
120
|
return (
|
120
121
|
this.open24Hours() == $other.workhoursday("open24Hours") &&
|
@@ -125,9 +126,8 @@ $(function() {
|
|
125
126
|
},
|
126
127
|
|
127
128
|
/**
|
128
|
-
*
|
129
|
-
*
|
130
|
-
* в отличие от метода closeTime({hours: ..., minutes: ...}).
|
129
|
+
* Gets or sets current state from array: [is_open_24h, is_open_until_last_client, open_time, close_time]
|
130
|
+
* Open and close times are string of form "hh:mm"
|
131
131
|
*/
|
132
132
|
value: function(value) {
|
133
133
|
if(value) {
|
@@ -158,26 +158,26 @@ $(function() {
|
|
158
158
|
|
159
159
|
|
160
160
|
|
161
|
-
//
|
161
|
+
// the last group ID taken
|
162
162
|
var cckWorkhoursGroupId = 0;
|
163
163
|
|
164
164
|
/**
|
165
|
-
*
|
166
|
-
*
|
165
|
+
* Work hours widget. Accepts a series of DIVs for each week day and converts it into a grouped series, where
|
166
|
+
* days are grouped by the same "work value" (checkboxes & open/close time):
|
167
167
|
*
|
168
|
-
* > [^]
|
169
|
-
* >
|
168
|
+
* > [^] Mon [^] Tue [^] Wed [^] Thu [^] Fri [_] Sat [_] Sun
|
169
|
+
* > from [09]:[00] till [20]:[00] [_] open 24 hours [_] open until last client
|
170
170
|
*
|
171
|
-
* > [_]
|
172
|
-
* >
|
171
|
+
* > [_] Mon [_] Tue [_] Wed [_] Thu [_] Fri [^] Sat [^] Sun
|
172
|
+
* > from [10]:[00] till [__]:[__] [_] open 24 hours [^] open until last client
|
173
173
|
*
|
174
|
-
* [
|
174
|
+
* [ Add days ]
|
175
175
|
*
|
176
|
-
*
|
177
|
-
*
|
176
|
+
* "Add days" link add an empty group. If a day is added to a group, it is removed from the previous group where it
|
177
|
+
* was. If a group is emptied (no more days left), it is deleted.
|
178
178
|
*
|
179
|
-
*
|
180
|
-
*
|
179
|
+
* The key is, when manipulating groups all the data is propagated to the hidden inputs in original HTML, thus
|
180
|
+
* the overall form data stays in the same format and a controller will not even now the widget was constructed.
|
181
181
|
*/
|
182
182
|
$.widget("cck.workhours", {
|
183
183
|
|
@@ -189,12 +189,13 @@ $(function() {
|
|
189
189
|
_$template: null,
|
190
190
|
|
191
191
|
/**
|
192
|
-
*
|
192
|
+
* Constructor
|
193
193
|
*/
|
194
194
|
_create: function() {
|
195
195
|
var $form = this.element;
|
196
196
|
var $widget = this;
|
197
197
|
|
198
|
+
// TODO: i18n in JS?
|
198
199
|
var $addGroupLink = $('<a href="#add-group">Добавить дней</a>').click(function() {
|
199
200
|
$widget.createGroup([], []);
|
200
201
|
});
|
@@ -206,7 +207,7 @@ $(function() {
|
|
206
207
|
var groups = [];
|
207
208
|
$widget._days = [];
|
208
209
|
|
209
|
-
//
|
210
|
+
// split existing days into groups and hide their DIVs
|
210
211
|
$form.children(".form_work_hours_day:not(.form_work_hours_day_template)").each(function() {
|
211
212
|
var $day = $(this).workhoursday().hide();
|
212
213
|
var dayName = $day.workhoursday("day");
|
@@ -230,53 +231,52 @@ $(function() {
|
|
230
231
|
},
|
231
232
|
|
232
233
|
/**
|
233
|
-
*
|
234
|
+
* Creates new DOM node for a group & bind event listeners
|
234
235
|
*/
|
235
236
|
createGroup: function(days, value) {
|
236
237
|
|
237
|
-
//
|
238
|
+
// make HTML, substitute id|name ~= template for a real ID (new one)
|
238
239
|
var newHtml = this._$template[0].outerHTML.replace(/((?:id|name)="[^"]*)template([^"]*")/g, "$1" + this.newGroupId() + "$2");
|
239
240
|
var $newGroup = $(newHtml);
|
240
241
|
|
241
|
-
//
|
242
|
+
// mark checkboxes
|
242
243
|
for(var i = 0, ic = days.length; i < ic; ++ i) {
|
243
244
|
$newGroup.find("input[name$=\"[days]\"][value=" + days[i] + "]").prop("checked", true).closest("li").addClass("active");
|
244
245
|
}
|
245
246
|
|
246
|
-
//
|
247
|
+
// hide checkboxes, link-o-buttons will be in their place
|
247
248
|
$newGroup.find("input[name$=\"[days]\"]").hide();
|
248
249
|
$newGroup.find(".nav-pills").on("click", "a", function(event) {
|
249
|
-
//
|
250
|
+
// skip events originated at checkbox inside this link
|
250
251
|
if(event.target == this) {
|
251
252
|
$(this).children("input:checkbox").click();
|
252
253
|
return false;
|
253
254
|
}
|
254
255
|
});
|
255
256
|
|
256
|
-
//
|
257
|
+
// listen for the form changes to propagate to the original DOM nodes
|
257
258
|
var $widget = this;
|
258
259
|
$newGroup.on("change", "input, select", function() {
|
259
260
|
$widget.groupChangeListener(this);
|
260
261
|
});
|
261
262
|
|
262
|
-
//
|
263
|
+
// make HTML & instantiate widget workhoursday
|
263
264
|
$newGroup.workhoursday().workhoursday("value", value).insertBefore(this._lastP).show();
|
264
265
|
},
|
265
266
|
|
266
267
|
/**
|
267
|
-
*
|
268
|
+
* Listens for a group events
|
268
269
|
*/
|
269
270
|
groupChangeListener: function(input) {
|
270
271
|
|
271
272
|
var $group = $(input).closest(".form_work_hours_day");
|
272
273
|
|
273
|
-
//
|
274
|
+
// an event from day checkboxes?
|
274
275
|
if(input.getAttribute("name").substr(-6) == '[days]') {
|
275
276
|
|
276
277
|
if(input.checked) {
|
277
278
|
|
278
|
-
//
|
279
|
-
// сделаем себе временную метку, чтобы себя не выключить тоже
|
279
|
+
// this day is on in this group, so make it off in another groups
|
280
280
|
var dayName = input.value;
|
281
281
|
|
282
282
|
if (!$group.data("multiDays")) {
|
@@ -285,18 +285,18 @@ $(function() {
|
|
285
285
|
input.removeAttribute("data-hold-check");
|
286
286
|
}
|
287
287
|
|
288
|
-
//
|
288
|
+
// propagate all the fields from this group to the day's original fields
|
289
289
|
this._days[dayName].workhoursday("value", $group.workhoursday("value"));
|
290
290
|
|
291
|
-
//
|
291
|
+
// mark the day as active
|
292
292
|
input.parentNode.parentNode.className += " active";
|
293
293
|
|
294
294
|
} else {
|
295
295
|
|
296
|
-
//
|
296
|
+
// propagate the off state to the day's original fields
|
297
297
|
this._days[input.value].workhoursday("value", []);
|
298
298
|
|
299
|
-
//
|
299
|
+
// remove this group if no more days left inside
|
300
300
|
if($group.find("input:checked[name$='[days]']").size() == 0) {
|
301
301
|
$group.remove();
|
302
302
|
} else {
|
@@ -304,57 +304,56 @@ $(function() {
|
|
304
304
|
}
|
305
305
|
}
|
306
306
|
|
307
|
-
//
|
307
|
+
// an event not from day checkboxes -> propagate the value to the original node
|
308
308
|
} else {
|
309
309
|
|
310
310
|
var match = input.getAttribute("name").match(/(?:\[(open_time|close_time)\])?\[([^\]]*)\]$/);
|
311
311
|
var fieldName = (match[1] ? match[1] + '_' : '') + match[2];
|
312
312
|
var inputNodeName = input.nodeName.toLowerCase();
|
313
313
|
|
314
|
-
//
|
314
|
+
// active days in this group
|
315
315
|
var days = [];
|
316
316
|
$group.find("input:checked[name$='[days]']").each(function() {
|
317
317
|
days.push(this.value);
|
318
318
|
});
|
319
319
|
|
320
|
-
//
|
321
|
-
// если текущее поле выбрано, то...
|
320
|
+
// some UX friendly checks
|
322
321
|
if(inputNodeName == "input" && input.checked || inputNodeName == "select" && input.value != '') {
|
323
322
|
switch(fieldName) {
|
324
323
|
|
325
|
-
//
|
324
|
+
// open 24 hours? nullify open/close time
|
326
325
|
case "open_24_hours":
|
327
326
|
$group.workhoursday("openTime", {hours: '', minutes: ''}).workhoursday("closeTime", {hours: '', minutes: ''});
|
328
327
|
break;
|
329
328
|
|
330
|
-
//
|
329
|
+
// open until last client? nullify close time
|
331
330
|
case "open_until_last_client":
|
332
331
|
$group.workhoursday("closeTime", {hours: '', minutes: ''});
|
333
332
|
break;
|
334
333
|
|
335
|
-
//
|
334
|
+
// close time set? uncheck "open until last" checkbox
|
336
335
|
case "close_time_hours":
|
337
336
|
case "close_time_minutes":
|
338
337
|
$group.workhoursday("openUntilLastClient", false);
|
339
|
-
// break
|
338
|
+
// break skipped on purpose!
|
340
339
|
|
341
|
-
//
|
340
|
+
// any time set? uncheck "open 24h" checkbox
|
342
341
|
case "open_time_hours":
|
343
342
|
case "open_time_minutes":
|
344
343
|
$group.workhoursday("open24Hours", false);
|
345
344
|
break;
|
346
345
|
}
|
347
346
|
|
348
|
-
//
|
347
|
+
// hour is set but minutes are not? set :00
|
349
348
|
var camelCasedTime = this.camelCaseTime(fieldName, 6);
|
350
349
|
if((fieldName == "open_time_hours" || fieldName == "close_time_hours") && !$group.workhoursday(camelCasedTime)) {
|
351
350
|
$group.workhoursday(camelCasedTime, {minutes: 0})
|
352
351
|
}
|
353
352
|
|
354
|
-
//
|
353
|
+
// not input
|
355
354
|
} else {
|
356
355
|
|
357
|
-
//
|
356
|
+
// setting hours or minutes? nullify minutes or hours respectively
|
358
357
|
if(fieldName == "open_time_hours" || fieldName == "close_time_hours") {
|
359
358
|
$group.workhoursday(this.camelCaseTime(fieldName, 6), {minutes: ''});
|
360
359
|
} else if(fieldName == "open_time_minutes" || fieldName == "close_time_minutes") {
|
@@ -362,7 +361,7 @@ $(function() {
|
|
362
361
|
}
|
363
362
|
}
|
364
363
|
|
365
|
-
//
|
364
|
+
// all checks are made, propagate the value to days inside this group
|
366
365
|
var value = $group.workhoursday("value");
|
367
366
|
for(var i = 0, ic = days.length; i < ic; ++ i) {
|
368
367
|
this._days[days[i]].workhoursday("value", value);
|
@@ -384,14 +383,14 @@ $(function() {
|
|
384
383
|
},
|
385
384
|
|
386
385
|
/**
|
387
|
-
*
|
386
|
+
* Generates a unique sequential group DOM ID
|
388
387
|
*/
|
389
388
|
newGroupId: function() {
|
390
389
|
return 'group' + (cckWorkhoursGroupId ++);
|
391
390
|
},
|
392
391
|
|
393
392
|
/**
|
394
|
-
*
|
393
|
+
* To not worry about redundant comma after the last hash key
|
395
394
|
*/
|
396
395
|
slashzero: null
|
397
396
|
|
@@ -54,10 +54,10 @@ class CckFormsMap.AbstractMap
|
|
54
54
|
|
55
55
|
@.setMarkerToPoint latlon
|
56
56
|
@.setCenter latlon
|
57
|
-
@.setZoom 17 #
|
57
|
+
@.setZoom 17 # adjusted by experiment for better view
|
58
58
|
|
59
59
|
xhr.fail ->
|
60
|
-
alert "
|
60
|
+
alert "Server error encountered"
|
61
61
|
|
62
62
|
|
63
63
|
refresh: ->
|
@@ -209,7 +209,7 @@ class CckFormsMap.GoogleMap extends CckFormsMap.AbstractMap
|
|
209
209
|
@.refresh()
|
210
210
|
|
211
211
|
refresh: ->
|
212
|
-
center = @internalMapAPI.getCenter() #
|
212
|
+
center = @internalMapAPI.getCenter() # keep the map center rock solid
|
213
213
|
google.maps.event.trigger(@internalMapAPI, "resize")
|
214
214
|
@internalMapAPI.setCenter(center)
|
215
215
|
|
@@ -260,32 +260,6 @@ window.init_map = (canvas) ->
|
|
260
260
|
|
261
261
|
$canvas.data('maps', maps)
|
262
262
|
|
263
|
-
|
264
|
-
cityInputSelectorst = [
|
265
|
-
'#' + $source.data("cityid"),
|
266
|
-
'[data-behavior="map_city_change"]'
|
267
|
-
].join(', ')
|
268
|
-
$cityInput = $(cityInputSelectorst)
|
269
|
-
|
270
|
-
if $cityInput.data('mapCityValue')
|
271
|
-
mapCityValue = $cityInput.data('mapCityValue')
|
272
|
-
$cityInput = $cityInput.find(mapCityValue)
|
273
|
-
|
274
|
-
handleCityChange = =>
|
275
|
-
cities = $source.data("cities")
|
276
|
-
city = cities[$cityInput.val()]
|
277
|
-
|
278
|
-
if city
|
279
|
-
latLng = new google.maps.LatLng(city.lat, city.lon) unless hasLatLng
|
280
|
-
zoom = city.zoom unless hasZoom
|
281
|
-
|
282
|
-
$.each $canvas.data('maps'), (i, map) ->
|
283
|
-
map.setCenter latitude: latLng.lat(), longitude: latLng.lng()
|
284
|
-
map.setZoom zoom
|
285
|
-
|
286
|
-
$cityInput.change handleCityChange
|
287
|
-
handleCityChange() unless $lat.val() or $lon.val()
|
288
|
-
|
289
263
|
activeMapType = $canvas
|
290
264
|
.find('.cck-map-switchers a.active')
|
291
265
|
.data("mapType")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cck_forms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Konanykhin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|