SimpleCodeTM commited on
Commit
262c881
·
verified ·
1 Parent(s): 9350af9

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +5 -3
  2. index.html +710 -19
  3. prompts.txt +4 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Tree Moved
3
- emoji: 🏢
4
  colorFrom: green
5
  colorTo: red
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: tree-moved
3
+ emoji: 🐳
4
  colorFrom: green
5
  colorTo: red
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,710 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Интерактивное дерево с плавным перетаскиванием</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .tree-node {
11
+ transition: all 0.2s ease;
12
+ position: relative;
13
+ }
14
+ .tree-node:hover {
15
+ background-color: #f3f4f6;
16
+ }
17
+ .tree-node.dragging {
18
+ opacity: 0.5;
19
+ background-color: #e5e7eb;
20
+ }
21
+ .tree-node-placeholder {
22
+ border: 2px dashed #3b82f6;
23
+ background-color: #eff6ff;
24
+ height: 40px;
25
+ margin: 4px 0;
26
+ border-radius: 4px;
27
+ transition: all 0.1s ease;
28
+ }
29
+ .nested {
30
+ display: none;
31
+ transition: all 0.3s ease;
32
+ }
33
+ .nested.active {
34
+ display: block;
35
+ animation: fadeIn 0.3s ease-in-out;
36
+ }
37
+ @keyframes fadeIn {
38
+ from { opacity: 0; transform: translateY(-10px); }
39
+ to { opacity: 1; transform: translateY(0); }
40
+ }
41
+ .drag-handle {
42
+ cursor: move;
43
+ opacity: 0.5;
44
+ transition: opacity 0.2s ease;
45
+ }
46
+ .drag-handle:hover {
47
+ opacity: 1;
48
+ }
49
+ .drag-ghost {
50
+ position: absolute;
51
+ z-index: 1000;
52
+ opacity: 0.8;
53
+ pointer-events: none;
54
+ background: white;
55
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
56
+ border-radius: 0.375rem;
57
+ border: 1px solid #e5e7eb;
58
+ transform: translate(0, 0);
59
+ transition: transform 0.1s ease;
60
+ }
61
+ </style>
62
+ </head>
63
+ <body class="bg-gray-50 font-sans p-6">
64
+ <div class="max-w-4xl mx-auto">
65
+ <div class="bg-white rounded-xl shadow-md overflow-hidden">
66
+ <div class="p-6">
67
+ <h1 class="text-2xl font-bold text-gray-800 mb-6">Интерактивное дерево с плавным перетаскиванием</h1>
68
+
69
+ <div class="flex space-x-4 mb-6">
70
+ <button id="addRootNode" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
71
+ <i class="fas fa-plus"></i>
72
+ <span>Добавить корневой элемент</span>
73
+ </button>
74
+ <button id="expandAll" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg flex items-center space-x-2">
75
+ <i class="fas fa-expand"></i>
76
+ <span>Развернуть все</span>
77
+ </button>
78
+ <button id="collapseAll" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg flex items-center space-x-2">
79
+ <i class="fas fa-compress"></i>
80
+ <span>Свернуть все</span>
81
+ </button>
82
+ </div>
83
+
84
+ <div id="treeContainer" class="border border-gray-200 rounded-lg p-4 min-h-40">
85
+ <!-- Дерево будет сгенерировано здесь -->
86
+ <div id="treeRoot" class="space-y-1"></div>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </div>
91
+
92
+ <!-- Модальное окно для добавления/редактирования узла -->
93
+ <div id="nodeModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
94
+ <div class="bg-white rounded-lg p-6 max-w-md w-full">
95
+ <div class="flex justify-between items-start mb-4">
96
+ <h3 class="text-lg font-medium text-gray-900" id="modalTitle">Добавить узел</h3>
97
+ <button id="closeNodeModal" class="text-gray-400 hover:text-gray-500">
98
+ <i class="fas fa-times"></i>
99
+ </button>
100
+ </div>
101
+ <div class="mb-4">
102
+ <label for="nodeName" class="block text-sm font-medium text-gray-700 mb-1">Название узла</label>
103
+ <input type="text" id="nodeName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
104
+ </div>
105
+ <div class="flex justify-end space-x-3">
106
+ <button id="cancelNode" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
107
+ Отмена
108
+ </button>
109
+ <button id="saveNode" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
110
+ Сохранить
111
+ </button>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ <script>
117
+ // Инициализация дерева
118
+ let treeData = [
119
+ {
120
+ id: 1,
121
+ name: "Корневой элемент 1",
122
+ children: [
123
+ {
124
+ id: 2,
125
+ name: "Дочерний элемент 1.1",
126
+ children: [
127
+ {
128
+ id: 3,
129
+ name: "Вложенный элемент 1.1.1",
130
+ children: []
131
+ },
132
+ {
133
+ id: 4,
134
+ name: "Вложенный элемент 1.1.2",
135
+ children: []
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ id: 5,
141
+ name: "Дочерний элемент 1.2",
142
+ children: []
143
+ }
144
+ ]
145
+ },
146
+ {
147
+ id: 6,
148
+ name: "Корневой элемент 2",
149
+ children: []
150
+ }
151
+ ];
152
+
153
+ // Переменные для управления состоянием
154
+ let nextId = 7;
155
+ let currentNodeId = null;
156
+ let currentParentId = null;
157
+ let isEditing = false;
158
+ let draggedNode = null;
159
+ let draggedNodeParent = null;
160
+ let draggedNodeIndex = null;
161
+ let dragGhost = null;
162
+ let lastDragPosition = { x: 0, y: 0 };
163
+ let placeholder = null;
164
+ let isDragging = false;
165
+ let targetParentId = null;
166
+ let targetIndex = null;
167
+
168
+ // DOM элементы
169
+ const treeRoot = document.getElementById('treeRoot');
170
+ const nodeModal = document.getElementById('nodeModal');
171
+ const nodeNameInput = document.getElementById('nodeName');
172
+ const modalTitle = document.getElementById('modalTitle');
173
+ const addRootNodeBtn = document.getElementById('addRootNode');
174
+ const expandAllBtn = document.getElementById('expandAll');
175
+ const collapseAllBtn = document.getElementById('collapseAll');
176
+
177
+ // Инициализация дерева при загрузке
178
+ document.addEventListener('DOMContentLoaded', () => {
179
+ renderTree();
180
+ setupEventListeners();
181
+ });
182
+
183
+ // Рендер дерева
184
+ function renderTree(data = treeData, parentElement = treeRoot, level = 0) {
185
+ parentElement.innerHTML = '';
186
+
187
+ if (data.length === 0 && parentElement === treeRoot) {
188
+ parentElement.innerHTML = '<p class="text-gray-500 italic">Дерево пустое</p>';
189
+ return;
190
+ }
191
+
192
+ data.forEach((node, index) => {
193
+ const hasChildren = node.children && node.children.length > 0;
194
+
195
+ const nodeElement = document.createElement('div');
196
+ nodeElement.className = 'tree-node pl-' + (level * 4);
197
+ nodeElement.dataset.id = node.id;
198
+ nodeElement.dataset.parentId = parentElement.dataset.id || 'root';
199
+ nodeElement.dataset.index = index;
200
+
201
+ nodeElement.innerHTML = `
202
+ <div class="flex items-center py-2 px-3 rounded-lg border border-gray-200">
203
+ <div class="flex items-center flex-1">
204
+ <span class="drag-handle mr-2 text-gray-400 cursor-move">
205
+ <i class="fas fa-grip-vertical"></i>
206
+ </span>
207
+ ${hasChildren ? `
208
+ <button class="toggle-node mr-2 text-gray-500 hover:text-gray-700" data-id="${node.id}">
209
+ <i class="fas fa-caret-right"></i>
210
+ </button>
211
+ ` : '<span class="w-6"></span>'}
212
+ <span class="node-name">${node.name}</span>
213
+ </div>
214
+ <div class="flex space-x-2">
215
+ <button class="edit-node p-1 text-blue-500 hover:text-blue-700" data-id="${node.id}">
216
+ <i class="fas fa-edit"></i>
217
+ </button>
218
+ <button class="add-child p-1 text-green-500 hover:text-green-700" data-id="${node.id}">
219
+ <i class="fas fa-plus"></i>
220
+ </button>
221
+ <button class="delete-node p-1 text-red-500 hover:text-red-700" data-id="${node.id}">
222
+ <i class="fas fa-trash"></i>
223
+ </button>
224
+ </div>
225
+ </div>
226
+ ${hasChildren ? `
227
+ <div class="nested pl-4" data-parent-id="${node.id}"></div>
228
+ ` : ''}
229
+ `;
230
+
231
+ parentElement.appendChild(nodeElement);
232
+
233
+ // Рендерим детей, если они есть
234
+ if (hasChildren) {
235
+ const nestedContainer = nodeElement.querySelector('.nested');
236
+ renderTree(node.children, nestedContainer, level + 1);
237
+ }
238
+ });
239
+ }
240
+
241
+ // Настройка обработчиков событий
242
+ function setupEventListeners() {
243
+ // Кнопки модального окна
244
+ document.getElementById('closeNodeModal').addEventListener('click', closeNodeModal);
245
+ document.getElementById('cancelNode').addEventListener('click', closeNodeModal);
246
+ document.getElementById('saveNode').addEventListener('click', saveNode);
247
+
248
+ // Кнопки управления деревом
249
+ addRootNodeBtn.addEventListener('click', () => {
250
+ openNodeModal(null, null, false);
251
+ });
252
+
253
+ expandAllBtn.addEventListener('click', expandAllNodes);
254
+ collapseAllBtn.addEventListener('click', collapseAllNodes);
255
+
256
+ // Делегирование событий для динамически созданных элементов
257
+ treeRoot.addEventListener('click', (e) => {
258
+ const target = e.target.closest('.toggle-node');
259
+ if (target) {
260
+ toggleNode(target.dataset.id);
261
+ return;
262
+ }
263
+
264
+ const editBtn = e.target.closest('.edit-node');
265
+ if (editBtn) {
266
+ openNodeModal(editBtn.dataset.id, null, true);
267
+ return;
268
+ }
269
+
270
+ const addChildBtn = e.target.closest('.add-child');
271
+ if (addChildBtn) {
272
+ openNodeModal(null, addChildBtn.dataset.id, false);
273
+ return;
274
+ }
275
+
276
+ const deleteBtn = e.target.closest('.delete-node');
277
+ if (deleteBtn) {
278
+ deleteNode(deleteBtn.dataset.id);
279
+ return;
280
+ }
281
+ });
282
+
283
+ // Перетаскивание
284
+ setupDragAndDrop();
285
+ }
286
+
287
+ // Настройка плавного перетаскивания
288
+ function setupDragAndDrop() {
289
+ document.addEventListener('mousedown', (e) => {
290
+ const handle = e.target.closest('.drag-handle');
291
+ if (!handle) return;
292
+
293
+ const nodeElement = handle.closest('.tree-node');
294
+ if (!nodeElement) return;
295
+
296
+ draggedNode = findNodeById(treeData, nodeElement.dataset.id);
297
+ draggedNodeParent = nodeElement.dataset.parentId === 'root' ? treeData :
298
+ findNodeById(treeData, nodeElement.dataset.parentId).children;
299
+ draggedNodeIndex = parseInt(nodeElement.dataset.index);
300
+
301
+ // Создаем призрачный элемент для перетаскивания
302
+ dragGhost = nodeElement.cloneNode(true);
303
+ dragGhost.classList.add('drag-ghost');
304
+ dragGhost.style.width = nodeElement.offsetWidth + 'px';
305
+ dragGhost.style.left = nodeElement.getBoundingClientRect().left + 'px';
306
+ dragGhost.style.top = nodeElement.getBoundingClientRect().top + 'px';
307
+ document.body.appendChild(dragGhost);
308
+
309
+ // Сохраняем начальную позицию
310
+ lastDragPosition = { x: e.clientX, y: e.clientY };
311
+ isDragging = true;
312
+
313
+ // Добавляем класс для визуального эффекта
314
+ nodeElement.classList.add('dragging');
315
+
316
+ // Отключаем выделение текста при перетаскивании
317
+ document.body.style.userSelect = 'none';
318
+
319
+ // Обработчики для плавного перетаскивания
320
+ document.addEventListener('mousemove', handleDragMove);
321
+ document.addEventListener('mouseup', handleDragEnd);
322
+
323
+ e.preventDefault();
324
+ });
325
+
326
+ function handleDragMove(e) {
327
+ if (!isDragging || !dragGhost) return;
328
+
329
+ // Вычисляем смещение
330
+ const dx = e.clientX - lastDragPosition.x;
331
+ const dy = e.clientY - lastDragPosition.y;
332
+
333
+ // Обновляем позицию призрака
334
+ const ghostRect = dragGhost.getBoundingClientRect();
335
+ dragGhost.style.left = (ghostRect.left + dx) + 'px';
336
+ dragGhost.style.top = (ghostRect.top + dy) + 'px';
337
+
338
+ // Обновляем последнюю позицию
339
+ lastDragPosition = { x: e.clientX, y: e.clientY };
340
+
341
+ // Определяем элемент под курсором
342
+ const elements = document.elementsFromPoint(e.clientX, e.clientY);
343
+ let targetElement = null;
344
+
345
+ for (const el of elements) {
346
+ if (el.classList.contains('tree-node') || el.classList.contains('nested') || el.id === 'treeRoot') {
347
+ targetElement = el;
348
+ break;
349
+ }
350
+ }
351
+
352
+ // Обработка позиционирования плейсхолдера
353
+ if (targetElement) {
354
+ // Удаляем старый плейсхолдер
355
+ removePlaceholder();
356
+
357
+ if (targetElement.classList.contains('tree-node')) {
358
+ const rect = targetElement.getBoundingClientRect();
359
+ const midpoint = rect.top + rect.height / 2;
360
+
361
+ // Определяем, куда вставлять - выше или ниже узла
362
+ if (e.clientY < midpoint) {
363
+ showPlaceholder(targetElement, 'before');
364
+ targetParentId = targetElement.dataset.parentId;
365
+ targetIndex = parseInt(targetElement.dataset.index);
366
+ } else {
367
+ const hasChildren = targetElement.querySelector('.toggle-node') !== null;
368
+
369
+ if (hasChildren) {
370
+ const nested = targetElement.querySelector('.nested');
371
+ if (!nested.classList.contains('active')) {
372
+ // Если узел свернут, показываем плейсхолдер внутри
373
+ showPlaceholder(nested, 'first');
374
+ targetParentId = targetElement.dataset.id;
375
+ targetIndex = 0;
376
+ } else {
377
+ // Если узел развернут, показываем плейсхолдер после
378
+ showPlaceholder(targetElement, 'after');
379
+ targetParentId = targetElement.dataset.parentId;
380
+ targetIndex = parseInt(targetElement.dataset.index) + 1;
381
+ }
382
+ } else {
383
+ showPlaceholder(targetElement, 'after');
384
+ targetParentId = targetElement.dataset.parentId;
385
+ targetIndex = parseInt(targetElement.dataset.index) + 1;
386
+ }
387
+ }
388
+ }
389
+ else if (targetElement.classList.contains('nested')) {
390
+ const children = Array.from(targetElement.children).filter(el => el.classList.contains('tree-node'));
391
+
392
+ if (children.length === 0) {
393
+ showPlaceholder(targetElement, 'first');
394
+ targetParentId = targetElement.dataset.parentId;
395
+ targetIndex = 0;
396
+ } else {
397
+ const lastChild = children[children.length - 1];
398
+ showPlaceholder(lastChild, 'after');
399
+ targetParentId = targetElement.dataset.parentId;
400
+ targetIndex = children.length;
401
+ }
402
+ }
403
+ else if (targetElement.id === 'treeRoot') {
404
+ const children = Array.from(targetElement.children).filter(el => el.classList.contains('tree-node'));
405
+
406
+ if (children.length === 0) {
407
+ showPlaceholder(targetElement, 'first');
408
+ targetParentId = 'root';
409
+ targetIndex = 0;
410
+ } else {
411
+ const lastChild = children[children.length - 1];
412
+ showPlaceholder(lastChild, 'after');
413
+ targetParentId = 'root';
414
+ targetIndex = children.length;
415
+ }
416
+ }
417
+ }
418
+ }
419
+
420
+ function handleDragEnd(e) {
421
+ if (!isDragging) return;
422
+
423
+ // Удаляем призрака
424
+ if (dragGhost) {
425
+ dragGhost.remove();
426
+ dragGhost = null;
427
+ }
428
+
429
+ // Удаляем плейсхолдер
430
+ removePlaceholder();
431
+
432
+ // Восстанавливаем выделение текста
433
+ document.body.style.userSelect = '';
434
+
435
+ // Удаляем обработчики
436
+ document.removeEventListener('mousemove', handleDragMove);
437
+ document.removeEventListener('mouseup', handleDragEnd);
438
+
439
+ // Если есть перетаскиваемый узел и целевая позиция
440
+ if (draggedNode && targetParentId !== null && targetIndex !== null) {
441
+ // Определяем новый родительский массив
442
+ let newParentArray;
443
+ if (targetParentId === 'root') {
444
+ newParentArray = treeData;
445
+ } else {
446
+ const parentNode = findNodeById(treeData, targetParentId);
447
+ if (parentNode) {
448
+ newParentArray = parentNode.children;
449
+ } else {
450
+ newParentArray = treeData;
451
+ }
452
+ }
453
+
454
+ // Проверяем, что перемещение допустимо (не в самого себя или своих потомков)
455
+ if (!isDescendant(draggedNode, targetParentId === 'root' ? null : findNodeById(treeData, targetParentId))) {
456
+ // Удаляем узел из старого места
457
+ const oldIndex = draggedNodeParent.indexOf(draggedNode);
458
+ if (oldIndex !== -1) {
459
+ draggedNodeParent.splice(oldIndex, 1);
460
+ }
461
+
462
+ // Вставляем узел в новое место
463
+ if (targetIndex > newParentArray.length) {
464
+ targetIndex = newParentArray.length;
465
+ }
466
+ newParentArray.splice(targetIndex, 0, draggedNode);
467
+
468
+ // Перерисовываем дерево
469
+ renderTree();
470
+
471
+ // Автоматически раскрываем родительский узел, если нужно
472
+ if (targetParentId !== 'root') {
473
+ const parentElement = document.querySelector(`.tree-node[data-id="${targetParentId}"]`);
474
+ if (parentElement) {
475
+ const nested = parentElement.querySelector('.nested');
476
+ if (nested && !nested.classList.contains('active')) {
477
+ toggleNode(targetParentId);
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
483
+
484
+ // Сбрасываем состояние перетаскивания
485
+ resetDragState();
486
+
487
+ // Удаляем класс dragging со всех элементов
488
+ document.querySelectorAll('.tree-node.dragging').forEach(el => {
489
+ el.classList.remove('dragging');
490
+ });
491
+
492
+ isDragging = false;
493
+ targetParentId = null;
494
+ targetIndex = null;
495
+ }
496
+ }
497
+
498
+ // Показать плейсхолдер для перетаскивания
499
+ function showPlaceholder(element, position) {
500
+ removePlaceholder();
501
+
502
+ placeholder = document.createElement('div');
503
+ placeholder.className = 'tree-node-placeholder';
504
+ placeholder.dataset.position = position;
505
+
506
+ if (position === 'before') {
507
+ element.parentNode.insertBefore(placeholder, element);
508
+ }
509
+ else if (position === 'after') {
510
+ element.parentNode.insertBefore(placeholder, element.nextSibling);
511
+ }
512
+ else if (position === 'first') {
513
+ element.insertBefore(placeholder, element.firstChild);
514
+ }
515
+ else if (position === 'last') {
516
+ element.appendChild(placeholder);
517
+ }
518
+ }
519
+
520
+ // Удалить плейсхолдер
521
+ function removePlaceholder() {
522
+ if (placeholder) {
523
+ placeholder.remove();
524
+ placeholder = null;
525
+ }
526
+ }
527
+
528
+ // Сбросить состояние перетаскивания
529
+ function resetDragState() {
530
+ draggedNode = null;
531
+ draggedNodeParent = null;
532
+ draggedNodeIndex = null;
533
+ }
534
+
535
+ // Проверить, является ли узел потомком другого узла
536
+ function isDescendant(node, parentNode) {
537
+ if (!parentNode) return false;
538
+ if (node.id === parentNode.id) return true;
539
+
540
+ // Проверяем всех детей родительского узла
541
+ for (const child of parentNode.children) {
542
+ if (isDescendant(node, child)) {
543
+ return true;
544
+ }
545
+ }
546
+
547
+ return false;
548
+ }
549
+
550
+ // Найти узел по ID
551
+ function findNodeById(data, id) {
552
+ for (let i = 0; i < data.length; i++) {
553
+ if (data[i].id == id) {
554
+ return data[i];
555
+ }
556
+
557
+ if (data[i].children && data[i].children.length > 0) {
558
+ const found = findNodeById(data[i].children, id);
559
+ if (found) return found;
560
+ }
561
+ }
562
+
563
+ return null;
564
+ }
565
+
566
+ // Найти родительский узел
567
+ function findParentNode(data, id, parent = null) {
568
+ for (let i = 0; i < data.length; i++) {
569
+ if (data[i].id == id) {
570
+ return parent;
571
+ }
572
+
573
+ if (data[i].children && data[i].children.length > 0) {
574
+ const found = findParentNode(data[i].children, id, data[i]);
575
+ if (found) return found;
576
+ }
577
+ }
578
+
579
+ return null;
580
+ }
581
+
582
+ // Открыть модальное окно для добавления/редактирования узла
583
+ function openNodeModal(nodeId, parentId, editMode) {
584
+ currentNodeId = nodeId;
585
+ currentParentId = parentId;
586
+ isEditing = editMode;
587
+
588
+ if (editMode) {
589
+ modalTitle.textContent = 'Редактировать узел';
590
+ const node = findNodeById(treeData, nodeId);
591
+ nodeNameInput.value = node.name;
592
+ } else {
593
+ modalTitle.textContent = parentId ? 'Добавить дочерний узел' : 'Добавить корневой узел';
594
+ nodeNameInput.value = '';
595
+ }
596
+
597
+ nodeModal.classList.remove('hidden');
598
+ nodeNameInput.focus();
599
+ }
600
+
601
+ // Закрыть модальное окно
602
+ function closeNodeModal() {
603
+ nodeModal.classList.add('hidden');
604
+ }
605
+
606
+ // Сохранить узел
607
+ function saveNode() {
608
+ const name = nodeNameInput.value.trim();
609
+
610
+ if (!name) {
611
+ alert('Пожалуйста, введите название узла');
612
+ return;
613
+ }
614
+
615
+ if (isEditing) {
616
+ // Редактирование существующего узла
617
+ const node = findNodeById(treeData, currentNodeId);
618
+ if (node) {
619
+ node.name = name;
620
+ }
621
+ } else {
622
+ // Добавление нового узла
623
+ const newNode = {
624
+ id: nextId++,
625
+ name: name,
626
+ children: []
627
+ };
628
+
629
+ if (currentParentId) {
630
+ // Добавляем как дочерний узел
631
+ const parentNode = findNodeById(treeData, currentParentId);
632
+ if (parentNode) {
633
+ parentNode.children.push(newNode);
634
+ }
635
+ } else {
636
+ // Добавляем как корневой узел
637
+ treeData.push(newNode);
638
+ }
639
+ }
640
+
641
+ // Перерисовываем дерево
642
+ renderTree();
643
+ closeNodeModal();
644
+ }
645
+
646
+ // Удалить узел
647
+ function deleteNode(nodeId) {
648
+ if (!confirm('Вы уверены, что хотите удалить этот узел и все его дочерние элементы?')) {
649
+ return;
650
+ }
651
+
652
+ const parent = findParentNode(treeData, nodeId);
653
+
654
+ if (parent) {
655
+ // Удаляем из дочерних элементов родителя
656
+ parent.children = parent.children.filter(node => node.id != nodeId);
657
+ } else {
658
+ // Удаляем из корневых элементов
659
+ treeData = treeData.filter(node => node.id != nodeId);
660
+ }
661
+
662
+ // Перерисовываем дерево
663
+ renderTree();
664
+ }
665
+
666
+ // Переключить видимость дочерних узлов
667
+ function toggleNode(nodeId) {
668
+ const nodeElement = document.querySelector(`.tree-node[data-id="${nodeId}"]`);
669
+ if (!nodeElement) return;
670
+
671
+ const nestedContainer = nodeElement.querySelector('.nested');
672
+ if (!nestedContainer) return;
673
+
674
+ const toggleBtn = nodeElement.querySelector('.toggle-node');
675
+
676
+ if (nestedContainer.classList.contains('active')) {
677
+ // Скрываем
678
+ nestedContainer.classList.remove('active');
679
+ toggleBtn.innerHTML = '<i class="fas fa-caret-right"></i>';
680
+ } else {
681
+ // Показываем
682
+ nestedContainer.classList.add('active');
683
+ toggleBtn.innerHTML = '<i class="fas fa-caret-down"></i>';
684
+ }
685
+ }
686
+
687
+ // Развернуть все узлы
688
+ function expandAllNodes() {
689
+ document.querySelectorAll('.nested').forEach(nested => {
690
+ nested.classList.add('active');
691
+ });
692
+
693
+ document.querySelectorAll('.toggle-node').forEach(btn => {
694
+ btn.innerHTML = '<i class="fas fa-caret-down"></i>';
695
+ });
696
+ }
697
+
698
+ // Свернуть все узлы
699
+ function collapseAllNodes() {
700
+ document.querySelectorAll('.nested').forEach(nested => {
701
+ nested.classList.remove('active');
702
+ });
703
+
704
+ document.querySelectorAll('.toggle-node').forEach(btn => {
705
+ btn.innerHTML = '<i class="fas fa-caret-right"></i>';
706
+ });
707
+ }
708
+ </script>
709
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=SimpleCodeTM/tree-moved" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
710
+ </html>
prompts.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ выделить ВСЕ и поиск не функционируют
2
+ дерево с возможностью углубления на любую глубину и плавным перетаскиванием элементов за левую иконку в любое место дерева и на любую в т.ч. и новую глубину
3
+ скачет все сильно, очень дискомфортно
4
+ уже лучше , не дергается но не запоминает конечную позицию ( не перемещает )