nested_array 2.3.0 → 3.0.0
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/.gitignore +0 -1
- data/.rspec +4 -1
- data/.rubocop.yml +125 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +35 -14
- data/README-ru-old.md +333 -0
- data/README-ru.md +451 -139
- data/README.md +510 -30
- data/TODO.md +6 -20
- data/doc/images/2.1.3.1.png +0 -0
- data/doc/images/2.1.3.2.png +0 -0
- data/doc/images/2.2.1.1.png +0 -0
- data/doc/images/2.2.1.2.png +0 -0
- data/doc/images/2.2.1.3-1.png +0 -0
- data/doc/images/2.2.1.3-2.png +0 -0
- data/doc/images/2.2.1.4-1.png +0 -0
- data/doc/images/2.2.1.4-2.png +0 -0
- data/doc/images/2.2.1.5.png +0 -0
- data/doc/images/2.2.2.1.png +0 -0
- data/doc/images/2.2.2.2.png +0 -0
- data/doc/images/2.2.2.3.png +0 -0
- data/doc/images/2.2.2.4.png +0 -0
- data/doc/images/2.2.3.1.png +0 -0
- data/doc/images/2.2.3.2.png +0 -0
- data/doc/images/2.2.3.3.png +0 -0
- data/lib/nested_array/nested.rb +228 -179
- data/lib/nested_array/version.rb +1 -1
- data/lib/nested_array.rb +4 -4
- data/vendor/assets/stylesheets/nested_array.scss +92 -0
- metadata +23 -8
- data/test.old/Gemfile +0 -5
- data/test.old/Gemfile.lock +0 -34
- data/test.old/bash/run/bundle.sh +0 -9
- data/test.old/bash/run/test.sh +0 -9
- data/test.old/test.rb +0 -42
data/lib/nested_array/nested.rb
CHANGED
@@ -11,22 +11,19 @@ module NestedArray::Nested
|
|
11
11
|
# Имена полей для получения/записи информации, чувствительны к string/symbol
|
12
12
|
id: 'id',
|
13
13
|
parent_id: 'parent_id',
|
14
|
+
|
14
15
|
children: 'children',
|
15
16
|
level: 'level',
|
16
17
|
|
17
18
|
# Параметры для преобразования в nested
|
18
19
|
hashed: false,
|
19
|
-
add_level: false,
|
20
20
|
root_id: nil,
|
21
|
+
branch_id: nil,
|
21
22
|
|
22
23
|
# Параметры для преобразования в html
|
23
24
|
tabulated: true,
|
24
25
|
inline: false,
|
25
26
|
tab: "\t",
|
26
|
-
ul: '<ul>',
|
27
|
-
_ul: '</ul>',
|
28
|
-
li: '<li>',
|
29
|
-
_li: '</li>',
|
30
27
|
|
31
28
|
# Параматры для "склеивания" вложенных структур
|
32
29
|
path_separator: '-=path_separator=-',
|
@@ -35,140 +32,74 @@ module NestedArray::Nested
|
|
35
32
|
# Настройки формирования массива для опций тега <select>
|
36
33
|
option_value: 'id', # Что брать в качестве значений при формировании опций селекта.
|
37
34
|
option_text: 'name',
|
38
|
-
|
39
|
-
|
35
|
+
thin_option: false,
|
36
|
+
pseudographics: %w(┳ ━ ╸ ┣ ┗ ┃),
|
37
|
+
thin_pseudographics: %w(┬ ─ ╴ ├ └ │),
|
40
38
|
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
def each_nested options={}
|
45
|
-
options = NESTED_OPTIONS.merge options
|
46
|
-
level = 0
|
47
|
-
cache = []
|
48
|
-
cache[level] = self.clone
|
49
|
-
parents = []
|
50
|
-
parents[level] = nil
|
51
|
-
i = []
|
52
|
-
i[level] = 0
|
53
|
-
while level >= 0
|
54
|
-
node = cache[level][i[level]]
|
55
|
-
i[level]+= 1
|
56
|
-
if node != nil
|
57
|
-
is_last_children = cache[level][i[level]].blank?
|
58
|
-
|
59
|
-
yield(node.clone, parents.clone, level, is_last_children, node.origin)
|
60
|
-
|
61
|
-
if !node[options[:children]].nil? && node[options[:children]].length > 0
|
62
|
-
level+= 1
|
63
|
-
parents[level] = node.clone
|
64
|
-
cache[level] = node[options[:children]]
|
65
|
-
i[level] = 0
|
66
|
-
end
|
67
|
-
else
|
68
|
-
parents[level] = nil
|
69
|
-
level-= 1
|
70
|
-
end
|
71
|
-
end
|
72
|
-
self
|
73
|
-
end
|
74
|
-
|
75
|
-
def each_nested! options={}
|
76
|
-
options = NESTED_OPTIONS.merge options
|
77
|
-
level = 0
|
78
|
-
cache = []
|
79
|
-
cache[level] = self
|
80
|
-
parents = []
|
81
|
-
parents[level] = nil
|
82
|
-
i = []
|
83
|
-
i[level] = 0
|
84
|
-
while level >= 0
|
85
|
-
node = cache[level][i[level]]
|
86
|
-
i[level]+= 1
|
87
|
-
if node != nil
|
88
|
-
is_last_children = cache[level][i[level]].blank?
|
39
|
+
# Выводить html теги от раскрывающегося списка на основе тега details.
|
40
|
+
details: false,
|
89
41
|
|
90
|
-
|
42
|
+
ul: '<ul>',
|
43
|
+
_ul: '</ul>',
|
44
|
+
li: '<li>',
|
45
|
+
_li: '</li>',
|
91
46
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
i[level] = 0
|
97
|
-
end
|
98
|
-
else
|
99
|
-
parents[level] = nil
|
100
|
-
level-= 1
|
101
|
-
end
|
102
|
-
end
|
103
|
-
self
|
47
|
+
uld: '<details><summary></summary><ul>',
|
48
|
+
uldo: '<details open><summary></summary><ul>',
|
49
|
+
_uld: '</ul></details>'
|
50
|
+
}
|
104
51
|
end
|
105
52
|
|
106
|
-
def to_nested
|
53
|
+
def to_nested(options = {})
|
107
54
|
options = NESTED_OPTIONS.merge options
|
55
|
+
# Зарезервированные поля узла.
|
108
56
|
fields = {
|
109
57
|
id: options[:id],
|
110
58
|
parent_id: options[:parent_id],
|
111
59
|
level: options[:level],
|
112
60
|
children: options[:children],
|
113
61
|
}
|
114
|
-
fields.delete :level if !options[:add_level]
|
115
62
|
cache = {}
|
116
63
|
nested = options[:hashed] ? {} : []
|
117
64
|
# Перебираем элементы в любом порядке!
|
118
|
-
self.each do |
|
119
|
-
|
120
|
-
value = value.serializable_hash if !value.is_a? Hash
|
65
|
+
self.each do |origin|
|
66
|
+
value = origin.is_a?(Hash) ? origin : origin.serializable_hash
|
121
67
|
# 1. Если нет родителя текущего элемента, и текущий элемент не корневой, то:
|
122
68
|
# 1.1 создадим родителя
|
123
69
|
# 1.2 поместим в кэш
|
124
|
-
if !(cache.key? value[
|
70
|
+
if !(cache.key? value[options[:parent_id]]) && (value[options[:parent_id]] != options[:root_id])
|
125
71
|
# 1.1
|
126
72
|
temp = OpenStruct.new
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
temp[field] = value[fields[:parent_id]]
|
131
|
-
when :children
|
132
|
-
# не создаём поле
|
133
|
-
else
|
134
|
-
temp[field] = nil
|
135
|
-
end
|
136
|
-
end
|
73
|
+
temp[options[:id]] = value[options[:parent_id]]
|
74
|
+
temp[options[:parent_id]] = nil
|
75
|
+
temp[options[:level]] = nil
|
137
76
|
# 1.2
|
138
|
-
cache[value[
|
77
|
+
cache[value[options[:parent_id]]] = temp
|
139
78
|
end
|
140
79
|
# 2. Если текущий элемент уже был создан, значит он был чьим-то родителем, тогда:
|
141
|
-
# 2.1 обновим в нем информацию
|
80
|
+
# 2.1 обновим в нем информацию о parent_id и другие не зарезервированные поля.
|
142
81
|
# 2.2 поместим в родителя
|
143
|
-
if cache.key? value[
|
82
|
+
if cache.key? value[options[:id]]
|
144
83
|
# 2.1
|
145
|
-
|
146
|
-
|
147
|
-
when :id, :children
|
148
|
-
# не обновляем информацию
|
149
|
-
else
|
150
|
-
cache[value[fields[:id]]][field] = value[field]
|
151
|
-
end
|
152
|
-
end
|
153
|
-
value.keys.each do |field|
|
154
|
-
cache[value[fields[:id]]][field] = value[field] if !(field.in? fields)
|
155
|
-
end
|
156
|
-
cache[value[fields[:id]]].origin = origin
|
84
|
+
cache[value[options[:id]]][options[:parent_id]] = value[options[:parent_id]]
|
85
|
+
cache[value[options[:id]]].origin = origin
|
157
86
|
# 2.2
|
158
87
|
# Если текущий элемент не корневой - поместим в родителя, беря его из кэш
|
159
|
-
if value[
|
160
|
-
cache[value[
|
88
|
+
if value[options[:parent_id]] != options[:root_id]
|
89
|
+
cache[value[options[:parent_id]]][options[:children]] ||= options[:hashed] ? {} : []
|
161
90
|
if options[:hashed]
|
162
|
-
cache[value[
|
91
|
+
cache[value[options[:parent_id]]][options[:children]][value[options[:id]]] = nested[value[options[:id]]]
|
163
92
|
else
|
164
|
-
cache[value[
|
93
|
+
cache[value[options[:parent_id]]][options[:children]] << cache[value[options[:id]]]
|
165
94
|
end
|
166
95
|
# иначе, текущий элемент корневой, поместим в nested
|
167
96
|
else
|
168
|
-
if options[:
|
169
|
-
|
170
|
-
|
171
|
-
|
97
|
+
if options[:branch_id].nil? || options[:branch_id] == value[options[:id]]
|
98
|
+
if options[:hashed]
|
99
|
+
nested[value[options[:id]]] = cache[value[options[:id]]]
|
100
|
+
else
|
101
|
+
nested << cache[value[options[:id]]]
|
102
|
+
end
|
172
103
|
end
|
173
104
|
end
|
174
105
|
# 3. Иначе, текущий элемент не создан, тогда:
|
@@ -178,72 +109,65 @@ module NestedArray::Nested
|
|
178
109
|
else
|
179
110
|
# 3.1
|
180
111
|
temp = OpenStruct.new
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
temp[field] = value[field]
|
185
|
-
when :parent_id
|
186
|
-
temp[field] = value[field]
|
187
|
-
when :children
|
188
|
-
# ничего не делаем
|
189
|
-
else
|
190
|
-
temp[field] = value[field]
|
191
|
-
end
|
192
|
-
end
|
193
|
-
value.keys.each do |field|
|
194
|
-
temp[field] = value[field] if !(field.in? fields)
|
195
|
-
end
|
112
|
+
temp[options[:id]] = value[options[:id]]
|
113
|
+
temp[options[:parent_id]] = value[options[:parent_id]]
|
114
|
+
temp[options[:level]] = nil
|
196
115
|
temp.origin = origin
|
197
116
|
# 3.2
|
198
|
-
cache[value[
|
117
|
+
cache[value[options[:id]]] = temp
|
199
118
|
# 3.3
|
200
119
|
# Если текущий элемент не корневой - поместим в родителя, беря его из кэш
|
201
|
-
if value[
|
202
|
-
cache[value[
|
120
|
+
if value[options[:parent_id]] != options[:root_id]
|
121
|
+
cache[value[options[:parent_id]]][options[:children]] ||= options[:hashed] ? {} : []
|
203
122
|
if options[:hashed]
|
204
|
-
cache[value[
|
123
|
+
cache[value[options[:parent_id]]][options[:children]][value[options[:id]]] = cache[value[options[:id]]]
|
205
124
|
else
|
206
|
-
cache[value[
|
125
|
+
cache[value[options[:parent_id]]][options[:children]] << cache[value[options[:id]]]
|
207
126
|
end
|
208
127
|
# иначе, текущий элемент корневой, поместим в nested
|
209
128
|
else
|
210
|
-
if options[:
|
211
|
-
|
212
|
-
|
213
|
-
|
129
|
+
if options[:branch_id].nil? || options[:branch_id] == value[options[:id]]
|
130
|
+
if options[:hashed]
|
131
|
+
nested[value[options[:id]]] = cache[value[options[:id]]]
|
132
|
+
else
|
133
|
+
nested << cache[value[options[:id]]]
|
134
|
+
end
|
214
135
|
end
|
215
136
|
end
|
216
137
|
end
|
217
138
|
end
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
else
|
237
|
-
level-= 1
|
139
|
+
|
140
|
+
# Добавление level к узлу.
|
141
|
+
level = 0
|
142
|
+
cache = []
|
143
|
+
cache[level] = nested
|
144
|
+
i = []
|
145
|
+
i[level] = 0
|
146
|
+
while level >= 0
|
147
|
+
node = cache[level][i[level]]
|
148
|
+
i[level] += 1
|
149
|
+
if node != nil
|
150
|
+
|
151
|
+
node[options[:level]] = level
|
152
|
+
|
153
|
+
if !node[options[:children]].nil? && node[options[:children]].length > 0
|
154
|
+
level += 1
|
155
|
+
cache[level] = node[options[:children]]
|
156
|
+
i[level] = 0
|
238
157
|
end
|
158
|
+
else
|
159
|
+
level -= 1
|
239
160
|
end
|
240
161
|
end
|
162
|
+
|
241
163
|
nested
|
242
164
|
end
|
243
165
|
|
244
|
-
|
166
|
+
#
|
167
|
+
# Перебирает вложенную стуктуру.
|
168
|
+
#
|
169
|
+
def each_nested(options = {})
|
245
170
|
options = NESTED_OPTIONS.merge options
|
246
|
-
html = ''
|
247
171
|
level = 0
|
248
172
|
cache = []
|
249
173
|
cache[level] = self.clone
|
@@ -251,43 +175,142 @@ module NestedArray::Nested
|
|
251
175
|
parents[level] = nil
|
252
176
|
i = []
|
253
177
|
i[level] = 0
|
178
|
+
prev_level = nil
|
254
179
|
while level >= 0
|
255
180
|
node = cache[level][i[level]]
|
256
|
-
i[level]+= 1
|
181
|
+
i[level] += 1
|
257
182
|
if node != nil
|
183
|
+
clone_node = node.clone
|
184
|
+
|
185
|
+
# Текущий узел является последним ребёнком своего родителя:
|
186
|
+
clone_node.is_last_children = cache[level][i[level]].blank?
|
187
|
+
# Текущий узел имеет детей:
|
188
|
+
clone_node.is_has_children = !node[options[:children]].nil? && node[options[:children]].length > 0
|
189
|
+
# Текущий узел последний в дереве:
|
190
|
+
clone_node.is_last = clone_node.is_last_children && !clone_node.is_has_children && (0..(clone_node.level)).to_a.map{|l| cache[l][i[l]].blank?}.all?(true)
|
191
|
+
|
192
|
+
next_level = if clone_node.is_has_children
|
193
|
+
level + 1
|
194
|
+
elsif clone_node.is_last_children
|
195
|
+
nl = nil
|
196
|
+
(0..clone_node.level).to_a.reverse.each do |l|
|
197
|
+
if cache[l][i[l]].present?
|
198
|
+
nl = l
|
199
|
+
break
|
200
|
+
end
|
201
|
+
end
|
202
|
+
nl
|
203
|
+
else
|
204
|
+
level
|
205
|
+
end
|
206
|
+
|
207
|
+
clone_node.parents = parents.clone
|
208
|
+
|
209
|
+
# В текущем узле всегда есть li
|
210
|
+
clone_node.before = options[:li].html_safe
|
211
|
+
clone_node.li = clone_node.before
|
212
|
+
# Следующий уровень тот же? — текущий закрываем просто.
|
213
|
+
if next_level.present? && next_level == clone_node.level
|
214
|
+
clone_node._ = options[:_li].html_safe
|
215
|
+
end
|
216
|
+
# Следующий уровень понизится? - текущий закрываем сложно.
|
217
|
+
if next_level.present? && next_level < clone_node.level
|
218
|
+
clone_node._ = options[:_li]
|
219
|
+
(clone_node.level - next_level).times do |t|
|
220
|
+
clone_node._ += options[:details] ? options[:_uld] + options[:_li] : options[:_ul] + options[:_li]
|
221
|
+
end
|
222
|
+
clone_node._ = clone_node._.html_safe
|
223
|
+
end
|
224
|
+
# Следующий уровень повысится? — открываем подуровень.
|
225
|
+
if clone_node.is_has_children
|
226
|
+
clone_node.ul = if options[:details]
|
227
|
+
options[:uld].html_safe
|
228
|
+
else
|
229
|
+
options[:ul].html_safe
|
230
|
+
end
|
231
|
+
end
|
232
|
+
# Последний в дереве? — последние закрывающие теги.
|
233
|
+
if clone_node.is_last
|
234
|
+
clone_node._ = options[:_li]
|
235
|
+
clone_node.level.times do |t|
|
236
|
+
clone_node._ += options[:details] ? options[:_uld] + options[:_li] : options[:_ul] + options[:_li]
|
237
|
+
end
|
238
|
+
clone_node._ = clone_node._.html_safe
|
239
|
+
end
|
240
|
+
|
241
|
+
clone_node.define_singleton_method(:after) do |*args|
|
242
|
+
ret = ''
|
243
|
+
# Следующий уровень тот же? — текущий закрываем просто.
|
244
|
+
if next_level.present? && next_level == clone_node.level
|
245
|
+
ret += options[:_li]
|
246
|
+
end
|
247
|
+
# Следующий уровень понизится? - текущий закрываем сложно.
|
248
|
+
if next_level.present? && next_level < clone_node.level
|
249
|
+
ret += options[:_li]
|
250
|
+
(clone_node.level - next_level).times do |t|
|
251
|
+
ret += options[:details] ? options[:_uld] + options[:_li] : options[:_ul] + options[:_li]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
# Следующий уровень повысится? — открываем подуровень.
|
255
|
+
if self.is_has_children
|
256
|
+
if options[:details]
|
257
|
+
ret += args.present? && args[0]&.[](:open) == true ? options[:uldo] : options[:uld]
|
258
|
+
else
|
259
|
+
ret += options[:ul]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
# Последний в дереве? — последние закрывающие теги.
|
263
|
+
if self.is_last
|
264
|
+
ret += options[:_li]
|
265
|
+
self.level.times do |t|
|
266
|
+
ret += options[:details] ? options[:_uld] + options[:_li] : options[:_ul] + options[:_li]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
ret.html_safe
|
270
|
+
end
|
258
271
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
html+= node_html.to_s
|
272
|
+
yield(clone_node, clone_node.origin)
|
273
|
+
|
274
|
+
prev_level = node.level
|
263
275
|
|
264
276
|
if !node[options[:children]].nil? && node[options[:children]].length > 0
|
265
|
-
level+= 1
|
266
|
-
|
267
|
-
html+= options[:tab] * (level * 2) if options[:tabulated]
|
268
|
-
html+= node_options&.[](:ul) || options[:ul]
|
269
|
-
html+= "\n" if !options[:inline]
|
270
|
-
parents[level] = node.clone
|
277
|
+
level += 1
|
278
|
+
parents[level] = clone_node
|
271
279
|
cache[level] = node[options[:children]]
|
272
280
|
i[level] = 0
|
273
|
-
else
|
274
|
-
html+= options[:_li]
|
275
|
-
html+= "\n" if !options[:inline]
|
276
281
|
end
|
277
282
|
else
|
278
283
|
parents[level] = nil
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
284
|
+
level -= 1
|
285
|
+
end
|
286
|
+
end
|
287
|
+
self
|
288
|
+
end
|
289
|
+
|
290
|
+
def to_flat(options = {})
|
291
|
+
ret = []
|
292
|
+
options = NESTED_OPTIONS.merge options
|
293
|
+
level = 0
|
294
|
+
cache = []
|
295
|
+
cache[level] = self.clone
|
296
|
+
i = []
|
297
|
+
i[level] = 0
|
298
|
+
while level >= 0
|
299
|
+
node = cache[level][i[level]]
|
300
|
+
i[level] += 1
|
301
|
+
if node != nil
|
302
|
+
ret.push node.origin
|
303
|
+
|
304
|
+
if !node[options[:children]].nil? && node[options[:children]].length > 0
|
305
|
+
level += 1
|
306
|
+
cache[level] = node[options[:children]]
|
307
|
+
i[level] = 0
|
286
308
|
end
|
287
|
-
|
309
|
+
else
|
310
|
+
level -= 1
|
288
311
|
end
|
289
312
|
end
|
290
|
-
|
313
|
+
ret
|
291
314
|
end
|
292
315
|
|
293
316
|
#
|
@@ -296,11 +319,36 @@ module NestedArray::Nested
|
|
296
319
|
# ```
|
297
320
|
# [['option_text1', 'option_value1'],['option_text2', 'option_value2'],…]
|
298
321
|
# ```
|
299
|
-
def nested_to_options options={}
|
322
|
+
def nested_to_options(origin_text, origin_value, options = {})
|
323
|
+
options = NESTED_OPTIONS.merge options
|
324
|
+
ret = []
|
325
|
+
|
326
|
+
last = []
|
327
|
+
downhorizontal, horizontal, left, rightvertical, rightup, space, vertical = options[:thin_pseudographic] ? options[:thin_pseudographics] : options[:pseudographics]
|
328
|
+
|
329
|
+
each_nested do |node, origin|
|
330
|
+
last[node.level + 1] = node.is_last_children
|
331
|
+
node_text = origin.send(origin_text)
|
332
|
+
node_level = (1..node.level).map{|l| last[l] == true ? space : vertical}.join
|
333
|
+
node_last = node.is_last_children ? rightup : rightvertical
|
334
|
+
node_children = node[options[:children]].present? && node[options[:children]].length > 0 ? downhorizontal : horizontal
|
335
|
+
option_text = "#{node_level}#{node_last}#{node_children}#{left}".html_safe + "#{node_text}"
|
336
|
+
option_value = origin.send(origin_value)
|
337
|
+
ret.push [option_text, option_value]
|
338
|
+
end
|
339
|
+
ret
|
340
|
+
end
|
341
|
+
|
342
|
+
# Преобразует вложенную структуру данных в плоскую, но добавляет в значение
|
343
|
+
# поля отвечающего за текстовое представление (:name) псевдографику
|
344
|
+
# древовидной структуры.
|
345
|
+
# Это позволяет вывести тэг select в сносном виде для использования с
|
346
|
+
# вложенными структурами.
|
347
|
+
def nested_to_collection_select(options={})
|
300
348
|
options = NESTED_OPTIONS.merge options
|
301
349
|
ret = []
|
302
350
|
last = []
|
303
|
-
each_nested do |node, parents, level, is_last|
|
351
|
+
each_nested do |node, parents, level, is_last, origin|
|
304
352
|
last[level+1] = is_last
|
305
353
|
node_text = node[options[:option_text]]
|
306
354
|
node_level = (1..level).map{|l| last[l] == true ? ' ' : '┃'}.join
|
@@ -308,7 +356,8 @@ module NestedArray::Nested
|
|
308
356
|
node_children = node[options[:children]].present? && node[options[:children]].length > 0 ? '┳' : '━'
|
309
357
|
option_text = "#{node_level}#{node_last}#{node_children}╸".html_safe + "#{node_text}"
|
310
358
|
option_value = node[options[:option_value]]
|
311
|
-
|
359
|
+
node[options[:option_text]] = option_text
|
360
|
+
ret.push node
|
312
361
|
end
|
313
362
|
ret
|
314
363
|
end
|
data/lib/nested_array/version.rb
CHANGED
data/lib/nested_array.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
require "active_support/all"
|
2
|
-
require "nested_array/version"
|
3
2
|
|
3
|
+
require_relative "nested_array/version"
|
4
4
|
require_relative "nested_array/nested"
|
5
5
|
|
6
6
|
module NestedArray
|
7
|
-
|
8
7
|
class Array < ::Array
|
9
|
-
|
10
8
|
include NestedArray::Nested
|
11
9
|
end
|
10
|
+
|
11
|
+
class Engine < ::Rails::Engine
|
12
|
+
end
|
12
13
|
end
|
13
14
|
|
14
15
|
class Array
|
15
|
-
|
16
16
|
include ::NestedArray::Nested
|
17
17
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
.nested_array-details {
|
2
|
+
font-size: 1em;
|
3
|
+
margin: 0;
|
4
|
+
padding: 0 0 0 6px;
|
5
|
+
list-style-type: none;
|
6
|
+
line-height: 1.5em;
|
7
|
+
}
|
8
|
+
.nested_array-details ul {
|
9
|
+
margin: 0;
|
10
|
+
padding: 0 0 0 6px;
|
11
|
+
list-style-type: none;
|
12
|
+
}
|
13
|
+
.nested_array-details li {
|
14
|
+
margin: 0;
|
15
|
+
padding: 0 0 0 30px;
|
16
|
+
border-left: solid 1px gray;
|
17
|
+
|
18
|
+
position: relative;
|
19
|
+
}
|
20
|
+
.nested_array-details li > * {
|
21
|
+
margin-top: 0;
|
22
|
+
margin-bottom: 0;
|
23
|
+
}
|
24
|
+
.nested_array-details details {
|
25
|
+
position: relative;
|
26
|
+
top: 0;
|
27
|
+
/* -li.padding + ((li:before.width - 1) / 2) - ((summary.width - 1) / 2) */
|
28
|
+
/* -30 + ((27 - 1) / 2) - ((13 - 1) / 2) = -23 */
|
29
|
+
left: -23px;
|
30
|
+
}
|
31
|
+
.nested_array-details details::before {
|
32
|
+
content: none;
|
33
|
+
}
|
34
|
+
.nested_array-details details[open]::before {
|
35
|
+
content: '';
|
36
|
+
display: block;
|
37
|
+
position: absolute;
|
38
|
+
width: 1px;
|
39
|
+
height: 1em;
|
40
|
+
background-color: grey;
|
41
|
+
top: -0.75em;
|
42
|
+
left: 6px;
|
43
|
+
}
|
44
|
+
.nested_array-details summary {
|
45
|
+
position: absolute;
|
46
|
+
width: 13px;
|
47
|
+
height: 13px;
|
48
|
+
box-sizing: border-box;
|
49
|
+
top: calc(-0.75em - 6px);
|
50
|
+
left: auto;
|
51
|
+
list-style-type: none;
|
52
|
+
border: solid 1px gray;
|
53
|
+
cursor:pointer;
|
54
|
+
background:
|
55
|
+
linear-gradient(#000, #000),
|
56
|
+
linear-gradient(#000, #000),
|
57
|
+
#FFF;
|
58
|
+
background-position: center;
|
59
|
+
background-size: 7px 1px, 1px 7px;
|
60
|
+
background-repeat: no-repeat;
|
61
|
+
}
|
62
|
+
.nested_array-details details[open] > summary {
|
63
|
+
background:
|
64
|
+
linear-gradient(#000, #000),
|
65
|
+
#FFF;
|
66
|
+
background-position: center;
|
67
|
+
background-size: 7px 1px, 1px 7px;
|
68
|
+
background-repeat: no-repeat;
|
69
|
+
}
|
70
|
+
.nested_array-details li::before {
|
71
|
+
content: '';
|
72
|
+
display: block;
|
73
|
+
border-bottom: solid 1px gray;
|
74
|
+
position: absolute;
|
75
|
+
width: 27px;
|
76
|
+
height: 0.75em;
|
77
|
+
left: -1px;
|
78
|
+
top: 0;
|
79
|
+
}
|
80
|
+
.nested_array-details li:last-child {
|
81
|
+
border-left: 1px solid transparent;
|
82
|
+
}
|
83
|
+
.nested_array-details li:last-child::before {
|
84
|
+
border-left: solid 1px gray;
|
85
|
+
}
|
86
|
+
|
87
|
+
.nested_array-select {
|
88
|
+
option {
|
89
|
+
padding: 0;
|
90
|
+
font-family: monospace;
|
91
|
+
}
|
92
|
+
}
|