nested_array 2.4.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +438 -177
- data/README.md +510 -30
- data/TODO.md +3 -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 +211 -185
- 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
|
39
|
+
# Выводить html теги от раскрывающегося списка на основе тега details.
|
40
|
+
details: false,
|
74
41
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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?
|
89
|
-
|
90
|
-
yield(node, parents, level, is_last_children, node.origin)
|
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)
|
258
191
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
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
|
271
|
+
|
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,18 +319,21 @@ 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 = {})
|
300
323
|
options = NESTED_OPTIONS.merge options
|
301
324
|
ret = []
|
325
|
+
|
302
326
|
last = []
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
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)
|
311
337
|
ret.push [option_text, option_value]
|
312
338
|
end
|
313
339
|
ret
|
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
|
+
}
|